§
    øžyjÕ  ã                  ó€   — d Z ddlmZ ddlZddlmZ dZ eh d£¦  «        Zdd
„Z	dd„Z
dd„Zdd„Zdd„Zdd„Zdd„ZdS )zÚGateway response filtering helpers.

These helpers operate at the gateway boundary: they decide whether a completed
agent turn should be delivered to the chat, not what should be persisted in the
conversation history.
é    )ÚannotationsN)ÚAnyÚNO_REPLY>   úNO REPLYÚSILENTr   ú[SILENT]ÚtextÚstrÚreturnc                ó˜   — d                      |                      ¦   «                              ¦   «                              ¦   «         ¦  «        S )NÚ )ÚjoinÚstripÚupperÚsplit)r	   s    ú>/home/ragecks/.hermes/hermes-agent/gateway/response_filters.pyÚ_canonical_silence_candidater      s4   € Ø�8Š8�D—J’J‘L”L×&Ò&Ñ(Ô(×.Ò.Ñ0Ô0Ñ1Ô1Ð1ó    c                óp  — d}t          | ¦  «        }||k     ry| |         dvrot          j        | |         ¦  «                             d¦  «        rB|dz  }||k     r7| |         dvr-t          j        | |         ¦  «                             d¦  «        °B||k    r…| |dz
           dvrxt          j        | |dz
           ¦  «                             d¦  «        rH|dz  }||k    r=| |dz
           dvr0t          j        | |dz
           ¦  «                             d¦  «        °H| ||…                              ¦   «         S )zøStrip stray edge punctuation without erasing marker structure.

    Models sometimes emit ``.NO_REPLY`` or ``*NO_REPLY*`` instead of the exact
    marker. Keep square brackets structural so malformed ``[SILENT`` does not
    become ``SILENT``.
    r   z[]ÚPé   )ÚlenÚunicodedataÚcategoryÚ
startswithr   )r	   ÚstartÚends      r   Ú_strip_edge_silence_punctuationr      sD  € ð €EÝ
ˆd‰)Œ)€CØ
�#Š+ˆ+˜$˜uœ+¨TÐ1Ð1µkÔ6JÈ4ÐPUÌ;Ñ6WÔ6W×6bÒ6bÐcfÑ6gÔ6gÐ1Ø�‰
ˆð �#Š+ˆ+˜$˜uœ+¨TÐ1Ð1µkÔ6JÈ4ÐPUÌ;Ñ6WÔ6W×6bÒ6bÐcfÑ6gÔ6gÐ1à
�Š+ˆ+˜$˜s Q™wœ-¨tÐ3Ð3½Ô8LÈTÐRUÐXYÑRYÌ]Ñ8[Ô8[×8fÒ8fÐgjÑ8kÔ8kÐ3Øˆq‰ˆð �Š+ˆ+˜$˜s Q™wœ-¨tÐ3Ð3½Ô8LÈTÐRUÐXYÑRYÌ]Ñ8[Ô8[×8fÒ8fÐgjÑ8kÔ8kÐ3à��c�	Œ?× Ò Ñ"Ô"Ð"r   útuple[str, ...]c                ó¾   — t          | ¦  «        }t          |                      ¦   «         ¦  «        }||                      ¦   «         k    r|fS t          |¦  «        }||fS ©N)r   r   r   )r	   ÚexactÚstrippedÚfallbacks       r   Ú_canonical_silence_candidatesr%   /   sV   € Ý(¨Ñ.Ô.€EÝ.¨t¯zªz©|¬|Ñ<Ô<€HØ�4—:’:‘<”<ÒÐØˆxˆÝ+¨HÑ5Ô5€HØ�8ÐÐr   Úresponser   Úboolc                óÖ   — t          | t          ¦  «        sdS |                      ¦   «         }|sdS t          |¦  «        dk    rdS t	          d„ t          |¦  «        D ¦   «         ¦  «        S )a  Return True only when ``response`` is exactly a silence marker.

    Substantive prose that merely mentions ``NO_REPLY`` or ``[SILENT]`` must be
    delivered normally.  A blank response is also not silence; blank output is
    handled by the empty-response failure path.
    Fé@   c              3  ó(   K  — | ]}|t           v V — Œd S r!   )ÚLIVE_GATEWAY_SILENT_MARKERS)Ú.0Ú	candidates     r   ú	<genexpr>z2is_intentional_silence_response.<locals>.<genexpr>F   s(   è è € ÐqÐq¸IˆyÕ7Ð7ÐqÐqÐqÐqÐqÐqr   )Ú
isinstancer
   r   r   Úanyr%   )r&   r#   s     r   Úis_intentional_silence_responser1   8   st   € õ �h¥Ñ$Ô$ð ØˆuØ�~Š~ÑÔ€HØð ØˆuÝ
