
    iD[                     ,   d Z ddlZddlZddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZmZmZmZmZmZmZmZmZmZmZmZ  ej                    Z	 ddlmZ n# e$ r dZY nw xY wddlmZmZm Z  ddl!m"Z" h d	Z#d
 Z$ddZ%d Z&d Z'ddZ(de)de*fdZ+dS )zt
Hermes Web UI -- SSE streaming engine and agent thread runner.
Includes Sprint 10 cancel support via CANCEL_FLAGS.
    N)Path)parse_reasoning_effort)STREAMSSTREAMS_LOCKCANCEL_FLAGSCLI_TOOLSETSLOCKSESSIONSSESSION_DIR_get_session_agent_lock_set_thread_env_clear_thread_envclamp_reasoning_effortresolve_model_provider)AIAgent)Sessionget_session
title_from)set_last_workspace>   namerolecontentrefusal
tool_callstool_call_idc                     g }| D ]`}t          |t                    sd |                                D             }|                    d          r|                    |           a|S )a*  Return a deep copy of messages with only API-safe fields.

    The webui stores extra metadata on messages (attachments, timestamp, _ts)
    for display purposes. Some providers (e.g. Z.AI/GLM) reject unknown fields
    instead of ignoring them, causing HTTP 400 errors on subsequent messages.
    c                 ,    i | ]\  }}|t           v ||S  )_API_SAFE_MSG_KEYS).0kvs      */home/ubuntu/hermes-webui/api/streaming.py
<dictcomp>z._sanitize_messages_for_api.<locals>.<dictcomp>5   s)    MMMdaQ:L5L5LQ5L5L5L    r   )
isinstancedictitemsgetappend)messagescleanmsg	sanitizeds       r#   _sanitize_messages_for_apir/   *   st     E $ $#t$$ 	MMciikkMMM	==   	$LL###Lr%   c                    d}	 t          |           }n# t          $ r d}Y nw xY w	 t          j        |           }n# t          $ r d}Y nw xY w|rJ|rHt	          t          |dg           pg           t	          t          |dg           pg           k    r|}n|}n|p|}|dS |dk    }|rdnd}|rdnd}	d| d	|	 d
| }
|r	|
d| dz  }
|j        r|j        d         nd}t          |t                    rT|	                    d          dk    r;t          |	                    dd                                                    |
k    rdS |j                            d|
t          t          j                              d           t          |j        |j                  |_        |                                 t$          5  |t&          | <   t)          t&          d          rt'          j        |            ddd           dS # 1 swxY w Y   dS )zIAppend a visible assistant error to the session so reloads don't lose it.Nr+   
rate_limitu   ⏱️u   ⚠️zRate limit reachedErrorz** z:** z

**r   	assistantr    r   r   	timestampmove_to_end)r   	Exceptionr   loadlengetattrr+   r&   r'   r)   strstripr*   inttimer   titlesaver	   r
   hasattrr:   )
session_id
error_typemessagehintcached	persistedsis_rate_limiticonlabelr   lasts               r#   _persist_stream_errorrQ   ;   s   FZ((   L,,		   			   V  wy*b117R88CPZ\^@_@_@ece<f<fffAAAAy,.M$288(D$1>  wE.4..%..W..G #?4???"Z11:b>>TD$ $((6"2"2k"A"Ac$((S\^`JaJaFbFbFhFhFjFjnuFuFuJ%%    
 QW--AGFFHHH	 - - 8]++ 	- ,,,- - - - - - - - - - - - - - - - - -s-    ##< A
A?4H  HHc                    t          |pd                                          }|st          | pg           S t          | pg           }t          d t	          |          D             d          }|r=t          |                    dd          pd                                          |k    r|S |                    d|t          t          j                              d           |S )zEEnsure a returned final_response exists in persisted message history.r7   c              3   v   K   | ]4}t          |t                    r|                    d           dk    0|V  5dS )r   r6   N)r&   r'   r)   )r    r-   s     r#   	<genexpr>z1_ensure_final_response_message.<locals>.<genexpr>s   sU       	
 	
#t$$	
),K)G)G )G)G)G)G	
 	
r%   Nr   r6   r8   )	r?   r@   listnextreversedr)   r*   rA   rB   )r+   final_response
normalizedresultlast_assistants        r#   _ensure_final_response_messager\   k   s   ^)r**0022J $HN###(.b!!F	
 	
