+
    i                       R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RIH	t	H
t
HtHt  ^ RIHt Rt^ RIHtHt ^ RIHtHt ^ RIHtHt ^ R	IHtHt ^ R
IHt ^ RIH t  ^ RI!H"t"H#t#H$t$ ]PJ                  ! ]&4      t'Rt(Rt)^dt*Rt+R R lt, ! R R4      t-RRRR/t.]'       d   ]P^                  R 4       t0MRt0R(R R llt1]'       d   ]P^                  R 4       t2MRt2RRRR/t3]'       d   ]P^                  R  4       t4MRt4 ! R! R"4      t5]5! 4       t6R# R$ lt7 ^ R%I8H9t:H;t<H=t>H?t@HAtBHCtDHEtFHGtH RtI ! R& R']4      tJR#   ] d	    RtRt ELi ; i  ] d    RtI L*i ; i))u  
OpenAI-compatible API server platform adapter.

Exposes an HTTP server with endpoints:
- POST /v1/chat/completions        — OpenAI Chat Completions format (stateless; opt-in session continuity via X-Hermes-Session-Id header)
- POST /v1/responses               — OpenAI Responses API format (stateful via previous_response_id)
- GET  /v1/responses/{response_id} — Retrieve a stored response
- DELETE /v1/responses/{response_id} — Delete a stored response
- GET  /v1/models                  — lists hermes-agent as an available model
- POST /v1/runs                    — start a run, returns run_id immediately (202)
- GET  /v1/runs/{run_id}/events    — SSE stream of structured lifecycle events
- GET  /health                     — health check

Any OpenAI-compatible frontend (Open WebUI, LobeChat, LibreChat,
AnythingLLM, NextChat, ChatBox, etc.) can connect to hermes-agent
through this adapter by pointing at http://localhost:8642/v1.

Requires:
- aiohttp (already available in the gateway)
N)AnyDictListOptional)webTF)PlatformPlatformConfig)BasePlatformAdapter
SendResult)load_configsave_config)curated_models_for_providerlist_available_providers	SessionDBMemoryStore)
skill_viewskills_categoriesskills_list	127.0.0.1i!  i@B c                $    V ^8  d   QhR\         /#    returnbool)formats   "9/home/ubuntu/hermes-agent/gateway/platforms/api_server.py__annotate__r   :   s      t     c                     \         # )z/Check if API server dependencies are available.)AIOHTTP_AVAILABLE r    r   check_api_server_requirementsr$   :   s    r    c                      a  ] tR t^?t o Rt]R3V 3R lR lltV 3R lR ltV 3R lR ltV 3R	 lR
 lt	V 3R lR lt
V 3R lR ltV 3R lR ltV 3R lR ltRtV tR# )ResponseStoreaI  
SQLite-backed LRU store for Responses API state.

Each stored response includes the full internal conversation history
(with tool calls and results) so it can be reconstructed on subsequent
requests via previous_response_id.

Persists across gateway restarts.  Falls back to in-memory SQLite
if the on-disk path is unavailable.
Nc                &   < V ^8  d   QhRS[ RS[/# )r   max_sizedb_path)intstr)r   __classdict__s   "r   r   ResponseStore.__annotate__K   s       c r    c                   Wn         Vf    ^ RIHp \        V! 4       R,          4      p \
        P                  ! VRR7      V n        V P                  P                  R4       V P                  P                  R4       V P                  P                  R4       V P                  P                  4        R #   \         d    Rp Li ; i  \         d!    \
        P                  ! RRR7      T n         Li ; i)	N)get_hermes_homezresponse_store.dbz:memory:F)check_same_threadzPRAGMA journal_mode=WALzCREATE TABLE IF NOT EXISTS responses (
                response_id TEXT PRIMARY KEY,
                data TEXT NOT NULL,
                accessed_at REAL NOT NULL
            )zCREATE TABLE IF NOT EXISTS conversations (
                name TEXT PRIMARY KEY,
                response_id TEXT NOT NULL
            ))
	_max_sizehermes_cli.configr/   r+   	Exceptionsqlite3connect_connexecutecommit)selfr(   r)   r/   s   &&& r   __init__ResponseStore.__init__K   s    !?%=o/2EEF	N EJDJ 	

45

	
 	

	
 	

)  %$%  	N uMDJ	Ns"   B4 C 4CC(C21C2c                L   < V ^8  d   QhRS[ RS[S[S[ S[3,          ,          /# r   response_idr   )r+   r   r   r   )r   r,   s   "r   r   r-   g   s(     " "s "xS#X'? "r    c                4   V P                   P                  RV34      P                  4       pVf   R# ^ RIpV P                   P                  RVP                  ! 4       V34       V P                   P	                  4        \
        P                  ! V^ ,          4      # )z?Retrieve a stored response by ID (updates access time for LRU).z0SELECT data FROM responses WHERE response_id = ?Nz:UPDATE responses SET accessed_at = ? WHERE response_id = ?)r6   r7   fetchonetimer8   jsonloads)r9   r>   rowrA   s   &&  r   getResponseStore.getg   s|    jj  >

(* 	 ;

HYY[+&	
 	

zz#a&!!r    c                @   < V ^8  d   QhRS[ RS[S[ S[3,          RR/# )r   r>   datar   Nr+   r   r   )r   r,   s   "r   r   r-   v   s*      s $sCx. T r    c           	        ^ RI pV P                  P                  RV\        P                  ! V\
        R7      VP                   ! 4       34       V P                  P                  R4      P                  4       ^ ,          pW@P                  8  d.   V P                  P                  RW@P                  ,
          34       V P                  P                  4        R# )z5Store a response, evicting the oldest if at capacity.NzRINSERT OR REPLACE INTO responses (response_id, data, accessed_at) VALUES (?, ?, ?))defaultSELECT COUNT(*) FROM responseszoDELETE FROM responses WHERE response_id IN (SELECT response_id FROM responses ORDER BY accessed_at ASC LIMIT ?))	rA   r6   r7   rB   dumpsr+   r@   r1   r8   )r9   r>   rH   rA   counts   &&&  r   putResponseStore.putv   s    

`$**T37E	

 

""#CDMMOPQR>>!JJW')
 	

r    c                &   < V ^8  d   QhRS[ RS[/# r=   r+   r   )r   r,   s   "r   r   r-      s     # ## #$ #r    c                    V P                   P                  RV34      pV P                   P                  4        VP                  ^ 8  # )zDRemove a response from the store. Returns True if found and deleted.z+DELETE FROM responses WHERE response_id = ?)r6   r7   r8   rowcount)r9   r>   cursors   && r   deleteResponseStore.delete   s>    ##9K>
 	

""r    c                6   < V ^8  d   QhRS[ RS[S[ ,          /# )r   namer   )r+   r   )r   r,   s   "r   r   r-      s     ' 'S 'Xc] 'r    c                ~    V P                   P                  RV34      P                  4       pV'       d
   V^ ,          # R# )z3Get the latest response_id for a conversation name.z4SELECT response_id FROM conversations WHERE name = ?Nr6   r7   r@   )r9   rY   rD   s   && r   get_conversationResponseStore.get_conversation   s:    jj  BTG

(* 	 s1v&$&r    c                *   < V ^8  d   QhRS[ RS[ RR/# )r   rY   r>   r   Nr+   )r   r,   s   "r   r   r-      s"      S s t r    c                t    V P                   P                  RW34       V P                   P                  4        R# )z2Map a conversation name to its latest response_id.zFINSERT OR REPLACE INTO conversations (name, response_id) VALUES (?, ?)N)r6   r7   r8   )r9   rY   r>   s   &&&r   set_conversationResponseStore.set_conversation   s/    

T	
 	

r    c                   < V ^8  d   QhRR/# r   r   Nr#   )r   r,   s   "r   r   r-      s      t r    c                `     V P                   P                  4        R#   \         d     R# i ; i)zClose the database connection.N)r6   closer3   r9   s   &r   rf   ResponseStore.close   s)    	JJ 		s    --c                    < V ^8  d   QhRS[ /# r   r*   )r   r,   s   "r   r   r-      s     $ $ $r    c                z    V P                   P                  R 4      P                  4       pV'       d
   V^ ,          # ^ # )rL   r[   )r9   rD   s   & r   __len__ResponseStore.__len__   s1    jj  !ABKKMs1v#!#r    )r6   r1   )__name__
__module____qualname____firstlineno____doc__MAX_STORED_RESPONSESr:   rE   rO   rV   r\   ra   rf   rl   __static_attributes____classdictcell__r,   s   @r   r&   r&   ?   sa     	 (<D  8" " "# #' '  $ $r    r&   zAccess-Control-Allow-Methodsz&GET, POST, PATCH, PUT, DELETE, OPTIONSzAccess-Control-Allow-Headersz,Authorization, Content-Type, Idempotency-Keyc                  "   V P                   P                  R4      pV P                  P                  RR4      pRpVe@   VP                  V4      '       g   \        P
                  ! RR7      # VP                  V4      pV P                  R8X  d4   Vf   \        P
                  ! RR7      # \        P
                  ! ^VR7      # V! V 4      G Rj  xL
 pVe   VP                  P                  V4       V#  L%5i)	zJAdd CORS headers for explicitly allowed origins; handle OPTIONS preflight.api_server_adapterOrigin Ni  statusOPTIONSr|   headers)	apprE   r   _origin_allowedr   Response_cors_headers_for_originmethodupdate)requesthandleradapterorigincors_headersresponses   &&    r   cors_middlewarer      s      ++//"67$$Xr2**622||3//";;FCL>>Y&#||3//<<sLAA ))###L1 *s   AC6A7C6C4&C6c                v    V ^8  d   QhR\         R\         R\         R\         R\        \         \        3,          /# )r   messageerr_typeparamcoder   rI   )r   s   "r   r   r      s>     	 	3 	# 	PS 	be 	quvy{~v~q 	r    c           	         RRV RVRVRV//# )zOpenAI-style error envelope.errorr   typer   r   r#   )r   r   r   r   s   &&&&r   _openai_errorr      s*     	wHUD	
 r    c                h  "   V P                   R9   dY   V P                  P                  R4      pVe:    \        V4      \        8  d$   \
        P                  ! \        RRR7      RR7      #  V! V 4      G Rj  xL
 #   \         d'    \
        P                  ! \        RR	R7      R
R7      u # i ; i L85i)zAReject overly large request bodies early based on Content-Length.zContent-LengthNzRequest body too large.body_too_larger   i  r{   zInvalid Content-Length header.invalid_content_length  )POSTPUTPATCH)	r   r   rE   r*   MAX_REQUEST_BYTESr   json_responser   
ValueError)r   r   cls   && r   body_limit_middlewarer      s      >>55$$%56B~I2w!22"00?X_o1py|}} 3 W%%% " I,,];[bz-{  EH  I  II%s4   1B26A< *B27B08B2<.B-*B2,B--B2zX-Content-Type-OptionsnosniffzReferrer-Policyzno-referrerc                   "   V! V 4      G Rj  xL
 p\         P                  4        F   w  r4VP                  P                  W44       K"  	  V#  L>5i)z9Add security headers to all responses (including errors).N)_SECURITY_HEADERSitemsr   
setdefault)r   r   r   kvs   &&   r   security_headers_middlewarer      sG      !))%++-DA''- . *s   AA?Ac                   R   a  ] tR t^t o RtR	V 3R lR lltR tV 3R lR ltRtV t	R# )
_IdempotencyCachez=In-memory idempotency cache with TTL and basic LRU semantics.c                &   < V ^8  d   QhRS[ RS[ /# )r   	max_itemsttl_secondsrj   )r   r,   s   "r   r   _IdempotencyCache.__annotate__   s      # 3 r    c                B    ^ RI Hp V! 4       V n        W n        Wn        R# )    )OrderedDictN)collectionsr   _store_ttl_max)r9   r   r   r   s   &&& r   r:   _IdempotencyCache.__init__   s    +!m		r    c                   ^ RI pVP                  4       pV P                  P                  4        UUu. uF'  w  r4W$R,          ,
          V P                  8  g   K%  VNK)  	  pppV F  pV P                  P	                  VR4       K!  	  \        V P                  4      V P                  8  d   V P                  P                  RR7       KB  R# u uppi )r   NtsF)last)rA   r   r   r   poplenr   popitem)r9   _tnowr   r   expireds   &     r   _purge_IdempotencyCache._purge  s    ggi!%!2!2!4R!4g		8Q11!4RAKKOOAt$ $++*KKU+ + Ss   "CCc                &   < V ^8  d   QhRS[ RS[ /# )r   keyfingerprintr_   )r   r,   s   "r   r   r     s     	 	C 	c 	r    c                2  "   V P                  4        V P                  P                  V4      pV'       d   VR ,          V8X  d
   VR,          # V! 4       G Rj  xL
 p^ RIpRVR VRVP                  4       /V P                  V&   V P                  4        V#  L=5i)fprespNr   )r   r   rE   rA   )r9   r   r   compute_coroitemr   r   s   &&&&   r   
get_or_set_IdempotencyCache.get_or_set  sy     {{s#DJ+-<!^#"D$T2779MC	 $s   ABB>B)r   r   r   N)i  ,  )
rn   ro   rp   rq   rr   r:   r   r   rt   ru   rv   s   @r   r   r      s!     G ,	 	r    r   c                t    V ^8  d   QhR\         \        \        3,          R\        \        ,          R\        /# )r   bodykeysr   r   r+   r   r   )r   s   "r   r   r     s-     < <DcN <$s) < <r    c                     ^ RI Hp V Uu/ uF  q3V P                  V4      bK  	  ppV! \        V4      P	                  R4      4      P                  4       # u upi )r   )sha256utf-8)hashlibr   rE   reprencode	hexdigest)r   r   r   r   subsets   &&   r   _make_request_fingerprintr     sK    &*+d!ndF+$v,%%g./99;; ,s   A)	list_jobsget_job
create_job
update_job
remove_job	pause_job
resume_jobtrigger_jobc                     a a ] tR tRt oRtV3R lV 3R llt]V3R lR l4       tV3R lR ltV3R	 lR
 lt	V3R lR lt
V3R lR ltV3R lR lt]V3R lR l4       t]V3R lR l4       t]RV3R lR ll4       tR t]RV3R lR ll4       tRV3R lR lltV3R lR ltV3R lR ltV3R  lR! ltV3R" lR# ltV3R$ lR% ltV3R& lR' ltV3R( lR) ltV3R* lR+ ltV3R, lR- ltV3R. lR/ ltV3R0 lR1 ltV3R2 lR3 ltV3R4 lR5 ltV3R6 lR7 lt V3R8 lR9 lt!V3R: lR; lt"V3R< lR= lt#V3R> lR? lt$V3R@ lRA lt%V3RB lRC lt&V3RD lRE lt'V3RF lRG lt(V3RH lRI lt)RV3RJ lRK llt*V3RL lRM lt+V3RN lRO lt,V3RP lRQ lt-].t/]0! RR4      Pc                  RS4      t20 Rmt3^t4RTt5V3RU lRV lt6V3RW lRX lt7V3RY lRZ lt8V3R[ lR\ lt9V3R] lR^ lt:V3R_ lR` lt;V3Ra lRb lt<V3Rc lRd lt=V3Re lRf lt>V3Rg lRh lt?]V3Ri lRj l4       t@RV3Rk lRl lltA^
tBRmtCV3Rn lRo ltDV3Rp lRq ltEV3Rr lRs ltFV3Rt lRu ltGV3Rv lRw ltHV3Rx lRy ltIRV3Rz lR{ lltJV3R| lR} ltKR~tLVtMV ;tN# )APIServerAdapteri3  z
OpenAI-compatible HTTP API server adapter.

