+
    jHàj0  ã                   ó®  a€ R- t:0 t R t^ RIt^ RIHt ^ RIHt ^ RIHtH	t	 ]
! 4       t] ^ k Rs] ^k R R lt];QJ d    . R R. 4       F  NK  	  5M! R R. 4       4      ;tw  ttttttttttttttttt t!t"]! R	]R
7      t#]! R]R
7      t$]! R]R
7      t%]! R]R
7      t&]! R]R
7      t'. ]O]%N]&N]'N U u/ uF  q PP                  V bK  	  up t)R R lt*R R lt+]R/R R ll4       t,]R R l4       t-R R lt.R R lt/RRRRRRRRRRRRRRRRRRR]RR3R R llt0R R  lt1R! R" lt2R0R# R$ llt3]4! 0 R1m4      t5R% R& lt6R' R( lt7R) R* lt8R+ R, lt9R# u up i )2aI  Session-scoped context variables for the Hermes gateway.

Replaces the old ``os.environ``-based ``HERMES_SESSION_*`` state with task-local ``ContextVar``s
(inherited by ``run_in_executor`` threads), so concurrently handled messages no longer clobber each
other's routing ids.  ``get_session_env`` is a drop-in for ``os.getenv``.
N)Úcontextmanager)Ú
ContextVar)ÚAnyÚIteratorFc                ó$   € V ^8„  d   QhR\         /# ©é   Úreturn©Úbool)Úformats   "Ú</home/ubuntu/.hermes/hermes-agent/gateway/session_context.pyÚ__annotate__r      s   € ÷ $ñ $¤ñ $ó    c                 ó   € \         # )zHTrue if any session has been bound via set_session_vars in this process.)Ú_session_context_engaged© r   r   Úsession_context_engagedr      s   € ä#Ð#r   c              #   óD   "  € T F  p\        V\        R 7      x € K  	  R# 5i)©ÚdefaultN)r   Ú_UNSET)Ú.0Únames   & r   Ú	<genexpr>r   (   s"   é € ð 
ñ 8¨tŒ*�T¤6×
*Ñ
*ó 8ùs   ‚ ÚHERMES_SESSION_ASYNC_DELIVERYr   ÚHERMES_SESSION_HISTORY_DELIVERYÚ!HERMES_CRON_AUTO_DELIVER_PLATFORMÚ HERMES_CRON_AUTO_DELIVER_CHAT_IDÚ"HERMES_CRON_AUTO_DELIVER_THREAD_IDc                ó4   € V ^8„  d   QhR\         R\        RR/# )r   ÚfuncÚargsr	   N)Ústrr   )r   s   "r   r   r   H   s!   € ÷ ñ ”sð ¤3ð ¨4ñ r   c                óV   €  ^ RI Hp \        W 4      ! V!   R#   \         d     R# i ; i)zVBest-effort call of ``agent.runtime_cwd.<func>``; import/runtime failures are ignored.)Úruntime_cwdN)Úagentr%   ÚgetattrÚ	Exception)r!   r"   r%   s   &* r   Ú_runtime_cwdr)   H   s)   € ðÝ%Ü�Ô" DÔ)øÜô Úðús   ‚ ™(§(c                ó(   € V ^8„  d   QhR\         RR/# )r   Ú
session_idr	   N©r#   )r   s   "r   r   r   Q   s   € ÷ 1ñ 1¤sð 1¨tñ 1r   c                ó¦   € \         P                  V 4        ^ RIHp V! 4       '       d   R#  V \
        P                  R&   R#   \         d     L"i ; i)zôSynchronize ``HERMES_SESSION_ID`` across ContextVar and ``os.environ`` (tools read it