ˆ8�}„}�rÒÐØˆuÝÐqÐqÕIfÐgoÑIpÔIpÐqÑqÔqÑqÔqÐqr   c                ó`  — t          | t          ¦  «        sdS |                      ¦   «         }|sdS dd„} ||¦  «        rdS d„ |                     ¦   «         D ¦   «         }|r$ ||d	         ¦  «        s ||d
         ¦  «        rdS |                     ¦   «                              d¦  «        rdS dS )a-  Loose silence matcher for autonomous lanes (cron, webhook).

    Autonomous lanes instruct the agent to emit ``[SILENT]`` when a tick
    produced nothing worth a human's attention, and models reliably bracket
    the marker with a short note explaining why they stayed quiet.  Unlike
    :func:`is_intentional_silence_response` (the interactive-chat rule, which
    demands the response be EXACTLY a marker), this suppresses when a marker
    is the whole response, sits on its own first or last line, or the
    bracketed sentinel opens the response (the documented
    ``[SILENT] No changes detected`` pattern).  A token buried mid-sentence
    in a genuine report is still delivered.

    Shares :data:`LIVE_GATEWAY_SILENT_MARKERS` so the interactive and
    autonomous marker sets can never drift apart.
    FÚliner
   r   r'   c                ó.   — t          | ¦  «        t          v S r!   )r   r+   )r3   s    r   Ú	_is_tokenz1is_autonomous_silence_response.<locals>._is_token_   s   € Ý+¨DÑ1Ô1Õ5PÐPÐPr   Tc                ó:   — g | ]}|                      ¦   «         ¯|‘ŒS © )r   )r,   Úlns     r   ú
<listcomp>z2is_autonomous_silence_response.<locals>.<listcomp>g   s%   € Ð>Ð>Ð>�B°2·8²8±:´:Ð>ˆRÐ>Ð>Ð>r   r   éÿÿÿÿr   )r3   r
   r   r'   )r/   r
   r   Ú
splitlinesr   r   )r&   r#   r5   Úliness       r   Úis_autonomous_silence_responser=   I   sì   € õ  �h¥Ñ$Ô$ð ØˆuØ�~Š~ÑÔ€HØð ØˆuðQð Qð Qð Qð €y�ÑÔð Øˆtð ?Ð>˜(×-Ò-Ñ/Ô/Ð>Ñ>Ô>€EØð �)�)˜E !œHÑ%Ô%ð ¨¨°5¸´9Ñ)=Ô)=ð Øˆtð ‡~‚~ÑÔ×"Ò" :Ñ.Ô.ð ØˆtØˆ5r   Úagent_resultúdict | Nonec                ó|   — t          | t          ¦  «        sdS |                      d¦  «        rdS t          |¦  «        S )zBSilence markers suppress delivery only for successful agent turns.FÚfailed)r/   ÚdictÚgetr1   )r>   r&   s     r   Ú#is_intentional_silence_agent_resultrD   r   sB   € å�l¥DÑ)Ô)ð ØˆuØ×Ò˜Ñ!Ô!ð ØˆuÝ*¨8Ñ4Ô4Ð4r   c                óú   ‡— t          | t          ¦  «        sdS |                      ¦   «         }|rt          |¦  «        dk    rdS t	          |¦  «        D ]'Š‰r#t          ˆfd„t          D ¦   «         ¦  «        r dS Œ(dS )ua  Return True while ``text`` could still resolve to a silence marker.

    The streaming path accumulates the reply delta-by-delta and must decide,
    before the whole response is known, whether to show what it has so far.
    A buffer whose canonical form is a non-empty *prefix* of a silence marker
    (e.g. ``"NO"`` on the way to ``"NO_REPLY"``, or an exact marker that has
    not yet been terminated by stream-end) is held back so a raw marker is
    never edited onto the screen and then belatedly retracted.

    Anything that has already diverged from every marker (ordinary prose) â€”
    and anything longer than the marker cap â€” returns False so normal
    streaming resumes immediately.  This is the streaming counterpart to
    :func:`is_intentional_silence_response`, sharing the same marker set and
    canonicalization so the two never drift.
    Fr)   c              3  óB   •K  — | ]}|                      ‰¦  «        V — Œd S r!   )r   )r,   Úmarkerr-   s     €r   r.   z,is_partial_silence_marker.<locals>.<genexpr>‘   s1   øè è € ÐdÐd¸f˜V×.Ò.¨yÑ9Ô9ÐdÐdÐdÐdÐdÐdr   T)r/   r
   r   r   r%   r0   r+   )r	   r#   r-   s     @r   Úis_partial_silence_markerrH   {   s—   ø€ õ  �d�CÑ Ô ð ØˆuØ�zŠz‰|Œ|€HØð •s˜8‘}”} rÒ)Ð)ØˆuÝ2°8Ñ<Ô<ð ð ˆ	Øð 	�ÐdÐdÐdÐdÕHcÐdÑdÔdÑdÔdð 	Ø�4�4øØˆ5r   )r	   r
   r   r
   )r	   r
   r   r   )r&   r   r   r'   )r>   r?   r&   r   r   r'   )r	   r   r   r'   )Ú__doc__Ú
__future__r   r   Útypingr   ÚSILENT_REPLY_TOKENÚ	frozensetr+   r   r   r%   r1   r=   rD   rH   r7   r   r   ú<module>rN      s  ððð ð #Ð "Ð "Ð "Ð "Ð "à Ð Ð Ð Ø Ð Ð Ð Ð Ð ð  Ð ð
 (˜ið )ð )ð )ñ ô Ð ð2ð 2ð 2ð 2ð#ð #ð #ð #ð ð ð ð ðrð rð rð rð"&ð &ð &ð &ðR5ð 5ð 5ð 5ðð ð ð ð ð r   