#F++	
 	
 	
 	 N  #n00B??E2FFLLNNR\\\
MM%%    
 Mr%   c                     d| dt          j        |d           d}| j                            |                    d                     | j                                         dS )z+Write one SSE event to the response stream.zevent: z
data: F)ensure_asciiz

zutf-8N)jsondumpswfilewriteencodeflush)handlereventdatapayloads       r#   _sseri      se    QQQtz$U'K'K'KQQQGMw//000Mr%   r7   c                     RST t          j        |          TTdS t          j                    Rt          5  Rt
          |<   ddd           n# 1 swxY w Y   RTfdS	 t                     }t          t          |          	                                
                                          |_        ||_        t          ||pt          |dd                    |_        t!                     }R                                ri Sdddi           	 t%                       t          5  t          j        |d           t          j        |d           ddd           dS # 1 swxY w Y   dS 	 dd	lm}	 t           |	                      }
n0# t,          $ r# t.          j                            d
d          }
Y nw xY wt3          t          |j                  d |
           t4          5  t.          j                            d          }t.          j                            d          }t.          j                            d          }t.          j                            d
          }t          |j                  t.          j        d<   dt.          j        d<    t.          j        d<   |
r|
t.          j        d
<   	 Sfd}S fd}t6          t-          d          t9          |          \  }}}d}	 ddlm}  ||          }|                    d          }|s|                    d          }|s|                    d          }n+# t>          $ r}tA          d| d           Y d}~nd}~ww xY wddl!m"}  |            }|                    di           }tG          |tH                    r|                    dtJ                    ntJ          }t7          ||||dd|d tM          t          |dd          pd          ||          }d|j         d }d!|j         d"}d}t          |d#d          } | r$|                    d$i           }!|!                    d%i           }"tG          |"tH                    r| |"v r|"|          }#tG          |#tH                    r|#                    d&d          p|#                    d'd          g}$|#                    d(          r|$'                    d)|#d(                     |#                    d*          r|$'                    d+|#d*                     d,(                    d- |$D                       }nt          |#          }|r||_)        |*                    ||z   |tW          |j,                   |.          }%t[          |%                    d/          p|j,        |%                    d0                    |_,        t          |d1d          }&d2}'|&r|& k    r }(|&})t\          |( d3z  }*t\          |) d3z  }+|)|_/        t`          5  |(tb          v rtc          j        |(          tb          |)<   ddd           n# 1 swxY w Y   |*2                                r;|+2                                s'	 |*3                    |+           n# th          $ r Y nw xY wd}'|'s*t          |d4d          },|,rt          |,d5d          dk    rd}'|'r Sd6dd7i           tk          j5                    }-|j,        D ]S}.tG          |.tH                    r<|.                    d8          s'|.                    d9          stm          |-          |.d8<   Tto          |j,        |j8                  |_8        t          |d:d          pd}/t          |d;d          pd}0t          |d<d          }1|j9        pd|/z   |_9        |j:        pd|0z   |_:        |1r|j;        pd|1z   |_;        g }2i }3i }4i }5ty          |j,                  D ]y\  }6}7|7                    d=          d>k    r|7                    d?d          }8tG          |8tz                    r|8D ]}}9tG          |9tH                    rf|9                    d@          dAk    rM|9                    dBd          }:|9                    dCd          |3|:<   |9                    dDi           |4|:<   |6|5|:<   ~|7                    dEg           D ]};tG          |;tH                    s|;                    dBd          p|;                    dFd          }:|;                    dGi           }<|<                    dCd          }=	 ddl>}>|>?                    |<                    dHdI          pdI          }?n# t>          $ r i }?Y nw xY w|:r|=r|=|3|:<   |?|4|:<   |6|5|:<   ǐ|7                    d=          dJk    r|7                    dK          p|7                    dLd          }:|3                    |:d          }=|=r|=dJk    r|5                    |:dM          }@|4                    |:i           }?t          |7                    d?d                    }A	 t}          j?        |A          }Bt          |B                    dN          p+|B                    dO          p|B                    dP          p|A          ddQ         }Cn# t>          $ r |AddQ         }CY nw xY wi }DtG          |?tH                    rct{          |?@                                          ddR         D ]9\  }E}Ft          |F          }G|GddS         t          |G          dSk    rdTndz   |D|E<   :|2'                    |=|C|:|@|DdU           {|2|_B        |rt          |j,                  D ]}7|7                    d=          dVk    rot          |7                    d?d                    }H|D                    dW          d         E                                }I|IddX         |Hv s|HddX         |v r||7dY<    n|F                                 	 ddZl!mG}J  |J                                d[          rGdd\lHmI}K  |K|j/        |j9        pd|j:        pd|j;        ||j8        t          |j,                  ]           n# t>          $ r Y nw xY w|/|0|1d^}Lt          |d4d          }M|MrBt          |Md_d          pd|Ld_<   t          |Md`d          pd|Ld`<   t          |Mdad          pd|Lda<    Sdb|J                                |j,        |2dcz  |Ldd           |!t.          j                            dd           n|t.          j        d<   |!t.          j                            dd           n|t.          j        d<   |!t.          j                            dd           n|t.          j        d<   |!t.          j                            d
d           n|t.          j        d
<   n# |!t.          j                            dd           n|t.          j        d<   |!t.          j                            dd           n|t.          j        d<   |!t.          j                            dd           n|t.          j        d<   |!t.          j                            d
d           n|t.          j        d
<   w xY wddd           n# 1 swxY w Y   n# t>          $ r}NtA          det          jL                    z   d           t          |N          }Odf|OM                                v pdg|Ov pdht          |N          jO        v }P|Pr%di}Qt           dj|O|Q            Sdk|Odj|Qdl           n t           dP|O            Sdk|OdPdm           Y d}N~Nnd}N~Nww xY wt%                       t          5  t          j        |d           t          j        |d           ddd           dS # 1 swxY w Y   dS # t%                       t          5  t          j        |d           t          j        |d           ddd           w # 1 swxY w Y   w xY w)nzIRun agent in background thread, writing SSE events to STREAMS[stream_id].Nc                                                      r| dvrd S 	                     | |f           d S # t          $ r Y d S w xY w)N)cancelerror)is_set
put_nowaitr;   )rf   rg   cancel_eventqs     r#   putz!_run_agent_streaming.<locals>.put   sj       	U2E%E%EF	LL%''''' 	 	 	DD	s   6 
AAreasoning_effortr7   rl   rH   zCancelled before startr   )get_active_hermes_homeHERMES_HOME1)TERMINAL_CWDHERMES_EXEC_ASKHERMES_SESSION_KEYru   rw   rx   ry   c                 ,    | d S  dd| i           d S )Ntokentextr   )r|   rr   s    r#   on_tokenz&_run_agent_streaming.<locals>.on_token   s)    <FGfd^,,,,,r%   c                    i }t          |t                    rct          |                                          d d         D ]9\  }}t	          |          }|d d         t          |          dk    rdndz   ||<   : d| ||d           ddlm}m}m	}	  |          rM|	5  t          |
                    i                     }
