Ë
    âß²jÒ5  ã                  ó|  — d Z ddlmZ ddlZddlZddlmZ ddlZddlmZm	Z	 ddl
mZ ddlmZmZmZ erddlmZ  ej$                  e«      Zd	Zd
defZ G d„ de«      Z ed¬«       G d„ d«      «       Zdd„Zdd„Zdd„Zdd„Zdd„Zddddœ	 	 	 	 	 	 	 	 	 	 	 d d„Z	 	 	 	 	 	 	 	 d!d„Z ddddœ	 	 	 	 	 	 	 	 	 	 	 d"d„Z!y)#u   One frozen routing identity per inbound gateway event.

A multiplexed gateway answers three questions about every event, and until now answered them in
three places that only agreed because they read the same fallback chain: WHICH bot received it
(``_transport_owner``), WHO may admit it (``_authorization_home_for_source``) and WHERE the turn
runs (``_resolve_profile_home_for_source`` / ``_session_key_profile``). :func:`resolve_identity`
answers all three once and pins the result on the source as a wire-invisible dynamic attribute
(like ``_transport_adapter_ref``); the existing helpers read it when present and keep their
fallback chain when absent, so a source built outside the runner still resolves as before.

``SessionSource.profile`` stays the serialized runtime profile â€” ``None`` on the wire means the
receiving bot's own profile â€” so nothing here changes the wire format or any historical
``agent:main`` key.
é    )ÚannotationsN)Úsuppress)Ú	dataclassÚfield)ÚPath)ÚTYPE_CHECKINGÚAnyÚOptional)ÚSessionSourceÚ	_identityÚ_transport_adapter_refÚ_authorization_profile_homec                  ó   — e Zd ZdZy)ÚIdentityUnresolvedzðUnder multiplexing the event's runtime profile could not be established (an explicit
    ``profile_routes`` entry targets a profile this gateway does not serve). Callers drop the
    event; it must never fall through to the default profile.N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__© ó    ú=/home/ubuntu/.hermes/hermes-agent/gateway/session_identity.pyr   r   #   s   „ òAr   r   T)Úfrozenc                  óÆ   — e Zd ZU dZded<   ded<   ded<   ded<   dZd	ed
<    eddd¬«      Zded<    eddd¬«      Zd	ed<   e	dd„«       Z
e	dd„«       Ze	dd„«       Zdd„Zy)ÚRoutingIdentityu  Everything a turn needs to know about who it is, resolved once at ingress.

    ``transport_profile`` owns the receiving adapter (its credential and allowlist);
    ``runtime_profile`` is the profile that executes the turn â€” the same name unless a
    ``profile_routes`` entry re-homed the event. Both are explicit (``"default"`` is spelled out);
    ``None`` never means default here. ``multiplexed`` is False for a standalone gateway, whose
    keys stay in the legacy ``agent:main`` namespace whatever profile it was launched with.
    ÚstrÚtransport_profileÚruntime_profiler   Úauthorization_homeÚruntime_homeTÚboolÚmultiplexedNF)ÚdefaultÚcompareÚhashzOptional[weakref.ref]Ú	transportÚtransport_inferredc                ó2   — ddl m}  || j                  «      S )u�   ``agent:<ns>`` prefix for this identity's session keys â€” byte-identical to
        :func:`gateway.session._session_key_namespace` for every historical key.r   )Ú_session_key_namespace)Úgateway.sessionr(   Úsession_key_profile)Úselfr(   s     r   Ú	namespacezRoutingIdentity.namespaceB   s   € õ 	;Ù% d×&>Ñ&>Ó?Ð?r   c                ó    — | j                   dz  S )Nzstate.db)r   ©r+   s    r   Ú
store_pathzRoutingIdentity.store_pathI   s   € à× Ñ  :Ñ-Ð-r   c                ó6   — | j                   r| j                  S dS )z°The ``profile=`` argument :func:`gateway.session.build_session_key` expects for this
        identity: the runtime profile under multiplexing, else ``None`` (legacy namespace).N)r!   r   r.   s    r   r*   z#RoutingIdentity.session_key_profileM   s   € ð (,×'7Ò'7ˆt×#Ñ#ÐA¸TÐAr   c                ó>   — | j                   �| j                  «       S dS )zGThe live receiving adapter, or None when it is gone or was never known.N)r%   r.   s    r   ÚadapterzRoutingIdentity.adapterS   s   € à#'§>¡>Ð#=ˆt�~‰~ÓÐGÀ4ÐGr   )Úreturnr   )r3   r   )r3   úOptional[str])r3   r	   )r   r   r   r   Ú__annotations__r!   r   r%   r&   Úpropertyr,   r/   r*   r2   r   r   r   r   r   )   s›   … ñð ÓØÓØÓØÓØ€K�Óñ (-°TÀ5ÈuÔ'U€IÐ$ÓUñ
  %¨U¸EÈÔNÐ˜ÓNàò@ó ð@ð ò.ó ð.ð òBó ðBô