with an os.environ fallback).  Delegated subagent children (built in the parent process)
get ONLY the task-local write, or they would clobber the parent's id.)Úis_delegated_child_contextNÚHERMES_SESSION_ID)Ú_SESSION_IDÚsetÚagent.delegation_contextr.   r(   ÚosÚenviron)r+   r.   s   & r   Úset_current_session_idr5   Q   sN   € ô ‡O�O�JÔðÝGÙ%×'Ò'Ùð (ð '1„B‡J�JÐ"Ó#øô ô Ùðús   —A ÁAÁAc                óL   € V ^8„  d   QhR\         R,          R\        R,          /# )r   r+   Nr	   ©r#   r   )r   s   "r   r   r   `   s"   € ÷ 	"ñ 	"¬#°­*ð 	"ÄÈÅñ 	"r   c              #  óÐ   "  € \         P                  4       pV e   \         P                  V 4        Rx € \         P                  V4       R#   \         P                  T4       i ; i5i)z•Bind a task-local session id and restore the prior value on exit; never touches
``os.environ``.  ``session_id=None`` is a pure save/restore boundary.N)r0   Úgetr1   )r+   Úpreviouss   & r   Úscoped_current_session_idr;   _   sE   é € ô �‰Ó €HØÒÜ�‰˜
Ô#ð"Ûä�‰˜Ö!øŒ�‰˜Õ!üs   ‚.A&±A µA&ÁA#Á#A&c                ó>   € V ^8„  d   QhR\         R\        R,          /# )r   Úsession_keyr	   Nr7   )r   s   "r   r   r   m   s   € ÷ "ñ "¤Cð "¬H°T­Nñ "r   c              #  ó    "  € \         P                  V 4      p Rx € \         P                  V4       R#   \         P                  T4       i ; i5i)z¡Bind only the route key of the session a call works for (a hook fired for it outside its
turn) and restore the prior value on exit; never touches ``os.environ``.N)Ú_SESSION_KEYr1   Úreset)r=   Útokens   & r   Úscoped_session_keyrB   l   s;   é € ô ×Ñ˜[Ó)€Eð"Ûä×Ñ˜5Ö!øŒ×Ñ˜5Õ!üs   ‚A™4 �A´AÁAc                ó$   € V ^8„  d   QhR\         /# r   r,   )r   s   "r   r   r   w   s   € ÷ ,ñ ,œ3ñ ,r   c                 óF   € \         P                  4       p V \        J d   R# T # )z The route key bound in THIS context, ``""`` when none is: no ``os.environ`` fallback, so a
thread that inherited no context never borrows another session's key.Ú )r?   r9   r   )Úvalues    r   Úbound_session_keyrG   w   s#   € ô ×ÑÓ€EØœ&“ˆ2Ð+ eÐ+r   c                óX   € V ^8„  d   QhR\         R\        R,          R\        R,          /# )r   ÚsourceÚmetadataNr	   )r   Údict)r   s   "r   r   r   ~   s.   € ÷ Dñ D¤#ð D´¸µð DÄÈÅñ Dr   c                ó¢   € R Uu/ uF%  p\        WR4      ;p'       g   K  V\        V4      bK'  	  ppV'       d   / T;'       g    / CVC# T# u upi )zKKeep inbound route anchors for durable deliveries after the source is gone.N)Úscope_idÚparent_chat_id)r'   r#   )rI   rJ   ÚkeyrF   Úanchorss   &&   r   Úsource_route_metadatarQ   ~   s^   € á*Hó 9Ñ*H 3Ü# F°Ó6Ð6�5Ó6ô ˆs”C˜“JŠÑ*H€Gð 9ç.5Ð*ˆx�~ˆ~˜2Ð* 'Ð*ÐC¸8ÐCùò9s
   …A ArE   Tc          .      ó:  € V ^8„  d   QhR\         R\         R\         R\         R\         R\         R\         R\         R	\         R
\         R\         R\         R\         R\         R\         R\         R\         R\        R\         R\        R\         R\         R,          R\        /# )r   ÚplatformrI   Úchat_idÚ	chat_typeÚ	chat_nameÚ	thread_idÚuser_idÚuser_id_altÚ	user_namerM   r=   r+   Ú
message_idÚprofileÚbrowser_control_principalÚ browser_control_transport_familyÚcwdÚasync_deliveryÚui_session_idÚcron_sessionrN   Úsession_history_deliveryNr	   )r#   r   r   Úlist)r   s   "r   r   r   …   sî   € ÷ ñ ÜðÜ #ðÜ36ðÜHKðäðä$'ðä7:ðäNQðô ðô $'ðô ;>ðô QTðô ð	ô $'ð	ô ILð	ô
 '*ðô
 69ðô
 PTðô ðô ,/ðô JMðô " D�jðô 
ñr   c                ód  € Rs WW#WEWgW‰W«VWÍWïVV3p\        \        V4       UUu. uF  w  ppVP                  V4      NK  	  pppVP	                  \
        P                  \        V4      4      4       TP	                  \        P                  Vf   \        MT4      4       \        RV4       V# u uppi )u•  Set all session context variables and return reset tokens.  Call
``clear_session_vars(tokens)`` in a ``finally``; not nestable, clearing resets every var
to ``""`` rather than restoring prior values (tokens are accepted only for API compat).

``session_history_delivery`` declares whether the bound chat id is one the client can address again:
``"1"`` (audited producers â€” explicit session-id header, native API sessions, /v1/runs) or
``""`` / omitted (default-deny, #98619).  ``None`` leaves the var at ``_UNSET`` ("never
declared"), which ``session_history_delivery_supported()`` treats as NOT capable â€” an omitted declaration
cannot grant wake authority.TÚset_session_cwd)
r   ÚzipÚ_SESSION_VARSr1   ÚappendÚ_SESSION_ASYNC_DELIVERYr   Ú_SESSION_HISTORY_DELIVERYr   r)   )rS   rI   rT   rU   rV   rW   rX   rY   rZ   rM   r=   r+   r[   r\   r]   r^   r_   r`   ra   rb   rN   rc   ÚvaluesÚvarrF   Útokenss   &&&&&&&&&&&&&&&&&&&&&&    r   Úset_session_varsro   …   sª   € ð&  $Ðà˜'¨iÀGØ˜[°mÀZØ!À\ÐSað€Fô
 03´=À&Ô/IÔJÑ/I¡  eˆc�g‰g�eŽnÑ/I€FÑJØ