Runs an aiohttp web server that accepts OpenAI-format requests
and routes them through hermes-agent's AIAgent.
c                    < V ^8  d   QhRS[ /# )r   config)r   )r   r,   s   "r   r   APIServerAdapter.__annotate__;  s     9 9~ 9r    c                  < \         SV `  V\        P                  4       VP                  ;'       g    / pVP                  R \        P                  ! R\        4      4      V n	        \        VP                  R\        P                  ! R\        \        4      4      4      4      V n        VP                  R\        P                  ! RR4      4      V n        V P                  VP                  R\        P                  ! RR4      4      4      V n        R	V n        R	V n        R	V n        \)        4       V n        / V n        / V n        R	V n        R	V n        R	# )
hostAPI_SERVER_HOSTportAPI_SERVER_PORTr   API_SERVER_KEYrz   cors_originsAPI_SERVER_CORS_ORIGINSN)superr:   r   
API_SERVERextrarE   osgetenvDEFAULT_HOST_hostr*   r+   DEFAULT_PORT_port_api_key_parse_cors_origins_cors_origins_app_runner_siter&   _response_store_run_streams_run_streams_created_session_db_memory_store)r9   r   r   	__class__s   && r   r:   APIServerAdapter.__init__;  s    !4!45""))FBII6G,VW
eii		:KSQ]M^0_`a
"YYubii8H".MN.2.F.FIInbii0I2&NO/
 26	26.2
,HJ68!0448r    c                :   < V ^8  d   QhRS[ RS[S[R3,          /# )r   valuer   .)r   tupler+   )r   r,   s   "r   r   r   P  s'     O O3 O5c? Or    c                   V '       g   R# \        V \        4      '       d   V P                  R4      pM0\        V \        \        \
        34      '       d   T pM\        V 4      .p\        ;QJ d    . R V 4       F  NK  	  5# ! R V 4       4      # )z6Normalize configured CORS origins into a stable tuple.,c              3      "   T F?  p\        V4      P                  4       '       g   K$  \        V4      P                  4       x  KA  	  R # 5iN)r+   strip).0r   s   & r   	<genexpr>7APIServerAdapter._parse_cors_origins.<locals>.<genexpr>\  s.     N54CIOO<M&SY__&&5s
   !A	!A	r#   )
isinstancer+   splitlistr	  set)r  r   s   & r   r   $APIServerAdapter._parse_cors_originsO  sm     IeS!!KK$EeS122EZLEuN5NuNuN5NNNr    c                L   < V ^8  d   QhRS[ RS[S[S[ S[ 3,          ,          /# r   r   r   )r+   r   r   )r   r,   s   "r   r   r   ^  s(      s xS#X7O r    c                    V'       d   V P                   '       g   R# RV P                   9   d   \        \        4      pRVR&   RVR&   V# WP                   9  d   R# \        \        4      pWR&   RVR&   RVR&   V# )z2Return CORS headers for an allowed browser origin.N*zAccess-Control-Allow-Origin600zAccess-Control-Max-Agery   Vary)r   dict_CORS_HEADERS)r9   r   r   s   && r   r   )APIServerAdapter._cors_headers_for_origin^  s    T///$$$$=)G58G1205G,-N+++}%17-.",1()r    c                &   < V ^8  d   QhRS[ RS[/# r  rR   )r   r,   s   "r   r   r   r  s     I Ic Id Ir    c                    V'       g   R# V P                   '       g   R# RV P                   9   ;'       g    WP                   9   # )zDAllow non-browser clients and explicitly configured browser origins.TFr  )r   )r9   r   s   &&r   r    APIServerAdapter._origin_allowedr  s9    !!!d(((HHF6H6H,HHr    c                2   < V ^8  d   QhRRRS[ R,          /# r   r   web.Requestr   web.Responser   )r   r,   s   "r   r   r     s      
 
= 
Xn5M 
r    c           	     "   V P                   '       g   R# VP                  P                  RR4      pVP                  R4      '       d*   VR,          P	                  4       pW0P                   8X  d   R# \
        P                  ! RRRR	R
RR//RR7      # )z
Validate Bearer token from Authorization header.

Returns None if auth is OK, or a 401 web.Response on failure.
If no API key is configured, all requests are allowed.
NAuthorizationrz   zBearer :   NNr   r   zInvalid API keyr   invalid_request_errorr   invalid_api_keyi  r{   )r   r   rE   
startswithr  r   r   )r9   r   auth_headertokens   &&  r   _check_authAPIServerAdapter._check_auth  s     }}}oo))/2>!!),,O))+E%  y"3V=TV\^opq
 	
r    c                    < V ^8  d   QhRS[ /# r   r   )r   r,   s   "r   r   r     s          r    c                T    V P                   f   \        4       V n         V P                   # )zCreate the session DB lazily.)r  r   rg   s   &r   _get_session_db APIServerAdapter._get_session_db  s$    #({Dr    c                    < V ^8  d   QhRS[ /# r   r   )r   r,   s   "r   r   r     s     " "; "r    c                    V P                   f*   \        4       V n         V P                   P                  4        V P                   # )zCreate the memory store lazily.)r  r   load_from_diskrg   s   &r   _get_memory_store"APIServerAdapter._get_memory_store  s6    %!,D--/!!!r    c                r   < V ^8  d   QhRS[ S[S[S[3,          ,          RS[ S[S[S[3,          ,          /# )r   sessionr   )r   r   r+   r   )r   r,   s   "r   r   r     s:      8DcN+C QUVY[^V^Q_H` r    c                    V f   R# \        V 4      pVP                  R4      pV'       d    \        P                  ! V4      VR&   V# V#   \        \        P
                  3 d     T# i ; i)z7Parse serialized session fields into API-friendly JSON.Nmodel_config)r  rE   rB   rC   	TypeErrorJSONDecodeError)r<  
normalizedr>  s   &  r   _normalize_session_record*APIServerAdapter._normalize_session_record  sp     ?']
!~~n5-1ZZ-E
>* z t334 s   A	 	A('A(c                R   < V ^8  d   QhRS[ S[S[3,          RS[ S[S[3,          /# )r   r   r   r   r+   r   )r   r,   s   "r   r   r     s/     M MS#X M4S> Mr    c                   V P                  R4      p\        V\        4      '       d   R\        VP                  R4      ;'       g    VP                  R4      ;'       g    R4      P	                  4       R\        VP                  R4      ;'       g    R4      P	                  4       R\        VP                  R4      ;'       g    R4      P	                  4       R\        VP                  R4      ;'       g    R4      P	                  4       /# \        V\        4      '       d   RVP	                  4       RRRRRR/# RRRRRRRR/# )z:Extract model/provider/base_url/api_mode from config.yaml.modelrK   rz   providerapi_modebase_url)rE   r  r  r+   r  )r   	model_cfgs   & r   _current_model_settings(APIServerAdapter._current_model_settings  s    JJw'	i&&Y]]95UUw9OUUSUV\\^C	j 9 ? ?R@FFHC	j 9 ? ?R@FFHC	j 9 ? ?R@FFH	  i%%*BBB	  ZZZLLr    c                2   < V ^8  d   QhRS[ RS[RS[RS[/# )r   r  rK   minimumr   )r   r*   )r   r,   s   "r   r   r     s)      #  c # r    c                V    V R9   d   V# \        V 4      pW28  d   \        RV 24      hV# )z-Parse an integer query parameter with bounds.zValue must be >= )Nrz   )r*   r   )r  rK   rO  parseds   &&& r   
_parse_intAPIServerAdapter._parse_int  s8     JNU0	:;;r    c                    V P                   f     ^ RIHp V! 4       V n         V P                   # V P                   #   \         d,   p\        P                  RT4        Rp?T P                   # Rp?ii ; i)zLazily initialise and return the shared SessionDB instance.

Sessions are persisted to ``state.db`` so that ``hermes sessions list``
shows API-server conversations alongside CLI and gateway ones.
Nr   z(SessionDB unavailable for API server: %s)r  hermes_stater   r3   loggerdebug)r9   r   es   &  r   _ensure_session_db#APIServerAdapter._ensure_session_db  sn     #L2#,;  t  LGKKLs   : A0A++A0c                b   < V ^8  d   QhRS[ RS[S[S[S[ S[3,          ,          ,          RS[/# )r   textattachmentsr   )r+   r   r   r   r   r	  )r   r,   s   "r   r   r     s7     0# 0#0# (d38n)= >0#	0#r    c                   V'       g   W 3# . pV EF~  p\        V\        4      '       g   K  RpR FT  pVP                  V4      p\        V\        4      '       g   K,  VP	                  4       '       g   KD  VP	                  4       p M	  VP                  R4      '       g   K  RpR FT  pVP                  V4      p\        V\        4      '       g   K,  VP	                  4       '       g   KD  VP	                  4       p M	  V'       gb   VP                  RR4      p\        V\        4      '       d:   VP                  R4      '       d#   RV9   d   VP                  R^4      R,          MRpV'       g   EKa  VP                  RRRRRV R	V 2//4       EK  	  V'       g   W 3# . p	V P	                  4       '       d   V	P                  RR
R
V /4       V	P                  V4       W3# )zBuild multimodal content from text + image attachments.

Returns (user_content, persist_text) where user_content is either
a plain string or a list of content parts for multimodal input.
rz   zimage/dataUrlzdata:r  r   	image_urlurlz;base64,r\  )contentTypemimeType	mediaType)contentbase64rH   )	r  r  rE   r+   r  r-  r  appendextend)
r\  r]  image_partsattmimer   valre  data_urlcontent_partss
   &&        r   _build_user_content$APIServerAdapter._build_user_content  s    :,.Cc4((D?ggclc3''CIIKK99;D	 @
 ??8,,G4ggclc3''CIIKK!iikG	 5
 779b1h,,1D1DW1M1M<?8OhnnS!4R8QSGeuTF(7)%DE  1 : :.0::<<  &&&$!?@[)""r    c                L   < V ^8  d   QhRS[ S[,          RS[ S[,          RS[/# )r   ephemeral_system_prompt
session_idr   )r   r+   r   )r   r,   s   "r   r   r     s1     < <!)#< SM< 
<r    c                   ^ RI Hp ^ RIHpHpHp ^ RIHp	 \        P                  P                  RR4      p
\        P                  P                  RR4      p V! 4       pV
e   V
\        P                  R&   Ve   V\        P                  R&   T! 4       pT! 4       p\        T	! TR4      4      p\        \        P                  ! RR	4      4      p^ R
IHp TP                  4       pT! RRT/TBRTRRRRRT;'       g    RRTRTRRRTRTRT P!                  4       RT/B pT#   T
e   T
\        P                  R&   Te   T\        P                  R&   i i ; i)aH  
Create an AIAgent instance using the gateway's runtime config.

Uses _resolve_runtime_agent_kwargs() to pick up model, api_key,
base_url, etc. from config.yaml / env vars.  Toolsets are resolved
from config.yaml platform_toolsets.api_server (same as all other
gateway platforms), falling back to the hermes-api-server default.
)AIAgent)_resolve_runtime_agent_kwargs_resolve_gateway_model_load_gateway_config)_get_platform_toolsOPENAI_API_KEYNOPENAI_BASE_URL
api_serverHERMES_MAX_ITERATIONS90)GatewayRunnerrG  max_iterations
quiet_modeTverbose_loggingFrs  enabled_toolsetsrt  platformstream_delta_callbacktool_progress_callback
session_dbfallback_modelr#   )	run_agentrv  gateway.runrw  rx  ry  hermes_cli.tools_configrz  r   environr   sortedr*   r   r  _load_fallback_modelrY  )r9   rs  rt  r  r  rv  rw  rx  ry  rz  _stale_oai_key_stale_oai_baseruntime_kwargsrG  user_configr  r  r  r  agents   &&&&&               r   _create_agentAPIServerAdapter._create_agent  s    	&kk? (8$?**..):DA	@:<N )/=

+,*0?

,-&(*,!"5k<"PQRYY'>EF 	.&;;= 


 *
 	

 "
 %<$C$Ct
 .
 "
 "
 #8
 $:
 ..0
 *
 ? )/=

+,*0?

,- +s   D 1Ec                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   Y  s     O OM On Or    c                >   "   \         P                  ! RRRR/4      # 5i)u$   GET /health — simple health check.r|   okr  hermes-agent)r   r   )r9   r   s   &&r   _handle_healthAPIServerAdapter._handle_healthY  s       (D*n!MNNs   c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   ]  s      M n r    c                   "   V P                  V4      pV'       d   V# \        P                  ! RRRRRRRR\        \        P                  ! 4       4      RR	R
. RRRR/./4      # 5i)u=   GET /v1/models — return hermes-agent as an available model.objectr  rH   idr  rG  createdowned_byhermes
permissionrootparentN)r0  r   r   r*   rA   r9   r   auth_errs   && r   _handle_modelsAPIServerAdapter._handle_models]  su     ##G,O  f.gs499;/ "Nd
"
  	s   A!A#c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   r  s     C C= C^ Cr    c                  "   V P                  V4      pV'       d   V#  V P                  VP                  P                  R4      ^24      pV P                  VP                  P                  R4      ^ 4      pTP                  P                  R4      ;'       g    RP                  4       ;'       g    RpT P                  4       pTP                  YcTR	7       Uu. uF  pT P                  T4      NK  	  p	pTP                  TR
7      p
\
        P                  ! RT	RT