Hr   r   c                óL   — t        | t        d«      }t        |t        «      r|S dS )zDThe identity pinned on *source* by :func:`resolve_identity`, if any.N)ÚgetattrÚ_IDENTITY_ATTRÚ
isinstancer   ©ÚsourceÚidentitys     r   Úidentity_ofr>   X   s$   € ä�vœ~¨tÓ4€HÜ! (¬OÔ<ˆ8ÐFÀ$ÐFr   c                óÖ   — t         ddfD ]&  }t        t        «      5  t        | |«       ddd«       Œ( t        t        «      5  d| _        ddd«       y# 1 sw Y   ŒRxY w# 1 sw Y   yxY w)uÍ  Drop the pinned identity AND the routed runtime profile so the next :func:`canonical_identity`
    re-routes from scratch â€” for sources a caller reuses across events whose routing may differ (a
    guild's cached voice source is shared by every speaker, and ``profile_routes[].user_id`` routes
    per speaker). ``source.profile`` is the previous event's routing *result*; left in place it
    short-circuits the route and the new speaker runs as the old one.Úprofile_route_rejectedr   N)r9   r   ÚAttributeErrorÚdelattrÚprofile)r<   Úattrs     r   Úclear_identityrE   ^   ss   € ô  Ð!9Ð;XÐYò "ˆÜ”nÓ%ñ 	"Ü�F˜DÔ!÷	"ð 	"ð"ô 
”.Ó	!ñ ØˆŒ÷ð ÷	"ð 	"ú÷ð ús   œAÁAÁA	ÁA(c                óP   — t        | «      }|�|j                  r|j                  S dS )zÑThe receiving bot's profile to persist alongside a routing entry (``SessionEntry.transport_profile``);
    None outside multiplexing or when nothing resolved the source (an unknown transport is never guessed).N)r>   r!   r   r;   s     r   Útransport_profile_ofrG   k   s-   € ô ˜6Ó"€HØ)1Ð)=À(×BVÒBVˆ8×%Ñ%Ð`Ð\`Ð`r   c                ó‚   — t        j                  | fi |¤Ž}t        D ]  }t        | |d«      }|€Œt	        |||«       Œ! |S )zØ:func:`dataclasses.replace` that keeps the wire-invisible provenance (transport ref,
    authorization home, identity). A plain ``replace`` silently produces a source the runner
    can only route through heuristics.N)ÚdataclassesÚreplaceÚ_PROVENANCE_ATTRSr8   Úsetattr)r<   ÚchangesÚcopiedÚnameÚvalues        r   Úreplace_sourcerQ   r   sO   € ô × Ñ  Ñ3¨7Ñ3€FÜ!ò )ˆÜ˜  dÓ+ˆØÑÜ�F˜D %Õ(ð)ð €Mr   c                óR   — t        | t        «      r| j                  «       nd}|xs d S )NÚ )r:   r   Ústrip)rP   Útexts     r   Ú_namerV   ~   s"   € Ü& u¬cÔ2ˆ5�;‰;Œ=¸€DØŠ<�4Ðr   )r2   r   Úprimary_homec               óš   — t        | «      }|�|S 	 t        | ||||¬«      S # t        $ r }t        j	                  d|«       Y d}~yd}~ww xY w)uN  The identity already pinned on *source*, else :func:`resolve_identity` â€” the one call every
    ingress path makes FIRST, before any key is derived. ``None`` = unresolved under multiplexing
    (``source.profile_route_rejected`` is set): the caller drops the event and says so once; it
    must never fall through to ``agent:main``.N)Úrunnerr2   r   rW   zidentity unresolved: %s)r>   Úresolve_identityr   ÚloggerÚdebug)r<   rY   r2   r   rW   r=   Úexcs          r   Úcanonical_identityr^   ƒ   s\   € ô ˜6Ó"€HØÐØˆðÜØ˜6¨7ÐFWØ%ô'ð 	'øô ò Ü�‰Ð.°Ô4Üûðús   ‘! ¡	A
