
    `gj                        d Z ddlZddlZddlmZ ddlmZ ddlmZ  ej                  e	      Z
 e       dz  Zedz  Z	 	 	 	 dded	ed
ededee   dee   dedefdZ	 	 dded	edee   dee   dee   f
dZdededdfdZy)a}  
Session mirroring for cross-platform message delivery.

When a message is sent to a platform (via send_message or cron delivery),
this module appends a "delivery-mirror" record to the target session's
transcript so the receiving-side agent has context about what was sent.

Standalone -- works from CLI, cron, and gateway contexts without needing
the full SessionStore machinery.
    N)datetime)Optional)get_hermes_homesessionszsessions.jsonplatformchat_idmessage_textsource_label	thread_iduser_idrolereturnc           	      d   	 t        | t        |      ||      }|st        j                  d| |||       y||t	        j
                         j                         d|d}t        ||       t        j                  d||       y# t        $ r$}	t        j                  d| ||||	       Y d}	~	yd}	~	ww xY w)	u[  
    Append a delivery-mirror message to the target session's transcript.

    Finds the gateway session that matches the given platform + chat_id,
    then writes a mirror entry to both the JSONL transcript and SQLite DB.

    ``role`` defaults to ``"assistant"`` — correct for the interactive
    ``send_message`` mirror, where the mirrored text is the agent's own
    outgoing reply (a genuine assistant turn). Callers mirroring text that is
    NOT the agent speaking — e.g. a cron brief delivered out-of-band — must
    pass ``role="user"``: the ``mirror``/``mirror_source`` metadata is dropped
    at the SQLite boundary (only role+content persist), so on replay an
    assistant-role mirror is indistinguishable from a real assistant turn and
    produces ``assistant → assistant`` pairs that break strict-alternation
    providers (issue #2221). A user-role mirror collapses safely via
    ``repair_message_sequence``'s consecutive-user merge on every provider.

    Returns True if mirrored successfully, False if no matching session or error.
    All errors are caught -- this is never fatal.
    )r   r   z(Mirror: no session found for %s:%s:%s:%sFT)r   content	timestampmirrormirror_sourcez%Mirror: wrote to session %s (from %s)z!Mirror failed for %s:%s:%s:%s: %sN)	_find_session_idstrloggerdebugr   now	isoformat_append_to_sqlite	Exception)
r   r   r	   r
   r   r   r   
session_id
mirror_msges
             A/root/.hermes/venv/lib/python3.12/site-packages/gateway/mirror.pymirror_to_sessionr       s    :'%L	

 LL:  #!113)

 	*j1<j,W 	/	
 	s   3B AB 	B/B**B/c                    	 ddl m}  |       }	 t        |dd      }t        |      r) || |||      }|rt	        |      |j                          S |j                          	 t        j                         sy	 t        t        d      5 }	t        j                  |	      }
ddd       | j                         }g }
j                         D ]  \  }}t	        |      j!                  d	      st#        |t$              s1|j'                  d
      xs i }|j'                  d      xs |j'                  dd      j                         }||k7  rt	        |j'                  dd            }|t	        |      k(  s|j'                  d      }|t	        |xs d      t	        |      k7  r|j)                  |        |sy|r`|D cg c]A  }t	        |j'                  d
      xs i j'                  d      xs d      t	        |      k(  r|C }}|r|}nt+        |      dkD  ryt+        |      dkD  r|D ch c]  }t	        |j'                  d
      xs i j'                  d      xs d      j-                         r?t	        |j'                  d
      xs i j'                  d      xs d      j-                          }}t+        |      dkD  ryt/        |d       }|j'                  d      S # |j                          w xY w# t        $ r!}t        j                  d|       Y d}~d}~ww xY w# 1 sw Y   xY w# t        $ r Y yw xY wc c}w c c}w )a3  
    Find the active session_id for a platform + chat_id pair.

    Queries state.db gateway session rows (primary source since #9006);
    falls back to scanning sessions.json for pre-migration databases.
    DM session keys don't embed the chat_id (e.g. "agent:main:telegram:dm"),
    so we match on the persisted chat origin, not the key.

    When *user_id* is provided, prefer exact sender matches. If multiple
    same-chat candidates exist and none matches the user, return None instead
    of guessing and contaminating another participant's session.
    r   	SessionDBfind_session_by_originN)r   r   r   r   z)Mirror state.db session lookup failed: %szutf-8)encoding_originr    r   r   r      c                 &    | j                  dd      S )N
updated_atr(   )get)entrys    r   <lambda>z"_find_session_id.<locals>.<lambda>   s    599\23N     )keyr   )hermes_stater#   getattrcallabler   closer   r   r   _SESSIONS_INDEXexistsopenjsonloadloweritems
startswith
isinstancedictr,   appendlenstripmax)r   r   r   r   r#   dbfinderr   r   fdataplatform_lower
candidates_keyr-   r'   entry_platformorigin_chat_idorigin_thread_idexact_user_matchesdistinct_user_ids
best_entrys                         r   r   r   `   s   &E*[	R!94@F#%#'#	
 z?HHJBHHJ
 !!#/G4 	 99Q<D	 
 ^^%NJzz| %e t9$Jud,C8$* **Z0MEIIj"4MTTV^+VZZ	267S\)%zz+6$-=-C)DI)Ve$!%$ )
EIIh'-2229=CDGT 
 
 +J_q 	Z1	 $
EIIh'-2229=CDJJL 8$*//	:@bAGGI
 

  !A%Z%NOJ>>,''s HHJ E@!DDE	  	  8

sl   K5 0K   K5 K5 8L/ 	L"L/ =AL>+BM K22K5 5	L>LL"L,'L/ /	L;:L;r   messagec                 8   d}	 ddl m}  |       }|j                  | |j                  dd      |j                  d             ||j                          yy# t        $ r }t
        j                  d|       Y d}~8d}~ww xY w# ||j                          w w xY w)	z0Append a message to the SQLite session database.Nr   r"   r   	assistantr   )r   r   r   zMirror SQLite write failed: %s)r1   r#   append_messager,   r   r   r   r4   )r   rP   rC   r#   r   s        r   r   r      s    	B*[
!V[1KK	* 	 	
 >HHJ   :5q99: >HHJ s*   A A 	B!A<7B <BB B)cliNNrR   )NN)__doc__r8   loggingr   typingr   hermes_cli.configr   	getLogger__name__r   _SESSIONS_DIRr5   r   boolr    r   r>   r    r/   r   <module>r^      s  	     -			8	$!J./1 #!DDD D 	D
 }D c]D D 
DT  $!	[([([( }[( c]	[(
 c][(~#   r/   