d d d            n# 1 swxY w Y   |
r d	|
           d S d S d S )
N   x   ...r7   tool)r   previewargsr   )has_pending_pending_lockapproval)r&   r'   rU   r(   r?   r=   tools.approvalr   r   r   r)   )r   r   r   	args_snapr!   r"   s2_has_pendingr   r   prr   rF   s              r#   on_toolz%_run_agent_streaming.<locals>.on_tool   st   	dD)) \ $TZZ\\ 2 22A2 6 \ \1 VVBttHs2wws{{eeXZ4[Yq\\FTgyQQRRRWWWWWWWWWW<
++ + ? ? j"!=!=>>? ? ? ? ? ? ? ? ? ? ? ? ? ? ? +J*****	+ ++ +s   #$CCCz?AIAgent not available -- check that hermes-agent is on sys.path)resolve_runtime_provider)	requestedapi_keyproviderbase_urlz2[webui] WARNING: resolve_runtime_provider failed: T)rd   )
get_configplatform_toolsetscli)modelr   r   r   platform
quiet_modeenabled_toolsetsfallback_modelrF   reasoning_configstream_delta_callbacktool_progress_callbackz[Workspace: z]
z#Active workspace at session start: ab  
Every user message is prefixed with [Workspace: /absolute/path] indicating the workspace the user has selected in the web UI at the time they sent that message. This tag is the single authoritative source of the active workspace and updates with every message. It overrides any prior workspace mentioned in this system prompt, memory, or conversation history. Always use the value from the most recent [Workspace: ...] tag as your default working directory for ALL file operations: write_file, read_file, search_files, terminal workdir, and patch. Never fall back to a hardcoded path when this tag is present.personalityagentpersonalitiessystem_promptprompttonezTone: stylezStyle: 
c              3      K   | ]}||V  	d S Nr   )r    r   s     r#   rT   z'_run_agent_streaming.<locals>.<genexpr>$  s'      7O7OaQ7O7O7O7O7O7O7Or%   )user_messagesystem_messageconversation_historytask_idpersist_user_messager+   rX   rF   Fz.jsoncontext_compressorcompression_count
compressedz4Context auto-compressed to continue the conversationr9   _tssession_prompt_tokenssession_completion_tokenssession_estimated_cost_usdr   r6   r   typetool_useidr   inputr   call_idfunction	argumentsz{}r   r   tool_use_idr5   outputrZ   rm         r   r   )r   snippettidassistant_msg_idxr   userz