/4      #   \         d.   p\
        P                  ! R\        T4      /RR7      u Rp?# Rp?ii ; iu upi 5i)u$   GET /api/sessions — list sessions.limitoffsetr   r   r{   Nsourcerz   )r  r  r  r  r   total)r0  rR  queryrE   r   r   r   r+   r  r4  list_sessions_richrB  session_count)r9   r   r  r  r  rX  r  dbr   r   r  s   &&         r   _handle_list_sessions&APIServerAdapter._handle_list_sessionsr  s?    ##G,O	DOOGMM$5$5g$>CE__W]]%6%6x%@!DF --##H-33::<DD!!# --VQW-X
X **40X 	 
    /  '5'5!ABB  	D$$gs1v%6sCC	D

sM   EAD 5!EE/(EE1.EE*"EEEEEc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s      7  7M  7n  7r    c                  "   V P                  V4      pV'       d   V#  VP                  4       G Rj  xL
 pTP                  R4      p\        TP                  R4      ;'       g    R4      P                  4       ;'       g    RpTP                  R	4      pTP                  R
4      pR\        P                  ! 4       P                   2pT P                  4       p	 T	P                  TTTTR7       Te   T	P                  T\        T4      4       T P!                  T	P#                  T4      4      p\        P
                  ! RT/4      #  EL  \        P                  \        3 d    \        P
                  ! RR/RR7      u # i ; i  \         d.   p
\        P
                  ! R\        T
4      /RR7      u Rp
?
# Rp
?
i\         d.   p
\        P
                  ! R\        T
4      /RR7      u Rp
?
# Rp
?
ii ; i5i)u,   POST /api/sessions — create a new session.Nr   Invalid JSON in request bodyr   r{   titler  r}  rG  system_promptsess_)rt  r  rG  r    r<  )r0  rB   r@  r3   r   r   rE   r+   r  uuiduuid4hexr4  create_sessionset_session_titler   rB  get_session)r9   r   r  r   r  r  rG  r  rt  r  rX  r<  s   &&          r   _handle_create_session'APIServerAdapter._handle_create_session  s    ##G,O	\ 'D !TXXh'77<8>>@PPL!1TZZ\--./
!!#	D%+	    $$ZU< 00
1KL  )W!5665 ($$i0 	\$$g/M%NWZ[[	\&  	D$$gs1v%6sCC 	D$$gs1v%6sCC	Ds   G4E EE -G4%G4AG44F 8G4E 5F =G4?F  G4G1"F60G11G46G1G1"G,&G1'G4,G11G4c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     ^ ^] ^~ ^r    c                  "   V P                  V4      pV'       d   V# VP                  P                  R4      ;'       g    RP                  4       pV'       g   \        P
                  ! RR/RR7      #  V P                  VP                  P                  R4      ^4      pV P                  VP                  P                  R4      ^ 4      pT P                  4       P                  Y4TR
7      p\        P
                  ! RTR\        T4      RT/4      #   \         d.   p\        P
                  ! R\        T4      /RR7      u R	p?# R	p?ii ; i5i)u=   GET /api/sessions/search — search messages across sessions.qrz   r   zMissing query parameter: qr   r{   r  r  N)r  r  r  r  rN   results)r0  r  rE   r  r   r   rR  r   r+   r4  search_messagesr   )r9   r   r  r  r  r  rX  r  s   &&      r   _handle_search_sessions(APIServerAdapter._handle_search_sessions  s    ##G,O""3'--2446$$g/K%LUXYY	DOOGMM$5$5g$>CE__W]]%6%6x%@!DF &&(88uZ`8a  '5'3w<T[!\]]	  	D$$gs1v%6sCC	DsC   =E EE4AD 
AEE"E=E>EEEc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     	7 	7 	7> 	7r    c                .  "   V P                  V4      pV'       d   V# VP                  R,          pV P                  V P                  4       P	                  V4      4      pVf   \
        P                  ! RR/RR7      # \
        P                  ! RV/4      # 5i)u5   GET /api/sessions/{session_id} — fetch one session.rt  r   Session not found  r{   r<  )r0  
match_inforB  r4  r  r   r   )r9   r   r  rt  r<  s   &&   r   _handle_get_session$APIServerAdapter._handle_get_session  s     ##G,O''5
001E1E1G1S1ST^1_`?$$g/B%CCPP  )W!566s   BBc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     
H 
H- 
HN 
Hr    c                :  "   V P                  V4      pV'       d   V# VP                  R,          pV P                  4       pVP                  V4      f   VP	                  VRR7       VP                  V4      p\        P                  ! RVR\        V4      /4      # 5i)uC   GET /api/sessions/{session_id}/messages — fetch session messages.rt  r   r  r   r  )	r0  r  r4  r  ensure_sessionget_messagesr   r   r   )r9   r   r  rt  r  r   s   &&    r   _handle_get_session_messages-APIServerAdapter._handle_get_session_messages  s     ##G,O''5
!!#>>*%-j7
+  '5'3u:!FGGs   BBc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     7 7M 7n 7r    c                  "   V P                  V4      pV'       d   V# VP                  R,          pV P                  4       pVP                  V4      f   \        P
                  ! RR/RR7      #  VP                  4       G Rj  xL
 p R	T9   d!   TP                  Y5P                  R	4      4       R
T9   d!   TP                  Y5P                  R
4      4       RT9   d5   TP                  T\        TP                  R4      ;'       g    R4      4       T P                  TP                  T4      4      p\        P
                  ! RT/4      #  L  \        P                  \        3 d    \        P
                  ! RR/RR7      u # i ; i  \         d.   p\        P
                  ! R\        T4      /RR7      u Rp?# Rp?i\         d.   p\        P
                  ! R\        T4      /RR7      u Rp?# Rp?ii ; i5i)u6   PATCH /api/sessions/{session_id} — update a session.rt  Nr   r  r  r{   r  r   r  r  
end_reasonupdatedr  r<  )r0  r  r4  r  r   r   rB   r@  r3   r  rE   update_system_promptend_sessionr+   r   rB  )r9   r   r  rt  r  r   rX  r<  s   &&      r   _handle_update_session'APIServerAdapter._handle_update_session  s    ##G,O''5
!!#>>*%-$$g/B%CCPP	\ 'D
	D$$$Z'1BC$&''
HH_4MNt#z3txx/E/R/R+ST 00
1KL  )W!566# ($$i0 	\$$g/M%NWZ[[	\  	D$$gs1v%6sCC 	D$$gs1v%6sCC	Ds   A,G7/E E	E A=F F 8G7	E 5F G7FG7G4"F93G44G79G4G4"G/)G4*G7/G44G7c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     	/ 	/M 	/n 	/r    c                  "   V P                  V4      pV'       d   V# VP                  R,          pV P                  4       P                  V4      pV'       g   \        P
                  ! RR/RR7      # \        P
                  ! RR/4      # 5i)u7   DELETE /api/sessions/{session_id} — delete a session.rt  r   r  r  r{   r  T)r0  r  r4  delete_sessionr   r   )r9   r   r  rt  deleteds   &&   r   _handle_delete_session'APIServerAdapter._handle_delete_session  sw     ##G,O''5
&&(77
C$$g/B%CCPP  $..s   AB
2B
c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     &R &R- &RN &Rr    c                &  "   V P                  V4      pV'       d   V# VP                  R,          pV P                  4       pVP                  V4      pVf   \        P
                  ! RR/RR7      # R\        P                  ! 4       P                   2p TP                  TVP                  R4      ;'       g    R	VP                  R
4      VP                  R4      VP                  R4      VR7       VP                  V4      pV F  pVP                  VVP                  R4      VP                  R4      VP                  R4      VP                  R4      VP                  R4      VP                  R4      VP                  R4      VP                  R4      R7	       K  	  T P                  TP                  T4      4      p
\        P
                  ! RT
RT/4      #   \         d.   p	\        P
                  ! R\        T	4      /RR7      u Rp	?	# Rp	?	ii ; i5i)uJ   POST /api/sessions/{session_id}/fork — clone a session and its messages.rt  Nr   r  r  r{   r  r  r}  rG  r  user_id)rt  r  rG  r  r  parent_session_idrolere  	tool_name
tool_callstool_call_idtoken_countfinish_reason	reasoning)	rt  r  re  r  r  r  r  r  r  r  r<  forked_from)r0  r  r4  r  r   r   r  r  r  r  rE   r  append_messager3   r+   rB  )r9   r   r  rt  r  original	forked_idmessagesr   rX  r<  s   &&         r   _handle_fork_session%APIServerAdapter._handle_fork_session  s    ##G,O''5
!!#>>*-$$g/B%CCPPDJJL,,-.		D$||H-==ll7+&ll?; Y/",   z2H#!!( V,#KK	2%kk+6&{{<8!(^!< 'M :")++o">%kk+6 " 
 $ 00	1JK  )WmZ!PQQ	  	D$$gs1v%6sCC	Ds=   BH#G 7C%G :HH!"H	HH	HHc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r      s     I I- IN Ir    c                  a aaaaaa"   S P                  V4      pV'       d   V# VP                  R,          oS P                  4       oS P                  SP	                  S4      4      pVf>   SP                  SRR7       S P                  SP	                  S4      4      ;'       g    / p VP                  4       G Rj  xL
 pTP                  R	4      p\        T\        4      '       g   \        P                  ! RR
/RR7      # TP                  R4      pT'       d   \        P                  R\!        T4      T Uu. uF{  p\        T\"        4      '       g   K  TP                  R4      TP                  R4      \!        TP                  RR4      ;'       g    TP                  RR4      ;'       g    R4      3NK}  	  up4       S P%                  YV4      w  oo\        S\&        4      '       d    \        P                  R\!        S4      4       TP                  R4      ;'       g    TP                  R4      ;'       g    RpTP                  R4      oSP)                  S4      o\*        P,                  ! 4       p	TTTT TTT3R lp
 T	P/                  RT
4      G Rj  xL
 w  r\        P                  ! RSRR\2        P4                  ! 4       P6                   2RTRTP                  R4      RTP                  RR4      R TP                  R R4      R!TP                  R!R4      R"TP                  R"^ 4      R#TP                  R#. 4      R$TP                  R$4      R%TP                  R%R4      R&T/4      #  EL  \        P                  \        3 d    \        P                  ! RR/RR7      u # i ; iu upi  EL  \         dG   p\        P1                  RSTRR7       \        P                  ! R\        T4      /RR7      u Rp?# Rp?ii ; i5i)'uG   POST /api/sessions/{session_id}/chat — run a session-aware chat turn.rt  Nr   r  r   r  r   r{   r   "Missing or invalid 'message' fieldr]  z$[chat] Received %d attachment(s): %srY   rb  re  rz   rf  z-[chat] Built multimodal content with %d partsrG  r  system_messagec            
         < SP                  SSR 7      p SV n        V P                  S	SSR7      pR\        V R^ 4      ;'       g    ^ R\        V R^ 4      ;'       g    ^ R\        V R^ 4      ;'       g    ^ /pW3# ))rs  rt  conversation_historypersist_user_messageinput_tokenssession_prompt_tokensoutput_tokenssession_completion_tokenstotal_tokenssession_total_tokens)r  r  run_conversationgetattr)
r  resultusager  historypersist_textr9   rt  r  user_contents
      r   _run3APIServerAdapter._handle_session_chat.<locals>._runD  s    &&(6% ' E !#E++%,%1 , F /F J O Oa0KQ!O!T!TST/Eq I N NQE
 = r    z%Error running session chat for %s: %sTexc_infor  run_idrun_final_response	completedFpartialinterrupted	api_callsr  last_reasoningresponse_previewedr  )r0  r  r4  rB  r  r  rB   r@  r3   r   r   rE   r  r+   rV  rW  r   r  rp  r  get_messages_as_conversationasyncioget_event_looprun_in_executorr   r  r  r  )r9   r   r  r<  r   r   raw_attachments_syncarG  loopr  r  r  rX  r  r  r  rt  r  r  s   f&            @@@@@@r   _handle_session_chat%APIServerAdapter._handle_session_chat   s    ##G,O''5
!!#00
1KL?j744R^^J5OPVVTVG	\ 'D ((9%'3''$$g/S%T]`aa#xx6LL?12 BV  n  BV|}  Zd  ef  hl  Zmw155=!%%*>AEE)UWDXDuDu\]\a\abjln\oDuDusu@vw  BV  no &*%=%=g%\"llD))LLH#lJ[\!KKW[[%9KK^"2311*=%%'	! 	!$	D"&"6"6tT"BBMF
   *TZZ\--./Ufjj)9:K7vzz)U36::mU;K3

:r2fjj)9: &**-A5"IU"
  	] ($$i0 	\$$g/M%NWZ[[	\ n: C 	DLL@*aZ^L_$$gs1v%6sCC	Ds   BP&P*M. =M+>M. APP:N)=N)N)/N);A'P#P<APN1 N.N1 CP+M. .5N&#P%N&&P.N1 1P<;O=7P8P=PPc                "   < V ^8  d   QhRRRR/# r   r   r%  r   web.StreamResponser#   )r   r,   s   "r   r   r   k  s      d d dK_ dr    c                r  a aaaaaaaa a!a"a#a$a%a&a'"   S P                  V4      pV'       d   V# VP                  R,          o$S P                  4       oS P                  SP	                  S$4      4      pVf>   SP                  S$RR7       S P                  SP	                  S$4      4      ;'       g    / p VP                  4       G Rj  xL
 pTP                  R	4      p\        T\        4      '       g   \        P                  ! RR
/RR7      # TP                  R4      pT'       d   \        P                  R\!        T4      T Uu. uF{  p\        T\"        4      '       g   K  TP                  R4      TP                  R4      \!        TP                  RR4      ;'       g    TP                  RR4      ;'       g    R4      3NK}  	  up4       S P%                  YV4      w  o'o"\        S'\&        4      '       d    \        P                  R\!        S'4      4       TP                  R4      o&SP)                  S$4      o R\*        P,                  ! 4       P.                   2o^ RIpTP3                  4       o%R R loR TT%3R lloR R lp	RNR R llp
R\*        P,                  ! 4       P.                   2o#TTT#T$3R loTTT#T$3R loR.o\4        P6                  ! 4       o!TTTTT T!T"T T$T&T'3R  lp\4        P8                  ! T! 4       4      pR!R"R#R$R%R&R'R(/pTP:                  P                  R)R4      pT'       d   S P=                  T4      MRpT'       d   TP?                  T4       \        P@                  ! ^TR*7      pTPC                  T4      G Rj  xL
   R+\*        P,                  ! 4       P.                   2pTPE                  S! R,RS$R-S#R.TP                  R.4      ;'       g    R//4      4      G Rj  xL
  TPE                  S! R0RS$R-S#R1R2TR3R4RT//4      4      G Rj  xL
  TPE                  S! R5RS$R-S#R	R2SR3R6//4      4      G Rj  xL
    S!PG                  RT%3R7 l4      G Rj  xL
 pTf   MTPE                  T4      G Rj  xL
  K@  TG Rj  xL
 pT	! TP                  R84      ;'       g    . 4      pTP                  R84      ;'       g    .  F  pTP                  R34      R98w  d   K  TP                  R:4      pTP                  T/ 4      pTPE                  S! R;RS$R-S#R:TR<TP                  R<4      ;'       g    TP                  R<4      ;'       g    R=R>TP                  R>4      R?T
