
    jx6                     V   d Z ddlZddlmZ ddlmZ ddlmZ ddlmZm	Z	m
Z
mZ ddlmZ  ej        e          ZdZd	Zd
dlmZmZ d
dlmZ de
e         defdZde
e         defdZdedefdZdede
e         fdZdedefdZe G d d                      Z G d d          Z dS )u0  
Delivery routing for cron job outputs and agent responses.

Routes messages to the appropriate destination based on:
- Explicit targets (e.g., "telegram:123456789")
- Platform home channels (e.g., "telegram" → home channel)
- Origin (back to where the job was created)
- Local (always saved to files)
    N)Path)datetime)	dataclass)DictListOptionalAny)get_hermes_homei  i     )PlatformGatewayConfig)SessionSourcechat_idreturnc                 b    | dS 	 t          |           dk    S # t          t          f$ r Y dS w xY w)NFr   int	TypeError
ValueError)r   s    //usr/local/lib/hermes-agent/gateway/delivery.py$_looks_like_telegram_private_chat_idr      sI    u7||az"   uus    ..valuec                 ^    | dS 	 t          |            dS # t          t          f$ r Y dS w xY w)NFTr   )r   s    r   _looks_like_intr   %   sH    }uE


tz"   uus    ,,resultc                     t          | t                    r|                     d          du S t          | dd          du S )NsuccessFT)
isinstancedictgetgetattr)r   s    r   _send_result_failedr"   /   sB    &$ .zz)$$--69d++u44    c                     t          | t                    r|                     d          }nt          | dd           }|rt	          |          nd S )Nerror)r   r   r    r!   strr   r%   s     r   _send_result_errorr(   5   sM    &$ /

7##..(3u:::D(r#   c                 j    t          |           }t          |od|                                v           S )Nzthread not found)r(   boollowerr'   s     r   #_is_thread_not_found_delivery_errorr,   =   s0    v&&E=,=>>>r#   c                       e Zd ZU dZeed<   dZee         ed<   dZ	ee         ed<   dZ
eed<   dZeed<   edd	ed
ee         dd fd            ZdefdZdS )DeliveryTargetu   
    A single delivery target.
    
    Represents where a message should be sent:
    - "origin" → back to source
    - "local" → save to local files
    - "telegram" → Telegram home channel
    - "telegram:123456" → specific Telegram chat
    platformNr   	thread_idF	is_originis_explicittargetoriginr   c                    |                                 }|                                }|dk    r7|r | |j        |j        |j        d          S  | t
          j        d          S |dk    r | t
          j                  S d|v r|                    dd          }|d	                                         }t          |          d
k    r|d
         nd}t          |          dk    r|d         nd}	 t          |          }	 | |	||d          S # t          $ r  | t
          j                  cY S w xY w	 t          |          }	 | |	          S # t          $ r  | t
          j                  cY S w xY w)u   
        Parse a delivery target string.
        
        Formats:
        - "origin" → back to source
        - "local" → local files only
        - "telegram" → Telegram home channel
        - "telegram:123456" → specific Telegram chat
        r4   T)r/   r   r0   r1   )r/   r1   local)r/   :   r   r   N)r/   r   r0   r2   )
stripr+   r/   r   r0   r   LOCALsplitlenr   )
clsr3   r4   target_strippedtarget_lowerpartsplatform_strr   r0   r/   s
             r   parsezDeliveryTarget.parseS   s    !,,..&,,..8## 	Ds#_"N$."	    sHNdCCCC7""3//// /!!#))#q11E 8>>++L"%e**q..eAhhdG$'JJNNaI4#L11sHg`deeee 4 4 4sHN3333334
	0--H3)))) 	0 	0 	03//////	0s$   1D  D21D26E  E43E4c                     | j         rdS | j        t          j        k    rdS | j        r%| j        r| j        j         d| j         d| j         S | j        r| j        j         d| j         S | j        j        S )zConvert back to string format.r4   r6   r7   )r1   r/   r   r:   r   r0   r   )selfs    r   	to_stringzDeliveryTarget.to_string   s    > 	8=HN**7< 	LDN 	Lm)KKDLKK4>KKK< 	;m)::DL:::}""r#   N)__name__
