
    'j                        U d Z ddlmZ ddlZddlmZ ddlmZm	Z	m
Z
mZmZ ddlmZ i Zded<   ddZddZ	 dddZddZdS )u^  Conversation history adapter for pydantic-ai agents.

Cache strategy (write-through, per-process):
  - ``load_conversation_history``: cache-first; on miss loads from DB and
    stores the result so subsequent calls in the same process never hit DB again.
  - ``append_to_history_cache``: called after every ``save_message``; appends
    the new message directly to the in-memory list so the cache grows with the
    conversation.  Creates the entry if not yet present (covers new chats where
    ``load_conversation_history`` may not have been called yet).
  - ``serialize_history`` / ``deserialize_history``: compact wire format
    ``[{role, content}]`` so rt_agent can pass its already-loaded history to
    tatasteel and ui_agent in the HTTP request body — those processes have their
    own caches and would otherwise each make a redundant DB round-trip.
    )annotationsN)logger)ModelMessageModelRequestModelResponseTextPartUserPromptPart)get_messageszdict[int, list[ModelMessage]]_HISTORY_CACHEhistorylist[ModelMessage]returnlist[dict[str, str]]c                z   g }| D ]}t          |t                    rE|j        D ]<}t          |d          r*|                    dt          |j                  d           =\t          |t                    rD|j        D ]<}t          |d          r*|                    dt          |j                  d           =|S )zBFlatten ModelMessages to ``[{role, content}]`` for HTTP transport.contentuser)roler   	assistant)
isinstancer   partshasattrappendstrr   r   )r   resultmsgparts       K/var/www/html/ai-enterprise-brain/backend/chanakya/conversation/_history.pyserialize_historyr      s    #%F W Wc<(( 	W	 R R4++ RMM6c$,>O>O"P"PQQQR ]++ 	W	 W W4++ WMM;3t|CTCT"U"UVVVM    datac                N   g }| D ]}|                     dd          }|                     dd          }|dk    r3|                    t          t          |          g                     g|dk    r2|                    t	          t          |          g                     |S )zFReconstruct ModelMessages from ``[{role, content}]`` transport format.r    r   r   r   r   r   )getr   r   r	   r   r   )r    r   itemr   r   s        r   deserialize_historyr'   .   s    !#F L Lxx##((9b))6>>MM,nW.M.M.M-NOOOPPPP[  MM-x/H/H/H.IJJJKKKMr   conversation_id
int | Noneauthorr   messagetatasteel_cachedict | NoneNonec           	     B   | sdS | t           vr
g t           | <   |dk    r>t           |                              t          t          |          g                     n|dk    r|}|rM|                    d          r8|d|                    dd	           d
t          j        |d                    dz  }t           |                              t          t          |          g                     t          j
        d|| t          t           |                               dS )u  Append a newly saved message to the in-memory cache.

    Creates the cache entry when it does not yet exist — this covers new
    conversations where ``load_conversation_history`` may not have been called
    before the first ``save_message``.

    Args:
        conversation_id: Conversation the message belongs to.
        author:          ``"user"`` or ``"assistant"``.
        message:         Plain-text message content.
        tatasteel_cache: For assistant messages, ``{rows, explanation, question}``
                         from metadata — rows are embedded so visualization
                         follow-ups work without a DB re-query.
    Nr   r#   r$   r   rows(   

[Previous query data — explanation: explanationr"   
rows: ]zE[HISTORY] Appended {} message to cache for conversation {} (total={}))r   r   r   r	   r%   jsondumpsr   r   _logdebuglen)r(   r*   r+   r,   r   s        r   append_to_history_cacher:   ?   sc   (  n,,*,''..w ? ? ?@AAA	
 	
 	
 	
 
;		 	226:: 	B%4%8%8%K%KB B:of&=>>B B BG
 	'..'!:!:!: ;<<<	
 	
 	
 	JO^O%D!E!E    r   c           	       K   | sg S t                               |           }|%t          j        d| t	          |                     |S 	 t          |            d{V }g }|D ]F}|d         dk    r9|                    t          t          |d                   g                     H|d         dk    r|d         }|                    d	          }|r	 t          |t                    rt          j        |          n|}|                    d
          }|rM|                    d          r8|d|                    dd           dt          j        |d                    dz  }n# t          $ r Y nw xY w|                    t          t!          |          g                     Ht          j        dt	          |          |            |t           | <   |S # t          $ r"}	t          j        d| |	           g cY d}	~	S d}	~	ww xY w)a  Return conversation history as a pydantic-ai message list.

    Cache-first: if the conversation is already in memory, returns that copy
    without touching the DB.  Falls back to a DB load and caches the result.

    Args:
        conversation_id: The conversation to load, or ``None`` / ``0`` to skip.

    Returns:
        Ordered ``list[ModelMessage]`` for ``agent.run(message_history=...)``.
        Returns ``[]`` when *conversation_id* is falsy or on any DB error.
    Nz5[HISTORY] Cache hit for conversation {} ({} messages)message_authorr   r+   r#   r$   r   metadata_tatasteel_cacher0   r1   r2   r"   r3   r4   z8[HISTORY] Loaded {} messages from DB for conversation {}z8[HISTORY] Failed to load conversation history for {}: {})r   r%   r7   r8   r9   r
   r   r   r	   r   r   r5   loadsr6   	Exceptionr   r   warning)
r(   cachedmessagesr   r   r   raw_metar=   cacheexcs
             r   load_conversation_historyrG   s   s|       	00F
CS[[	
 	
 	
 !%o66666666&( 	Q 	QC#$..|>#i.3Y3Y3Y2Z[[[\\\\%&+55i.77:.. 
;EhPS;T;T#b4:h#7#7#7Zb (-? @ @  UYYv%6%6 #!H5:YY}b5Q5Q!H !H+/:eFm+D+D!H !H !HG
 %   }HW4M4M4M3NOOOPPP
FLL/	
 	
 	
 +2'   FS	
 	
 	
 						sE   	BG BE&%G &
E30G 2E33A%G 
H#H :H H)r   r   r   r   )r    r   r   r   )N)
r(   r)   r*   r   r+   r   r,   r-   r   r.   )r(   r)   r   r   )__doc__
__future__r   r5   logurur   r7   pydantic_ai.messagesr   r   r   r   r	   &backend.chanakya.conversation.databaser
   r   __annotations__r   r'   r:   rG    r   r   <module>rO      s      # " " " " "  ! ! ! ! ! ! d d d d d d d d d d d d d d ? ? ? ? ? ?02 2 2 2 2   
 
 
 
* $(	- - - - -h9 9 9 9 9 9r   