! TP                  R4      4      /4      4      G Rj  xL
  K  	  TPE                  S! R@RS$R-S#RASRTP                  RB4      ;'       g    RRCTP                  RCRD4      RETP                  RERD4      RFTP                  RFRD4      /4      4      G Rj  xL
  TPE                  S! RGRS$R-S#RASRCTP                  RCRD4      RETP                  RERD4      RFTP                  RFRD4      RHTP                  RH4      /4      4      G Rj  xL
  TPE                  S! RIRS$R-S#RJRK/4      4      G Rj  xL
  T#  EL  \        P                  \        3 d    \        P                  ! RR/RR7      u # i ; iu upi  ELV EL EL EL EL  TPH                   dj    TPK                  4       '       dO     S%PM                  4       pTf   M3TPE                  T4      G Rj  xL 
  K3    TPH                   d     Mi ; i EK   EK!  i ; i EL EL EL ELr EL L  \N        \P        \R        \T        3 d    S^ ,          pTe%    TPW                  RL4       M  \         d     Mi ; iTPK                  4       '       g?   TPY                  4         TG Rj  xL 
  M!  \4        PZ                  \        3 d     Mi ; i\        P]                  RMS$4        T# i ; i5i)OuT   POST /api/sessions/{session_id}/chat/stream — stream a session chat turn over SSE.rt  Nr   r  r   r  r   r{   r   r  r]  z+[chat/stream] Received %d attachment(s): %srY   rb  re  rz   rf  z4[chat/stream] Built multimodal content with %d partsr  	msg_asst_c                ^    V ^8  d   QhR\         R\        \         \        3,          R\        /# )r   
event_namepayloadr   )r+   r   r   bytes)r   s   "r   r   BAPIServerAdapter._handle_session_chat_stream.<locals>.__annotate__  s.     	o 	oC 	o$sCx. 	oU 	or    c                 ^    R V  R\         P                  ! VRR7       R2P                  R4      # )zevent: z
data: Fensure_ascii

r   )rB   rM   r   )r,  r-  s   &&r   _encode_sseAAPIServerAdapter._handle_session_chat_stream.<locals>._encode_sse  s1    ZLGRW1X0YY]^eefmnnr    c                V    V ^8  d   QhR\         R\        \         \        3,          RR/# )r   r,  r-  r   NrI   )r   s   "r   r   r/    s)     	; 	;S 	;4S> 	;d 	;r    c                 6   < SP                  S! W4      4       R # r  rO   )r,  r-  r4  stream_qs   &&r   _queue_eventBAPIServerAdapter._handle_session_chat_stream.<locals>._queue_event  s    LLZ9:r    c                    V ^8  d   QhR\         \        \        \        3,          ,          R\        \        \        \        \        3,          3,          /# )r   r  r   )r   r   r+   r   )r   s   "r   r   r/    s9     	 	T#s(^ 4 	c4S>>Q9R 	r    c                    / pV  EF  pVP                  R 4      R8w  d   K  \        VP                  R4      ;'       g    . 4       F  w  r4VP                  R4      pV'       g   K   VP                  R4      ;'       g    / pVP                  R4      p \        V\        4      '       d-   VP	                  4       '       d   \
        P                  ! V4      M/ pRVP                  R4      ;'       g&    VP                  R4      ;'       g    RV^,            2R	V/W&   K  	  EK  	  V#   \
        P                   d    Tp Lhi ; i)
r  	assistantr  r  function	argumentsr  rY   tool_args)rE   	enumerater  r+   r  rB   rC   r@  )	r  mappingr   index	tool_calltool_idfnraw_argsparsed_argss	   &        r   	_tool_map?APIServerAdapter._handle_session_chat_stream.<locals>._tool_map  s   13G 88F#{2(1$((<2H2N2NB(O$E'mmD1G" "z288bB!vvk2H/>HSV>W>W\d\j\j\l\ldjj&:rt $RVVF^%c%ctxx7L%c%cRWX]`aXaWbPc(G$ )P !" N  // /&./s   +D%>D%%D?>D?c                <    V ^8  d   QhR\         R\        R\        /# )r   re  r  r   )r   r*   r+   )r   s   "r   r   r/    s&     	G 	GS 	G 	G 	Gr    c                     \        V \        4      '       d   T M\        P                  ! V R R7      pVRV \	        V4      V8  d	   R,           # R,           # )Fr1  Nz...rz   )r  r+   rB   rM   r   )re  r  r\  s   && r   _result_previewEAPIServerAdapter._handle_session_chat_stream.<locals>._result_preview  sE    (#667DJJw]b<cD<CI,=5FF2FFr    r  c                 >   < V '       d   S! R RSRSRSRV /4       R# R# )zassistant.deltart  r  
message_iddeltaNr#   )rS  r:  assistant_message_idr  rt  s   &r   	_on_delta?APIServerAdapter._handle_session_chat_stream.<locals>._on_delta  s-    %!:xOcelnst r    c                 f   < V R 8X  d   S! RRSRSRSRV/4       R# RSRSRV RVR	V/pS! R
V4       R# )	_thinkingztool.progressrt  r  rR  rS  Nr  previewrB  tool.startedr#   )rY   rY  rB  r-  r:  rT  r  rt  s   &&& r   _on_tool_progressGAPIServerAdapter._handle_session_chat_stream.<locals>._on_tool_progress  s^    {"#!:xOcelnuv j&T7G 1r    c            
      b   <"   VVVVVVVV	V
V3
R  lp SP                  RV 4      G Rj  xL
 #  L5i)c                  n   <
 SP                  S	SSSR 7      p SV n        V S^ &   V P                  S
SSR7      # )rs  rt  r  r  r   )r  r  r	  )r  rU  r[  	agent_refr  r  r  r9   rt  r  r  s    r   r  SAPIServerAdapter._handle_session_chat_stream.<locals>._run_agent_task.<locals>._run  sX    **,:)*3+<	 +  %'!$	!-- )0)5 .  r    N)r   )r  rU  r[  r`  r  r  r#  r  r9   rt  r  r  s    r   _run_agent_taskEAPIServerAdapter._handle_session_chat_stream.<locals>._run_agent_task  s+       --dD9999s   %/-/Content-Typetext/event-streamCache-Controlno-cache
Connectionz
keep-aliveX-Accel-Bufferingnory   r~   	msg_user_zsession.createdr  r  zNew Chatzrun.starteduser_messager  r  userzmessage.startedr>  c                  (   < S P                  R R7      # g      ?timeoutrE   r9  s   r   <lambda>>APIServerAdapter._handle_session_chat_stream.<locals>.<lambda>
      X\\Z]\E^r    r  toolr  tool.completedr  unknownrB  result_previewzassistant.completedrR  r  r  Fr  r  run.completedr  donestatefinalSSE client disconnectedz7Session SSE client disconnected; interrupted session %s)i  )/r0  r  r4  rB  r  r  rB   r@  r3   r   r   rE   r  r+   rV  rW  r   r  rp  r  r  r  r  r  queueQueuer  r  ensure_futurer   r   r   StreamResponsepreparewriter   Emptyr|  
get_nowaitConnectionResetErrorConnectionAbortedErrorBrokenPipeErrorOSError	interruptcancelCancelledErrorinfo)(r9   r   r  r<  r   r   raw_attachmentsr"  _qrK  rO  rb  
agent_tasksse_headersr   corsr   user_message_idframer  toolsr   rG  	tool_metar  r4  rU  r[  r:  r`  rT  r  r  r#  r  r  rt  r9  r  r  s(   f&                       @@@@@@@@@@@@@@@r   _handle_session_chat_stream,APIServerAdapter._handle_session_chat_streamk  s    ##G,O''5
!!#00
1KL?j744R^^J5OPVVTVG	\ 'D ((9%'3''$$g/S%T]`aa ((=1LLF_- BQ  i  BQ|}  U_  `a  cg  Uhw155=!%%*>AEE)UWDXDuDu\]\a\abjln\oDuDusu@vw  BQ  ij &*%=%=g%W"llD))LLOQTUaQbc"2311*=!*4::<+;+;*<=
 	XXZ	o	; 	;	*	G 

(()*	 		2 	2  F	%%'	: 	:$ **?+<=
 /Z,	
 $$Xr28>t,,V4Dt$%%S+Fw'''[	_ )$**,*:*:);<O..->j&W-;;A "   
 ..]j&/Fw!= "    ..->j&D"6LA "    "&"6"6t=^"__E =nnU+++%%Ffjj4::;E

:.44"488F#v-((>2!IIgr2	nn[1A *f"G{!;!a!atxx?T!a!aXaIMM&1$odhhy6I&JD &    5 ..-Bj&26::&67==2VZZU;6::i7vzz-?E "    .._j&2VZZU;6::i7vzz-?VZZ4? "    ..VlJPXZ`bikr5s!tuuu  m ($$i0 	\$$g/M%NWZ[[	\ iT 	(
 `xx !(("&(0(;(;(=#(=$)&.nnU&; ; ;#%88 & %&  ,% v$&<owW 	_aLE OO$=>  ??$$!!#$$$..	: KKQS]^	_s4  B`7/`73Z ZZ A`7%`7[ =[[8[F`7
=`7[`7A]: ]: )[ *+]: [#)]: ?[& ]: [, [) [, $]: =])>]: 	],
]: (]: A-]: 5]: 7]: ]/4]: ;A]:  ]2A,]: -]5.%]: ]8]: `7Z 5[`7[	`7 ]: #]: &]: )[, ,&]&]&])]&*]>]?]]&]]&]]&]: %]&&]: ,]: /]: 2]: 5]: 8]: :(`4#^54`45_ `4_`4`4-_92_53_98`49``4``40`73`44`7c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   Q  s     7 7 7. 7r    c           
     d  "   V P                  V4      pV'       d   V# VP                  P                  R4      ;'       g    RP                  4       P	                  4       pVR9  d   \
        P                  ! RR/RR7      # V P                  4       pVP                  4        . pVR9   d5   VP                  RRR	VP                  R
\        VP                  4      /4       VR9   d5   VP                  RRR	VP                  R
\        VP                  4      /4       \
        P                  ! RV/4      # 5i)u.   GET /api/memory — read current memory state.targetallmemoryrm  r   z(target must be one of: all, memory, userr   r{   entriesentry_counttargets>   r  rm  r  >   r  r  >   r  rm  )r0  r  rE   r  lowerr   r   r9  r8  rh  memory_entriesr   user_entries)r9   r   r  r  storer  s   &&    r   _handle_get_memory#APIServerAdapter._handle_get_memoryQ  s    ##G,O--##H-66==?EEG22$$g/Y%Zcfgg&&(&&NN(5//s5#7#78 
 _$NN&5--s5#5#56 
   )W!566s   =D0 C0D0c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   k  s     8 8 8. 8r    c                  "   V P                  V4      pV'       d   V#  VP                  4       G Rj  xL
 p\        TP                  R4      ;'       g    R4      P                  4       P                  4       p\        TP                  R4      ;'       g    R4      pTR9  d   \        P
                  ! RR	/RR7      # T P                  4       P                  YE4      pTP                  R
4      '       d   ^MRp\        P
                  ! YgR7      #  L  \        P                  \        3 d    \        P
                  ! RR/RR7      u # i ; i5i)u(   POST /api/memory — add a memory entry.Nr   r  r   r{   r  rz   re  !target must be 'memory' or 'user'success>   rm  r  )r0  rB   r@  r3   r   r   r+   rE   r  r  r9  add)r9   r   r  r   r  re  r  r|   s   &&      r   _handle_add_memory#APIServerAdapter._handle_add_memoryk  s    ##G,O	\ 'D TXXh'--2.446<<>dhhy)//R0++$$g/R%S\_``'')--f>

