+
    jHàj”3 ã                   ó   a € ER% Etâ0 t 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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 ^ RIHtHt ^ RIHt ^ RIHt ^ RIHtHtH t H!t!H"t"H#t#H$t$ ^ RI%H&t& ^ R	I'H(t( ^ R
I)H*t*H+t+H,t,H-t-H.t.H/t/H0t0H1t1H2t2H3t3 ^ RI4H5t5H6t6H7t7 ^ RI8H9t9 ^ RI:H;t; ^ RI<H=t=H>t>H?t?H@t@HAtA ^ RIBHCtC ^ RIDHEtEHFtF ^ RIGHHtHHItI ^ RIJHKtK ^ RILHMtM ^€tNRtORtPRtQRtRRtS^tTER&tURtVER'tW]P°                  ! R4      tYRtZ]P°                  ! R]P¶                  ! ],4       R]P¶                  ! ]+4       R]P¶                  ! ]*4       R2]P¸                  ]Pº                  ,          4      t^ER(t_Rt`R taR! tbR" R# ltcR$ R% ltdR& R' lteR( R) ltfR* R+ ltgR,R-/R. R/ llthR0R1/R2 R3 lltiER)R4 R5 lltjR6 R7 ltk]P°                  ! RPÙ                  R8 ],]+]*]2]3]1]0].]/]-3
 4       4      ]P¸                  4      tmR9 R: ltn]o! 0 ER*m4      tpR; R< ltq]P°                  ! R=]P¸                  4      tr]P°                  ! R>]P¸                  4      ts]P°                  ! R?]P¸                  4      ttER+tu]P°                  ! R@RPÙ                  ]u4      ,           R,           ]P¸                  4      tvER,tw]P°                  ! R@RPÙ                  ]w4      ,           R,           ]P¸                  4      txER-ty]P°                  ! R@RPÙ                  ]y4      ,           R,           ]P¸                  4      tzRA RB lt{RC RD lt|ER)RER/RF RG lllt}ER)RH RI llt~RJ RK lt]o! 0 ER.m4      t€RL RM lt�RN RO lt‚RP RQ ltƒRR RS lt„RTRURVRURWR1/RX RY llt…]tRZ3]sR[3]rR\3]xR]3]zR^3]vR_33t†R` Ra lt‡Rb Rc ltˆRd Re lt‰ER/tŠ]P°                  ! RfRPÙ                  ]Š]uRg,          ,           ER0,           4      ,           R,           ]P¸                  4      t‹Rh Ri ltŒRj Rk lt�Rl Rm ltŽRn Ro lt�Rp t�Rq Rr lt‘RsRU/Rt Ru llt’Rv Rw lt“RxR1RERRyR/Rz R{ llt”R| R} lt•ER1t–Rt—R~t˜R R€ lt™R� R‚ ltšRƒ R„ lt›R… R† ltœR‡ Rˆ lt�R‰ RŠ ltžR‹ RŒ ltŸR� RŽ lt R�RR�R/R‘ R’ llt¡ER2R“RU/R” R• lllt¢R“RU/R– R— llt£ER3t¤] ^ k ER4R˜ R™ llt¥Ršt¦R›t§Rœt¨R� Rž lt©RŸ R  ltªER)R¡ R¢ llt«R£ R¤ lt¬ER)R¥ R¦ llt­R§ R¨ lt®R© Rª lt¯R«RR¬R1/R­ R® llt°R¯ R° lt±R± R² lt²R³ R´ lt³0 ER5mt´^ RµIµH¶t¶ R¶t·R·t¸R¸ R¹ lt¹Rº R» ltºER6t»]P°                  ! R¼]P¸                  4      t¼^ R½I½H¾t¿ ER7R¾ R¿ lltÀRÀ RÁ ltÁRÂ RÃ ltÂRÄ RÅ ltÃRÆ RÇ ltÄRÈ RÉ ltÅRÊ RË ltÆRÌ]EPŽ                  RÍ&   ]EP�                  EP“                  ^ ]Ê! ]! ]Ë4      EP˜                  EP˜                  4      4       ^ RÎIÍHÎtÎHÏtÏHÐtÐ ]Ð! 4       tÑ^ RÏIÒHÓtÓ ]ÑRÐ,          tÔ]Ó! ]Ñ]! ]Ë4      EP«                  4       EP¬                  ^,          RÐ,          RÑ7       RÒ RÓ lt×RÔ RÕ ltØRÖ R× ltÙ^ RØIÚHÛtÜHÝtÞHßtß  ! RÙ RÚ]à4      tá ! RÛ RÜ]â4      tãRÝ RÞ ltäRß Rà ltåRá Râ ltæRã Rä ltçRå Ræ ltèRç Rè ltéRé Rê ltêER2Rë Rì lltëRí Rî ltì]ÞER)RïRU/Rð Rñ lll4       tí]ÜRò Ró l4       tîRô Rõ ltïRö R÷ ltðRø Rù ltñ]P°                  ! Rú4      tòRûRü0tó^ RýIôHõtö ]Ê! ]öRþ,          Rÿ,          4      ]EPŽ                  ER &   ERERRÿER ERERERERERERER	ER
ERERERERERERERER/
t÷ERERERER/tøERERERERERER/tùER ER ltúER ER  ltûER! ER" ltüER# ER$ ltýER% ER& ltþER' ER( ltÿ]ÑER),          Et / Et] ^k E] EP                  4       '       d    ]ÿ! E] 4      Et]þ! E]4        ^ ER.IÍEHEt E]EP                  ER// 4      Et
E]! E]
E]4      '       d&   E]
EP                  ER04      '       d   E]! RUER17        ^ ER3IGEHEt E]! 4         ^ ER5IGEHEt E]! 4        RÌ]EPŽ                  ER7&   ^ ER8EIEHEtEHEt ^ ER9EIEHEtEHEtEHEtEHEtEHEtEHEt ^ ER:EIEHEtEHEtEHEtEHEtEHEtEH Et  ^ ER;EI!EH"Et" ^ ER<EI#EH$Et$ ^ ER=EI%EH&Et&EH'Et'EH(Et( ^ ER>EI)EH*Et* ^ ER?EI+EH,Et, ^ ER@EI-EH.Et. ^ ERAEI/EH0Et0 ^ ERBEI1EH2Et2 ^ ERCEI3EH4Et4 ^ ERDEI5EH6Et6EH7Et7 ^ EREEI8EH9Et9EH:Et: ^ ERFEI;EH<Et< ^ ERGEI=EH>Et> ^ ERHEI?EH@Et@EHAEtA ^ ERIEIBEHCEtC ^ ERJEIDEHEEtE ^ ERKEIFEHGEtG ^ ERLEIHEHIEtI ^ ERMEIJEHKEtK ^ ERNEILEHMEtM ^ EROEINEHOEtO ^ ERPEIPEHQEtQEHREtREHSEtS ^ ERQEITEHUEtUEHVEtV ^ ERREIWEHXEtXEHYEtYEHZEtZEH[Et[ ]EP¸                  ! E]4      Et]ER)ERS ERT llEt^ERUEt_ERV ERW lEt`E]a! 4       EtbER8Etc] ^k ERX ERY lEtdERZ ER[ lEte]	EPÌ                  ! RUER\7       ! ER] ER^4      4       EtgER9ER_ ER` llEthER)ERa ERb llEtiERc ERd lEtjERe ERf lEtkERg ERh lEtlERi ERj lEtmERk ERl lEtnERm ERn lEtoERo ERp lEtpERq ERr lEtqERs ERt lEtrERuRU/ERv ERw llEtsERx ERy lEttERz ER{ lEtuER| ER} lEtvER~EtwEREtxER€EtyER�EtzER‚Et{ERƒEt|ER„Et}ER…Et~ER†EtER‡Et€ERˆR/ER‰ ERŠ llEt�ER:Et‚ER‹ ERŒ lEtƒERˆR/ER� ERŽ llEt„ER�RERˆR/ER� ER‘ llEt…]o! E]wEP                  4       E]xEP                  4       E]yEP                  4       E]~EP                  4       E]{EP                  4       E]EP                  4       E]€EP                  4       04      Et‡ER’ ER“ lEtˆER” ER• lEt‰ER– ER— lEtŠER˜ ER™ lEt‹ERš ER› lEtŒERœ ER� lEt�ERž ERŸ lEtŽER)ER  ER¡ llEt�^ ER¢EI�EH‘Et’ ER)ER£ ER¤ llEt“ER¥RER¦R/ER§ ER¨ llEt”ER¥RER¦R/ER© ERª llEt•ER« ER¬ lEt–]P°                  ! ER­4      Et—ER® ER¯ lEt˜ER;ER° ER± llEt™ER)ER² ER³ llEtšER´ ERµ lEt›ER¶ ER· lEtœ^ REI�EtžER¸ EsŸ] ^k ER¹^ /ERº ER» llEt ER¼ ER½ lEt¡ER¾ ER¿ lEt¢ERÀ ERÁ lEt£ERÂ ERÃ lEt¤ERÄEt¥ERÅ ERÆ lEt¦ERÇ ERÈ lEt§ERÉ ERÊ lEt¨E]a! 4       Et©ERËERÌ/EtªERÍ ERÎ lEt«ERÏ ERÐ lEt¬ERÑ ERÒ lEt­E]EP\                  ER<E]EP^                  ER=E]EP`                  ER>/Et±] ^k ERÓ ERÔ lEt²^ ERÕEI³EH´Et´  ! ERÖ ER×E]*E],E].E]0E]2E]4E]6E]9E]<E]>E]@E]CE]EE]GE]IE]KE]´E]ME]O4      EtµER�ERØ/ERÙ ERÚ llEt¶ERÛ ERÜ lEt·ERÝ ERÞ lEt¸ERß ERà lEt¹ERá ERâ lEtºERã ERä lEt»ERå ERæ lEt¼ERç ERè lEt½ERé ERê lEt¾ER)ERë ERì llEt¿ERí ERî lEtÀERï ERð lEtÁERñ ERò lEtÂER)ERó ERô llEtÃER?ERõ ERö llEtÄER@ER÷ ERø llEtÅERù ERú lEtÆERûEtÇERüEtÈERAERý ERþ llEtÉERBERÿ ER  llEtÊER ER lEtËER ER lEtÌER ER lEtÍER ER lEtÎER	 ER
 lEtÏER ER lEtÐER EtÑER4ER ER llEtÒER ER lEtÓER ER lEtÔER ER lEtÕER ER lEtÖER ER lEt×^ EREIØEHÙEtÙEHÚEtÚEHÛEtÛEHÜEtÜ ER4ER ER llEtÝERCER ER llEtÞER ER  lEtßER! EtàER" ER# lEtáE]ER$8X  d   E]à! 4        R# R#   ] d   t]P
                  R8w  d   h  RtAELîRtAii ; i  ]â d\   EtE]! ER*E]! E]4      EP                   ER+E] 2]EP                  ER,7       E]! ER-]EP                  ER,7        REtEAELÏREtEAii ; i  ]â d-   EtE]! ER2E] 2]EP                  ER,7        REtEAEL®REtEAii ; i  ]â d-   EtE]! ER4E] 2]EP                  ER,7        REtEAELÒREtEAii ; i  ]â d-   EtE]! ER6E] 2]EP                  ER,7        REtEAELöREtEAii ; i(D  zäGateway runner - entry point for messaging platform integrations.

Provides ``start_gateway()`` (start all configured adapters) and ``GatewayRunner`` (lifecycle).
Run via ``python -m gateway.run`` or ``python cli.py --gateway``.NÚhermes_bootstrap)ÚOrderedDict)ÚContextÚcopy_context©ÚPath)Údatetime)ÚCallableÚDictÚOptionalÚAnyÚListÚTupleÚcast)Úsafe_schedule_threadsafe©Út)
ÚCOMPACTION_DONE_STATUSÚCOMPACTION_HEARTBEAT_STATUSÚCOMPACTION_STATUSÚ1COMPRESSION_RETRY_CONTEXT_REDUCED_STATUS_TEMPLATEÚ*COMPRESSION_RETRY_MESSAGES_STATUS_TEMPLATEÚ(COMPRESSION_RETRY_TOKENS_STATUS_TEMPLATEÚ+COMPRESSION_RETRY_TOO_LARGE_STATUS_TEMPLATEÚIDLE_COMPACTION_STATUS_TEMPLATEÚ#PRE_API_COMPRESSION_STATUS_TEMPLATEÚ%PREFLIGHT_COMPRESSION_STATUS_TEMPLATE)ÚMERGED_DURABLE_ROWSÚRETIRED_DURABLE_ROWSÚUNNAMED_DURABLE_ROWS)Ú"INTERRUPT_WAITING_FOR_MODEL_PREFIX)Úrequest_hard_interrupt)ÚABSORBED_MESSAGE_UIDSÚMESSAGE_UIDÚcopy_identity_fieldsÚis_compaction_scaffoldingÚscaffolding_replay_fields©Úcompression_made_progress)ÚActivityProvenanceÚAwakeIdleMeter)Ú_is_ssh_remote_tilde_cwdÚcfg_get)Úpre_agent_fallback_notice©Ú_UnboundedThreadExecutorg      ¬@ç      >@g     €f@g     €F@ç      @g      .@z'(?<![\w:/])/([A-Za-z0-9][A-Za-z0-9_-]*)Úgateway_hygieneaq  (auxiliary\s+.+\s+failed|compression\s+summary\s+failed|fallback\s+context\s+marker|configured\s+compression\s+model\s+.+\s+failed|no\s+auxiliary\s+llm\s+provider\s+configured|auto-lowered\s+compression\s+threshold|auto-lowered\s+(?:this\s+)?session'?s?\s+threshold|configured\s+auxiliary\s+compression\s+provider\s+.+\s+unavailable|skipping\s+concurrent\s+compression|Ú|uŽ  |resumed\s+after\s+\d+s\s+idle\s+[â€”-]\s+compacting|preflight\s+compression|pre[- ]api\s+compression|context\s+too\s+large\s+\(~[\d,]+\s+tokens\)\s+[â€”-]+\s+compressing|compressed\s+\d[\d,]*\s+(?:â†’|->)\s+\d[\d,]*\s+messages,\s+retrying|compressed\s+~[\d,]+\s+(?:â†’|->)\s+~[\d,]+\s+tokens,\s+retrying|context\s+reduced\s+to\s+[\d,]+\s+tokens\s+\(was\s+[\d,]+\),\s+retrying|session\s+compressed\s+\d+\s+times|rate\s+limited\.\s+waiting\s+\d|retrying\s+in\s+\d|max\s+retries\s+\(\d+\).*(?:trying\s+fallback|exhausted|invalid\s+responses)|stream\s+(?:drop|drop\s+mid\s+tool-call).+retry\s+\d|stale\s+connections\s+from\s+a\s+previous\s+provider\s+issue|Ú)g      N@c                ó6   € \        V RR4      p\        VRV4      # )zXThe raw SessionDB behind ``gateway._session_db`` (unwrapping the async facade), or None.Ú_session_dbNÚ_db)Úgetattr)ÚgatewayÚ
session_dbs   & Ú0/home/ubuntu/.hermes/hermes-agent/gateway/run.pyÚ_gateway_session_db_innerr<   t   s   € ä˜ -°Ó6€JÜ�:˜u jÓ1Ð1ó    c                ó<   € V ^8„  d   QhR\         R\        R\        /# )é   Úsession_keyÚbase_cooldown_secondsÚreturn©ÚstrÚfloat)Úformats   "r;   Ú__annotate__rG   z   s(   € ÷ #Rñ #R¼ð #RÔTYð #RÔ^cñ #Rr=   c                óº  € ^RrC V P                  V4      P                  p\        \        V 4      RR4      p\        V4      '       d(    \        ^\        V! V4      4      4      pVe   W4n
        M)Ve&   V;P                  ^,          un
        VP                  p\        \        V\        \        4      4      ^,
          ,          p\        W',          \        4      #   \         d!   p\        P	                  RT4        Rp?LÞRp?ii ; i  \         dJ   p\        P	                  RT4       Te&   T;P                  ^,          un
        TP                  p Rp?L¾Rp?ii ; i)uÓ  Bump the hygiene failure streak and return the escalated cooldown (x1/x3/x9 over base, clamped).

Hygiene's per-run ``AIAgent`` is fresh, so the streak lives in SQLite keyed by rotation-stable session_key.

It exists because the in-agent equivalent is unreachable from here:
``ContextCompressor.record_timeout_failure`` escalates on an absolute 60 -> 300 -> 900s ladder driven by
the in-memory ``_consecutive_timeout_failures`` counter, which ``bind_session_state`` zeroes. Session
hygiene constructs a FRESH ``AIAgent`` per run and re-binds state every time, so from the gateway that
streak is structurally always 0 and only the flat ``hygiene_failure_cooldown_seconds`` could ever be
recorded â€” a session whose summary model always times out retried on that same fixed interval forever
(#79624). The streak is mirrored to SQLite by rotation-stable ``session_key`` so it outlives both the
per-run agent and gateway restarts; ``PersistentState`` keeps the hot in-process view.
Nz(hygiene failure streak update failed: %sÚ increment_hygiene_failure_streakz)hygiene failure streak persist failed: %s)Ú_session_stateÚ
persistentÚ	ExceptionÚloggerÚdebugr8   r<   ÚcallableÚmaxÚintÚhygiene_failure_streakÚ$_HYGIENE_COOLDOWN_LADDER_MULTIPLIERSÚminÚlenÚ_HYGIENE_COOLDOWN_MAX_SECONDS)r9   r@   rA   ÚstreakÚstateÚexcÚ	incrementÚ
multipliers   &&&     r;   Ú_hygiene_cooldown_for_failurer\   z   s1  € ð �tˆEðFØ×&Ñ& {Ó3×>Ñ>ˆô Ô1°'Ó:Ð<^Ð`dÓe€IÜ�	×Òð	6Ü˜œC¡	¨+Ó 6Ó7Ó8ˆFØÒ Ø/5Ô,øð 
Ò	Ø×$Ò$¨Õ)Õ$Ø×-Ñ-ˆÜ5ÜˆF”CÔ<Ó=Ó>ÀÕBõD€JäÐ$Õ1Ô3PÓQÐQøô% ô FÜ�‰Ð?À×EÑEûðFûô ô 	6Ü�L‰LÐDÀcÔJØÒ Ø×,Ò,°Õ1Õ,Ø×5Ñ5�ÿøð		6ús/   …C Á%D ÃDÃ#C>Ã>DÄEÄ?EÅEc                ó(   € V ^8„  d   QhR\         RR/# ©r?   r@   rB   N©rD   )rF   s   "r;   rG   rG       s   € ÷ Tñ T¼ð TÀñ Tr=   c                ór  €  V P                  V4      pVe   ^ VP                  n        \        \        T 4      RR4      p\        T4      '       d    T! T4       R# R#   \         d!   p\        P                  RT4        Rp?LZRp?ii ; i  \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)z«Clear the hygiene failure streak after a compression that reduced context.

Peeks, never get-or-creates: a no-op 0 write must not create a never-evicted ``_sessions`` row.Nz'hygiene failure streak reset failed: %sÚreset_hygiene_failure_streakz2hygiene failure streak persistent reset failed: %s)	Ú_peek_session_staterK   rR   rL   rM   rN   r8   r<   rO   )r9   r@   rX   rY   Úresets   &&   r;   Ú_reset_hygiene_failure_streakrd       s«   € ðEØ×+Ñ+¨KÓ8ˆØÒØ67ˆE×ÑÔ3ô Ô-¨gÓ6Ð8VÐX\Ó]€EÜ�‡‚ð	TÙ�+Öñ øô ô EÜ�‰Ð>À×DÑDûðEûô ô 	TÜ�L‰LÐMÈs×SÒSûð	Tús/   ‚&A ÁB
 ÁBÁ'BÂBÂ
B6ÂB1Â1B6c                óx   € V ^8„  d   QhR\         R\         R\         R\        R\        R\        R\        R\         /# )	r?   ÚabortedÚrotatedÚin_placeÚ	msg_countÚ	new_countÚapprox_tokensÚ
new_tokensrB   )ÚboolrQ   )rF   s   "r;   rG   rG   ²   sV   € ÷ Vñ VÜðVÜ#ðVÜ/3ðVÜ@CðVÜPSðVäðVä$'ðVä,0ñVr=   c                óN   € V '       g   V'       g   V'       g   R# \        W4WV4      # )uK  True when a hygiene run actually recovered the session (extracted to be unit testable).

Requires no abort, a real rewrite (the no-op path reuses pre-compression counts) and material shrink per
:func:`compression_made_progress` (a bare ``<`` misses row-count wins and counts estimate noise).

* the compressor did not abort (no summary produced at all); * the transcript was actually rewritten â€”
either rotated into a new session or compacted in place. The degenerate "did not rotate or compact in
place" path (#21301) reuses the pre-compression counts, so relying on the numbers alone would read a
no-op as success; * the request materially shrank, per the canonical :func:`compression_made_progress`
(#39548) â€” a row-count drop counts even when the summary keeps the token estimate flat, and a sub-5%
token wobble does not count at all.
Fr'   )rf   rg   rh   ri   rj   rk   rl   s   $$$$$$$r;   Úhygiene_compaction_recoveredro   ²   s   € ÷ —w§(ÙÜ$ Y¸=ÓUÐUr=   c          
      óT   € V ^8„  d   QhR\         R\        R\        R\         R\        /# )r?   Útotal_exhaustedÚelapsedÚidle_timeoutÚprogress_observedrB   )rm   rE   rD   )rF   s   "r;   rG   rG   Æ   s;   € ÷ Dñ DÜðDÜ',ðDÜ<AðDÜVZðDÜ_bñDr=   c                óP   € \        R4      pV '       d   V# V\        R4      ,           # )zëDescribe the host timeout that actually ended hygiene compression. Chat users cannot edit
model config, so the copy names /compress, /new and `hermes doctor`, never a config key or the
raw second counts (those stay in the gateway log).z gateway.compress.hygiene_timeoutz,gateway.compress.hygiene_timeout_doctor_hintr   )rq   rr   rs   rt   Úleads   $$$$ r;   Ú$_hygiene_compression_timeout_messagerw   Æ   s(   € ô
 Ð/Ó0€DßØˆØ”!ÐBÓCÕCÐCr=   c                ó$   € V ^8„  d   QhR\         /# ©r?   r@   r_   )rF   s   "r;   rG   rG   Ñ   s   € ÷ Eñ E´Cñ Er=   c                óN  € \        V RR4      pVf   R# \        V RR4      p T;'       g    \        4       ;_uu_ 4        VP                  V4      pRRR4       \	        X\
        4      '       d   T'       d
   T^ ,          # T#   + '       g   i     L9; i  \         d    Rp LKi ; i)zhThe cached live AIAgent for ``session_key`` (or the pending sentinel / None), read under the cache lock.Ú_agent_cacheNÚ_agent_cache_lock)r8   ÚsuppressÚgetrL   Ú
isinstanceÚtuple)r9   r@   ÚcacheÚlockÚentrys   &&   r;   Ú_cached_agent_for_hygiener„   Ñ   s�   € ä�G˜^¨TÓ2€EØ‚}ÙÜ�7Ð/°Ó6€DðØ× Ð ”h“j× Ñ Ø—I‘I˜kÓ*ˆE÷ !ô " %¬×/Ò/·Eˆ5��8ÐD¸uÐD÷	 !× ûäô ØŠðús3   ¢B «B ¾BÁB ÂB	ÂB ÂB ÂB$Â#B$Úfailure_cooldown_secondsç     Àr@c                óx   € V ^8„  d   QhR\         R\         R\         R\        R\        R\        R\        R\         /# )	r?   r@   Ú
session_idÚ	auto_modeÚhistoryrk   Útimeout_secondsr…   rB   )rD   ÚlistrQ   rE   )rF   s   "r;   rG   rG   ß   sL   € ÷ > ñ > Üð> Ü+.ð> Ü>Að> ÜLPð> äð> ä).ð> äJOð> ä\_ñ> r=   c             ƒ  óŒ  aaaa"  € \        T;'       g    R4      P                  4       pVR9  d   RpVR8w  d   RV 2# \        W4      oSe   S\        J d   R# \	        SRR4      f   R# \	        SRR4      p	\	        V	R	^ 4      p
\
        P                  ! 4       P                  R\        4       P                  VVVV3R
 l4      p\	        V RR4      p\        V4      '       d
   V! VS4        \
        P                  ! \
        P                  ! V4      \        \        V4      R4      R7      G Rj  x€L
  \	        T	R	^ 4      pYê8”  d   \)        Y4       R# R#  L&  \         d1    T^ 8¼  d   \!        T STR4       \"        P%                  RST4        R# \&         d'   p\"        P%                  RST4       RT 2u Rp?# Rp?ii ; i5i)uÛ  Session hygiene for ``codex_app_server`` sessions.

The real context is the server-side thread; the local transcript is a never-replayed mirror, so rewriting
it shrinks nothing and evicting the live agent starts the next turn on an EMPTY thread. So: compact the LIVE
agent via ``thread/compact/start``, keep it cached, never build a detached compressor. ``native``/``off``
skip without local fallback. Returns ``compacted``, ``skipped:<reason>`` or ``failed:<reason>``.

See #73503.
* Evicting the cached live agent afterwards destroys the only real context: the next turn spawns an
EMPTY thread and the model starts blank while Hermes still mirrors a full history (abrupt amnesia â€” the
user-facing damage documented on #73503).
ÚnativeÚhermeszskipped:mode=Nzskipped:no-cached-agentÚ_codex_sessionzskipped:no-live-threadÚcontext_compressorÚcompression_countc                  óD   <€ S P                  SR SS;'       g    RRR7      # )Ú Údefaultr2   )rk   Útask_idÚtrigger)Ú_compress_context)Úagentrk   rŠ   rˆ   s   €€€€r;   Ú<lambda>Ú.run_codex_hygiene_compaction.<locals>.<lambda>  s-   ø€ �×'Ñ'¨°À=ÐZd×ZqÐZqÐhqð  |MÐ'ô  Nr=   Ú_track_deferred_agent_workerç      ð?©Útimeoutz,codex app-server thread compaction timed outzwSession hygiene: codex app-server thread compaction for session %s timed out after %.1fs; continuing without compactionzfailed:timeoutzMSession hygiene: codex app-server thread compaction for session %s failed: %szfailed:Ú	compactedzfailed:no-boundary>   Úoffr�   rŽ   )rD   Úlowerr„   Ú_AGENT_PENDING_SENTINELr8   ÚasyncioÚget_running_loopÚrun_in_executorr   ÚrunrO   Úwait_forÚshieldrP   rE   ÚTimeoutErrorÚ_record_hygiene_cooldownrM   ÚwarningrL   rd   )r9   r@   rˆ   r‰   rŠ   rk   r‹   r…   ÚmodeÚ
compressorÚcount_beforeÚworker_futureÚtrack_workerrY   Úcount_afterr™   s   &&f$dd$$       @r;   Úrun_codex_hygiene_compactionr³   ß   s²  ûé € ô ˆy×$Ð$˜HÓ%×+Ñ+Ó-€DØÐ.Ô.ØˆØˆxÔà˜t˜fÐ%Ð%ä% gÓ;€EØ‚}˜Ô!8Ó8á(ÜˆuÐ&¨Ó-Ò5Ù'ä˜Ð 4°dÓ;€JÜ˜:Ð':¸AÓ>€Lä×,Ò,Ó.×>Ñ>ØŒl‹n× Ñ ÷ 	NóO€Mô ˜7Ð$BÀDÓI€LÜ�×Òá�] EÔ*ðÜ×ÒœwŸ~š~¨mÓ<ÄcÌ%ÐP_ÓJ`ÐbeÓFfÔg×gÐgô  ˜*Ð&9¸1Ó=€KØÔ!ä% gÔ;Ùáñ- 	høÜô 	 à# qÔ(Ü$Ø˜Ð%=Ð?môoä�‰ðNà˜ô	)ò  Üô Ü�‰Ø[Ð]gÐilô	nà˜˜ˆÕûðüs[   †C%GÃ,AE Ä.EÄ/E Ä3"GÅE Å7GÆGÆGÆGÆF<Æ6GÆ7GÆ<GÇGÚfence_cancelledFc                ó`   € V ^8„  d   QhR\         R\         R\         R\         R\        R\        /# )r?   ÚidlerŸ   ÚwaitedÚceilingr´   rB   )rE   rm   )rF   s   "r;   rG   rG     sD   € ÷ 	Gñ 	GÜð	GÜ"ð	GÜ,1ð	GÜ<Að	GÜTXð	Gä	ñ	Gr=   c                ó@   € V'       * ;'       d    W8  ;'       d    W#8  # )zìWhether the hygiene host should keep waiting for a slow summary.

A cancelled commit fence cannot commit: extending only queues inbound messages behind a doomed attempt.

Stop extending immediately so the turn can continue. See #96953.
© )r¶   rŸ   r·   r¸   r´   s   $$$$$r;   Úhygiene_wait_should_extendr»     s"   € ð Ô×FÐF 4¡>×FÐF°fÑ6FÐFr=   c                óV   € V ^8„  d   QhR\         R\        R\        \         ,          RR/# )r?   rˆ   Úcooldown_secondsÚerrorrB   N)rD   rE   r   )rF   s   "r;   rG   rG   +  s6   € ÷ Iñ IÜðIÜ05ðIÜ>FÄs½mðIØW[ñIr=   c                óæ   € \        \        V 4      RR4      pVf   R#  V! V\        P                  ! 4       V,           V4       R#   \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)aÆ  Persist a session-hygiene compression-failure cooldown to the state DB (survives restarts).

``error`` must be forwarded: the recorder writes compression_failure_error UNCONDITIONALLY (NULL clobber).

Uses the same ``compression_failure_cooldown_until`` column and ``record_compression_failure_cooldown``
method that the in-conversation compression path (``agent/context_compressor.py``) already uses, so the
cooldown survives gateway restarts (#74136).
Ú#record_compression_failure_cooldownNz+session hygiene cooldown persist failed: %s)r8   r<   ÚtimerL   rM   rN   )r9   rˆ   r½   r¾   ÚrecorderrY   s   &&&&  r;   r«   r«   +  se   € ô Ô0°Ó9Ð;`ÐbfÓg€HØÒÙðIÙ�œTŸYšY›[Ð+;Õ;¸UÖCøÜô IÜ�‰ÐBÀC×HÒHûðIús   ž$A ÁA0ÁA+Á+A0c                ó0   € V ^8„  d   QhR\         R\         /# )r?   ÚtemplaterB   r_   )rF   s   "r;   rG   rG   >  s   € ÷ =ñ =¬ð =´ñ =r=   c                ó`   € \         P                  ! RV 4      pRP                  R V 4       4      # )z­Compile a compression status template constant into a regex source.

Literal text is escaped verbatim (wording drift can't diverge from the matcher); ``{field}`` -> numeric.z
\{[^{}]*\}z[\d,]+c              3   óN   "  € T F  p\         P                  ! V4      x € K  	  R # 5i©N)ÚreÚescape)Ú.0Úparts   & r;   Ú	<genexpr>Ú,_status_template_to_regex.<locals>.<genexpr>C  s   é € Ð<±e¨dœ"Ÿ)š) DŸ/˜/³eùs   ‚#%)rÈ   ÚsplitÚjoin)rÄ   Úpartss   & r;   Ú_status_template_to_regexrÑ   >  s)   € ô �HŠH�] HÓ-€EØ�>‰>Ñ<±eÓ<Ó<Ð<r=   c              #   ó8   "  € T F  p\        V4      x € K  	  R # 5irÇ   )rÑ   )rÊ   Ú	_templates   & r;   rÌ   rÌ   M  s$   é € ð @ñ?ˆIô 	" )×,Ð,ó?ùó   ‚c                ó$   € V ^8„  d   QhR\         /# ©r?   rB   ©rm   )rF   s   "r;   rG   rG   X  s   € ÷ ñ ´tñ r=   c                 ó4  €  \        4       p \        V \        4      '       d   V P                  R4      MRp\        V\        4      '       d;   \	        VP                  RR4      4      P                  4       P                  4       R9   #  R#   \         d     R# i ; i)a  True when ``compression.progress_notices`` is on (default False: chat is silent by design).

Read live (mtime-cached) so a config edit applies at the next status; fail-closed on read error.

Reads ``compression.progress_notices`` from the gateway's raw YAML config (#52995).
ÚcompressionNÚprogress_noticesF>   Ú1ÚonÚyesÚtrue)Ú_load_gateway_configr   Údictr~   rD   Ústripr¢   rL   )ÚconfigÚcompression_cfgs     r;   Ú-_gateway_compression_progress_notices_enabledrä   X  s’   € ðÜ%Ó'ˆÜ7AÀ&Ì$×7OÒ7O˜&Ÿ*™* ]Ô3ÐUYˆÜ�o¤t×,Ò,Ü�×*Ñ*Ð+=¸uÓEÓF×LÑLÓN×TÑTÓVð [*ñ *ð *ð -ñ
 øô ô ØÙðús   ‚BB ÂBÂBc                ó0   € V ^8„  d   QhR\         R\        /# ©r?   ÚplatformrB   ©r   rm   )rF   s   "r;   rG   rG   m  s   € ÷ Lñ L¬sð L´tñ Lr=   c                ó&   € \        V 4      \        9   # )zBTrue only for programmatic/local surfaces that must keep raw text.)Ú_gateway_platform_valueÚ_GATEWAY_RAW_TEXT_PLATFORMS©rç   s   &r;   Ú _gateway_surface_passes_raw_textrí   m  s   € ä" 8Ó,Ô0KÑKÐKr=   zÀ(cybersecurity\s+risk|security\s+policy|safety\s+policy|policy\s+violation|violat(?:e|es|ed|ion)|blocked\s+(?:because|by|under)|request\s+(?:was\s+)?(?:blocked|rejected)|disallowed|moderation)zd(provider\s+authentication\s+failed|incorrect\s+api\s+key|invalid\s+api\s+key|(?<![\d:,.])401(?!\d))z7(rate\s+limit|rate-limited|\b429\b|quota|usage\s+limit)Ú(c                ó   € V ^8„  d   QhRR/# ©r?   rB   Nrº   )rF   s   "r;   rG   rG   ¦  s   € ÷ .ñ .¨dñ .r=   c                 óV  € \         P                  R8w  d   R# \        \        4      P	                  4       P
                  P
                  p ^ RIHpHp V! V 4      e   R# \        P                  P                  R4      3 Uu. uF  q3'       g   K  \        V4      NK  	  upV R,          .,           p\        4       pV EFÑ  p VP	                  4       p\        V4      P                  4       pW…9   d   K6  VP!                  V4       VR,          R,          p	V	P#                  4       '       g   Ko  V! V4      ;p
\         P$                  R,          8w  d9   \&        P)                  R	Yz;'       g    R
\         P$                  R,          4       KË  \        V 4      p\        V	4      pV\         P*                  9  d!   \         P*                  P-                  ^ V4       \.        P0                  ! V4       V\         P*                  9   d    \         P*                  P3                  V4       \         P*                  '       d   \         P*                  ^ ,          V8X  d   ^M^ p\         P*                  P-                  WÜ4       \        V4      \        P                  R&    R# 	  R# u upi   \         d    Tp ELØi ; i)z¤Make detached Windows gateway runs see the Hermes venv packages.

Patched before MCP discovery so tool injection does not depend on launchers preserving PYTHONPATH.Úwin32N)Úcommitted_venvÚvenv_python_versionÚVIRTUAL_ENVÚvenvÚLibzsite-packages:Nr?   Nz/Skipping venv overlay %s: Python %s, gateway %sÚunknown)Úsysrç   r   Ú__file__ÚresolveÚparentÚpm.environmentsró   rô   ÚosÚenvironr~   ÚsetÚOSErrorrD   r¢   ÚaddÚexistsÚversion_inforM   rN   ÚpathÚinsertÚsiteÚ
addsitedirÚremove)Úproject_rootró   rô   ÚvÚ
candidatesÚseenÚvenv_dirÚresolved_venvÚvenv_keyÚsite_packagesÚfoundÚproject_entryÚ
site_entryÚ	insert_ats                 r;   Ú$_ensure_windows_gateway_venv_importsr  ¦  sû  € ô ‡|�|�wÔÙäœ“>×)Ñ)Ó+×2Ñ2×9Ñ9€LßCñ �lÓ#Ò/ÙÜ$&§J¡J§N¡N°=Ó$AÑ#CÓIÑ#C˜aÃq”'”$�q–'Ñ#CÑIÈ\Ð\bÕMbÐLcÕc€Jä“U€DÜˆð	%Ø$×,Ñ,Ó.ˆMô �}Ó%×+Ñ+Ó-ˆØÔÙØ�‰�Ôà%¨Õ-°Õ?ˆØ×#Ñ#×%Ò%Ùá(¨Ó7Ð7ˆE¼C×<LÑ<LÈRÕ<PÔPÜ�L‰LÐJÈM×[mÐ[mÐdmÔor×oÑoð  ACõ  pDô  EÙÜ˜LÓ)ˆÜ˜Ó'ˆ
Ø¤§¡Ô(Ü�H‰H�O‰O˜A˜}Ô-ä�Š˜
Ô#ØœŸ™Ô!Ü�H‰H�O‰O˜JÔ'ÜŸŸ˜¤c§h¡h¨q¥k°]Ô&B‘AÈˆ	Ü�‰�‰˜	Ô.ä$'¨Ó$6Œ�
‰
�=Ñ!Úó; ùò Jøô ô 	%Ø$‹Mð	%ús   Á?	JÂJÂ?JÊJ(Ê'J(c                ó0   € V ^8„  d   QhR\         R\        /# ræ   ©r   rD   )rF   s   "r;   rG   rG   ×  s   € ÷ Kñ K¤cð K¬cñ Kr=   c                óz   € \        \        V RV 4      ;'       g    R4      P                  4       P                  4       # )zDReturn a normalized gateway platform value for enums or raw strings.Úvaluer”   )rD   r8   rá   r¢   rì   s   &r;   rê   rê   ×  s0   € äŒw�x ¨(Ó3×9Ð9°rÓ:×@Ñ@ÓB×HÑHÓJÐJr=   rç   c          	      ó¬   € V ^8„  d   QhR\         \        \        \        3,          ,          R\        R\         \        \        \        3,          ,          /# )r?   Úmetadatarç   rB   ©r   rà   rD   r   )rF   s   "r;   rG   rG   Ü  sC   € ÷ ñ Ü”tœC¤˜H•~Õ&ðÜ<?ðÜKSÔTXÔY\Ô^aÐYaÕTbÕKcñr=   c               ó^   € \        V4      R8w  d   V # \        T ;'       g    / 4      pRVR&   V# )zEMark Discord lifecycle/status sends without changing other platforms.ÚdiscordTÚnon_conversational)rê   rà   )r  rç   Úmergeds   &$ r;   Ú_non_conversational_metadatar"  Ü  s6   € ô ˜xÓ(¨IÔ5ØˆÜ�(—.�.˜bÓ!€FØ#'€FÐÑ Ø€Mr=   c                óŠ   € V ^8„  d   QhR\         \        \        \        3,          ,          R\        \        \        3,          /# )r?   r  rB   r  )rF   s   "r;   rG   rG   æ  s/   € ÷ ñ ¤¬¬c´3¨h­Õ 8ð ÄDÌÌcÈÅNñ r=   c                ó:   € \        T ;'       g    / 4      pRVR&   V# )a  Mark a mid-turn status/advisory send as NOT the turn-final.

Stream-is-the-message adapters seal the live stream with the first unmarked send to an armed (chat, turn)
key, so every mid-turn send MUST carry this marker. Gateway-internal; adapters strip it before the wire.TÚ_interim_send©rà   )r  r!  s   & r;   Ú_interim_metadatar'  æ  s#   € ô
 �(—.�.˜bÓ!€FØ"€Fˆ?ÑØ€Mr=   c                ót   € V ^8„  d   QhR\         R\        \        \        \         3,          ,          R\        /# )r?   r™   Úsession_rowrB   )r   r   rà   rD   rm   )rF   s   "r;   rG   rG   ð  s/   € ÷ ñ ¤sð ¼Ä$ÄsÌCÀxÅ.Õ9Qð ÔVZñ r=   c                óà   € Rp\        V\        4      '       d@   VP                  R4      p\        V\        4      '       d   VP	                  4       '       d   TpW n        RV n        \        V4      # )a  Keep gateway hygiene from rebuilding a live session's system prompt.

Hygiene lacks the live prompt environment, so a rebuild (persisted by compression) would strip external
provider blocks. Seed the persisted prompt (or an empty cache entry); the real turn rebuilds properly.r”   Úsystem_promptT)r   rà   r~   rD   rá   Ú_cached_system_promptÚ_retain_seeded_system_promptrm   )r™   r)  Ústored_promptÚ
raw_prompts   &&  r;   Ú_seed_hygiene_system_promptr0  ð  s]   € ð
 €MÜ�+œt×$Ò$Ø —_‘_ _Ó5ˆ
Ü�j¤#×&Ò&¨:×+;Ñ+;×+=Ò+=Ø&ˆMà"/Ôà)-€EÔ&Ü�ÓÐr=   c                ó0   € V ^8„  d   QhR\         R\        /# )r?   rY   rB   )ÚBaseExceptionrm   )rF   s   "r;   rG   rG     s   € ÷ ñ ¤]ð ´tñ r=   c                ó  € \        4       pT p^ pVex   V^8  dq   \        V4      pWA9   d    R# VP                  V4       V^,          p\        V4      P                  \
        9   d   R# VP                  ;'       g    VP                  pK{  R# )u  True for transient network errors safe to log + swallow (the next poll recovers; never crash).

Walks the cause chain so wrapped errors (PTB ``NetworkError`` over ``httpx.ConnectError``) match.

The crash class targeted by #31066 / #31110: an unhandled Telegram ``TimedOut`` (or peer
``NetworkError`` / ``httpx`` connection error) propagating to the event loop and killing the entire
gateway process. These are by definition transient â€” the next poll cycle or user action recovers â€” so
they must never crash the process.
TF)r   Úidr  ÚtypeÚ__name__Ú$_TRANSIENT_NETWORK_ERROR_CLASS_NAMESÚ	__cause__Ú__context__)rY   r  ÚcurÚdepthÚidents   &    r;   Ú_is_transient_network_errorr=    sz   € ô “U€DØ#&€CØ€EØ
Š/˜e bœjÜ�3“ˆØŒ=Øñ ð 	�‰�ŒØ��
ˆÜ�‹9×ÑÔ!EÔEÙØ�m‰m×.Ð.˜sŸ™ŠÙr=   c                ój   € V ^8„  d   QhR\         P                  R\        \        \        3,          RR/# )r?   ÚloopÚcontextrB   N)r¤   ÚAbstractEventLooprà   rD   r   )rF   s   "r;   rG   rG      s2   € ÷ ,ñ ,Ü
×
#Ñ
#ð,Ü.2´3¼°8­nð,ØAEñ,r=   c           	     ó  € VP                  R4      pVe¾   \        V4      '       d­   VP                  R4      ;'       g    VP                  R4      pRpVe/    \        VR4      '       d   VP                  4       M
\	        V4      p\        P                  RT;'       g    R\        V4      P                  V\        V4      W"P                  3R	7       R# V P                  V4       R#   \
         d    \	        T4      p Lyi ; i)
aX  Loop-level safety net for transient network errors (installed once by ``start_gateway``).

Logs WARNING with traceback; non-transient errors go to the default handler so real bugs surface.

Catches the ``telegram.error.TimedOut`` crash class (issues #31066 / #31110) and any peer transient
network error before it can kill the gateway process.
Ú	exceptionNÚfutureÚtaskr”   Úget_namez9Gateway swallowed transient network error from %s: %s: %sz<unknown task>©Úexc_info)r~   r=  ÚhasattrrF  ÚreprrL   rM   r¬   r5  r6  Ú__traceback__Údefault_exception_handler)r?  r@  rY   rE  Ú	task_names   &&   r;   Ú_gateway_loop_exception_handlerrN     sÞ   € ð �+‰+�kÓ
"€CØ
‚Ô6°s×;Ò;Ø�{‰{˜8Ó$×;Ð;¨¯©°FÓ(;ˆØˆ	ØÒð'Ü/6°t¸Z×/HÒ/H˜DŸM™MœOÌdÐSWËj�	ô 	�‰ØGÈ×IfÐIfÐVfÜ�‹I×Ñ ¬t°C«y¸#×?PÑ?PÐ.Qð 	ô 	Sñ 	Ø×"Ñ" 7Ö+øô ô 'Ü  ›J’	ð'ús   Á-C& Ã&C?Ã>C?c                ó0   € V ^8„  d   QhR\         R\         /# ©r?   ÚtextrB   r_   )rF   s   "r;   rG   rG   9  s   € ÷ #ñ #¬cð #´cñ #r=   c                ó   € ^ RI Hp V! V 4      # )z¾Secret redaction before text can leave the gateway for a chat platform: the shared egress scrub
(``force=True`` holds even when ``security.redact_secrets`` is off; fails closed). See #23810.)Úredact_for_egress)Úagent.redactrS  )rQ  rS  s   & r;   Ú#_redact_gateway_user_facing_secretsrU  9  s   € õ /á˜TÓ"Ð"r=   c                ó>   € V ^8„  d   QhR\         R,          R\         /# )r?   ÚcmdNrB   r_   )rF   s   "r;   rG   rG   A  s   € ÷ 
=ñ 
=¤#¨¥*ð 
=´ñ 
=r=   c                óH   € ^ RI Hp T! \        T ;'       g    R4      RR7      # )aã  Redact credentials from a command before it goes into an approval prompt.

The gateway approval prompt is built from the raw command string, so a credential-shaped value would
otherwise be echoed verbatim to the chat platform (#48456). Uses ``redact_sensitive_text(force=True)`` so
the prompt honors redaction even when ``security.redact_secrets`` is off. Module-level so the wiring is
unit-testable (the call site is a deeply nested gateway closure that cannot be driven directly).
)Úredact_sensitive_textr”   T©Úforce)rT  rY  rD   )rW  rY  s   & r;   Ú_redact_approval_commandr\  A  s   € õ 3á ¤ S§Y Y¨B£°tÔ<Ð<r=   Úallow_permanentTÚallow_sessionÚsmart_deniedc                ól   € V ^8„  d   QhR\         R\         R\         R\        R\        R\        R\         /# )r?   ÚcommandÚdescriptionÚcommand_prefixr]  r^  r_  rB   ©rD   rm   )rF   s   "r;   rG   rG   N  sM   € ÷ Eñ EÜðEÜ"ðEÜ47ðEÜMQðEäðEä.2ðEä?BñEr=   c               óP  € ^ RI HpHpHpHp	 \        V 4      ^È8”  d   V R,          R,           MT p
V'       d   \        R4      M
RV! 4        R2p\        RVR7      .pV'       gI   V'       dA   VP                  \        R	VR7      4       V'       d   VP                  \        R
VR7      4       VP                  \        RVR7      4       \        RWºV! 4       VR7      \        R4      P                  VRR 4      ,           \        RVR,          R7      ,           V	! V! 4       4      ,           # )zÚRender the text fallback from approval capabilities, not platform names. Same words as
the button card (``BasePlatformAdapter._format_exec_approval``), plus the typed ``/approve``
steps a surface without buttons needs.)Úapproval_timeout_secondsÚea_header_textÚea_reason_label_textÚformat_approval_deadline_lineºNéÈ   Nz...z(gateway.exec_approval.smart_deny_headingu	   âš ï¸� **z**z&gateway.exec_approval.text_choice_once)Úprefixz)gateway.exec_approval.text_choice_sessionz(gateway.exec_approval.text_choice_alwaysz&gateway.exec_approval.text_choice_denyzgateway.exec_approval.text_body)Úheadingra  Úreason_labelÚreasonz(gateway.exec_approval.text_choice_joinerNz&gateway.exec_approval.text_choice_last)Úchoiceéÿÿÿÿ)	Ú$gateway.platforms.base_exec_approvalrf  rg  rh  ri  rU   r   ÚappendrÏ   )ra  rb  rc  r]  r^  r_  rf  rg  rh  ri  Úcmd_previewrm  Úchoicess   &&&$$$       r;   Ú_format_exec_approval_fallbackrv  N  s  € ÷gó gä+.¨w«<¸#Ô+=�'˜$•- %Ö'À7€Kß@LŒqÐ;Ô<Ø¡Ó 0Ð1°Ð4ð ô Ð9À.ÔQÐR€GßŸMØ�‰”qÐDÈ^Ô\Ô]ßØ�N‰Nœ1ÐGÐP^Ô_Ô`Ø‡N�N”1Ð=ÀnÔUÔVä	Ð
+°WÙ+Ó-°kô	Cä
Ð6Ó
7×
<Ñ
<¸WÀSÀb¸\Ó
Jõ	Kô Ð4¸WÀR½[Ô
Iõ	Jñ (Ñ(@Ó(BÓ
Cõ		DðEr=   úgateway.errors.rate_limitedzgateway.errors.auth_failedzgateway.errors.bad_requestz%gateway.errors.connection_interruptedzgateway.errors.unreachablez!gateway.errors.connection_unknownc                ó$   € V ^8„  d   QhR\         /# rÖ   r_   )rF   s   "r;   rG   rG   }  s   € ÷ 0ñ 0¤ñ 0r=   c                 ó   € \        R4      # )u®   Shared by the failed-turn normalizer and ``run_turn._hmwa_agent_error_reply``; canonical
commands (/compress, /new) â€” the /compact and /reset aliases are absent from /help.zgateway.errors.context_overflowr   rº   r=   r;   Ú_context_overflow_replyrz  }  s   € ô Ð.Ó/Ð/r=   c                ó0   € V ^8„  d   QhR\         R\         /# rP  r_   )rF   s   "r;   rG   rG   ƒ  s   € ÷ Wñ WœCð W¤Cñ Wr=   c                ó€   € ^ RI HpHp V! V 4      ;'       g    ^ pV^x8  d   \        R4      # \        RV! V4      R7      # )a  Name the reset window a quota 429 carries (``resets_in_seconds`` body field, the credential
pool's ``retry after Ns``, ``resets in 4hr``) so a weekly cap is not sold as "wait a moment"
(#89401). One grammar table with the retry loop: ``agent.retry_utils.RETRY_DELAY_PATTERNS``.)Úformat_reset_windowÚreset_delay_from_messagerw  z!gateway.errors.usage_limit_resets)Úwindow)Úagent.retry_utilsr}  r~  r   )rQ  r}  r~  Úsecondss   &   r;   Ú_rate_limit_replyr‚  ƒ  sA   € ÷ PÙ& tÓ,×1Ð1°€GØ�„}ÜÐ.Ó/Ð/ÜÐ0Ñ9LÈWÓ9UÔVÐVr=   c                ó0   € V ^8„  d   QhR\         R\         /# rP  r_   )rF   s   "r;   rG   rG   Ž  s   € ÷ 5ñ 5¬ð 5´ñ 5r=   c                ó¬   € \          F@  w  rVP                  V 4      '       g   K  V\        J d   \        V 4      u # \	        V4      u # 	  \	        R4      # )z@Map raw provider/API errors to a short user-safe Telegram reply.z$gateway.errors.provider_kept_failing)Ú_PROVIDER_ERROR_REPLIESÚsearchÚ_GATEWAY_RATE_LIMIT_REr‚  r   )rQ  ÚpatternÚ	reply_keys   &  r;   Ú_gateway_provider_error_replyrŠ  Ž  sL   € ç5ÑˆØ�>‰>˜$×ÔØ.5Ô9OÓ.OÔ$ TÓ*ÒaÔUVÐW`ÓUaÒañ 6ô Ð3Ó4Ð4r=   z^\s*(\W*\s*)?(:Né   Nc                ó0   € V ^8„  d   QhR\         R\        /# rP  rd  )rF   s   "r;   rG   rG   ¢  s   € ÷ 	?ñ 	?¬Sð 	?´Tñ 	?r=   c                óÔ   € V '       g   R# \        V 4      P                  4       p\        V4      R8”  g   VP                  R4      ^8”  d   R# \	        \
        P                  V4      4      # )z¬True when text is a provider failure envelope, not normal content.

Must be short (envelopes are 1-3 lines) AND start with the marker, so prose citing a status code misses.Fi�  Ú
)rD   rá   rU   Úcountrm   Ú _GATEWAY_PROVIDER_ERROR_SHAPE_REr†  )rQ  Úbodys   & r;   Ú"_looks_like_gateway_provider_errorr’  ¢  sO   € ÷ ÙÜˆt‹9�?‰?Ó€DÜ
ˆ4ƒy�3„˜$Ÿ*™* TÓ*¨QÔ.ÙÜÔ0×7Ñ7¸Ó=Ó>Ð>r=   c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r?   rç   rQ  rB   r  )rF   s   "r;   rG   rG   ®  s!   € ÷ "ñ "¬sð "¼#ð "Ä#ñ "r=   c                ó|  € V'       d   \        V 4      '       d   V# ^ RIHp V! \        V4      4      p\	        V4      pV^ 8¼  d   VRV P                  4       p\        V4      P                  4       P                  \        4      '       d   R# \        \        V4      4      p\        V4      '       d   \        V4      # V# )z³Sanitize final gateway replies for chat surfaces: concise, secret-redacted provider failure
categories instead of raw HTTP bodies, request IDs, leaked credentials, or policy text.)Ú_sanitize_surrogatesNr”   )rí   Úagent.message_sanitizationr•  rD   Ú_terminal_sentinel_startÚrstriprá   Ú
startswithr    rU  r’  rŠ  )rç   rQ  r•  Ú
_eos_startÚredacteds   &&   r;   Ú _sanitize_gateway_final_responserœ  ®  sž   € ÷ Ô3°H×=Ò=Øˆõ @á¤ D£	Ó*€Dô *¨$Ó/€JØ�Q„Ø�K�ZÐ ×'Ñ'Ó)ˆô ˆ4ƒy‡�Ó×#Ñ#Ô$F×GÒGÙä2´3°t³9Ó=€HÜ)¨(×3Ò3Ü,¨XÓ6Ð6Ø€Or=   c          	      ó^   € V ^8„  d   QhR\         R\        R\        R\        \        ,          /# )r?   rç   Ú
event_typeÚmessagerB   )r   rD   r   )rF   s   "r;   rG   rG   Ó  s/   € ÷ ñ ¬cð ¼sð ÌSð ÔU]Ô^aÕUbñ r=   c                ód  € \        T;'       g    R4      P                  4       pV'       g   R# \        V 4      '       d   V# \        V4      p\        P                  V4      '       d.   \        4       '       d   \        P                  V4      '       g   R# \        V4      '       d   \        V4      # V# )z¤Filter/sanitize agent status callbacks before platform delivery.

Local/CLI keep the raw diagnostic stream; messaging surfaces drop transient aux/compression noise.r”   N)
rD   rá   rí   rU  Ú_TELEGRAM_NOISY_STATUS_REr†  rä   Ú_COMPRESSION_PROGRESS_STATUS_REr’  rŠ  )rç   rž  rŸ  rQ  s   &&& r;   Ú_prepare_gateway_status_messager£  Ó  s‡   € ô ˆw�}ˆ}˜"Ó×#Ñ#Ó%€DßÙÜ'¨×1Ò1Øˆä.¨tÓ4€Dä ×'Ñ'¨×-Ò-Ü5×7Ò7Ô<[×<bÑ<bÐcg×<hÒ<háÜ)¨$×/Ò/Ü,¨TÓ2Ð2Ø€Kr=   c                ó$   € V ^8„  d   QhR\         /# rÖ   r_   )rF   s   "r;   rG   rG   è  s   € ÷ :ñ :¤#ñ :r=   c                ó^   € \        \        V RR4      ;'       g    R4      P                  4       # )zÃRender an AgentNotice to a single plaintext line (messaging has no status bar: one-shot push).

The level glyph is already baked into the text (prepending would DOUBLE it); malformed/empty -> "".rQ  r”   )rD   r8   rá   )Únotices   &r;   Úrender_notice_liner§  è  s)   € ô Œw�v˜v rÓ*×0Ð0¨bÓ1×7Ñ7Ó9Ð9r=   c              ƒ  ó¨   "  € \        V RR4      p\        V4      '       d   V! WW4R7      G Rj  x€L
 # V P                  WVR7      G Rj  x€L
 #  L L5i)z¾Route a status through adapter.send_or_update_status when supported (edits the previous
bubble for the same status_key instead of appending); otherwise fall back to plain send.

See #30045.
Úsend_or_update_statusN)r  )r8   rO   Úsend)ÚadapterÚchat_idÚ
status_keyÚcontentr  Úsenders   &&&&& r;   Ú_send_or_update_status_coror°  ï  sP   é € ô �WÐ5°tÓ<€FÜ�×ÒÙ˜G°ÔL×LÐLØ—‘˜g¸�ÓB×BÐBñ MÙBùs!   ‚,A®A¯AÁ	AÁ
AÁAc                ó0   € V ^8„  d   QhR\         R\        /# )r?   rŸ   rB   ©rE   rD   )rF   s   "r;   rG   rG   û  s   € ÷ 3ñ 3¬Eð 3´cñ 3r=   c                ó²  € V f   \         P                  R4       R#  V P                  VR7      p\        TRR4      '       d   R	# ^ R
IH	p \        TRR4      p\        T\        4      '       d?   TP                  R4      '       d(   \         P                  RTP                  R4      4       R# T! T4      '       d$   \         P                  R\        TRR4      4       R# \         P                  R\        TRR4      ;'       g    R4       R#   \        P                  P
                   d     R# \         d"   p\         P                  RT4        Rp?R# Rp?ii ; i)a  Classify an approval prompt send as ``sent`` / ``failed`` / ``ambiguous``.

``ambiguous`` = future timed out but the card may have posted: keep the registration, do NOT re-send.
Only a DEFINITIVE failure (error result / non-timeout exception / no future) re-asks; logged here.Nz;Prompt send failed: no scheduling future (loop unavailable)Úfailedrž   Ú	ambiguouszPrompt send failed: %sÚsuccessFÚsent)Údeclined_sendÚraw_responsez$Prompt send AMBIGUOUS (lost ack): %sr¾   z2Prompt send DECLINED by connector egress guard: %sÚdeclinedzunknown error)rM   r¬   ÚresultÚ
concurrentÚfuturesrª   rL   r8   Úgateway.relay.egressr¸  r   rà   r~   )rD  rŸ   r»  rY   r¸  Ú_raws   &&    r;   Ú_approval_send_outcomerÀ  û  s  € ð
 ‚~Ü�‰ÐTÔUÙðØ—‘ w�Ó/ˆô ˆv�y %×(Ò(Ùõ 3ä�6˜>¨4Ó0€DÜ�$œ×Ò $§(¡(¨;×"7Ò"7ô 	�‰Ð=¸t¿x¹xÈÓ?PÔQÙÙ�V×Òô 	�‰Ø@Ü�F˜G TÓ*ô	
ñ Ü
‡N�NÐ+¬W°V¸WÀdÓ-K×-^Ð-^ÈÔ_ÙøôS ×Ñ×*Ñ*ô ÚÜô Ü�‰Ð/°Ô5Ýûðús#   �D	 Ä	EÄ+EÄ4EÄ5EÅEÚreply_in_threadc                ój   € V ^8„  d   QhR\         R\         R\         R\        R\        \        ,          /# )r?   rç   Úsource_thread_idÚevent_message_idrÁ  rB   )r   rm   r   rD   )rF   s   "r;   rG   rG   1  s8   € ÷ ñ ÜðÜ%(ðÜ<?ðÜUYðäŒc…]ñr=   c               óL  € \        \        V RV 4      ;'       g    R4      P                  4       pV'       gA   V'       d$   V'       d   \        V4      \        V4      8X  d   R# V'       d   \        V4      # R# V'       d   \        V4      # VR9   d   V'       d   \        V4      # R# )a$  Return thread/root ID that progress/status bubbles should target.

``reply_in_thread=False`` (Slack): no synthetic-thread fallback, else the final flat reply inherits a thread.
A source.thread_id equal to the event's message id is the adapter's synthetic session key: no thread.

See #18859.
r  r”   N>   ÚbuzzÚslackÚ
mattermost)rD   r8   r¢   )rç   rÃ  rÄ  rÁ  Úplatform_keys   &&&$ r;   Ú_resolve_progress_thread_idrÊ  1  s„   € ô ”w˜x¨°(Ó;×AÐA¸rÓB×HÑHÓJ€Lßß× 0´SÐ9IÓ5JÌcÐRbÓNcÔ5cÙß(8ŒsÐ#Ó$ÐB¸dÐBßÜÐ#Ó$Ð$ØÐ6Ô6×;KÜÐ#Ó$Ð$Ùr=   c                óH   € V ^8„  d   QhR\         R\        R\        R\        /# )r?   Úuser_configrÉ  ÚsettingrB   )rà   rD   rm   )rF   s   "r;   rG   rG   G  s0   € ÷ 	Fñ 	F´ð 	FÄCð 	FÔRUð 	FÔZ^ñ 	Fr=   c                ó0  € \        V \        4      '       d   V P                  R4      MRp\        V\        4      '       g   R# VP                  R4      p\        V\        4      '       g   R# VP                  V4      p\        V\        4      ;'       d    W%9   # )zFReturn True when display.platforms.<platform> explicitly sets setting.ÚdisplayNFÚ	platforms©r   rà   r~   )rÌ  rÉ  rÍ  rÏ  rÐ  Úplatform_cfgs   &&&   r;   Ú_has_platform_display_overriderÓ  G  sr   € ä,6°{ÄD×,IÒ,Iˆk�o‰o˜iÔ(Èt€GÜ�gœt×$Ò$ÙØ—‘˜KÓ(€IÜ�i¤×&Ò&ÙØ—=‘= Ó.€LÜ�l¤DÓ)×EÐE¨gÑ.EÐEr=   r•   Úrequire_platform_override_forc                ó�   € V ^8„  d   QhR\         R\        R\        R\        R\        R\        \        ,          R,          R\        /# )	r?   rÌ  rÉ  rÍ  r•   rç   rÔ  NrB   )rà   rD   rm   r   r   )rF   s   "r;   rG   rG   S  sL   € ÷ ñ ÜðÜ%(ðÜ36ðÜDHðäðä9<¼S½ÀD½ðäTXñr=   c               ó²  € \        T;'       g    T4      pT;'       g    \        4        Uu0 uF  p\        V4      kK  	  ppWh9   d   \        WV4      '       g   R# ^ RIHp	 V	! WW#4      p
\        V
\        4      '       d   V
# \        V
\        4      '       d"   V
P                  4       P                  4       R9   # V
f   \        V4      # \        V
4      # u upi )z²Resolve a boolean display setting with optional platform-only opt-in.

Scratch-text is too noisy for threaded surfaces (Mattermost): they need an explicit per-platform override.
F)Úresolve_display_setting>   rÛ   rÜ   rÝ   rÞ   )
rê   r   rÓ  Úgateway.display_configr×  r   rm   rD   rá   r¢   )rÌ  rÉ  rÍ  r•   rç   rÔ  Úcurrent_platformÚcÚplatform_onlyr×  r  s   &&&$$$     r;   Ú_resolve_gateway_display_boolrÜ  S  sÀ   € ô /¨x×/GÐ/G¸<ÓHÐØ:W×:`Ð:`Ô[^Ó[`Ð:`ÓbÑ:`°AÔ,¨QÖ/Ñ:`€MÐbàÔ)Ü.¨{È'×RÒRÙå>á# K¸wÓP€EÜ�%œ×ÒØˆÜ�%œ×ÒØ�{‰{‹}×"Ñ"Ó$Ð(BÑBÐBØ‚}Ü�G‹}ÐÜ�‹;Ðùò cs   ¬Cc                ó<   € V ^8„  d   QhR\         R\        R\         /# )r?   rQ  rç   rB   )rD   r   )rF   s   "r;   rG   rG   m  s!   € ÷ <ñ <¬ð <´sð <¼sñ <r=   c                óx   a€ \        VRV4      pVR8w  d   V # ^ RIHo R V3R llp\        P	                  W04      # )zfRewrite slash-command mentions to Telegram-valid names (lowercase/digits/underscore); no-op elsewhere.r  Útelegram)Ú_sanitize_telegram_namec                óZ   € V ^8„  d   QhR\         P                  \        ,          R\        /# )r?   ÚmatchrB   )rÈ   ÚMatchrD   )rF   s   "r;   rG   Ú3_telegramize_command_mentions.<locals>.__annotate__u  s&   € ÷ @ñ @œŸ™¤�ð @¬#ñ @r=   c                 ón   <€ S! V P                  ^4      4      pV'       d   RV 2# V P                  ^ 4      # )é   Ú/)Úgroup)râ  Ú	sanitizedrà  s   & €r;   Ú_replaceÚ/_telegramize_command_mentions.<locals>._replaceu  s0   ø€ Ù+¨E¯K©K¸«NÓ;ˆ	ß"+��9�+ˆÐ?°·±¸Q³Ð?r=   )r8   Úhermes_cli.commands_platformsrà  Ú_TELEGRAM_COMMAND_MENTION_REÚsub)rQ  rç   Úplatform_valuerê  rà  s   &&  @r;   Ú_telegramize_command_mentionsrð  m  s@   ø€ ä˜X w°Ó9€NØ˜Ô#ØˆåE÷@ð @ô (×+Ñ+¨HÓ;Ð;r=   g      4@c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r?   r  rB   )r   r   rE   )rF   s   "r;   rG   rG   ˆ  s   € ÷ ñ ¤Sð ¬X´e­_ñ r=   c                óL  € V f   R# \        V \        4      '       d   V P                  4       # \        V \        4      '       d   R# \        V \        \
        34      '       d.   \        V 4      R8”  d   \        V 4      R,          # \        V 4      # \        V \        4      '       d9   V P                  4       pV'       g   R#  \        V4      pVR8”  d
   VR,          # T# R#   \         d     Mi ; i \        P                  ! T4      P                  4       #   \         d     R# i ; i)z¨Best-effort conversion of stored gateway timestamps to epoch seconds.

Missing/unparseable -> None, so legacy transcripts keep auto-continuing instead of being dropped.Nl    d(	 g     @�@)
r   r   Ú	timestamprm   rQ   rE   rD   rá   Ú
ValueErrorÚfromisoformat)r  rQ  Únumerics   &  r;   Ú_coerce_gateway_timestampr÷  ˆ  sø   € ð ‚}ÙÜ�%œ×"Ò"Ø�‰Ó Ð Ü�%œ×ÒÙÜ�%œ#œu˜×&Ò&ä(-¨e«°~Ô(EŒu�U‹|˜fÕ$ÐWÌ5ÐQVË<ÐWÜ�%œ×ÒØ�{‰{‹}ˆßÙð	Ü˜D“kˆGØ'.°Ô'?�7˜VÕ#ÐLÀWÐLñ øô ô 	Ùð	úð	Ü×)Ò)¨$Ó/×9Ñ9Ó;Ð;øÜô 	Úð	ús*   Â?C ÃC ÃC,Ã+C,Ã0#D ÄD#Ä"D#c                ó$   € V ^8„  d   QhR\         /# rÖ   ©rE   )rF   s   "r;   rG   rG   ¥  s   € ÷ ,ñ ,¬ñ ,r=   c                 ó   € ^ RI Hp  V ! 4       # )z­Auto-continue freshness window in seconds (non-positive disables the gate).

Thin wrapper over ``gateway.session`` kept so ``gateway.run`` imports/test patches keep working.©Úauto_continue_freshness_window)Úgateway.session_lifecyclerü  rû  s    r;   Ú_auto_continue_freshness_windowrþ  ¥  s   € õ IÙ)Ó+Ð+r=   c                ó$   € V ^8„  d   QhR\         /# rÖ   rù  )rF   s   "r;   rG   rG   ­  s   € ÷ kñ k¬Uñ kr=   c                 ó"   € \        R\        4      # )zÎMax seconds ``_finish_startup_restore`` holds the inbound gate for boot auto-resume; <=0 disables.

Duplicate-agent safety does NOT depend on it: ``_schedule_resume_pending_sessions`` claims SYNCHRONOUSLY.
Ú$HERMES_STARTUP_RESTORE_DRAIN_TIMEOUT)Ú
_float_envÚ+_STARTUP_RESTORE_DRAIN_TIMEOUT_SECS_DEFAULTrº   r=   r;   Ú#_startup_restore_drain_timeout_secsr  ­  s   € ô
 Ð<Ô>iÓjÐjr=   c                ó$   € V ^8„  d   QhR\         /# rÖ   rù  )rF   s   "r;   rG   rG   µ  s   € ÷ ]ñ ]¤eñ ]r=   c                 ó"   € \        R\        4      # )z¼Max seconds the boot warm-up (``_warm_turn_prerequisites``) may hold the inbound gate shut.

On timeout the gate opens and the warm-up finishes in the background. Non-positive disables it.ÚHERMES_STARTUP_WARMUP_TIMEOUT)r  Ú$_STARTUP_WARMUP_TIMEOUT_SECS_DEFAULTrº   r=   r;   Ú_startup_warmup_timeout_secsr	  µ  s   € ô Ð5Ô7[Ó\Ð\r=   c                ó$   € V ^8„  d   QhR\         /# rÖ   ©rQ   )rF   s   "r;   rG   rG   ¼  s   € ÷ &ñ &¤3ñ &r=   c                 ój  € ^ RI p ^ RIpRp ^ RIHp ^ RIHp \        V! V! 4       R4      4      pTP                  VRR7      p^ RIHp V! 4       P                  R	4      p\        V\        4      '       d   VP                  R
R4      '       d   ^ RIHp V! 4         \!        4       p\        P#                  RVP$                  VP&                  VP(                  4       \+        V4      #   \         d    \        P                  RRR7        LÚi ; i  \         d    \        P                  RRR7        LWi ; i)uá  Synchronously initialize first-turn prerequisites (executor thread); returns the schema count.

Covers the lazy init seen in skeleton turns: ``run_agent`` import graph, tool schemas (+ ``check_fn``
TTL cache), the local Python toolchain probe (#106064), and the default route's context-window
metadata (#105986) â€” a catalog HTTP probe that must not sit between the first inbound turn and its
inference request. Context files remain lazy because they need the active turn's agent.N©Úload_config_readonly)Ú_get_platform_toolsÚclizAplatform toolset resolution failed; warming the full tool surfaceTrG  )Úenabled_toolsetsÚ
quiet_moder™   Úenvironment_probe)Úget_environment_probe_linez*Model context warmed: %s -> %d tokens (%s)z(model-context warm-up failed (non-fatal))Ú	run_agentÚmodel_toolsÚhermes_cli.configr  Úhermes_cli.tools_configr  ÚsortedrL   rM   rN   Úget_tool_definitionsr~   r   rà   Útools.env_prober  Ú_resolve_gateway_model_contextÚinfoÚmodelÚcontext_lengthÚcontext_sourcerU   )	r  r  r  r  r  Ú	tool_defsÚ	agent_cfgr  Úctxs	            r;   Ú_warm_turn_machinery_syncr$  ¼  s  € ó Ûð
 ÐðiÝ:Ý?ä!Ñ"5Ñ6JÓ6LÈeÓ"TÓUÐð ×0Ñ0ÐBRÐ_cÐ0Ód€IÝ6á$Ó&×*Ñ*¨7Ó3€IÜ�i¤×&Ò&¨)¯-©-Ð8KÈT×*RÒ*Rõ 	?á"Ô$ðPô -Ó.ˆÜ�‰Ð@À#Ç)Á)ÈS×M_ÑM_Ðad×asÑasÔtô ˆy‹>Ðøô' ô iÜ�‰ÐXÐcgˆÖhðiûô" ô PÜ�‰Ð?È$ˆÖOðPús$   Œ#C% ÂA D Ã%"D
Ä	D
Ä"D2Ä1D2c                óh   € V ^8„  d   QhR\         R\        \        \        \        3,          ,          /# )r?   r  rB   )r   r   r€   rD   )rF   s   "r;   rG   rG   å  s'   € ÷ ñ œ#ð ¤(¬5´´c°­?Õ";ñ r=   c                ó  € \        V \        4      '       dl   \        V 4      ^8X  d\   \        ;QJ d    R V  4       F  '       d   K   RM	  RM! R V  4       4      '       d"   \	        \        \
        \
        3,          V 4      # R# )z¤*info* as a (thread_id, initial_name) pair, or None if it isn't one.

The pair crosses the relay connector boundary, so its shape is the connector's word, not ours.c              3   óB   "  € T F  p\        V\        4      x € K  	  R # 5irÇ   )r   rD   )rÊ   Úxs   & r;   rÌ   Ú"_as_thread_info.<locals>.<genexpr>é  s   é € Ð9[ÑVZÐQR¼*ÀQÌ×:LÐ:LÓVZùs   ‚FTN)r   r€   rU   Úallr   rD   )r  s   &r;   Ú_as_thread_infor+  å  sU   € ô �$œ×Ò¤3 t£9°¤>·c³cÑ9[ÑVZÓ9[·c·c²cÑ9[ÑVZÓ9[×6[Ò6[Ü”Eœ#œs˜(•O TÓ*Ð*Ùr=   c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r?   Únamer•   rB   rC   )rF   s   "r;   rG   rG   î  s!   € ÷ ñ ”Sð ¤5ð ¬Uñ r=   c                óÈ   € \         P                  P                  V 4      pVe   VR8X  d   \        V4      #  \        V4      #   \        \
        3 d    \        T4      u # i ; i)zcRead an env var as float; unset/empty/malformed fall back to ``default`` (never crash the gateway).r”   )rþ   rÿ   r~   rE   Ú	TypeErrorrô  )r-  r•   Úraws   && r;   r  r  î  sV   € ä
�*‰*�.‰.˜Ó
€CØ
‚{�c˜R”iÜ�W‹~ÐðÜ�S‹zÐøÜ”zÐ"ô Ü�W‹~Òðús   ·
A ÁA!Á A!c          
      óL   € V ^8„  d   QhR\         R\        R\        R\        RR/# )r?   r™   ÚdescÚ
provenanceÚdebug_labelrB   N)r   rD   r)   )rF   s   "r;   rG   rG   ù  s4   € ÷ 1ñ 1Üð1Üð1Ü'9ð1ÜHKð1ØPTñ1r=   c                ó~   €  V P                  WR7       R#   \         d    \        P                  TRR7        R# i ; i)zJBest-effort activity provenance stamp for hygiene compression transitions.)r3  TrG  N)Ú_touch_activityrL   rM   rN   )r™   r2  r3  r4  s   &&&&r;   Ú%_stamp_hygiene_compression_provenancer7  ù  s7   € ð1Ø×Ñ˜dÐÖ:øÜô 1Ü�‰�[¨4ˆ×0ð1ús   ‚ –"<»<ÚnowÚwindow_secsc                ót   € V ^8„  d   QhR\         R\        \        ,          R\        \        ,          R\        /# )r?   r  r8  r9  rB   )r   r   rE   rm   )rF   s   "r;   rG   rG     s4   € ÷ 
)ñ 
)Üð
)Ü ¤�ð
)Ü=EÄe½_ð
)ÜX\ñ
)r=   c               ó¾   € Ve   \        V4      M\        \        4      pV^ 8:  d   R# \        V 4      pVf   R# Vf   \        P                  ! 4       MTpWT,
          V8*  # )zfTrue when an interruption marker is fresh enough to auto-continue (unknown timestamps count as fresh).T)rE   Ú%_AUTO_CONTINUE_FRESHNESS_SECS_DEFAULTr÷  rÁ   )r  r8  r9  r  ró  Úcurrents   &$$   r;   Ú_is_fresh_gateway_interruptionr>    sW   € ð $/Ò#:ŒU�;ÔÄÔFkÓ@l€FØ�„{ÙÜ)¨%Ó0€IØÒÙØ š[Œd�iŠiŒk¨c€GØÕ &Ñ(Ð(r=   Úinteractivec                ó^   € V ^8„  d   QhR\         \        ,          R\        R\        R\        /# ©r?   ro  rŸ  r?  rB   ©r   rD   rm   )rF   s   "r;   rG   rG     s0   € ÷ (1ñ (1Ü”S�Mð(1Ü$'ð(1Ü>Bð(1ÜNQñ(1r=   c               ó²   € V R8X  d   RM
V R8X  d   RMRpV'       d   RpRpMV'       d   RpRpMR	pR
pRV RV RV R2V'       d   RV 2,           # R,           # )ué  Build the resume-pending recovery system note for an interrupted turn (empty ``message`` = auto-resume).

Interactive platforms report the restore and ask what next; non-interactive ones finish the work.

On non-interactive event platforms (webhook, API server â€” adapters with ``interactive_resume = False``)
nobody can answer; the resumed turn must instead complete the interrupted work, or the task is silently
abandoned behind a "restored" acknowledgement that goes nowhere (#57056).
Úrestart_timeoutza gateway restartÚshutdown_timeoutza gateway shutdownza gateway interruptionzTAddress the user's NEW message below FIRST and focus on what the user is asking now.u\   Do NOT re-execute old tool calls â€” skip any unfinished work from the conversation history.zfReport to the user that the session was restored successfully and ask what they would like to do next.zËNo user is present on this non-interactive platform, so do NOT emit a 'session restored' acknowledgement or ask questions. Review the conversation history and CONTINUE the interrupted task to completion.u€   Do NOT re-run tool calls whose results already appear in the history â€” resume from the first step that has no recorded result.z3[System note: The previous turn was interrupted by u‚   ; the gateway is now back online. Any restart/shutdown command in the history has already run â€” do NOT re-execute or verify it. Ú Ú]ú

r”   rº   )ro  rŸ  r?  Úreason_phraseÚresume_guidanceÚtail_guidances   &&$   r;   Úbuild_resume_recovery_noterL    s·   € ð  &Ð):Ô:ÑØ%+Ð/AÔ%AÑ!ÐG_ð ÷ àbð 	ð kñ 	÷ 
ðDð 	ð kñ 	ð
;ð 	ð`ð 	ð >Øˆ/ð 3à3BÐ2CÀ1À]ÀOÐSTð	V÷  'ˆT�'�Ðõ		0ð1ð
 -/õ		0ð1r=   c          
      ó–   € V ^8„  d   QhR\         \        ,          R\         \        ,          R\        R\        \        \        3,          /# rA  )r   rD   rm   r€   )rF   s   "r;   rG   rG   :  s@   € ÷ -ñ -Ü”S�Mð-Ü$,¬S¥Mð-ÜCGð-ÜSXÔY\Ô^aÐYaÕSbñ-r=   c               ó–   € \        Y;'       g    RVR7      p\        V\        4      '       d   VP                  4       '       d   TMTpW43# )uÊ  Return the recovery message and the user text to persist.

Empty original: persist the note (a "" user row trips the pre-call sanitizer). Real text: persist clean.

Resume turns replace the startup event's text with a recovery note before entering the agent. When the
original message is empty (the synthesized auto-resume turn), persist the note too â€” persisting the
empty string left a blank user row in state.db that the pre-call sanitizer re-healed on every later call
forever (#86580). When the user sent REAL text while the resume was pending, keep persisting their clean
words: the transcript stays scaffold-free (the model still receives the wrapped note), and a non-empty
row never trips the sanitizer.
r”   )r?  )rL  r   rD   rá   )ro  rŸ  r?  Úrecovery_messageÚpersist_messages   &&$  r;   Ú_prepare_resume_pending_messagerQ  :  s?   € ô 2°&¿-¸-ÀRÐU`ÔaÐÜ!+¨G´S×!9Ò!9¸g¿m¹m¿oºo‘gÐSc€OØÐ,Ð,r=   c                ó˜   € V ^8„  d   QhR\         R\        R\        \         \        3,          R\        R\        \         \        3,          /# )r?   Úroler®  ÚmsgÚpreserve_timestamprB   )rD   r   rà   rm   )rF   s   "r;   rG   rG   `  sD   € ÷ 1ñ 1Ü
ð1Üð1Ü"&¤s¬C x¥.ð1ÜFJð1ä	Œ#Œsˆ(…^ñ1r=   c                óê  € RV RV/pVP                  R4      pV R	9   d8   \        V\        4      '       d"   V'       d   WP                  R4      8X  d   WTR&   V R8X  dA   \         F6  pWb9  d   K  VP                  V4      pVR8X  d   Vf   MV'       g   K2  WtV&   K8  	  V'       d$   VP                  R4      '       d   VR,          VR&   VP	                  \        V4      4       \        \        \        3 Uu/ uF  qˆV9   g   K  W‚V,          bK  	  upV4       VP                  R4      '       d   RVR&   \        \        \        3 F&  p	VP                  V	4      '       g   K  W),          WI&   K(  	  V# u upi )
a  Build a replay entry for a non-tool-calling message, preserving ``_ASSISTANT_REPLAY_FIELDS``.

``preserve_timestamp``: only user rows need it (stale-dangerous-confirmation stripper). Falsy fields are
dropped EXCEPT ``reasoning_content``: DeepSeek/Kimi treat "" as a sentinel; dropping it can 400.

Empty values: most fields are dropped when falsy (matching the original PR #2974 behaviour) since an
empty list/string for those carries no information. The exception is ``reasoning_content``:
DeepSeek/Kimi thinking-mode replay treats an empty string as a meaningful sentinel that
``_copy_reasoning_content_for_api`` upgrades to a single space. Dropping it here would make the gateway
send no ``reasoning_content`` at all on the next turn, which can cause HTTP 400 from strict thinking
providers.
rS  r®  Úapi_contentÚ	assistantÚreasoning_contentró  Ú_db_persistedT)ÚuserrX  )r~   r   rD   Ú_ASSISTANT_REPLAY_FIELDSÚupdater&   r$   r#   r"   r   r   r   )
rS  r®  rT  rU  rƒ   Ú_sidecarÚ_rkeyÚ_rvalÚkeyÚstamps
   &&&&      r;   Ú_build_replay_entryrc  `  sM  € ð $ T¨9°gÐ>€Eð �w‰w�}Ó%€HàÐ%Ô%Ü�x¤×%Ò%ßØ—w‘w˜yÓ)Ô)Ø'ˆmÑØˆ{Ôß-ˆEØÔÙØ—G‘G˜E“NˆEØ"'Ð+>Ô">�“ÏÙØ �%‹Lñ .÷ ˜cŸg™g k×2Ò2Ø  Õ-ˆˆkÑØ	‡L�LÔ*¨3Ó/Ô0ô ´KÔAVÑ3WÓfÑ3W¨CÐbeÑ[eœ-˜# 3�xš-Ñ3WÑfÐhmÔnð ‡w�wˆ×ÒØ!%ˆˆoÑô &Ô';Ô=QÓRˆØ�7‰7�5�>Œ>Ø�:ˆE‹Lñ Sð €Lùò gs   Ã5E0ÄE0zobserved Telegram group contextz>[Observed Telegram group context - context only, not requests]zh[Current addressed message - answer only this unless it explicitly asks you to use the observed context]c                óF   € V ^8„  d   QhR\         \        ,          R\        /# )r?   Úchannel_promptrB   rB  )rF   s   "r;   rG   rG   ™  s"   € ÷ _ñ _¼(Ä3½-ð _ÌDñ _r=   c                ó:   € \        T ;'       d
    \        V 9   4      # )zµReturn True for Telegram group turns that may include observed chatter.

Observed rows must not replay as ordinary user turns, or a weak wake word makes old chatter look like work.
)rm   Ú(_TELEGRAM_OBSERVED_CONTEXT_PROMPT_MARKER)re  s   &r;   Ú%_uses_telegram_observed_group_contextrh  ™  s   € ô
 �×]Ð]Ô#KÈ~Ñ#]Ó^Ð^r=   c                óF   € V ^8„  d   QhR\         R\        \        ,          /# )r?   r0  rB   ©r   r   rD   )rF   s   "r;   rG   rG   ¡  s"   € ÷ Jñ JœSð J¤S¬¥Xñ Jr=   c                ó�  € V f   \        4       # \        V \        4      '       dK   V  Uu0 uF=  p\        V4      P	                  4       '       g   K$  \        V4      P	                  4       kK?  	  up# \        V 4      P                  R4       Uu0 uF*  qP	                  4       '       g   K  VP	                  4       kK,  	  up# u upi u upi )zDNormalize a config list or comma-separated scalar into a string set.Ú,)r   r   rŒ   rD   rá   rÎ   )r0  rË   s   & r;   Ú_csv_or_list_to_setrm  ¡  s†   € à
‚{Ü‹uˆÜ�#”t×ÒÙ.1ÓG©c d´S¸³Y·_±_×5FÔ!”�D“	—‘Ö!©cÑGÐGÜ%(¨£X§^¡^°CÔ%8ÓIÑ%8˜T¿J¹J¿LŒLˆD�J‰JŽLÑ%8ÑIÐIùò HùÚIs   ©!B>ÁB>ÂCÂ'Cc                óR   € V ^8„  d   QhR\         R\         R\        \        ,          /# )r?   râ   r«  rB   rj  )rF   s   "r;   rG   rG   ª  s(   € ÷ $ñ $¼ð $Äcð $ÔUXÔY\ÕU]ñ $r=   c                ób  € RpVe2   \        \        VRR4      RR4      ;'       g    / P                  R4      p\        V R/ 4      P                  \        P                  4      pVf%   Ve!   Vf   \        VR/ 4      P                  R4      pVf   ^ RIHp V! R4      ;'       g    Rp\        V4      # )aZ  Return Slack channels that the generic gateway must never dispatch.

Duplicates the adapter's drop as a fail-safe so bypasses can't reach auth, pairing or sessions.
``adapter`` is the source's routed adapter: under multiplex ``config`` is the DEFAULT profile's
GatewayConfig, so a secondary Slack bot's list lives only in its adapter's ``extra``.Nrâ   ÚextraÚignored_channelsrÐ  )Úplatform_gate_envÚSLACK_IGNORED_CHANNELS)r8   r~   ÚPlatformÚSLACKÚgateway.platforms._sharedrr  rm  )râ   r«  r0  rÒ  Ú_platform_gate_envs   &&   r;   Ú+_slack_ignored_channels_from_gateway_configrx  ª  s¨   € ð €CØÒÜ”w˜w¨°$Ó7¸À$ÓG×MÐMÈ2×RÑRÐSeÓfˆÜ˜6 ;°Ó3×7Ñ7¼¿¹ÓG€LØ
‚{�|Ò/°G²OÜ�l G¨RÓ0×4Ñ4Ð5GÓHˆØ
‚{õ 	VÙ Ð!9Ó:×BÐB¸dˆÜ˜sÓ#Ð#r=   c                ó0   € V ^8„  d   QhR\         R\        /# )r?   r¬  rB   r  )rF   s   "r;   rG   rG   ¾  s   € ÷ <ñ <¤cð <¬cñ <r=   c                óZ   € V '       d#   \        V 4      P                  R^4      ^ ,          # R# )zFReturn the parent Slack channel from a possibly thread-scoped chat ID.Ú:r”   )rD   rÎ   )r¬  s   &r;   Ú_slack_parent_channel_idr|  ¾  s%   € ç,3Œ3ˆw‹<×Ñ˜c 1Ó% aÕ(Ð;¸Ð;r=   c                óH   € V ^8„  d   QhR\         R\         R\         R\        /# )r?   râ   r¬  r«  rB   rè   )rF   s   "r;   rG   rG   Ã  s/   € ÷ Jñ J¤cð J´Cð JÄ#ð JÔQUñ Jr=   c                óv   € \        V4      p\        W4      p\        T;'       d    RV9   ;'       g    W49   4      # )zªCheck the generic Slack gateway blacklist for channel or thread IDs (``adapter`` = the source's
routed adapter, whose ``extra`` is authoritative for a secondary profile).Ú*)r|  rx  rm   )râ   r¬  r«  Ú
channel_idÚignoreds   &&&  r;   Ú_is_slack_ignored_channelr‚  Ã  s:   € ô *¨'Ó2€JÜ9¸&ÓJ€GÜ�
×HÐH  w¡× GÐ G°*Ñ2GÓIÐIr=   c                óF   € V ^8„  d   QhR\         \        ,          R\        /# )r?   rÌ  rB   )r   rà   rm   )rF   s   "r;   rG   rG   Ë  s   € ÷ ñ ¬X´d­^ð Äñ r=   c                ó  € \        V \        4      '       g   R# V P                  R4      p\        V\        4      '       g   R# VP                  R4      p\        V\        4      '       d   \        VP                  RR4      4      # \        V4      # )zdTrue when gateway.message_timestamps.enabled is opted in (default OFF: changes what the model sees).Fr9   Úmessage_timestampsÚenabled)r   rà   r~   rm   )rÌ  ÚgwÚmts   &  r;   Ú_message_timestamps_enabledr‰  Ë  sk   € ä�k¤4×(Ò(ÙØ	�‰˜Ó	#€BÜ�bœ$×ÒÙØ	�‰Ð$Ó	%€BÜ�"”d×ÒÜ�B—F‘F˜9 eÓ,Ó-Ð-ä�‹8€Or=   c                ój   € V ^8„  d   QhR\         R\         R\        \        \         3,          R\        /# )r?   rS  r®  rT  rB   )r   rà   rD   rm   )rF   s   "r;   rG   rG   Ù  s0   € ÷ ñ ¤#ð ´ð ¼$¼sÄC¸x½.ð ÌTñ r=   c                ó¼   € V R8H  ;'       dQ    V'       * ;'       dB    \        VP                  R4      \        4      ;'       d    \        VP                  R4      4      # )aQ  True for an assistant row whose reply lives only in the ``api_content`` sidecar.

A reasoning-only clean stop persists ``content=""`` and the promoted text in ``api_content``
(agent/turn_final_response.py). Gating replay on ``content`` alone dropped that row, so the
next gateway turn lost the assistant's answer and replayed user->user.rX  rW  )r   r~   rD   rm   )rS  r®  rT  s   &&&r;   Ú_has_replayable_sidecarrŒ  Ù  sZ   € ð 	�Ñ÷ 	)ð 	)ØŒK÷	)ð 	)ä�s—w‘w˜}Ó-¬sÓ3÷	)ð 	)ô �—‘˜Ó'Ó(ð	r=   re  Úinject_timestampsc                ó  € V ^8„  d   QhR\         \        \        \        3,          ,          R\        \        ,          R\
        R\        \         \        \        \        3,          ,          \        \        ,          3,          /# )r?   rŠ   re  r�  rB   )rŒ   rà   rD   r   r   rm   r€   )rF   s   "r;   rG   rG   ç  s^   € ÷ I+ñ I+Ü”$”sœC�x•.Õ!ðI+Ü6>¼sµmðI+äðI+ä(-¬d´4¼¼S¸µ>Õ.BÄHÌSÅMÐ.QÕ(RñI+r=   c               ó,  € ^ RI Hp ^ RIHpHp V! 4       p. p. p\        V4      p	T ;'       g    .  EF¢  p
V
P                  R4      pV'       d   VR9   d   K&  V
P                  R4      pV	'       dˆ   V
P                  R4      '       dq   VR8X  dj   V'       db   V'       d0   \        V\        4      '       d   V! WÊP                  R4      VR7      pVP                  \        V4      P                  4       4       KÆ  R	V
9   g   R
V
9   g   VR8X  dA   V
P                  4        UUu/ uF  w  rÞVR9  g   K  WÞbK  	  pppVP                  V4       EK  V'       g   \        W¼V
4      '       g   EK8  V
P                  R4      pVR8X  dH   \        V\        4      '       d'   V! WÆR7      w  pp\        V4      pVV8w  d	   TpVe   TpV'       g   EK—  \        W¼W«R8H  R7      pV'       d–   VR8X  d�   \        V\        4      '       dy   \        V
4      '       gh   V! VVVR7      pVP                  R4      pVV8w  d@   V'       d8   VV8X  g1   VP!                  VR,           4      '       g   VP#                  RR4       VVR&   V
P                  R4      '       d7   V
P                  RR4      pRV RVR,           2VR&   VP#                  RR4       VP                  V4       EK¥  	  \%        V4      pRP'                  V4      P                  4       ;'       g    RpVV3# u uppi )z¨Convert stored gateway transcript rows into agent replay messages.

Observed context stays out of ``conversation_history`` so consecutive-user repair can't merge it in.)Úget_timezone)Ú"render_user_content_with_timestampÚ strip_leading_message_timestampsrS  r®  Úobservedr[  ró  )ÚtzÚ
tool_callsÚtool_call_idÚtoolN)rU  rW  rH  ÚmirrorÚmirror_sourcezanother sessionz[Delivered from z] rŽ  >   ÚsystemÚsession_meta>   r“  ró  )Úhermes_timer�  Úgateway.message_timestampsr‘  r’  rh  r~   r   rD   rs  rá   ÚitemsrŒ  Ú_strip_auto_continue_noiserc  r%   r™  ÚpopÚcanonicalize_replay_historyrÏ   )rŠ   re  r�  Ú_get_msg_tzÚ_render_msg_tsÚ_strip_msg_tsÚ_msg_tzÚagent_historyÚobserved_group_contextÚseparate_observed_contextrT  rS  r®  Úkr  Ú	clean_msgÚreplay_timestampr‘  Úembedded_timestampÚ
clean_bodyrƒ   ÚrenderedÚsidecarÚ
mirror_srcÚobserved_contexts   &$$                      r;   Ú_build_gateway_agent_historyr²  ç  s©  € õ 8÷ñ
 ‹m€GØ*,€MØ(*ÐÜ EÀnÓ UÐà�}ˆ}˜"‹}ˆØ�w‰w�v‹ˆç�tÐ9Ô9Ùà—'‘'˜)Ó$ˆß$¨¯©°×)<Ò)<ÀÈÄ×T[ß ¤Z°¼×%=Ò%=Ù(¨·'±'¸+Ó2FÈ7ÔS�Ø"×)Ñ)¬#¨g«,×*<Ñ*<Ó*>Ô?Ùð ˜3Ô .°CÔ"7¸4À6¼>Ø*-¯)©)¬+Ô\©+¡$ !¸ÐB[Ñ9[œ˜š©+ˆIÑ\Ø× Ñ  ×+ßÔ/°¸s×CÕCØ"Ÿw™w {Ó3Ðð �vŒ~Ü˜g¤s×+Ò+Ù/<¸WÔ/QÑ,�DÐ,Ü!;¸DÓ!A�JØ! TÔ)Ø",˜Ø-Ò9Ø/AÐ,ßÚä'¨°sÐX^ÑP^Ô`ˆEß  T¨V¤^¼
À7ÌC×8PÒ8PÔYrÐsv×YwÒYwÙ)¨'Ð3CÈÔP�ð  Ÿ)™) MÓ2�Ø˜wÔ&¯7Ø˜xÔ'¨7×+=Ñ+=¸hÈÕ>O×+PÒ+Pà—I‘I˜m¨TÔ2Ø#+��iÑ Ø�w‰w�x× Ò Ø ŸW™W _Ð6GÓH�
Ø%5°j°\ÀÀEÈ)ÕDTÐCUÐ#V��iÑ Ø—	‘	˜-¨Ô.Ø× Ñ  ×'ña ôj 0°Ó>€Mà—y‘yÐ!7Ó8×>Ñ>Ó@×HÐHÀDÐØÐ*Ð*Ð*ùóS ]s   ÄLÄ/Lc          	      ó¬   € V ^8„  d   QhR\         \        \        \        3,          ,          R\        R\         \        \        \        3,          ,          /# )r?   Úpersisted_historyÚlive_historyrB   )rŒ   rà   rD   r   )rF   s   "r;   rG   rG   3  s?   € ÷ ñ ÜœD¤¤c �NÕ+ðÜ;>ðÜCGÌÌSÔRUÈXÍÕCWñr=   c                ó  a€ \        V\        4      '       dm   \        V4      \        V 4      8”  dT   ^ RIHo \
        ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      pV'       d   \        V4      # V # )aÌ  Prefer the cached live transcript only when it is longer AND has a real, non-ephemeral unpersisted row.

Guards FTS write-corruption amnesia (stale reload while the cached agent holds unpersisted rows). Length
alone is not enough: a longer all-durable list can be an expected replay-filtering delta.

Guards the FTS write-corruption case (#50502): when message writes fail silently through corrupt FTS
triggers, the next turn reloads a stale/empty ``conversation_history`` from disk even though the same
cached ``AIAgent`` still holds unpersisted real rows in ``_session_messages``. Replacing those rows with
the shorter persisted copy causes immediate same-session amnesia. Length alone does not trigger
retention.
)Ú_is_ephemeral_scaffoldingc              3   óª   <"  € T FH  p\        V\        4      ;'       d,    VP                  R 4      '       * ;'       d    S! V4      '       * x € KJ  	  R# 5i)rZ  NrÑ  )rÊ   rŸ  r·  s   & €r;   rÌ   Ú/_select_cached_agent_history.<locals>.<genexpr>C  sR   øé € ð "TáFR¸7ô �w¤Ó%÷ 7ð 7¨g¯k©k¸/Ó.JÔ*J÷ 7ð 7Ù-¨gÓ6Ô6ô7ÛFRùs   ƒAŸA½ATF)r   rŒ   rU   Úagent.session_persistencer·  Úany)r´  rµ  Úhas_unpersisted_rowr·  s   && @r;   Ú_select_cached_agent_historyr½  3  so   ø€ ô �,¤×%Ò%¬#¨lÓ*;¼cÐBSÓ>TÔ*TÝGç!›cô "TáFRó"TŸcŸcšcô "TáFRó"Tó TÐ÷ Ü˜Ó%Ð%ØÐr=   c                óR   € V ^8„  d   QhR\         R\        \        ,          R\         /# )r?   rŸ  r±  rB   )r   r   rD   )rF   s   "r;   rG   rG   K  s)   € ÷ ñ ¼ð ÔPXÔY\ÕP]ð Ôbeñ r=   c                óò  € V'       g   V # \          RV R\         R2p\        V \        4      '       d   V V  2# \        V \        4      '       d£   V  Uu. uF&  p\        V\
        4      '       d   \        V4      MTNK(  	  ppV FN  p\        V\
        4      '       g   K  VP                  R4      R8X  g   K3  V VP                  RR4       2VR&   Vu # 	  RRRVP                  4       /.V,           # V # u upi )zDPrepend observed Telegram context to the API-only current user turn.rŽ  rH  r5  rQ  r”   )Ú_OBSERVED_GROUP_CONTEXT_HEADERÚ!_CURRENT_ADDRESSED_MESSAGE_HEADERr   rD   rŒ   rà   r~   r˜  )rŸ  r±  rl  rË   Úwrappeds   &&   r;   Ú+_wrap_current_message_with_observed_contextrÃ  K  sî   € çØˆä.Ð/¨rÐ2BÐ1CÀ4ÔHiÐGjÐjlÐm€Fä�'œ3×ÒØ�˜'˜Ð#Ð#ä�'œ4× Ò ÙNUÓVÉgÀd¤¨D´$×!7Ò!7”4˜”:¸TÒAÉgˆÐVÛˆDÜ˜$¤×%Ô%¨$¯(©(°6Ó*:¸fÖ*DØ"( ¨$¯(©(°6¸2Ó*>Ð)?Ð@��V‘Ø’ñ ð ˜ ¨¯©«Ð9Ð:¸WÕDÐDà€Nùò Ws   Á,C4c                ó~   € V ^8„  d   QhR\         \        \        \        \        3,          ,          ,          R\        /# )r?   rŠ   rB   )r   rŒ   rà   rD   r   )rF   s   "r;   rG   rG   `  s,   € ÷ ñ ¬´´d¼3Ä¸8µnÕ1EÕ(Fð Ì3ñ r=   c                óæ   € V '       g   R# \        V 4       FW  p\        V\        4      '       g   K  VP                  R4      pV'       d   VR9   d   K=  VP                  R4      pVe   Vu #  R# 	  R# )u·   Return the ``timestamp`` of the last usable (non-metadata) transcript row, if any.

``None`` when the last usable row has no timestamp â€” callers treat that as "fresh" (legacy rows).NrS  ró  >   rš  r›  )Úreversedr   rà   r~   )rŠ   rT  rS  Útss   &   r;   Ú_last_transcript_timestamprÈ  `  sd   € ÷ ÙÜ˜Ö ˆÜ˜#œt×$Ò$ÙØ�w‰w�v‹ˆß�tÐ9Ô9ÙØ�W‰W�[Ó!ˆØŠ>ØŠIÚñ !ñ r=   )r¡  z [System note: Your previous turnz[System note: A new messagec                ó0   € V ^8„  d   QhR\         R\        /# ©r?   r®  rB   rè   )rF   s   "r;   rG   rG     s   € ÷ Fñ F¤Sð F¬Tñ Fr=   c                óh   € \        V \        4      ;'       d    V P                  \        \        34      # )zdReturn True if this user-message content is a gateway-injected auto-continue note (never replay it).)r   rD   r™  Ú_AUTO_CONTINUE_NOTE_PREFIXÚ_AUTO_CONTINUE_FALLBACK_PREFIX)r®  s   &r;   Ú_is_auto_continue_noiserÎ    s5   € ä�gœsÓ#÷ Fð F¨×(:Ñ(:Ü	#Ô%CÐDó)Fð Fr=   c                ó0   € V ^8„  d   QhR\         R\         /# rÊ  ©r   )rF   s   "r;   rG   rG   …  s   € ÷ 
ñ 
¬ð 
´ñ 
r=   c                óÎ   € \        V 4      '       g   V # \        V 4      p\        V4      '       d6   VP                  R4      pV^ 8  d   R# W^,           R P                  4       pKF  V# )zdStrip leading persisted auto-continue notes from user text; the trailing real question is preserved.rG  r”   N)rÎ  rD   ÚfindÚlstrip)r®  rQ  Úends   &  r;   rŸ  rŸ  …  sX   € ä" 7×+Ò+ØˆÜˆw‹<€DÜ
! $×
'Ò
'Ø�i‰i˜‹nˆØ�Œ7ÙØ˜!•G�Iˆ×%Ñ%Ó'ŠØ€Kr=   z MEDIA:((?:[A-Za-z]:[/\\]|/|~\/)\S+\.(?:png|jpe?g|gif|webp|mp4|mov|avi|mkv|webm|ogg|opus|mp3|wav|m4a|flac|epub|pdf|zip|rar|7z|docx?|xlsx?|pptx?|txt|csv|apk|ipa)))Útool_name_by_call_idc          
      óÎ   € V ^8„  d   QhR\         \        \        \        3,          ,          R\        R\
        \        ,          R\        \         \        ,          \        3,          /# )r?   ÚmessagesÚhistory_offsetÚhistory_media_pathsrB   )	rŒ   rà   rD   r   rQ   r   r   r€   rm   )rF   s   "r;   rG   rG   ¢  sJ   € ÷ 9+ñ 9+Ü”4œœS˜•>Õ"ð9+Ü47ð9+ä!¤#�ð9+ä27¼¼S½	Ä4¸Õ2Hñ9+r=   c                ó®  € T;'       g    \        4       pV'       d   \        V 4      V8¼  d   WR MT p\        V4      p. pRpV EF÷  pVP                  R4      R9  d   K  \	        VP                  R4      ;'       g    VP                  R4      ;'       g    R4      pVP                  V4      \
        9  d   Ku  \	        VP                  R4      ;'       g    R4      p	VP                  V4      p
V
R8X  dÁ   R	V	9  dº    \        P                  ! V	4      p\        V\        4      '       dŠ   VP                  R
4      '       ds   \         Fh  pVP                  V4      p\        V\        4      '       g   K,  \        P                  R	V 24      '       g   KL  WÒ9  g   KT  VP                  R	V 24        M	  EKq  R	V	9  d   EK{  \        P                  V	4       FW  pVP!                  ^4      P#                  4       P%                  R4      pV'       g   K;  WÒ9  g   KC  VP                  R	V 24       KY  	  RV	9   g   EKõ  RpEKú  	  WV3#   \         d    Rp EL@i ; i)a²  Collect real media tags from current-turn producer-tool results only.

Producer allowlist: docs/logs/search results contain example MEDIA: strings that must never become
attachments. If mid-run compression shrank the list below the history length the slice is
untrustworthy, so scan every message (dedup via history_media_paths).

1. Producer-tool allowlist: only tools that intentionally emit deliverable artifacts (TTS) are eligible.
(Fixes the original report behind #16721.) 2. Current-turn isolation: only messages produced this turn
are scanned, so a tool result from an earlier turn (still present in the full message list) cannot leak
onto a later text-only reply (#34608).
When that happens the slice boundary is no longer trustworthy, so fall back to scanning every message
and rely on ``history_media_paths`` for dedup, preserving the compression-safe behaviour of #160. The
producer-tool allowlist still applies on the fallback path.
NFrS  r–  Úcall_idr”   r®  Úimage_generateúMEDIA:r¶  ú",}ú[[audio_as_voice]]T)r—  Úfunction)r   rU   Ú_tool_name_by_call_idr~   rD   Ú_AUTO_APPEND_MEDIA_TOOL_NAMESÚjsonÚloadsrL   r   rà   Ú_JSON_MEDIA_TOOL_PATH_FIELDSÚ_TOOL_MEDIA_REÚ	fullmatchrs  Úfinditerrè  rá   r˜  )r×  rØ  rÙ  Únew_messagesrÕ  Ú
media_tagsÚhas_voice_directiverT  rÛ  r®  Ú	tool_nameÚpayloadÚfieldr  râ  s   &&&            r;   Ú_collect_auto_append_media_tagsrï  ¢  s  € ð" .×6Ð6´³Ðç%¬#¨h«-¸>Ô*Ið ˜_Ñ-ØOWð ô 1°Ó>Ðà€JØÐÜˆØ�7‰7�6‹?Ð"6Ô6ÙÜ�c—g‘g˜nÓ-×IÐI°·±¸Ó1C×IÐIÀrÓJˆØ×#Ñ# GÓ,Ô4QÔQÙÜ�c—g‘g˜iÓ(×.Ð.¨BÓ/ˆØ(×,Ñ,¨WÓ5ˆ	àÐ(Ô(¨X¸WÔ-DðÜŸ*š* WÓ-�ô ˜'¤4×(Ò(¨W¯[©[¸×-CÒ-Cß9�EØ"Ÿ;™; uÓ-�DÜ" 4¬×-Ô-Ü .× 8Ñ 8¸6À$À¸× IÔ IØ $Ö ?Ø"×)Ñ)¨F°4°&¨/Ô:Ùñ :ò Ø˜7Ô"ÚÜ#×,Ñ,¨WÖ5ˆEØ—;‘;˜q“>×'Ñ'Ó)×0Ñ0°Ó7ˆDß‰t˜Ö7Ø×!Ñ! F¨4¨& /Ö2ñ 6ð   7×*Ø"&Óñ= ð@ Ð*Ð*øô) ô Ø“ðús   Ã=IÉIÉIc                óh   € V ^8„  d   QhR\         \        \        \        3,          ,          R\        /# )r?   r¦  rB   )rŒ   rà   rD   r   r   )rF   s   "r;   rG   rG   Þ  s'   € ÷ (ñ (´´T¼#¼s¸(µ^Õ0Dð (Ìñ (r=   c                ó  a
€ \        4       o
\        V 4      pR V
3R llpV  EFM  pVP                  R4      pVR9  d   K  \        VP                  RR4      ;'       g    R4      pRV9   d   V! V4       KT  VR8X  d   K]  \        VP                  R4      ;'       g    VP                  R	4      ;'       g    R4      pVP                  V4      R
8X  g   K²   \        P
                  ! V4      p\        V\        4      '       g   Ká  VP                  R4      '       g   Kú  \         FI  pVP                  V4      p	\        V	\        4      '       g   K,  V	'       g   K6  S
P                  V	4        EKK  	  EKP  	  S
#   \         d    Rp Lši ; i)zöDedup set of media paths already delivered (JSON-payload and assistant-message shapes alike).

Missing the JSON-payload shape caused #46627; missing the assistant-message shape caused repeated
delivery when the model echoed a previous MEDIA tag.
c                ó(   € V ^8„  d   QhR\         RR/# )r?   r®  rB   Nr_   )rF   s   "r;   rG   Ú2_collect_history_media_paths.<locals>.__annotate__ç  s   € ÷ >ñ >¤sð >¨tñ >r=   c                 ó2  <€ \         P                  V 4       FL  pVP                  ^4      P                  4       P	                  R4      pV'       g   K;  SP                  V4       KN  	  \        P                  ! V 4      w  r4SP                  R V 4       4       R# )ræ  rÞ  c              3   ó*   "  € T F	  w  rVx € K  	  R # 5irÇ   rº   )rÊ   r  Ú	_is_voices   &  r;   rÌ   ÚN_collect_history_media_paths.<locals>._add_text_media_paths.<locals>.<genexpr>î  s   é € Ð=±™o˜d•T³ùs   ‚N)	ræ  rè  rè  rá   r˜  r  ÚBasePlatformAdapterÚextract_mediar]  )r®  râ  r  Úmedia_filesÚ_Úpathss   &    €r;   Ú_add_text_media_pathsÚ;_collect_history_media_paths.<locals>._add_text_media_pathsç  so   ø€ Ü#×,Ñ,¨WÖ5ˆEØ—;‘;˜q“>×'Ñ'Ó)×0Ñ0°Ó7ˆDß‰tØ—	‘	˜$–ñ 6ô
 -×:Ò:¸7ÓC‰ˆØ�‰Ñ=±Ó=Ö=r=   rS  rX  r®  r”   rÝ  r–  rÛ  rÜ  Nr¶  )rX  r—  rà  )r   rá  r~   rD   rã  rä  rL   r   rà   rå  r  )r¦  rÕ  rý  rT  rS  r®  Úcidrí  rî  Újprü  s   &         @r;   Ú_collect_history_media_pathsr  Þ  sE  ø€ ô “€EÜ0°Ó?Ð÷>ð >ô ˆØ�w‰w�v‹ˆØÐ8Ô8ÙÜ�c—g‘g˜i¨Ó,×2Ð2°Ó3ˆØ�wÔÙ! 'Ô*ÙØ�;ÔÙÜ�#—'‘'˜.Ó)×EÐE¨S¯W©W°YÓ-?×EÐEÀ2ÓFˆØ×#Ñ# CÓ(Ð,<Ö<ðÜŸ*š* WÓ-�ô ˜'¤4×(Ô(¨W¯[©[¸×-CÔ-Cß9�EØ Ÿ™ UÓ+�BÜ! "¤c×*Ô*¯r©rØŸ	™	 "œÛô	 :ñ# ð, €Løô ô Ø’ðús   ÃE6Å6FÆFc                ó0   € V ^8„  d   QhR\         R\         /# ©r?   Úplatform_namerB   r_   )rF   s   "r;   rG   rG     s   € ÷ [ñ [¬ð [´ñ [r=   c                óT   € ^ RI Hp V! V 4      ;'       g    V P                  4        R2# )z]Home-target env var: the plugin's ``cron_deliver_env_var``, then
``<PLATFORM>_HOME_CHANNEL``.)Ú_resolve_home_env_varÚ_HOME_CHANNEL)Úcron.scheduler_deliveryr  Úupper)r  r  s   & r;   Ú_home_target_env_varr
    s+   € õ >Ù  Ó/×ZÐZ°m×6IÑ6IÓ6KÐ5LÈMÐ3ZÐZr=   c                ó0   € V ^8„  d   QhR\         R\         /# r  r_   )rF   s   "r;   rG   rG     s   € ÷ >ñ >¬ð >´ñ >r=   c                ó   € \        V 4       R2# )zDReturn the optional thread/topic env var for a platform home target.Ú
_THREAD_ID)r
  )r  s   &r;   Ú_home_thread_env_varr    s   € ä" =Ó1Ð2°*Ð=Ð=r=   c                ó$   € V ^8„  d   QhR\         /# rÖ   r×   )rF   s   "r;   rG   rG     s   € ÷ <ñ <¤tñ <r=   c                 ó8   € \         R,          P                  4       # )zIReturn True when a /restart completion marker is waiting to be delivered.z.restart_notify.json)Ú_hermes_homer  rº   r=   r;   Ú_restart_notification_pendingr    s   € äÐ1Õ1×9Ñ9Ó;Ð;r=   c                ó$   € V ^8„  d   QhR\         /# rÖ   r   )rF   s   "r;   rG   rG     s   € ÷ 2ñ 2¬Dñ 2r=   c                  ó   € \         R ,          # )z.restart_pending.json)r  rº   r=   r;   Ú"_planned_restart_notification_pathr    s   € ÜÐ1Õ1Ð1r=   c                ó$   € V ^8„  d   QhR\         /# rÖ   r×   )rF   s   "r;   rG   rG     s   € ÷ 9ñ 9¬tñ 9r=   c                 ó2   € \        4       P                  4       # )zHReturn True when a non-chat planned restart should notify home channels.)r  r  rº   r=   r;   Ú%_planned_restart_notification_pendingr    s   € ä-Ó/×6Ñ6Ó8Ð8r=   rÛ   Ú_HERMES_GATEWAY)Úget_hermes_homeÚget_hermes_home_overrideÚget_process_hermes_home)Úload_hermes_dotenvú.env©Úhermes_homeÚproject_envc                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   4  s   € ÷ 	0ñ 	0¸ñ 	0r=   c                 óÒ   € ^ RI Hp  V ! 4       '       gE   \        \        \	        \
        4      P                  4       P                  ^,          R,          R7       \        \        4       R# )aW  Reload .env per turn for rotated keys while config.yaml stays authoritative for budgets (else a
stale HERMES_MAX_ITERATIONS wins). Multiplex never reloads .env globally: secrets come from the
per-turn ``set_secret_scope`` and mutating ``os.environ`` would leak the default profile's keys to
every profile; it still honors the max_turns bridge.©Úis_multiplex_activer  r  N)	Úagent.secret_scoper%  r  r  r   rú   rû   ÚparentsÚ_bridge_max_turns_from_configr$  s    r;   Ú/_reload_runtime_env_preserving_config_authorityr)  4  sE   € õ
 7Ù× Ò ÜÜ$´$´x³.×2HÑ2HÓ2J×2RÑ2RÐSTÕ2UÐX^Õ2^õ	`ä!¤,Ö/r=   c                ó(   € V ^8„  d   QhR\         RR/# )r?   ÚhomerB   Nr   )rF   s   "r;   rG   rG   @  s   € ÷ Jñ J¬ð J°ñ Jr=   c                ó$  € ^ RI Hp V! 4       '       d   R# V R,          pVP                  4       '       g   R#  \        V4      p\        TP                  R/ 4      4       \        TP                  R/ 4      \        4       R#   \         d     R# i ; i)a  Re-bridge agent.max_turns (+ sessions.*) per turn; managed overlay applies or it reverts.
Skipped inside a served secondary's scope: the env slots are the launch profile's and
hermes_state reads the routed profile's ``sessions.*`` from its own config under scope.)Úprofile_scopedNúconfig.yamlr™   Úsessions)	rv  r-  r  Ú_load_bridge_configrL   Ú_bridge_max_turns_to_envr~   Ú_bridge_section_to_envÚ_SESSIONS_ENV_BRIDGE)r+  r-  Úconfig_pathÚcfgs   &   r;   r(  r(  @  s}   € õ 9Ù×ÒÙØ˜Õ&€KØ×Ñ×ÒÙðÜ! +Ó.ˆô ˜SŸW™W W¨bÓ1Ô2Ü˜3Ÿ7™7 :¨rÓ2Ô4HÖIøô ô Úðús   ¸B  Â BÂBc                ó$   € V ^8„  d   QhR\         /# rÖ   r  )rF   s   "r;   rG   rG   R  s   € ÷ Cñ C¤ñ Cr=   c                 ó˜  € \        4        ^ RIHp  \        4       pV'       d{   \	        V4      R,          p VP                  4       '       d   \        V4      M/ pVP                  R4      pT ! \        V\        4      '       d   VP                  R4      4      # R4      # V ! \        P                  ! R4      4      #   \         d    / p Loi ; i)aÔ  Return the per-turn iteration budget after runtime env refresh; ``resolve_turn_limit`` maps
``agent.max_turns: none``/``unlimited`` (bridged as a string) to the unlimited sentinel, not an
``int()`` crash. A routed profile (HERMES_HOME override, multiplexed turns) reads ITS
``agent.max_turns`` straight from config: the ``HERMES_MAX_ITERATIONS`` bridge is one process-wide
slot holding the launch profile's value, so every secondary would inherit the default's budget.)Úresolve_turn_limitr.  r™   Ú	max_turnsNÚHERMES_MAX_ITERATIONS)r)  r  r8  r  r   r  r0  rL   r~   r   rà   rþ   Úgetenv)Ú_resolve_turn_limitÚoverrider4  r5  r"  s        r;   Ú_current_max_iterationsr>  R  s¬   € ô 4Ô5ÝKÜ'Ó)€HßÜ˜8“n }Õ4ˆð	Ø6A×6HÑ6H×6JÒ6JÔ% kÔ2ÐPRˆCð —G‘G˜GÓ$ˆ	Ù"ÄÈIÔW[×A\ÒA\ 9§=¡=°Ó#=ÓgÐgÐbfÓgÐgÙœrŸyšyÐ)@ÓAÓBÐBøô	 ô 	ØŠCð	ús   ¶#B9 Â9C	ÃC	)ÚasynccontextmanagerÚcontextmanagerr}   c                   ó   € ] tR tRtRtRtR# )ÚMultiplexConfigErrorii  z©Invalid profile multiplexer config: the operator must fix config.yaml, so it propagates to the
startup guard instead of being treated as retryable adapter-connect noise.rº   N©r6  Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__static_attributes__rº   r=   r;   rB  rB  i  s   † õRr=   rB  c                   ó   € ] tR tRtRtRtR# )ÚHygieneTurnHoldExceededin  z¾Hygiene-compression turn-hold budget elapsed mid-stream. Availability boundary, not a failure:
must NOT take the idle-timeout path (AGENT_COMPRESSION_TIMEOUT, "no output", failure cooldown).rº   NrC  rº   r=   r;   rJ  rJ  n  s   † õgr=   rJ  c                óh   € V ^8„  d   QhR\         R\        \        \        \        3,          ,          /# ©r?   râ   rB   ©ÚobjectrŒ   r€   rD   r   )rF   s   "r;   rG   rG   s  s(   € ÷ 3ñ 3¤Vð 3´´U¼3Ä¸9Õ5EÕ0Fñ 3r=   c                ój   € \        V RR4      pVe   \        V4      # ^ RIHp \        V! RR7      4      # )a  The profile set this multiplexer SERVES: the process reservation once boot took it (grown
and shrunk by the hot-serve reconcile, which diffs it against what exists under ``profiles/``
via ``profiles_to_serve``), else the live directory read for pre-reservation callers.Ú_runtime_profile_homesN)Úprofiles_to_serveT)Ú	multiplex)r8   rŒ   Úhermes_cli.profilesrQ  )râ   ÚreservedrQ  s   &  r;   Ú_multiplex_profile_homesrU  s  s7   € ô �vÐ7¸Ó>€HØÒÜ�H‹~ÐÝ5ÜÑ!¨DÔ1Ó2Ð2r=   c                óh   € V ^8„  d   QhR\         R\        \        \        \        3,          ,          /# rL  rM  )rF   s   "r;   rG   rG   ~  s(   € ÷ ñ ¤Vð ´´U¼3Ä¸9Õ5EÕ0Fñ r=   c                ó  a€ ^ RI HpHp \        V 4      pV! 4       ;'       g    Ro\        ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      '       d   V#  VSV! S4      3.,           #   \
         d    Tu # i ; i)a{  Profile homes the in-process ticker visits: the served set PLUS the process-active
profile: ``profiles_to_serve`` lists default + every live named profile, but a ``--profile
<name>`` gateway's own profile may sit outside ``profiles/`` (custom HERMES_HOME). One host
process ticks all of them regardless of ``gateway.multiplex_profiles``. Adapter startup
already skips ``active``.)Úget_active_profile_nameÚget_profile_dirr•   c              3   ó2   <"  € T F  w  rVS8H  x € K  	  R # 5irÇ   rº   )rÊ   r-  Ú_homeÚactives   &  €r;   rÌ   Ú+_cron_tick_profile_homes.<locals>.<genexpr>ˆ  s   øé € Ð
3©U™k˜dˆ4�6Ž>«Uùs   ƒTF)rS  rX  rY  rU  r»  rL   )râ   rX  rY  Úhomesr\  s   &   @r;   Ú_cron_tick_profile_homesr_  ~  sz   ø€ ÷ Mä$ VÓ,€EÙ$Ó&×3Ð3¨)€Fß
ƒsÔ
3©UÓ
3‡s‡s‚sÔ
3©UÓ
3×3Ò3ØˆðØ˜¡°Ó!8Ð9Ð:Õ:Ð:øÜô ØŠðús   Á)A; Á;BÂ
Bc                ó<   € V ^8„  d   QhR\         R\        R\        /# )r?   r-  r+  rB   )rD   r   rm   )rF   s   "r;   rG   rG   �  s&   € ÷ _ñ _œSð _¬ð _´ñ _r=   c                óF  a€ ^ RI HoHp  V! \        V4      RV3R lR7      pTP                  ;'       d9    TP                  RJ;'       d#    TP                  \        P                  ! 4       8g  '       * #   \         d"   p\
        P                  RY4        Rp?R# Rp?ii ; i)ug  Tick ``home`` this cycle unless ANOTHER gateway process owns it.

Same stand-down the serve/Desktop ticker applies (``hermes_cli/web_server.py``): a host that
has not finished converging onto the one host gateway (``hermes gateway migrate --multiplex``)
may still run profile B's own gateway, and without this both it and this process race B's
``cron/.tick.lock``. The lock stops a simultaneous double-run but not the race: when this
process wins, B's delivery leaves through ``SharedRouteAdapters``/fail-closed instead of B's
live adapters.

The liveness answer is compared against our OWN pid, never used bare: this process holds the
launch home's ``gateway.pid`` and publishes every served profile in ``served_profiles``, so a
bare ``_check_gateway_running`` reports "running" for every home we serve â€” standing us down
from all of them and stopping cron host-wide.
)Úget_running_pidÚresolve_gateway_livenessFc                 ó   <€ S! V R R7      # )F)Úcleanup_stalerº   )r  rb  s   &€r;   rš   Ú$_cron_profile_gate.<locals>.<lambda>¤  s   ø€ ¡?°4ÀuÕ#Mr=   )Úprofile_dirÚ	use_cacheÚ	pid_probez6Cron profile gate probe failed for %s (ticking it): %sNT)Úgateway.statusrb  rc  r   rL   rM   rN   ÚrunningÚpidrþ   Úgetpid)r-  r+  rc  ÚlivenessrY   rb  s   &&   @r;   Ú_cron_profile_gatero  �  s†   ø€ ÷ IðÙ+Ü˜T›
¨eÜMôOˆð × Ñ ×]Ð] X§\¡\¸Ð%=×]Ð]À(Ç,Á,ÔRT×R[ÒR[ÓR]ÑB]Ô^Ð^øô ô Ü�‰ÐMÈtÔYÝûðús   ‹A4 Á4B Á?BÂB c                ó0   € V ^8„  d   QhR\         R\        /# rL  )rN  rm   )rF   s   "r;   rG   rG   «  s   € ÷ ñ ¬&ð ´Tñ r=   c                óâ   € \        V RR4      '       g   R#  ^ RIHp T! \        V 4       UUu. uF  w  r#VNK	  	  upp4      # u uppi   \         d    \
        P                  RRR7        R# i ; i)u  Route agent.log/errors.log/gateway.log records to their owning profile (inert single-profile).
``setup_logging(mode="gateway")`` binds file handlers to the launch home, so under multiplexing
every secondary profile's records would land in the default profile's logs.

Swap the static handlers for the profile routers from #99440 â€” the same primitive the Desktop cron
ticker uses â€” once the served-profile set is known. Inert for single-profile gateways
(``enable_profile_log_routing`` is a no-op below two homes).
Úmultiplex_profilesF)Úenable_profile_log_routingz(could not enable per-profile log routingTrG  )r8   Úhermes_loggingrs  rU  rL   rM   rN   )râ   rs  Ú_namer+  s   &   r;   Ú_enable_multiplex_log_routingrv  «  sj   € ô �6Ð/°×7Ò7ÙðÝ=Ù)ÔC[Ð\bÔCcÔ*dÑCc±K°E«4ÑCcÒ*dÓeÐeùÓ*døÜô Ü�‰Ð?È$ˆÔOÚðús!   —A ­A
ºA ÁA Á"A.Á-A.c                ó0   € V ^8„  d   QhR\         R\        /# ©r?   ÚrunnerrB   ©rN  rŒ   )rF   s   "r;   rG   rG   ¾  s   € ÷ ñ ¤&ð ¬Tñ r=   c                ó  € R	.p \        V RR4      pVeO   \        VRR4      '       d<   \        V4       F,  w  r4Ve   V'       d   VR8X  d   K  VP                  W434       K.  	  V#   \         d    \        P                  RRR7        T# i ; i)
a‡  ``(profile_name, home)`` pairs whose ``state.db`` the watcher must poll; ``(None, None)`` = root
poll, always first. ``/handoff`` writes into the store of the profile the CLI ran under; an unscoped
watcher polls only the ROOT store, so a secondary profile's handoff would never be seen (CLI times
out). A raising resolver degrades to the root poll rather than silently disabling the watcher.Nrâ   rr  Fr•   z5Could not resolve multiplex homes for handoff watcherTrG  ©NN)r8   rU  rs  rL   rM   rN   )ry  Úscopesrâ   r-  r+  s   &    r;   Ú_handoff_watch_scopesr~  ¾  s•   € ð
 !�>€Fð]Ü˜ ¨4Ó0ˆØÒ¤'¨&Ð2FÈ×"NÒ"NÜ6°vÖ>‘
�Ø’<§t¨t°yÔ/@ÙØ—‘˜t˜lÖ+ñ ?ð €Møô ô ]Ü�‰ÐLÐW[ˆÕ\Ø€Mð]ús   …?A& ÁA& Á&"BÂBc                ó0   € V ^8„  d   QhR\         R\        /# rx  rz  )rF   s   "r;   rG   rG   Ð  s   € ÷ )ñ )´ð )¼4ñ )r=   c              ƒ  óØ   "  € \        V RR4      pVe   \        VRR4      '       g   R.# \        V RR4      p\        V4      '       d   V! \        V 4      G Rj  x€L
 # \        V 4      #  L5i)uy  ``_handoff_watch_scopes`` for an on-loop watcher tick. Multiplex resolution walks the filesystem
(``profiles_to_serve``), so it hops to the executor; single-profile mode does no I/O and returns the
root poll directly â€” no per-tick thread spawn on the unbounded executor. A config-less stand-in
(tests) and a runner without the executor hop fall through to the plain resolver.râ   Nrr  FÚ_run_in_executor_with_contextr|  )r8   rO   r~  )ry  râ   Úoffloads   &  r;   Ú_resolve_handoff_watch_scopesrƒ  Ð  sm   é € ô
 �V˜X tÓ,€FØÒ¤'¨&Ð2FÈ×"NÒ"NØˆ~ÐÜ�fÐ=¸tÓD€GÜ�×ÒÙÔ2°FÓ;×;Ð;Ü  Ó(Ð(ñ <ùs   ‚AA*ÁA(ÁA*c                ó(   € V ^8„  d   QhR\         RR/# ©r?   ry  rB   N©rN  )rF   s   "r;   rG   rG   Þ  s   € ÷ Eñ E¤ð E¨Dñ Er=   c              ƒ  ó\  "  € \        \        V RR4      RR4      p\        V4      '       g   R#  V! R4      G Rj  x€L
 pT'       d9   \        P                  R\        T4      R	P                  R
 T 4       4      4       R# R#  LF  \         d    \        P	                  RRR7        R# i ; i5i)a)  Fail handoffs left in ``running`` by a gateway that died mid-dispatch (once per store at startup).
``running`` is only set for one in-process dispatch, so a leftover row belongs to a dead process and
blocks ``request_handoff`` for that session forever. Defensive: a raising reclaim aborts startup.r6   NÚreclaim_stale_running_handoffszVgateway stopped mid-handoff; state reclaimed at startup. Re-run /handoff to try again.zStale-handoff reclaim raisedTrG  zGReclaimed %d handoff(s) stranded in 'running' by a previous gateway: %sú, c              3   ó8   "  € T F  p\        V4      x € K  	  R # 5irÇ   r_   )rÊ   Úis   & r;   rÌ   Ú!_reclaim_stale.<locals>.<genexpr>î  s   é € Ð.C¹s¸!¬s°1¯v¨v»sùrÔ   )r8   rO   rL   rM   rN   r¬   rU   rÏ   )ry  ÚreclaimÚidss   &  r;   Ú_reclaim_staler�  Þ  s£   é € ô ”g˜f m°TÓ:Ð<\Ð^bÓc€GÜ�G×ÒÙðÙØdóf÷ fˆ÷
 Ü�‰ðÜ˜s›8 T§Y¡YÑ.C¹sÓ.CÓ%Cö	Eñ ñføäô Ü�‰Ð3¸dˆÔCÚðüs=   ‚,B,¯B ºB»B ¿B,Á:B,ÂB Â"B)Â%B,Â(B)Â)B,c                ó0   € V ^8„  d   QhR\         R\         /# )r?   r•   rB   r_   )rF   s   "r;   rG   rG   ñ  s   € ÷ ,ñ ,¤ð ,¬cñ ,r=   c                ó„   €  ^ RI Hp T! RT 4      #   \         d$    \        P                  P                  RT 4      u # i ; i)z™Scope-aware TERMINAL_CWD read for footer/context surfaces. Only an import failure falls back:
an active refusal scope must raise, not use the launch cwd.)Úterminal_envÚTERMINAL_CWD)Útools.terminal_scoper’  ÚImportErrorrþ   rÿ   r~   )r•   Ú_ts_envs   & r;   Ú_terminal_scope_cwdr—  ñ  s?   € ð7Ý@ñ �> 7Ó+Ð+øô ô 7Ü�z‰z�~‰~˜n¨gÓ6Ò6ð7ús   ‚ ‘+?¾?c                ó0   € V ^8„  d   QhR\         R\        /# )r?   Úprofile_homerB   ©r   rà   )rF   s   "r;   rG   rG   û  s   € ÷ /ñ /¬Tð /´dñ /r=   c                ó¼   € ^ RI HpHp ^ RIHp ^ RIHp V! \        V 4      4      p V! \        V 4      4       V! \        V 4      4      V! V4       #   T! T4       i ; i)z?Hydrate and load one profile's secrets under its home override.©Úset_hermes_home_overrideÚreset_hermes_home_override)Úhydrate_profile_secret_sources©Úowner_secret_scope)	Úhermes_constantsr�  rž  Úhermes_cli.env_loaderrŸ  Ú!tui_gateway.launch_profile_policyr¡  rD   r   )r™  r�  rž  rŸ  r¡  Ú
home_tokens   &     r;   Ú_load_profile_secret_scoper¦  û  sK   € çUåDÝDá)¬#¨lÓ*;Ó<€Jð/Ù&¤t¨LÓ'9Ô:Ù!¤$ |Ó"4Ó5á" :Õ.øÑ" :Õ.ús   §!A Á
AÚhydrate_secretsc                óR   € V ^8„  d   QhR\         R\        \        ,          R\        /# )r?   r™  Úprepared_secret_scoper§  )r   r   rà   rm   )rF   s   "r;   rG   rG     s(   € ÷  3ñ  3Üð 3Ü/7¼­~ð 3äñ 3r=   c             #  óâ  "  € ^ RI HpHp ^ RIHpHp R;rx V! \        V 4      4      pVe   Tp	M4V'       d   \        \        V 4      4      p	M^ RI	H
p
 V
! \        V 4      4      p	T! V	\        V 4      R7      p^ RIHp V! \        V 4      4      ;_uu_ 4        Rx € RRR4       Ve	   V! V4       Ve   V! V4       R# R#   + '       g   i     L,; i  Te	   T! T4       Te
   T! T4       i i ; i5i)aY  Scope config/skills/memory AND credentials to a profile for one turn (multiplexed path only).
``set_hermes_home_override`` is a contextvar (reaches the agent worker via ``copy_context()``);
``set_secret_scope`` makes the profile ``.env`` the credential source without mutating
``os.environ``, so subprocesses never inherit cross-profile secrets.rœ  )Úset_secret_scopeÚreset_secret_scopeNr   )r™  )Ú(install_and_reset_profile_terminal_scope)r¢  r�  rž  r&  r«  r¬  rD   r¦  r   r¤  r¡  r”  r­  )r™  r©  r§  r�  rž  r«  r¬  r¥  Úsecret_tokenÚsecretsr¡  r­  s   &&$         r;   Ú_profile_runtime_scoper°  
  sÙ   é € ÷ VßGà $Ð$€Jð3Ù-¬c°,Ó.?Ó@ˆ
Ø Ò,Ø+‰GßÜ0´°lÓ1CÓD‰GåLÙ(¬¨lÓ);Ó<ˆGÙ'¨¼cÀ,Ó>OÔPˆõ 	Rá5´d¸<Ó6H×IÕIÛ÷ Jð Ò#Ù˜|Ô,ØÒ!Ù& zÖ2ñ "÷ J×Iûð Ò#Ù˜|Ô,ØÒ!Ù& zÕ2ð "üs:   ‚C/—C ·AC ÂB>ÂC Â"C/Â>C	Ã	C ÃC,Ã,C/c                ó$   € V ^8„  d   QhR\         /# )r?   r™  r   )rF   s   "r;   rG   rG   /  s   € ÷ ñ ´Tñ r=   c               óè   "  € \         P                  ! \        \        V 4      4      G Rj  x€L
 p\	        \        V 4      V4      ;_uu_ 4        R5x € RRR4       R#  L1  + '       g   i     R# ; i5i)zEEnter a profile scope without loading secret files on the event loop.N)r¤   Ú	to_threadr¦  r   r°  )r™  r¯  s   & r;   Ú_async_profile_runtime_scoper´  .  sN   é € ô ×%Ò%Ô&@Ä$À|ÓBTÓU×U€GÜ	¤ \Ó 2°G×	<Õ	<Ü÷ 
=Ñ	<ñ Vß	<×	<Ð	<üs'   ‚(A2ªA«!A2ÁAÁA2ÁA/	Á)	A2c                ó   € V ^8„  d   QhRR/# )r?   rB   ÚGatewayConfigrº   )rF   s   "r;   rG   rG   6  s   € ÷ &ñ &¨ñ &r=   c                 ó  € ^ RI Hp Hp \        4       pV ! V! V4      4       VP                  '       g   V#  ^ RIHp V! R4        ^ RI
Hp V! 4       p \        \        T4      4      ;_uu_ 4        \        4       pRRR4       TP                  Xn        T#   \         d    \        P                  RRR7        Lui ; i  \         d    Tu # i ; i  + '       g   i     L^; i  \         d    \        P                  RRR7       Tu # i ; i)	u§  Load gateway config for the process-level GatewayRunner. An UNSET ``multiplex_profiles`` is
settled first by ``resolve_multiplex_mode`` (the default is on; the boot guard keeps a fleet that
still runs per-profile gateways standalone). Multiplexed: set multiplex-active, then reload
under the default root's ``_profile_runtime_scope`` â€” not ``get_hermes_home()``, which is the
named launcher when a profile-scoped process started the host. A scope miss must not fall
through to that process's ``os.environ``. Off -> identical to ``load_gateway_config()``.

See #64674.

The probe load above only decides whether this process is a multiplexer. The primary
config is the scoped reload: multiplex must already be active (a scope miss must not
fall through to the launching profile's ``os.environ``) and the home must be the
default root, not ``get_hermes_home()`` â€” a named launcher's home is not the owner
of the primary adapter map.
©Úlog_multiplex_decisionÚresolve_multiplex_mode©Úset_multiplex_activeTz9could not set multiplex-active before primary config loadrG  )Úget_default_hermes_rootNzAmultiplex default-scope config reload failed; using unscoped load)Ú!hermes_cli.gateway_multiplex_moder¹  rº  Úload_gateway_configrr  r&  r¼  rL   rM   rN   r¢  r½  r°  r   )r¹  rº  r5  r¼  r½  r+  Úscopeds          r;   Úload_gateway_config_for_runnerrÁ  6  sî   € ÷  aÜ
Ó
€CÙÑ1°#Ó6Ô7Ø×!×!Ð!Øˆ
ðaÝ;Ù˜TÔ"ðÝ<Ù&Ó(ˆðÜ#¤D¨£J×/Õ/Ü(Ó*ˆF÷ 0ð
 !$× 6Ñ 6€FÔØ€Møô ô aÜ�‰ÐPÐ[_ˆÖ`ðaûô
 ô ØŠ
ðú÷ 0×/ûäô Ü�‰ÐXÐcgˆÔhØŠ
ðúsS   ¶B ÁB= ÁC# Á/CÁ:C# Â"B:Â9B:Â=CÃCÃC 	ÃC# Ã C# Ã#$D
Ä	D
c                ó(   € V ^8„  d   QhR\         RR/# )r?   râ   rB   Nr†  )rF   s   "r;   rG   rG   _  s   € ÷ jñ j¬fð j¸ñ jr=   c           
   ƒ  ó�  "  € ^ RI Hp ^ RIHp \        P
                  ! 4       pV! 4       ;_uu_ 4        \        V RR4      '       g9   VP                  R\        4       P                  V4      G Rj  x€L
   RRR4       R# \        V 4       FX  w  rE \        \        V4      4      ;_uu_ 4        VP                  R\        4       P                  V4      G Rj  x€L
  RRR4       KZ  	  RRR4       R#  L€ L  + '       g   i     K{  ; i  \         d    \        P                  RTRR7        K¤  i ; i  + '       g   i     R# ; i5i)	uY  Run startup MCP discovery for every profile this gateway serves: ``discover_mcp_tools`` reads
``mcp_servers`` from ``get_hermes_home()``'s config, so an unscoped call only connects the launch
profile's servers (single-profile gateways keep the unscoped call).

Under multiplex, run it once per served profile inside that profile's ``_profile_runtime_scope`` and
carry the scope into the executor thread with ``copy_context()`` (the same shape as
``_run_in_executor_with_context``). See #95518.

No gateway run can complete a browser OAuth flow (nobody watches its stdout; on Windows its
DEVNULL stdin even passes ``isatty``), so discovery runs with interactive OAuth suppressed â€” the
same gate the CLI's background discovery uses. An expired token then parks the server with an
actionable ``hermes mcp login`` warning instead of opening an authorize tab.
)Úsuppress_interactive_oauth)Údiscover_mcp_toolsrr  FNz*MCP tool discovery failed for profile '%s'TrG  )Útools.mcp_oauthrÄ  Útools.mcp_tool_discoveryrÅ  r¤   r¥   r8   r¦   r   r§   rU  r°  r   rL   rM   r¬   )râ   rÄ  rÅ  r?  Úprofile_namer™  s   &     r;   Ú_discover_gateway_mcp_toolsrÉ  _  s  é € õ ;Ý;Ü×#Ò#Ó%€DÙ	#×	%Õ	%Ü�vÐ3°U×;Ò;Ø×&Ñ& t¬\«^×-?Ñ-?ÐASÓT×TÐTØ÷ 
&Ñ	%ô +CÀ6Ö*JÑ&ˆLðjÜ+¬D°Ó,>×?Õ?Ø×.Ñ.¨t´\³^×5GÑ5GÐI[Ó\×\Ð\÷ @Ñ?ñ +K÷	 
&Ñ	%áTñ
 ]÷ @×?Ð?ûäô jÜ—‘ÐKÈ\Ðdh�×iðjú÷ 
&×	%Ð	%üs”   ‚1E³<D2Á/C0Á0D2Á5
EÁ?D2ÂDÂ,)C4ÃC2ÃC4ÃDÃ"D2Ã&
EÃ0D2Ã2C4Ã4DÃ?DÄD2ÄDÄ#D/	Ä+D2Ä.D/	Ä/D2Ä2E	Ä=	Ec                ó,   € V ^8„  d   QhRRRRR\         /# )r?   rç   rt  Úplatform_configÚPlatformConfigrB   r×   )rF   s   "r;   rG   rG   |  s(   € ÷ cñ c¨:ð cÐHXð cÔ]añ cr=   c           	     ó8  a€ ^ RI HpHp WP                  J dJ   ^ RIHp \        VP                  P                  RV! RR4      4      4      pVR,          P                  4       # W9  d   R# R FJ  p\        WR4      ;'       g    R	p\        V\        4      '       g   K1  VP                  4       '       g   KI   R# 	  WP                  Jd   R
# \        VRR4      ;'       g    / o\        ;QJ d    V3R lR 4       F  '       d   K   R
# 	  R# ! V3R lR 4       4      # )zÀReturn True when a token-authenticated platform has a usable bot credential; platforms not using
``PlatformConfig.token`` (Signal session paths, port-binding HTTP adapters) always return True.)ÚPLATFORM_TOKEN_ENV_NAMESrt  )Úget_hermes_dirÚsession_pathzplatforms/whatsapp/sessionzwhatsapp/sessionz
creds.jsonTNr”   Frp  c              3   óˆ   <"  € T F7  p\        SP                  V4      ;'       g    R 4      P                  4       x € K9  	  R# 5i)r”   N)rD   r~   rá   )rÊ   ra  rp  s   & €r;   rÌ   Ú/_platform_has_bot_credential.<locals>.<genexpr>—  s4   øé € ÐbÑ<a°SŒs�5—9‘9˜S“>×'Ð' RÓ(×.Ñ.×0Ð0Ó<aùs
   ƒ!A¥A)ÚtokenÚapi_key)Ú
homeserverÚuser_idÚpassword)Úgateway.configrÎ  rt  ÚWHATSAPPr¢  rÏ  r   rp  r~   r  r8   r   rD   rá   ÚMATRIXr*  )	rç   rË  rÎ  rt  rÏ  ÚsessionÚattrr  rp  s	   &&      @r;   Ú_platform_has_bot_credentialrÝ  |  sê   ø€ ÷ BØ×$Ñ$Ó$Ý3Ü�×,Ñ,×0Ñ0Ø™NÐ+GÐI[Ó\ó^ó _ˆà˜,Õ&×.Ñ.Ó0Ð0ØÔ/ÙÛ$ˆÜ˜¨tÓ4×:Ð:¸ˆÜ�eœS×!Ô! e§k¡k§m¤mÚñ %ð —‘Ó&ÙÜ�O W¨dÓ3×9Ð9°r€Eß‹3ÔbÑ<aÓb�3Œ3ÐbŠ3Ðbˆ3ÔbÑ<aÓbÓbÐbr=   z=^(?P<host>.+):(?P<container>/[^:]+?)(?::(?P<options>[^:]+))?$z/outputz/outputs)ÚDEFAULT_CONFIGr™   Úgateway_turn_lease_timeoutÚHERMES_TURN_LEASE_TIMEOUTÚgateway_timeoutÚHERMES_AGENT_TIMEOUTÚgateway_timeout_warningÚHERMES_AGENT_TIMEOUT_WARNINGÚgateway_notify_intervalÚHERMES_AGENT_NOTIFY_INTERVALÚsession_stall_timeoutÚHERMES_SESSION_STALL_TIMEOUTÚrestart_drain_timeoutÚHERMES_RESTART_DRAIN_TIMEOUTÚcron_drain_timeoutÚHERMES_CRON_DRAIN_TIMEOUTÚgateway_auto_continue_freshnessÚHERMES_AUTO_CONTINUE_FRESHNESSÚ%gateway_startup_restore_drain_timeoutr  Úgateway_startup_warmup_timeoutr  Úcjk_ftsÚHERMES_CJK_FTSÚsearch_slow_msÚHERMES_SEARCH_SLOW_MSÚbusy_input_modeÚHERMES_GATEWAY_BUSY_INPUT_MODEÚbusy_text_modeÚHERMES_GATEWAY_BUSY_TEXT_MODEÚbusy_ack_enabledÚHERMES_GATEWAY_BUSY_ACK_ENABLEDc                óV   € V ^8„  d   QhR\         R\        \        \        3,          RR/# )r?   ÚsectionÚmappingrB   N)r   rà   rD   )rF   s   "r;   rG   rG   ·  s)   € ÷ <ñ <¤Cð <´$´s¼C°xµ.ð <ÀTñ <r=   c                ó¼   € \        V \        4      '       dF   VP                  4        F/  w  r#W 9   g   K  \        W,          4      \        P
                  V&   K1  	  R# R# )zKExport every present ``mapping`` key of a config section as ``str(value)``.N)r   rà   rž  rD   rþ   rÿ   )rü  rý  Úcfg_keyÚenv_vars   &&  r;   r2  r2  ·  sC   € ä�'œ4× Ò Ø '§¡¦ÑˆGØÖ!Ü&)¨'Õ*:Ó&;”—
‘
˜7Ó#ó !0ñ !r=   c                ó(   € V ^8„  d   QhR\         RR/# )r?   r"  rB   NrÐ  )rF   s   "r;   rG   rG   ¿  s   € ÷ 
0ñ 
0¬ð 
0°ñ 
0r=   c                óê   € \        V \        4      '       d   RV 9  d   R# V R,          pVe   \        V4      \        P                  R&   R# R\        P                  9   d   \        P                  R R# R# )zôBridge ``agent.max_turns`` preserving its raw spelling ("none", "unlimited", "120"); Python None
(`null` / bare `key:`) clears a stale bridge instead, since str(None) -> "None" would map to the
unlimited sentinel rather than "absent = default".r9  Nr:  )r   rà   rD   rþ   rÿ   )r"  r0  s   & r;   r1  r1  ¿  s[   € ô �i¤×&Ò&¨+¸YÔ*FÙØ
�KÕ
 €CØ
‚Ü.1°#«hŒ�
‰
Ð*Ó+Ø	 ¤B§J¡JÔ	.Ü�J‰JÐ.Ò/ñ 
/r=   c                ó(   € V ^8„  d   QhR\         RR/# )r?   Ú_terminal_cfgrB   Nr&  )rF   s   "r;   rG   rG   Ì  s   € ÷ 2añ 2a´$ð 2a¸4ñ 2ar=   c                ój  € \        V P                  R4      ;'       g*    \        P                  P                  R4      ;'       g    R4      P	                  4       P                  4       p/ RRbRRbRRbRR	bR
RbRRbRRbRRbRRbRRbRRbRRbRRbRRbRRbR R!bR"R#b/ R$R%bR&R'bR(R)bR*R+bR,R-bR.R/bR0R1bR2R3bR4R5bR6R7bR8R9bR:R;bR<R=bR>R?bR@RAbRBRCbCpVP                  4        FÐ  w  r4W09  d   K  W,          pVR8X  dg   \        V4      RE9   d   K.  \        V\         4      '       d?   \        WP	                  4       4      '       g    \        P                  P                  V4      p\        V\        \        34      '       d   \        P                  ! V4      M
\        V4      \        P                  V&   KÒ  	  RD# )Fz]Bridge nested ``terminal.*`` config to TERMINAL_* env vars (config.yaml overrides .env here).ÚbackendÚTERMINAL_ENVr”   Údegraded_modeÚTERMINAL_DEGRADED_MODEÚcwdr“  rŸ   ÚTERMINAL_TIMEOUTÚ	home_modeÚTERMINAL_HOME_MODEÚlifetime_secondsÚTERMINAL_LIFETIME_SECONDSÚdocker_imageÚTERMINAL_DOCKER_IMAGEÚdocker_forward_envÚTERMINAL_DOCKER_FORWARD_ENVÚmodal_imageÚTERMINAL_MODAL_IMAGEÚdaytona_imageÚTERMINAL_DAYTONA_IMAGEÚvercel_runtimeÚTERMINAL_VERCEL_RUNTIMEÚvercel_imageÚTERMINAL_VERCEL_IMAGEÚssh_hostÚTERMINAL_SSH_HOSTÚssh_userÚTERMINAL_SSH_USERÚssh_portÚTERMINAL_SSH_PORTÚssh_keyÚTERMINAL_SSH_KEYÚcontainer_cpuÚTERMINAL_CONTAINER_CPUÚcontainer_memoryÚTERMINAL_CONTAINER_MEMORYÚcontainer_diskÚTERMINAL_CONTAINER_DISKÚcontainer_persistentÚTERMINAL_CONTAINER_PERSISTENTÚdocker_volumesÚTERMINAL_DOCKER_VOLUMESÚ
docker_envÚTERMINAL_DOCKER_ENVÚdocker_extra_argsÚTERMINAL_DOCKER_EXTRA_ARGSÚdocker_shm_sizeÚTERMINAL_DOCKER_SHM_SIZEÚdocker_mount_cwd_to_workspaceÚ&TERMINAL_DOCKER_MOUNT_CWD_TO_WORKSPACEÚdocker_networkÚTERMINAL_DOCKER_NETWORKÚdocker_run_as_host_userÚ TERMINAL_DOCKER_RUN_AS_HOST_USERÚdocker_snap_compatÚTERMINAL_DOCKER_SNAP_COMPATÚdocker_persist_across_processesÚ(TERMINAL_DOCKER_PERSIST_ACROSS_PROCESSESÚdocker_shared_container_keyÚ$TERMINAL_DOCKER_SHARED_CONTAINER_KEYÚdocker_orphan_reaperÚTERMINAL_DOCKER_ORPHAN_REAPERÚsandbox_dirÚTERMINAL_SANDBOX_DIRÚpersistent_shellÚTERMINAL_PERSISTENT_SHELLN>   Ú.r
  Úauto)rD   r~   rþ   rÿ   rá   r¢   rž  r   r+   r  Ú
expanduserrŒ   rà   rã  Údumps)r  Ú_terminal_backendÚ_terminal_env_mapÚ_cfg_keyÚ_env_varÚ_vals   &     r;   Ú_bridge_terminal_config_to_envrO  Ì  s¨  € äØ×Ñ˜)Ó$×LÐL¬¯
©
¯©°~Ó(F×LÐLÈ"óNßNSÉeËg×V[ÑV[ÓV]ð ð!9Ø�>ð!9àÐ1ð!9ð 	ˆ~ð!9ð 	Ð%ð	!9ð
 	Ð)ð!9ð 	Ð7ð!9ð 	Ð/ð!9ð 	Ð;ð!9ð 	Ð-ð!9ð 	Ð1ð!9ð 	Ð3ð!9ð 	Ð/ð!9ð 	Ð'ð!9ð 	Ð'ð!9ð 	Ð'ð!9ð  	Ð%ð!!9ð" 	Ð1ñ#!9ð$ 	Ð7ð%!9ð& 	Ð3ð'!9ð( 	Ð ?ð)!9ð* 	Ð3ð+!9ð, 	Ð+ð-!9ð. 	Ð9ð/!9ð0 	Ð5ð1!9ð2 	(Ð)Qð3!9ð4 	Ð3ð5!9ð6 	"Ð#Eð7!9ð8 	Ð;ð9!9ð: 	*Ð+Uð;!9ð< 	&Ð'Mð=!9ð> 	Ð ?ð?!9ð@ 	Ð-ðA!9ðB 	Ð7ñC!9ÐðD 0×5Ñ5Ö7ÑˆØÔ(ÙØÕ&ˆØ�uÔä�4‹yÐ0Ô0Ùô ˜$¤×$Ò$Ô-EÐFW×YcÑYcÓYe×-fÒ-fÜ—w‘w×)Ñ)¨$Ó/�Ü3=¸dÄTÌ4ÀL×3QÒ3QœtŸzšz¨$Ô/ÔWZÐ[_ÓW`Œ�
‰
�8Óó 8r=   c                ó(   € V ^8„  d   QhR\         RR/# )r?   Ú_auxiliary_cfgrB   Nr&  )rF   s   "r;   rG   rG     s   € ÷ Eñ E´Dð E¸Tñ Er=   c                ó\  € RR0p ^ RI Hp V! 4        F  pVP                  VR,          4       K  	  V Fã  pV P	                  V/ 4      p\        V\        4      '       g   K-  VP                  4       p\        VP	                  RR4      4      P                  4       pV'       d   VR8w  d   V\        P                  RV R	2&   R FQ  w  r‰\        VP	                  VR4      4      P                  4       p
V
'       g   K8  V
\        P                  RV R
V	 2&   KS  	  Kå  	  R#   \         d     Løi ; i)z^Bridge auxiliary model/endpoint overrides (vision, approval, plugins); compression reads yaml.ÚvisionÚapproval)Úget_plugin_auxiliary_tasksra  Úproviderr”   rG  Ú
AUXILIARY_Ú	_PROVIDERrû  N))r  ÚMODEL)Úbase_urlÚBASE_URL)rÔ  ÚAPI_KEY)Úhermes_cli.pluginsrU  r  rL   r~   r   rà   r	  rD   rá   rþ   rÿ   )rQ  Ú_aux_bridged_keysrU  Ú_entryÚ	_task_keyÚ	_task_cfgÚ_upperÚ_provÚ_fieldÚ_suffixÚ_values   &          r;   Ú_bridge_auxiliary_config_to_envrg    s  € à! :Ð.ÐðÝAÙ0Ö2ˆFØ×!Ñ! &¨¥-Ö0ñ 3ó 'ˆ	Ø"×&Ñ& y°"Ó5ˆ	Ü˜)¤T×*Ò*ÙØ—‘Ó"ˆÜ�I—M‘M *¨bÓ1Ó2×8Ñ8Ó:ˆß�U˜f”_Ø9>ŒB�J‰J˜ F 8¨9Ð5Ñ6Ûe‰OˆFÜ˜Ÿ™ v¨rÓ2Ó3×9Ñ9Ó;ˆFß‰vØ>D”—
‘
˜Z¨ x¨q°°	Ð:Ó;ó  fó 'øô ô Ùðús   †,D ÄD+Ä*D+c                ó(   € V ^8„  d   QhR\         RR/# )r?   Ú_cfgrB   Nr&  )rF   s   "r;   rG   rG     s   € ÷ *rñ *r¤ð *r¨ñ *rr=   c                ór  € V P                  4        F`  w  r\        V\        \        \        \
        34      '       g   K-  V\        P                  9  g   KD  \        V4      \        P                  V&   Kb  	  V P                  R/ 4      pV'       d"   \        V\        4      '       d   \        V4       V P                  R/ 4      pV'       d"   \        V\        4      '       d   \        V4       V P                  R/ 4      p\        V4       \        V\        4       \        V P                  R/ 4      \        4       V P                  R/ 4      p\        V\         4       \        V\        4      '       d@   RV9   d9   R\        P                  9  d$   \        VR,          4      \        P                  R&   V P                  RR	4      pV'       d8   \        V\        4      '       d"   VP#                  4       \        P                  R
&   V P                  R/ 4      p\        V\        4      '       dE   VP                  R4      e2   \        VR,          4      P%                  4       \        P                  R&   V P                  R/ 4      p	\        V	\        4      '       d¤   ^ RIHp
 V
! V 4       V	P                  R4      pVe   \        V4      \        P                  R&   RV	9   d\   \        P                  P                  RR	4      P#                  4       '       g&   \        V	R,          4      \        P                  R&   R# R# R# R# )zGExport config.yaml settings to the env vars os.getenv() consumers read.ÚterminalÚ	auxiliaryr™   r/  rÏ  Úbusy_steer_ack_enabledÚ%HERMES_GATEWAY_BUSY_STEER_ACK_ENABLEDÚtimezoner”   ÚHERMES_TIMEZONEÚsecurityÚredact_secretsNÚHERMES_REDACT_SECRETSr9   )Úapply_media_policy_envÚtrust_recent_files_secondsÚ!HERMES_MEDIA_TRUST_RECENT_SECONDSÚplatform_connect_timeoutÚ'HERMES_GATEWAY_PLATFORM_CONNECT_TIMEOUT)rž  r   rD   rQ   rE   rm   rþ   rÿ   r~   rà   rO  rg  r1  r2  Ú_AGENT_ENV_BRIDGEr3  Ú_DISPLAY_ENV_BRIDGErá   r¢   Úgateway.media_policyrt  )ri  Ú_keyrN  r  rQ  Ú
_agent_cfgÚ_display_cfgÚ_tz_cfgÚ_security_cfgÚ_gateway_cfgrt  Ú_trust_recent_secondss   &           r;   Ú_bridge_config_to_envrƒ    sT  € à—j‘j–l‰
ˆÜ�dœS¤#¤u¬dÐ3×4Ô4¸ÄRÇZÁZÖ9OÜ" 4›yŒB�J‰J�tÓñ #ð —H‘H˜Z¨Ó,€Mßœ M´4×8Ò8Ü& }Ô5Ø—X‘X˜k¨2Ó.€Nßœ* ^´T×:Ò:Ü'¨Ô7ð
 —‘˜' 2Ó&€JÜ˜ZÔ(Ü˜:Ô'8Ô9Ü˜4Ÿ8™8 J°Ó3Ô5IÔJØ—8‘8˜I rÓ*€LÜ˜<Ô)<Ô=ä�<¤×&Ò&Ð+CÀ|Ô+SØ7¼r¿z¹zÔIÜ>AÀ,ÐOgÕBhÓ>iŒ�
‰
Ð:Ñ;Ø�h‰h�z 2Ó&€Gß”:˜g¤s×+Ò+Ø(/¯©«Œ�
‰
Ð$Ñ%Ø—H‘H˜Z¨Ó,€MÜ�-¤×&Ò&¨=×+<Ñ+<Ð=MÓ+NÒ+ZÜ.1°-Ð@PÕ2QÓ.R×.XÑ.XÓ.ZŒ�
‰
Ð*Ñ+à—8‘8˜I rÓ*€LÜ�,¤×%Ò%Ý?Ù˜tÔ$Ø ,× 0Ñ 0Ð1MÓ NÐØ Ò,Ü>AÐBWÓ>XŒB�J‰JÐ:Ñ;à&¨,Ô6ÜŸ
™
Ÿ™Ð'PÐRTÓU×[Ñ[×]Ò]ÜDGÈÐUoÕHpÓDqŒB�J‰JÐ@ÓAñ ^ñ 7ñ &r=   c                ó0   € V ^8„  d   QhR\         R\        /# )r?   r4  rB   rš  )rF   s   "r;   rG   rG   E  s   € ÷ 	3ñ 	3¤Tð 	3¬dñ 	3r=   c                óD   € ^ RI Hp V! 4       pVe   V# ^ RIHp V! V 4      # )a$  Effective USER config (no defaults) for the presence-sensitive env bridge: only keys the user
or the managed layer wrote get bridged, else all of DEFAULT_CONFIG would be exported. A bypass
worker bridges its frozen explicit snapshot instead: the profile file is exactly what it must not read.)Úworker_config_snapshot©Úload_user_config_effective)Úagent.safe_worker_policyr†  Úhermes_cli.config_effectiverˆ  )r4  r†  Úsnapshotrˆ  s   &   r;   r0  r0  E  s)   € õ @Ù%Ó'€HØÒØˆÝFÙ% kÓ2Ð2r=   r.  u.     Warning: config.yaml â†’ env bridge failed: ú: ©Úfilezz  Gateway will fall back to .env values, which may not match your current config.yaml. Run `hermes doctor` to investigate.)Úapply_ipv4_preferenceÚnetworkÚ
force_ipv4rZ  z/  Warning: IPv4 preference application failed: )Úprint_config_warningsz%  Warning: config validation failed: )Úwarn_deprecated_cwd_env_varsz%  Warning: deprecation check failed: ÚHERMES_QUIET)ÚCWD_PLACEHOLDERSÚ resolve_placeholder_terminal_cwd)ÚChannelOverridert  r¶  rÌ  Ú_getenvr¿  )ÚAsyncSessionStoreÚSessionStoreÚSessionSourceÚSessionContextÚbuild_session_keyÚ"profile_from_session_key_namespace)ÚDeliveryRouter)ÚSessionTurnLeaseRegistry)ÚSessionStateÚlegacy_dict_propertyÚlegacy_lease_token_property)ÚGatewayAuthorizationMixin)ÚGatewayKanbanWatchersMixin)ÚGatewaySlashCommandsMixin)ÚGatewayVoiceMixin)ÚGatewayAdapterLifecycleMixin)ÚGatewayTopicThreadsMixin)ÚGatewayTurnMixinÚ"is_context_overflow_failure_result)ÚGatewayShutdownMixinÚ_resolve_gateway_exit_verdict)ÚGatewayBusySessionMixin)ÚGatewayConfigLoadersMixin)ÚGatewayStartupMixinÚ_own_policy_envs)ÚGatewaySessionWatchersMixin)ÚGatewayNotificationsMixin)ÚGatewayInboundMixin)ÚGatewayGoalsMixin)ÚGatewayAgentCacheMixin)ÚGatewayProfileReconcileMixin)ÚGatewayPluginRewireMixin)rø  Ú_reply_anchor_for_eventr—  )ÚMessageEventÚMessageType)Ú"DEFAULT_GATEWAY_CRON_DRAIN_TIMEOUTÚ*DEFAULT_GATEWAY_RESTART_AFTER_TURN_TIMEOUTÚ%DEFAULT_GATEWAY_RESTART_DRAIN_TIMEOUTÚ.DEFAULT_GATEWAY_SIGNAL_INTERRUPT_GRACE_TIMEOUTc                ól   € V ^8„  d   QhR\         . \        3,          R\        \        ,          R\        /# )r?   ÚfnÚ	debug_msgrB   )r	   r   r   rD   )rF   s   "r;   rG   rG   ¯  s.   € ÷ ñ ”X˜b¤#˜gÕ&ð ´8¼Cµ=ð ÌCñ r=   c                ó~   €  V ! 4       #   \          d)   pT'       d   \        P                  Y4        Rp?R# Rp?ii ; i)z[Call ``fn``; return None on any Exception (debug-logged via ``debug_msg`` ``%s`` if given).N©rL   rM   rN   )rÁ  rÂ  rY   s   && r;   Ú_best_effortrÅ  ¯  s0   € ðÙ‹tˆøÜô ßÜ�L‰L˜Ô(Ýûðús   ‚	 ‰<”7·<g       @c                ó:   € V ^8„  d   QhR\         \        ,          /# rÖ   ©r   rD   )rF   s   "r;   rG   rG   ¾  s   € ÷ ñ ´(¼3µ-ñ r=   c                óŒ  € \        \        4      ;_uu_ 4        ^ RIHp V! 4        RRR4       \	        V R/ 4      P                  4        EFb  w  r#\	        VRR4      '       g   K  \        V4      pV'       g   K0  Vw  rVp\	        VRR4      ;'       g    / p\        VP                  R4      ;'       g    V'       d   \        VR4      MR4      P                  4       P                  4       p	\        VP                  R	4      ;'       g    V'       d   \        VR4      MR4      P                  4       P                  4       p
V	R
8w  d   V
R
8w  d   EK  \        RR4      P                  4       R9   pV'       g(   V'       d#   \        VR4      P                  4       R9   d   EKT  VP                   R2u # 	  R#   + '       g   i     EL•; i)zFReturn a startup-abort reason when open policy lacks allow-all opt-in.)Údiscover_pluginsNrÐ  r†  Frp  Ú	dm_policyÚpairingÚgroup_policyÚopenÚGATEWAY_ALLOW_ALL_USERSr”   z&: open policy without allow-all opt-in>   rÛ   rÝ   rÞ   )r}   rL   r]  rÉ  r8   rž  r±  rD   r~   r˜  rá   r¢   r  )râ   rÉ  rç   rË  Úopen_envÚdm_envÚ	group_envÚallow_all_envrp  rÊ  rÌ  Úgateway_allow_alls   &           r;   Ú"_own_policy_open_startup_violationrÔ  ¾  st  € ä	”)×	Õ	Ý7ÙÔ÷ 
ô &-¨V°[À"Ó%E×%KÑ%K×%MÑ!ˆÜ�¨	°5×9Ò9ÙÜ# HÓ-ˆßÙØ+3Ñ(ˆ˜=Ü˜¨°$Ó7×=Ð=¸2ˆÜ˜Ÿ	™	 +Ó.÷ Qð Qß:@œG F¨IÔ6ÀióRßRWÑRWÓRY×Z_ÑZ_ÓZað 	äØ�I‰I�nÓ%×dÐdÏ9¬'°)¸YÔ*GÐZcó
ç
‰%‹'—%‘%“'ð 	ð ˜Ô <°6Ô#9ÚÜ#Ð$=¸rÓB×HÑHÓJÐNbÑbÐßß¤'¨-¸Ó"<×"BÑ"BÓ"DÐH\Ô"\ÚØ—.‘.Ð!Ð!GÐHÒHñ' &Nñ( ÷/ 
×	Ð	ús   ˜F2Æ2G	c                ó$   € V ^8„  d   QhR\         /# rÖ   r&  )rF   s   "r;   rG   rG   ü  s   € ÷ "Lñ "L¤tñ "Lr=   c                 óH  € ^ RI Hp HpHp V! 4       pVP	                  R4      ;'       g    RP                  4       pVP	                  R4      ;'       g    RP                  4       p V ! \        4       4      w  rgTeq   / \        T4      CRTR,          R\        YTTP	                  R4      ;'       g    TP	                  R4      ;'       g    RTP	                  R4      ;'       g    R4      /C# TP	                  R	4      p	\        T	\        4      '       dU   T	P                  4        U
Uu/ uF7  w  r«\        T
\        4      '       g   K  \        T\        4      '       g   K5  Y«bK9  	  upp
M/ p	/ \        T4      CR	T	/C#   \         d   p\        T! T4      4      ThRp?ii ; iu upp
i )
aP  Resolve provider credentials for gateway-created AIAgent instances.
``resolve_runtime_provider()`` may fall back to env vars; behavioral config is config.yaml only.
An ``AuthError`` from the primary walks the configured fallback chain through the shared
``resolve_runtime_with_fallback`` (the gateway keeps no resolver loop of its own).)Úresolve_runtime_with_fallbackÚformat_runtime_provider_errorÚ_get_model_configr•   r”   rV  Nr  Ú_fallback_noticerø   Úcapabilities)Úhermes_cli.runtime_providerr×  rØ  rÙ  r~   rá   rß   rL   ÚRuntimeErrorÚ_runtime_agent_kwargsr-   r   rà   rž  rD   rm   )r×  rØ  rÙ  Ú
_model_cfgÚ_primary_modelÚ_primary_providerÚruntimeÚfallback_entryrY   rÛ  r©  r  s               r;   Ú_resolve_runtime_agent_kwargsrä  ü  s�  € ÷
Yñ Yñ
 #Ó$€JØ —n‘n YÓ/×5Ð5°2×<Ñ<Ó>€NØ#Ÿ™¨
Ó3×9Ð9°r×@Ñ@ÓBÐðHÙ"?Ô@TÓ@VÓ"WÑˆð Ò!ð?Ô'¨Ó0ð ?°'¸>È'Õ;RØ"Ô$=Ø%Ø—K‘K 
Ó+×ZÐZ¨~×/AÑ/AÀ*Ó/M×ZÐZÐQZØ"×&Ñ& wÓ/×<Ð<°9ó%>ñ?ð 	?ð —;‘;˜~Ó.€Lô �l¤D×)Ò)ð '×,Ñ,Ô.Ô]Ñ.‘$�!´*¸QÄ×2DŒÌÐTUÔW[×I\ŒˆŠÑ.Ó]Ø/1ð ð LÔ# GÓ,ÐK¨n¸lÑKÐKøô% ô HÜÑ8¸Ó=Ó>ÀCÐGûðHüó 	^s*   Á%E9 Ä%FÅFÅFÅ9FÆFÆFc                ó0   € V ^8„  d   QhR\         R\         /# )r?   râ  rB   r&  )rF   s   "r;   rG   rG   !	  s   € ÷ ?ñ ?¤4ð ?¬Dñ ?r=   c                ó^  € RV P                  R4      RV P                  R4      RV P                  R4      RV P                  R4      RV P                  R4      RV P                  R4      R\        V P                  R4      ;'       g    . 4      RV P                  R4      R	V P                  R	4      /	# )
zªAIAgent constructor kwargs shared by every runtime-provider resolution.
``request_overrides`` passes through as resolved so the provider's request body reaches each turn.rÔ  rZ  rV  Úrequested_providerÚapi_modera  ÚargsÚcredential_poolÚrequest_overrides)r~   rŒ   )râ  s   &r;   rÞ  rÞ  !	  sœ   € ð 	�7—;‘;˜yÓ)Ø�G—K‘K 
Ó+Ø�G—K‘K 
Ó+Ø˜gŸk™kÐ*>Ó?Ø�G—K‘K 
Ó+Ø�7—;‘;˜yÓ)Ø”�W—[‘[ Ó(×.Ð.¨BÓ/Ø˜7Ÿ;™;Ð'8Ó9Ø˜WŸ[™[Ð)<Ó=ð	?ð 	?r=   )Úfrozenc                   ó0   a € ] tR tRt o RtV 3R ltRtV tR# )Ú_GatewayModelContexti0	  z<Effective gateway model route and context-window resolution.c                óV   <€ V ^8„  d   Qh/ S[ ;R&   S[ ;R&   S[ ;R&   S[;R&   S[ ;R&   # )r?   r  rV  rZ  r  r   ©rD   rQ   )rF   Ú__classdict__s   "€r;   rG   Ú!_GatewayModelContext.__annotate__0	  sC   ø‡ ‚ ñ �Jñ	 ñ
 �Mñ ñ �Mñ ñ Ññ ñ Ñò r=   rº   N©r6  rD  rE  rF  rG  Ú__annotate_func__rH  Ú__classdictcell__©rñ  s   @r;   rî  rî  0	  s   ø‡ € áF÷ ƒ r=   rî  c                óh   € V ^8„  d   QhR\         \        ,          R\         \        ,          R\        /# )r?   r  ÚrouterB   )r   rD   rà   rî  )rF   s   "r;   rG   rG   ;	  s6   € ÷ QFñ QFÜ”C�=ðQFÜ(0´­ðQFäñQFr=   c           	     ó¨  aaaaaaaaaa€ ^ RI HpHpHpHp T ;'       g    \        4       oR;o;o;o;ooR;o;ooR VVVVVVV3R llpR VVVV3R llpR VVVVVV3R llpR	 VVV3R
 llp	\        V4       \        V4       Se   \        V4      '       g   RoSf&   S'       d   S'       d   \        V	4      ;'       g    RoT! SS;'       g    RS;'       g    RSS;'       g    RSR7      p
W£8H  ;'       d#    V! V\        S4      P                  4       4      RJ pSe   RMV'       d   RMRp\        SS;'       g    RS;'       g    RW¬R7      # )u6  Resolve the configured gateway route and effective context window. Call off-loop (may block).

``route`` (``provider`` / ``base_url`` / ``api_key`` of a session-only /model switch) replaces the
default runtime credentials so the window is looked up against the endpoint that actually serves
``model``; a ``model.context_length`` pin only survives when that route still matches the config.
``context_source`` is ``"default"`` only for a model unknown to the catalog that fell through to
``DEFAULT_FALLBACK_CONTEXT`` â€” a catalog-listed 256K model is ``"detected"``.
)ÚDEFAULT_CONTEXT_LENGTHSÚDEFAULT_FALLBACK_CONTEXTÚ_longest_key_matchÚget_model_context_lengthNc                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   Ú4_resolve_gateway_model_context.<locals>.__annotate__L	  s   € ÷ <ñ <˜$ñ <r=   c                  ó\  <€ \        4       p V '       g   R # V P                  R/ 4      p\        V\        4      '       dª   VP                  R4      ;'       g    VP                  R4      oVP                  R4      pVe1   \	        \
        \        4      ;_uu_ 4        \        V4      oR R R 4       VP                  R4      ;'       g    R ;oo
VP                  R4      ;'       g    R ;oo ^ RIH	p V! V 4      o	R #   + '       g   i     L[; i  \         d    T P                  R4      o	 R # i ; i)Nr  r•   r  rV  rZ  )Úget_compatible_custom_providersÚcustom_providers)rß   r~   r   rà   r}   r/  rô  rQ   r  r  rL   )ÚdataÚ	model_cfgÚraw_ctxr  rZ  Úconfig_context_lengthÚconfigured_base_urlÚconfigured_modelÚconfigured_providerr  rV  s       €€€€€€€r;   Ú_read_configÚ4_resolve_gateway_model_context.<locals>._read_configL	  sõ   ø€ ô $Ó%ˆßÙØ—H‘H˜W bÓ)ˆ	Ü�i¤×&Ò&Ø(Ÿ}™}¨YÓ7×QÐQ¸9¿=¹=ÈÓ;QÐØ—m‘mÐ$4Ó5ˆGØÒ"Üœi¬×4Õ4Ü,/°«LÐ)÷ 5à-6¯]©]¸:Ó-F×-NÐ-NÈ$ÐNÐ (Ø-6¯]©]¸:Ó-F×-NÐ-NÈ$ÐNÐ (ð	<ÝIÙ>¸tÓDÒ÷ 5×4ûô ô 	<Ø#Ÿx™xÐ(:Ó;Óð	<ús   ÂC8Ã(D Ã8D	ÄD+Ä*D+c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rÿ  a	  s   € ÷ )ñ )˜4ñ )r=   c                  óV  <€ S'       dO   SP                  R 4      '       d8   SP                  R4      ;'       g    SoSR ,          oSP                  R4      oR# \        4       p V P                  R4      ;'       g    SoV P                  R 4      ;'       g    SoV P                  R4      oR# )rZ  rV  rÔ  N)r~   rä  )râ  rÔ  rZ  rV  rø  s    €€€€r;   Ú_read_runtimeÚ5_resolve_gateway_model_context.<locals>._read_runtimea	  s‰   ø€ ç�U—Y‘Y˜z×*Ò*ð —y‘y Ó,×8Ð8°ˆHØ˜ZÕ(ˆHØ—i‘i 	Ó*ˆGÙÜ/Ó1ˆØ—;‘;˜zÓ*×6Ð6¨hˆØ—;‘;˜zÓ*×6Ð6¨hˆØ—+‘+˜iÓ(Šr=   c                ó$   € V ^8„  d   QhR\         /# rÖ   r×   )rF   s   "r;   rG   rÿ  p	  s   € ÷ lñ l¤ñ lr=   c                  ó4   <€ ^ RI Hp  V ! SSSSSS4      '       * # )é    )Úshould_clear_context_pin)Úhermes_cli.route_identityr  )r  rZ  r  r  r	  rV  Úresolved_models    €€€€€€r;   Ú_pin_still_appliesÚ:_resolve_gateway_model_context.<locals>._pin_still_appliesp	  s+   ø€ åFÙ+Ø˜nÐ.AÀ8ÐM`Ðbjólô lð 	lr=   c                ó:   € V ^8„  d   QhR\         \        ,          /# rÖ   )r   rQ   )rF   s   "r;   rG   rÿ  v	  s   € ÷ Xñ Xœ¤#�ñ Xr=   c                  ó&   <€ ^ RI Hp  V ! SSSR7      # )r  )Ú"get_custom_provider_context_length)r  rZ  r  )r  r  )r  rZ  r  r  s    €€€r;   Ú_custom_ctxÚ3_resolve_gateway_model_context.<locals>._custom_ctxv	  s   ø€ ÝHÙ1Ø ¨8ÐFVôXð 	Xr=   r”   )rZ  rÔ  r  rV  r  râ   r•   Údetected)r  rV  rZ  r  r   )
Úagent.model_metadatarú  rû  rü  rý  Ú_resolve_gateway_modelrÅ  rD   r¢   rî  )r  rø  rú  rû  rü  rý  r
  r  r  r  r  Úfell_throughr   rÔ  rZ  r  r  r  r	  r  rV  r  s   &f           @@@@@@@@@r;   r  r  ;	  s]  ÿù€ ÷ió ià×6Ð6Ô4Ó6€NØOSÐSÐÐS˜HÐS xÐS°'Ð<LØCGÐGÐÐGÐ*Ð-@÷<ö <÷*)ó )÷lõ l÷Xò Xô
 �ÔÜ�ÔØÒ(´Ð>P×1QÒ1QØ $ÐØÒ$×)9¿hÜ ,¨[Ó 9× AÐ A¸TÐá-Ø § ¨R¸¿¸ÀBØ3¸h¿n¸nÈ"Ø)ô+€Nð #Ñ>÷ ið iÙ*Ð+BÄCÈÓDW×D]ÑD]ÓD_Ó`ÐdhÐhð à"7Ò"C‘hß(4™9¸*ð äØ x§~ ~°2ÀÇÀÈBØ%ôFð Fr=   c                óR   € V ^8„  d   QhR\         R\        \         ,          R\        /# )r?   rV  Útarget_modelrB   )rD   r   rà   )rF   s   "r;   rG   rG   �	  s,   € ÷ Añ A¼ð AÌHÔUXÍMð AÔeiñ Ar=   c           	     ó2  € ^ RI HpHp  T! Y;'       g    RR7      p/ \        T4      CR\        TP                  R4      ;'       g    / 4      R\        TP                  R4      ;'       g    / 4      /C#   \         d   p\	        T! T4      4      ThRp?ii ; i)aQ  Resolve runtime credentials for a specific provider (e.g. from channel override).

``target_model`` is the model the override will actually send: the ladder's model-keyed rungs
(Zen/Go relay + api_mode) must see it rather than config's ``default``, or a Go-only override
resolves an api_mode/base_url the sent model cannot use (#112600).)Úresolve_runtime_providerrØ  N)Ú	requestedr"  rë  rÛ  )rÜ  r$  rØ  rL   rÝ  rÞ  rà   r~   )rV  r"  r$  rØ  râ  rY   s   &&    r;   Ú*_resolve_runtime_agent_kwargs_for_providerr&  �	  sŸ   € ÷ dðHÙ*°X×L`ÐL`Ð\`ÔaˆðAÜ
 Ó
(ðAàœT '§+¡+Ð.AÓ"B×"HÐ"HÀbÓIØœ˜WŸ[™[¨Ó8×>Ð>¸BÓ?ñAð Aøô ô HÜÑ8¸Ó=Ó>ÀCÐGûðHús   Š
A4 •A4 Á4BÁ?BÂBc                óh   € V ^8„  d   QhR\         \        ,          R\         \        ,          R\        /# )r?   Úbaser=  rB   )r   rà   )rF   s   "r;   rG   rG    	  s*   € ÷ 	1ñ 	1¬´­ð 	1Ä(Ì4Å.ð 	1ÔUYñ 	1r=   c                óš   € ^ RI Hp \        T ;'       g    / 4      p\        T;'       g    / 4      pV'       g   V# V'       g   V# V! W44      # )z@Merge request_overrides dicts, deep-merging nested dictionaries.)Ú_deep_merge)r  r*  rà   )r(  r=  r*  Ú	base_dictÚoverride_dicts   &&   r;   Ú_deep_merge_request_overridesr-   	  sB   € å-Ü�T—Z�Z˜RÓ €IÜ˜Ÿ˜ RÓ(€MßØÐßØÐÙ�yÓ0Ð0r=   c                ó:   € V ^8„  d   QhR\         \        ,          /# )r?   rV  rÇ  )rF   s   "r;   rG   rG   ¬	  s   € ÷ ñ ¬H´S­Mñ r=   c                ó  € V '       d    \        V 4      P                  4       '       g   R#  \        \        V 4      P                  4       4      P                  R4      #   \         d    \
        P                  RT RR7        R# i ; i)zJReturn the live credential pool for a provider id (e.g. ``custom:hyper``).Nrê  z1Failed to resolve credential pool for provider=%sTrG  )rD   rá   r&  r~   rL   rM   rN   )rV  s   &r;   Ú_credential_pool_for_providerr0  ¬	  si   € çœ3˜x›=×.Ñ.×0Ò0ÙðÜ9¼#¸h»-×:MÑ:MÓ:OÓP×TÑTÐUfÓgÐgøÜô Ü�‰ÐHÈ(Ð]aˆÔbÚðús   «0A Á#BÂBc                ó0   € V ^8„  d   QhR\         R\        /# ©r?   ÚindexrB   )rQ   rD   )rF   s   "r;   rG   rG   ·	  s   € ÷ Bñ B¤sð B¬sñ Br=   c                ód   € \        V RR4      ;'       g    . pV\        V4      8  d	   W!,          # R# )zRPer-attachment MIME at *index*; "" when the adapter set only a message-level type.Úmedia_typesNr”   )r8   rU   )Úeventr3  r5  s   && r;   Ú_event_media_type_atr7  ·	  s2   € ä˜% °Ó5×;Ð;¸€KØ!&¬¨[Ó)9Ô!9ˆ;ÕÐA¸rÐAr=   c                óH   € V ^8„  d   QhR\         R\        R\        R\        /# )r?   r3  Úmime_prefixÚfallback_typesrB   )rQ   rD   Ú	frozensetrm   )rF   s   "r;   rG   rG   ½	  s/   € ÷ Bñ B¤sð B¼ð BÌið BÔ\`ñ Br=   c                ój   € \        W4      pV'       d   VP                  V4      # \        V RR4      V9   # )zšPer-attachment MIME first, message-level type only when unknown (else a document uploaded
alongside an image is base64'd as vision and the provider 400s).Úmessage_typeN)r7  r™  r8   )r6  r3  r9  r:  Úmtypes   &&&& r;   Ú_event_media_kind_isr?  ½	  s6   € ô ! Ó.€EßØ×Ñ Ó,Ð,Ü�5˜.¨$Ó/°>ÑAÐAr=   c                ó0   € V ^8„  d   QhR\         R\        /# r2  ©rQ   rm   )rF   s   "r;   rG   rG   Æ	  ó   € ÷ Xñ X¬ð X´ñ Xr=   c                 óL   € \        WR \        \        P                  04      4      # )zimage/)r?  r;  r»  ÚPHOTO©r6  r3  s   &&r;   Ú_event_media_is_imagerF  Æ	  ó   € Ü ¨h¼	Ä;×CTÑCTÐBUÓ8VÓWÐWr=   c                ó0   € V ^8„  d   QhR\         R\        /# r2  rA  )rF   s   "r;   rG   rG   Ê	  s   € ÷ kñ k¬ð k´ñ kr=   c           	      ój   € \        WR \        \        P                  \        P                  04      4      # )úaudio/)r?  r;  r»  ÚVOICEÚAUDIOrE  s   &&r;   Ú_event_media_is_audiorM  Ê	  s(   € Ü ¨h¼	Ä;×CTÑCTÔVa×VgÑVgÐBhÓ8iÓjÐjr=   c                ó0   € V ^8„  d   QhR\         R\        /# r2  rA  )rF   s   "r;   rG   rG   Î	  s   € ÷ hñ h¬Cð h´Dñ hr=   c                óÔ   € \        V RR4      pV\        P                  \        P                  09   d   R# V\        P                  8H  ;'       g    \        W4      P                  R4      # )zFTrue when an audio attachment should enter the automatic STT pipeline.r=  NFrJ  )r8   r»  rL  ÚDOCUMENTrK  r7  r™  )r6  r3  r=  s   && r;   Ú_event_media_is_stt_inputrQ  Î	  sW   € ä˜5 .°$Ó7€LØœ×)Ñ)¬;×+?Ñ+?Ð@Ô@ÙØœ;×,Ñ,Ñ,×gÐgÔ0DÀUÓ0R×0]Ñ0]Ð^fÓ0gÐgr=   c                ó0   € V ^8„  d   QhR\         R\        /# r2  rA  )rF   s   "r;   rG   rG   Ö	  rB  r=   c                 óL   € \        WR \        \        P                  04      4      # )zvideo/)r?  r;  r»  ÚVIDEOrE  s   &&r;   Ú_event_media_is_videorU  Ö	  rG  r=   c                ó$   € V ^8„  d   QhR\         /# rÖ   r_   )rF   s   "r;   rG   rG   Ú	  s   € ÷ ñ ¤sñ r=   c                ó˜  € . p\        V RR4      ;'       g    . p\        V4       F’  w  r4\        W4      '       d   VP                  RV R24       K-  \	        W4      '       d   VP                  RV R24       KU  \        W4      '       d   VP                  RV R24       K}  VP                  RV R24       K”  	  RP                  V4      # )	z§Text placeholder for media-only events (later replaced by vision enrichment).
Queued media is dequeued via .text only, so a caption-less event would otherwise be lost.Ú
media_urlsNz[User sent an image: rG  z[User sent audio: z[User sent a video: z[User sent a file: rŽ  )r8   Ú	enumeraterF  rs  rM  rU  rÏ   )r6  rÐ   rX  r‹  Úurls   &    r;   Ú_build_media_placeholderr[  Ú	  sº   € ð €EÜ˜ ¨dÓ3×9Ð9°r€JÜ˜JÖ'‰ˆÜ  ×*Ò*Ø�L‰LÐ0°°°QÐ7Ö8Ü" 5×,Ò,Ø�L‰LÐ-¨c¨U°!Ð4Ö5Ü" 5×,Ò,Ø�L‰LÐ/°¨u°AÐ6Ö7à�L‰LÐ.¨s¨e°1Ð5Ö6ñ (ð �9‰9�UÓÐr=   Úcontent_inlinedc          
      óT   € V ^8„  d   QhR\         R\         R\         R\        R\         /# )r?   Údisplay_nameÚ
agent_pathr>  r\  rB   rd  )rF   s   "r;   rG   rG   ë	  s4   € ÷ 7ñ 7Üð7Ü#&ð7Ü/2ð7ÜHLð7ÜX[ñ7r=   c               ó¤   € VP                  R4      '       d   V'       d
   RV  RV R2# VP                  R4      '       d
   RV  RV R2# RV  RV R2# )	zÚContext note prepended to a user turn when they attach a document.
``content_inlined=False`` = cached without content, so tell the agent to read it. Binary docs must
say *extract* the text; "ask the user" made it punt.ztext/z![The user sent a text document: 'zC'. Its content has been included below. The file is also saved at: rG  z'. It is saved at: z�. Its content is not inlined here. Read the cached file yourself before answering when the user's request involves its contents.]z[The user sent a document: 'u
  . Its text is not inlined here (it's a binary format such as PDF or DOCX). To read it, extract the document's text yourself â€” for example with the terminal tool or the ocr-and-documents skill â€” before answering, instead of asking the user to paste the contents.])r™  )r^  r_  r>  r\  s   &&&$r;   Ú_build_document_context_notera  ë	  sˆ   € ð
 ×Ñ˜× Ò §_à/°¨~ð >*Ø*4¨°Qð8ð	9ð ×Ñ˜× Ò à/°¨~Ð=PÐQ[ÐP\ð ]>ð ?ð	@ð
 ' | nÐ4GÈ
À|ð T5ð 	6ð7r=   c                ó0   € V ^8„  d   QhR\         R\        /# )r?   r�  rB   r²  )rF   s   "r;   rG   rG   
  s   € ÷ #ñ #œeð #¬ñ #r=   c                 óœ   € \        ^ \        V 4      4      p\        VR4      w  r#\        V^<4      w  rEV'       d   V RVR RVR 2# V RVR 2# )r  é  r{  Ú02d)rP   ÚroundÚdivmod)r�  ÚtotalÚhoursÚremÚminutesÚsecss   &     r;   Ú_format_durationrm  
  s^   € Ü�”5˜“>Ó"€EÜ˜˜tÓ$�J€EÜ˜3 “O�M€GßØ�˜˜' #˜ a¨¨S zÐ2Ð2ØˆY�a˜˜S�zÐ"Ð"r=   c                óF   € V ^8„  d   QhR\         R\        \         ,          /# ©r?   r  rB   ©rD   r   )rF   s   "r;   rG   rG   

  s   € ÷ !ñ !¤cð !¬h´s­mñ !r=   c              ƒ  ój  a "  € \         P                  P                  S 4      ^,          P                  4       pVR8X  d2    R V 3R llp\	        \
        P                  ! V4      G Rj  x€L
 4      # VR9   d2    R V 3R llp\	        \
        P                  ! V4      G Rj  x€L
 4      #  \
        P                  ! RRR	R
RRRS \
        P                  P                  \
        P                  P                  R7
      G Rj  x€L
 p\
        P                  ! VP                  4       RR7      G Rj  x€L
 w  rVVP                  ^ 8X  d1   \	        \        VP                  4       P!                  4       4      4      #  R#  EL  \         d     ELi ; i Lê  \         d     Lñi ; i L  Lt  \         d     R# i ; i5i)zSBest-effort duration probe. Returns formatted MM:SS / HH:MM:SS, or None on failure.z.wavc                ó$   € V ^8„  d   QhR\         /# rÖ   rù  )rF   s   "r;   rG   Ú+_probe_audio_duration.<locals>.__annotate__
  s   € ÷ 0ñ 0¤5ñ 0r=   c                  óö   <€ ^ RI p V P                  SR4      ;_uu_ 4       pVP                  4       pVP                  4       ;'       g    ^pV\	        V4      ,          uuRRR4       #   + '       g   i     R# ; i)r  NÚrb)ÚwaverÍ  Ú
getnframesÚgetframeraterE   )rv  ÚwfÚframesÚrater  s       €r;   Ú_wav_durationÚ,_probe_audio_duration.<locals>._wav_duration
  sS   ø€ ÛØ—Y‘Y˜t T×*Ô*¨bØŸ]™]›_�FØŸ?™?Ó,×1Ð1°�DØ!¤E¨$£KÕ/÷ +×*×*Ó*ús    <A'Á'A8	Nc                ó$   € V ^8„  d   QhR\         /# rÖ   rù  )rF   s   "r;   rG   rs  
  s   € ÷ 8ñ 8¤5ñ 8r=   c                  óZ   <€ ^ RI Hp  \        V ! S4      P                  P                  4      # )r  )ÚOggOpus)Úmutagen.oggopusr€  rE   r  Úlength)r€  r  s    €r;   Ú_ogg_durationÚ,_probe_audio_duration.<locals>._ogg_duration
  s!   ø€ Ý3Ü™W T›]×/Ñ/×6Ñ6Ó7Ð7r=   Úffprobeú-vr¾   z-show_entrieszformat=durationz-ofz"default=noprint_wrappers=1:nokey=1)ÚstdoutÚstderrr1   rž   )z.oggz.opusz.oga)rþ   r  Úsplitextr¢   rm  r¤   r³  rL   Úcreate_subprocess_execÚ
subprocessÚPIPEr¨   ÚcommunicateÚ
returncoderE   Údecoderá   )r  Úextr|  rƒ  Úprocr‡  rû  s   f      r;   Ú_probe_audio_durationr’  

  s„  øé € ä
�'‰'×
Ñ
˜4Ó
  Õ
#×
)Ñ
)Ó
+€CØ
ˆf„}ð		÷0ð 0ô $¬'×*;Ò*;¸MÓ*J×$JÓKÐKð Ð'Ô'ð	÷8ð 8ô $¬'×*;Ò*;¸MÓ*J×$JÓKÐKð	Ü×3Ò3Ø�t˜W oÐ7HØÐ7¸Ü×%Ñ%×*Ñ*´7×3EÑ3E×3JÑ3JôL÷ Lˆô "×*Ò*¨4×+;Ñ+;Ó+=ÀsÔK×K‰	ˆØ�?‰?˜aÔÜ#¤E¨&¯-©-«/×*?Ñ*?Ó*AÓ$BÓCÐCð  ñ
 ò- %KøÜô 	Úð	úñ %KøÜô 	Ùð	úñLñ Løô ô Øáðüs»   ƒ<F3Á 'E8 Á'E5Á(E8 Á/F3Á8'F ÂF
Â F Â'F3Â)AF! Ã<FÃ=-F! Ä*FÄ+AF! Å1F3Å5E8 Å8FÆF3ÆFÆF3Æ
F ÆFÆF3ÆFÆF3ÆF! ÆF! Æ!F0Æ,F3Æ/F0Æ0F3c                ó>   € V ^8„  d   QhR\         R\        R,          /# r^   )rD   rº  )rF   s   "r;   rG   rG   .
  s   € ÷ 4ñ 4´ð 4¼ÈÕ9Lñ 4r=   c                ó$   € V P                  V4      # )zgConsume and return the pending event; media metadata is kept so follow-ups re-enter preprocessing.
    )Úget_pending_message)r«  r@   s   &&r;   Ú_dequeue_pending_eventr–  .
  s   € ð ×&Ñ& {Ó3Ð3r=   zStop requestedzSession reset requestedz Execution timed out (inactivity)zgateway inactivity watchdogz(Session ended while the turn was runningzsession evictedzgateway shutdownzSSE client disconnectedzGateway shutting downzGateway restartingÚis_still_currentc          	      óx   € V ^8„  d   QhR\         R\         R\        \        . \        3,          ,          R\        /# )r?   r–   Úsourcer—  rB   )rD   r   r	   rm   rQ   )rF   s   "r;   rG   rG   B
  s:   € ÷ !ñ !Üð!Ü/2ð!äœx¨¬D¨Õ1Õ2ð!ä>Añ!r=   c               óˆ  € V '       g   ^ # Ve(    V! 4       '       g   \         P                  RW4       ^ #  ^ RIHp  VP                  WVR7      pT'       d   \         P                  RYPT4       T#   \         d    \         P                  RYRR7        L`i ; i  \         d    \         P                  RYRR7        ^ # i ; i)	zûReap only background processes created by one abandoned turn.
``task_id`` is session-scoped, so a *replacement* turn can spawn its own process mid-reap;
``is_still_current`` lets the caller bail instead of killing it (that turn owns its own baseline).zdSkipping reap for turn %s (%s): a newer turn already claimed this session; it owns its own baseline.z>is_still_current check failed for turn %s (%s); reaping anywayTrG  )Úprocess_registry)r™  z4Failed to reap background processes for turn %s (%s)zBReaped %d background process(es) created by abandoned turn %s (%s))rM   rN   rL   Útools.process_registryr›  Úkill_started_sincer¬   )r–   Úprocess_baseliner™  r—  r›  Úkilleds   &&$$  r;   Ú_reap_gateway_turn_processesr   B
  sÕ   € ÷ áØÒ#ð		0Ù#×%Ò%Ü—‘ðFØGNôXñ ð	 &õ 8ðØ!×4Ñ4°WÐW]Ð4Ó^ˆ÷ Ü�‰ØPØ˜Vô	%ð €Møô# ô 	0Ü�L‰LØPØ¨$ð ö 0ð	0ûô ô ä�‰ØBÀGÐ^bð 	ô 	dâð	ús'   �A1 �A1 ½B Á1#BÂBÂ#CÃ Cc                ó(   € V ^8„  d   QhR\         RR/# )r?   r–   rB   Nr_   )rF   s   "r;   rG   rG   k
  s   € ÷ Eñ E¤cð E¨dñ Er=   c                óR  a€  \         P                  ! 4       p\        P                  ! 4        Uu/ uF  q"P                  VP
                  bK  	  pp^ pVP                  4        Fô  w  rVV\        P                  ! 4       8X  d   K!  \        P                  ! V4      pRP                  V4      o\        ;QJ d#    V3R l\         4       F  '       g   K   RM	  RM! V3R l\         4       4      '       g   K’  V^,          pV^8”  d   \        P                  RV 4        M>\        P                  RWP                  VR4      VRP                  VRR 4      4       Kö  	  V^ 8X  d   \        P                  R	V 4       R# R# u upi   \          d    \        P#                  R
RR7        R# i ; i)zóLog the stack of every thread that looks like turn work, at reap time.
The hard interrupt frees the wedged worker before a profiler can attach, so dump BEFORE it.
Best-effort, bounded (turn-machinery threads only, capped output), never raises.r”   c              3   ó,   <"  € T F	  qS9   x € K  	  R # 5irÇ   rº   )rÊ   ÚmarkerÚjoineds   & €r;   rÌ   Ú+_dump_wedged_turn_stacks.<locals>.<genexpr>x
  s   øé € ÐUÑ6T¨F Ö'Ó6Tùs   ƒTFzKWedged-turn stack dump for task %s truncated: more than 8 candidate threadsz7Wedged-turn stack dump (task=%s thread=%s ident=%s):
%sÚ?NzoWedged-turn stack dump for task %s: no thread with turn-machinery frames found (worker may have already exited)zWedged-turn stack dump failedrG  içÿÿÿ)rù   Ú_current_framesÚ	threadingrY  r<  r-  rž  Ú	get_identÚ	tracebackÚformat_stackrÏ   r»  Ú_TURN_STACK_DUMP_FRAME_MARKERSrM   r¾   r~   rL   rN   )	r–   rz  r   ÚnamesÚdumpedr<  ÚframeÚstackr¥  s	   &       @r;   Ú_dump_wedged_turn_stacksr²  k
  sT  ø€ ðEÜ×$Ò$Ó&ˆÜ*3×*=Ò*=Ô*?Ó@Ñ*? Q—‘˜!Ÿ&™&’Ñ*?ˆÐ@ØˆØ"ŸL™LžN‰LˆEØœ	×+Ò+Ó-Ô-ÙÜ×*Ò*¨5Ó1ˆEØ—W‘W˜U“^ˆFß“3ÔUÕ6TÓU—3—3’3ÔUÕ6TÓU×UÒUÙØ�a�KˆFØ˜ŒzÜ—‘ØaØôñ Ü�L‰LØJØŸ™ 5¨#Ó.°°r·w±w¸uÀSÀT¸{Ó7KöMñ +ð  �QŒ;Ü�L‰LðOØPWöYñ ùò% Aøô, ô EÜ�‰Ð4¸tˆ×DðEús6   ƒ,F  ¯E;ÁA&F  Â5F  Ã!F  Ã2BF  Å;F  Æ "F&Æ%F&c                óÌ   € V ^8„  d   QhR\         R\        P                  R\        P                  R\        P                  R\        \
        . \        3,          ,          R\        /# )r?   r–   Úworker_doneÚtimeout_firedÚcleanup_lockr—  rB   )rD   r©  ÚEventÚLockr   r	   rm   )rF   s   "r;   rG   rG   ‹
  s[   € ÷ ñ Ü!ðÜBKÇ/Á/ðä—?‘?ðä2;·.±.ðô œx¨¬D¨Õ1Õ2ðô ?Cñr=   c                ó0  € T;_uu_ 4        VP                  4       '       g   VP                  4       '       d    RRR4       R# VP                  4        RRR4       \        V4       V '       d
   V ^ ,          MRpVe&    \        V\        \
        R7       ^ RI	H
p V! V4        \        WRVR	7       R#   + '       g   i     Lh; i  \         d    \        P                  RRR7        LVi ; i  \         d    \        P                  R
TRR7        R# i ; i)z@Interrupt one timed-out turn and reap only processes it created.NF)Útool_reasonz Timed-out agent interrupt failedTrG  )Úrecord_watchdog_turn_abortÚgateway_turn_timeout)r™  r—  z9Failed to reap background processes for timed-out turn %s)Úis_setr   r²  r!   Ú_INTERRUPT_REASON_TIMEOUTÚ_INTERRUPT_TOOL_REASON_TIMEOUTrL   rM   rN   Ú/hermes_cli.observability.shared_metrics_processr»  r   r¬   )	Úagent_holderr–   rž  r´  rµ  r¶  r—  r™   r»  s	   $$$$$$$  r;   Ú_abandon_timed_out_gateway_turnrÂ  ‹
  sø   € ÷
 
ŠØ×Ñ×Ò =×#7Ñ#7×#9Ò#9Ø÷ 
‰ð 	×ÑÔ÷ 
ô ˜WÔ%ç+ˆL˜ŽO°€EØÒð	LÜ" 5Ô*CÔQoÕpõ 	_Ù" 5Ô)ðaÜ$ØÐ.DØ-õ	/ñ ÷1 
�ûô ô 	LÜ�L‰LÐ;ÀdˆLÖKð	Lûô ô aÜ�‰ØGÈÐ[_ð 	õ 	aáðaús:   ‹,B3¸B3ÁB3Á>C Â#C. Â3C	Ã"C+Ã*C+Ã.#DÄDÚpoll_intervalc                óÜ   € V ^8„  d   QhR\         R\        R\        P                  R\        P                  R\        P                  R\        R\
        \        . \        3,          ,          RR	/# )
r?   r–   rŸ   r´  rµ  r¶  rÃ  r—  rB   N)rD   rE   r©  r·  r¸  r   r	   rm   )rF   s   "r;   rG   rG   «
  sm   € ÷  ñ  Ü!ð Ü>Cð ÜR[×RaÑRað ä—?‘?ð ä2;·.±.ð äQVð ô œx¨¬D¨Õ1Õ2ð ð ?Cñ r=   c        	   
     ó  € \         P                  ! 4       p	\        4       p
VP                  \	        RV4      4      '       g±   \         P                  ! 4       pW¹,
          pV '       d
   V ^ ,          MRpVec   \        VR4      '       dQ    VP                  4       P                  R4      pVe-   V
P                  \	        R\        V4      4      4      pW¼,
          p	WÃ8  d   K¿  \        WVWEVVR7       R# R#   \         d     L)i ; i)a7  Thread watchdog that remains runnable when gateway asyncio is starved.

Until an agent publishes a usable activity snapshot, elapsed worker time is the
liveness clock.  Otherwise a provider hang before activity initialization can
retain the session turn lease forever because every watchdog poll just skips it.
g{®Gáz„?NÚget_activity_summaryÚseconds_since_activityç        )rÁ  r–   rž  r´  rµ  r¶  r—  )rÁ   Ú	monotonicr*   ÚwaitrP   rI  rÆ  r~   ÚmeasurerE   rL   rÂ  )rÁ  r–   rž  rŸ   r´  rµ  r¶  rÃ  r—  Úactivity_originÚ
awake_idler8  Úidle_secondsr™   Úreported_idles   $$$$$$$$$      r;   Ú_watch_gateway_turn_inactivityrÐ  «
  sî   € ô —n’nÓ&€OÜÓ!€JØ×Ñœs 4¨Ó7×8Ò8Ü�nŠnÓˆØÕ,ˆß#/�˜Q–°TˆØÒ¤¨Ð0F×!GÒ!GðØ %× :Ñ :Ó <× @Ñ @ÐAYÓ Z�Ø Ò,Ø#-×#5Ñ#5´c¸#¼uÀ]Ó?SÓ6TÓ#U�Lð '*Õ&8�Oð Ô!ÙÜ'Ø%ÐIYØ#È|Ø-õ	/ñ 	ñ) 9øô ô Ùðús   ÂAC3 Ã3DÄ Dc                óF   € V ^8„  d   QhR\         \        ,          R\        /# )r?   rŸ  rB   rB  )rF   s   "r;   rG   rG   Õ
  s"   € ÷ Yñ Y¬8´C­=ð Y¼Tñ Yr=   c                ó¬   € V '       g   R# RP                  \        V 4      P                  4       P                  4       4      P	                  4       \
        9   # )z?Return True when an interrupt message is internal control flow.FrF  )rÏ   rD   rá   rÎ   r¢   Ú_CONTROL_INTERRUPT_MESSAGES)rŸ  s   &r;   Ú_is_control_interrupt_messagerÔ  Õ
  s<   € çÙØ�8‰8”C˜“L×&Ñ&Ó(×.Ñ.Ó0Ó1×7Ñ7Ó9Ô=XÑXÐXr=   c                ó0   € V ^8„  d   QhR\         R\         /# )r?   ÚresponserB   r_   )rF   s   "r;   rG   rG   Ü
  s   € ÷ 	\ñ 	\¼#ð 	\Ì3ñ 	\r=   c                óˆ   € VP                  V 4      w  r#VP                  RR4      P                  RR4      P                  4       # )aÔ  Return the visible text portion of a response before direct send().
Only explicit ``MEDIA:`` attachments are stripped; bare paths/URLs stay visible. No broad regex after
``extract_media()``: it deliberately preserves protected code spans and unvalidated tags.

Queued follow-up resends only replay explicit ``MEDIA:`` attachments in this path. Keep bare local paths
and ordinary image URLs visible because the post-stream uploader intentionally ignores them (#20834).
rß  r”   z[[as_document]])rù  Úreplacerá   )rÖ  r«  rû  Úcleaneds   &&  r;   Ú+_strip_response_attachments_for_direct_sendrÚ  Ü
  s@   € ð ×&Ñ& xÓ0�J€AØ�?‰?Ð/°Ó4×<Ñ<Ð=NÐPRÓS×YÑYÓ[Ð[r=   c                ón   € V ^8„  d   QhR\         R\        \        R,          \        R,          3,          /# )r?   Úskill_mdrB   N)r   r€   rD   )rF   s   "r;   rG   rG   è
  s,   € ÷ )ñ )¬4ð )´E¼#À½*ÄcÈDÅjÐ:PÕ4Qñ )r=   c                óP  €  V P                  RRR7      pTP                  R4      pTP                  R4      '       g   R# TP	                  R^4      pT^ 8  d   R# RpT^T P                  4        F›  pTP                  4       pTP                  R4      '       g   K,  TP                  R	^4      ^,          P                  4       p\        T4      ^8¼  d)   T^ ,          TR,          8X  d   T^ ,          R9   d   T^R pTP                  4       p M	  T'       g   R# TP                  4       P                  R
R4      P                  RR4      p\        P                  ! RRT4      p\        P                  ! RRT4      P                  R4      pT;'       g    RT3#   \         d    Ru # i ; i)zÀDerive ``(slug, declared_name)`` from a SKILL.md; ``(None, None)`` if unreadable or no ``name:``.
Matches ``scan_skill_commands``: the slug comes from frontmatter ``name:``, NOT the directory.ú	utf-8-sigrØ  )ÚencodingÚerrorsNu   ï»¿z---z
---zname:r{  rF  Ú-rû  z
[^a-z0-9-]r”   z-{2,}r|  rq  >   Ú"Ú')Ú	read_textrL   rÓ  r™  rÒ  Ú
splitlinesrá   rÎ   rU   r¢   rØ  rÈ   rî  )rÜ  r®  rÔ  Údeclared_nameÚliner0  Úslugs   &      r;   Ú_skill_slug_from_frontmatterré  è
  s~  € ðØ×$Ñ$¨kÀ)Ð$ÓLˆð �n‰n˜XÓ&€GØ×Ñ˜e×$Ò$ØÐØ
�,‰,�w Ó
"€CØ
ˆQ„wØÐØ $€MØ˜˜#�×)Ñ)Ö+ˆØ�z‰z‹|ˆØ�?‰?˜7×#Ô#Ø—*‘*˜S !Ó$ QÕ'×-Ñ-Ó/ˆCÜ�3‹x˜1Œ}  Q¥¨3¨r­7Ô!2°s¸1µvÀÔ7KØ˜!˜B�i�ØŸI™I›KˆMÙñ ,÷ ØÐØ×ÑÓ ×(Ñ(¨¨cÓ2×:Ñ:¸3ÀÓD€Dä�6Š6�-  TÓ*€DÜ�6Š6�(˜C Ó&×,Ñ,¨SÓ1€DØ�LˆL�D˜=Ð(Ð(øô/ ô ØÒðús   ‚F ÆF%Æ$F%c                ó>   € V ^8„  d   QhR\         R\         R,          /# )r?   Úcommand_namerB   Nr_   )rF   s   "r;   rG   rG     s   € ÷ &ñ &¬3ð &´3¸µ:ñ &r=   c                ó|  € V P                  4       P                  RR4      p ^ RIHp ^ RIHpHp V! 4       pV! 4        F�  pVP                  4       '       g   K  VP                  R4       FQ  pV! V4      '       d   K  \        V4      w  r‰V'       d	   V	'       g   K2  W�8X  g   K:  W•9   g   KB  \        RV R7      u u # 	  Kƒ  	  ^ RIHp
 \        \        4      P                  4       P                   P                   pV
! VR	,          4      pVP                  4       '       dŒ   VP                  R4       Fv  pV! V4      '       d   K  \        V4      w  r�V'       d   W�8w  d   K0  VP                   P#                  V4      pR
RP%                  VP&                  4       2p\        RWR7      u # 	  R#   \(         d     R# i ; i)zYHint when a command matches a skill that is disabled or optional-install only; else None.rû  rá  )Ú_get_disabled_skill_names)Úget_all_skills_dirsÚis_excluded_skill_pathzSKILL.mdzgateway.skills.disabled)r-  )Úget_optional_skills_dirzoptional-skillsz	official/rç  zgateway.skills.not_installed)r-  Úinstall_nameN)r¢   rØ  Útools.skills_toolrí  Úagent.skill_utilsrî  rï  r  Úrglobré  r   r¢  rð  r   rú   rû   rü   Úrelative_torÏ   rÐ   rL   )rë  Ú
normalizedrí  rî  rï  ÚdisabledÚ
skills_dirrÜ  rè  ræ  rð  Ú	repo_rootÚoptional_dirÚ	_declaredÚrelÚinstall_paths   &               r;   Ú_check_unavailable_skillrþ    st  € à×#Ñ#Ó%×-Ñ-¨c°3Ó7€Jð"Ý?ßQÙ,Ó.ˆá-Ö/ˆJØ×$Ñ$×&Ò&ÙØ&×,Ñ,¨ZÖ8�Ù)¨(×3Ò3ÙÜ&BÀ8Ó&LÑ#�ß§=ÙàÖ%¨-Ö*CÜÐ6¸\ÔJÔJó 9ñ 0õ 	=Üœ“N×*Ñ*Ó,×3Ñ3×:Ñ:ˆ	Ù.¨yÐ;LÕ/LÓMˆØ×Ñ× Ò Ø(×.Ñ.¨zÖ:�Ù)¨(×3Ò3ÙÜ">¸xÓ"H‘�ß˜tÔ1Ùà—o‘o×1Ñ1°,Ó?�Ø!*¨3¯8©8°C·I±IÓ+>Ð*?Ð@�ÜÐ7¸lÔfÒfñ ;ñ øô ô ØÙðús1   ¢A7F, ÂF, Â$F, Â,F, Â=C*F, Æ(F, Æ,F;Æ:F;c                ó0   € V ^8„  d   QhR\         R\        /# ræ   )rt  rD   )rF   s   "r;   rG   rG   0  s   € ÷ Cñ C¤8ð C´ñ Cr=   c                óH   € V \         P                  8X  d   R# V P                  # )uN   Map a Platform enum to its config.yaml key (LOCALâ†’"cli", restâ†’enum value).r  )rt  ÚLOCALr  rì   s   &r;   Ú_platform_config_keyr  0  s   € à¤§¡Ô.ˆ5ÐB°H·N±NÐBr=   c                ó$   € V ^8„  d   QhR\         /# rÖ   r×   )rF   s   "r;   rG   rG   5  s   € ÷ fñ f¬ñ fr=   c                 ó„   € \        \        4       RR. R7      p \        V \        4      ;'       d    RV 9   ;'       g    RV 9   # )zAReturn True when the standalone Teams pipeline plugin is enabled.Úpluginsr†  )r•   Úteams_pipelinezteams-pipeline)r,   rß   r   rŒ   )r†  s    r;   Ú_teams_pipeline_plugin_enabledr  5  s@   € äÔ*Ó,¨i¸ÈBÔO€GÜ�gœtÓ$×eÐeÐ*:¸gÑ*E×*dÐ*dÐIYÐ]dÑIdÐer=   c                ó$   € V ^8„  d   QhR\         /# rÖ   r   )rF   s   "r;   rG   rG   ;  s   € ÷ 8ñ 8œdñ 8r=   c                 óH   € \        4       p V '       d   \        V 4      # \        # )z<Return the Hermes home that gateway config reads should use.)r  r   r  )r=  s    r;   Ú_gateway_config_homer
  ;  s   € ä'Ó)€Hß%Œ4�‹>Ð7¬<Ð7r=   c                ó>   € V ^8„  d   QhR\         R,          R\        /# )r?   r4  NrB   rš  )rF   s   "r;   rG   rG   A  s   € ÷ ñ ¤d¨T¥kð ¼Tñ r=   c                ó    € V f   \        4       R,          p  ^ RIHp V! V 4      #   \         d    \        P                  RT RR7       / u # i ; i)uü   The effective user config.yaml (managed overlay, ``${VAR}`` expansion, model-key canon; no
DEFAULT_CONFIG merge) â€” ``{}`` on any error (fail-open). Defaults to the active gateway home
(``_hermes_home`` monkeypatches apply); multiplexers pass a path.
r.  r‡  z%Could not load gateway config from %sTrG  )r
  rŠ  rˆ  rL   rM   rN   )r4  rˆ  s   & r;   rß   rß   A  sR   € ð
 ÒÜ*Ó,¨}Õ<ˆðÝJÙ)¨+Ó6Ð6øÜô Ü�‰Ð<¸kÐTXˆÔYØŠ	ðús   —% ¥%AÁA)Úcheckpoint_agent_kwargsc                ó>   € V ^8„  d   QhR\         R,          R\        /# )r?   râ   NrB   ©rà   rD   )rF   s   "r;   rG   rG   S  s"   € ÷ Nñ N¤4¨$¥;ð N¼#ñ Nr=   c                ó   € ^ RI Hp V e   T M	\        4       P                  R/ 4      p\	        V\
        4      '       d+   VP                  R4      ;'       g    VP                  R4      p\	        V\        4      '       d   TMR;'       g    V! 4       # )záThe profile's model when nothing else names one: config.yaml (single source of truth), else the
claimed welcome trial's. Temporary AIAgents (e.g. /compress) otherwise use the hardcoded default,
which fails under openai-codex.)Útrial_modelr  r•   r”   )Úhermes_cli.anon_authr  rß   r~   r   rà   rD   )râ   r  r  s   &  r;   r  r  S  so   € õ 1Ø!Ò-‘Ô3GÓ3I×NÑNÈwÐXZÓ[€IÜ�)œT×"Ò"Ø—M‘M )Ó,×FÐF°	·±¸gÓ0Fˆ	Ü# I¬s×3Ò3‰I¸×MÐMÁÃÐMr=   Ú	thread_idÚ	parent_idc          	      óŠ   € V ^8„  d   QhR\         R\        \         ,          R\        \         ,          R\        \         ,          /# )r?   r¬  r  r  rB   )rD   r   rŒ   )rF   s   "r;   rG   rG   ^  s@   € ÷ [ñ [Üð[Ü (¬¥ð[ÜAIÌ#Åð[ÜZ^Ô_bÕZcñ[r=   c               óP   € \        \        P                  R WV3 4       4      4      # )u¨   Ordered, de-duplicated ``channel_overrides`` lookup keys (matches ``resolve_channel_prompt``:
exact id first, then parent â€” Discord threads inherit parent overrides).c              3   óJ   "  € T F  q'       g   K  \        V4      x € K  	  R # 5irÇ   r_   )rÊ   ra  s   & r;   rÌ   Ú0_channel_override_lookup_keys.<locals>.<genexpr>b  s   é € ÐYÑ2Q¨3ÓUXœhœc #Ÿh˜hÓ2Qùs   ‚	#�#)rŒ   rà   Úfromkeys)r¬  r  r  s   &$$r;   Ú_channel_override_lookup_keysr  ^  s#   € ô ”—‘ÑY°7ÀyÑ2QÓYÓYÓZÐZr=   c                ó¢   € V ^8„  d   QhR\         R\        R\        R\        \        ,          R\        \        ,          R\        \        ,          /# )r?   râ   rç   r¬  r  r  rB   )r¶  rt  rD   r   r—  )rF   s   "r;   rG   rG   e  sJ   € ÷ ñ ÜðÜ%-ðÜ8;ðÜKSÔTWÍ=ðäœ�}ðä(0´Õ(Añr=   c               ó   € \        V RR4      pV'       g   R# VP                  V4      pV'       d   VP                  '       g   R# VP                  p\        W#VR7       F  pVP                  V4      p	V	f   K  V	u # 	  R# )zQPer-channel override via chat_id, then thread_id, then parent_id; None if absent.rÐ  N)r  r  )r8   r~   Úchannel_overridesr  )
râ   rç   r¬  r  r  rÐ  rË  Ú	overridesra  Úovs
   &&&$$     r;   Ú_get_channel_overrider   e  sr   € ô ˜ ¨TÓ2€IßÙØ—m‘m HÓ-€Oß /×"C×"CÐ"CÙØ×1Ñ1€IÜ,¨WÐU^×_ˆØ�]‰]˜3ÓˆØŒ>ØŠIñ `ñ r=   c                óP   € V ^8„  d   QhR\         \        \        ,          ,          /# rÖ   )r   rŒ   rD   )rF   s   "r;   rG   rG   w  s   € ÷ ñ œX¤d¬3¥iÕ0ñ r=   c                 óÔ   €  ^ RI p V P                  P                  R4      e   \        P                  RR.#  ^ RIpVP                  R4      pV'       d   V.# R#   \
         d     L/i ; i)a,  Hermes update/restart argv: the running interpreter's ``python -m hermes_cli.main``
(exactly this install), else ``hermes`` on PATH, else None. The module argv must win: a
PATH-first lookup lets an attacker-planted ``hermes`` shadow the running install when
/update or /restart re-execs it (#111569).NÚ
hermes_cliz-mzhermes_cli.mainr�   )Úimportlib.utilÚutilÚ	find_specrù   Ú
executablerL   ÚshutilÚwhich)Ú	importlibr(  Ú
hermes_bins      r;   Ú_resolve_hermes_binr,  w  sk   € ð
ÛØ�>‰>×#Ñ# LÓ1Ò=Ü—N‘N DÐ*;Ð<Ð<ð >ó Ø—‘˜hÓ'€JßØˆ|ÐÙøô ô Ùðús   ‚3A ÁA'Á&A'z^[a-z0-9][a-z0-9_-]{0,63}$c                ó>   € V ^8„  d   QhR\         R\        R,          /# r^   )rD   rà   )rF   s   "r;   rG   rG   Œ  s   € ÷ ñ ¤Cð ¬D°4­Kñ r=   c                óœ  € V P                  R4      p\        V4      ^8¼  d«   V^ ,          R8X  d�   V^,          R
9   g#   \        P                  V^,          4      '       dm   RV^,          RV^,          RV^,          /pV^,          R8w  d   \	        V^,          4      VR&   \        V4      ^8”  d   V^,          R9   d   V^,          VR&   V# R	# )uv  Parse a session key (``agent:{ns}:{platform}:{chat_type}:{chat_id}[:{extra}...]``).

``{ns}`` is ``main`` for the default profile, ``main~`` for a profile literally named ``main``
(``gateway.session._session_key_namespace``), or a named-profile id (profile ids match
``[a-z0-9][a-z0-9_-]{0,63}`` â€” never contain ``:`` â€” so a plain split stays unambiguous).
For group/channel sessions the suffix may be a user_id, not a thread_id, so ``thread_id``
is omitted. Named profiles are reported as ``profile``; ``main`` keys keep their historical
shape exactly (no ``profile`` key) so equality assertions on parsed dicts stay stable.
r{  r™   Úmainrç   Ú	chat_typer¬  Úprofiler  N)r/  zmain~>   ÚdmÚthread)rÎ   rU   Ú_PROFILE_ID_KEY_RErâ  rž  )r@   rÐ   r»  s   &  r;   Ú_parse_session_keyr5  Œ  s¸   € ð ×Ñ˜cÓ"€EäˆE‹
�aŒØ�!�H˜ÔØ�1�XÐ*Ô*Ô.@×.FÑ.FÀuÈQÅx×.PÒ.Pà˜e A�h¨°U¸1µX¸yÈ%ÐPQÍ(ÐSˆØ��8�vÔÜ BÀ5ÈÅ8Ó LˆF�9ÑÜˆu‹:˜Œ>˜e A�hÐ*:Ô:Ø"'¨¥(ˆF�;ÑØˆÙr=   c                ó<   € V ^8„  d   QhR\         R\        R\         /# )r?   ra  ÚlimitrB   rð  )rF   s   "r;   rG   rG   ¥  s!   € ÷ ñ ¬#ð ´cð Ä3ñ r=   c                óž   € RP                  T ;'       g    RP                  4       4      p\        V4      V8”  d   VRV^,
           R,           pV# )zFCollapse a shell command onto one line and cap its length for display.rF  r”   Nu   â€¦)rÏ   rÎ   rU   )ra  r7  Úone_lines   && r;   Ú_shorten_command_for_displayr:  ¥  sE   € à�x‰x˜Ÿ˜ B×-Ñ-Ó/Ó0€HÜ
ˆ8ƒ}�uÔØ˜K˜e a�iÐ(¨5Õ0ˆØ€Or=   c                óH   € V ^8„  d   QhR\         R\         R\         R\         /# )r?   rˆ   ra  ÚoutputrB   r_   )rF   s   "r;   rG   rG   ­  s,   € ÷ ñ ÜðÜ!ðÜ69ðÜUXñr=   c                ó  € VR9   pV'       d   \        R4      M
\        R4      .p\        V4      pV'       d   VP                  RV R24       . p\        V\        \
        34      '       dˆ   V^ 8¼  d�   \	        V4      p	V	R8¼  d.   VP                  V	R,           RV	R,          ^<,           R24       MAV	^<8¼  d'   VP                  V	^<,           R	V	^<,           R
24       MVP                  V	 R
24       V'       g   VP                  \        RVR7      4       V'       d%   VP                  RRP                  V4       R24       RP                  V4      p
V'       g“   V'       d‹   VP                  4       P                  4        Uu. uF  q»P                  4       '       g   K  VNK  	  upRR pRP                  V4      p\        V4      R8”  d   VRR pV'       d   V
\        RVR7      ,          p
V'       g   V
\        R4      ,          p
V
# u upi )z^One-line completion message for ``concise`` display mode; failure appends a short output tail.Nz gateway.background.task_finishedzgateway.background.task_failedu   â€” `Ú`rd  zh Úmzm Úszgateway.background.exit_code)Úcoderî   r‰  r4   rF  rŽ  iô  zgateway.background.last_output)Útailzgateway.background.rerun_hint>   Nr  éûÿÿÿiþÿÿ)
r   r:  rs  r   rQ   rE   rÏ   rá   rå  rU   )rˆ   ra  Ú	exit_coder<  Úduration_secondsÚokrÐ   Ú	short_cmdÚdetailsrl  rQ  ÚlnÚ
tail_linesrB  s   &&&&&         r;   Ú$_format_concise_process_notificationrK  ­  s°  € ð 
�iÑ	€Bß68ŒQÐ1Ô2¼aÐ@`Ó>aÐb€EÜ,¨WÓ5€IßØ�‰�u˜Y˜K qÐ)Ô*Ø€GÜÐ"¤S¬% L×1Ò1Ð6FÈ!Ô6KÜÐ#Ó$ˆØ�4Œ<Ø�N‰N˜d d�l˜^¨2¨t°d­{¸rÕ.AÐ-BÀ!ÐDÕEØ�RŒZØ�N‰N˜d b�j˜\¨¨D°2­I¨;°aÐ8Õ9à�N‰N˜d˜V 1˜:Ô&ßØ�‰”qÐ7¸iÔHÔIßØ�‰�q˜Ÿ™ 7Ó+Ð,¨AÐ.Ô/Ø�8‰8�E‹?€Dß—&Ø#)§<¡<£>×#<Ñ#<Ô#>ÓMÑ#>˜RÇ(Á(Ç*—b�bÑ#>ÑMÈbÈcÐRˆ
Ø�y‰y˜Ó$ˆÜˆt‹9�sŒ?Ø˜˜�;ˆDßØ”AÐ6¸TÔBÕBˆDßØ”Ð1Ó2Õ2ˆØ€Kùò Ns   ÆH	ÆH	c                ó>   € V ^8„  d   QhR\         R\        R,          /# )r?   ÚevtrB   Nr  )rF   s   "r;   rG   rG   Ï  s   € ÷ ñ ¬dð ´s¸Tµzñ r=   c                ó¬  € V P                  RR4      pV P                  RR4      pV P                  RR4      pVR9   d   RV P                  RR4       R	2# VR
8X  de   V P                  RR4      pV P                  RR4      pV P                  R^ 4      pRV RV RV RV 2pV'       d   VRV R2,          pVR	,          pV# VR9   d   ^ RIHp V! V 4      # R# )zOFormat a watch pattern event from completion_queue into a [IMPORTANT:] message.r5  Ú
completionrˆ   rø   ra  z[IMPORTANT: rŸ  r”   rG  Úwatch_matchrˆ  r§  r<  Ú
suppressedz[IMPORTANT: Background process z matched watch pattern "z".
Command: z
Matched output:
z
(z/ earlier matches were suppressed by rate limit))Úformat_process_notificationN)Úwatch_disabledÚwatch_overflow_trippedÚwatch_overflow_released)Úasync_delegationÚ	heartbeat)r~   Ú$tools.process_registry_notificationsrR  )	rM  Úevt_typeÚ_sidÚ_cmdÚ_patÚ_outÚ_suprQ  rR  s	   &        r;   Ú$_format_gateway_process_notificationr_  Ï  sý   € à�w‰w�v˜|Ó,€HØ�7‰7�< Ó+€DØ�7‰7�9˜iÓ(€Dð ÐZÔZØ˜cŸg™g i°Ó4Ð5°QÐ7Ð7à�=Ô Ø�w‰w�y #Ó&ˆØ�w‰w�x Ó$ˆØ�w‰w�| QÓ'ˆà-¨d¨Vð 4Ø#˜fð %Ø�vÐ0°°ð8ð 	÷ Ø�c˜$˜ÐNÐOÕOˆDØ��ˆØˆàÐ4Ô4ÝTÙ*¨3Ó/Ð/ár=   c                ó:   € V ^8„  d   QhR\         \        ,          /# rÖ   )rŒ   rà   )rF   s   "r;   rG   rG   í  s   € ÷ ñ ´T¼$µZñ r=   c                óD  € . p. pV P                  4       '       gZ    V P                  4       pTP                  RR4      pTR9   d   TP	                  T4       KS  TR8X  g   K\  TP	                  T4       Ko  V F  pV P                  V4       K  	  V#   \         d     K*  i ; i)z§Drain gateway-owned watch events without spinning on requeued events.
Foreign events requeued inside ``while not queue.empty()`` never terminate: detach, then requeue.r5  rO  rV  >   rW  rP  rS  rT  rU  )ÚemptyÚ
get_nowaitrL   r~   rs  Úput)Úcompletion_queueÚwatch_eventsÚrequeuerM  rY  s   &    r;   Ú_drain_gateway_watch_eventsrh  í  s¦   € ð  "€LØ€GØ×$Ñ$×&Ò&ð	Ø"×-Ñ-Ó/ˆCð —7‘7˜6 <Ó0ˆØð ô ð ×Ñ Ö$ØÐ+Ö+Ø�N‰N˜3ÖãˆØ×Ñ˜SÖ!ñ àÐøô ô 	Úð	ús   œB ÂBÂBc                  ó   € R # rÇ   rº   rº   r=   r;   rš   rš     s   € ©Dr=   Úhistory_lenc                óH   € V ^8„  d   QhR\         R\        R\        R\        /# )r?   Úagent_resultrÖ  rj  rB   )rà   rD   rQ   )rF   s   "r;   rG   rG   	  s2   € ÷ Sñ SÜðSÜ"%ðSÜ7:ðSÜCFñSr=   c               ó¾  € \        W4      pV'       d   V'       d   \        V4      '       g   V# V P                  R4      '       d÷   V P                  R4      ;'       g    \        R4      p\	        V4      P                  4       p\	        V P                  R4      ;'       g    R4      pVP                  R4      '       g   RV9   d5   VP                  R4      '       g   R	V9   d   \        R
4      # \        R4      # V'       d   \        4       # \        P                  R\	        V4      R,          4       \        R4      # \        V P                  R^ 4      ;'       g    ^ 4      pV P                  R4      '       d   V^ 8X  d   \        R4      # V# V^ 8”  Ed!   \        V 4      '       d   R# V P                  R4      '       dì   \	        V P                  R4      ;'       g    \        R4      4      p^ RIHp	 \	        V P                  R4      ;'       g    R4      V	9   dF   VP                  4       '       d0   \        V4      '       g   VP                  R4      '       d   V# RV 2# \        V4      '       d!   \        P                  RVR,          4       Rp
MRVR,           2p
\        RV
R7      # \        R4      # V^ 8X  d#   V P                  R4      '       g   \        R4      # V# )aÓ  Normalize empty/None agent responses into user-facing messages.
Covers ``failed``, work done (api_calls > 0) with no text, and never-ran (api_calls == 0, the
post-/stop silent-drop from a stale generation token) with a retry hint.

Consolidates the existing ``failed`` handler and adds a catch-all for the case where the agent did work
(api_calls > 0) but returned no text. Fix for #18765.
Also surfaces a retry hint when the agent never ran at all (api_calls == 0) for a non-interrupted,
non-failed turn -- this is the silent-drop pattern observed after ``/stop`` where the next user message
hits a stale generation token and returns an empty result, leaving the platform with nothing to send.
(#31884)

A failed context-overflow turn whose ``final_response`` is only the raw provider envelope
(``HTTP 400: {...}``) is rewritten too: returned unchanged, chat sanitizers turn it into a
generic provider-failed reply and the user never sees /compact. Curated agent text survives.
r´  r¾   zgateway.shared.unknown_errorÚfailure_reasonr”   Úsession_persistence_failedzsession storagez:diskÚdiskz/gateway.errors.session_storage_unavailable_diskz*gateway.errors.session_storage_unavailablez7Agent turn failed; reply sanitized for chat. Detail: %s:Niô  Nzgateway.errors.generic_failedÚ	api_callsÚinterruptedz'gateway.errors.interrupted_before_startÚpartialz$gateway.errors.processing_incomplete)ÚSITE_FAILURE_CODESu   âš ï¸�u   âš ï¸� z@Agent turn ended partially; reply sanitized for chat. Detail: %srŒ  rj  z'gateway.errors.stopped_before_finishing©ro  zgateway.errors.no_responsez$gateway.errors.previous_turn_cleanup)r«  r’  r~   r   rD   r¢   r™  Úendswithrz  rM   r¬   rQ   Ú,_is_gateway_hidden_reasoning_incomplete_turnÚagent.turn_failure_copyrt  rá   )rl  rÖ  rj  Úis_overflowÚerror_detailÚ	error_strrn  rq  Úerrrt  ro  s   &&$        r;   Ú_normalize_empty_agent_responser}  	  sp  € ô" 5°\ÓO€KßŸÔ)KÈH×)UÒ)UØˆØ×Ñ˜×!Ò!à#×'Ñ'¨Ó0×UÐU´AÐ6TÓ4UˆÜ˜Ó%×+Ñ+Ó-ˆ	ä˜\×-Ñ-Ð.>Ó?×EÐEÀ2ÓFˆØ×$Ñ$Ð%A×BÒBÐFWÐ[dÔFdØ×&Ñ& w×/Ò/°6¸YÔ3FÜÐJÓKÐKÜÐAÓBÐBßÜ*Ó,Ð,ä�‰ÐPÔRUÐVbÓRcÐdhÕRiÔjÜÐ0Ó1Ð1ä�L×$Ñ$ [°!Ó4×9Ð9¸Ó:€IØ×Ñ˜×&Ò&ð ˜Œ>ÜÐ>Ó?Ð?ØˆØ�1…}ô
 8¸×EÒEÙØ×Ñ˜I×&Ò&ô �l×&Ñ& wÓ/×\Ð\´1Ð5[Ó3\Ó]ˆCõ CÜ�L×$Ñ$Ð%5Ó6×<Ð<¸"Ó=ÐASÔSØŸ	™	ŸšÔ,NÈs×,SÒ,SØ!Ÿn™n¨X×6Ò6�sÐK¸gÀcÀU¸OÐKÜ1°#×6Ò6Ü—‘ÐaÐcfÐgkÕclÔmØ‘à˜c $�i˜[Ð)�ÜÐ>ÀvÔNÐNÜÐ-Ó.Ð.ð �A„~˜l×.Ñ.¨y×9Ò9ÜÐ7Ó8Ð8à€Or=   c                ó0   € V ^8„  d   QhR\         R\        /# ©r?   rl  rB   ©rà   rm   )rF   s   "r;   rG   rG   _  s   € ÷ >ñ >¼tð >Ìñ >r=   c                óÚ  € \        V \        4      '       dF   V P                  R4      '       g/   V P                  R4      '       g   V P                  R4      '       g   R# \        V P                  RR4      ;'       g    R4      P	                  4       pRVP                  4       9  d   R# \        V P                  R4      ;'       g    R4      P	                  4       pV'       * ;'       g    W!8H  # )	a  Detect retry-exhausted turns with hidden reasoning but no visible answer.
The loop returns the retry-exhaustion sentinel as BOTH ``final_response`` and ``error``, so a
non-empty ``final_response`` proves nothing; any text other than the sentinel is a real answer.r´  rr  rs  Fr¾   r”   zremained incomplete afterÚfinal_response)r   rà   r~   rD   rá   r¢   )rl  Ú
error_textr‚  s   &  r;   rw  rw  _  s¼   € ô �|¤T×*Ò*¨l×.>Ñ.>¸x×.HÒ.HØ×Ñ ×.Ò.°l×6FÑ6FÀy×6QÒ6QÙÜ�\×%Ñ% g¨rÓ2×8Ð8°bÓ9×?Ñ?ÓA€JØ"¨*×*:Ñ*:Ó*<Ô<ÙÜ˜×)Ñ)Ð*:Ó;×AÐA¸rÓB×HÑHÓJ€NØÔ×=Ð= Ñ!=Ð=r=   c                ó0   € V ^8„  d   QhR\         R\        /# r  r€  )rF   s   "r;   rG   rG   m  s   € ÷ 6ñ 6¼$ð 6Ä4ñ 6r=   c                ó  € \        V \        4      '       d   V P                  R4      '       d   R# V P                  R4      '       g/   V P                  R4      '       g   V P                  R4      '       d   R# V P                  R4      RJ# )zÏTrue only when a gateway turn really completed successfully.
``resume_pending`` is a durable restart-recovery marker; a soft interrupt can look like a normal
empty result, and clearing then loses the signal.rr  Fr´  rs  r¾   Ú	completedrÑ  )rl  s   &r;   Ú'_should_clear_resume_pending_after_turnr‡  m  so   € ô �l¤D×)Ò)¨\×-=Ñ-=¸m×-LÒ-LÙØ×Ñ˜×!Ò! \×%5Ñ%5°i×%@Ò%@ÀL×DTÑDTÐU\×D]ÒD]ÙØ×Ñ˜KÓ(°Ð5Ð5r=   c                ó<   € V ^8„  d   QhR\         R\         R\         /# )r?   Úcurrent_resultÚfollowup_resultrB   r&  )rF   s   "r;   rG   rG   x  s)   € ÷ Añ AÜðAÜ+/ðAÜ48ñAr=   c                ó  € \        V\        4      '       d   \        V \        4      '       g   V# V P                  R4      pVP                  R4      p\        V\        4      '       g   V# \        V\        4      '       d	   W28:  d   V# / VCRV/C# )zæCarry the outer history offset through queued follow-up drains.
Each recursive ``_run_agent()`` advances ``history_offset``; uncorrected, the outer persistence
step sees only the *last* queued turn as "new" and drops earlier ones.rØ  )r   rà   r~   rQ   )r‰  rŠ  Úcurrent_offsetÚfollowup_offsets   &&  r;   Ú(_preserve_queued_followup_history_offsetrŽ  x  sƒ   € ô
 �o¤t×,Ò,´J¸~Ìt×4TÒ4TØÐØ#×'Ñ'Ð(8Ó9€NØ%×)Ñ)Ð*:Ó;€OÜ�n¤c×*Ò*ØÐÜ�/¤3×'Ò'¨OÔ,MØÐØ@ˆoÐ@Ð/°Ñ@Ð@r=   c                ó6   € V ^8„  d   QhR\         R,          RR/# )r?   r«  NrB   )rø  )rF   s   "r;   rG   rG   ˆ  s$   € ÷ Mñ MÔ+>ÀÕ+Eð MÈ$ñ Mr=   c              ƒ  óà   "  € V f   R#  V P                  4       G Rj  x€L
  R#  L  \         d;    \        P                  R\	        T R\        T 4      P                  4      RR7        R# i ; i5i)u¼  Best-effort dispose for an adapter that never made it onto ``self.adapters`` (may be ``None``).
Nothing else calls ``disconnect()`` on it, so ``__init__`` resources (e.g. SQLite fds) would leak
until GC (not prompt for asyncio-bound objects) and exhaust the fd ulimit over a long retry loop.

The reconnect watcher in ``GatewayRunner._platform_reconnect_watcher`` constructs a fresh adapter on
every retry attempt. When the connect call fails â€” for any of the three reasons (non-retryable error,
retryable error, exception during connect) â€” the adapter is dropped without ever being installed, so
nothing else will call its ``disconnect()``. ``APIServerAdapter`` opens a SQLite ``ResponseStore`` that
holds 2 fds â€” the db file and its WAL sidecar) stay open until garbage collection sweeps the unreachable
object, which Python's cyclic GC does not do promptly for asyncio-bound objects with native handles. The
cumulative leak is 2 fds Ã— every retry at the 300s backoff cap â‰ˆ 12 fds/hour, and the default 2560-fd
ulimit is exhausted in ~12h of continuous failure, after which every open() call on the gateway raises
``OSError: [Errno 24] Too many open files`` and the gateway becomes a zombie (#37011).
Nz,Adapter dispose raised on unowned adapter %rr-  TrG  )Ú
disconnectrL   rM   rN   r8   r5  r6  )r«  s   &r;   Ú_dispose_unused_adapterr’  ˆ  sd   é € ð ‚ÙðMØ× Ñ Ó"×"Ô"øÜô Mä�‰Ø:Ü�G˜V¤T¨'£]×%;Ñ%;Ó<Àtð 	÷ 	MðMüs2   ‚A.Š& �$ž& ¢A.¤& ¦AA+Á'A.Á*A+Á+A.é,  c                ó0   € V ^8„  d   QhR\         R\         /# )r?   ÚattemptrB   r  )rF   s   "r;   rG   rG   ¥  s   € ÷ Bñ B¤ð B¬ñ Br=   c                óL   € \        ^^V ^,
          ,          ,          \        4      # )zCExponential reconnect backoff: 30s, 60s, 120s, ... capped at 5 min.)rT   Ú_RECONNECT_BACKOFF_CAP)r•  s   &r;   Ú_reconnect_backoffr˜  ¥  s   € äˆr�Q˜7 Q�;Õ'Õ(Ô*@ÓAÐAr=   c                ó$   € V ^8„  d   QhR\         /# rÖ   rù  )rF   s   "r;   rG   rG   ª  s   € ÷ Lñ L¬ñ Lr=   c                 ó  € ^ RI Hp  V ! 4       P                  R4      p\        V\        4      '       d   VP                  R4      MRp \        V4      #   \        \        3 d!    \        \        R,          R,          4      u # i ; i)a¹  ``agent.reconnect_attention_after`` of the profile whose scope is bound at call time (the launch
profile's when unbound). Seconds continuously in the reconnect queue before NEEDS_ATTENTION; retrying
never stops (transient outages must self-heal), this only makes a permanently-failing loop loud.
Non-positive disables. Read per call, never cached: one process serves many profiles and a config
edit must not need a gateway restart (#115635).r  r™   Úreconnect_attention_afterN)	r  r  r~   r   rà   rE   r/  rô  Ú_DEFAULT_CONFIG)r  r"  r0  s      r;   Ú_reconnect_attention_after_secsr�  ª  st   € õ 7Ù$Ó&×*Ñ*¨7Ó3€IÜ8BÀ9Ìd×8SÒ8Sˆ)�-‰-Ð3Ô
4ÐY]€CðLÜ�S‹zÐøÜ”zÐ"ô LÜ”_ WÕ-Ð.IÕJÓKÒKðLús   Á
A Á.BÂBc                ó<   € V ^8„  d   QhR\         R\        R\        /# )r?   r  r8  rB   )rà   rE   rm   )rF   s   "r;   rG   rG   ¹  s!   € ÷ 
*ñ 
*¤Tð 
*´ð 
*¼$ñ 
*r=   c                ót   € \        4       pV^ 8:  d   R# V P                  R4      pVf   WR&   R# W,
          V8¬  # )z¤True when a reconnect-queue entry has waited long enough for NEEDS_ATTENTION.
``queued_at`` is re-stamped on each (re)entry, so only *continuous* failure escalates.FÚ	queued_at)r�  r~   )r  r8  Ú	thresholdr   s   &&  r;   Ú_reconnect_needs_attentionr¢  ¹  sB   € ô 0Ó1€IØ�A„~ÙØ—‘˜Ó%€IØÒØˆ[ÑÙØ�O 	Ñ)Ð)r=   Ú	suspendedzy[System note: The user's previous session was stopped and suspended. This is a fresh conversation with no prior context.]c                ó(   € V ^8„  d   QhR\         RR/# )r?   ÚfieldsrB   NrÐ  )rF   s   "r;   rG   rG   Ñ  s   € ÷ ñ ¬#ð °$ñ r=   c                 óH   €  ^ RI Hp V! R/ V B  R#   \         d     R# i ; i)zQBest-effort status publication; persistence must never abort or block the caller.)Úpublish_runtime_statusNrº   )rj  r§  rL   )r¥  r§  s   , r;   Ú_write_runtime_status_quietr¨  Ñ  s'   € ðÝ9ÙÑ( Ô(øÜô Úðús   ‚ ’! !c                óF   € V ^8„  d   QhR\         R\        \        ,          /# ©r?   r™  rB   )r   r   rà   )rF   s   "r;   rG   rG   Ú  s   € ÷ ñ ¤sð ¬x¼­~ñ r=   c                ó6  €  \        V P                  RR4      ;'       g!    \        \        V RR4      ;'       g    R4      p\        V RR4      pV'       d2   V'       d*   RVR\        V4      R\        V RR4      R\        V RR4      /# R#   \         d     R# i ; i)zXDelivery origin for a shared CLI/gateway command so its job replies to this chat/thread.r  Nrç   r”   r¬  Ú	chat_namer  )r8   rç   rD   rL   )r™  rç   r¬  s   &  r;   Ú_command_origin_for_sourcer­  Ú  sŸ   € ð
Ü˜6Ÿ?™?¨G°TÓ:×hÐh¼cÄ'È&ÐR\Ð^`ÓBa×BgÐBgÐegÓ>hˆÜ˜& )¨TÓ2ˆßŸà˜HØœ3˜w›<ØœW V¨[¸$Ó?ØœW V¨[¸$Ó?ð	Að Añ øô ô ØÙðús!   ‚B	  B	 º#B	 Á(B	 Â	BÂBc                ó<   € V ^8„  d   QhR\         R\         R\         /# )r?   ÚmoduleÚadapter_nameÚrequirementr_   )rF   s   "r;   rG   rG   ê  s&   € ÷ Añ A¤Cð A´sð AÌñ Ar=   c                ó^   € ^ RI pVP                  RV  24      p\        WA4      \        WB4      3# )zSLazy-import ``(adapter_cls, requirements_ok)`` from ``gateway.platforms.<module>``.Nzgateway.platforms.)r*  Úimport_moduler8   )r¯  r°  r±  r*  Úmods   &&&  r;   Ú_builtin_adapter_importrµ  ê  s2   € ãØ
×
!Ñ
!Ð$6°v°hÐ"?Ó
@€CÜ�3Ó%¤w¨sÓ'@Ð@Ð@r=   c                óR   € V ^8„  d   QhR\         R\        R\        \        ,          /# )r?   rç   râ   rB   )rt  r   r   rø  )rF   s   "r;   rG   rG   û  s'   € ÷ 
ñ 
¬8ð 
¼Sð 
ÄXÔNaÕEbñ 
r=   c                óê   € \         P                  V 4      pVf   R# Vw  r4rV\        W4V4      w  rx\        V4      '       d   V! 4       '       g!   MV'       g   \        P                  V4       R# V! V4      # )zYInstantiate a core (non-plugin) adapter, or None when its requirements are unmet/unknown.N)Ú_BUILTIN_ADAPTERSr~   rµ  rO   rM   r¬   )	rç   râ   Úspecr¯  r°  r±  r¬   Úadapter_clsÚrequirements_oks	   &&       r;   Ú_instantiate_builtin_adapterr¼  û  sc   € ä× Ñ  Ó*€DØ‚|ÙØ15Ñ.€F˜+Ü#:¸6ÐQ\Ó#]Ñ €KÜ!)¨/×!:Ò!:‰O×ÓÇÜ�‰�wÔÙÙ�vÓÐr=   )ÚGatewayRuntimeInitMixinc                   ó¾  a € ] tR tRt o RtR tRtRt]t	]
t]t]tRtRtRtRtRtRtRtRtRtRtRtRtRtRtRt]! R4      t ]! R4      t!]! R	4      t"]! R
4      t#]$! 4       t%]! R4      t&]! R4      t']! R4      t(]! R4      t)]! R4      t*]! R4      t+]! R4      t,]! R4      t-]! R4      t.]! R4      t/]! R4      t0]! R4      t1]! R4      t2]! R4      t3V 3R lR lt4V 3R lR lt5V 3R lR lt6V 3R lR  lt7V 3R! lR" lt8Rt9Rt:Rt;R#t<Rt=Rt>Rt?R•V 3R$ lR% llt@R–V 3R& lR' lltA]BV 3R( lR) l4       tC]CPˆ                  V 3R* lR+ l4       tCV 3R, lR- ltEV 3R. lR/ ltFV 3R0 lR1 ltG]HR2,          tI]B! R3 4      tJ]B! R4 4      tK]B! R5 4      tL]B! R6 4      tMV 3R7 lR8 ltN]O! R9R:04      tPR;tQV 3R< lR= ltRV 3R> lR? ltSV 3R@ lRA ltTV 3RB lRC ltUV 3RD lRE ltVR—V 3RF lRG lltWV 3RH lRI ltXV 3RJ lRK ltYV 3RL lRM ltZ^ t[]\Pº                   ! RN RO4      4       t^R;t_RPt`^taRQtb]O! 0 R˜m4      tc^tdRRteRRtf^tgRSthRRti^tjRTRURVRWRXRY/tkV 3RZ lR[ ltlR\R]/V 3R^ lR_ lltmV 3R` lRa ltnV 3Rb lRc ltoV 3Rd lRe ltp]BV 3Rf lRg l4       tqV 3Rh lRi ltr]\Pº                   ! Rj Rk4      4       ts]\Pº                   ! Rl Rm4      4       ttR•V 3Rn lRo lltuRpRRqRRrR/V 3Rs lRt lltv]wRpRRrR/V 3Ru lRv ll4       tx]w! ]y4      ty]O! ]zPö                  ]zPø                  ]zPú                  ]zPü                  ]zPþ                  ]zEP                   ]zEP                  ]zEP                  ]zEP                  ]zEP                  ]zEP
                  ]zEP                  ]zEP                  ]zEP                  ]zEP                  04      tŠV 3Rw lRx lt‹V 3Ry lRz ltŒ]�V 3R{ lR| l4       tŽR} t�R~ t�V 3R lR€ lt‘V 3R� lR‚ lt’V 3Rƒ lR„ lt“]wV 3R… lR† l4       t”R™V 3R‡ lRˆ llt•Ršt–]wV 3R‰ lRŠ l4       t—R•V 3R‹ lRŒ llt˜V 3R� lRŽ lt™]\Pº                   ! R� R�4      4       tš]\Pº                   ! R‘ R’4      4       t›V 3R“ ltœR”t�V tžR# )›ÚGatewayRunneri  zWMain gateway controller: manages adapter lifecycles, routes messages to/from the agent.c                ó$   € V P                  V4      # )a-  The adapter that owns *source* for the session authority (admission checks, canonical
automation, native route checks, recovery bindings). Main split the old resolver into the
intake and delivery seams; the authority needs the answering adapter, so this is the
delivery seam under its historical name.)Ú_delivery_adapter_for©Úselfr™  s   &&r;   Ú_adapter_for_sourceÚ!GatewayRunner._adapter_for_source  s   € ð
 ×)Ñ)¨&Ó1Ð1r=   Ú	interruptNFÚ_running_agentsÚ_running_agents_tsÚ_active_session_leasesÚ_busy_ack_tsÚ_session_run_generationÚ_session_model_overridesÚ _pending_one_turn_model_restoresÚ_session_reasoning_overridesÚ_session_service_tier_overridesÚ_last_resolved_modelÚ_queued_eventsÚ_pending_turn_sidecar_notesÚ_pending_messagesÚ&_pending_native_image_paths_by_sessionÚ_session_ephemeral_pinÚ_session_vc_lastÚ_pending_approvalsÚ_update_prompt_pendingc                ó6   <€ V ^8„  d   QhRS[ S[S[3,          /# rÖ   )rà   rD   r¡  )rF   rñ  s   "€r;   rG   ÚGatewayRunner.__annotate__G  s   ø€ ÷ ñ ™t¡C©Ð$5Õ6ñ r=   c                ód   € V P                   P                  R4      pVf   / pWP                   R&   V# )zSPer-session state map; lazily created so bare ``object.__new__`` test runners work.Ú	_sessions©Ú__dict__r~   )rÃ  r/  s   & r;   Ú_sessions_mapÚGatewayRunner._sessions_mapG  s2   € à—=‘=×$Ñ$ [Ó1ˆØÒØˆHØ)1�M‰M˜+Ñ&Øˆr=   c                ó&   <€ V ^8„  d   QhRS[ RS[/# ©r?   r@   rB   )rD   r¡  )rF   rñ  s   "€r;   rG   rÚ  O  s   ø€ ÷ ñ ©#ð ±,ñ r=   c                ól   € V P                  4       pVP                  V4      pVf   \        4       pW2V&   V# )z<Get-or-create the :class:`SessionState` for ``session_key``.)rß  r~   r¡  )rÃ  r@   r/  rX   s   &&  r;   rJ   ÚGatewayRunner._session_stateO  s7   € à×%Ñ%Ó'ˆØ—‘˜[Ó)ˆØŠ=Ü “NˆEØ$)�[Ñ!Øˆr=   c                ó6   <€ V ^8„  d   QhRS[ RS[S[,          /# râ  )rD   r   r¡  )rF   rñ  s   "€r;   rG   rÚ  X  s    ø€ ÷ ?ñ ?©sð ?±xÁÕ7Mñ ?r=   c                ón   € V P                   P                  R4      pV'       d   VP                  V4      # R# )zAReturn the SessionState for ``session_key`` without creating one.rÜ  NrÝ  )rÃ  r@   r/  s   && r;   rb   Ú!GatewayRunner._peek_session_stateX  s,   € à—=‘=×$Ñ$ [Ó1ˆß,4ˆx�|‰|˜KÓ(Ð>¸$Ð>r=   c                ó&   <€ V ^8„  d   QhRS[ RS[/# râ  rd  )rF   rñ  s   "€r;   rG   rÚ  ]  s   ø€ ÷ Bñ B©sð B±tñ Br=   c                ól   € V P                  V4      pVRJ;'       d    VP                  P                  RJ# )zDTrue when the session holds a running-turn slot (agent or sentinel).N)rb   Úturnr™   )rÃ  r@   rX   s   && r;   Ú_is_session_runningÚ!GatewayRunner._is_session_running]  s4   € à×(Ñ(¨Ó5ˆØ˜DÐ ×AÐA U§Z¡Z×%5Ñ%5¸TÐ%AÐAr=   c                ó0   <€ V ^8„  d   QhRS[ S[,          /# rÖ   )rŒ   r€   )rF   rñ  s   "€r;   rG   rÚ  b  s   ø€ ÷ 1ñ 1¡d©5¥kñ 1r=   c                óÐ   € V P                  4       P                  4        UUu. uF6  w  rVP                  P                  f   K  WP                  P                  3NK8  	  upp# u uppi )zV(session_key, agent) pairs for sessions with a running turn (incl. pending sentinels).)rß  rž  rê  r™   )rÃ  ra  rX   s   &  r;   Ú_running_agent_itemsÚ"GatewayRunner._running_agent_itemsb  sW   € à:>×:LÑ:LÓ:N×:TÑ:TÔ:Vô 1Ñ:V©J¨CØ—:‘:×#Ñ#ô (�—j‘j×&Ñ&Ó'Ñ:Vò 1ð 	1ùó 1s   ¢A"ÁA"rÈ  c                ó0   <€ V ^8„  d   QhRS[ S[,          /# )r?   râ   )r   r¶  )rF   rñ  s   "€r;   rG   rÚ  q  s   ø€ ÷ &+ñ &+™x©Õ6ñ &+r=   c           	     ór  € Ve   TM	\        4       V n        Ve'   ^ RIHpHp V! V P                  4      pVe	   V! V4        ^ RIHp V! \        \        V P                  RR4      4      4       / V n        R V n        / V n        / V n        V P!                  4        \"        P$                  ! V 4      sV P)                  4        V P+                  4        V P-                  4        V P/                  4        V P1                  4        V P3                  4        R #   \         d    \        P                  RRR7        LÈi ; i)N)Ústandalone_launcher_decisionr¹  r»  rr  Fz#could not set multiplex-active flagTrG  )rÁ  râ   r¾  ró  r¹  r&  r¼  rm   r8   rL   rM   rN   ÚadaptersÚ_session_db_init_errorÚ_profile_adaptersÚ_profile_configsÚ'_warn_if_docker_media_delivery_is_riskyÚ_weakrefÚrefÚ_gateway_runner_refÚ_init_runtime_settingsÚ_init_session_storeÚ_init_lifecycle_stateÚ_init_runtime_cachesÚ_init_session_dbÚ_init_registries_and_clocks)rÃ  râ   ró  r¹  Údecisionr¼  s   &&    r;   Ú__init__ÚGatewayRunner.__init__q  s  € ð !'Ò 2‘fÔ8VÓ8XˆŒØÒßnÙ3°D·K±KÓ@ˆHØÒ#Ù& xÔ0ð	OÝ?Ù ¤¤g¨d¯k©kÐ;OÐQVÓ&WÓ!XÔYð >@ˆŒð 6:ˆÔ#àQSˆÔð 13ˆÔØ×4Ñ4Ô6Ü&Ÿlšl¨4Ó0Ðà×#Ñ#Ô%Ø× Ñ Ô"Ø×"Ñ"Ô$Ø×!Ñ!Ô#Ø×ÑÔØ×(Ñ(Ö*øô) ô 	OÜ�L‰LÐ>ÈˆLÖNð	Oús   Á,D Ä"D6Ä5D6c                ó&   <€ V ^8„  d   QhRS[ RS[/# )r?   Úraise_on_errorrB   )rm   r   )rF   rñ  s   "€r;   rG   rÚ  ™  s    ø€ ÷ 9^ñ 9^Áð 9^ÑQTñ 9^r=   c                ó  a aa	€ ^ RI HoHp ^ RIHo	 ^ RIHp \        V! 4       4      p\        S RR4      pVf&   V! S P                  S P                  R7      pVS n        VV	V 3R lpR V 3R	 llpVP                  WFWR
7      # )uÈ  AsyncSessionDB for the active profile scope, resolved per access (not in ``__init__``) since
``SessionDB()`` reads the context-local HERMES_HOME; one handle cached per path. Construction
failure enters bounded backoff; ``raise_on_error=True`` (priming) propagates it.

Same per-path cache as ``SessionStore._open_session_db_for_active_scope`` (#88532): ``SessionDB()``
resolves ``_default_db_path()`` at call time through the context-local HERMES_HOME override
installed by ``_profile_runtime_scope``, so resolving per access â€” instead of once in ``__init__`` â€”
is what lets /resume, /title, /history and session search on a multiplexed gateway read the *serving
profile's* store rather than the root one.
One ``AsyncSessionDB`` is cached per resolved path, so the wrapper identity is stable per profile
(callers compare and stash it) and two profiles never share a handle. A construction failure enters
bounded backoff; one caller retries after the deadline while concurrent callers continue to see the
unavailable fallback. ``raise_on_error=True`` (construction-time priming) propagates the failure
after recording that recoverable state so ``__init__`` can record ``_session_db_init_error`` for the
#88235 broadcast.
)ÚAsyncSessionDBÚ_default_db_path)Úacquire)ÚRecoverableHandleCacheÚ_session_db_handle_cacheN)Úhandlesr‚   c                  ó  <€ \        SR R4      p V e   \        V RR4      MRpVe   S! V4      pRVP                  R&   V# V e   \        R4      h S! S! 4       4      #   \         d   p\        P                  RT4       h Rp?ii ; i)Úsession_storeNr7   TÚ_hermes_borrowed_handlez&SessionStore SQLite handle unavailablez&SQLite session store not available: %s)r8   rÞ  rÝ  rL   rM   r¬   )ÚstoreÚborrowedÚwrapperrY   r  r
  rÃ  s       €€€r;   Ú_openÚ>GatewayRunner._open_session_db_for_active_scope.<locals>._openµ  s”   ø€ ô ˜D /°4Ó8ˆEØ6;Ò6G”w˜u e¨TÔ2ÈTˆHØÒ#Ù(¨Ó2�à>B�× Ñ Ð!:Ñ;Ø�ØÒ ä"Ð#KÓLÐLðÙ%¡g£iÓ0Ð0øÜô Ü—‘ÐGÈÔMØûðús   ÁA ÁBÁ'A>Á>Bc                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   ÚEGatewayRunner._open_session_db_for_active_scope.<locals>.__annotate__Î  s   € ÷ 	:ñ 	:˜Dñ 	:r=   c                  ó@   <€ R S n         \        P                  R4       R # )NzSQLite session store recovered)rõ  rM   r  ©rÃ  s   €r;   Ú
_recoveredÚCGatewayRunner._open_session_db_for_active_scope.<locals>._recoveredÎ  s   ø€ Ø*.ˆDÔ'Ü�K‰KÐ8Ö9r=   )r  Úon_recovered)Úhermes_stater  r	  Úhermes_state_registryr
  Úgateway.session_db_recoveryr  r   r8   Ú_session_db_handlesÚ_session_db_handles_lockr  r~   )
rÃ  r  r	  r  r  r�   r  r  r  r
  s
   f&      @@r;   Ú!_open_session_db_for_active_scopeÚ/GatewayRunner._open_session_db_for_active_scope™  sy   ú€ ÷" 	BÝ1ÝFÜÑ$Ó&Ó'ˆÜ˜Ð8¸$Ó?ˆØŠ=á*Ø×0Ñ0°t×7TÑ7TôVˆEà,1ˆDÔ)÷	÷2	:ð 	:ð �y‰y˜°^ˆyÓ]Ð]r=   c                ó    <€ V ^8„  d   QhRS[ /# rÖ   rÐ  )rF   rñ  s   "€r;   rG   rÚ  Õ  s   ø€ ÷ 8ñ 8™Sñ 8r=   c                ób   € V P                   \        Jd   V P                   # V P                  4       # )u¬   The AsyncSessionDB for the active profile scope, or a pinned override (assigning
``runner._session_db`` pins it for every later read â€” tests install fakes/None this way).)Ú_session_db_pinnedÚ_SESSION_DB_UNPINNEDr"  r  s   &r;   r6   ÚGatewayRunner._session_dbÔ  s.   € ð ×"Ñ"Ô*>Ó>Ø×*Ñ*Ð*Ø×5Ñ5Ó7Ð7r=   c                ó   <€ V ^8„  d   QhRR/# rð   rº   )rF   rñ  s   "€r;   rG   rÚ  Ý  s   ø€ ÷ (ñ ( Dñ (r=   c                ó   € Wn         R # rÇ   )r&  )rÃ  r  s   &&r;   r6   r(  Ü  s   € à"'Ör=   c                ó   <€ V ^8„  d   QhRR/# rð   rº   )rF   rñ  s   "€r;   rG   rÚ  à  s   ø€ ÷ 8ñ 8¨dñ 8r=   c                óH   € R R lpV P                   P                  V4       R# )a   Close every per-profile AsyncSessionDB this runner opened.

Drained under the lock, closed outside it; a pinned handle is the pinner's to close. Wrappers
BORROWED from ``session_store`` are skipped: the store's sweep (runs first) closes them.

See #98573.
c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   Ú@GatewayRunner.close_all_session_db_handles.<locals>.__annotate__è  s   € ÷ 	Sñ 	S˜$ñ 	Sr=   c                 ó  € \        V R / 4      P                  R4      '       d   R# \        V RV 4      pVe   \        VR4      '       g   R# ^ RIHp  V! V4       R#   \
         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)rÞ  r  Nr7   Úclose)Úrelease_or_closez-SessionDB close error during handle sweep: %s)r8   r~   rI  r  r1  rL   rM   rN   )ÚdbÚinnerr1  rY   s   &   r;   Ú_closeÚ:GatewayRunner.close_all_session_db_handles.<locals>._closeè  sy   € Ü�r˜: rÓ*×.Ñ.Ð/H×IÒIÙÜ˜B  rÓ*ˆEØŠ}¤G¨E°7×$;Ò$;Ùõ ?ðSÙ  Ö'øÜô SÜ—‘ÐLÈc×RÒRûðSús   ÁA ÁBÁ&BÂBN)r  Ú	close_all)rÃ  r4  s   & r;   Úclose_all_session_db_handlesÚ*GatewayRunner.close_all_session_db_handlesà  s   € õ	Sð 	×%Ñ%×/Ñ/°Ö7r=   c                ó   <€ V ^8„  d   QhRR/# rð   rº   )rF   rñ  s   "€r;   rG   rÚ  ø  s   ø€ ÷ ^ñ ^¨dñ ^r=   c                ó  € \         P                  V P                  9  d   R# \        4       '       g   \        P                  R4       R#  ^ RIHp  T! T 4      pT'       d   \        P                  R4       R# T P                  '       d#   \        P                  RT P                  4       R# R#   \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i  \         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)z_Bind the Teams meeting pipeline runtime to Graph webhook ingress (no-op if adapter/plugin off).Nz:Teams pipeline plugin is disabled; skipping runtime wiring)Úbind_gateway_runtimez(Teams pipeline runtime import failed: %sz(Teams pipeline runtime wiring failed: %sz7Teams pipeline runtime bound to msgraph webhook ingressz&Teams pipeline runtime unavailable: %s)rt  ÚMSGRAPH_WEBHOOKrô  r  rM   rN   Úplugins.teams_pipeline.runtimer;  rL   r¬   r  Ú_teams_pipeline_runtime_error)rÃ  r;  rY   Úbounds   &   r;   Ú_wire_teams_pipeline_runtimeÚ*GatewayRunner._wire_teams_pipeline_runtimeø  sÉ   € ä×#Ñ#¨4¯=©=Ô8ÙÜ-×/Ò/Ü�L‰LÐUÔVÙð	ÝKð	Ù(¨Ó.ˆE÷ Ü�K‰KÐQÖRØ×/×/Ð/Ü�N‰NØ8¸$×:\Ñ:\ö^ñ 0øô ô 	Ü�N‰NÐEÀsÔKÝûð	ûô
 ô 	Ü�N‰NÐEÀsÔKÝûð	ús0   Á
B. ÁC Â.CÂ9CÃCÃD	Ã(DÄD	c                ó   <€ V ^8„  d   QhRR/# rð   rº   )rF   rñ  s   "€r;   rG   rÚ    s   ø€ ÷ Qñ Q¸ñ Qr=   c                ó‚  € \         P                  ! RR4      P                  4       P                  4       R8w  d   R# V P                  P                  4       pV Uu. uF:  q"\        P                  \        P                  \        P                  09  g   K8  VNK<  	  ppV'       g   R# \         P                  ! RR4      P                  4       p. pV'       d`    \        P                  ! V4      p\        V\        4      '       d3   V Uu. uF&  p\        V\        4      '       g   K  \        V4      NK(  	  ppV F?  p\$        P'                  V4      p	V	'       g   K"  V	P)                  R	4      \*        9   g   K>   R# 	  \         P-                  R
4       R# u upi u upi   \         d    \         P#                  RRR7        LŠi ; i)z³Warn when Docker-backed gateways lack an explicit export mount: MEDIA delivery runs in the
gateway process, so model-emitted paths like `/output/report.txt` must be host-readable.r  r”   ÚdockerNr-  zACould not parse TERMINAL_DOCKER_VOLUMES for gateway media warningTrG  Ú	containeraF  Docker backend is enabled for the messaging gateway but no explicit host-visible output mount (for example '/home/user/.hermes/cache/documents:/output') is configured. This is fine if the model already emits host-visible paths, but MEDIA file delivery can fail for container-local paths like '/workspace/...' or '/output/...'.)rþ   r;  rá   r¢   râ   Úget_connected_platformsrt  r  Ú
API_SERVERÚWEBHOOKrã  rä  r   rŒ   rD   rL   rM   rN   Ú_DOCKER_VOLUME_SPEC_RErâ  rè  Ú$_DOCKER_MEDIA_OUTPUT_CONTAINER_PATHSr¬   )
rÃ  Ú	connectedÚpÚmessaging_platformsÚraw_volumesÚvolumesÚparsedr  r¹  râ  s
   &         r;   rø  Ú5GatewayRunner._warn_if_docker_media_delivery_is_risky  sX  € ô �9Š9�^ RÓ(×.Ñ.Ó0×6Ñ6Ó8¸HÔDÙØ—K‘K×7Ñ7Ó9ˆ	Ù*3Óx©) QÄÇÁÔQY×QdÑQdÔfn×fvÑfvÐ@wÑ7wŸq˜q©)ÐÐxß"Ùä—i’iÐ 9¸2Ó>×DÑDÓFˆØˆßðqÜŸš KÓ0�Ü˜f¤d×+Ò+Ù/5ÓL©v¨!¼ÀAÄs×9Kœvœs 1žv©v�GÐLó ˆDÜ*×0Ñ0°Ó6ˆEß‰u˜Ÿ™ [Ó1Ô5YÖYÚñ ô 	�‰ðPö	Qùò% yùò MøÜô qÜ—‘Ð`Ðko�Öpðqús6   Á5FÂFÃ0F ÄFÄ"FÄ1F ÆF Æ"F>Æ=F>zgateway_voice_mode.jsonc                ó   € V P                   # rÇ   )Ú_exit_cleanlyr  s   &r;   rš   ÚGatewayRunner.<lambda>/  s
   € °×0BÒ0Br=   c                ó   € V P                   # rÇ   )Ú_exit_with_failurer  s   &r;   rš   rT  0  s
   € °T×5LÒ5Lr=   c                ó   € V P                   # rÇ   )Ú_exit_reasonr  s   &r;   rš   rT  1  s
   € ¨×(9Ò(9r=   c                ó   € V P                   # rÇ   )Ú
_exit_coder  s   &r;   rš   rT  2  s   €  d§o¢or=   c                ó&   <€ V ^8„  d   QhRS[ RS[/# rª  )r›  rD   )rF   rñ  s   "€r;   rG   rÚ  4  s   ø€ ÷ ñ ©mð Áñ r=   c           	     ó<  € \        V R4      '       dK   V P                  e=    V P                  P                  V4      p\        V\        4      '       d   V'       d   V# \        V RR4      p^ RIHp V! V4      pRpVe   VP                  pMJ\        VRR4      '       d8   VP                  '       d   VP                  pM ^ RIHp V! 4       ;'       g    Rp\        V\        VR	R
4      \        VRR4      VR7      #   \
         d     Lªi ; i  \
         d    Rp LEi ; i)zUResolve the current session key for a source, honoring gateway config when available.r  Nrâ   ©Úidentity_ofrr  F©rX  r•   Úgroup_sessions_per_userTÚthread_sessions_per_user)r`  ra  r1  )rI  r  Ú_generate_session_keyr   rD   rL   r8   Úgateway.session_identityr^  Úsession_key_profiler1  rS  rX  r�  )rÃ  r™  r@   râ   r^  ÚidentityÚ_profilerX  s   &&      r;   Ú_session_key_for_sourceÚ%GatewayRunner._session_key_for_source4  s  € ä�4˜×)Ò)¨d×.@Ñ.@Ò.LðØ"×0Ñ0×FÑFÀvÓN�Ü˜k¬3×/Ò/·KØ&Ð&ô ˜˜x¨Ó.ˆõ 	9Ù˜vÓ&ˆØˆØÒØ×3Ñ3‰HÜ�VÐ1°5×9Ò9Ø�~�~ˆ~Ø!Ÿ>™>‘ð$ÝKÙ6Ó8×EÐE¸I�Hô !Ø¬G°FÐ<UÐW[Ó,\Ü%,¨VÐ5OÐQVÓ%WØôð 	øô) ô Ùðûô$ !ô $Ø#’Hð$ús/   ¢8C: ÁC: Â>D ÃD Ã:DÄDÄDÄDr”   rÛ   r0   c                ó&   <€ V ^8„  d   QhRS[ RS[ /# rª  ©r›  )rF   rñ  s   "€r;   rG   rÚ  X  s   ø€ ÷ añ a¹ð aÉ-ñ ar=   c                ó†   €  V P                  V4      pTf   T# \        P                  ! YR7      #   \         d    Tu # i ; i)u^  Apply Telegram DM topic recovery to a source for session-key purposes. Always derive override
storage keys from the result: ``_handle_message_with_agent`` rewrites ``thread_id`` before
deriving the session key, so keys from the raw ``event.source`` are never read next turn.

``_handle_message_with_agent`` rewrites ``source.thread_id`` via
``_recover_telegram_topic_thread_id`` *before* deriving the session key for a normal message turn (a
lobby/stripped reply gets pinned to the user's last-active topic). Session-scoped command handlers
like ``/model`` and ``/reasoning`` derive their override key from the raw inbound ``event.source``,
which skips that recovery â€” so the override is stored under a different key than the next message
turn reads, and the override is silently dropped on Telegram forum topics and after compression
session splits (#30479).
)r  )Ú!_recover_telegram_topic_thread_idrL   ÚdataclassesrØ  )rÃ  r™  Ú	recovereds   && r;   Ú!_normalize_source_for_session_keyÚ/GatewayRunner._normalize_source_for_session_keyX  sJ   € ð	Ø×>Ñ>¸vÓFˆIð #Ò*ˆvÐ`´×0CÒ0CÀFÔ0`Ð`øô ô 	ØŠMð	ús   ‚0 °A ¿A c                óF   <€ V ^8„  d   QhRS[ S[,          RS[ S[,          /# râ  rÇ  )rF   rñ  s   "€r;   rG   rÚ  k  s&   ø€ ÷ ñ ÁÉÅð ÑRZÑ[^ÕR_ñ r=   c                óf   € V'       g   Vf   V#  V P                  V4      #   \         d     R# i ; i)zW``session_key`` if given, else the key for ``source`` (None when it cannot be derived).N)rg  rL   )rÃ  r™  r@   s   &&&r;   Ú_resolve_session_key_or_noneÚ*GatewayRunner._resolve_session_key_or_nonek  s7   € ç˜&š.ØÐð	Ø×/Ñ/°Ó7Ð7øÜô 	Úð	ús   �! ¡0¯0c                ó    <€ V ^8„  d   QhRS[ /# rÖ   r  )rF   rñ  s   "€r;   rG   rÚ  t  s   ø€ ÷ )ñ )¡cñ )r=   c                ó,   € \        V P                  4      # rÇ   )rU   rÇ  r  s   &r;   Ú_running_agent_countÚ"GatewayRunner._running_agent_countt  s   € Ü�4×'Ñ'Ó(Ð(r=   c                ó    <€ V ^8„  d   QhRS[ /# rÖ   r_   )rF   rñ  s   "€r;   rG   rÚ  w  s   ø€ ÷ Dñ D¡cñ Dr=   c                ó.   € V P                   '       d   R # R# )ÚrestartÚshutdown)Ú_restart_requestedr  s   &r;   Ú_status_action_labelÚ"GatewayRunner._status_action_labelw  s   € Ø ×3×3Ð3ˆyÐC¸ÐCr=   c                ó    <€ V ^8„  d   QhRS[ /# rÖ   r_   )rF   rñ  s   "€r;   rG   rÚ  z  s   ø€ ÷ zñ z¡sñ zr=   c                óR   € V P                   '       d   \        R4      # \        R4      # )zRLocalized "restarting" / "shutting down" for the busy/drain notices shown in chat.zgateway.busy.action_restartingz!gateway.busy.action_shutting_down)r}  r   r  s   &r;   Ú_status_action_gerundÚ#GatewayRunner._status_action_gerundz  s%   € à6:×6M×6MÐ6MŒqÐ1Ó2ÐyÔSTÐUxÓSyÐyr=   c                óJ   <€ V ^8„  d   QhRS[ S[,          RS[ S[,          RR/# )r?   Úgateway_stateÚexit_reasonrB   NrÇ  )rF   rñ  s   "€r;   rG   rÚ  ~  s.   ø€ ÷ 	%ñ 	%±H¹SµMð 	%ÑW_Ñ`cÕWdð 	%Ðptñ 	%r=   c                ó°   € \        V R R4      '       d   R# VR8X  d   V P                  4       MRp\        WV P                  V P	                  4       VR7       R# )Ú_startup_cleanup_onlyFNÚdraining)r…  r†  Úrestart_requestedÚactive_agentsÚactive_work)r8   Ú_describe_active_workr¨  r}  Ú_active_work_count)rÃ  r…  r†  rŒ  s   &&& r;   Ú_update_runtime_statusÚ$GatewayRunner._update_runtime_status~  sR   € Ü�4Ð0°%×8Ò8Ùð 7DÀzÔ6Q�d×0Ñ0Ô2ÐW[ˆÜ#Ø'Ø"×5Ñ5ÀT×E\ÑE\ÓE^Ø#÷	%r=   c                ó   <€ V ^8„  d   QhRR/# rð   rº   )rF   rñ  s   "€r;   rG   rÚ  ‰  s   ø€ ÷ Mñ M¨ñ Mr=   c                ó:   € \        V P                  4       R7       R# )a  Persist the live in-flight agent count to ``gateway_state.json`` at every turn boundary.
Passes ONLY ``active_agents`` so the read-merge-write keeps lifecycle state (gateway_state=None
would clobber it). Best-effort: a failed write must never disrupt a turn.)r‹  N)r¨  rŽ  r  s   &r;   Ú_persist_active_agentsÚ$GatewayRunner._persist_active_agents‰  s   € ô 	$°$×2IÑ2IÓ2K×Lr=   c                ó    <€ V ^8„  d   QhRS[ /# rÖ   )r   )rF   rñ  s   "€r;   rG   rÚ  �  s   ø€ ÷ Gñ G¡Cñ Gr=   c                óŒ   € V P                  4        UUu0 uF"  w  rVf   K  V\        Jg   K  \        V4      kK$  	  upp# u uppi )u’   ``id()`` of every agent mid-turn â€” identity-keyed so the lookup is O(1) and independent of
``AIAgent.__eq__`` (MagicMock overrides it in tests).)rï  r£   r4  )rÃ  rû  Úas   &  r;   Ú_running_agent_idsÚ GatewayRunner._running_agent_ids�  sO   € ð #'×";Ñ";Ô"=ô GÑ"=™$˜!Øô Ø%&Ô.EÐ%Eô ”�1–Ñ"=ò Gð 	Gùó Gs   ”A ¡A ­A c                ó6   <€ V ^8„  d   QhRS[ S[S[3,          /# rÖ   )rà   rD   r   )rF   rñ  s   "€r;   rG   rÚ  •  s   ø€ ÷ bñ b©$©s±C¨x­.ñ br=   c                ón   € V P                  4        UUu/ uF  w  rV\        Jg   K  WbK  	  upp# u uppi rÇ   )rï  r£   )rÃ  r©  r—  s   &  r;   Ú_snapshot_running_agentsÚ&GatewayRunner._snapshot_running_agents•  s3   € Ø!%×!:Ñ!:Ô!<ÔaÑ!<™˜ÀÔI`Ð@`”�’Ñ!<ÒaÐaùÓas   ”1§1c                   ó,   a € ] tR tRt o V 3R ltRtV tR# )ÚGatewayRunner._BusySteerOutcomeiž  c                óV   <€ V ^8„  d   Qh/ S[ ;R&   S[;R&   S[;R&   S[;R&   S[;R&   # )r?   Úeffective_modeÚdemoted_for_subagentsÚdemoted_for_compressionÚsteeredÚ
redirectedrd  )rF   rñ  s   "€r;   rG   Ú,GatewayRunner._BusySteerOutcome.__annotate__ž  sC   ø‡ ‚ áÑñ ñ  $Ñ#ñ ñ "&Ñ%ñ	 ñ
 ‰ñ ñ Ñò r=   rº   N)r6  rD  rE  rF  rô  rH  rõ  rö  s   @r;   Ú_BusySteerOutcomerŸ  ž  s   ø‡ ‡ „ r=   r§  g      $@z.restart_failure_countsr“  r†   r  zgateway.busy.reject_modelzcodex-runtimez!gateway.busy.reject_codex_runtimeÚmoazgateway.busy.reject_moac                ó    <€ V ^8„  d   QhRS[ /# rÖ   r_   )rF   rñ  s   "€r;   rG   rÚ  Ç  s   ø€ ÷ ñ ¡cñ r=   c                óV   €  ^ RI Hp V! 4       ;'       g    R#   \         d     R# i ; i)z0Return the profile name this gateway represents.r_  r•   )rS  rX  rL   )rÃ  rX  s   & r;   Ú_active_profile_nameÚ"GatewayRunner._active_profile_nameÇ  s-   € ð	ÝCÙ*Ó,×9Ð9°	Ð9øÜô 	Úð	ús   ‚ – ™(§(Úallow_adapter_delegationTc                ó,   <€ V ^8„  d   QhRS[ RS[RS[/# )r?   r™  r­  rB   ©r›  rm   )rF   rñ  s   "€r;   rG   rÚ  Ï  s*   ø€ ÷ 
Añ 
AÙ#ð
AÙBFð
AÙRVñ
Ar=   c               óB   a aa€ R VV V3R llpS P                  SV4      # )zºAuthorize under the live transport's profile, not the routed runtime (which need not copy the
shared bot token/allowlist); the transport home is stamped on the source for this read only.c                ó$   € V ^8„  d   QhR\         /# rÖ   r×   )rF   s   "r;   rG   ÚBGatewayRunner._is_user_authorized_for_source.<locals>.__annotate__Ó  s   € ÷ 	Tñ 	Tœñ 	Tr=   c                  ó\   <€ S '       d   SP                  S4      # SP                  SR R7      # )F)r­  )Ú_is_user_authorized)r­  rÃ  r™  s   €€€r;   Ú_checkÚ<GatewayRunner._is_user_authorized_for_source.<locals>._checkÓ  s-   ø€ ç'Ø×/Ñ/°Ó7Ð7Ø×+Ñ+¨FÈUÐ+ÓSÐSr=   ©Ú_under_authorization_profile)rÃ  r™  r­  rµ  s   ffd r;   Ú_is_user_authorized_for_sourceÚ,GatewayRunner._is_user_authorized_for_sourceÏ  s$   ú€ ÷	Tò 	Tð ×0Ñ0°¸Ó@Ð@r=   c                ó&   <€ V ^8„  d   QhRS[ RS[/# rª  r¯  )rF   rñ  s   "€r;   rG   rÚ  Û  s   ø€ ÷ bñ b±Mð bÁdñ br=   c                ó4   a a€ S P                  SV V3R l4      # )zœCount a bot message under the profile that authorized it, so the guard's peek, count and
config all read the transport profile's ``gateway.bot_loop_guard``.c                  ó&   <€ S P                  S4      # rÇ   )Ú_admit_bot_messagerÂ  s   €€r;   rš   Ú=GatewayRunner._admit_bot_message_for_source.<locals>.<lambda>Þ  s   ø€ À×AXÑAXÐY_ÔA`r=   r·  rÂ  s   ffr;   Ú_admit_bot_message_for_sourceÚ+GatewayRunner._admit_bot_message_for_sourceÛ  s   ù€ ð ×0Ñ0°Õ9`ÓaÐar=   c                ó    <€ V ^8„  d   QhRS[ /# )r?   r™  rj  )rF   rñ  s   "€r;   rG   rÚ  à  s   ø€ ÷ ñ ±=ñ r=   c                ó¾   € V P                  V4      pVf   V! 4       # \        \        V4      4      ;_uu_ 4        V! 4       uuR R R 4       #   + '       g   i     R # ; irÇ   )Ú_authorization_home_for_sourcer°  r   )rÃ  r™  ÚcheckÚauthorization_homes   &&& r;   r¸  Ú*GatewayRunner._under_authorization_profileà  sE   € Ø!×@Ñ@ÀÓHÐØÒ%Ù“7ˆNÜ#¤DÐ);Ó$<×=Õ=Ù“7÷ >×=×=Ó=ús   ¹AÁA	c                ó$   <€ V ^8„  d   QhRS[ RR/# r^   r_   )rF   rñ  s   "€r;   rG   rÚ  ç  s   ø€ ÷ ñ ±ð Àñ r=   c                ó”  € V'       d   Vf   R # \        V RR 4      pVf   \        4       pW0n         \        P                  ! V4      W1&    TP                  T4       \        T RR4      p\        T4      T8”  d   TP                  RR7       K$  R #   \
         d    \        P                  RTRR7        R # i ; i  \
         d     R # i ; i)	NÚ_session_sourcesz*Failed to cache live session source for %sTrG  Ú_session_sources_maxi   F)Úlast)r8   r   rÊ  rm  rØ  rL   rM   rN   Úmove_to_endrU   Úpopitem)rÃ  r@   r™  Úcached_sourcesÚmax_sizes   &&&  r;   Ú_cache_session_sourceÚ#GatewayRunner._cache_session_sourceç  sÆ   € ß˜fšnÙÜ  Ð'9¸4Ó@ˆØÒ!Ü(›]ˆNØ$2Ô!ð	Ü*5×*=Ò*=¸fÓ*EˆNÑ'ð	Ø×&Ñ& {Ô3Ü˜tÐ%;¸SÓAˆHÜ�nÓ%¨Ô0Ø×&Ñ&¨EÐ&Ö2ñ 1øô ô 	Ü�L‰LÐEÀ{Ð]aˆLÔbÚð	ûô ô 	Úð	ús$   ±B Á
AB8 Â#B5Â4B5Â8CÃCc                ó    <€ V ^8„  d   QhRS[ /# rÖ   )r™  )rF   rñ  s   "€r;   rG   rÚ  ü  s   ø€ ÷ ñ Ñ%6ñ r=   c                ó’   € \        V RR4      pVe   VP                  V P                  Jd   \        V P                  4      pWn        V# )z>Return the single async facade for this runner's SessionStore.Ú_async_session_storeN)r8   Ú_storer  r™  rÕ  )rÃ  Úfacades   & r;   Úasync_session_storeÚ!GatewayRunner.async_session_storeû  sD   € ô ˜Ð5°tÓ<ˆØŠ>˜VŸ]™]°$×2DÑ2DÓDÜ& t×'9Ñ'9Ó:ˆFØ(.Ô%Øˆr=   c                ó    <€ V ^8„  d   QhRS[ /# ry   r_   )rF   rñ  s   "€r;   rG   rÚ    s   ø€ ÷ ñ ±cñ r=   c                ó   € V'       d   \        V R R4      MRpV'       g   R# VP                  V4      pVe4   \        \        4      ;_uu_ 4        VP	                  V4       RRR4       V# V#   + '       g   i     T# ; i)rÊ  N)r8   r~   r}   rL   rÍ  )rÃ  r@   rÏ  r™  s   &&  r;   Ú_get_cached_session_sourceÚ(GatewayRunner._get_cached_session_source  sg   € ßDOœ Ð'9¸4Ô@ÐUYˆßÙØ×#Ñ# KÓ0ˆØÒÜœ)×$Õ$Ø×*Ñ*¨;Ô7÷ %àˆˆvˆ÷ %Ö$àˆús   ÁA,Á,A=	c                   ó0   a € ] tR tRt o RtV 3R ltRtV tR# )ÚGatewayRunner._HygieneSettingsi  z<Resolved session-hygiene configuration for one inbound turn.c                óö   <€ V ^8„  d   Qh/ S[ ;R&   S[;R&   S[;R&   S[;R&   S[;R&   S[;R&   S[;R&   S[;R&   S[S[,          ;R	&   S[S[ ,          ;R
&   S[S[ ,          ;R&   S[S[ ,          ;R&   S[;R&   # )r?   r  Úthreshold_pctÚcompression_enabledÚhard_msg_limitr‹   Útotal_ceiling_secondsÚmax_turn_hold_secondsr…   r  rV  rZ  rÔ  r  )rD   rE   rm   rQ   r   r   )rF   rñ  s   "€r;   rG   Ú+GatewayRunner._HygieneSettings.__annotate__  s¼   ø‡ ‚ ñ ‰
ñ ñ Ññ	 ñ
 "Ñ!ñ ñ Ññ ñ Ññ ñ  %Ñ$ñ ñ  %Ñ$ñ ñ #(Ñ'ñ ñ  (©�}Ñ,ñ ñ ™3•-Ññ ñ ™3•-Ññ ñ ™#•Ññ ñ ‰	ò r=   rº   Nró  rö  s   @r;   Ú_HygieneSettingsrß    s   ø‡ € áJ÷ ƒ r=   rç  c                   óD   a € ] tR tRt o RtRtRtRtRtRt	V 3R lt
RtV tR# )ÚGatewayRunner._HygieneAttempti  z¶One detached hygiene compression attempt. ``cleanup_deferred`` is shared mutable state: wait
handlers set it on raise paths; the owning ``finally`` reads it to decide on cleanup now.NrÈ  Fc                ón   <€ V ^8„  d   Qh/ S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[;R&   S[;R&   S[ ;R&   # )r?   r™   ÚmetaÚcommit_fencerD  Úwait_startedÚcleanup_deferredrŠ   )r   rE   rm   )rF   rñ  s   "€r;   rG   Ú*GatewayRunner._HygieneAttempt.__annotate__  s^   ø‡ ‚ ñ ‰
ñ	 ñ
 ‰	ñ ñ Ñ ñ ñ Ññ ñ Ñ!ñ ñ Ñ&ñ ñ Ñò r=   rº   )r6  rD  rE  rF  rG  rì  rD  rí  rî  rŠ   rô  rH  rõ  rö  s   @r;   Ú_HygieneAttemptré    s.   ø‡ € ñ	eð !ˆØˆØ!ˆØ!&ÐØˆ÷ ƒ r=   rð  c                ó\   <€ V ^8„  d   QhRS[ S[,          RS[ S[S[S[3,          ,          /# )r?   Úreply_to_message_idrB   )r   rD   rà   r   )rF   rñ  s   "€r;   rG   rÚ  +  s1   ø€ ÷ $ñ $Ù+3±C­=ð$ÙDLÉTÑRUÑWZÐRZÍ^ÕD\ñ$r=   c                óÈ  € T P                  \        VRR4      \        VRR4      \        VRR4      \        VRR4      T;'       g    \        VRR4      R7      p\        VRR4      \        P                  8X  d”   \        VRR4      p\        VR	R4      pV'       g	   V'       dj   \	        T;'       g    / 4      pV'       d*   \        V4      VR
&   VP                  R\        V4      4       V'       d   VP                  R	\        V4      4       ^ RIHp V! W4      p\        \        VRR4      ;'       g    R4      P                  4       pV'       d   Ve   \	        V4      pWsR&   V# )z@Build the metadata dict platforms need for thread-aware replies.rç   Nr¬  r  r0  Ú
message_id)r0  rò  Úscope_idrÖ  Úslack_team_id)Úsource_route_metadatar1  r”   Úhermes_profile)
Ú_thread_metadata_for_targetr8   rt  ru  rà   rD   Ú
setdefaultÚgateway.session_contextr÷  rá   )rÃ  r™  rò  r  Úteam_idrÖ  r÷  r1  s   &&&     r;   Ú_thread_metadata_for_sourceÚ)GatewayRunner._thread_metadata_for_source+  s6  € ð ×3Ñ3Ü�F˜J¨Ó-¬w°v¸yÈ$Ó/OÜ�F˜K¨Ó.¼'À&È+ÐW[Ó:\Ø 3× ZÐ Z´w¸vÀ|ÐUYÓ7Zð 4ó \ˆô �6˜: tÓ,´·±Ô>ô ˜f j°$Ó7ˆGÜ˜f i°Ó6ˆGßŸ'Ü § ¨BÓ/�ßÜ03°G³�H˜_Ñ-Ø×'Ñ'¨
´C¸³LÔAßØ×'Ñ'¨	´3°w³<Ô@ÝAÙ(¨Ó:ˆô ”g˜f i°Ó6×<Ð<¸"Ó=×CÑCÓEˆß�xÒ+Ü˜H“~ˆHØ)0Ð%Ñ&Øˆr=   r0  rò  r«  c                óÊ   <€ V ^8„  d   QhRS[ S[,          RS[ S[,          RS[ S[,          RS[ S[,          RS[ S[,          RS[ S[,          RS[ S[S[S[3,          ,          /# )r?   rç   r¬  r  r0  rò  r«  rB   )r   rt  rD   r   rà   )rF   rñ  s   "€r;   rG   rÚ  Q  sp   ø€ ÷ ñ Ù ¡Õ*ðÙ5=¹cµ]ðÙOWÑX[Í}ðá™C•=ðá>FÁs½mðñ ™#•ðñ +3±4¹¹S¸µ>Õ*Bñr=   c               ó  € Vf   R# RV/pV P                  WW4VR7      '       d6   RVR&   \        V4      pV'       d   VR	9  d   W‡R&   Ve   \        V4      VR&   V\        P                  8X  d   Ve   \        V4      VR&   V# )
zGBuild thread metadata for synthetic sends that only have routing state.Nr  )r0  r«  TÚ telegram_dm_topic_reply_fallbackÚdirect_messages_topic_idÚtelegram_reply_to_message_idrô  >   r”   rÛ   )Ú_is_telegram_dm_topic_targetrD   rt  ru  )	rÃ  rç   r¬  r  r0  rò  r«  r  Útids	   &&&&$$$  r;   rù  Ú)GatewayRunner._thread_metadata_for_targetQ  s�   € ð
 ÒÙØ$/°Ð#;ˆØ×,Ñ,Ø˜yÀwð -÷ Pò Pà;?ˆHÐ7Ñ8ä�i“.ˆCß�s )Ô+Ø7:Ð3Ñ4Ø"Ò.Ü;>Ð?RÓ;S�Ð7Ñ8Ø”x—~‘~Ô%Ð*=Ò*Iä%(Ð)<Ó%=ˆH�\Ñ"Øˆr=   c                óŽ   <€ V ^8„  d   QhRS[ S[,          RS[ S[,          RS[ S[,          RS[ S[,          RS[ S[,          RS[/# )r?   rç   r¬  r  r0  r«  rB   )r   rt  rD   r   rm   )rF   rñ  s   "€r;   rG   rÚ  h  sS   ø€ ÷ ñ Ù™8Õ$ðÙ/7¹­}ðÙIQÑRUÍðá™C•=ðá2:¹3µ-ðáKOñr=   c               ó`  € V \         P                  8w  g   Vf   R# VR8X  d   R# Ve]   V'       dU   \        \        V4      RR4      p\	        V4      '       d.    V! V\        V4      \        V4      4      p\        V\        4      # R#   \         d    \        P                  RRR7        R# i ; i)z>Return True when a target is a Telegram private DM topic lane.NFr2  TÚ_get_dm_topic_infoz,Failed to inspect Telegram DM topic metadatarG  )rt  ÚTELEGRAMr8   r5  rO   rD   r   rà   rL   rM   rN   )rç   r¬  r  r0  r«  Úget_dm_topic_infoÚ
topic_infos   &&&$$  r;   r  Ú*GatewayRunner._is_telegram_dm_topic_targetg  s¦   € ð
 ”x×(Ñ(Ô(¨IÒ,=ÙØ˜ÔÙð Ò§7Ü '¬¨W«Ð7KÈTÓ RÐÜÐ)×*Ò*ð8Ù!2°7¼CÀ»LÌ#ÈiË.Ó!Y�Jô & j´$Ó7Ð7Ùøô	 !ô `Ü—L‘LÐ!OÐZ^�LÕ_ñ ð	`ús   ÁB Â"B-Â,B-c                ó&   <€ V ^8„  d   QhRS[ RS[/# )r?   r@  rB   )rœ  rŒ   )rF   rñ  s   "€r;   rG   rÚ  ‡  s   ø€ ÷ Vñ V©ð V¹4ñ Vr=   c                óÎ  € ^ RI Hp \        V RR4      ;'       g    / P                  VP                  P
                  4      p\        VRR4      p^ RIHp V! 4       pVP                  RR4      pT! R/ RVP                  P
                  P                  bR	VP                  P                  bR
VP                  P                  '       d    \        VP                  P                  4      MRbRVP                  P                  ;'       g    RbRVP                  P                  '       d    \        VP                  P                  4      MRbRVP                  P                  '       d    \        VP                  P                  4      MRbRVP                  P                   '       d    \        VP                  P                   4      MRbRVP                  P"                  '       d    \        VP                  P"                  4      MRbR\        \        VP                  RR4      ;'       g    R4      bR\        \        VP                  RR4      ;'       g    R4      bRVP$                  bRVP&                  ;'       g    RbRVP                  P(                  '       d    \        VP                  P(                  4      MRbR\        VP                  RR4      ;'       g    RbRVbRRbRVbVB # )z±Set session context variables (contextvars, not os.environ, so concurrent messages can't
overwrite each other). Returns reset tokens for ``_clear_session_env`` in a ``finally``.)Úset_session_varsrô  NÚsupports_async_deliveryT)Úapi_session_varsÚsession_history_deliveryrç   r¬  r0  r”   r¬  r  rÖ  Úuser_id_altÚ	user_namerõ  Úparent_chat_idr@   rˆ   rô  r1  Úasync_deliveryÚcron_sessionrº   )rû  r  r8   r~   r™  rç   Úgateway.session_api_turnr  r   r  r¬  r0  rD   r¬  r  rÖ  r  r  r@   rˆ   rô  )rÃ  r@  r  Ú_adapterÚ_async_deliveryr  Ú	_api_varsÚ_history_deliverys   &&      r;   Ú_set_session_envÚGatewayRunner._set_session_env‡  s†  € õ 	=ô ˜D *¨dÓ3×9Ð9°r×>Ñ>¸w¿~¹~×?VÑ?VÓWˆÜ! (Ð,EÀtÓLˆõ 	>Ù$Ó&ˆ	Ø%ŸM™MÐ*DÀdÓKÐÙò VØ—^‘^×,Ñ,×2Ò2ðVà—N‘N×*Ò*ðVð 8?·~±~×7O×7OÐ7O”c˜'Ÿ.™.×2Ñ2Ô3ÐUWøðVð —n‘n×.Ñ.×4Ð4°"øð	Vð
 8?·~±~×7O×7OÐ7O”c˜'Ÿ.™.×2Ñ2Ô3ÐUWøðVð 4;·>±>×3I×3IÐ3I”C˜Ÿ™×.Ñ.Ô/ÈrøðVð <C¿>¹>×;U×;UÐ;Uœ˜GŸN™N×6Ñ6Ô7Ð[]øðVð 8?·~±~×7O×7OÐ7O”c˜'Ÿ.™.×2Ñ2Ô3ÐUWøðVô œ §¡°¸RÓ@×FÐFÀBÔGðVô œw w§~¡~Ð7GÈÓL×RÐRÐPRÔSðVð  ×+Ò+ðVð ×)Ñ)×/Ð/¨RøðVð :A¿¹×9R×9RÐ9R”s˜7Ÿ>™>×4Ñ4Ô5ÐXZøðVô  ˜GŸN™N¨I°rÓ:×@Ð@¸bøð!Vñ" +ð#Vñ$ ð%Vñ$ 7HÈ9ñ%Vð 	Vr=   c                ó$   <€ V ^8„  d   QhRS[ RR/# )r?   ÚtokensrB   N©rŒ   )rF   rñ  s   "€r;   rG   rÚ  ¨  s   ø€ ÷ #ñ #©ð #°$ñ #r=   c                ó"   € ^ RI Hp V! V4       R# )z>Restore session context variables to their pre-handler values.)Úclear_session_varsN)rû  r$  )rÃ  r!  r$  s   && r;   Ú_clear_session_envÚ GatewayRunner._clear_session_env¨  s   € å>Ù˜6Ö"r=   c                ó    <€ V ^8„  d   QhRS[ /# )r?   r@  )rœ  )rF   rñ  s   "€r;   rG   rÚ  ®  s   ø€ ÷ ,ñ ,©.ñ ,r=   c              #  óˆ   "  € V P                  V4      p Rx € V P                  V4       R#   T P                  T4       i ; i5i)zîBind session context variables for the duration of the block, e.g. a plugin command
handler invoked outside the normal agent-turn path (``_set_session_env`` is otherwise only
reached there). Always cleared on exit, including on exception.N)r  r%  )rÃ  r@  r!  s   && r;   Ú_session_env_scopeÚ GatewayRunner._session_env_scope­  s;   é € ð
 ×&Ñ& wÓ/ˆð	,Ûà×#Ñ# FÖ+øˆD×#Ñ# FÕ+üs   ‚A•, ™A¬?¿Ac              ‡  ó¸   "  € \         P                  ! 4       p\        4       pVP                  ! V P	                  4       VP
                  V.VO5!  G Rj  x€L
 #  L5i)zJRun blocking work in the thread pool while preserving session contextvars.N)r¤   r¥   r   r¦   Ú_get_executorr§   )rÃ  Úfuncré  r?  r#  s   &&*  r;   r�  Ú+GatewayRunner._run_in_executor_with_context¸  sH   é € ä×'Ò'Ó)ˆÜ‹nˆØ×)Ò)¨$×*<Ñ*<Ó*>ÀÇÁÈÐUÐPTÓU×UÐUÑUùs   ‚AAÁAÁAc              ‡  ó´   "  € \         P                  ! 4       pVP                  ! V P                  4       \	        4       P
                  V.VO5!  G Rj  x€L
 #  L5i)a¢  Run best-effort session housekeeping off the TURN pool.

Callers of this helper bound their await with ``asyncio.wait_for`` and, on timeout, log
"the worker thread is left to finish on its own" and proceed. That bounds the AWAIT but
NOT the OCCUPANCY: a ``concurrent.futures`` work item that has already begun executing is
not cancellable, so an abandoned worker keeps its thread until its blocking call returns.
The turn pool is unbounded (one thread per turn), so sharing it would let wedged
housekeeping grow threads without limit. Housekeeping therefore gets its own bounded pool;
exhausting that one delays only more housekeeping, which is best-effort by construction.
N)r¤   r¥   r¦   Ú_get_housekeeping_executorr   r§   )rÃ  r-  ré  r?  s   &&* r;   Ú_run_housekeeping_in_executorÚ+GatewayRunner._run_housekeeping_in_executor¾  sW   é € ô ×'Ò'Ó)ˆØ×)Ò)Ø×+Ñ+Ó-¬|«~×/AÑ/AÀ4ðPØJNóP÷ Pð 	Pñ Pùs   ‚AAÁAÁAc                ó�   <€ V ^8„  d   QhRS[ RS[. S[P                  P                  3,          RS[P                  P                  /# )r?   rÜ  Ú	make_poolrB   )rD   r	   r¼  r½  ÚExecutor)rF   rñ  s   "€r;   rG   rÚ  Í  sM   ø€ ÷ ñ ©ð ¹ÀÁZ×EWÑEW×E`ÑE`ÐA`Õ8að Ñfp×fxÑfx÷  gBñ  gBñ r=   c                óX  € \        V RR4      pVf   \        P                  ! 4       pW0n        T;_uu_ 4        \        V RR4      '       d   \	        R4      h\        WR4      pVe   \        VRR4      '       d   V! 4       p\        WV4       VuuRRR4       #   + '       g   i     R# ; i)zeReturn (creating under ``_executor_lock``) the pool at ``attr``; one lock + closing flag fences both.Ú_executor_lockNÚ_executor_closingFz.Gateway is shutting down; executor unavailableÚ	_shutdown)r8   r©  r¸  r7  rÝ  Úsetattr)rÃ  rÜ  r4  r‚   Úexecutors   &&&  r;   Ú_get_or_create_poolÚ!GatewayRunner._get_or_create_poolÍ  s‰   € ä�tÐ-¨tÓ4ˆØŠ<Ü—>’>Ó#ˆDØ"&ÔßŠTÜ�tÐ0°%×8Ò8Ü"Ð#SÓTÐTÜ˜t¨4Ó0ˆHØÒ¤7¨8°[À%×#HÒ#HÙ$›;�Ü˜ HÔ-Ø÷ �T�T‹Tús   ·ABÂB)	c                óH   <€ V ^8„  d   QhRS[ P                  P                  /# rÖ   ©r¼  r½  r5  )rF   rñ  s   "€r;   rG   rÚ  Ü  s#   ø€ ÷ 
fñ 
f™z×1Ñ1×:Ñ:ñ 
fr=   c                ó2   € \         P                  V RR 4      # )aØ  Return the gateway-owned, UNBOUNDED executor for turn bodies and other blocking agent work.

A turn body holds its thread for the whole turn (every tool call blocks), so a finite pool
silently queued already-accepted turns behind running ones. Actual bound: one live turn per
session, plus turns abandoned by the inactivity timeout (run_turn keeps no handle; their
thread runs to completion). ``max_concurrent_sessions`` is the only admission cap and is
unset by default.
Ú	_executorc                  ó   € \        R R7      # )zhermes-gateway)Úthread_name_prefixr.   rº   r=   r;   rš   Ú-GatewayRunner._get_executor.<locals>.<lambda>æ  s   € Ô'?ÐScÕ'dr=   ©r¿  r<  r  s   &r;   r,  ÚGatewayRunner._get_executorÜ  s!   € ô ×0Ñ0Ø�+Ñdófð 	fr=   c                óH   <€ V ^8„  d   QhRS[ P                  P                  /# rÖ   r?  )rF   rñ  s   "€r;   rG   rÚ  è  s#   ø€ ÷ `ñ `©J×,>Ñ,>×,GÑ,Gñ `r=   c                ó2   € \         P                  V RR 4      # )zGReturn the gateway-owned executor for best-effort session housekeeping.Ú_housekeeping_executorc                  óL   € \         P                  P                  \        R R7      # )zhermes-gateway-hk)Úmax_workersrC  )r¼  r½  ÚThreadPoolExecutorÚ_HOUSEKEEPING_MAX_WORKERSrº   r=   r;   rš   Ú:GatewayRunner._get_housekeeping_executor.<locals>.<lambda>ì  s!   € ”J×&Ñ&×9Ñ9Ü5ÐJ]ð :ô _r=   rE  r  s   &r;   r0  Ú(GatewayRunner._get_housekeeping_executorè  s#   € ä×0Ñ0ØÐ*ñ_ó`ð 	`r=   c                ó    <€ V ^8„  d   QhRS[ /# rÖ   r"  )rF   rñ  s   "€r;   rG   rÚ  ð  s   ø€ ÷ ?ñ ?¡ñ ?r=   c                ó¼   € V f   . #  V P                  RRR7       \        \        V RR4      ;'       g    R4      #   \         d    T P                  RR7        L?i ; i)zgShut ``executor`` down without waiting; return its threads to join (`_threads` absent on test doubles).NFT)rÊ  Úcancel_futures)rÊ  Ú_threadsrº   )r|  r/  rŒ   r8   )r;  s   &r;   Ú
_stop_poolÚGatewayRunner._stop_poolï  sg   € ð ÒØˆIð	*Ø×Ñ 5¸ÐÔ>ô ”G˜H j°$Ó7×=Ð=¸2Ó>Ð>øô ô 	*Ø×Ñ 5ÐÖ)ð	*ús   ˆ; »AÁAc                ó&   <€ V ^8„  d   QhRS[ RS[/# )r?   Údrain_timeoutrB   )rE   rQ   )rF   rñ  s   "€r;   rG   rÚ  ú  s   ø€ ÷ Añ A±ð AÁñ Ar=   c                óD  € \        V RR4      pVf   ^ # V;_uu_ 4        RV n        \        V RR4      pRV n        \        V RR4      pRV n        RRR4       \        P                  X4      \        P                  X4      ,           p\        P                  ! 4       \        \        T;'       g    R4      R4      ,           pV F9  pV\        P                  ! 4       ,
          pV^ 8:  d    MVP                  V4       K;  	  \        R V 4       4      #   + '       g   i     LÉ; i)uº  Stop the gateway-owned pools; returns the number of worker threads still running.
``drain_timeout=0`` is fire-and-forget; shutdown passes a bounded budget so blocking DB work
cannot outlive ``SessionDB.close()``. ``cancel_futures`` only drops unstarted work and cancelling
a ``run_in_executor`` awaitable does not stop its thread, so running workers are joined â€” on
the turn pool AND the housekeeping pool, both of which write to SessionDB.r7  NTrA  rI  rÈ  c              3   óT   "  € T F  qP                  4       '       g   K  ^x € K   	  R# 5i)ræ  N)Úis_alive)rÊ   Úworkers   & r;   rÌ   Ú3GatewayRunner._shutdown_executor.<locals>.<genexpr>  s   é € Ð@¡7˜¯o©o×.?—1’1£7ùs   ‚(ž
()r8   r8  rA  rI  r¿  rT  rÁ   rÉ  rP   rE   rÏ   Úsum)	rÃ  rW  r‚   r;  ÚhousekeepingÚworkersÚdeadliner[  Ú	remainings	   &&       r;   Ú_shutdown_executorÚ GatewayRunner._shutdown_executorú  sí   € ô �tÐ-¨tÓ4ˆØŠ<ÙßŠTØ%)ˆDÔ"Ü˜t [°$Ó7ˆHØ!ˆDŒNÜ" 4Ð)AÀ4ÓHˆLØ*.ˆDÔ'÷ ô  ×*Ñ*¨8Ó4´}×7OÑ7OÐP\Ó7]Õ]ˆÜ—>’>Ó#¤c¬%°×0DÐ0DÀÓ*EÀsÓ&KÕKˆÛˆFØ ¤4§>¢>Ó#3Õ3ˆIØ˜AŒ~ÙØ�K‰K˜	Ö"ñ	 ô
 Ñ@¡7Ó@Ó@Ð@÷# �Tús   ž0DÄD	c                ó*   <€ V ^8„  d   QhRS[ RS[RR/# )r?   r™   Úinterrupt_depthrB   N)r   rQ   )rF   rñ  s   "€r;   rG   rÚ  ,  s"   ø€ ÷ "ñ "©3ð "Áð "Èñ "r=   c                óÀ   € V^ 8X  dP   \         P                   ! 4       V n        RV n        \        P                  V n        \        V R4      '       d   ^ V n        ^ V n        R# )us  Reset per-turn state on a cached agent before a new turn starts.
The activity ts/desc/provenance triple resets together and only at depth 0 â€” else a session idle
29 min trips the watchdog before the first call; interrupt-recursive turns keep it so stuck-turn
idle time accumulates to the 30-min timeout.

``_last_activity_ts``, ``_last_activity_desc``, and ``_last_activity_provenance`` are only reset for
fresh external turns (depth 0); they are a semantic triple - description and provenance describe the
activity *at* ts, so updating one without the others would make get_activity_summary() misleading.
See #15654, #9051.
zstarting new turn (cached)Ú_last_flushed_db_idxN)	rÁ   Ú_last_activity_tsÚ_last_activity_descr)   ÚUNKNOWNÚ_last_activity_provenancerI  rg  Ú_api_call_count)r™   re  s   &&r;   Ú_init_cached_agent_for_turnÚ)GatewayRunner._init_cached_agent_for_turn+  sP   € ð ˜aÔÜ&*§i¢i£kˆEÔ#Ø(DˆEÔ%Ü.@×.HÑ.HˆEÔ+ô �uÐ4×5Ò5Ø-.�Ô*Ø !ˆÖr=   c                óL   <€ V ^8„  d   QhRS[ RS[S[,          RS[S[,          /# )r?   r™  Úadapter_profilerB   )r›  r   rD   )rF   rñ  s   "€r;   rG   rÚ  B  s-   ø€ ÷ 2ñ 2Ù#ð2Ù6>¹sµmð2á	‘#�ñ2r=   c                óÀ  € \        V RR4      p\        VRR4      '       g   R# \        VRR4      pV'       g   R# VfO   \        \        VRR4      4      '       d   V P                  V4      MRp\        V\        4      '       d
   V^,          p^ RIHpHp  V! WAP                  P                  \        VRR4      VP                  \        VR	R4      \        VR
R4      V\        VRR4      R7      pT'       d…    \        T4       U
Uu0 uF  w  r«T
kK	  	  pp
pTP                   T9  dI   \        P                  RTP                  TP                   4       T! TP                  TP                   4      hTP                   # \        P#                  RTP                  P                  TP                  \        TR	R4      \        TR
R4      4       R#   \         d<   p	\        P                  RTP                  TP                  RR7       T! R4      T	hRp	?	ii ; iu upp
i   \         d;   p	\        P                  RTP                  RR7       T! TP                  4      T	hRp	?	ii ; i)uê  Resolve the profile name for an inbound source via configured routes (most specific wins).
``None`` = default/active profile (or, for a secondary adapter, its own profile â€” the caller
stamps it). Gated on ``multiplex_profiles``, since the scoped run only activates under
multiplexing; otherwise keys would be profile-namespaced while the agent ran in ``agent:main``.
``adapter_profile`` is the profile owning the receiving bot; only routes declaring it as
``bot_profile`` apply (#104933).râ   Nrr  FÚprofile_routesÚ_transport_adapter_ref)ÚProfileRouteRejectedÚmatch_profile_routeÚguild_idr  r  rÖ  )rç   rv  r¬  r  r  rp  rÖ  z.Rejecting %s/%s: profile route matching failedTrG  ÚmatcherzORejecting profile route %r because the served-profile set could not be resolvedz;Rejecting profile route %r: target profile %r is not servedzONo profile route matched: platform=%s chat_id=%s thread_id=%s parent_chat_id=%s)r8   rO   Ú_transport_ownerr   r€   Úgateway.profile_routingrt  ru  rç   r  r¬  rL   rM   r¬   rU  r-  r1  rN   )rÃ  r™  rp  râ   ÚroutesÚownerrt  ru  ÚmatchedrY   r-  r[  Úserveds   &&&          r;   Ú_profile_name_for_sourceÚ&GatewayRunner._profile_name_for_sourceB  s  € ô ˜˜x¨Ó.ˆÜ�vÐ3°U×;Ò;ÙÜ˜Ð!1°4Ó8ˆßÙØÒ"ä5=¼gÀfÐNfÐhlÓ>m×5nÒ5n�D×)Ñ)¨&Ô1ÐtxˆEÜ˜%¤×'Ò'Ø"'¨¥(�ßUð
	;Ù)Ø§¡×!6Ñ!6ÄÈÐQ[Ð]aÓAbØŸ™´'¸&À+ÈtÓ2TÜ& vÐ/?ÀÓFØ /¼ÀÈÐTXÓ9Yô	[ˆG÷ ðBÜ2JÈ6Ô2RÔSÑ2R¡; 4›$Ñ2R�ÑSð �‰ fÔ,Ü—‘ØQØ—L‘L '§/¡/ô3ñ +¨7¯<©<¸¿¹ÓIÐIØ—?‘?Ð"Ü�‰Ø]Ø�O‰O×!Ñ! 6§>¡>Ü�F˜K¨Ó.´¸Ð@PÐRVÓ0Wô	Yñ øô/ ô 	;Ü�N‰NØ@Ø—‘ §¡¸$ð ô @ñ ' yÓ1°sÐ:ûð		;üó TøÜô BÜ—‘ØeØ—L‘L¨4ð ô 1ñ +¨7¯<©<Ó8¸cÐAûð	BúsC   ÂAG	 Ã7H ÄHÄH Ç	HÇ6H
È
HÈH ÈIÈ#5IÉIc                ó&   <€ V ^8„  d   QhRS[ RS[/# rª  )r›  r   )rF   rñ  s   "€r;   rG   rÚ  v  s   ø€ ÷ "%ñ "%±}ð "%Éñ "%r=   c                óÞ  € ^ RI Hp ^ RIHp ^ RIHpHpHp ^ RIH	p V! V4      pVe   VP                  # Rp	 VP                  ;'       g    RP                  4       ;'       g    V P                  V4      p
T
;'       g    Rp	V
'       g   V! 4       ;'       g    Rp
V! V
4      pV	'       dW   V! V
4      '       gI   \        P                  RW‘P                   P"                  VP$                  \'        VR	R4      4       V! 4       # V#   T d    h \(         dY    \        P                  R
TP                   P"                  TP$                  \'        TR	R4      T	;'       g    RRR7       T! 4       u # i ; i)zÕResolve which profile's HERMES_HOME serves this source: the pinned identity's runtime
home, else ``source.profile``, then ``_profile_name_for_source`` (sources bypassing
``build_source``), then the active profile.)rt  r]  )rX  rY  Úprofile_exists)r  Nr”   r•   z\Profile %r does not exist for source %s/%s (guild_id=%s), falling back to global HERMES_HOMErv  zjFailed to resolve profile directory for source %s/%s (guild_id=%s), falling back to global HERMES_HOME: %sz(no profile)TrG  )ry  rt  rc  r^  rS  rX  rY  r‚  r¢  r  Úruntime_homer1  rá   r~  rM   r¬   rç   r  r¬  r8   rL   )rÃ  r™  rt  r^  rX  rY  r‚  r  re  Úexplicit_profiler-  rg  s   &&          r;   Ú _resolve_profile_home_for_sourceÚ.GatewayRunner._resolve_profile_home_for_sourcev  sH  € õ 	AÝ8ß`Ñ`Ý4Ù˜vÓ&ˆØÒØ×(Ñ(Ð(ØÐð	%Ø—N‘N×(Ð( b×/Ñ/Ó1×ZÐZ°T×5RÑ5RÐSYÓ5ZˆDØ#Ÿ|˜| tÐßÙ.Ó0×=Ð=°I�Ù)¨$Ó/ˆKß©°t×(<Ò(<Ü—‘ð9à$§o¡o×&;Ñ&;¸V¿^¹^Ü˜F J°Ó5ô	7ñ
 'Ó(Ð(ØÐøØ#ô 	ØÜô 	%Ü�N‰Nð9à—‘×%Ñ% v§~¡~´w¸vÀzÐSWÓ7XØ ×2Ð2 N¸Tð	 ô Cñ
 #Ó$Ò$ð	%úsO   ¸D ÁD Á#D Á>
D Â	D ÂD Â*D Â8AD Ä D ÄE,ÄAE,ÅE,Å+E,c                   óx   a € ] tR tRt o RtRtRtRtRtRt	Rt
RtRtRtRtRtRtRtRtRtRtRtRtV 3R ltRtV tR# )ÚGatewayRunner._RunAgentDisplayiš  zQPer-turn display / progress settings resolved by ``_run_agent_display_settings``.Nc                óò   <€ V ^8„  d   Qh/ S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R	&   S[ ;R
&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   # )r?   rÌ  rÉ  r  Údisabled_toolsetsr×  Úprogress_modeÚprogress_groupingÚ_display_surface_modeÚtool_progress_enabledÚ_live_status_modeÚ_live_status_adapterÚlog_mode_enabledÚ	log_queueÚ"interim_assistant_messages_enabledÚ_thinking_enabledÚ_native_slack_task_cardsÚneeds_progress_queueÚ_generic_status_phraserÐ  )rF   rñ  s   "€r;   rG   Ú+GatewayRunner._RunAgentDisplay.__annotate__š  sï   ø‡ ‚ ñ Ññ ñ Ñ ñ	 ñ
 Ñ$ñ ñ Ñ%ñ ñ "%Ñ+ñ ñ Ñ!ñ ñ Ñ%ñ ñ  #Ñ)ñ ñ  #Ñ)ñ ñ Ñ%ñ ñ "Ñ(ñ ñ Ñ$ñ ñ Ññ ñ  -0Ñ6ñ! ñ" Ñ%ñ# ñ$ #&Ñ,ñ% ñ& "Ñ(ñ' ñ( !$Ñ*ò) r=   rº   )r6  rD  rE  rF  rG  rÌ  rÉ  r  rŠ  r×  r‹  rŒ  r�  rŽ  r�  r�  r‘  r’  r“  r”  r•  r–  r—  rô  rH  rõ  rö  s   @r;   Ú_RunAgentDisplayrˆ  š  sw   ø‡ € á_ØˆØ ˆØ $ÐØ!%ÐØ'+ÐØ!ˆØ!%ÐØ%)ÐØ%)ÐØ!%ÐØ$(ÐØ $ÐØˆ	Ø26Ð*Ø!%ÐØ(,Ð Ø$(ÐØ&*Ð÷) ƒ r=   r™  c                   óT   a € ] tR tRt o RtRtRtRtRtRt	Rt
RtRtRtV 3R ltRtV tR# )ÚGatewayRunner._RunAgentWorkeri°  zPExecutor future + inactivity-watchdog handles for one ``_run_agent_inner`` turn.Nr”   c                ó¦   <€ V ^8„  d   Qh/ S[ ;R&   S[S[,          ;R&   S[S[,          ;R&   S[;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R&   S[ ;R	&   # )
r?   Úexecutor_taskÚagent_timeoutÚagent_warningr–   rž  r´  rµ  r¶  Ú
is_current)r   r   rE   rD   )rF   rñ  s   "€r;   rG   Ú*GatewayRunner._RunAgentWorker.__annotate__°  s‚   ø‡ ‚ ñ Ñ!ñ ñ  ¡•Ñ-ñ	 ñ
  ¡•Ñ-ñ ñ Ññ ñ Ñ$ñ ñ Ññ ñ Ñ!ñ ñ Ñ ñ ñ Ñò r=   rº   )r6  rD  rE  rF  rG  r�  rž  rŸ  r–   rž  r´  rµ  r¶  r   rô  rH  rõ  rö  s   @r;   Ú_RunAgentWorkerr›  °  s=   ø‡ € á^Ø!ˆØ)-ˆØ)-ˆØˆØ $ÐØˆØ!ˆØ ˆØˆ
÷ ƒ r=   r¢  c                ó  <€ V ^8„  d   Qh/ S[ ;R&   S[ ;R&   S[;R&   S[;R&   S[;R&   S[;R&   S[S[,          ;R&   S[;R&   S[;R	&   S[;R
&   S[;R&   S[;R&   S[;R&   S[;R&   S[S[,          ;R&   S[S[P                  ,          ;R&   S[S[P                  ,          ;R&   S[S[S[ S[S[	S[P                  3,          3,          ,          ;R&   S[S[
,          ;R&   S[;R&   S[S[P                  ,          ;R&   S[S[P                  ,          ;R&   S[S[
,          ;R&   S[S[
,          ;R&   S[;R&   S[S[P                  ,          ;R&   S[;R&   S[S[P                  ,          ;R&   S[S[ S[ 3,          ;R&   S[;R&   # )r?   Ú_busy_input_modeÚ_busy_text_modeÚ_restart_drain_timeoutÚ_restart_after_turn_timeoutÚ_cron_drain_timeoutÚ_signal_interrupt_grace_timeoutrZ  Ú	_drainingÚ_external_drain_activer}  Ú_restart_task_startedÚ_restart_detachedÚ_restart_via_serviceÚ _detached_restart_helper_startedÚ_restart_command_sourceÚ
_stop_taskÚ_restart_taskÚ_profile_failed_platformsÚ_systemd_watchdogÚ_startup_restore_in_progressÚ_startup_warmup_taskÚ_loop_heartbeat_taskÚ_loop_floor_timer_handleÚ_loop_liveness_watchdogÚ_gateway_started_atÚ_shutdown_watchdog_doneÚ _platform_lock_takeover_on_startÚ_reconnect_watcher_taskÚ_BUSY_REJECT_TEXTÚ_CACHE_BUSTING_CONFIG_KEYS)rD   rE   r   rQ   rm   r›  r¤   ÚTaskrà   rt  r   r©  r·  r€   )rF   rñ  s   "€r;   rG   rÚ    s  ø‡ ‚ ñ  Ñ'ñ! ñ" Ñ&ñ# ñ$ "ÑIñ% ñ& "'ÑSñ' ñ( ÑCñ) ñ* &+Ñ[ñ+ ñ, ™•Ñ$ñ- ñ. Ññ/ ñ0 !Ñ(ñ1 ñ2 Ñ$ñ3 ñ4  Ñ'ñ5 ñ6 Ñ#ñ7 ñ8 Ñ&ñ9 ñ: '+Ñ2ñ; ñ< &¡mÕ4Ñ;ñ= ñ> ™Ÿ™Õ&Ñ-ñ? ñ@ ™GŸL™LÕ)Ñ0ñA ñB  (©©S±$±xÁÇÁÐ7MÕ2NÐ-NÕ(OÕPÑWñC ñD  ¡•}Ñ+ñE ñF #'Ñ.ñG ñH #¡7§<¡<Õ0Ñ7ñI ñ| #¡7§<¡<Õ0Ñ7ñ} ñ~ '¡s�mÑ2ñ ñ@ &¡c�]Ñ1ñA ñB Ñ$ñC ñD &¡i§o¡oÕ6Ñ=ñE ñF '+Ñ2ñG ñH &¡g§l¡lÕ3Ñ:ñI ñn ™C¡˜H•~ñ *ño ñ\ !&ñ Sò] r=   )rÕ  rA  r8  r7  rI  rö  r÷  r  rõ  r&  rÊ  rô  râ   rÇ   ©Fr|  >   rD  rE  Úrestart_interrupted)rÈ  ))r  r  )rÙ   r†  )rÙ   rÚ   )rÙ   r¡  )rÙ   Úmodel_thresholds)rÙ   Úthreshold_tokens)rÙ   Úcodex_gpt55_autoraise)rÙ   Úcodex_app_server_auto)rÙ   Úcodex_responses_native)rÙ   Ú!codex_responses_compact_threshold)rÙ   rh   )rÙ   Úcheckpoint_required)rÙ   Úmicro_compact)rÙ   Úmicro_compact_every_n_turns)rÙ   Ú%micro_compact_defrag_threshold_tokens)rÙ   Útarget_ratio)rÙ   Ú	tail_mode)rÙ   Úprotect_last_n)rÙ   Úproactive_prune_tokens)rÙ   Ú proactive_prune_min_result_chars)rÙ   Ú"proactive_prune_min_reclaim_tokens)rÙ   Úmin_tail_user_messages)r™   rŠ  )ÚmemoryrV  )Úcheckpointsr†  )rÕ  Úmax_snapshots)rÕ  Úmax_total_size_mb)rÕ  Úmax_file_size_mb)Ÿr6  rD  rE  rF  rG  rÄ  r¤  r¥  r¾  r¦  r½  r§  r¼  r¨  r¿  r©  rZ  rª  r«  r}  r¬  r­  r®  r¯  r°  r±  r²  r³  r´  rµ  r¶  r¢  rÇ  rÈ  rÉ  rÊ  r£  Ú_turn_lease_tokensrË  rÌ  rÍ  rÎ  rÏ  rÐ  rÑ  rÒ  rÓ  rÔ  rÕ  rÖ  r×  rØ  rß  rJ   rb   rë  rï  r·  r¸  r¹  rº  r»  r¼  r½  r  r"  Úpropertyr6   Úsetterr7  r@  rø  r  Ú_VOICE_MODE_PATHÚshould_exit_cleanlyÚshould_exit_with_failurer†  rD  rg  r;  Ú_TELEGRAM_GENERAL_TOPIC_IDSÚ#_TELEGRAM_LOBBY_REMINDER_COOLDOWN_Sro  rs  rw  r~  r‚  r�  r“  r˜  rœ  Ú_BUSY_QUEUE_MAX_PENDINGrm  Ú	dataclassr§  Ú_CLEANUP_TIMEOUT_SÚ_FINALIZE_TIMEOUT_SÚ_STUCK_LOOP_THRESHOLDÚ_STUCK_LOOP_FILEÚ_AUTO_RESUME_REASONSÚ_MAX_SUPERVISED_RESTARTSÚ_SUPERVISED_HEALTHY_SECSÚ"_RECONNECT_WATCHER_SLOW_RETRY_SECSÚ_MAX_SLOW_WATCHER_RESPAWNSÚ$_TELEGRAM_CAPABILITY_HINT_COOLDOWN_SÚ_APPROVAL_TIMEOUT_SECONDSÚ_MAX_INTERRUPT_DEPTHr¾  r«  r¹  rÀ  r¸  rÑ  rØ  rÜ  rç  rð  rý  rù  Ústaticmethodr  r¹  rt  r
  ru  rÙ  ÚSIGNALrÚ  ÚEMAILÚSMSÚDINGTALKÚFEISHUÚWECOMÚWECOM_CALLBACKÚWEIXINÚBLUEBUBBLESÚQQBOTr  Ú_UPDATE_ALLOWED_PLATFORMSr  r%  Ú_contextmanagerr)  r�  r1  r<  r,  r0  rT  rb  r¿  rm  r~  r…  r™  r¢  rô  rH  rõ  rö  s   @r;   r¿  r¿    s  ø‡ € ñ bò2ð (ÐØ&€OØ$IÐØ)SÐØ!CÐØ-[Ð#Ø $€JØ€IØ#(ÐØ$ÐØ"'ÐØ#ÐØ!&ÐØ-2Ð$Ø7;ÐØ)-€JØ,0€MØSWÐØ'+ÐØ).Ð Ø37Ðñ +Ð+<Ó=€OÙ-Ð.BÓCÐÙ1Ð2JÓKÐÙ'¨Ó7€LÙ4Ó6ÐÙ2Ð3LÓMÐÙ3Ð4NÓOÐÙ';Ð<^Ó'_Ð$Ù#7Ð8VÓ#WÐ Ù&:Ð;\Ó&]Ð#Ù/Ð0FÓGÐÙ)Ð*:Ó;€NÙ"6Ð7TÓ"UÐÙ,Ð-@ÓAÐÙ-AØ0ó.2Ð*á1Ð2JÓKÐÙ+Ð,>Ó?ÐÙ-Ð.BÓCÐÙ1Ð2JÓKÐ÷ð ÷ð ÷?ð ?÷
Bð B÷
1ð 1ð 48ÐØ.2ÐØ-1ÐØ!$ÐØ9=ÐØ-2Ð$Ø6:Ð÷&+ò &+÷P9^ò 9^ðv ÷8ó ð8ð ×Ñ÷(ó ð(÷8ð 8÷0^ð ^÷.Qð Qð< $Ð&?Õ?Ðá"Ñ#BÓCÐÙ'Ñ(LÓMÐÙÑ9Ó:€KÙÑ5Ó6€I÷ð ñB #,¨R°¨IÓ"6ÐØ*.Ð'÷að a÷&ð ÷)ð )÷Dð D÷zð z÷	%ò 	%÷Mð M÷Gð G÷bð bð !Ðà×Ñ÷ð ó ðð Ðð ÐàÐØ0Ðñ
 %Ò%cÓdÐà Ðà"Ðà),Ð&à!"ÐØ+0Ð(Ø #ÐØÐð
 	Ð,ØÐ<ØÐ(ð)*Ð÷
ð ð
AØIM÷
Aò 
A÷bð b÷
ð ÷ð ð( ÷ó ð÷ð ð ×Ñ÷ð ó ðð  ×Ñ÷	ð 	ó ð	÷$ò $ðLà#'ðàNRðð "&÷ò ð, ðà#'ðàBF÷ñ ó ðñ* +Ð+BÓCÐñ !*Ø×Ñ˜8Ÿ>™>¨8×+<Ñ+<¸h¿o¹oÈxÏÉØ�Š˜Ÿš h×&7Ò&7Ø�Š˜Ÿš¨×)@Ò)@À(Ç/Â/ÐS[×SgÒSgÐiq×iwÒiwð  zB÷  zHò  zHð+ó !Ð÷Vð V÷B#ð #ð
 ÷,ó ð,òVòP÷ð ÷
fð 
f÷`ð `ð ÷?ó ð?÷Aò Að>)SÐð$ ÷"ó ð"÷,2ò 2÷h"%ð "%ðH ×Ñ÷+ð +ó ð+ð* ×Ñ÷
ð 
ó ð
÷M ƒ r=   r¿  g      à?c                óh   € V ^8„  d   QhR\         P                  R\        P                  R\        RR/# )r?   Ú
stop_eventr?  rÃ  rB   N)r©  r·  r¤   rA  rE   )rF   s   "r;   rG   rG   ¾  s6   € ÷ *'ñ *'Ü—‘ð*'Ü/6×/HÑ/Hð*'äð*'à#'ñ*'r=   c               ó´  € ^ RI HpHp V! 4       pV P                  4       '       g…    VP	                  4       '       d[   \        VRR4      '       gH   \        VRR4      '       d5   V! 4       '       g   V P                  V4       Ks  VP                  VR4       R# T P                  T4       Kš  R#   \         d!   p\        P                  RT4        Rp?L;Rp?ii ; i)uï  Poll for the planned-stop marker and trigger graceful shutdown (Windows lacks
``add_signal_handler``, so ``hermes gateway stop`` would never drain). Runs everywhere; on POSIX
the signal handler consumes the marker first and ``_running``/``_draining`` guard re-triggers.

On Windows, ``asyncio.add_signal_handler`` raises NotImplementedError for SIGTERM/SIGINT, so the
standard signal-driven shutdown path never runs when ``hermes gateway stop`` signals the gateway. The
consequence is that the drain loop is skipped â€” in-flight agent sessions are killed mid-turn and
``resume_pending`` is never set, so the next gateway boot has no idea those sessions need to be
auto-resumed (issue #33778, v0.13.0 session-resume feature broken on native Windows).
)Ú_get_planned_stop_marker_pathÚ planned_stop_marker_targets_selfrª  FÚ_runningNz#Planned-stop watcher tick error: %s)rj  rÿ  r 	  r½  r  r8   rÊ  Úcall_soon_threadsaferL   rM   rN   )	rý  ry  r?  Úshutdown_handlerrÃ  rÿ  r 	  Úmarker_pathÚ_es	   &&&&$    r;   Ú_run_planned_stop_watcherr	  ¾  s¹   € ÷Iá/Ó1€KØ×Ñ×!Ò!ð	Dà×"Ñ"×$Ò$Ü ¨°U×;Ò;Ü˜F J°×6Ò6ñ 8×9Ò9Ø—O‘O MÔ2Ùà×)Ñ)Ð*:¸DÔAÙð 	�‰˜Ö&ñ5 "øô0 ô 	DÜ�L‰LÐ>À×CÑCûð	Dús(   §B, ½2B, Á0B, ÂB, Â,CÂ7CÃCc                ó(   € V ^8„  d   QhR\         RR/# )r?   ÚlabelrB   Nr_   )rF   s   "r;   rG   rG   ë  s   € ÷ 1ñ 1œsð 1¸Dñ 1r=   c                óv   €  V! V/ VB  R#   \          d"   p\        P                  RY4        Rp?R# Rp?ii ; i)z¸Run one housekeeping chore; failures log at debug (a persistent failure such as a broken
import after a partial update would otherwise warn every tick forever) and never stop the loop.z%s error: %sNrÄ  )r	  rÁ  ré  ÚkwargsrY   s   &&*, r;   Ú_housekeeping_chorer	  ë  s5   € ð1Ù
ˆDÐ�FÔøÜô 1Ü�‰�^ U×0Ò0ûð1ús   ‚ Œ8—3³8c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   ô  s   € ÷ 	#ñ 	#°tñ 	#r=   c                 ó€   € ^ RI Hp Ve4   \        V! V 4      V\        RR7      pVe   VP	                  ^R7       R# R# R# )r  )Úbuild_channel_directoryNz*Channel directory refresh scheduling error)rM   Úlog_messagerž   )Úgateway.channel_directoryr	  r   rM   r»  )rô  r?  r	  Úfuts   &&  r;   Ú_housekeeping_channel_directoryr	  ô  sF   € ÝAØÒô 'Ù# HÓ-¨t¼FØDôFˆð Š?Ø�J‰J˜rˆJÖ"ñ ñ r=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG      s   € ÷ `ñ ` 4ñ `r=   c                  ód   € ^ RI Hp  V ! 4       w  rV'       d   \        P                  RW4       R# R# )r  )Ú_sweep_expired_pastesz4Paste sweep: deleted %d expired paste(s), %d pendingN)Úhermes_cli.debugr	  rM   r  )r	  Údeletedra  s      r;   Ú_housekeeping_paste_sweepr	     s'   € Ý6Ù.Ó0Ñ€GßÜ�‰ÐJÈGÖ_ñ r=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG     s   € ÷ Lñ LÀTñ Lr=   c                óf   € ^ RI Hp V! WVR7      pV'       d   \        P                  RV4       R# R# )zÁExternal cron providers only: fire jobs whose time passed with no external fire delivered (dead
loopback hop). No-op for the built-in ticker; enforces misfire_grace_minutes; CAS claim de-dupes.)Úfire_overdue_jobs©rô  r?  z)Misfire catch-up: fired %d overdue job(s)N)Úcron.scheduler_providerr	  rM   r  )Úcron_providerrô  r?  r	  Ú	caught_ups   &&&  r;   Ú_housekeeping_misfire_catch_upr 	    s*   € õ :Ù! -ÈÔN€IßÜ�‰Ð?ÀÖKñ r=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG     s   € ÷ mñ m˜tñ mr=   c                 ó:   € ^ RI Hp  V ! \        R4      R R7       R# )zYmaybe_run_curator() is gated by config.interval_hours (7 days default); this is the poll.©Úmaybe_run_curatorÚinfc                 ó.   € \         P                  R V 4      # )zcurator: %s)rM   r  )rT  s   &r;   rš   Ú'_housekeeping_curator.<locals>.<lambda>  s   € ÌFÏKÉKÐXeÐgjÔLkr=   )Úidle_for_secondsÚ
on_summaryN)Úagent.curatorr$	  rE   r#	  s    r;   Ú_housekeeping_curatorr+	    s   € å/Ù¤u¨U£|Ñ@k×lr=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG     s   € ÷ (ñ (¨4ñ (r=   c                 ó,   € ^ RI Hp  V ! \        R7       R# )uü   Plugin update-check cadence (plugins_cadence): due-gated by
plugins.auto_update_check_hours, read-only, receipt-surfaced; the
opt-in auto-apply rides the manual update pipeline. A network error
costs one warning and a stamped marker â€” never an apply.©Úmaybe_run_gateway_check)ÚlogN)Úhermes_cli.plugins_cadencer/	  rM   r.	  s    r;   Ú!_housekeeping_plugin_update_checkr2	    s   € õ
 Cá¤×'r=   c                ó\   € V ^8„  d   QhR\         \        \        \        3,          ,          /# rÖ   ©r   r€   r   )rF   s   "r;   rG   rG      s!   € ÷ 	1ñ 	1¤H¬U´4¼°:Õ->Õ$?ñ 	1r=   c                óR   € \        V RR4      pVf   R# \        4       \        V4      3# )uð   ``(launch home, its configured transcript dir)``, or ``None`` when the gateway carries none.

MUST be called outside any profile scope â€” ``get_hermes_home()`` is what identifies the launch
home. Consumed by :func:`_profile_sessions_dir`.
Úsessions_dirN)r8   r  r   )râ   r6	  s   & r;   Ú_launch_sessions_dirr7	     s.   € ô ˜6 >°4Ó8€LØÒÙÜÓœd <Ó0Ð0Ð0r=   c                óh   € V ^8„  d   QhR\         \        \        \        3,          ,          R\        /# )r?   ÚlaunchrB   r4	  )rF   s   "r;   rG   rG   ,  s(   € ÷ ñ ¤(¬5´´t°Õ+<Õ"=ð Ä$ñ r=   c                ó‚   € \        4       pV e*   \        V ^ ,          4      V8X  d   \        V ^,          4      # VR,          # )a—  Transcript dir of the profile currently in scope.

``gateway.sessions_dir`` overrides the LAUNCH profile's transcript dir only; every other served
profile keeps ``<home>/sessions``. Hardcoding ``<home>/sessions`` for the launch home too wrote
transcripts to the configured dir while the prune unlinked under the default one, orphaning
every pruned session's ``.json``/``.jsonl``/``request_dump_*`` forever.
r/  )r  r   )r9	  r+  s   & r;   Ú_profile_sessions_dirr;	  ,  s:   € ô Ó€DØÒœd 6¨!¥9›o°Ô5Ü�F˜1•I‹ÐØ�*ÕÐr=   c                ó`   € V ^8„  d   QhR\         \        \        \        3,          ,          RR/# )r?   r9	  rB   Nr4	  )rF   s   "r;   rG   rG   :  s)   € ÷ ñ ¬x¼¼dÄD¸jÕ8IÕ/Jð ÐVZñ r=   c                óð  € ^ RI Hp ^ RIHpHp V! 4       P                  R4      ;'       g    / pVP                  RR4      '       g   VP                  RR4      '       g   R# V! 4       p VP                  RR4      '       dF   VP                  \        VP                  R^4      4      \        VP                  R	^4      4      R
7       VP                  RR4      '       d„   VP                  \        VP                  R^Z4      4      \        VP                  R	^4      4      \        VP                  R^4      4      \        VP                  RR4      4      \        V 4      R7       V! V4       R#   T! T4       i ; i)u  Stale-session auto-archive plus auto-prune/VACUUM for ONE profile's state.db; both are gated
by sessions.min_interval_hours (VACUUM additionally by its own throttles). Opens its own
SessionDB â€” SQLite connections are thread-bound.

Profile-scoped by its caller: ``acquire()``, ``get_hermes_home()`` and ``load_config()`` all
resolve through the active scope, so an unscoped run swept only the LAUNCH profile's store with
the LAUNCH profile's retention settings and a multiplexed secondary was never archived, pruned
or vacuumed by anyone â€” the dashboard/serve trigger defers to the gateway for every profile a
gateway owns (``web_server_sessions``). *launch* carries the launch home's configured transcript
dir (:func:`_launch_sessions_dir`) so its override still governs its own profile.)Úload_config)r
  r1  r/  Úauto_archiveFÚ
auto_pruneNÚauto_archive_daysÚmin_interval_hours)Ú	idle_daysrB	  Úretention_daysÚmin_vacuum_interval_daysÚvacuum_after_pruneT)rD	  rB	  rE	  Úvacuumr6	  )r  r>	  r  r
  r1  r~   Úmaybe_auto_archiverE   rQ   Úmaybe_auto_prune_and_vacuumrm   r;	  )r9	  Ú_load_full_configr
  r1  Ú	_sess_cfgÚ_adbs   &     r;   Ú"_housekeeping_state_db_maintenancerM	  :  s7  € õ Cß?Ù"Ó$×(Ñ(¨Ó4×:Ð:¸€IØ�M‰M˜.¨%×0Ò0°I·M±MÀ,ÐPU×4VÒ4VÙÙ‹9€DðØ�=‰=˜¨×/Ò/Ø×#Ñ#Ü 	§¡Ð.AÀ1Ó EÓFÜ#& y§}¡}Ð5IÈ2Ó'NÓ#Oð $ô Qð �=‰=˜ u×-Ò-Ø×,Ñ,Ü" 9§=¡=Ð1AÀ2Ó#FÓGÜ#& y§}¡}Ð5IÈ2Ó'NÓ#OÜ),¨Y¯]©]Ð;UÐWYÓ-ZÓ)[Ü˜IŸM™MÐ*>ÀÓEÓFÜ2°6Ó:ð -ô <ñ 	˜ÖøÑ˜Õús   Á)E+ ÂAE+ ÃBE+ Å+
E5c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   [  s   € ÷ :ñ :¨$ñ :r=   c                 ó  € ^ RI Hp  V ! 4       ;_uu_ 4       pV FS  p\        VRR4      p\        V4      '       g   K#  V! 4       '       g   K2  \        P                  R\        VRR4      4       KU  	  RRR4       R#   + '       g   i     R# ; i)zÈA SessionDB opened while another process held the rebuild lock fails closed onto the LIKE fallback
and the gateway stays up for days. Non-blocking, rate-limited inside SessionDB; no-op when not stale.)Úborrow_live_shared_session_dbsÚretry_deferred_fts_recoveryNzUDeferred state.db FTS rebuild completed in-process for %s; full-text search restored.Údb_pathzstate.db)r  rP	  r8   rO   rM   r  )rP	  Ú_session_dbsÚ_sdbÚ_retrys       r;   Ú _housekeeping_deferred_fts_retryrV	  [  sg   € õ EÙ	'×	)Ô	)¨\Û ˆDÜ˜TÐ#@À$ÓGˆFÜ˜×Ô¡F§H¤HÜ—‘ØkÜ˜D )¨ZÓ8ö:ñ !÷ 
*×	)×	)Ò	)ús   –!A:¼
A:Á%A:Á:B	c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   k  s   € ÷ 9ñ 9 4ñ 9r=   c                 ó$   € ^ RI Hp  V ! RR7       R# )z[Messaging-gateway counterpart to the TUI idle reaper; config-gated and rate-limited inside.©Útrim_memoryzmessaging gateway housekeepingru  N)Úhermes_cli.mem_trimrZ	  rY	  s    r;   Ú_housekeeping_memory_trimr\	  k  s   € å/ÙÐ7×8r=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   q  s   € ÷ ñ ¨ñ r=   c                 ó    € ^ RI Hp  V ! 4        R# )zõCheckpoint store retention + size cap on a live timer; ``auto_prune_from_config`` gates on
``checkpoints.auto_prune`` and the 24h ``.last_prune`` marker. Off the startup path because its
``git gc`` can block for tens of seconds on a large store.©Úauto_prune_from_configN)Útools.checkpoint_maintenancer`	  r_	  s    r;   Ú_housekeeping_checkpoint_prunerb	  q  s   € õ DÙÖr=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   y  s   € ÷ Hñ HÈñ Hr=   c                óî  € ^ RI Hp ^ RI Hp Vf   V e   VP                  W4       R# \	        V4       Fª  w  rVVf   T pM\        VR/ 4      P                  V4      pVf   K.  \        T;'       g    \        4       4      ;_uu_ 4        Ve:   V'       g2   V '       d*   VP                  4       pV'       d   VP                  W4      pVP                  Wq4       RRR4       K¬  	  R#   + '       g   i     KÁ  ; i)zÅDrain each profile's worker queue through its matching live adapters. A credential-less satellite
profile (empty adapter map) drains through the primary's adapters routed by its own profile routes.)Ú	scheduler)Úscheduler_preflightNrö  )Úcronre	  rf	  Údrain_delivery_queuer~  r8   r~   r°  r  Ú(_primary_profile_routes_for_current_homeÚSharedRouteAdapters)	rô  r?  ry  Úcron_schedulerÚsched_preflightrÈ  r™  Úprofile_adaptersrz  s	   &&&      r;   Ú#_drain_restart_safe_cron_deliveriesrn	  y  sÑ   € õ 1Ý;à‚~ØÒØ×/Ñ/°Ô?ÙÜ&;¸FÖ&CÑ"ˆØÒØ'Ñä& vÐ/BÀBÓG×KÑKÈLÓYÐØÒ#ÙÜ# L×$EÐ$E´OÓ4E×FÕFØÒ'×0@ÇXØ(×QÑQÓS�ßØ'6×'JÑ'JÈ8Ó'\Ð$Ø×/Ñ/Ð0@ÔG÷ GÑFó 'D÷ G×FÐFús   ÂC#ÂC#ÂC#Â3"C#Ã#C4c                óD   € V ^8„  d   QhR\         P                  R\        /# ©r?   rý  Úinterval©r©  r·  rQ   )rF   s   "r;   rG   rG   ’  s$   € ÷ E0ñ E0Ü—‘ðE0ÜEHñE0r=   c                ó²  aaaaa€ ^ RI HpHpHp	 ^ RIHp
Hp ^ RIHpH	o ^R\        3.pSf   Se   VP                  ^VVVV3R l34       V^RVV3R l3^<R	V3^<R
\        3.,          pVP                  ^RVVV3R l34       Se   VP                  ^RVVV3R l34       Ve   VP                  ^RVP                  34       V^<RV! S\        4      3^<RV! S\        \!        SRR4      4      3R l4      3^RV! S\"        4      3^R\$        3^R\&        3^RV
! S4      3^R\(        3.,          pRpSf   Se   R V3R llpV! VVVV3R l4      p\*        P-                  RV4       ^ pV P/                  4       '       gC   V^,          pV F#  w  pppVV,          ^ 8X  g   K  \1        VV4       K%  	  V	! WV\0        4       KX  \*        P-                  R4       R# )a   Background thread for gateway-only periodic chores (NOT cron). Separate from the cron trigger
so chores run under any ``CronScheduler`` provider (external scale-to-zero has no 60s loop).
Cadences are ticks of ``interval``; inner gates own the real cadence.)ÚDRAIN_LABELÚDeliveryQueueWatchÚwait_for_next_tick)Ú_mcp_config_reconcilerÚprofile_scoped_chore)Úhousekeeping_media_cachesÚmaybe_post_auto_prune_promptzRuntime heartbeatNc                  ó   <€ \        S SS4      # rÇ   ©rn	  ©rô  r?  ry  s   €€€r;   rš   Ú-_start_gateway_housekeeping.<locals>.<lambda>¥  s   ø€ Ô/RÐS[Ð]aÐciÔ/jr=   zChannel directory refreshc                  ó0   <€ S ;'       d    \        S S4      # rÇ   )r	  r	  s   €€r;   rš   r~	  §  s   ø€ °×1mÐ1mÔ>]Ð^fÐhlÓ>mÐ1mr=   zMedia cache cleanupzPaste sweepzAuto-prune low-disk promptc                  ó   <€ S! SS 4      # rÇ   rº   )r?  rz	  ry  s   €€€r;   rš   r~	  «  s   ø€ Ñ<XÐY_ÐaeÔ<fr=   zMisfire catch-up sweepc                  ó   <€ \        SS S4      # rÇ   )r 	  )rô  r	  r?  s   €€€r;   rš   r~	  ­  s   ø€ Ô<ZÐ[hÐjrÐtxÔ<yr=   zCron ticker supervisorzCurator tickzstate.db maintenance tickrâ   c                 ó   € \        V 4      # rÇ   )rM	  )Ú_launchs   &r;   rš   r~	  ¹  s
   € Ü2°7Ô;r=   zPlugin update checkzDeferred FTS retry tickz gateway housekeeping memory trimzMCP config reconcilezCheckpoint prune tickc                ó$   € V ^8„  d   QhR\         /# rÖ   r"  )rF   s   "r;   rG   Ú1_start_gateway_housekeeping.<locals>.__annotate__É  s   € ÷ 	mñ 	mœdñ 	mr=   c                  ó\   <€ Se    \        S4       U Uu. uF  w  rVNK	  	  upp # R .# u upp i rÇ   )r~  )ru  r+  ry  s     €r;   Úserved_homesÚ1_start_gateway_housekeeping.<locals>.served_homesÉ  s3   ø€ ØNTÒN`Ô,AÀ&Ô,IÔJÑ,I™[˜U“DÑ,IÒJÐlÐgkÐflÐlùÓJs   ”(c                  ó   <€ \        S SS4      # rÇ   r|	  r}	  s   €€€r;   rš   r~	  Í  s   ø€ Ô"EÀhÐPTÐV\Ô"]r=   z+Gateway housekeeping started (interval=%ds)zGateway housekeeping stopped)Ú gateway.run_delivery_queue_watchrt	  ru	  rv	  Úgateway.run_profile_reconcilerw	  rx	  Úgateway.run_housekeeping_diskry	  rz	  r¨  rs  r	  Úrestart_if_deadr+	  r7	  r8   r2	  rV	  r\	  rb	  rM   r  r½  r	  )rý  rô  r?  rq	  r	  ry  Úcron_threadrt	  ru	  rv	  rw	  rx	  ry	  ÚchoresÚqueue_watchr‡	  Ú
tick_countÚeveryr	  rÁ  rz	  s   &ff&ff&             @r;   Ú_start_gateway_housekeepingr“	  ’  s  ü€ ÷ eÑdßZßeð 
ÐÔ!<Ð=ð*?€Fð Ò˜vÒ1ð 	�‰�q˜+Ö'jÐkÔlØ
Ø	
Ð'Õ)mÐnØ	Ð"Ð$=Ð>Ø	ˆ]Ô5Ð6ð8õ 8€Fð
 ‡M�M�1Ð2Ö4fÐgÔhØÒ Ø�‰�qÐ2Ö4yÐzÔ{ØÒð 	�‰�qÐ2°K×4OÑ4OÐPÔQØ
ð 
ˆ^Ñ1°&Ô:OÓPÐQØ	Ð(Ñ*>Øä/´¸ÀÈ$Ó0OÓPó <ó+=ð 	>ð 
Ð!Ñ#7¸Ô@aÓ#bÐcØ	
Ð%Ô'GÐHØ	
Ð.Ô0IÐJØ	
Ð"Ñ$:¸6Ó$BÐCà	
Ð#Ô%CÐDð#Fõ F€Fð* €KØÒ˜vÒ1÷	mð 	mñ )ØÖ]ó_ˆô ‡K�KÐ=¸xÔHØ€JØ×Ñ×!Ò!Ø�a�ˆ
Û &ÑˆE�5˜"Ø˜EÕ! QÖ&Ü# E¨2Ö.ñ !'ñ 	˜:°Ô>QÖRÜ
‡K�KÐ.Ö/r=   c                óD   € V ^8„  d   QhR\         P                  R\        /# rp	  rr	  )rF   s   "r;   rG   rG   Ú  s#   € ÷ `ñ `¤9§?¡?ð `ÔX[ñ `r=   c                óB   € ^ RI Hp V! 4       P                  WW#R7       R# )u¶   DEPRECATED shim â€” runs ONLY the built-in in-process cron tick loop; the trigger now lives behind
the ``CronScheduler`` provider and housekeeping in ``_start_gateway_housekeeping``.)ÚInProcessCronScheduler)rô  r?  rq	  N)r	  r–	  Ústart)rý  rô  r?  rq	  r–	  s   &&&& r;   Ú_start_cron_tickerr˜	  Ú  s   € õ ?ÙÓ×"Ñ" :ÀtÐ"Ö_r=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   á  s   € ÷ <ñ < Tñ <r=   c                óî   €  V P                  4        R#   \         d,   p\        P                  RTP                  4        Rp?R# Rp?i\
         d"   p\        P                  RT4        Rp?R# Rp?ii ; i)zEStop a cron provider without letting it choose the gateway exit code.zICron provider stop() attempted to exit the gateway with code %s; ignoringNzCron provider stop() error: %s)ÚstopÚ
SystemExitrM   r¬   rA  rL   rN   )rV  rY   s   & r;   Ú_stop_cron_providerr�	  á  s[   € ð<Ø�‰ŽøÜô cÜ�‰ØWÐY\×YaÑYa÷	cò 	cûäô <Ü�‰Ð5°s×;Ò;ûð<ús&   ‚ ”A4Ÿ AÁA4ÁA4ÁA/Á/A4g     @P@g     €A@c                ór   € V ^8„  d   QhR\         \        P                  ,          R\        R\        R\        /# )r?   r3  rŸ   ÚpollrB   )r   r©  ÚThreadrE   rm   )rF   s   "r;   rG   rG   ó  s7   € ÷ !ñ !Ü”Y×%Ñ%Õ&ð!Ü16ð!Ü>Cð!ÜNRñ!r=   c              ƒ  óh  "  € V f   R# \         P                  ! 4       P                  4       \        RV4      ,           pV P	                  4       '       dI   \         P                  ! 4       P                  4       V8  d!   \         P
                  ! V4      G Rj  x€L
  K^  V P	                  4       '       * #  L5i)u.  Wait for a daemon thread to exit WITHOUT blocking the event loop; True if it exited in time.
A synchronous ``join()`` freezes the loop â€” fatal for the cron ticker, whose in-flight delivery is a
coroutine on *this* loop: it could never run, so the join timed out and the message dropped.

See #58818.
NTrÈ  )r¤   r¥   rÁ   rP   rZ  Úsleep)r3  rŸ   rŸ	  r`  s   &&& r;   Ú_await_thread_exitr£	  ó  s   é € ð ‚~ÙÜ×'Ò'Ó)×.Ñ.Ó0´3°s¸GÓ3DÕD€HØ
�/‰/×
Ò
¤× 8Ò 8Ó :× ?Ñ ?Ó AÀHÔ LÜ�mŠm˜DÓ!×!Ò!Ø�‰Ó Ô Ð ñ 	"ùs   ‚AB2ÁAB2ÂB0ÂB2c                ó<   € V ^8„  d   QhR\         R\        R\        /# )r?   rŸ   râ   rB   )rE   r   rm   )rF   s   "r;   rG   rG     s"   € ÷ 4ñ 4´Uð 4Ì#ð 4ÔY]ñ 4r=   c              ƒ  óž  aaa"  € ^ RI Ho \        VRR4      '       d   \        V4      M. o\	        RV \        S4      ^,           ,          4      oR VVV3R llp\        P                  ! \        4       P                  V3RRR	7      pVP                  4        \        W0R
7      G Rj  x€L
 pV'       g   \        P                  RV 4       V#  L$5i)u»  Close MCP servers off-loop with a bounded wait; True when done within ``timeout``.
``shutdown_mcp_servers()`` can block ~15s; on the loop thread short-grace supervisors (s6 3s)
SIGKILL us before ``mark_exited()`` runs, so every later boot reports a phantom unclean death.
On timeout shutdown proceeds and the daemon thread is left to finish or die.

Teardown is per served profile, under that profile's runtime scope â€” the mirror of startup
discovery (``_discover_mcp_tools_for_profiles``) and of the periodic reconcile chore. A
server's close path reads its own config/credentials at call time, so an unscoped shutdown on
a bare thread resolved every served profile's teardown against the LAUNCH home. The trailing
wildcard call (under the launch profile's own scope) stops the shared loop and reaps anything
the per-profile passes did not own.

``timeout`` is a TOTAL budget: each pass gets ``timeout / (N + 1)``, because the default 15s
per-pass wait inside ``shutdown_mcp_servers`` let N profiles consume the whole caller budget and
the trailing wildcard pass â€” the only one that stops the shared loop â€” never ran.

The worker runs in a FRESH context, not ``copy_context()``: the caller may sit inside a served
profile's scope, and the trailing wildcard pass must run under the launch profile's own scope
(``launch_profile_scope_if_multiplexed`` binds the launch home) â€” inheriting the caller's made it
resolve the live home to that profile.

See #82874.
)Ú#launch_profile_scope_if_multiplexedrr  Fr�   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   Ú7_shutdown_mcp_servers_nonblocking.<locals>.__annotate__!  s   € ÷ ?ñ ?�ñ ?r=   c                  óð  <€ ^ RI Hp  ^ RIHp S FE  w  r# \	        \        V4      RR7      ;_uu_ 4        V! V P                  4       SR7       RRR4       KG  	   S! 4       ;_uu_ 4        V! SR
7       RRR4       R#   + '       g   i     K~  ; i  \         d    \        P                  RTRR	7        K§  i ; i  + '       g   i     R# ; i  \         d    \        P                  RRR	7        R# i ; i)r  )Ú_core)Úshutdown_mcp_serversF)r§  )ÚscoperŸ   Nz$MCP shutdown raised for profile '%s'TrG  rž   zMCP shutdown raised)
Útools.mcp_tool_commonrª	  Útools.mcp_tool_lifecycler«	  r°  r   Ú_mcp_registry_scoperL   rM   rN   )rª	  r«	  rÈ  r™  r¦	  Úpass_timeoutÚprofile_homess       €€€r;   Ú_doÚ._shutdown_mcp_servers_nonblocking.<locals>._do!  sÆ   ø€ Ý/ÝAÛ*7Ñ&ˆLðbÜ+¬D°Ó,>ÐPU×VÖVÙ(¨u×/HÑ/HÓ/JÐT`Õa÷ WÑVñ +8ð	?Ù4×6Õ6Ù$¨\Õ:÷ 7Ñ6÷ W×VÐVûäô bÜ—‘ÐCÀ\Ð\`�×aðbú÷ 7×6Ð6ûäô 	?Ü�L‰LÐ.¸ˆL×>ð	?ús^   –B´A=ÁBÁC Á)
B;Á3C Á=BÂBÂBÂ#B8Â7B8Â;C	ÃC ÃC Ã"C5Ã4C5zmcp-shutdownT)Útargetré  r-  Údaemonrž   NzxMCP shutdown did not finish within %.1fs; continuing gateway teardown (background thread will be reaped at process exit))r¤  r¦	  r8   rU  rP   rU   r©  r 	  r   r§   r—	  r£	  rM   r¬   )rŸ   râ   r²	  r3  Údoner¦	  r°	  r±	  s   &&   @@@r;   Ú!_shutdown_mcp_servers_nonblockingr·	    s°   úé € õ0 Vô -4°FÐ<PÐRW×,XÒ,XÔ  Ô(Ð^`ð ä�s˜G¤s¨=Ó'9¸AÕ'=Õ>Ó?€L÷?ò ?ô ×Ò¤W£Y§]¡]¸#¸ÀnÐ]aÔb€FØ
‡L�L„NÜ# FÔ<×<€DßÜ�‰ðJØKRô	Tð €Kñ =ùs   …B!CÂ&CÂ'CÂ3Cc                ó(   € V ^8„  d   QhR\         RR/# r…  rÐ  )rF   s   "r;   rG   rG   :  s   € ÷ 	Rñ 	R¬Cð 	R°Dñ 	Rr=   c                ó®   € \        V RR4      pVf   R# RV n         VP                  4        R#   \         d    \        P                  RRR7        R# i ; i)z9Idempotently drain and detach Gateway Health OTLP export.Ú_gateway_health_export_runtimeNz*gateway health OTLP export shutdown failedTrG  )r8   rº	  r|  rL   rM   rN   )ry  râ  s   & r;   Ú_shutdown_gateway_health_exportr»	  :  sU   € ä�fÐ>ÀÓE€GØ‚ÙØ,0€FÔ)ðRØ×ÑÖøÜô RÜ�‰ÐAÈDˆ×QðRús   œ. ®"AÁAc                ó8   € V ^8„  d   QhR\         P                  /# rÖ   )ÚloggingÚ	Formatter)rF   s   "r;   rG   rG   F  s   € ÷ Qñ Q¤7×#4Ñ#4ñ Qr=   c                 ó   € ^ RI Hp  V ! R4      # )zAReturn the redacting formatter used by the gateway stderr stream.©ÚRedactingFormatterz/%(asctime)s %(levelname)s %(name)s: %(message)s)rT  rÁ	  rÀ	  s    r;   Ú_gateway_stderr_formatterrÂ	  F  s   € å/ÙÐOÓPÐPr=   c                ó0   € V ^8„  d   QhR\         R\        /# )r?   Úexisting_pidrB   rA  )rF   s   "r;   rG   rG   M  s   € ÷ Rñ R¼3ð RÄ4ñ Rr=   c                ó  a a€  ^ RI HpHp V! 4       pVe‡   VP                  S 8X  dv   VP	                  V! \        4       4      4      '       dQ   \        P                  RS \        VP                  4      RP                  VP                  4      ;'       g    R4       R#  ^ R	IHpHpHpHpHpHp	HoHp
 T! 4       pR
\,        P.                  /R R llpT! T! 4       4      p\1        T\2        4      '       d   T	! T4      '       g
   T! RS 4      # T! T4      pTS 8w  d   T! RTS 4      # TP5                  R4      p\1        T\6        4      '       d   \1        T\8        4      '       d   R# T! S 4      T8w  d
   T! RS 4      # TP5                  R4      p\1        T\:        4      '       d   TP=                  4       '       g
   T! RS 4      # T
! TT4      '       g   T! RTT\,        P>                  R7      # \A        TT 3R l4      pT'       d-   \C        TT4      '       d   T! RS T\,        P>                  R7      # R#   \         d    \        P                  RS RR7        EL·i ; i  \         d    \        P                  RS RR7        R# i ; i)uÉ  Return True when ``--replace`` must refuse to signal ``existing_pid``.
A poisoned/stale PID record can point at another profile's LIVE gateway (cross-profile SIGTERM
restart loop). Ownership is decided by the persisted identity record ALONE, bound to the live target
by exact PID + start-time; live argv can never PROVE ownership (no HERMES_HOME), it is only a
consistency check. Missing, legacy, conflicting or unprovable identity â†’ refuse (fail closed).)Úhost_gatewayÚprofile_name_for_homez--replace target PID %s is the host gateway serving %d profile(s) (%s); replacing it restarts the host process for all of them.r‰  rø   Fz1host served-set ownership probe failed for PID %sTrG  )Ú_get_pid_pathÚ_get_process_hermes_homeÚ_get_process_start_timeÚ_pid_from_recordÚ_read_pid_recordÚ_record_looks_like_gatewayÚ_read_process_cmdlineÚ_same_hermes_homeÚlevelc                ó0   € V ^8„  d   QhR\         R\        /# )r?   rT  rB   rd  )rF   s   "r;   rG   Ú>_replace_target_belongs_to_other_profile.<locals>.__annotate__|  s   € ÷ 	ñ 	œð 	¼dñ 	r=   c                óF   € \         P                  ! VR V ,           .VO5!   R# )zRefusing --replace: T)rM   r0	  )rT  rÐ	  ré  s   &$*r;   ÚrefuseÚ8_replace_target_belongs_to_other_profile.<locals>.refuse|  s   € Ü�JŠJ�uÐ4°sÕ:ÐB¸TÔBÙr=   z9no valid gateway pid record to prove ownership of PID %s.z#pid record names %s, not target %s.Ú
start_timezRpid record start-time does not match the live process %s (stale/PID-reuse record).r   zJpid record predates hermes_home stampings; ownership of PID %s unprovable.zpid record belongs to a different HERMES_HOME (%s, ours %s). Remove the stale PID record or stop the owning profile explicitly.)rÐ	  c                  ó   <€ S ! S4      # rÇ   rº   )rÎ	  rÄ	  s   €€r;   rš   Ú:_replace_target_belongs_to_other_profile.<locals>.<lambda>–  s   ø€ Ñ,AÀ,Ô,Or=   zYtarget PID %s command line explicitly advertises a different profile than HERMES_HOME %s.zMcross-profile --replace ownership probe failed for PID %s; refusing to signal)"Úgateway.host_attachrÆ	  rÇ	  rl  Úservesr  rM   r¬   rU   ÚprofilesrÏ   rL   rN   rj  rÈ	  rÉ	  rÊ	  rË	  rÌ	  rÍ	  rÎ	  rÏ	  r½	  ÚWARNINGr   rà   r~   rQ   rm   rD   rá   ÚERRORrÅ  Ú)_looks_like_profile_conflict_from_cmdline)rÄ	  rÆ	  rÇ	  r{  rÈ	  rÉ	  rÊ	  rË	  rÌ	  rÍ	  rÏ	  Úour_homerÔ	  ÚrecordÚ
record_pidÚrecorded_startÚrecorded_homeÚlive_cmdlinerÎ	  s   f                 @r;   Ú(_replace_target_belongs_to_other_profilerå	  M  sO  ù€ ðgßKá“ˆØÒ §¡¨lÔ!:¸u¿|¹|Ù%¤oÓ&7Ó8÷@:ò @:ä�N‰NðJàœc %§.¡.Ó1°4·9±9¸U¿^¹^Ó3L×3YÐ3YÐPYô[ñ ð()÷	d÷ 	dó 	dñ ,Ó-ˆð	¬'¯/©/÷ 	ñ
 "¡-£/Ó2ˆÜ˜&¤$×'Ò'Ñ/IÈ&×/QÒ/QÙÐUÐWcÓdÐdÙ% fÓ-ˆ
Ø˜Ô%ÙÐ?ÀÈ\ÓZÐZØŸ™ LÓ1ˆÜ˜.¬#×.Ò.´*¸^ÌT×2RÒ2RÙÙ" <Ó0°NÔBÙÐnØ&ó(ð (àŸ
™
 =Ó1ˆÜ˜-¬×-Ò-°]×5HÑ5H×5JÒ5JÙÐfØ&ó(ð (á  °×9Ò9Ùð JØKXÐZbÜ '§¡ô/ð /ô $Õ$OÓPˆßÔEÀlÐT\×]Ò]Ùð ,Ø-9¸8Ì7Ï=É=ôZð Záøôo ô gÜ�‰ÐHÈ,Ðaeˆ×fðgûôp ô ä�‰ÐfØ#¨dð 	ô 	4âð	úsb   „BH. ÂH. ÂA#I ÄI ÄI Ä$=I Å#I Å9<I Æ6I Æ?I ÇI Ç(AI È.#IÉIÉ#I?É>I?c                ó0   € V ^8„  d   QhR\         R\        /# )r?   ra  rB   rd  )rF   s   "r;   rG   rG   ¢  s   € ÷ .Vñ .V´sð .VÌñ .Vr=   c                ó¢  a
€ ^ RI Hp V! V4      p \        P                  ! V 4      o
R V
3R llpR V
3R llpR R lpR F%  pV! V4      pVf   K  Ve   VR	8X  g	   Wƒ8w  g   K$   R
# 	  V! R4      ;'       g    V! 4       p	\        V	RJ;'       d    V! V	4      V! \        V4      4      8g  4      #   \         d    T P                  4       o
 L¦i ; i)a  Token-exact contradiction check between a target argv and our home (authority is the pid record).
Substring matching is not identity: ``--profile timothy`` must NOT read as profile ``tim``. Returns
False whenever the argv does not clearly contradict our home.)Ú_profile_name_for_homec                óF   € V ^8„  d   QhR\         R\        \         ,          /# )r?   ÚflagrB   rp  )rF   s   "r;   rG   Ú?_looks_like_profile_conflict_from_cmdline.<locals>.__annotate__­  s   € ÷ .ñ .œ#ð .¤(¬3¥-ñ .r=   c                óŒ  <€ . p^ pV\        S4      8  dž   SV,          pW08X  dB   V^,           \        S4      8  d+   VP                  SV^,           ,          4       V^,          pK`  VP                  V R,           4      '       d%   VP                  V\        V 4      ^,           R 4       V^,          pK­  V'       d
   VR,          # R# )z>Value of ``--flag X`` / ``--flag=X`` occurrences, token-exact.Ú=Nrq  )rU   rs  r™  )rê	  Úvaluesr‹  Útokr!  s   &   €r;   Ú_flag_valueÚ>_looks_like_profile_conflict_from_cmdline.<locals>._flag_value­  s�   ø€ àˆØˆØ”#�f“+ŒoØ˜•)ˆCØŒ{˜q 1�u¤s¨6£{Ô2Ø—‘˜f Q¨¥U�mÔ,Ø�Q•�ÙØ�~‰~˜d S�j×)Ò)Ø—‘˜c¤# d£)¨a¥- .Ð1Ô2Ø��FŠAß#ˆv�b�zÐ-¨Ð-r=   c                ó:   € V ^8„  d   QhR\         \        ,          /# rÖ   rÇ  )rF   s   "r;   rG   rë	  ¼  s   € ÷ ñ œX¤c�]ñ r=   c                 ó~   <€ Rp \        S4       F*  pVP                  V 4      '       g   K  V\        V 4      R u # 	  R# )zAHERMES_HOME=<path> env-style assignment on the argv, token-exact.zHERMES_HOME=N)rÆ  r™  rU   )rl  rï	  r!  s     €r;   Ú_env_home_valueÚB_looks_like_profile_conflict_from_cmdline.<locals>._env_home_value¼  s<   ø€ àˆÜ˜FÖ#ˆCØ�~‰~˜f×%Ô%Øœ3˜v›;˜<Ð(Ò(ñ $ñ r=   c                ó0   € V ^8„  d   QhR\         R\         /# ro  r_   )rF   s   "r;   rG   rë	  Ä  s   € ÷ 8ñ 8”Cð 8œCñ 8r=   c                 óz   € \         P                  P                  \         P                  P                  V 4      4      # rÇ   )rþ   r  ÚnormcaseÚnormpath)r  s   &r;   Ú_normÚ8_looks_like_profile_conflict_from_cmdline.<locals>._normÄ  s&   € Ü�w‰w×Ñ¤§¡× 0Ñ 0°Ó 6Ó7Ð7r=   Nr•   Tz--hermes-home)z	--profilez-p)rj  rè	  ÚshlexrÎ   rô  rm   rD   )ra  rß	  rè	  rÈ  rð	  rô	  rú	  rê	  r  Ú
home_valuer!  s   &&        @r;   rÞ	  rÞ	  ¢  sÒ   ø€ õ 6Ù)¨(Ó3€Lð!Ü—’˜WÓ%ˆ÷.ð .÷ð õ8ó $ˆÙ˜DÓ!ˆØŠ=Ùð Ò <°9Ô#<ÀÖ@UÚñ $ñ ˜_Ó-×BÐB±Ó1B€JÜ�
 $Ð&×TÐT©5°Ó+<ÁÄcÈ(ÃmÓ@TÑ+TÓUÐUøôM ô !Ø—‘“Šð!ús   ‘B0 Â0CÃCc                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   Ó  s   € ÷ ñ  dñ r=   c                 óF   €  ^ RI Hp  V ! 4        R#   \         d     R# i ; i)z_Best-effort: the marker is scoped to one target; a stale one would grief an unrelated shutdown.©Úclear_takeover_markerN)rj  r
  rL   r 
  s    r;   Ú_clear_takeover_marker_quietr
  Ó  s"   € ðÝ8ÙÖøÜô Úðús   ‚ ‘ Ÿ c                óH   € V ^8„  d   QhR\         R\         R\        R\        /# )r?   rl  ÚattemptsÚdelayrB   )rQ   rE   rm   )rF   s   "r;   rG   rG   Ü  s(   € ÷ ñ ¤#ð ´ð ¼Uð Ätñ r=   c              ƒ  ó    "  € ^ RI Hp \        V4       F2  pV! V 4      '       g    R# \        P                  ! V4      G Rj  x€L
  K4  	  R#  L
5i)u»   Poll for process exit without blocking the loop (a blocking sleep freezes signal handlers and
health checks). ``os.kill(pid, 0)`` on Windows is NOT a no-op â€” use the handle-based check.)Ú_pid_existsTNF)rj  r
  Úranger¤   r¢	  )rl  r
  r
  r
  rû  s   &&&  r;   Ú_wait_for_pid_exitr	
  Ü  sB   é € õ +Ü�8Ž_ˆÙ˜3×ÒÚÜ�mŠm˜EÓ"×"Ò"ñ ñ ñ 	#ùs   ‚?AÁAÁAc                ó   a € V 3R lpV# )z[Build the SIGUSR1 handler: log what the signal means, then the drain-aware service restart.c                  óX   <€ \         P                  R 4       S P                  RRR7       R# )u¹   SIGUSR1 received (systemctl reload / hermes gateway restart): performing a graceful gateway restart â€” drain active turns, exit, supervisor relaunches. Not an in-process config reload.FT)ÚdetachedÚvia_serviceN)rM   r  Úrequest_restart)ry  s   €r;   Úrestart_signal_handlerÚJ_start_gateway_make_restart_signal_handler.<locals>.restart_signal_handleré  s+   ø€ ô 	�‰ðô	ð 	×Ñ¨¸4ÐÖ@r=   rº   )ry  r
  s   f r;   Ú*_start_gateway_make_restart_signal_handlerr
  ç  s   ø€ õAð "Ð!r=   c                ó(   € V ^8„  d   QhR\         RR/# )r?   r[  rB   Nr×   )rF   s   "r;   rG   rG   ô  s   € ÷ b'ñ b'¤Dð b'°Tñ b'r=   c                óÎ  € ^ RI Hp V '       gU   ^ RIHpHp V! \        4       R4      pVe8   VP                  V8X  d'   ^ RIHp \        VP                  4       \        V4      h VP                  VP                  4      w  rgWaP                  P                  J dM   VP!                  VP                  R\#        \        4       4      R7       VP%                  VP                  4       R# WaP                  P&                  J d   \(        P+                  RV4       R#  Rp TP1                  TP                  RR
7      pT '       d2   \(        P+                  RT'       d   TP3                  T4      MR4       R# ^ RIHp	Hp
HpHpHp ^ RIHp TeI   T! TP@                  \        4       4      '       d(   \(        P+                  RTP3                  T4      4       R# T! \        4       4      '       dX   T! T	R7      pT! \        4       T4      pTe:   TP                  T
8X  d   R# ^ RIHp \        TP                  4       \        T4      h\C        4       '       d;   \(        P+                  RT'       d   TP3                  T4      MR\E        4       4       R# \G        T4       R#   \,         d    \(        P/                  RRR	7        R# i ; i  \,         d    \(        P/                  RRR	7        EL«i ; i)u  Take the HOST-wide gateway lock, publish the record â€” or REFUSE to be the second gateway.

The lock is no longer observe-only. ``gateway.host_attach`` already answers "is there a host
gateway and does it serve me?" before anything binds, but it reads a RECORD, and a record is
published a moment after the owner starts: two gateways launched together (a supervisor
restarting two units, an update relaunch racing a manual start) can both see no owner and both
proceed. The lock is the only atomic arbiter of that race, so losing it means we are the second
gateway on this host â€” the shape multiplex-only forbids.

The refusal is deliberately EX_TEMPFAIL (75), never the parking 78: losing a lock race is a
runtime observation, not a config verdict. Every supervisor we generate retries 75, and on the
retry the owner's record exists, so the attach path resolves the profile properly (attach,
rescan-then-attach, or a named refusal) instead of the unit being parked forever.

``--force`` skips the question exactly as it does in the attach path.
©Úhost_rendezvous)ÚREFUSEÚstandalone_attach_decisionN©Ú!GATEWAY_SERVICE_RESTART_EXIT_CODE©rÛ	  r+  u•   Host gateway lock could not be opened (%s); this gateway is not discoverable. No second gateway is implied â€” the lock directory itself is unusable.zhost gateway rendezvous failedTrG  )Úinclude_stalezhost gateway record unreadablez>--force: starting a second gateway although %s owns this host.zanother process)ÚATTACH_CHANNEL_WAIT_SÚSTARTrÆ	  Úlaunched_by_other_tenantr
  )Úprofile_is_standalonezZAnother Hermes home's gateway owns this host (%s); starting this home's gateway beside it.)Úwait_for_channelz°Another profile's standalone gateway owns this host (%s); starting beside it rather than retrying a race no second profile can win. Fold every profile onto one gateway with: %szowner unknownrº   )$r9   r
  rÙ	  r
  r
  r  ÚoutcomeÚgateway.restartr
  ÚprintrŸ  rœ	  Úclaim_host_lockÚROLE_GATEWAYÚHostLockOutcomeÚACQUIREDÚpublish_recordrD   Úcleanup_on_exitÚCOULD_NOT_OPENrM   r¬   rL   rN   Úread_recordÚdescriber
  r
  rÆ	  r
  rS  r
  r+  Ú_owner_is_standaloneÚ_migrate_commandÚ_refuse_second_host_gateway)r[  Úhrr
  r
  r  r
  r!
  r¾   r{  r
  r
  rÆ	  r
  r
  Ú
live_owners   &              r;   Ú_claim_host_gateway_roler2
  ô  se  € õ" .÷ ßJÙ-¬oÓ.?ÀÓFˆØÒ H×$4Ñ$4¸Ô$>ÝIÜ�(×"Ñ"Ô#ÜÐ>Ó?Ð?ðØ×+Ñ+¨B¯O©OÓ<‰ˆØ×(Ñ(×1Ñ1Ó1ð ×Ñ˜bŸo™o¸ÄÄ_ÓEVÓAWÐÔXà×Ñ˜rŸ™Ô/ÙØ×(Ñ(×7Ñ7Ó7ô �N‰NðZØ[`ôbñ ð 8ð €EðFØ—‘˜rŸ™¸d�ÓCˆ÷ Ü�‰ÐWß-2�r—{‘{ 5Ô)Ð8Iô	Ká÷õ õ :ØÒÑ5°e·j±jÄ/ÓBS×TÒTô 	�‰ØhØ�K‰K˜Óô	 ñ 	Ùœ_Ó.×/Ò/á!Ð3HÔIˆ
ñ
 .¬oÓ.?ÀÓLˆØÒØ×Ñ 5Ô(ÙÝIÜ�(×"Ñ"Ô#ÜÐ>Ó?Ð?Ü×Òô 	�‰ðç.3˜Ÿ™ EÔ*¸ÔJZÓJ\ô	^ñ 	Ü Ö&øôg ô Ü�‰Ð5ÀˆÔEÚðûô ô FÜ�‰Ð5Àˆ×EðFús+   Á$B J Ã&/J ÄJ> Ê"J;Ê:J;Ê>"K$Ë#K$c                ó$   € V ^8„  d   QhR\         /# rÖ   r_   )rF   s   "r;   rG   rG   Y  s   € ÷ ñ œ#ñ r=   c                  ó   € ^ RI Hp  V # )r  ©ÚMIGRATE_COMMAND)Úhermes_cli.gateway_migrater6
  r5
  s    r;   r.
  r.
  Y  s   € Ý:àÐr=   c                ó$   € V ^8„  d   QhR\         /# rÖ   r×   )rF   s   "r;   rG   rG   _  s   € ÷ ñ œdñ r=   c                 ó>  €  ^ RI Hp HpHp V ! 4       pVe%   VP                  \
        P                  ! 4       8X  d   R# V! V! \        4       4      VR7      p\        VRJ;'       d    VP                  4      #   \         d    \        P                  RRR7        R# i ; i)a  True when the host owner answers that it does NOT multiplex (an unmigrated fleet).

Asked only on the lock-losing path, and any failure answers False: an owner we cannot reach
is treated as a multiplexer, which keeps the second-gateway refusal as the default.
)rÆ	  rÇ	  Úrequest_serve_profileNF)r{  zAstandalone-owner probe failed; keeping the second-gateway refusalTrG  )rÙ	  rÆ	  rÇ	  r:
  rl  rþ   rm  r  rm   Ú
standalonerL   rM   rN   )rÆ	  rÇ	  r:
  r{  Úanswereds        r;   r-
  r-
  _  sŠ   € ðßbÑbá“ˆØŠ=˜EŸI™I¬¯ª«Ô4ÙÙ(Ñ)>¼Ó?PÓ)QÐY^Ô_ˆÜ�H DÐ(×@Ð@¨X×-@Ñ-@ÓAÐAøÜô Ü�‰ÐXØ"ð 	ô 	$âðús   ‚9A6 ½'A6 Á%A6 Á6"BÂBc                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   s  s   € ÷ 8ñ 8¨$ñ 8r=   c                óÊ   € ^ RI Hp ^ RIHp V '       d   VP	                  V 4      MRpRV R\        4        R2p\        P                  RV4       \        V4       \        V4      h)a  Print the named refusal and exit 75 so a supervisor retries instead of parking the unit.

Reached only after losing the host lock, so ``--replace`` is not offered: an owner that serves
this profile was already handled before the claim, and ``--replace`` does not skip the lock.
r
  r
  z"owner unknown (its record is gone)u,   â�Œ Another gateway already owns this host: z¾
   Exactly one gateway per host serves every profile, so this process will not start a
   second one (it would double-bind this profile's platforms).
   Fold every profile onto the owner:  zæ
   Or stop the other gateway first, then start this one.
   Or start one anyway (skips the host-lock check):  hermes gateway run --force
   (--replace does not skip this check; it only replaces an owner that serves this profile.)ú3Refusing to start a second gateway on this host: %s)
r9   r
  r"
  r
  r,
  r.
  rM   r¾   r#
  rœ	  )r{  r0
  r
  ÚwhorŸ  s   &    r;   r/
  r/
  s  sk   € õ .ÝAç %ˆ"�+‰+�eÔ
Ð+O€Cà
6°s°eð <2ô 3CÓ2DÐ1Eð Fgð	hð ô ‡L�LÐFÈÔLÜ	ˆ'„NÜ
Ð6Ó
7Ð7r=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   Š  s   € ÷ Oñ O°ñ Or=   c                ó|  €  \        V P                  RR4      '       g   R# ^ RIHpHp ^ RIHp \        V P                  4       4      pV! RRRR7       F<  w  rVVR8w  g   K  WT9  g   K  V! V4      '       g   K&  \        P                  R	WS4       K>  	  R#   \         d    \        P                  R
RR7        R# i ; i)a  One INFO line per standalone profile when the MULTIPLEXER takes its served set at boot.

The host gateway silently omits an opted-out profile from its served set; without this line an
operator reading the boot log cannot tell "not created yet" from "excluded by config".
rr  FN)rQ  r
  )ÚSTANDALONE_DEPRECATION_NOTICET)Úinclude_standaloneÚinclude_parkedr•   zUprofile '%s' is standalone (gateway.standalone: true); not served by this gateway. %sz%standalone-profile boot notice failedrG  )r8   râ   rS  rQ  r
  r¾  rC
  r   Úserved_profile_namesrM   r¬   rL   )ry  rQ  r
  rC
  r}  r-  r+  s   &      r;   Ú _log_standalone_profiles_at_bootrG
  Š  s¡   € ðOÜ�v—}‘}Ð&:¸E×BÒBÙßPÝSÜ�V×0Ñ0Ó2Ó3ˆÙ+¨DÀTÐZ^×_‰JˆDØ�yÖ  TÖ%7Ñ<QÐRV×<WÔ<WÜ—‘ð  2Ø37öXó `øô ô OÜ�‰Ð>Èˆ×NðOús(   ‚B ¡;B Á!B Á)B Á9B Â"B;Â:B;c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   ž  s   € ÷ Jñ J¨Dñ Jr=   c                óš  € ^ RI Hp ^ RIHp  VP	                  VP
                  4      '       g   R# \        4       p\        V P                  RR4      '       d   \        V P                  4       4      pM	V! V4      3pVP                  VP
                  V\        V4      R7       R#   \         d    \        P                  RRR	7        R# i ; i)
uR  Republish the host record with the SETTLED served set, now that the channel answers.

The claim-time publish is deliberately empty: only the runner knows whether multiplex ended up
on and which profiles it took. A standalone gateway serves exactly its own profile â€” not the
whole roster ``served_profiles()`` would have guessed for it.
r
  )rÇ	  Nrr  Fr
  z"host gateway record refresh failedTrG  )r9   r
  rÙ	  rÇ	  Úowns_host_lockr%
  r  r8   râ   r€   rF
  r(
  rD   rL   rM   rN   )ry  r0
  rÇ	  r+  r}  s   &    r;   Ú_refresh_host_gateway_recordrK
  ž  s£   € õ .Ý9ð
JØ× Ñ  §¡×1Ò1ÙÜÓ ˆÜ�6—=‘=Ð"6¸×>Ò>Ü˜6×6Ñ6Ó8Ó9‰Fá+¨DÓ1Ð3ˆFØ
×Ñ˜"Ÿ/™/°FÄÀTÃÐÖKøÜô JÜ�‰Ð9ÀDˆ×IðJús   Ž B$ ±A1B$ Â$"C
Ã	C
)Ú+_start_gateway_make_shutdown_signal_handlerÚ(_start_gateway_replace_existing_instanceÚ_start_gateway_shutdown_tailÚ*_start_gateway_start_cron_and_housekeepingc                óR   € V ^8„  d   QhR\         R\         R\        \         ,          /# )r?   rØ  r[  rB   )rm   r   )rF   s   "r;   rG   rG   ½  s%   € ÷ !ñ !¬ð !´Tð !ÄhÌtÅnñ !r=   c              ƒ  óÒ  "  € V'       d   \         P                  R4       R# ^ RIHpHpHpHp V! \        4       V R7      pVP                  V8X  dZ   \         P                  RVP                  '       d   VP                  P                  4       MR4       \        VP                  4       R# VP                  V8X  dZ   \         P                  RVP                  '       d   VP                  P                  4       MR4       \        VP                  4       R	# VP                  V8X  d?   VP                  e1   \        VP                  P                   R4      G Rj  x€L
 '       g   R	# R#  L5i)
uš  Attach / rescan / refuse against the ONE host gateway; ``None`` = start normally.

Returns ``True`` when this invocation is satisfied by the running host process (exit 0, nothing
spawned) and ``False`` when it must refuse. The per-home duplicate guard below cannot answer
this at all: another profile's gateway lives in another home, so it sees no PID and starts a
second process â€” the shape multiplex-only forbids.

``force`` is the operator's escape hatch when the owner is wedged or lying: skip the whole
question and start. Ignoring it here made ``--force`` print the starting banner and then attach
anyway, leaving no supported way to start a gateway at all.
z:--force: starting a gateway without asking the host owner.N)ÚATTACHr
  ÚREPLACE_HOSTÚdecide)rØ  zBAttaching to the host gateway instead of starting a second one: %srø   Tr?
  F)rM   r¬   rÙ	  rR
  r
  rS
  rT
  r  r!
  r  r{  r,
  r#
  rŸ  r¾   rM
  rl  )rØ  r[  rR
  r
  rS
  rT
  r  s   &&     r;   Ú_host_attach_or_nonerU
  ½  sÿ   é € ÷ Ü�‰ÐSÔTÙçHÓHá”oÓ'°Ô9€HØ×Ñ˜6Ô!Ü�‰ÐXØ19··°�H—N‘N×+Ñ+Ô-ÀYô	Päˆh×ÑÔÙØ×Ñ˜6Ô!Ü�‰ÐJØ2:·.·.°.�X—^‘^×,Ñ,Ô.Àiô	Qäˆh×ÑÔÙØ×Ñ˜<Ô'¨H¯N©NÒ,Fä=¸h¿n¹n×>PÑ>PÐRVÓW×WÖWÙÙñ Xùs&   ‚A0E'Á3A)E'ÃA9E'ÅE%Å	E'Å!E'c                óŒ   € V ^8„  d   QhR\         \        ,          R\        R\         \        ,          R\        R\        R\        /# )r?   râ   rØ  Ú	verbosityr[  Ú	idle_exitrB   )r   r¶  rm   rQ   )rF   s   "r;   rG   rG   á  sK   € ÷ Iñ I¤¬Õ 7ð IÌð IÜ#+¬C¥=ðIÜ=AðIÜVZðIÜgkñIr=   c              ƒ  ó>   "  € ^ RI Hp V! WW#V4      G Rj  x€L
 #  L5i)zKRun the process lifecycle; the runner facade remains the public entrypoint.)Ústart_gatewayN)Úgateway.run_bootstraprZ
  )râ   rØ  rW
  r[  rX
  Ú	bootstraps   &&&&& r;   rZ
  rZ
  á  s    é € õ AÙ˜6¨I¸iÓH×HÐHÑHùs   ‚–—c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rG   è  s   € ÷ 
%ñ 
% Dñ 
%r=   c                 ó˜   € ^ RI Hp Hp  V! 4        R#   T  d0   p\        RT 2\        P
                  R7       \        ^4      ThRp?ii ; i)a%  Fail closed when the active profile's config.yaml cannot be parsed: nobody can repair it on this
surface, and defaults would let provider auto-detection adopt ``.env`` credentials the config never
named. Same policy and escape hatch (``HERMES_IGNORE_USER_CONFIG=1``) as ``hermes_cli/main.py``.)ÚInvalidUserConfigErrorÚrequire_parseable_user_configzError: r�  N)r  r_
  r`
  r#
  rù   rˆ  rœ	  )r_
  r`
  rY   s      r;   Ú_guard_corrupt_user_configra
  è  sC   € ÷ Xð%Ù%Ö'øØ!ô %Ü�˜�uˆo¤C§J¡JÕ/Ü˜‹m Ð$ûð%ús   Š “A	š*AÁA	c                 ó  € \        4        \        P                  P                  RR4       \        P                  P                  RR4       R R lp R R lpR	 R
 lpWV3 F  p\	        V4       K  	   ^ RIHp ^ RIHp V! V! 4       4      pV'       d   \        P                  V4        ^ RIHp ^ RIHp T! T! 4       4       ^ RIpTP!                  RR7      p	T	P#                  RRRR7       T	P#                  RRRRR7       T	P%                  4       p
RpT
P&                  '       dr   ^ RIp\+        T
P&                  RR7      ;_uu_ 4       p\,        P.                  ! TP1                  T4      ;'       g    / 4      pRRR4       ^ R IHpHp T! T! T4      4        \8        P:                  ! \=        T4      4      pT'       d   ^ M^p\G        T4       R#   \         d    \        P                  RRR7        ELLi ; i  \         d    \        P                  RRR7        EL[i ; i  + '       g   i     L±; i  \>         dI   pTP@                  f   ^ M-\C        TP@                  \D        4      '       d   TP@                  M^p Rp?LÀRp?ii ; i)!z CLI entry point for the gateway.ÚAI_AGENTzhermes-agentÚHERMES_AGENTrÞ   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   Úmain.<locals>.__annotate__ÿ  s   € ÷ +ñ + ñ +r=   c                  ó4   € ^ RI Hp Hp V! R4       V ! 4        R# )r  ©Ú attach_self_to_kill_on_close_jobÚregister_selfr9   N)Úhermes_cli.process_identityri
  rj
  rh
  s     r;   Ú_register_identityÚ main.<locals>._register_identityÿ  s   € ç_Ù�iÔ Ù(Ö*r=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rf
    s   € ÷ ñ ˜4ñ r=   c                  ó    € ^ RI Hp  V ! 4        R# )r  ©Úarm_startup_watchdogN)Úhermes_startup_watchdogrq
  rp
  s    r;   Ú_arm_watchdogÚmain.<locals>._arm_watchdog  s   € õ 	AÙÖr=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   rf
    s   € ÷ "ñ "˜ñ "r=   c                  ó    € ^ RI Hp  V ! 4        R# )r  ©Úconfigure_windows_stdioN)Úhermes_cli.stdiorx
  rw
  s    r;   Ú_utf8_stdioÚmain.<locals>._utf8_stdio  s   € å<ÙÖ!r=   )Úcheck_runtime)Úinstall_rootzpm startup check failedTrG  )Úmaybe_run_boot_bootstrapzboot bootstrap failedNz)Hermes Gateway - Multi-platform messaging)rb  z--configz-czPath to gateway config file)Úhelpz	--verboser†  Ú
store_truezVerbose output)Úactionr
  rÞ  )rß  r¸  )$ra
  rþ   rÿ   rú  rÅ  Úhermes_cli.venv_syncr|
  Úpm.pathsr}
  rM   r¬   rL   rN   Úhermes_cli.boot_bootstrapr~
  ÚargparseÚArgumentParserÚadd_argumentÚ
parse_argsrâ   Úhermes_yamlrÍ  r¶  Ú	from_dictÚ	safe_loadr¾  r¹  rº  r¤   r§   rZ
  rœ	  rA  r   rQ   Ú_exit_after_graceful_shutdown)rl
  rs
  rz
  Ú_stepr|
  r}
  Úproblemr~
  r…
  Úparserré  râ   ÚyamlÚfr¹  rº  r¶  rD  Úes                      r;   r/  r/  õ  sÿ  € ô Ô ô ‡J�J×Ñ˜* nÔ5Ü‡J�J×Ñ˜.¨&Ô1õ+õõ"ð
 %°[ÓAˆÜ�UÖñ Bð?Ý6Ý)á¡£Ó/ˆßÜ�N‰N˜7Ô#ð=ÝFÝ)á ¡£Ô0ó Ø×$Ñ$Ð1\Ð$Ó]€FØ
×Ñ˜
 DÐ/LÐÔMØ
×Ñ˜ T°,ÐEUÐÔVØ×ÑÓ€Dà€FØ‡{‡{€{Û"Ü�$—+‘+¨×4Õ4¸Ü"×,Ò,¨T¯^©^¸AÓ->×-DÐ-DÀ"ÓEˆF÷ 5÷ 	eÙÑ5°fÓ=Ô>ðVô —+’+œm¨FÓ3Ó4ˆß ‘A aˆ	ô " )Ö,øôW ô ?Ü�‰Ð.¸ˆ×>ð?ûô ô =Ü�‰Ð,°tˆ×<ð=ú÷ 5×4ûô* ô VàŸ™š‘A´zÀ!Ç&Á&Ì#×7NÒ7N¨Q¯VªVÐTU�	ûðVúsN   Á4 G ÂG Â+G: Å
0H#Æ+H6 Ç"G7Ç6G7Ç:"H ÈH È#H3	È6J	É>JÊJ	c                ó(   € V ^8„  d   QhR\         RR/# )r?   rD  rB   Nr  )rF   s   "r;   rG   rG   L  s   € ÷ +ñ +¬Sð +°Tñ +r=   c                ó`  a € \         P                  \         P                  3 F3  p\        \        4      ;_uu_ 4        VP                  4        RRR4       K5  	  R R lpR V 3R llpR R lpW#V3 F  p\        V4       K  	  \        P                  ! S 4       R#   + '       g   i     K‹  ; i)uh  Flush stdio, release the PID file + runtime lock, then hard-exit.
``os._exit`` (not ``sys.exit``): SystemExit runs ``Py_FinalizeEx``, which joins every non-daemon
thread â€” exactly the hang a wedged worker causes. It bypasses ``atexit``, so PID/lock release and the
bounded log drain (file handlers sit behind a ``QueueListener`` thread) are done here explicitly.

Graceful teardown is already complete by the time this runs, so there is nothing left that needs a clean
interpreter shutdown. See #53107.
``os._exit`` bypasses ``atexit`` handlers, so we cannot rely on the ``atexit``-registered
``remove_pid_file`` / ``release_gateway_runtime_lock`` (registered in ``start_gateway``) to run. The
full-shutdown path releases both explicitly in ``_stop_impl``, but the EARLY exit paths â€”
clean-fatal-config (#51228) and startup-aborted-before-running â€” raise ``SystemExit`` right after
``runner.start()`` without going through ``_stop_impl``, so on those paths ``atexit`` was the only thing
releasing them. Now that those paths are routed through this backstop (#53107), release both here
explicitly. Both calls are idempotent â€” ``remove_pid_file`` only unlinks a PID file that belongs to this
process, and ``release_gateway_runtime_lock`` no-ops when the lock is already released â€” so this is a
no-op on the normal shutdown path and the actual cleanup on the early-exit paths.
Nc                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   Ú3_exit_after_graceful_shutdown.<locals>.__annotate__a  s   € ÷ 'ñ '˜Dñ 'r=   c                  ó2   € ^ RI Hp Hp V ! 4        V! 4        R# )r  ©Úremove_pid_fileÚrelease_gateway_runtime_lockN)rj  r™
  rš
  r˜
  s     r;   Ú_release_locksÚ5_exit_after_graceful_shutdown.<locals>._release_locksa  s   € çPÙÔÙ$Ö&r=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   r–
  g  s   € ÷ ;ñ ;˜$ñ ;r=   c                  óD   <€ ^ RI Hp  V ! R4       ^ RIHp V! SRR7       R# )r  )Ú
stamp_exitÚclean)Úmark_exitedÚgraceful_shutdownru  N)rÀ  rŸ
  Úgateway.lifecycle_ledgerr¡
  )rŸ
  r¡
  rD  s     €r;   Ú_mark_exitedÚ3_exit_after_graceful_shutdown.<locals>._mark_exitedg  s   ø€ õ 	OÙ�7ÔÝ8Ù�IÐ&9×:r=   c                ó   € V ^8„  d   QhRR/# rð   rº   )rF   s   "r;   rG   r–
  o  s   € ÷ %ñ %˜ñ %r=   c                  ó$   € ^ RI Hp  V ! RR7       R# )r  ©Údrain_log_queuer�   rž   N)rt  r©
  r¨
  s    r;   Ú_drain_logsÚ2_exit_after_graceful_shutdown.<locals>._drain_logso  s   € õ 	3Ù ×$r=   )	rù   r‡  rˆ  r}   rL   ÚflushrÅ  rþ   Ú_exit)rD  Ústreamr›
  r¤
  rª
  r�
  s   f     r;   rŒ
  rŒ
  L  s}   ø€ ô$ —:‘:œsŸz™zÓ*ˆÜ”i× Õ Ø�L‰LŒN÷ !Ñ ñ +õ'÷;ð ;õ%ð !°Ó<ˆÜ�UÖñ =ä‡H‚HˆYÖ÷1 !× Ð ús   ¼BÂB-Ú__main__c                óf  € V ^8„  d   Qh/ ^ \         9   d   \        \        R3,          ;R&   ^\         9   d
   \        ;R&   ^\         9   d
   \        ;R&   ^\         9   d   \        P
                  ;R&   ^\         9   d6   \        \        \        \        \        \        \        3,          3,          ;R&   # )r?   .r\  ri  Ú_CONVERSATION_SCOPED_STATErû  r¸  )Ú__conditional_annotations__r€   rD   rà   rù  rú  rt  )rF   s   "r;   rG   rG      s°   € ÷ Eñ E÷t"ò œ%¤ S �/ñ ñu"E÷bB ‚„d�ñcBE÷RG#ò #œEñ #ñSGE÷J` 1Ò 0”X—\‘\Ñ 0ñK`E÷bgJò J”4œ¤%¬¬S´#´sÐ(:Õ";Ð;Õ<ñ JòcgEr=   )Úsession_resetÚ	user_exitÚsession_switchÚnew_sessioni   )ræ  é   é	   rÇ   >   ÚlocalÚwebhookÚ
api_serverÚmsgraph_webhook)z3(?:\w+\.)?(?:api\s*)?connection\s*(?:error|timeout)ú%(?:\w+\.)?connect\s*(?:error|timeout)úconnection\s+refusedúconnection\s+resetúconnection\s+abortedúactively\s+refusedúwinerror\s+10061\búerrno\s+111\búno\s+route\s+to\s+hostúnetwork\s+is\s+unreachableúcannot\s+connectúfailed\s+to\s+establishúcould\s+not\s+connect)r¿
  rÀ
  zerrno\s+104\bzerrno\s+103\bzbroken\s+pipezserver\s+disconnectedzpeer\s+closed\s+connectionzconnection\s+was\s+closedznetwork\s+connection\s+lostzunexpected\s+eofzincomplete\s+chunked\s+readzresponse\s+ended\s+prematurelyzsocket\s+hang\s+upz(?:\w+\.)?remoteprotocolerrorz(?:\w+\.)?readerror)
r¾
  rÁ
  rÂ
  rÃ
  rÄ
  rÅ
  rÆ
  rÇ
  rÈ
  r½
  >   ÚTimedOutÚ	ReadErrorÚ
WriteErrorÚPoolTimeoutÚReadTimeoutÚConnectErrorÚNetworkErrorÚWriteTimeoutÚClientOSErrorÚConnectTimeoutÚRemoteProtocolErrorÚClientConnectorErrorÚServerDisconnectedError)zapi\s+(?:call\s+)?failedz"provider\s+authentication\s+failedznon-retryable\s+errorz&rate\s+limited\s+after\s+\d+\s+retrieszerror\s+code\s*:zhttp\s*\d{3}\bzincorrect\s+api\s+keyzinvalid\s+api\s+key)z$all\s+connection\s+attempts\s+failedrd  )r”   )Ú	reasoningrY  Úreasoning_detailsÚcodex_reasoning_itemsÚcodex_message_itemsÚfinish_reasonrÁ  >   rÜ  Útext_to_speechÚtext_to_speech_tool)Ú
host_imageÚimageÚagent_visible_image)r  N)
rÌ  rÍ  rÎ  rÏ  Ú_pending_model_notesrÐ  rÑ  Ú_session_stall_notifiedÚ_transcript_lag_streaksrÒ  r|  )Úrun_conversationÚrun_syncÚ _run_sync_with_timeout_lifecycleÚfinalize_turnÚend_turnÚrun_in_session)éP   )r»
  ÚAPIServerAdapterÚcheck_api_server_requirementsz!API Server: aiohttp not installed)rº
  ÚWebhookAdapterÚcheck_webhook_requirementszWebhook: aiohttp not installed)r¼
  ÚMSGraphWebhookAdapterÚ"check_msgraph_webhook_requirementsz&MSGraph webhook: aiohttp not installed)NNé<   NNN)NNrð
  )gš™™™™™¹?)r1   N)NFr  FF(ã  r²
  rG  r   ÚModuleNotFoundErrorrY   r-  r¤   Úconcurrent.futuresr¼  rm  rã  r½	  rþ   rÈ   rü	  r  rù   Úsignalr©  rÁ   r«  Úcollectionsr   Úcontextvarsr   r   Úpathlibr   r   Útypingr	   r
   r   r   r   r   r   Úagent.async_utilsr   Ú
agent.i18nr   Úagent.conversation_compressionr   r   r   r   r   r   r   r   r   r   Ú&agent.conversation_compression_archiver   r   r   Úagent.conversation_loopr    Úagent.interrupt_compatr!   Úagent.message_metadatar"   r#   r$   r%   r&   Úagent.turn_contextr(   Úagent.session_activityr)   r*   r  r+   r,   Úhermes_cli.fallback_configr-   Úgateway.turn_executorr/   Ú_AGENT_CACHE_MAX_SIZEÚ_AGENT_CACHE_IDLE_TTL_SECSÚ&_PLATFORM_CONNECT_TIMEOUT_SECS_DEFAULTÚ&_TELEGRAM_CONNECT_TIMEOUT_SECS_DEFAULTÚ._TELEGRAM_INITIAL_CONNECT_TIMEOUT_SECS_DEFAULTÚ(_ADAPTER_DISCONNECT_TIMEOUT_SECS_DEFAULTrM  Ú_USER_BOUNDARY_END_REASONSÚ"_STALL_NOTIFY_SEND_TIMEOUT_SECONDSÚ#_GATEWAY_PROXY_SSE_BUFFER_MAX_CHARSÚcompilerí  Ú_GATEWAY_HYGIENE_PLATFORMrÉ   Ú
IGNORECASEÚDOTALLr¡  rS   rV   Ú_HYGIENE_TURNHOLD_RETRY_SECONDSr<   r\   rd   ro   rw   r„   r³   r»   r«   rÑ   rÏ   r¢  rä   r;  rë   rí   Ú_GATEWAY_PROVIDER_POLICY_REÚ_GATEWAY_AUTH_ERROR_REr‡  Ú_CONNECTION_ERROR_MARKERSÚ_GATEWAY_CONNECTION_ERROR_REÚ_CONNECTION_INTERRUPTED_MARKERSÚ"_GATEWAY_CONNECTION_INTERRUPTED_REÚ_ENDPOINT_UNREACHABLE_MARKERSÚ _GATEWAY_ENDPOINT_UNREACHABLE_REr  rê   r"  r'  r0  r7  r=  rN  rU  r\  rv  r…  rz  r‚  rŠ  Ú_PROVIDER_ERROR_MARKERSr�  r’  rœ  r£  r§  r°  rÀ  rÊ  rÓ  rÜ  rð  r<  r  r  r÷  rþ  r  r	  r$  r+  r  r7  r>  rL  rQ  r\  rc  rg  rÀ  rÁ  rh  rm  rx  r|  r‚  r‰  rŒ  r²  r½  rÃ  rÈ  râ  Úagent.replay_cleanupr¡  rÌ  rÍ  rÎ  rŸ  rå  ræ  Úgateway.media_repairrÕ  rá  rï  r  r
  r  r  r  r  rÿ   r  r  rD   rú   rü   r¢  r  r  r  r  r£  r  Ú	_env_pathrû   r'  r)  r(  r>  Ú
contextlibr?  Ú_asynccontextmanagerr@  rû  r}   rÝ  rB  rL   rJ  rU  r_  ro  rv  r~  rƒ  r�  r—  r¦  r°  r´  rÁ  rÉ  rÝ  rI  rJ  Úhermes_cli.config_defaultsrÞ  rœ  ry  r3  rz  r2  r1  rO  rg  rƒ  r0  Ú_config_pathri  r  Ú_bridge_errr#
  r5  r6  rˆ  r�  r~   Ú_network_cfgr   rà   Ú_bootstrap_excr’  r“  Úgateway.cwd_placeholderr•  r–  rØ  r—  rt  r¶  rÌ  r˜  r¿  Úgateway.sessionr™  rš  r›  rœ  r�  rž  Úgateway.deliveryrŸ  Úgateway.turn_leaser   Úgateway.session_stater¡  r¢  r£  Úgateway.authz_mixinr¤  Úgateway.kanban_watchersr¥  Úgateway.slash_commandsr¦  Úgateway.run_voicer§  Úgateway.run_adaptersr¨  Úgateway.run_topicsr©  Úgateway.run_turnrª  r«  Úgateway.run_shutdownr¬  r­  Úgateway.run_busyr®  Úgateway.run_config_loadersr¯  Úgateway.run_startupr°  r±  Úgateway.run_watchersr²  Úgateway.run_notificationsr³  Úgateway.run_inboundr´  Úgateway.run_goalsrµ  Úgateway.run_agent_cacher¶  r‹	  r·  Úgateway.run_plugin_rewirer¸  Úgateway.platforms.baserø  r¹  r—  Úgateway.platforms.eventrº  r»  r"
  r¼  r½  r¾  r¿  Ú	getLoggerrM   rÅ  Ú_EXECUTOR_QUIESCE_TIMEOUTrÔ  rN  r£   r±
  rä  rÞ  râ  rî  r  r&  r-  r0  r7  r?  rF  rM  rQ  rU  r[  ra  rm  r’  r–  Ú_INTERRUPT_REASON_STOPÚ_INTERRUPT_REASON_RESETr¾  r¿  Ú_INTERRUPT_REASON_EVICTEDÚ_INTERRUPT_TOOL_REASON_EVICTEDÚ'_INTERRUPT_TOOL_REASON_GATEWAY_SHUTDOWNÚ _INTERRUPT_REASON_SSE_DISCONNECTÚ"_INTERRUPT_REASON_GATEWAY_SHUTDOWNÚ!_INTERRUPT_REASON_GATEWAY_RESTARTr   r­  r²  rÂ  rÐ  r¢   rÓ  rÔ  rÚ  ré  rþ  r  r  r
  rß   Ú gateway.session_worker_constructr  Ú_checkpoint_agent_kwargsr  r  r   r,  r4  r5  r:  rK  r_  rh  Úweakrefrù  rû  r}  rw  r‡  rŽ  r’  r—  r˜  r�  r¢  r'  Ú_AUTO_RESET_CONTEXT_NOTESr¨  r­  rµ  rG  rH  r<  r¸  r¼  Úgateway.run_runtime_initr½  r¿  r	  r	  r	  r	  r 	  r+	  r2	  r7	  r;	  rM	  rV	  r\	  rb	  rn	  r“	  r˜	  r�	  Ú_CRON_SHUTDOWN_DRAIN_TIMEOUTÚ$_HOUSEKEEPING_SHUTDOWN_DRAIN_TIMEOUTr£	  r·	  r»	  rÂ	  rå	  rÞ	  r
  r	
  r
  r2
  r.
  r-
  r/
  rG
  rK
  r[
  rL
  rM
  rN
  rO
  rU
  rZ
  ra
  r/  rŒ
  rG   )r²
  s   @r;   Ú<module>rM     s  øð÷Eð EðÛó
 Û Û Û Û Û 	Û 	Û Û Û 
Û Û Û Û Ý #ß -Ý Ý ß C× CÑ Cå 6Ý ÷P÷ P÷ P÷
 sÑ rÝ FÝ 9÷ Rõ  RÝ 8ß Eß ?Ý @Ý :ð Ð Ø#Ð Ø)-Ð &à).Ð &ð 26Ð .Ø+.Ð (àÐ ñ ]Ð à%)Ð "Ù&6Ð #Ø!ŸzšzÐ*TÓUÐ Ø-Ð àŸJšJð	ð 
�ŠÐ$Ó	%Ð&Øˆ�ŠÐ.Ó	/Ð0ð	ð 
�ŠÐ)Ó	*Ð+Øð;	ð< ‡M�M�B—I‘IÕó?Ð ñB (1Ð $à &Ð à"&Ð ò2õ#RõLTõ$Võ(DõEð> àRW÷> ð@	GØ[`÷	G÷Ið Iõ&=ð #%§*¢*Ø‡H�Hñ @ð Ð:Ð<RÐTwØ1Ð3RØ7Ð9cØ4Ø=ñ?ó@ó @ð ‡M�Mó	#Ð õñ$ (Ó(]Ó^Ð õLð
 !Ÿjšjð
	ð ‡M�MóÐ ð" Ÿšðà‡M�MóÐ ð
 ŸšØ>ÀÇÁóOÐ ñOÐ ð
  "Ÿzšz¨#°·±Ð9RÓ0SÕ*SÐVYÕ*YÐ[]×[hÑ[hÓiÐ ñ#>Ð ð &(§Z¢ZØˆ#�(‰(Ð2Ó
3Õ3°cÕ9¸2¿=¹=ó&JÐ "ñ!dÐ ð $&§:¢:Øˆ#�(‰(Ð0Ó
1Õ1°CÕ7¸¿¹ó$HÐ  õ.õbKò
ØBF÷ð ÷ð õñ" (1ó 2-ó (.Ð $õõ2,õ2#õ
=ðEØTXðEàðEà5:÷EðN Ð:Ð;ØÐ9Ð:Ø Ð">Ð?Ø'Ð)PÐQØ%Ð'CÐDØ!Ð#FÐGðIÐ õ0õWõ5ñ6Ð ð $&§:¢:ØØ	‡h�hÐ&Ð)BÀ2Õ)FÕFÑIsÕsÓtõuà	õ
ð ‡M�Mó	$Ð  õ	?õ"õJõ*:ò	Cõ3ðlØ\`÷õ,	FðØKPðàðàKO÷õ4<ñ" )0Ð %ð /3Ð +ð (,Ð $õõ:,õkõ]õ&õRõõ1ð
)Ø*.ð
)ØOS÷
)ò(1ØEI÷(1ð (1ðV-ØJN÷-ñB-Ð ó ÷
1ð 1ðh ,MÐ (Ø!aÐ ð %OÐ !õ_õJ÷$ð $õ(<÷
Jð JõõðI+ØFJðI+à#÷I+õXõ0õ*ó( !\Ð õ =ð @Ð Ø!>Ð õFõ
ñ  NÐ ð —’ðð ‡M�Mó€õ O÷9+ð 9+õx(õT[õ>õ
<õ
2õ9ð !$€‡
‚
ÐÑ à ‡‚‡‚�‘3‘t˜H“~×,Ò,×3Ò3Ó4Ô 5ç _Ñ _ñ
 'Ó(€õ 5Ø˜6Õ!€	Ù ˜|¹¸h»×9OÒ9OÓ9Q×9YÒ9YÐZ[Õ9\Ð_eÕ9eÕ fõ	0õJõ$C÷( pÑ oôR˜<ô Rô
g˜iô gõ
3õõ$_õ6õ&õ$)õE÷&,ð ,õ/ð ò 3à ÷ 3ó ð 3ðF ôó ðõ&õRjõ:cð< ŸšÐ$dÓeÐ Ø(1°:Ð'>Ð $õ IÙ*-¨o¸gÕ.FÐGcÕ.dÓ*e€‡
‚
Ñ&Ñ 'ñ
 Ñ-Ø Ñ"=ÙÑ=ÙÑ=ÙÑ;ÙÑ;ÙÑ5Ù%Ñ'GÙ+Ñ-SÙ$Ñ&Eð
GÐ ñ "Ñ#3Ñ5EÑG^Ð_Ð áÑ7ÙÑ5ÙÑ9ð;Ð ÷<÷
0÷2a÷jE÷.*r÷Z	3ð ™mÕ+�Ø�ƒÙ×Ò×ÒðÙ"¡<Ó0‰Ù™dÔ#ð_ß6Ð6Ù—8’8™I rÓ*�LÚ‘,¡×%Ò%©,×*:Ò*:¹<×*HÒ*HÚ DÖ)ðUß7Ð7ÚÔðUß>Ð>Ú Ô"ð !€‡
‚
‰>Ñ ÷ WÕ V÷\÷ \÷ \õ \÷(÷ (÷ (õ (÷ ,Ñ +ß 7Ñ 7ß a× aÑ aß 9Ñ 9ß >Ñ >ß <Ñ <ß /Ñ /ß =Ñ =ß 7Ñ 7ß QÕ Qß TÕ Tß 4Ñ 4ß @Ñ @ß EÕ Eß <Ñ <ß ?Ñ ?ß 3Ñ 3ß /Ñ /ß :Ñ :ß FÑ Fß >Ñ >÷÷ ñ ÷
 >Õ =÷4÷ 4õ 4ð 
×	Ó	™8Ó	$�÷ó ñ  Ñ ÷ð ò< !›(Ñ ñ%#Ñ ó #÷$"Lð "L÷J?ð ?ð ×Ó˜dÕ#÷ò ó $ñ÷QFó QF÷hAó A÷"	1ð 	1÷ð ÷Bð B÷Bð B÷Xð X÷kð k÷hð h÷Xð X÷ð ñ"7ØOS÷7ò 7÷,#ð #÷!ð !÷H4ð 4ñ *Ñ Ù3Ñ Ù>Ñ á!>Ñ ÙFÑ á!2Ñ Ù*<Ñ 'Ù#<Ñ  Ù%<Ñ "Ù$8Ñ !ñ!à59÷!ò !ñH"3Ñ ÷
Eð Eñ@ð 6:÷ò ñ@ àY\ñ ð 6:÷ ò  ñF (Ù× Ò Ó"Ñ$;×$AÒ$AÓ$CÙ×#Ò#Ó%Ñ'G×'MÒ'MÓ'OÙ×#Ò#Ó%Ñ'I×'OÒ'OÓ'QÙ%×+Ò+Ó-ð	)/ó 0Ñ ÷Yð Y÷	\ð 	\÷)ð )÷>&ð &÷RCð C÷
fð f÷8ð 8÷ó ÷ aÑ `÷Nó Nñ[Ø04ñ[ØQU÷[ò [ñØ[_ñà#÷ò ÷$ð ð$ —Z’ZÑ =Ó>Ñ ÷ð ÷2ó ÷ó ÷Dð ÷<ð õ0 Ú$0Ñ Ó 0ñSØ=>÷Sò S÷l>ð >÷6ð 6÷Að A÷ Mð Mñ6 Ñ ÷Bð B÷
Lð L÷
*ð 
*ò “xÑ ñ
 ñ  MðÑ ÷
ð ÷ð ÷ Að Añ ×Òñ ?á×Òñ 9á×Òñ Ið@JÑ ó J÷
ð 
÷ =Ñ <öpÙÑ9Ñ;TÙÑ3Ñ5MÑO_ÙÑ1Ñ3LÑNaÙÑ!:Ñ<OÑQbÙÑ3Ñ5QÑSkõpñf*'á÷*'ò *'÷Z1ð 1÷	#ð 	#÷`ð `÷Lð L÷mð m÷(ð (÷	1ð 	1÷ð ÷ó ÷B:ð :÷ 9ð 9÷ð ÷Hó H÷2E0ó E0÷P`ó `÷<ð <ñ  $Ñ ñ (,Ñ $÷!ó !÷ 4ó 4÷n	Rð 	R÷Qð Q÷Rð R÷j.Vð .V÷bð ÷ð ô
"÷b'ó b'÷Jð ÷ð ÷(8ð 8÷.Oð O÷(Jð J÷2÷ õ ÷!ó !÷HIó I÷
%ð 
%ôT-÷n+ð +ñ\ ‰zÔÚ†Fñ øðcc ô Ø
‡x�xÐ%Ô%Øõ &ûðûð\B õ âÙ<ºTÁ+Ó=N×=WÒ=WÐ<XÑXZÑ[fÐZgÐhØ—’ö	ò 	ñLà—’÷	ö 	ýðûð  õ _Ú	Ñ;¹NÐ;KÐ
LÐSV×S]ÒS]×^Ö^ýð_ûð õ UÚ	Ñ1±.Ð1AÐ
BÈÏÊ×TÖTýðUûð õ UÚ	Ñ1±.Ð1AÐ
BÈÏÊ×TÖTýðUúsˆ   Œ{ Ý?| Þ0}+ ß}+ ß}+ ß*~! ß< û|û&{>û>|ü}(üA}!ý!}(ý+~ý3~þ~þ!þ)ÿÿA@
ÿA@Á@A@