ªAÁA
c          	     óÒ  — t        |«      }|€yt        t        t        |dd«      dd«      «      syt        | «      }|�|S ddlm} ddlm} t        t        |dd«      «      xs d	}t        t        | d
d«      «      xs |}||k(  rt         |«       «      n ||«      }	||k(  r|	nt        |j                  | «      «      }
|	| _
        t        |||	|
dd¬«      }t        | t        |«       |S )uŠ  Pin the identity of a source rebuilt from durable state (``SessionEntry.origin``, a
    ``sessions`` row, a cached copy) â€” no live adapter, so ``transport=None``: the restored row of the
    transport matrix, where delivery goes through the persisted transport owner or fails closed.

    *transport_profile* is what the routing index persisted at ingress (``SessionEntry.transport_profile``);
    ``None`` = a row written before the column existed, whose transport is unknown â†’ nothing is pinned
    and the legacy heuristics (``_is_shared_bot_satellite``) keep deciding. Standalone gateways have
    nothing to restore (one bot, one home).
    NÚconfigÚmultiplex_profilesFr   ©Úget_profile_dir)Úget_process_hermes_homeÚ_primary_profile_namer"   rC   T©r   r   r   r   r!   r%   )rV   r    r8   r>   Úhermes_cli.profilesrc   Úhermes_constantsrd   r   Ú _resolve_profile_home_for_sourcer   r   rL   r9   )r<   rY   r   Útransport_nameÚexistingrc   rd   Úprimary_profileÚruntime_namer   r   r=   s               r   Úrestore_identityrn   —   sý   € ô Ð,Ó-€NØÐØÜ”œ ¨°$Ó7Ð9MÈuÓUÔVØÜ˜6Ó"€HØÐØˆÝ3Ý8äœG FÐ,CÀTÓJÓKÒXÈy€OÜœ ¨°DÓ9Ó:ÒM¸o€Là+9¸_Ò+LŒÑ$Ó&Ô'Ù˜^Ó,ð ð +¨nÒ<ÑÜ�&×9Ñ9¸&ÓAÓBð ð *<€FÔ&ÜØ(¸,Ø-¸LØ Dô*€Hô ˆF”N HÔ-Ø€Or   c          	     ó`  — ddl m} ddlm}m} t        t        t        |dd«      dd«      «      }t        t        |dd«      «      }	|	€.t        |d	d«      }