‡M�MÔ)×-Ñ-¬d°>Ó.BÓCÔDØ
‡M�MÔ+×/Ñ/Ð:RÒ:ZµÐ`xÓyÔzÜÐ" CÔ(Ø€Mùó	 Ks   £B,c                ó(   € V ^8„  d   QhR\         RR/# )r   rn   r	   N)rd   )r   s   "r   r   r   ¥   s   € ÷ 
&ñ 
&œtð 
&¨ñ 
&r   c                ó¼   € \          F  pVP                  R4       K  	  \        P                  \        4       \        P                  \        4       \        R4       R# )u¥  Mark session context variables as explicitly cleared (``""``, not ``_UNSET``), so
``get_session_env`` returns empty instead of stale ``os.environ`` values.  Async-delivery
goes back to ``_UNSET``: a cleared context is default-supported, not opted-out.  Wake
capability goes back to ``_UNSET`` too â€” but for the opposite reason: a cleared context has
declared nothing, and an undeclared capability FAILS CLOSED (#98619).rE   Úclear_session_cwdN)rh   r1   rj   r   rk   r)   )rn   rm   s   & r   Úclear_session_varsrs   ¥   s>   € ÷ ˆØ�‰�Žñ ä×Ñ¤Ô'Ü×!Ñ!¤&Ô)ÜÐ$Ö%r   c                ó   € V ^8„  d   QhRR/# ©r   r	   Nr   )r   s   "r   r   r   ²   s   € ÷ 
&ñ 
&˜Dñ 
&r   c                 óà   € \         P                  4        F  p V P                  \        4       K  	  \        P                  \        4       \
        P                  \        4       \        R4       R# )a‚  Reset every session var to ``_UNSET`` ("never bound here") for THIS context.  Call at
the top of a fresh task *before* it binds: ``create_task`` snapshots the context, so B's
task inherits A's already-set vars and a subprocess spawned before B binds would read A's
identity.  ``_SESSION_ASYNC_DELIVERY`` and ``_SESSION_HISTORY_DELIVERY`` (outside ``_VAR_MAP``)
are reset explicitly too.rr   N)Ú_VAR_MAPrl   r1   r   rj   rk   r)   )rm   s    r   Úreset_session_varsrx   ²   sE   € ô �‰Ö ˆØ�‰”Žñ !ä×Ñ¤Ô'Ü×!Ñ!¤&Ô)ÜÐ$Ö%r   c                ó<   € V ^8„  d   QhR\         R\         R\         /# )r   r   r   r	   r,   )r   s   "r   r   r   ¿   s!   € ÷ $ñ $œ#ð $¬ð $´Sñ $r   c                ó˜   € \         P                  V 4      pVe   VP                  4       ;p\        Jd   V# \        P                  ! W4      # )z«Read a session var by legacy ``HERMES_SESSION_*`` name; drop-in for os.getenv.  The
ContextVar wins if ever set here (even to ``""``); else ``os.environ``; else *default*.)rw   r9   r   r3   Úgetenv)r   r   rm   rF   s   &&  r   Úget_session_envr|   ¿   s=   € ô �,‰,�tÓ
€CØ
‚ S§W¡W£YÐ.˜E´vÓ=ØˆÜ�9Š9�TÓ#Ð#r   c                ó$   € V ^8„  d   QhR\         /# r   r
   )r   s   "r   r   r   Ñ   s   € ÷ Zñ Z¤dñ Zr   c                 óì   € \         P                  ! R4      ;'       g    \        RR4      p V \        RR4      3pR V 4       p\        ;QJ d    R V 4       F  '       g   K   R# 	  R# ! R V 4       4      # )	z�Whether this turn is delivered over a human messaging channel (checks
``HERMES_PLATFORM``, then the session platform, then the session source).ÚHERMES_PLATFORMÚHERMES_SESSION_PLATFORMrE   ÚHERMES_SESSION_SOURCEc              3   ó„   "  € T F6  p\        T;'       g    R 4      P                  4       P                  4       x € K8  	  R# 5i)rE   N)r#   ÚstripÚlower)r   Úvs   & r   r   Ú/session_is_messaging_surface.<locals>.<genexpr>Ö   s/   é € Ð;±F¨qŒc�!—'�'�r‹l× Ñ Ó"×(Ñ(×*Ð*³Fùs
   ‚A •+A c              3   óF   "  € T F  q;'       d
    V\         9  x € K  	  R # 5i©N)ÚNON_MESSAGING_SESSION_SURFACES)r   Úidents   & r   r   r†   ×   s!   é € ÐYÑRXÈ×DÐD˜Ô&DÑDÔDÓRXùs   ‚!�!TF)r3   r{   r|   Úany)rS   Úidentss     r   Úsession_is_messaging_surfacer�   Ñ   sk   € ô �yŠyÐ*Ó+×]Ð]¬Ð?XÐZ\Ó/]€HØœÐ(?ÀÓDÐE€FÙ;±FÓ;€Fß‹3ÑYÑRXÓY�3Œ3ÐYŠ3ÐYˆ3ÑYÑRXÓYÓYÐYr   c                ó   € V ^8„  d   QhRR/# ru   r   )r   s   "r   r   r   Ú   s   € ÷ 'ñ ' 4ñ 'r   c                 ó0   € \         P                  R4       R# )a7  Declare that this session cannot receive an async background completion.  Unlike
``set_session_vars(async_delivery=False)`` this does NOT latch ``_session_context_engaged``
(flipping the subprocess env bridge), which a one-shot CLI must not do as a side effect.

See NousResearch/hermes-agent#53027 and #63142.
FN)rj   r1   r   r   r   Údeclare_stateless_channelr�   Ú   s   € ô ×Ñ Ö&r   c                ó$   € V ^8„  d   QhR\         /# r   r
   )r   s   "r   r   r   ä   s   € ÷ 
4ñ 
4¤$ñ 
4r   c                 óÌ   € ^ RI Hp  \        P                  P	                  R4      '       g   V ! 4       '       d   R# \
        P	                  4       pV\        J d   R# \        V4      # )a©  Whether the current session can deliver a background completion later.  False for
stateless channels (:func:`declare_stateless_channel`), Kanban workers
(``HERMES_KANBAN_TASK``: one-shot subprocesses whose parent disappears after the turn) and
registered worker processes: a managed worker exits at its turn boundary, so detached work
it scheduled would be lost (recovered ``unknown``) and its completion queue has no reader.)Úis_worker_processÚHERMES_KANBAN_TASKFT)Úagent.runtime_session_storer“   r3   r4   r9   rj   r   r   )r“   rF   s     r   Úasync_delivery_supportedr–   ä   sJ   € õ >Ü	‡z�z‡~�~Ð*×+Ò+Ñ/@×/BÒ/BÙÜ#×'Ñ'Ó)€EØœF“?ˆ4Ð3¬¨U«Ð3r   c                ó$   € V ^8„  d   QhR\         /# r   r
   )r   s   "r   r   r   ñ   s   € ÷ 2ñ 2¬Dñ 2r   c                 ó0   € \         P                  4       R8H  # )zœWhether this request declares a server-history consumer for detached results.

Fail closed on omitted bindings; never borrow authority from the environment.Ú1)rk   r9   r   r   r   Ú"session_history_delivery_supportedrš   ñ   s   € ô %×(Ñ(Ó*¨cÑ1Ð1r   c                óh   € V ^8„  d   Qh/ ^ \         9   d
   \        ;R&   ^\         9   d
   \        ;R&   # )r   r   r   )Ú__conditional_annotations__r   r   )r   s   "r   r   r      s0   € ÷ ñ ÷ Ò ŒÑ ñ÷" 'Ò &œ$Ñ &ò#r   )r€   r�   ÚHERMES_SESSION_CHAT_IDÚHERMES_SESSION_CHAT_TYPEÚHERMES_SESSION_CHAT_NAMEÚHERMES_SESSION_THREAD_IDÚHERMES_SESSION_USER_IDÚHERMES_SESSION_USER_ID_ALTÚHERMES_SESSION_USER_NAMEÚHERMES_SESSION_SCOPE_IDÚHERMES_SESSION_KEYr/   ÚHERMES_UI_SESSION_IDÚHERMES_SESSION_MESSAGE_IDÚHERMES_SESSION_PROFILEÚ HERMES_BROWSER_CONTROL_PRINCIPALÚ'HERMES_BROWSER_CONTROL_TRANSPORT_FAMILYÚHERMES_CRON_SESSIONÚHERMES_SESSION_PARENT_CHAT_IDrˆ   )rE   >   rE   ÚcliÚtuiÚtoolÚcodexÚlocalÚkanbanÚdesktopÚgatewayÚwebhookÚ
api_serverÚmsgraph_webhook);rœ   Ú__doc__r3   Ú
contextlibr   Úcontextvarsr   Útypingr   r   Úobjectr   r   r   Útuplerh   Ú_SESSION_PLATFORMÚ_SESSION_SOURCEÚ_SESSION_CHAT_IDÚ_SESSION_CHAT_TYPEÚ_SESSION_CHAT_NAMEÚ_SESSION_THREAD_IDÚ_SESSION_USER_IDÚ_SESSION_USER_ID_ALTÚ_SESSION_USER_NAMEÚ_SESSION_SCOPE_IDr?   r0   Ú_SESSION_UI_SESSION_IDÚ_SESSION_MESSAGE_IDÚ_SESSION_PROFILEÚ_BROWSER_CONTROL_PRINCIPALÚ!_BROWSER_CONTROL_TRANSPORT_FAMILYÚ_CRON_SESSIONÚ_SESSION_PARENT_CHAT_IDrj   rk   Ú_CRON_AUTO_DELIVER_PLATFORMÚ_CRON_AUTO_DELIVER_CHAT_IDÚ_CRON_AUTO_DELIVER_THREAD_IDr   rw   r)   r5   r;   rB   rG   rQ   ro   rs   rx   r|   Ú	frozensetr‰   r�   r�   r–   rš   r   )rm   rœ   s   0@r   Ú<module>rÓ      sñ  øðöó 
Ý %Ý "ß  ñ ‹h€Ó ð "'Ð Ó &õ$÷& 
€Eñ 
ñ 8ó 
‡E�Eñ 
ñ 8ó 
ó ð€ñ Ø�Ð(8Ð:LØÐ*Ð,<Ð>RØÐ)¨<¸ØÐ/Ð1AØÐ AÀ=ÐRiñ %Ð%DÈfÔUÐ ñ 'Ð'HÐRXÔYÐ ñ )Ð)LÐV\Ô]Ð Ù'Ð(JÐTZÔ[Ð Ù)Ð*NÐX^Ô_Ð ð&Øð&Ø/ð&Ø1Kð&à ñ&ó ñ &˜c�H‰H�cŠMñ &ñ €õõ1ð ö	"ó ð	"ð ô"ó ð"õ,õDð  b¸ÈbØ¨"¸RÐTVØ¨ÀÐVXØ¨ÈbØ,.¸2ÐVZØ°ÈrØ+/÷õ@
&õ
&÷$ñ "+ò ,ó "Ð õZõ'õ
4÷2ùò_s   Â4E