[Attached files:<   attachments)load_settingssync_to_insights)sync_session_usage)rF   input_tokensoutput_tokensestimated_costr   rC   message_count)r   r   r   context_lengththreshold_tokenslast_prompt_tokensdone)r+   r   )sessionusagez[webui] stream error:
z
rate limit429RateLimitErrorz*Rate limit reached. Try again in a moment.r1   apperror)rH   r   rI   )rH   r   )Qr   r)   	threadingEventr   r   r   r?   r   
expanduserresolve	workspacer   r   r>   rs   r   rn   r   popapi.profilesrt   ImportErrorosenvironr   	_ENV_LOCKr   r   hermes_cli.runtime_providerr   r;   print
api.configr   r&   r'   r   r   r*   joinephemeral_system_promptrun_conversationr/   r+   r\   r   rF   r	   r
   existsrenameOSErrorrB   rA   r   rC   r   r   r   	enumeraterU   r_   loadsr(   r=   r   rW   splitr@   rD   r   api.state_syncr   compact	traceback
format_exclowerr   __name__rQ   )UrF   msg_textr   r   	stream_idr   rs   rL   _agent_lockrt   _profile_homeold_cwdold_exec_askold_session_keyold_hermes_homer}   r   resolved_modelresolved_providerresolved_base_urlresolved_api_keyr   _rt_e_get_config_cfg_pt	_toolsetsr   workspace_ctxworkspace_system_msg_personality_prompt_pname
_agent_cfg_personalities_pval_partsrZ   
_agent_sid_compressedold_sidnew_sidold_pathnew_path_compressor_now_mr   r   r   r   pending_namespending_argspending_asst_idxmsg_idxmcr   r   tcfnr   _jr   asst_idxrawrdr   r   r!   r"   r   r   	base_text_load_settingsr   r   _cceerr_strrM   rI   rp   rr   rq   sU   `                                                                                 @@@r#   _run_agent_streamingr'     s   IAy ?$$L	 / /".Y/ / / / / / / / / / / / / / /     D.
##$y//4466>>@@AA3B+=r B B
 

 .j99    	C9&>?@@@f	 	 	. 	.K	4(((Y---	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	.c		>;;;;;; 6 6 8 899MM 	> 	> 	>JNN="==MMM	> 	Q[)))%		
 	
 	
 	
  O	> O	>JNN>22'(9::,JNN+?@@/JNN=99/'*1;'7'7"*^
$*-"*&
'-7"*)
* 8*7bj'D>- - - - -
+ + + + + + !"cdddCYZ_C`C`@N-/@  $	]PPPPPP..9JKKK#&779#5#5 ( <(+
(;(;%( <(+
(;(;% ] ] ]O2OOW[\\\\\\\\\] =<<<<<;==D ((.33C8B38M8M_|444S_I$**(!*  $%!7CUWY8Z8Z8`^`!a!a&.'.  E& <1;;;;MPak P P P ! #'Qt44F 9!XXgr22
!+!D!Dnd33 
9.8P8P*62E!%.. 9"'))OR"@"@"[EIIhXZD[D[!\ 99V,, D"MM*B5=*B*BCCC 99W-- F"MM*DE'N*D*DEEE.2ii7O7O67O7O7O.O.O++.1%jj+" D0C-++*X53%?
%K%K"%- ,  F 8

:&&4!*

+,, AJ !d;;JK #jJ66$$&G):):)::&G):):)::& B B(**,4L,A,A)B B B B B B B B B B B B B B B ??$$ X__->->  1111"   " '%e-A4HH '7;8KQ#O#ORS#S#S"&K LU#   
 9;;Dj 0 0b$'' 0{0C0C 0BFFSXMM 0&)$iiB{O QW55AG"5*A1EEJL#E+FJJOaM$U,H$OONn1\AAN 3!}DAO L$%$4$9^#K  JML!'
33 1 1
55==K//i,,A!!T** @!" @ @A)!T22 @quuV}}
7R7R&'eeD"oo56UU625F5Fc 245EE'24F4FS 18? 0 5eeL"55 < <)"d33 %$ ffT2..G"&&B2G2GVVJ33!vvfb11&----#%88BFF;,E,E,M#N#NDD( & & &#%DDD& <4 <15M#.04L-4;,S1< UU6]]f,,%%//K1553K3KC(,,S"55D !46>> /33C<<H'++C44DaeeIr2233C,!Z__"%bffX&6&6&d"&&:J:J&dbffU\oo&dad"e"efjgjfj"k$ , , ,"%dsd), !#I!$-- W$($6$6rr$: W WDAq!$QB+-dsd8B#uuSU+VIaLL%% $-5y' '    &AL  "!!*-- " "AuuV}}.."%aeeIr&:&:";";$,NN3I$J$J1$M$S$S$U$U	$SbS>W448P8P/:Am,!EFFHHHFFFFFF!>##''(:;; 
AAAAAA&&#$<%&^%8q&'o&:'('7#g&)!*oo       %1MesttE%!5t<<C Y*1#7G*K*K*Pq&',3C9KQ,O,O,TST().5c;OQR.S.S.XWX*+CAIIKKqzYc2d2d$dotuuvvv
~t D D D D/6"*^,#RZ^^4Et%L%L%L%L2>"*./&
7KT(R(R(R(R5D"*12&
}d(K(K(K(K.="*]++ 
~t D D D D/6"*^,#RZ^^4Et%L%L%L%L2>"*./&
7KT(R(R(R(R5D"*12&
}d(K(K(K(K.="*]+====_O	> O	> O	> O	> O	> O	> O	> O	> O	> O	> O	> O	> O	> O	> O	>b  C C C')*>*@*@@MMMMa&& %7s5G;KsO_cghicjcjcsOs 
	C?D!*lGTJJJC
"$      "*gw???C
AABBB!C$ 	 	. 	.K	4(((Y---	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	 	. 	.K	4(((Y---	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	. 	.s  AAA B2{ (+E  E$'E$.F { *F96{ 8F99/{ (C{66w7-AMw7
M+M&!w7&M++J*w7&Y;w7Y	w7Y	+w7;Zw7
Zw7ZJ'w7/e65w76f	w7f	Cw7A*j>=w7>kw7kEw7,A*rw7
r$!w7#r$$B
w7.C	{7C
{{{ {{ {{ 8 
~&B+~8 ~8 3+++/2/8AA@+AA@9AAAAA	A	AAAAA	AAAr   returnc                 H   t           5  | t          vr	 ddd           dS t          j        |           }|r|                                 t          j        |           }|r+	 |                    dddif           n# t          $ r Y nw xY wddd           n# 1 swxY w Y   dS )zISignal an in-flight stream to cancel. Returns True if the stream existed.NFrl   rH   zCancelled by userT)r   r   r   r)   setro   r;   )r   flagrq   s      r#   cancel_streamr,    s   	  G##        	** 	HHJJJK	"" 	h4G(HIJJJJ                  4s;   BA B!A;:B;
BBBBBBr   )Nr7   ),__doc__r_   r   queuer   rB   r   pathlibr   hermes_constantsr   r   r   r   r   r   r	   r
   r   r   r   r   r   r   Lockr   	run_agentr   r   
api.modelsr   r   r   api.workspacer   r   r/   rQ   r\   ri   r'  r?   boolr,  r   r%   r#   <module>r6     s     				                 3 3 3 3 3 3                            IN	!!!!!!!   GGG 7 7 7 7 7 7 7 7 7 7 , , , , , ,
 ZYY   "-- -- -- --`  2  X. X. X. X.DS T      s   A A$#A$