9--3  77 ($$i0 	\$$g/M%NWZ[[	\D   E
D DD E
?E
A9E
D 5EE
EE
c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   }  s     8 8M 8n 8r    c                  "   V P                  V4      pV'       d   V#  VP                  4       G Rj  xL
 p\        TP                  R4      ;'       g    R4      P                  4       P                  4       p\        TP                  R4      ;'       g    R4      p\        TP                  R	4      ;'       g    R4      pTR9  d   \        P
                  ! RR
/RR7      # T P                  4       P                  YET4      pTP                  R4      '       d   ^MRp\        P
                  ! YxR7      #  L  \        P                  \        3 d    \        P
                  ! RR/RR7      u # i ; i5i)u-   PATCH /api/memory — replace a memory entry.Nr   r  r   r{   r  rz   old_textre  r  r  >   rm  r  )r0  rB   r@  r3   r   r   r+   rE   r  r  r9  replace)	r9   r   r  r   r  r  re  r  r|   s	   &&       r   _handle_replace_memory'APIServerAdapter._handle_replace_memory}  s4    ##G,O	\ 'D TXXh'--2.446<<>txx
+11r2dhhy)//R0++$$g/R%S\_``'')11&GL

9--3  77 ($$i0 	\$$g/M%NWZ[[	\sJ   E/D4 D2D4 E/?E/#E/8A:E/2D4 45E,)E/+E,,E/c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     8 8= 8^ 8r    c                  "   V P                  V4      pV'       d   V#  VP                  4       G Rj  xL
 p\        TP                  R4      ;'       g    R4      P                  4       P                  4       p\        TP                  R4      ;'       g    R4      pTR9  d   \        P
                  ! RR	/RR7      # T P                  4       P                  YE4      pTP                  R
4      '       d   ^MRp\        P
                  ! YgR7      #  L  \        P                  \        3 d    \        P
                  ! RR/RR7      u # i ; i5i)u-   DELETE /api/memory — delete a memory entry.Nr   r  r   r{   r  rz   r  r  r  >   rm  r  )r0  rB   r@  r3   r   r   r+   rE   r  r  r9  remove)r9   r   r  r   r  r  r  r|   s   &&      r   _handle_delete_memory&APIServerAdapter._handle_delete_memory  s    ##G,O	\ 'D TXXh'--2.446<<>txx
+11r2++$$g/R%S\_``'')00B

9--3  77 ($$i0 	\$$g/M%NWZ[[	\r  c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     M M M> Mr    c                "  "   V P                  V4      pV'       d   V# VP                  P                  R4      ;'       g    RP                  4       ;'       g    Rp\        P
                  ! \        P                  ! \        VR7      4      4      # 5i)u    GET /api/skills — list skills.categoryrz   N)r  )	r0  r  rE   r  r   r   rB   rC   r   )r9   r   r  r  s   &&  r   _handle_list_skills$APIServerAdapter._handle_list_skills  si     ##G,OMM%%j177R>>@HHD  K,J!KLLs   =B B7Bc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     B Bm B Br    c                   "   V P                  V4      pV'       d   V# \        P                  ! \        P                  ! \        4       4      4      # 5i)u5   GET /api/skills/categories — list skill categories.)r0  r   r   rB   rC   r   r  s   && r   _handle_skill_categories)APIServerAdapter._handle_skill_categories  s;     ##G,O  ,=,?!@AAs   AAc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     T T T. Tr    c           	     H  "   V P                  V4      pV'       d   V# VP                  R,          pVP                  P                  R4      ;'       g    RP	                  4       ;'       g    Rp\
        P                  ! \        P                  ! \        W4R7      4      4      # 5i)u/   GET /api/skills/{name} — fetch skill details.rY   	file_pathrz   N)r  )
r0  r  r  rE   r  r   r   rB   rC   r   )r9   r   r  rY   r  s   &&   r   _handle_view_skill#APIServerAdapter._handle_view_skill  sy     ##G,O!!&)]]&&{399r@@BJJd	  Jt,Q!RSSs   AB"B"+7B"c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s       . r    c                   "   V P                  V4      pV'       d   V# \        4       pV P                  V4      p\        P                  ! RVR,          RVR,          RVR,          RVR,          RV/4      # 5i)u-   GET /api/config — fetch the current config.rG  rH  rI  rJ  r   )r0  r   rL  r   r   )r9   r   r  r   currents   &&   r   _handle_get_config#APIServerAdapter._handle_get_config  sy     ##G,O..v6  WW%
+
+
+f"
  	s   A3A5c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     3 3= 3^ 3r    c                  "   V P                  V4      pV'       d   V#  VP                  4       G Rj  xL
 p\        4       pTP                  R4      p\        T\        4      '       d   \        T4      pMA\        T\        4      '       d*   TP                  4       '       d   RTP                  4       /pM/ p\        TP                  R4      ;'       g    R	4      P                  4       p\        TP                  R4      ;'       g    R	4      P                  4       pT'       d4   R
T9   d-   T'       g%   TP                  R
^4      p	T	^ ,          pT	^,          pT'       d   YR&   T'       d   YvR&   RT9   d6   \        TP                  R4      ;'       g    R	4      P                  4       TR&   YdR&   T'       d   YtR&    \        T4       T P                  T4      p\        P
                  ! RRRTR,          RTR,          RTR,          /4      #  EL  \        P                  \        3 d    \        P
                  ! RR/RR7      u # i ; i  \         d.   p
\        P
                  ! R\        T
4      /RR7      u Rp
?
# Rp
?
ii ; i5i)u>   PATCH /api/config — update model/provider/base_url settings.Nr   r  r   r{   rG  rK   rH  rz   /rJ  r  r  T)r0  rB   r@  r3   r   r   r   rE   r  r  r+   r  r  r   rL  )r9   r   r  r   r   rK  updated_model_cfgnew_provider	new_modelpartsrX  r  s   &&          r   _handle_update_config&APIServerAdapter._handle_update_config  s(    ##G,O	\ 'D JJw'	i&& $Y	3''IOO,=,=!*IOO,= > "488J/5526<<>)//R0668	 	),OOC+E 8LaI+4i(,8j),/0D0J0J,K,Q,Q,Sj)+w!-:	D ..v6  $WW%
+
+	"
  	Q ($$i0 	\$$g/M%NWZ[[	\F  	D$$gs1v%6sCC	Ds   JH HH A(J 1J1JJ!J0+JJ('J(J9I AJH 5I JIJI>"I93I>4J9I>>Jc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     5c 5cm 5c 5cr    c                  "   V P                  V4      pV'       d   V# \        4       pV P                  V4      pVP                  P	                  R4      ;'       g    VR,          ;'       g    RP                  4       p\        V4       UUu. uF  w  rgRVRVRV/NK  	  pppV U	u0 uF  qR,          kK  	  p
p	\        4       pV F  pVP	                  R4      '       d   VR,          V8X  d   K*  \        VR,          4       F]  w  rmWj9  g   K  TP                  RTRT;'       g    VP	                  RVR,          4      RVR,          /4       V
P                  V4       K_  	  K  	  VP	                  R4      ;'       g    RP                  4       pV'       d0   W9  d*   VP                  ^ RVRR	RV/4       V
P                  V4        ^ R
IpR EFq  p VP                  4       ;_uu_4       GR
j  xL
 pVP	                  V R2VP                  ^R7      R7      ;_uu_4       GR
j  xL
 pVP                  ^8X  d   VP                  4       G R
j  xL
 pV U	u0 uF  qR,          kK  	  p
p	VP	                  R4      ;'       g    .  Fr  pVP	                  R4      ;'       g    VP	                  R4      ;'       g    RpV'       g   KA  VV
9  g   KJ  VP                  RVRRRR/4       V
P                  V4       Kt  	   R
R
R
4      GR
j  xL
  R
R
R
4      GR
j  xL
   M&R
R
R
4      GR
j  xL
  R
R
R
4      GR
j  xL
  EKt  	   \        4       p\$        P&                  ! RVRVRV/4      # u uppi u up	i  EL ELS EL-u up	i  L{ Lm L]  + GR
j  xL 
 '       g   i     Lt; i Lk  + GR
j  xL 
 '       g   i     EK  ; i  \          d     EK  i ; i  \"         d     Li ; i5i)uK   GET /api/available-models — list provider models and available providers.rH  
openrouterr  descriptionauthenticatedlabelrG  rz   r  Nz	/api/tags)r  rp  modelsrY   localollama	providers)zhttp://127.0.0.1:11434zhttp://localhost:11434)r0  r   rL  r  rE   r  r   r   rh  r  insertaiohttpClientSessionClientTimeoutr|   rB   r3   ImportErrorr   r   )r9   r   r  r   r  rH  model_idr  r  m	model_idsr  pdesccurrent_model_aiohttpollama_base_sessr   rH   omrY   s   &&                    r   _handle_available_models)APIServerAdapter._handle_available_models  s[    ##G,O..v6MM%%j1XXWZ5HXXL__a *EX)N
)N% 8]KXN)N 	 
 '--ftWWf	-,.	A55))QtW-@"=ag"F,MM4=$BaBa!%%PWYZ[_Y`Jacmopquov"wxMM(+ #G  !W-33::<-a$}iQ[]e!fgm,	&S'557775#(99}I-FPXPfPfmnPfPo9#p#p#ptx#{{c1-1YY['8>D,EftWWf	,E+/88H+=+C+C+CB+-66&>+R+RRVVG_+R+RPRD'+tI0E(.tT=RY[ego6p(q(1d(;	 ,D
 !& $q#p  877#p#p  877  T$ -.	  *h&+W`!abb[
 .,  8#p'8,E $q  8#p#p#p#p  8777 !  		s  AO(O(,O(M)O(%M/6AO(O($AO(=O(/O(
O O-M4
.O13N&$M7%N&(%NM:NM='NNN8NN-N;N&N
N&ONOO O(N&(N
)N&-O8N$9O=O 2O(4O7N&:N=NN&ON&N!N
N!N!N&$O&O,N/-
O8O:O>O OOO OO O%"O($O%%O(c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   5  s#     v] v]m v] v]r    c                  a aaa a!a""   S P                  V4      pV'       d   V#  VP                  4       G Rj  xL
 pTP                  R4      pT'       d   \        T\        4      '       g   \        P
                  ! RRRR	R
//RR7      # TP                  R4      pTP                  RR4      pT^8X  g   TR8X  d   \        P
                  ! RR\        P                  ! 4       P                  R,           2RRR\        \        P                  ! 4       4      RT;'       g    RRR^ RRRRR/RR/.RR^ R ^R!^//4      # TP                  R"R#4      pRo!. pT Ff  p	T	P                  RR4      p
T	P                  RR4      pT
R$8X  d   S!f   To!K6  S!R%,           T,           o!KH  T
R>9   g   KQ  TP                  RT
RT/4       Kh  	  Ro". oT'       d   TR?,          P                  RR4      o"TRR? oS"'       g   \        P
                  ! RRR&R	R
//RR7      # TP                   P                  R'R4      P#                  4       pT'       d*   To  S P%                  4       pTe   TP'                  S 4      oM\-        \        P                  ! 4       4      o R)\        P                  ! 4       P                  R*,           2pTP                  RR4      p\        \        P                  ! 4       4      pT'       dp   ^ RIpTP1                  4       oT3R+ lpT3R, lpR.p\2        P4                  ! S P7                  S"SS!S TTTR-7      4      pS P9                  YTTSTTS R.7      G Rj  xL
 # TT T T!T"3R/ lpTP                   P                  R04      pT'       d4   \;        T. R@OR17      p \<        P?                  TTT4      G Rj  xL
 w  ppM T! 4       G Rj  xL
 w  ppTP                  R9R4      pT'       g   TP                  RR:4      pRTRRRTRTRR^ RRRRT/RR/.RRTP                  R;^ 4      R TP                  R<^ 4      R!TP                  R!^ 4      //p\        P
                  ! TR'S /R=7      #  EL&  \        P                  \        3 d%    \        P
                  ! \        R4      RR7      u # i ; i  \         d%   p\(        P+                  R(S T4       . o Rp?ELGRp?ii ; i EL EL+  \         dI   p\(        PA                  R2TR3R47       \        P
                  ! \        R5T 2R6R77      R8R7      u Rp?# Rp?ii ; i ELp  \         dI   p\(        PA                  R2TR3R47       \        P
                  ! \        R5T 2R6R77      R8R7      u Rp?# Rp?ii ; i5i)Au=   POST /v1/chat/completions — OpenAI Chat Completions format.Nr  r   r{   r  r   r   z#Missing or invalid 'messages' fieldr   r+  
max_tokensrG  rz   testr  zchatcmpl-probe-:N   Nr  zchat.completionr  r  choicesrE  r  r>  re  r  r  stopr  prompt_tokenscompletion_tokensr  streamFsystem
z!No user message found in messagesX-Hermes-Session-Idz)Failed to load session history for %s: %sz	chatcmpl-:N   Nc                 6   < V e   SP                  V 4       R # R # r  r8  )rS  	_stream_qs   &r   rU  <APIServerAdapter._handle_chat_completions.<locals>._on_delta  s     $MM%( %r    c                   < V P                  R4      '       d   R# ^ RIHp V! V 4      pT;'       g    T pSP                  RV RV R24       R# )z8Inject tool progress into the SSE stream for Open WebUI._N)get_tool_emojiz
` z`
)r-  agent.displayr  rO   )rY   rY  rB  r  emojir  r  s   &&&   r   r[  DAPIServerAdapter._handle_chat_completions.<locals>._on_tool_progress  sH    ??3''8&t,4E7!E7#67r    )rl  r  rs  rt  r  r  r`  )rt  c                  J   <"   SP                  SS SSR 7      G Rj  xL
 #  L5i)rl  r  rs  rt  N
_run_agent)r  r9   rt  r  rl  s   r   _compute_completionFAPIServerAdapter._handle_chat_completions.<locals>._compute_completion  s2     )%,(5%	 )       #!#Idempotency-Keyr   z,Error running agent for chat completions: %sTr  Internal server error: server_errorr   r  r  (No response generated)r  r  )r   )rm  r>  rg  )rG  r  r  tool_choicer  )!r0  rB   r@  r3   r   r   r   rE   r  r  r  r  r  r*   rA   rh  r   r  rY  r  rV  warningr+   r  r  r  r  r  _write_sse_chat_completionr   _idem_cacher   r   )#r9   r   r  r   r  r  probe_modelr  conversation_messagesmsgr  re  provided_session_idr  rX  completion_id
model_namer  r  rU  r[  r`  r  r  idempotency_keyr   r  r  r  response_datar  r  rt  r  rl  s#   f&                            @@@@@r   _handle_chat_completions)APIServerAdapter._handle_chat_completions5  s    ##G,O	` 'D 88J'z(D99$$9&KVUlmn  XXl+
hhw+?kV3$$

(8(8(<'=>+3tyy{+66WaV[)UY4Z\kmstu/1.A1nVWX&   (E* 68C7762&Dggi,Gx ($+M$1D$87$BM..%,,fdIw-OP   0488BGL+CR0G$$9&I6Sjkl  &oo112GLRRT,J,,.> ==jIG
 TZZ\*J $DJJL$4$4S$9#:;XXg~6
diik""$((*I	)8 I ..t)%,(5%&/'8# 0? 0 J 88
GYI* 9   	 	 "//--.?@*46mnB&1&<&<_bRe&f f&9&; ;  $4b9#ZZ1JKN -'wZQ!>  $V	 >1!=#UYY%B		.! <
,   9NPZ8[\\] ($$i0 	`$$]3Q%R[^__	`@  JJXYZ`$ !g KQY]^((!$;A3"?.Y  !< KQY]^((!$;A3"?.Y s&  V
Q! QQ! V
CV
BV
$$V
	%V
/AV
?V
%R# 'C*V
S0V
V
S -S.S 5V
7
T4 T1T4 	V
#A;V
Q! !<R V
R  V
#S.SV
SV
S T.&=T)#T.$V
)T..V
1T4 4V?=V<V=V
VV
c                :   < V ^8  d   QhRRRS[ RS[ RS[RS[ RR/# )	r   r   r%  r   rG  r  rt  r   r(  )r+   r*   )r   r,   s   "r   r   r     sG     j j$j58jADjjHKj 
jr    c	                  a"   ^ RI p	RRRR/p
VP                  P                  RR4      pV'       d   V P                  V4      MRpV'       d   V
P	                  V4       V'       d   WR&   \
        P                  ! ^V
R	7      pVP                  V4      G Rj  xL
   R
VRRRVRVRR^ RRR/RR/./pVP                  R\        P                  ! V4       R2P                  4       4      G Rj  xL
  \        P                  ! 4       p  VP                  RV3R l4      G Rj  xL
 pTf   MVR
TRRRTRTRR^ RRT/RR/./pTP                  R\        P                  ! T4       R2P                  4       4      G Rj  xL
  K{  R^ R^ R^ /p TG Rj  xL
 w  ppT;'       g    TpR
TRRRTRTRR^ R/ RR/.RRTP                  R^ 4      RTP                  R^ 4      RTP                  R^ 4      //pTP                  R\        P                  ! T4       R2P                  4       4      G Rj  xL
  TP                  R 4      G Rj  xL
  T#  EL EL_ EL-  T	P                   d    TP!                  4       '       d     SP#                  4       pTf   MnR
TRRRTRTRR^ RRT/RR/./pTP                  R\        P                  ! T4       R2P                  4       4      G Rj  xL 
  Kn    T	P                   d     Mi ; i EK   EK  i ; i EL EL}  \$         d     ELzi ; i L L  \&        \(        \*        \,        3 d    T'       d
   T^ ,          MRpTe%    TP/                  R!4       M  \$         d     Mi ; iTP!                  4       '       g?   TP1                  4         TG Rj  xL 
  M!  \        P2                  \$        3 d     Mi ; i\4        P7                  R"T4        T# i ; i5i)#a  Write real streaming SSE from agent's stream_delta_callback queue.

If the client disconnects mid-stream (network drop, browser tab close),
the agent is interrupted via ``agent.interrupt()`` so it stops making
LLM API calls, and the asyncio task wrapper is cancelled.
Nrd  re  rf  rg  ry   rz   r  r~   r  r  zchat.completion.chunkr  rG  r  rE  rS  r  r>  r  data: r3  c                  (   < S P                  R R7      # ro  rr  rs  s   r   rt  =APIServerAdapter._write_sse_chat_completion.<locals>.<lambda>  rv  r    re  r  r  r  r  r  r  r  s   data: [DONE]

r  z2SSE client disconnected; interrupted agent task %s)r  r   rE   r   r   r   r  r  r  rB   rM   r   r  r  r   r  r|  r  r3   r  r  r  r  r  r  r  rV  r  )r9   r   r   rG  r  r9  r  r`  rt  r  r  r   r  r   
role_chunkr#  rS  content_chunkr  r  agent_usagefinish_chunkr  s   &&&&&f&&&              r   r  +APIServerAdapter._write_sse_chat_completion  s!     	%':OZX $$Xr28>t,,V4Dt$1;-.%%S+Fw'''P	] mX/F7GUWa6;2GZ^_`J
 ..6$**Z*@)A!F!M!M!OPPP ))+D"&"6"6t=^"__E( = -3Jw!Wy%6H/[_ `a!
 nnvdjj.G-H%M%T%T%VWWW $QNANE,6&6##,,u mX/F7GUWa"ovNO#UYY~q%A'?A)F"EIIna$@		L ..6$**\*B)C4!H!O!O!QRRR..!4555& i 	( Q `xx !(("&(0(;(;(=#(=$)$(-CZ$-w$-!WyRWFXZiko0p/q1"
 '/nnvdjj>W=XX\5]5d5d5f&g g g#%88 & %&#6 X
 '7  S5$&<owW 	] %.IaL4E OO$=>  ??$$!!#$$$..	: KKLm\%	]s  A	O+O+&0O+IO+AL$ +I
,L$ I  I!I %AL$ 9L:L$ 	L LL L "BL$ 'L (L$  L"L$ O+
L$ I &L7L9K%LAK%K K%#L%K96L8K99L<L$ LL$ L LL$ LL$ "L$ $"O(O(M)(O()M74O(6M77O(O(!N-&N)'N-,O(-OO(
OO($O+'O((O+c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   Y  s     e0 e0} e0 e0r    c                <  a aaaa "   S P                  V4      pV'       d   V#  VP                  4       G Rj  xL
 pTP                  R	4      pTf"   \        P
                  ! \        R
4      RR7      # TP                  R4      oTP                  R4      pTP                  R4      pTP                  RR4      pT'       d*   T'       d"   \        P
                  ! \        R4      RR7      # T'       d   S P                  P                  T4      p. p\        T\        4      '       d
   RRRT/.pEM\        T\        4      '       Ed   T EF{  p	\        T	\        4      '       d   TP                  RRRT	/4       K1  \        T	\        4      '       g   KI  T	P                  RR4      p
T	P                  RR4      p\        T\        4      '       d   . pT F  p\        T\        4      '       d:   TP                  R4      R8X  d$   TP                  TP                  RR4      4       KR  \        T\        4      '       d:   TP                  R4      R8X  d$   TP                  TP                  RR4      4       K  \        T\        4      '       g   K  TP                  T4       K  	  RP                  T4      pTP                  RT
RT/4       EK~  	  M!\        P
                  ! \        R4      RR7      # . oT'       dt   S P                  P                  T4      pTf%   \        P
                  ! \        RT 24      RR7      # \        TP                  R. 4      4      oSf   TP                  R4      oTRR<  F  pSP                  T4       K  	  T'       d   TR<,          P                  RR4      MRo S '       g"   \        P
                  ! \        R4      RR7      # TP                  R4      R8X  d   \!        S4      ^d8  d   SR=R o\        \"        P$                  ! 4       4      oTTT TT 3R  lpTP&                  P                  R!4      pT'       d4   \)        T. R>OR#7      p \*        P-                  TTT4      G Rj  xL
 w  ppM T! 4       G Rj  xL
 w  ppTP                  R*R4      pT'       g   TP                  RR+4      pR,\"        P$                  ! 4       P2                  R-,           2p\5        \6        P6                  ! 4       4      p\        S4      pTP                  RRRS /4       TP                  R.. 4      pT'       d   TP9                  T4       MTP                  RR/RT/4       S P;                  T4      pR0TR1R2R3R4R5TR"TP                  R"R64      R7TR8R9TP                  R9^ 4      R:TP                  R:^ 4      R;TP                  R;^ 4      //pT'       dG   S P                  P=                  TR2TRTRS/4       T'       d   S P                  P?                  TT4       \        P
                  ! T4      #  EL  \        P                  \        3 d"    \        P
                  ! RRRRR//RR7      u # i ; i EL  \         dI   p\.        P1                  R$TRR%7       \        P
                  ! \        R&T 2R'R(7      R)R7      u Rp?# Rp?ii ; i ELB  \         dI   p\.        P1                  R$TRR%7       \        P
                  ! \        R&T 2R'R(7      R)R7      u Rp?# Rp?ii ; i5i)?u3   POST /v1/responses — OpenAI Responses API format.Nr   r   r  r   r+  r   r{   inputMissing 'input' fieldinstructionsprevious_response_idconversationr  Tz9Cannot use both 'conversation' and 'previous_response_id'r  rm  re  rz   
input_textr\  output_textr  z!'input' must be a string or arrayzPrevious response not found: r  r  No user message found in input
truncationautoc                  J   <"   SP                  SS SSR 7      G Rj  xL
 #  L5ir  r  )r  r4  r9   rt  rl  s   r   _compute_response=APIServerAdapter._handle_responses.<locals>._compute_response  s2     )%9(4%	 )    r  r  rG  r  z%Error running agent for responses: %sr  r  r  r  r  r  r  resp_:N   Nr  r>  r  r  r   r|   r  
created_atr  outputr  r  r  r  rg  i)r2  r4  r5  r6  rG  r  ) r0  rB   r@  r3   r   r   rE   r   r   r\   r  r+   r  rh  r  joinr   r  r  r   r   r  r   rV  r   r  r*   rA   ri  _extract_output_itemsrO   ra   )!r9   r   r  r   	raw_inputr5  r6  r  input_messagesr   r  re  
text_partspartstoredr  r=  r"  r   r  r  rX  r  r>   rA  full_historyagent_messagesoutput_itemsr#  r  r4  rt  rl  s!   f&                           @@@@r   _handle_responses"APIServerAdapter._handle_responsesY  s>    ##G,O	 'D HHW%	$$]3J%KTWXXxx/#xx(>?xx/$' 0$$]3n%ox{|| #'#7#7#H#H#V  02i%%%vy)DEN	4((!dC(("))669d*KLd++88FF3D"hhy"5G!'400%'
$+D)$55$((6:Jl:Z * 1 1$((622F G!+D$!7!7DHHV<LP]<] * 1 1$((622F G!+D#!6!6 * 1 1$ 7 %, #'))J"7"))64G*LM# "& $$]3V%W`cdd 68))--.BCF~((9VWkVl7m)nwz{{#'

3I2(N#O #%zz.9 "#2&C '', ' AO~b)--i<TV$$]3S%T]`aa 88L!V+4H0IC0O#7#>  &
	 	 "//--.?@*hB&1&<&<_bRc&d d&7&9 9  $4b9#ZZ1JKNdjjl..s345%
 01VVYEFJ3/i PQ 11&9 +jk*TXXg~6l		.! <?A!>		.! <
   $$[M&3  $$55lKP  //{ ($$i0 	$$9&DfNefg 	x !e DaRVW((!$;A3"?.Y  !: DaRVW((!$;A3"?.Y s  \X+ X(X+ B\?\(\0B\C2\A+\1B\	"\,B&\Y- -Y*.Y- 5\7
[ [[ 	\#D(\)\62\(X+ +9Y'$\&Y''\*Y- -[ 8=Z;5[ 6\;[  \[ \=\\\\\c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     5 5- 5N 5r    c                &  "   V P                  V4      pV'       d   V# VP                  R,          pV P                  P                  V4      pVf%   \        P
                  ! \        RV 24      RR7      # \        P
                  ! VR,          4      # 5i)u?   GET /v1/responses/{response_id} — retrieve a stored response.r>   Response not found: r  r{   r   )r0  r  r   rE   r   r   r   )r9   r   r  r>   rI  s   &&   r   _handle_get_response%APIServerAdapter._handle_get_response  s     ##G,O((7%%))+6>$$]5I+3W%Xadee  
!344s   BBc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s      ] ~ r    c                ,  "   V P                  V4      pV'       d   V# VP                  R,          pV P                  P                  V4      pV'       g%   \        P
                  ! \        RV 24      RR7      # \        P
                  ! RVRRRR	/4      # 5i)
u@   DELETE /v1/responses/{response_id} — delete a stored response.r>   rQ  r  r{   r  r  r   r  T)r0  r  r   rV   r   r   r   )r9   r   r  r>   r  s   &&   r   _handle_delete_response(APIServerAdapter._handle_delete_response  s     ##G,O((7&&--k:$$]5I+3W%Xadee  +jt"
  	s   ABA Brez[a-f0-9]{12}i  c                .   < V ^8  d   QhRS[ R,          /# )r   r   r&  r'  )r   r,   s   "r   r   r   1  s      x'? r    c                ^    V P                   '       g   \        P                  ! RR/RR7      # R# )z5Return error response if cron module isn't available.r   zCron module not availablei  r{   N)_CRON_AVAILABLEr   r   rg   s   &r   _check_jobs_available&APIServerAdapter._check_jobs_available1  s1    ###$$56s  r    c                $   < V ^8  d   QhRRRS[ /# )r   r   r%  r   )r	  )r   r,   s   "r   r   r   9  s      ] u r    c                    VP                   R,          pV P                  P                  V4      '       g   V\        P                  ! RR/RR7      3# VR3# )z>Validate and extract job_id. Returns (job_id, error_response).job_idr   zInvalid job ID formatr   r{   N)r  
_JOB_ID_RE	fullmatchr   r   )r9   r   r`  s   && r   _check_job_idAPIServerAdapter._check_job_id9  sX    ##H-((003,,123   t|r    c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   B  s     D D} D Dr    c                  "   V P                  V4      pV'       d   V# V P                  4       pV'       d   V#  VP                  P                  RR4      P	                  4       R	9   p\        VR7      p\        P                  ! RV/4      #   \         d.   p\        P                  ! R\        T4      /RR7      u Rp?# Rp?ii ; i5i)
u%   GET /api/jobs — list all cron jobs.include_disabledrz   )rg  jobsr   r  r{   N)true1)
r0  r\  r  rE   r  
_cron_listr   r   r3   r+   )r9   r   r  cron_errrg  rh  rX  s   &&     r   _handle_list_jobs"APIServerAdapter._handle_list_jobsB  s     ##G,O--/O	D&}}001CRHNNPTaa/?@D$$fd^44 	D$$gs1v%6sCC	Ds:   3CCAB
 	C
C"B=7C8C=CCc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r   Q  s     .D .D .D. .Dr    c                  "   V P                  V4      pV'       d   V# V P                  4       pV'       d   V#  VP                  4       G Rj  xL
 pVP                  R4      ;'       g    RP	                  4       pVP                  R4      ;'       g    RP	                  4       pVP                  RR4      pVP                  RR4      pVP                  R4      p	VP                  R	4      p
V'       g   \
        P                  ! R
R/RR7      # \        V4      V P                  8  d)   \
        P                  ! R
RV P                   R2/RR7      # V'       g   \
        P                  ! R
R/RR7      # \        V4      V P                  8  d)   \
        P                  ! R
RV P                   R2/RR7      # V
e8   \        V
\        4      '       d   V
^8  d   \
        P                  ! R
R/RR7      # RVRVRVRV/pV	'       d   WR&   V
e   WR	&   \        R/ VB p\
        P                  ! RV/4      #  EL  \         d.   p\
        P                  ! R
\        T4      /RR7      u Rp?# Rp?ii ; i5i)u)   POST /api/jobs — create a new cron job.NrY   rz   schedulepromptdeliverr  skillsrepeatr   zName is requiredr   r{      Name must be ≤  characterszSchedule is required   Prompt must be ≤ z!Repeat must be a positive integerjobr  r#   )r0  r\  rB   rE   r  r   r   r   _MAX_NAME_LENGTH_MAX_PROMPT_LENGTHr  r*   _cron_creater3   r+   )r9   r   r  rl  r   rY   rq  rr  rs  rt  ru  kwargsry  rX  s   &&            r   _handle_create_job#APIServerAdapter._handle_create_jobQ  sB    ##G,O--/O&	D 'DHHV$**113D,2299;HXXh+Fhhy'2GXXh'FXXh'F(('3E)FsSS4y4000(( 1$2G2G1HTU^a  (('3I)JSVWW6{T444(( 3D4K4K3LKXYbe  !:fc+B+Bfqj(('3V)W`cdd &H7	F #)x !#)x ((C$$eS\22G (H  	D$$gs1v%6sCC	Ds   3I+I+H0 H-H0 )(H0 AH0 1H0 
I+AH0 I+H0 H0 .I+/AH0 0I+1:H0 +I+,H0 >.H0 ,I+-H0 0I(;"I#I(I+#I((I+c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r          D D] D~ Dr    c                  "   V P                  V4      pV'       d   V# V P                  4       pV'       d   V# V P                  V4      w  rEV'       d   V#  \        V4      pV'       g   \        P
                  ! RR/RR7      # \        P
                  ! RV/4      #   \         d.   p\        P
                  ! R\        T4      /RR7      u Rp?# Rp?ii ; i5i)u1   GET /api/jobs/{job_id} — get a single cron job.r   Job not foundr  r{   ry  r  N)r0  r\  rc  	_cron_getr   r   r3   r+   r9   r   r  rl  r`  id_errry  rX  s   &&      r   _handle_get_job APIServerAdapter._handle_get_job  s     ##G,O--/O++G4M	DF#C(('?)CCPP$$eS\22 	D$$gs1v%6sCC	DF   3CC,B CB CC&"CC	CCCc                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     D D D. Dr    c                  "   V P                  V4      pV'       d   V# V P                  4       pV'       d   V# V P                  V4      w  rEV'       d   V#  VP                  4       G Rj  xL
 pVP	                  4        UUu/ uF  w  rxWpP
                  9   g   K  WxbK  	  p	ppV	'       g   \        P                  ! RR/RR7      # RV	9   dJ   \        V	R,          4      V P                  8  d)   \        P                  ! RRV P                   R2/RR7      # R	V	9   dJ   \        V	R	,          4      V P                  8  d)   \        P                  ! RR
V P                   R2/RR7      # \        WI4      p
V
'       g   \        P                  ! RR/RR7      # \        P                  ! RV
/4      #  ELAu uppi   \         d.   p\        P                  ! R\        T4      /RR7      u Rp?# Rp?ii ; i5i)u/   PATCH /api/jobs/{job_id} — update a cron job.Nr   zNo valid fields to updater   r{   rY   rv  rw  rr  rx  r  r  ry  r  )r0  r\  rc  rB   r   _UPDATE_ALLOWED_FIELDSr   r   r   rz  r{  _cron_updater3   r+   )r9   r   r  rl  r`  r  r   r   r   	sanitizedry  rX  s   &&          r   _handle_update_job#APIServerAdapter._handle_update_job  s    ##G,O--/O++G4M	D 'D*.**,[,$!!?Z?Z:Z,I[(('3N)OX[\\"s9V+<'=@U@U'U(( 1$2G2G1HTU^a  9$Yx-@)ADD[D[)[(( 3D4K4K3LKXYbe  v1C(('?)CCPP$$eS\22# ([   	D$$gs1v%6sCC	Ds   3G.G.F3 )F**F3 F-F- $F3 G.AF3 G.AF3 $G.%,F3 G.F3 )G.*F3 -F3 3G+>"G& G+!G.&G++G.c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r          D D D. Dr    c                  "   V P                  V4      pV'       d   V# V P                  4       pV'       d   V# V P                  V4      w  rEV'       d   V#  \        V4      pV'       g   \        P
                  ! RR/RR7      # \        P
                  ! RR/4      #   \         d.   p\        P
                  ! R\        T4      /RR7      u Rp?# Rp?ii ; i5i)	u0   DELETE /api/jobs/{job_id} — delete a cron job.r   r  r  r{   r  Tr  N)r0  r\  rc  _cron_remover   r   r3   r+   )r9   r   r  rl  r`  r  r  rX  s   &&      r   _handle_delete_job#APIServerAdapter._handle_delete_job  s     ##G,O--/O++G4M	D"6*G(('?)CCPP$$dD\22 	D$$gs1v%6sCC	Dr  c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s     D D} D Dr    c                  "   V P                  V4      pV'       d   V# V P                  4       pV'       d   V# V P                  V4      w  rEV'       d   V#  \        V4      pV'       g   \        P
                  ! RR/RR7      # \        P
                  ! RV/4      #   \         d.   p\        P
                  ! R\        T4      /RR7      u Rp?# Rp?ii ; i5i)u3   POST /api/jobs/{job_id}/pause — pause a cron job.r   r  r  r{   ry  r  N)r0  r\  rc  _cron_pauser   r   r3   r+   r  s   &&      r   _handle_pause_job"APIServerAdapter._handle_pause_job  s     ##G,O--/O++G4M	Df%C(('?)CCPP$$eS\22 	D$$gs1v%6sCC	Dr  c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     r  r    c                  "   V P                  V4      pV'       d   V# V P                  4       pV'       d   V# V P                  V4      w  rEV'       d   V#  \        V4      pV'       g   \        P
                  ! RR/RR7      # \        P
                  ! RV/4      #   \         d.   p\        P
                  ! R\        T4      /RR7      u Rp?# Rp?ii ; i5i)u<   POST /api/jobs/{job_id}/resume — resume a paused cron job.r   r  r  r{   ry  r  N)r0  r\  rc  _cron_resumer   r   r3   r+   r  s   &&      r   _handle_resume_job#APIServerAdapter._handle_resume_job  s     ##G,O--/O++G4M	Dv&C(('?)CCPP$$eS\22 	D$$gs1v%6sCC	Dr  c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     r  r    c                  "   V P                  V4      pV'       d   V# V P                  4       pV'       d   V# V P                  V4      w  rEV'       d   V#  \        V4      pV'       g   \        P
                  ! RR/RR7      # \        P
                  ! RV/4      #   \         d.   p\        P
                  ! R\        T4      /RR7      u Rp?# Rp?ii ; i5i)u<   POST /api/jobs/{job_id}/run — trigger immediate execution.r   r  r  r{   ry  r  N)r0  r\  rc  _cron_triggerr   r   r3   r+   r  s   &&      r   _handle_run_job APIServerAdapter._handle_run_job  s     ##G,O--/O++G4M	D'C(('?)CCPP$$eS\22 	D$$gs1v%6sCC	Dr  c                b   < V ^8  d   QhRS[ S[S[3,          RS[S[ S[S[3,          ,          /# )r   r  r   r   )r   r,   s   "r   r   r     s0     - -d38n -d38n9M -r    c                   . pV P                  R. 4      pV F  pVP                  R4      pVR8X  d   VP                  R4      '       dn   VR,           F^  pVP                  R/ 4      pVP                  RRRVP                  RR	4      R
VP                  R
R	4      RVP                  RR	4      /4       K`  	  K  VR8X  g   K  VP                  RRRVP                  RR	4      RVP                  RR	4      /4       K  	  V P                  RR	4      pV'       g   V P                  RR4      pVP                  RRRRRRRRV/./4       V# )a  
Build the full output item array from the agent's messages.

Walks *result["messages"]* and emits:
- ``function_call`` items for each tool_call on assistant messages
- ``function_call_output`` items for each tool-role message
- a final ``message`` item with the assistant's text reply
r  r  r>  r  r?  r   function_callrY   rz   r@  call_idr  rw  function_call_outputr  rB  re  r  r   r  r   r8  r\  )rE   rh  )r  r   r  r  r  tcfuncr~  s   &       r   rD  &APIServerAdapter._extract_output_items  sN    ')::j"-C776?D{"sww|'<'<l++B66*b1DLL 4#TXXk2%>!266$#3	"  , 2sww~r:cggi4  & 

+R0JJw(ABEIKME	
 		 r    c                   < V ^8  d   QhRS[ RS[S[S[ S[ 3,          ,          RS[S[ ,          RS[S[ ,          RS[S[,          RS[/# )r   rl  r  rs  rt  r`  r   )r+   r   r   r   r  r	  )r   r,   s   "r   r   r   9  s`     +6 +6+6 #4S>2+6 "*#	+6
 SM+6 D>+6 
+6r    c                   a aaaaaaa"   \         P                  ! 4       pVVVV VVVV3R lp	VP                  RV	4      G Rj  xL
 #  L5i)a  
Create an agent and run a conversation in a thread executor.

Returns ``(result_dict, usage_dict)`` where *usage_dict* contains
``input_tokens``, ``output_tokens`` and ``total_tokens``.

If *agent_ref* is a one-element list, the AIAgent instance is stored
at ``agent_ref[0]`` before ``run_conversation`` begins.  This allows
callers (e.g. the SSE writer) to call ``agent.interrupt()`` from
another thread to stop in-progress LLM calls.
c            
         < SP                  SSSS	R 7      p Se   V S^ &   V P                  S
SR7      pR\        V R^ 4      ;'       g    ^ R\        V R^ 4      ;'       g    ^ R\        V R^ 4      ;'       g    ^ /pW3# )r_  rl  r  r  r  r  r  r  r  )r  r	  r
  )r  r  r  r`  r  rs  r9   rt  r  r  rl  s      r   r  )APIServerAdapter._run_agent.<locals>._runP  s    &&(?%&;'=	 ' E $$	!++)%9 , F
 /F J O Oa0KQ!O!T!TST/Eq I N NQE
 = r    N)r  r  r   )
r9   rl  r  rs  rt  r  r  r`  r#  r  s
   ffffffff  r   r  APIServerAdapter._run_agent9  s;     * %%'	! 	!( ))$5555s   8A	AA	r   c                $   < V ^8  d   QhRS[ RR/# )r   r  r#  zasyncio.AbstractEventLoopr_   )r   r,   s   "r   r   r   m  s     ' 's ':U 'r    c                <   a aaa R VVV 3R lloRR VV3R lllpV# )zUReturn a tool_progress_callback that pushes structured events to the run's SSE queue.c                J    V ^8  d   QhR\         \        \        3,          RR/# )r   eventr   NrE  )r   s   "r   r   ?APIServerAdapter._make_run_event_callback.<locals>.__annotate__o  s"     	 	c3h 	D 	r    c                    < SP                   P                  S4      pVf   R #  SP                  VP                  V 4       R #   \         d     R # i ; ir  )r  rE   call_soon_threadsafe
put_nowaitr3   )r  r  r#  r  r9   s   & r   _push8APIServerAdapter._make_run_event_callback.<locals>._pusho  sL    !!%%f-Ay))!,,> s   A AAc                <    V ^8  d   QhR\         R\         R\         /# )r   
event_typer  rY  r_   )r   s   "r   r   r  x  s!     	 	# 	# 	s 	r    c                 <  < \         P                   ! 4       pV R 8X  d   S! RR RSRVRVRV/4       R# V R8X  dA   S! RRRSRVRVR\        VP                  R^ 4      ^4      RVP                  R	R
4      /4       R# V R8X  d   S! RRRSRTRT;'       g    R/4       R# R# )rZ  r  r  	timestamprw  rY  rx  durationr   is_errorFzreasoning.availabler\  rz   N)rA   roundrE   )r  r  rY  rB  r}  r   r  r  s   &&&&, r   	_callback<APIServerAdapter._make_run_event_callback.<locals>._callbackx  s    B^+^fIw  //-fIfjjQ&? CVZZ
E:  442fGMMr	  5r    )NNNr#   )r9   r  r#  r  r  s   fff @r   _make_run_event_callback)APIServerAdapter._make_run_event_callbackm  s    	 		 	8 r    c                "   < V ^8  d   QhRRRR/# r$  r#   )r   r,   s   "r   r   r     s#     tV tV- tVN tVr    c           	       a a
aaaaaaaa"   S P                  V4      pV'       d   V# \        S P                  4      S P                  8  d2   \        P
                  ! \        RS P                   R2RR7      RR7      #  VP                  4       G Rj  xL
 pTP                  R
4      pT'       g"   \        P
                  ! \        R4      R	R7      # \        T\        4      '       d   TM0\        T\        4      '       d   TR,          P                  RR4      MRoS'       g"   \        P
                  ! \        R4      R	R7      # R\        P                  ! 4       P                   2o\         P"                  ! 4       o\         P$                  ! 4       oSS P                  S&   \&        P&                  ! 4       S P(                  S&   S P+                  SS4      oR TTT3R llo
TP                  R4      pTP                  R4      p. oT'       dT   S P,                  P                  T4      pT'       d1   \        TP                  R. 4      4      oTf   TP                  R4      pTP                  R4      ;'       g    SoToT
TTTTTT TT3	R lp\         P.                  ! T! 4       4      p	 S P0                  P3                  T	4       \7        T	R4      '       d&   T	P9                  S P0                  P:                  4       \        P
                  ! RSRR/^R7      #  EL  \         d%    \        P
                  ! \        R4      R	R7      u # i ; i  \4         d     Li ; i5i)u@   POST /v1/runs — start an agent run, return run_id immediately.zToo many concurrent runs (max )rate_limit_exceededr   i  r{   NzInvalid JSONr   r2  r3  re  rz   r9  r  c                >    V ^8  d   QhR\         \        ,          RR/# )r   rS  r   N)r   r+   )r   s   "r   r   3APIServerAdapter._handle_runs.<locals>.__annotate__  s     	 	HSM 	d 	r    c                    < V f   R #  SP                  SP                  RRRSR\        P                  ! 4       RV /4       R #   \         d     R # i ; i)Nr  zmessage.deltar  r  rS  )r  r  rA   r3   )rS  r#  r  r  s   &r   _text_cb/APIServerAdapter._handle_runs.<locals>._text_cb  sW    }))!,,_fU	9   s   7A AAr4  r5  r  rt  c                    <	a"    SP                  SSSS	R 7      oVVV3R lp \        P                  ! 4       P                  RV 4      G Rj  xL
 w  r\	        V\
        4      '       d   VP                  RR4      MRpS
P                  RRRSR\        P                  ! 4       R	VR
V/4        S
P                  R4       R#  Lr  \         dl   p\        P                  RS4        S
P                  RRRSR\        P                  ! 4       R\        T4      /4        Rp?Lr  \         d      Rp?Li ; iRp?ii ; i  \         d     R# i ; i   S
P                  R4       i   \         d     i i ; i; i5i)r_  c            
         < SP                  SSR 7      p R\        SR^ 4      ;'       g    ^ R\        SR^ 4      ;'       g    ^ R\        SR^ 4      ;'       g    ^ /pW3# )r  r  r  r  r  r  r  )r	  r
  )rur  r  rl  s     r   	_run_syncHAPIServerAdapter._handle_runs.<locals>._run_and_close.<locals>._run_sync  sz    ..%1-A / A
 '7NPQ(R(W(WVW'8SUV)W)\)\[\&7Mq(Q(V(VUVA
 4Kr    Nr  rz   r  r{  r  r  rB  r  z[api_server] run %s failedz
run.failedr   )r  r  get_running_loopr   r  r  rE   r  rA   r3   rV  	exceptionr+   )r  r  r  r  excr  r  r  rs  event_cbr  r  r9   rt  rl  s        @r   _run_and_close5APIServerAdapter._handle_runs.<locals>._run_and_close  sb    ,**,C)*2+3	 + 
  '.&>&>&@&P&PQUW`&a aEOPVX\E]E],<b!Ace_fnU (LL&/ !b  
  !=vFLL &#TYY[S	"   ! 
 ! LL&  s   E3AC  B>AC  +D9 <E3>C   D6D1"5DE D.'D1(E -D..D11D66E 9EE3EE3E0EE0E-*E0,E--E00E3add_done_callbackr  r|   startedrg  )r0  r   r  _MAX_CONCURRENT_RUNSr   r   r   rB   r3   rE   r  r+   r  r  r  r  r  r  r  rA   r  r  r   create_task_background_tasksr  r?  hasattrr  discard)r9   r   r  r   rE  r4  r5  rI  r  taskr  r  rs  r  r#  r  r  rt  rl  s   f&        @@@@@@@@@r   _handle_runsAPIServerAdapter._handle_runs  s    ##G,O t  !T%>%>>$$ >t?X?X>YYZ[bwx 
	P 'D HHW%	$$]3J%KTWXX$.y#$>$>yist}  @D  jE  jEYr]EVEVW`bdEe  KM$$]3S%T]`aa

(()*'')-4]]_$%&!,0IIK!!&)00>	 	 xx/#xx(>?57))--.BCF'+FJJ7Mr,R'S$'#)::n#=LXXl+55v
".-	 -	^ "">#34	""&&t, 4,--""4#9#9#A#AB  (FHi!HQTUUM ( 	P$$]>%B3OO	P@  		s   A1M>L LL M/A1M!C&M"M+AM3.M"M =AML ,M?MMMMMMMc                "   < V ^8  d   QhRRRR/# r'  r#   )r   r,   s   "r   r   r   	  s     / / /BV /r    c           	       "   V P                  V4      pV'       d   V# VP                  R,          p\        ^4       F3  pW0P                  9   d    MH\        P
                  ! R4      G Rj  xL
  K5  	  \        P                  ! \        RV 2RR7      RR7      # V P                  V,          p\        P                  ! ^R	R
RRRR/R7      pVP                  V4      G Rj  xL
     \        P                  ! VP                  4       RR7      G Rj  xL
 pTf   TP                  R4      G Rj  xL
  MCR\        P                   ! T4       R2pTP                  TP#                  4       4      G Rj  xL
  K  T P                  P+                  TR4       T P,                  P+                  TR4       T#  ELE L L  \        P                   d     TP                  R4      G Rj  xL 
   EK  i ; i L L  \$         d!   p	\&        P)                  RY94        Rp	?	LRp	?	ii ; i  T P                  P+                  TR4       T P,                  P+                  TR4       i ; i5i)uQ   GET /v1/runs/{run_id}/events — SSE stream of structured agent lifecycle events.r  g?NzRun not found: run_not_foundr   r  r{   rd  re  rf  rg  ri  rj  r~   g      >@rp  s   : keepalive

s   : stream closed

r(  r3  z,[api_server] SSE stream error for run %s: %s)r0  r  ranger  r  sleepr   r   r   r  r  wait_forrE   TimeoutErrorr  rB   rM   r   r3   rV  rW  r   r  )
r9   r   r  r  r  r  r   r  r-  r  s
   &&        r   _handle_run_events#APIServerAdapter._handle_run_events	  s    ##G,O##H- rA***--%%% 
 $$]_VH3MTc%dmpqqf%%% 3#T
 w'''	8")"2"21557D"IIE ="..)?@@@"4::e#4"5T:nnW^^%5666 !!&$/%%))&$7G & 	(
 J++ "..);<<<
 A 7 	VLLGUU	V !!&$/%%))&$7s   A(I*F/+A3IF2I$G1 &)F6 F4F6 G1 ,G--G1 1H 2<G1 .G//G1 5;I2I4F6 6)G*G" G*%G1 )G**G1 /G1 1H<HH HH :IIc                   < V ^8  d   QhRR/# rd   r#   )r   r,   s   "r   r   r   =	  s     < <D <r    c                  "    \         P                  ! ^<4      G Rj  xL
  \        P                  ! 4       p\        V P                  P                  4       4       UUu. uF   w  r#W,
          V P                  8  g   K  VNK"  	  pppV FQ  p\        P                  RV4       V P                  P                  VR4       V P                  P                  VR4       KS  	  K   Lu uppi 5i)z;Periodically clean up run streams that were never consumed.Nz%[api_server] sweeping orphaned run %s)r  r  rA   r  r  r   _RUN_STREAM_TTLrV  rW  r  r   )r9   r   r  rA  stales   &    r   _sweep_orphaned_runs%APIServerAdapter._sweep_orphaned_runs=	  s     --###))+C +/t/H/H/N/N/P*Q*Q&F#d&:&:: *Q  
  DfM!!%%fd3))--fd;   $s(   C'C?C'C!=C!AC'!C'c                    < V ^8  d   QhRS[ /# r   r   )r   r,   s   "r   r   r   P	  s     T Tt Tr    c                  "   \         '       g#   \        P                  RV P                  4       R#  \        \
        \        3 Uu. uF
  qf   K  VNK  	  pp\        P                  ! VR7      V n	        W P                  R&   V P                  P                  P                  RV P                  4       V P                  P                  P                  RV P                  4       V P                  P                  P                  RV P                  4       V P                  P                  P                  R	V P                  4       V P                  P                  P                  R
V P                   4       V P                  P                  P                  RV P"                  4       V P                  P                  P%                  RV P&                  4       V P                  P                  P                  RV P(                  4       V P                  P                  P                  RV P*                  4       V P                  P                  P                  RV P,                  4       V P                  P                  P/                  RV P0                  4       V P                  P                  P%                  RV P2                  4       V P                  P                  P                  RV P4                  4       V P                  P                  P                  RV P6                  4       V P                  P                  P                  RV P8                  4       V P                  P                  P                  RV P:                  4       V P                  P                  P                  RV P<                  4       V P                  P                  P                  RV P>                  4       V P                  P                  P                  RV P@                  4       V P                  P                  P                  RV PB                  4       V P                  P                  P                  RV PD                  4       V P                  P                  P                  RV PF                  4       V P                  P                  P/                  RV PH                  4       V P                  P                  P%                  RV PJ                  4       V P                  P                  P                  RV PL                  4       V P                  P                  P                  RV PN                  4       V P                  P                  P                  RV PP                  4       V P                  P                  P                  RV PR                  4       V P                  P                  P                  RV PT                  4       V P                  P                  P/                  RV PV                  4       V P                  P                  P%                  RV PX                  4       V P                  P                  P                  RV PZ                  4       V P                  P                  P                  RV P\                  4       V P                  P                  P                  RV P^                  4       V P                  P                  P                  RV P`                  4       V P                  P                  P/                  RV Pb                  4       V P                  P                  P                  RV Pd                  4       \f        Ph                  ! V Pk                  4       4      p V Pl                  Po                  V4       \s        VR 4      '       d&   VPu                  V Pl                  Pv                  4       ^ RI<p VPy                  VPz                  VP|                  4      ;_uu_ 4       pVP                  ^4       VP                  R!V P                  34       RRR4       \        P                  R"V P                  V P                  4       R# u upi   \p         d     Li ; i  + '       g   i     LS; i  \        \        3 d     Mi ; i\        P                  ! T P                  4      T nF        T P                  P                  4       G Rj  xL 
  \        P                  ! T P                  T P                  T P                  4      T nJ        T P                  P                  4       G Rj  xL 
  T P                  4        \        P                  R#T P                  T P                  T P                  4       R$#   \         d-   p\        P                  R%T P                  T4        Rp?R# Rp?ii ; i5i)&zStart the aiohttp web server.z[%s] aiohttp not installedFN)middlewaresrx   z/healthz
/v1/healthz
/v1/modelsz/v1/chat/completionsz/v1/responsesz/v1/responses/{response_id}z	/api/jobsz/api/jobs/{job_id}z/api/jobs/{job_id}/pausez/api/jobs/{job_id}/resumez/api/jobs/{job_id}/runz/v1/runsz/v1/runs/{run_id}/eventsz/api/sessionsz/api/sessions/searchz/api/sessions/{session_id}z#/api/sessions/{session_id}/messagesz/api/sessions/{session_id}/forkz/api/sessions/{session_id}/chatz&/api/sessions/{session_id}/chat/streamz/api/memoryz/api/skillsz/api/skills/categoriesz/api/skills/{name}z/api/configz/api/available-modelsr  r   z[[%s] Port %d already in use. Set a different port in config.yaml: platforms.api_server.portz)[%s] API server listening on http://%s:%dTz#[%s] Failed to start API server: %s)Or"   rV  r  rY   r   r   r   r   Applicationr   routeradd_getr  r  add_postr$  rM  rR  
add_deleterV  rm  r~  r  	add_patchr  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r$  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r?  r  r  r  socketAF_INETSOCK_STREAM
settimeoutr5   r   r   ConnectionRefusedErrorr  	AppRunnerr   setupTCPSiter   r   start_mark_connectedr  r3   )r9   mwmws
sweep_task_socket_srX  s   &      r   r5   APIServerAdapter.connectP	  s      NN7CN	!02GId ex e"22 eCxC8DI.2II*+II$$Y0C0CDII$$\43F3FGII$$\43F3FGII%%&<d>[>[\II%%ot7M7MNII$$%BDD]D]^II''(EtGcGcdII$$[$2H2HIII%%k43J3JKII$$%94;O;OPII&&';T=T=TUII''(<d>U>UVII%%&@$BXBXYII%%&A4CZCZ[II%%&>@T@TUII%%j$2C2CDII$$%?AXAXYII$$_d6P6PQII%%ot7R7RSII$$%;T=Y=YZII$$%A4C[C[\II$$%JDLmLmnII&&'CTE`E`aII''(DdFaFabII%%&GIbIbcII%%&GIbIbcII%%&NPTPpPpqII$$]D4K4KLII%%mT5L5LMII&&}d6Q6QRII''t7Q7QRII$$]D4L4LMII$$%=t?\?\]II$$%94;R;RSII$$]D4K4KLII&&}d6P6PQII$$%<d>[>[\ ,,T-F-F-HIJ&&**:6 z#677,,T-C-C-K-KL %^^GOOW5H5HIIRMM!$JJTZZ89 J z  }A  }F  }F  HL  HR  HR  Sw y^   JI
 +G4  ==3DL,,$$&&&T\\4::tzzJDJ**""$$$  "KK;		4::tzz  	LL>		1M	s   /g'f- a?a?] f- b 1;f- -.b( /b
3b( =g'?f- bf- bf- b%	 b( (b<9f- ;b<<Af- dAf- e" Af- +g'-g$8!gg'g$$g'c                   < V ^8  d   QhRR/# rd   r#   )r   r,   s   "r   r   r   	  s     : :$ :r    c                  "   V P                  4        V P                  '       d*   V P                  P                  4       G Rj  xL
  RV n        V P                  '       d*   V P                  P	                  4       G Rj  xL
  RV n        RV n        V P                  e"   V P                  P                  4        RV n        RV n        \        P                  RV P                  4       R#  L Ll5i)zStop the aiohttp web server.Nz[%s] API server stopped)_mark_disconnectedr   r  r   cleanupr   r  rf   r  rV  r  rY   rg   s   &r   
disconnectAPIServerAdapter.disconnect	  s     !:::**//###DJ<<<,,&&(((DL	'""$#D!-tyy9 $ )s+   A C,C(C, C,=C*>A+C,*C,c                n   < V ^8  d   QhRS[ RS[ RS[S[ ,          RS[S[S[ S[3,          ,          RS[/# )r   chat_idre  reply_tometadatar   )r+   r   r   r   r
   )r   r,   s   "r   r   r   	  sU     
d 
d
d 
d 3-	
d
 4S>*
d 

dr    c                $   "   \        RRR7      # 5i)uE   
Not used — HTTP request/response cycle handles delivery directly.
Fz1API server uses HTTP request/response, not send())r  r   )r
   )r9   r  re  r  r  s   &&&&&r   sendAPIServerAdapter.send	  s      %/bccs   c                <   < V ^8  d   QhRS[ RS[S[ S[3,          /# )r   r  r   rI   )r   r,   s   "r   r   r   	  s#     
 
3 
4S> 
r    c                F   "   RRRRRV P                   RV P                  /# 5i)z'Return basic info about the API server.rY   z
API Serverr   apir   r   )r   r   )r9   r  s   &&r   get_chat_infoAPIServerAdapter.get_chat_info	  s-      LEDJJDJJ	
 	
s   !)r   r   r   r   r  r   r   r  r  r   r  r   )r   r  )NNNN)NN>   rY   skillrr  ru  rt  rs  enabledrq  )NNNNN)Orn   ro   rp   rq   rr   r:   staticmethodr   r   r   r0  r4  r9  rB  rL  rR  rY  rp  r  r  r  r  r  r  r  r  r  r  r  r$  r  r  r  r  r  r  r  r  r  r  r  r$  r  rM  rR  rV  _CRON_MODULE_AVAILABLEr[  
__import__compilera  r  rz  r{  r\  rc  rm  r~  r  r  r  r  r  r  rD  r  r  r  r  r  r  r  r5   r  r  r   rt   ru   __classcell__)r  r,   s   @@r   r   r   3  s2    9 9( O O (I I
 
*   " "   M M&    $ 0# 0# 0#d< <DO O *C C( 7  7D^ ^"	7 	7
H 
H7 7:	/ 	/&R &RPI IVd dL7 748 8$8 8&8 8$M MB BT T 3 3j5c 5cnv] v]pj jXe0 e0V5 5 0 -OD!))/:Jn  D D.D .D`D D&D DBD D&D D&D D&D D. - -f+6 +6b O' 'RtV tVl/ /b< <&T Tl: : 
d 
d
 
 
r    r   )r+  NN)Krr   r  rB   loggingr   r4   rA   r  typingr   r   r   r   r  r   r"   r  gateway.configr   r   gateway.platforms.baser	   r
   r2   r   r   hermes_cli.modelsr   r   rU  r   tools.memory_toolr   tools.skills_toolr   r   r   	getLoggerrn   rV  r   r   rs   r   r$   r&   r  
middlewarer   r   r   r   r   r   r  r   	cron.jobsr   rk  r   r  r   r|  r   r  r   r  r   r  r   r  r   r  r%  r   r#   r    r   <module>r3     s  *    	    , ,
 4 7 S " ) H H			8	$   
h$ h$` #$L"$R ^^ ( O	 ^^
& 
& ! i}  ^^  #' :  !<#	 	 	 "
V"
* V"
c  
CZ  #"#s#   D: E :E	E		EE