
    .cj                    ~    d Z ddlmZ ddlZddlZddlmZmZ  ej        e	          Z
dZdZddZdddddZddZdS )u  Wake an existing agent session from a background completion event.

Two delivery strategies, selected by the target adapter's
``supports_async_delivery`` capability flag:

* Push-capable adapters (telegram, discord, plugin platforms, ...): inject a
  synthetic ``MessageEvent(internal=True)`` through ``adapter.handle_message``
  — the pre-existing wake path, preserved exactly.

* Stateless request/response adapters (the API server,
  ``supports_async_delivery = False``): ``handle_message`` would run the wake
  turn under a ``build_session_key()``-derived key
  (``agent:main:api_server:group:<sid>``) that NEVER matches the raw
  ``X-Hermes-Session-Id`` key real gateway/HQ turns run under
  (``_bind_api_server_session``), so the wake lands in a parallel, invisible
  session. Instead we self-POST ``/v1/chat/completions`` on the in-pod API
  server with the raw session id in the ``X-Hermes-Session-Id`` header — the
  exact entry point real turns use — so the wake turn resumes the REAL
  session, with full history, and its result is visible the next time the
  client polls/reopens the conversation.

Failures RAISE (after bounded retries on transient errors) so callers can
rewind cursors / retry instead of silently losing the event.
    )annotationsN)AnyOptionalg     @)g       @g      @g      $@adapterr   returnboolc                >    t          t          | dd                    S )u  Whether this adapter can push a message to the user after a turn ends.

    Mirrors ``gateway.session_context.async_delivery_supported`` but reads the
    capability off the adapter class (``supports_async_delivery``) instead of
    the request-scoped contextvar — background watchers run outside any bound
    session context. Adapters that don't declare the flag are push-capable.
    supports_async_deliveryT)r   getattr)r   s    ./home/ice/.hermes/hermes-agent/gateway/wake.pyadapter_supports_pushr   -   s     !:DAABBB     )
session_idsourcetextstrr   r   Nonec                 K   t          |           rJ|t          d          ddlm}m}  |||j        |d          }|                     |           d{V  dS |st          d          t          | ||           d{V  dS )	u  Deliver a wake turn to the session behind ``adapter``.

    ``session_id`` is the RAW session id (the ``X-Hermes-Session-Id`` value /
    ``state.db`` key) — required for non-push adapters. ``source`` is the
    ``SessionSource`` used to build the synthetic event — required for
    push-capable adapters.

    Raises on failure (bad arguments, exhausted retries, HTTP error) so the
    caller can rewind/retry instead of treating the wake as delivered.
    Nz;deliver_wake: push-capable adapter requires a SessionSourcer   )MessageEventMessageTypeT)r   message_typer   internalzudeliver_wake: non-push adapter (supports_async_delivery=False) requires the raw session id to self-post the wake turn)r   r   )r   
ValueErrorgateway.platforms.baser   r   TEXThandle_message_self_post_chat_completion)r   r   r   r   r   r   synth_events          r   deliver_waker    8   s      " W%% >M   	EDDDDDDD"l$)	
 
 
 $$[111111111 
E
 
 	
 %W4J
O
O
OOOOOOOOOOr   c               T  K   ddl }t          t          | dd          pd          }|dv rd}t          t          | dd          pd          }t          t          | d	d          pd          }|st	          d
          d|v r|                    d          sd| d}d| d| d}d| |d}t          t          | dd          pd          d|dgdd}	d}
dt          t                    z   }t          |          D ]}|r(t          j
        t          |dz
                      d{V  	 |                    t                    }|                    |          4 d{V }|                    ||	|          4 d{V }|j        dk    rVt	          d|           }
t                               d|
|dz   |           	 ddd          d{V  ddd          d{V  |j        dk    r?|                                 d{V dd          }t	          d!| d"|j         d#|           |                                 d{V  t                               d$||dz              	 ddd          d{V  ddd          d{V   dS # 1 d{V swxY w Y   	 ddd          d{V  n# 1 d{V swxY w Y   # |j        t          j        t.          f$ r.}|}
t                               d%||dz   ||           Y d}~d}~ww xY wt	          d&| d'| d(|
           |
))u  POST the wake text to the in-pod API server as a normal session turn.

    Uses the adapter's own bind host/port/key (``ApiServerAdapter.__init__``).
    Session continuation via ``X-Hermes-Session-Id`` is 403-gated on
    ``API_SERVER_KEY`` being configured, so a missing key is a hard error —
    raise loudly rather than run the wake in a fresh fingerprint-derived
    session nobody is looking at.
    r   N_hostr   z	127.0.0.1)z0.0.0.0z::*_porti!  _api_keyzwake self-post requires API_SERVER_KEY: session continuation via X-Hermes-Session-Id is rejected (403) on an unauthenticated API server, so the wake cannot reach the target session:[]zhttp://z/v1/chat/completionszBearer )AuthorizationzX-Hermes-Session-Id_model_namezhermes-agentuser)rolecontentF)modelmessagesstream   )total)timeout)jsonheadersi  z:wake self-post got HTTP 429 (concurrency cap) for session z%s; attempt %d/%di  i,  z"wake self-post failed for session z: HTTP z: z4wake self-post delivered for session %s (attempt %d)zCwake self-post transient failure for session %s (attempt %d/%d): %sz#wake self-post gave up for session z after z attempts: )aiohttpr   r   intRuntimeError
startswithlen_RETRY_DELAYS_SECONDSrangeasynciosleepClientTimeoutWAKE_TURN_TIMEOUT_SECONDSClientSessionpoststatusloggerwarningr   readinfoClientErrorTimeoutErrorOSError)r   r   r   r6   hostportapi_keyurlr5   payloadlast_errattemptsattemptr3   httprespbodyexcs                     r   r   r   a   s      NNNww,,;<<D%%%ww++3t44D'':r228b99G 
B
 
 	
 d{{4??3//{4{{{
5D
5
54
5
5
5C,7,,) G
 WWmR88JNKK$667 G )-H3,---H?? * * 	D- 5gk BCCCCCCCCC'	++2K+LLG,,W,==       99Sw9HH       D{c)) $08+58 8$ $ /7Q;   !                        {c))&*iikk 1 1 1 1 1 14C48*: : :$(K: :37: :   ))++%%%%%%%KKN"!  
 3                                                                 6 #W%97C 
	 
	 
	HNN&!   HHHH
	 	+j 	+ 	+	+ 	+ (	+ 	+  sy   ,7K#J1?JJ1K$BJ(J19K
JJ1JJ1K1
J;	;K>J;	?KL #L		L)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=   loggingtypingr   r   	getLogger__name__rD   r@   r;   r   r    r    r   r   <module>r^      s    2 # " " " " "                  		8	$	$ "  ) C C C C &P &P &P &P &P &PRW W W W W Wr   