t        |
«      rt         |
«       «      ndxs d
}	t        | dd«      }d}|€|j                  | «      }|�B|\  }}n<t        | dd«      €t        j                  |«      | _        |j                  ||«      \  }}t        |«      xs t        |«      xs |	}|du xr t        |«      du xr t        |«      du }|�t        j                  |«      nd}|s4t         |«       «      }t        |	|	||d|¬«      }t!        | t"        |«       |S ||	k(  r|�t        |«      nt         |«       «      }nddlm}  ||«      }|| _        t        |d|«      › dt        | dd«      › �}t        | dd«      du rt+        |› d�«      ‚t        t        | dd«      «      €;||	k(  rdn|}	 |€|j-                  | «      n|j-                  | |¬«      }|xs || _        t        | j0                  «      xs |	}||k(  r|nt        |j3                  | «      «      }t        ||||d||¬«      }t!        | t"        |«       |S # |$ r}d| _        t+        |› d|› �«      |‚d}~ww xY w)a|  Resolve and pin the :class:`RoutingIdentity` of an inbound *source*.

    *adapter* is the receiving adapter when the caller holds it; otherwise the source's own
    transport provenance is consulted. *transport_profile* names the receiving bot's owning
    profile when the caller knows it by construction (the runner's per-profile handlers);
    ``None`` = derive it from the adapter registry, primary when unknown. *primary_home* is the
    primary bot's home for authorization (default: the process home, never a per-turn override).

    Stamps ``source.profile`` the way the ingress handlers always did (routed name, else a
    secondary's own name; ``None`` stays ``None`` for the primary so the wire is unchanged) and
    ``_authorization_profile_home`` for the existing authorization readers.

    Raises :class:`IdentityUnresolved` under multiplexing when the route is rejected.
    r   )ÚProfileRouteRejected)Úget_hermes_homerd   r`   Nra   Fre   Ú_active_profile_namer"   Úplatformr   rf   rb   rP   ú/Úchat_idrS   r@   Tz: profile route rejectedrC   )Úadapter_profilez: )r   r   r   r   r!   r%   r&   )Úgateway.profile_routingrp   rh   rq   rd   r    r8   rV   ÚcallableÚ_transport_ownerÚweakrefÚrefr   Ú_owning_profiler   r   rL   r9   rg   rc   r   r   Ú_profile_name_for_sourcer@   rC   ri   )r<   rY   r2   r   rW   rp   rq   rd   r!   rl   Úactivers   Úowner_profileÚownerÚ_registeredrj   r&   Útransport_refÚhomer=   r   rc   Úwhererv   Úroutedr]   rm   r   s                               r   rZ   rZ   ¿   sø  € õ$ =ßIä”wœw v¨x¸Ó>Ð@TÐV[Ó\Ó]€KÜœG FÐ,CÀTÓJÓK€OØÐÜ˜Ð!7¸Ó>ˆÜ.6°vÔ.>œ5¡£œ?ÀDÒVÈYˆÜ�v˜z¨4Ó0€Hà#'€MØ€Ø×'Ñ'¨Ó/ˆØÐØ%*Ñ"ˆG‘]ä�6Ð3°TÓ:ÐBÜ,3¯K©K¸Ó,@ˆFÔ)Ø%+×%;Ñ%;¸GÀXÓ%NÑ"ˆ�]ÜÐ,Ó-ÒX´°}Ó1EÒXÈ€NØ  D˜Òn¬UÐ3DÓ-EÈÐ-MÒnÔRWÐXeÓRfÐjnÐRnÐØ,3Ð,?”G—K‘K Ô(ÀT€MáÜ‘OÓ%Ó&ˆÜ"Ø-¸Ø#°$ÀEÐUbôdˆô 	�œ¨Ô1Øˆà˜Ò(Ø3?Ð3KœT ,Ô/ÔQUÑVmÓVoÓQpÑå7Ù,¨^Ó<ÐØ);€FÔ&ä�x ¨(Ó3Ð4°A´g¸fÀiÐQSÓ6TÐ5UÐV€EÜˆvÐ/°Ó7¸4Ñ?Ü  E 7Ð*BÐ!CÓDÐDÜŒW�V˜Y¨Ó-Ó.Ð6Ø"0°OÒ"C™$Èˆð	Að <KÐ;R�×/Ñ/°Ô7Ø×4Ñ4°VÈ_Ð4Ó]ð ð  Ò2 ?ˆŒä˜Ÿ™Ó(Ò;¨O€Lð +¨nÒ<ÑÜ�&×9Ñ9¸&ÓAÓBð ô Ø(¸,Ø-¸LØ MÐFXôZ€Hô ˆF”N HÔ-Ø€Oøð! $ò 	AØ,0ˆFÔ)Ü$¨ w¨b°°Ð%6Ó7¸SÐ@ûð	Aús   Ç;&J ÊJ-ÊJ(Ê(J-)r<   r	   r3   úOptional[RoutingIdentity])r<   r	   r3   ÚNone)r<   r	   r3   r4   )r<   ú'SessionSource'rM   r	   r3   rˆ   )rP   r	   r3   r4   )r<   rˆ   rY   r	   r2   r	   r   r4   rW   úOptional[Path]r3   r†   )r<   rˆ   rY   r	   r   r4   r3   r†   )r<   rˆ   rY   r	   r2   r	   r   r4   rW   r‰   r3   r   )"r   Ú
__future__r   rI   ÚloggingÚ
contextlibr   rz   r   r   Úpathlibr   Útypingr   r	   r
   r)   r   Ú	getLoggerr   r[   r9   rK   ÚRuntimeErrorr   r   r>   rE   rG   rQ   rV   r^   rn   rZ   r   r   r   ú<module>r‘      sN  ðñõ #ã Û Ý Û ß (Ý ß /Ñ /áÝ-à	ˆ×	Ñ	˜8Ó	$€à€à-Ð/LÈnÐ]Ð ôA˜ô Añ �$Ô÷+Hð +Hó ð+Hó\Gó
óaó	óð =AØ'+ÈDñØðØ(+ðØ69ðà$ðà;Iðð óð(%Øð%Ø(+ð%Ø@Mð%àó%ðR =AØ'+ÈDñRØðRØ(+ðRØ69ðRà$ðRà;IðRð ôRr   