__module____qualname____doc__r   __annotations__r   r   r&   r0   r1   r*   r2   classmethodr   rB   rE    r#   r   r.   r.   B   s           !GXc]!!!#Ix}###ItK00 003 00(? 00K[ 00 00 00 [00d
#3 
# 
# 
# 
# 
# 
#r#   r.   c                   d   e Zd ZdZddedeeef         fdZ	 	 	 dde	de
e         dee	         d	ee	         d
eee	ef                  dee	ef         fdZde	dee	         d	ee	         d
eee	ef                  dee	ef         f
dZde	de	defdZdede	d
eee	ef                  dee	ef         fdZdS )DeliveryRouterz
    Routes messages to appropriate destinations.
    
    Handles the logic of resolving delivery targets and dispatching
    messages to the right platform adapters.
    Nconfigadaptersc                 X    || _         |pi | _        t                      dz  dz  | _        dS )z
        Initialize the delivery router.
        
        Args:
            config: Gateway configuration
            adapters: Dict mapping platforms to their adapter instances
        cronoutputN)rP   rQ   r
   
output_dir)rD   rP   rQ   s      r   __init__zDeliveryRouter.__init__   s1      B)++f4x?r#   contenttargetsjob_idjob_namemetadatar   c                 `  K   i }|D ]}	 |j         t          j        k    r|                     ||||          }n|                     |||           d{V }d|d||                                <   i# t          $ r1}	dt          |	          d||                                <   Y d}	~	d}	~	ww xY w|S )a  
        Deliver content to all specified targets.
        
        Args:
            content: The message/output to deliver
            targets: List of delivery targets
            job_id: Optional job ID (for cron jobs)
            job_name: Optional job name
            metadata: Additional metadata to include
        
        Returns:
            Dict with delivery results per target
        NT)r   r   F)r   r%   )r/   r   r:   _deliver_local_deliver_to_platformrE   	Exceptionr&   )
rD   rW   rX   rY   rZ   r[   resultsr3   r   es
             r   deliverzDeliveryRouter.deliver   s      *  	 	F?hn44!00&(HUUFF#'#<#<VWh#W#WWWWWWWF  $$/ /((**++    $ VV/ /((**++++++ s   A%A00
B+:'B&&B+c                    t          j                                        d          }|r| j        |z  | dz  }n| j        dz  | dz  }|j                            dd           g }|r|                    d|            n|                    d           |                    d           |                    d	t          j                                        d
                      |r|                    d|            |r5|                                D ] \  }}	|                    d| d|	            !|                    d           |                    d           |                    d           |                    |           |                    d	                    |                     t          |          |dS )zSave content to local files.%Y%m%d_%H%M%Sz.mdmiscTparentsexist_okz# z# Delivery Output z**Timestamp:** z%Y-%m-%d %H:%M:%Sz**Job ID:** z**z:** z---
)path	timestamp)r   nowstrftimerU   parentmkdirappenditems
write_textjoinr&   )
rD   rW   rY   rZ   r[   rl   output_pathlineskeyr   s
             r   r]   zDeliveryRouter._deliver_local   s    LNN++O<<	 	G/F2	5F5F5FFKK/F2	5F5F5FFK   ===  	.LLh))))LL,---RUx|~~'>'>?R'S'SUUVVV 	2LL000111 	4&nn.. 4 4
U2#225223333RURWtyy//000 $$"
 
 	
r#   c                     t          j                                        d          }t                      dz  dz  }|                    dd           || d| dz  }|                    |           |S )z7Save full cron output to disk and return the file path.rd   rS   rT   Trf   _z.txt)r   rm   rn   r
   rp   rs   )rD   rW   rY   rl   out_dirrk   s         r   _save_full_outputz DeliveryRouter._save_full_output   sx    LNN++O<<	!##f,x7dT222F44Y4444   r#   r3   c                   K   | j                             |j                  }|st          d|j        j                   |j        st          d|j        j         d          t          |          t          k    rm|pi                     dd          }|                     ||          }t          
                    dt          |          |           |dt                   d| d	z   }t          |pi           }d
}d}	|j        r2d|v pd|v }
|j        }|j        t          j        k    o.t!          |j                  ot#          |           o
d|vod|vo|
 }|rj|}	t%          |dd          }|t'          d           ||j        |           d{V }|st'          d| d          t)          |          }||d<   d|d<   ns|j        t          j        k    rOt!          |j                  r;d|vr7d|vr3|
s1|                    d          }|t'          d          ||d<   d|d<   nd|vrd|vr|
s||d<   |                    |j        ||pd           d{V }t-          |          r|r|	rt/          |          rt%          |dd          }|t'          d           ||j        |	d           d{V }|st'          d|	 d          t)          |          |d<   d|d<   |                    |j        ||pd           d{V }t-          |          r+t'          t1          |          p|j        j         d          |S )z(Deliver content to a messaging platform.zNo adapter configured for zNo chat ID for z	 deliveryrY   unknownu4   Cron output truncated (%d chars) — full output: %sNz'

... [truncated, full output saved to ]Fdirect_messages_topic_id!telegram_direct_messages_topic_idr0   message_thread_idensure_dm_topicz6Telegram adapter cannot create named private DM topicsz,Failed to create Telegram private DM topic ''T"telegram_dm_topic_created_for_sendtelegram_reply_to_message_idzyTelegram private DM topic delivery requires telegram_reply_to_message_id; send to the bare chat or provide a reply anchor telegram_dm_topic_reply_fallback)r[   z7Telegram adapter cannot refresh named private DM topics)force_createz-Failed to refresh Telegram private DM topic 'z delivery failed)rQ   r    r/   r   r   r   r<   MAX_PLATFORM_OUTPUTr{   loggerinfoTRUNCATED_VISIBLEr   r0   r   TELEGRAMr   r   r!   RuntimeErrorr&   sendr"   r,   r(   )rD   r3   rW   r[   adapterrY   
saved_pathsend_metadatais_named_telegram_private_topic!named_telegram_private_topic_namehas_explicit_direct_topictarget_thread_idr   created_thread_idreply_anchorr   refreshed_thread_ids                    r   r^   z#DeliveryRouter._deliver_to_platform  s      -##FO44 	SQ&/:OQQRRR~ 	QOv/DOOOPPP w<<---n"))(I>>F//@@JKKNPST[P\P\^hiii***+KjKKKL 
 X^,,*/';?) 1	>*m; H6-G &  &/8#44 28HH2'(89992  }42 (}<	2
 21 , / #>4D1")'3Dd"K"K"*&P   +:/&.JZ*[*[$[$[$[$[$[$[!( &ZGWZZZ   $''8#9#9 -=k*FJBCC8#4448HH 5}44'}<<1 =  -001OPP'&J   .>k*DH@AAM116IQ^6^6^  hA6^-=k*||FNGmF[W[|\\\\\\\\v&& 	m/e5e 8??e
 #*'3Dd"K"K"*&Q   -<ON5!%- - - ' ' ' ' ' '#
 + &lHilll   .11D-E-Ek*FJBC&||FNGmNc_c|dddddddd"6** m"#5f#=#=#kFODYAkAkAklllr#   rF   )NNN)rG   rH   rI   rJ   r   r   r   r	   rV   r&   r   r.   r   rb   r]   r   r{   r^   rM   r#   r   rO   rO      s        
@ 
@} 
@Xs]8K 
@ 
@ 
@ 
@  !%"&-1( (( n%( 	(
 3-( 4S>*( 
c3h( ( ( (T,
,
 ,
 3-	,

 4S>*,
 
c3h,
 ,
 ,
 ,
\ c d    hh h 4S>*	h
 
c3hh h h h h hr#   rO   )!rJ   loggingpathlibr   r   dataclassesr   typingr   r   r   r	   hermes_cli.configr
   	getLoggerrG   r   r   r   rP   r   r   sessionr   r&   r*   r   r   r"   r(   r,   r.   rO   rM   r#   r   <module>r      s                 ! ! ! ! ! ! , , , , , , , , , , , , - - - - - -		8	$	$   + + + + + + + + " " " " " "(3- D    8C= T    5 5 5 5 5 5)s )x} ) ) ) )? ? ? ? ? ?
 M# M# M# M# M# M# M# M#`] ] ] ] ] ] ] ] ] ]r#   