
    Ájھ                       d Z ddlmZ ddlZddlZddlZddlZddlZddlm	Z	m
Z
mZmZ ddlmZ ddlmZ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 ddlmZ ddlmZm Z m!Z!m"Z"m#Z# ddl$m%Z% d	dl&m'Z'm(Z(m)Z) d	dl*m+Z,m-Z- d	dl.m/Z/ e	rd	dl0m1Z1 d	dl2m3Z3 g dZ4e
e e!f   Z5e
e'e(f   Z6e
e-e/f   Z7e8e6e
ed   df   f   Z9dZ:dZ;dZ<dZ=d	Z>dZ? ej                  eA      ZB G d d      ZC ed       G d  d!             ZDd*d"Zd+d#ZE	 	 	 	 	 	 	 	 d,d$ZF G d% d&      ZGd-d'ZHej                  e?ddd(	 	 	 	 	 	 	 	 	 	 	 	 	 d.d)       ZJy)/u  The sessions-side tool runner — the managed-agents counterpart to
``client.beta.messages.tool_runner``.

:class:`SessionToolRunner` attaches to a managed-agents session's event stream,
reconciles against the events-list endpoint, dispatches every ``agent.tool_use``
*and* ``agent.custom_tool_use`` event against a local tool registry, posts the
matching result event back (``user.tool_result`` / ``user.custom_tool_result``),
and yields one :class:`DispatchedToolCall` per completed call. A call the
server gated behind user confirmation (``evaluated_permission`` ``ask``, e.g.
an ``always_ask`` tool) is held until its ``user.tool_confirmation`` event
arrives — executed on ``allow``, never executed on ``deny``. It also stops
itself once the session has been idle (``stop_reason`` ``end_turn``) for
``max_idle`` seconds. It does **not** touch the work-item lease — wrap it in
:class:`anthropic.lib.environments.EnvironmentWorker` if you need heartbeating /
force-stop.
    )annotationsN)TYPE_CHECKINGUnionLiteralcast)	dataclass)SequenceAsyncIterator   )TRANSIENT_ERRORSis_fatal_status_error   )Headers   )tool_registryrun_runnable_tooltool_error_content)_copy_client_with_bearer_auth)	ToolErrorBetaRunnableToolBetaAsyncRunnableToolBetaFunctionToolResultTypeaclose_runnable_tool)helper_header)"BetaManagedAgentsAgentToolUseEvent(BetaManagedAgentsAgentCustomToolUseEvent*BetaManagedAgentsUserToolConfirmationEvent)Content*BetaManagedAgentsUserToolResultEventParams)0BetaManagedAgentsUserCustomToolResultEventParams)AsyncAnthropic)AsyncEvents)SessionToolRunnerDispatchedToolCallDispatchedToolUseEventDispatchedToolResultParamsBetaAnyRunnableToolMANAGED_AGENTS_BETADEFAULT_MAX_IDLE_run_session_toolsallowzmanaged-agents-2026-04-01g      ?g      $@g     b@g      N@c                  L    e Zd ZdZdZddZddZddZddZddZ	ddZ
dd	Zy
)
_IdleClocku  Tracks how long the session has been idle after an ``end_turn`` stop.

    :attr:`end_turn_at` is the monotonic timestamp of the most recent
    ``session.status_idle`` event with ``stop_reason.type == "end_turn"`` for
    which no newer event has since arrived; ``None`` whenever the session is not
    in that state. :meth:`SessionToolRunner._idle_watchdog` stops the runner
    once it has been set for ``max_idle`` seconds.

    Confirmation-gated calls pause the clock while they are unresolved:
    :meth:`hold` / :meth:`release` count them — from the moment a call is held
    awaiting its verdict until it is denied or, when allowed, until the dispatch
    loop has finished with it — and an :meth:`arm` landing while any are
    outstanding is deferred rather than applied. The last :meth:`release`
    applies a still-pending deferral so the runner can time out once nothing
    gated remains in flight.

    The clock is event-driven, not polled: every armed-state change signals the
    :attr:`wake` event so the watchdog wakes immediately instead of waiting out
    a poll interval. The watchdog captures :attr:`wake` *before* it reads
    :attr:`end_turn_at`, so a change landing between the read and the wait still
    wakes it.
    )end_turn_atwake_holds_arm_deferredc                `    d | _         t        j                         | _        d| _        d| _        y )Nr   F)r.   anyioEventr/   r0   r1   selfs    O/tmp/pip-target-k_scjv0h/lib/python/anthropic/lib/tools/_beta_session_runner.py__init__z_IdleClock.__init__   s&    )-KKM	"    c                j    | j                   j                          t        j                         | _         y N)r/   setr3   r4   r5   s    r7   _signalz_IdleClock._signal   s    		KKM	r9   c                    t        |dd      }|dk(  ry|dk(  r,t        t        |dd      dd      dk(  r| j                          y| j                          y)up  Arm the clock on an ``end_turn`` idle, disarm it on anything else.

        ``user.tool_confirmation`` events are neutral: they signal neither agent
        activity nor an idle, and their effect on the clock flows through
        :meth:`hold` / :meth:`release` instead — disarming here would discard
        the deferred arm the verdict is about to settle.
        typeNuser.tool_confirmationsession.status_idlestop_reasonend_turn)getattrarmdisarm)r6   evev_types      r7   
note_eventz_IdleClock.note_event   sV     "fd+..++MSW8XZ`bf0gku0uHHJKKMr9   c                ~    | j                   rd| _        yt        j                         | _        | j                          y)u+  (Re)start the idle countdown from now and wake the watchdog.

        Deferred while any gated call is held or in flight — stopping then
        would drop the held call when its verdict later arrives, or cut the
        runner off before a released call's result can drive the next turn.
        TN)r0   r1   time	monotonicr.   r=   r5   s    r7   rE   z_IdleClock.arm   s.     ;;!%D>>+r9   c                Z    d| _         | j                  d| _        | j                          yy)z@Cancel the idle countdown; only signals on an actual transition.FN)r1   r.   r=   r5   s    r7   rF   z_IdleClock.disarm   s,    "'#DLLN (r9   c                    | xj                   dz  c_         | j                  d| _        d| _        | j                          yy)z<Pause the countdown while a gated call is held or in flight.r   NT)r0   r.   r1   r=   r5   s    r7   holdz_IdleClock.hold   s<    q' "&D#DLLN (r9   c                    | xj                   dz  c_         | j                   dk(  r| j                  r| j                          yyy)u  Drop one hold; the last release applies any deferred arm.

        Once nothing gated is held or in flight, a deferred ``end_turn``
        countdown starts now (with a fresh grace window) so the runner can
        still time out — any newer event disarms it again as usual.
        r   r   N)r0   r1   rE   r5   s    r7   releasez_IdleClock.release   s7     	q;;! 2 2HHJ !3r9   NreturnNone)rG   objectrS   rT   )__name__
__module____qualname____doc__	__slots__r8   r=   rI   rE   rF   rO   rQ    r9   r7   r-   r-      s2    . CI#"
 	r9   r-   T)frozenc                  l    e Zd ZU dZded<   	 ded<   	 ded<   	 ded<   	 d	ed
<   	 dZd	ed<   	 dZded<   y)r$   ug  One tool call observed by :class:`SessionToolRunner`.

    Covers both tool-call event kinds — a builtin ``agent.tool_use`` and a
    custom ``agent.custom_tool_use``. The originating event is in :attr:`event`
    (with its input) and the posted-back result in :attr:`result`; ``name`` and
    ``tool_use_id`` are flat conveniences mirroring ``event``.
    r%   eventz!DispatchedToolResultParams | Noneresultstrtool_use_idnameboolis_errorTpostedNzLiteral['allow', 'deny'] | Noneconfirmation)rV   rW   rX   rY   __annotations__re   rf   r[   r9   r7   r$   r$      se     "!3 .-/ - IJN& FD9 59L185r9   r$   c                X    |t        | |d      S | j                  t        d            S )a  Build the runner's request client.

    With an environment key, defer to :func:`_copy_client_with_bearer_auth`
    for a Bearer-only sub-client. Without one, layer the helper-telemetry
    header onto the caller's client via ``with_options`` (parent is not
    mutated).
    zsession-tool-runner)
auth_tokenhelper)default_headers)r   with_optionsr   )clientenvironment_keys     r7   _scoped_clientro      s4     ",VXmnn}=R/STTr9   c                ~   t        | t              r
d| xs ddgS g }| D ]  }|j                  d      }|dk(  r4t        d|j                  d      xs d      }|j	                  d|d       M|dv r|j	                  t        d|             m|j	                  dt        j                  |      d        |xs dddgS )a  Bridge Messages-API tool-result content to the narrower Sessions-API content union.

    The two APIs share text/image/document/search_result block shapes but use
    distinct nominal TypedDicts; ToolReference blocks have no Sessions equivalent
    so they are stringified.
    textz(no output))r?   rq   r?   r`   )imagedocumentsearch_result_SessionContent)
isinstancer`   getr   appendjsondumps)contentoutblockkindrq   s        r7   _to_session_contentr   -  s     '3)AMBCC!#C Dyy 6>uyy0AMBDJJ56;;JJt-u56JJ

50ABCD ;FM:;;r9   c                    t        |      }| j                  dk(  rd| j                  ||d}|S d| j                  ||d}|S )ac  Build the result-event params matching ``ev``'s tool-call kind.

    A custom tool call (``agent.custom_tool_use``) is answered with a
    ``user.custom_tool_result`` keyed by ``custom_tool_use_id``; a builtin tool
    call (``agent.tool_use``) with a ``user.tool_result`` keyed by
    ``tool_use_id``. Both use the codegen'd event-params TypedDicts.
    agent.custom_tool_useuser.custom_tool_result)r?   custom_tool_use_idrd   r{   user.tool_result)r?   ra   rd   r{   )r   r?   id)rG   r{   rd   session_contentcustom_resultbuiltin_results         r7   _build_result_eventr   C  s[     *'2O	ww))-"$%% &	K
 "uu"	BN r9   c                      e Zd ZdZeddd	 	 	 	 	 	 	 	 	 	 	 	 	 ddZddZddZej                  dd       Z
ddZdd	Zdd
ZddZddZddZddZddZddZddZddZddZy)r#   uY  Attach to a managed-agents session and dispatch its tool calls locally.

    The sessions-side counterpart to ``client.beta.messages.tool_runner``: an
    async iterable that, for each ``agent.tool_use`` or ``agent.custom_tool_use``
    event the agent emits, executes the matching tool from ``tools``, posts the
    matching result event back (``user.tool_result`` for a builtin tool call,
    ``user.custom_tool_result`` for a custom one), and yields one
    :class:`DispatchedToolCall`. Internally drives event-stream reconnect (with
    capped backoff) and result posting via an ``anyio`` task group, so it works
    under both ``asyncio`` and ``trio``.

    Iteration ends when the session terminates (``session.status_terminated`` /
    ``session.deleted``), when the consumer breaks out of the loop, or — once
    the session has gone idle with ``stop_reason`` ``end_turn`` — when
    ``max_idle`` seconds elapse with no new event (any new event resets the
    countdown; it re-arms on the next ``end_turn`` idle). ``max_idle=None``
    disables that last condition. On exit it runs each tool's optional cleanup:
    the ``close`` hook and, for tools defined as an (async) context manager, its
    ``__exit__`` / ``__aexit__``. It does **not** touch the work-item lease —
    wrap it in an
    :class:`~anthropic.lib.environments.EnvironmentWorker` for heartbeating /
    force-stop.

    Pass ``environment_key`` to authenticate the event stream / list / send
    calls with the self-hosted environment key (bearered, with the client's
    default ``x-api-key`` dropped); leave it unset to use the client's own
    credentials.

    A self-hosted session is commonly serviced by **two** clients at once: this
    runner inside the customer's sandbox (registered with the file/shell sandbox
    tools) and the customer's app backend (handling the agent's ``custom``
    function tools). The Sessions API has a partial-fulfillment contract: when a
    session pauses on ``requires_action`` the pending tool-call ids can mix both
    kinds, and each client must post results **only** for the ids it owns and
    leave the rest pending for the other client. A tool-call event whose name is
    not in ``tools`` is therefore assumed to belong to the other client: the
    runner posts no result for it, does not mark it answered, and leaves the
    ``tool_use_id`` pending — but still yields a :class:`DispatchedToolCall`
    (``posted=False``, ``is_error=False``, ``result=None``) so the caller can
    observe the unowned dispatch.

    Tool calls the server gated behind user confirmation are **not** executed
    on arrival: an ``agent.tool_use`` event whose ``evaluated_permission`` is
    ``ask`` (e.g. a tool configured with the ``always_ask`` permission policy)
    is held until the matching ``user.tool_confirmation`` event arrives. An
    ``allow`` verdict releases the call to execute as normal; a ``deny``
    verdict — or a call the server already evaluated to ``deny`` — is never
    executed and nothing is posted for it (the denial itself resolves the call
    server-side), but it is still yielded (``confirmation="deny"``,
    ``posted=False``, ``result=None``) so the caller can observe it.

    Usage::

        from anthropic.lib.tools.agent_toolset import AgentToolContext, beta_agent_toolset_20260401

        async with AgentToolContext(workdir="/workspace") as env:
            async for call in client.beta.sessions.events.tool_runner(
                work.data.id,
                tools=[*beta_agent_toolset_20260401(env), my_tool],
            ):
                print(f"{call.name} -> {'error' if call.is_error else 'ok'}")
    Nmax_idlern   extra_headersc               ^    || _         || _        || _        t        ||      | _        || _        y r;   )
session_idtoolsr   ro   _scopedr   )r6   rm   r   r   r   rn   r   s          r7   r8   zSessionToolRunner.__init__  s3     %49
  &fo> +r9   c                  K   | j                         4 d {   }|2 3 d {   }| 7 7 6 d d d       d {  7   y # 1 d {  7  sw Y   y xY wwr;   )_run)r6   callscalls      r7   	__aiter__zSessionToolRunner.__aiter__  sV     99; 	 	%#  d
	e	 	 	 	 	sY   A-AA1/1AA1AAA AA
AAAc                *   K   | 2 3 d{   }
7 6 yw)a=  Drive the runner to completion, discarding the per-call observations.

        Named to match ``BetaToolRunner.until_done`` (and to avoid colliding
        with :meth:`EnvironmentWorker.run`, which is a forever-loop): it returns
        once the session ends / goes idle, rather than running until cancelled.
        Nr[   )r6   _s     r7   
until_donezSessionToolRunner.until_done  s"       	 	!	ts   c                  K    j                   j                  j                  j                   _        t
        j                  d j                         t         j                         _
        t                _        t                _        i  _        i  _        t!        j"                          _        t'                _        t!        j*                  t,           d      \   _         _        t!        j*                  t2           t4        j6                        \   _         _        d fd}	 t!        j<                         5  t!        j>                         4 d{   }|jA                   jB                         |jA                   jD                         |jA                   jF                          jH                  |jA                   jJ                         	  |         j$                  j                          |jL                  jO                          ddd      d{    ddd       t!        j<                  d      5   j:                   j8                   j0                   j.                  fD ]  }	 |jQ                          d{     	 ddd       t!        j<                  d      5   j                  D ]  }tU        |       d{     	 ddd       y7 #  j$                  j                          |jL                  jO                          w xY w7 # 1 d{  7  sw Y   
xY w# 1 sw Y   xY w7 # tR        $ r Y w xY w# 1 sw Y   xY w7 # 1 sw Y   yxY w# t!        j<                  d      5   j:                   j8                   j0                   j.                  fD ]+  }	 |jQ                          d{  7   # tR        $ r Y )w xY w 	 ddd       n# 1 sw Y   nxY wt!        j<                  d      5   j                  D ]  }tU        |       d{  7    	 ddd       w # 1 sw Y   w xY wxY ww)	u  Drive the session tool loop, yielding an iterator of
        :class:`DispatchedToolCall`. :meth:`__aiter__` (and the module-level
        :func:`_run_session_tools` shim used by ``EnvironmentWorker``) wrap this.

        Per-run state lives on ``self`` as private attributes so the loops below
        — :meth:`_stream_loop`, :meth:`_dispatch_loop`, :meth:`_reconcile`,
        :meth:`_idle_watchdog`, :meth:`_stop_watcher` — can mutate it as methods
        rather than threading a shared state object through free functions.
        z*session tool runner starting session_id=%sd   )max_buffer_sizec                J   K   j                   2 3 d {   } |  7 
6 y wr;   )_recv_results)r   r6   s    r7   iteratorz(SessionToolRunner._run.<locals>.iterator  s,      #00  d
0s   #!!#!#NTshieldrS   z!AsyncIterator[DispatchedToolCall])+r   betasessionsevents_eventsloginfor   r   r   _tools_by_namer<   _seen	_answered_confirmations_awaiting_confirmationr3   r4   _stopr-   _idle_clockcreate_memory_object_stream	_WorkItem
_send_work
_recv_workr$   mathinf_send_resultsr   CancelScopecreate_task_group
start_soon_stop_watcher_stream_loop_dispatch_loopr   _idle_watchdogcancel_scopecancelaclose	Exceptionr   )r6   r   tgstreamtools   `    r7   r   zSessionToolRunner._run  sq     %)LL$5$5$>$>$E$E=tO>KDJJ>W  #u
#&5 DFIK#[[]
%<+0+L+LY+W,
( 271R1RSe1f HH2
.D.	(	5 ""$ 1 224 1 1
 MM$"4"45MM$"3"34MM$"5"56}}0d&9&9:	1&j( 

(..0'1 112 ""$/ #1143E3EtX\XgXgh F$mmo-- ""$/ 5 JJ 5D.t44455 5C1$ 

(..0'1 1 1 11 18 .$ 	  55 5 ""$/ #1143E3EtX\XgXgh F$mmo--$    ""$/ 5 JJ 5D.t44455 5 5s{  D&Q*M( >L0KL0A9L
K4LL0LL0#M( +Q2M4L?L=L?MQ-MMM	QL06LLL0L-	 L#!L-	(L00L:5M( =L??	MM
MMMQMM%!Q(Q?2O&2OOOO&	OO&OO&	Q&O/+QP8&P)'P8/	Q8Q=QQc                ^  K   g }d}d}	 | j                   j                  | j                  d| j                        2 3 d{   }|j                  dk(  s|j                  dk(  r7| j
                  j                  |j                         |j                  |       n|j                  dk(  r&| j                  j                  |j                         n|j                  dk(  r&| j                  j                  |j                         nJ|j                  d	k(  r;|j                  | j                  vr#|j                  | j                  |j                  <   |j                  d
k(  xr t        t        |dd      dd      dk(  }@7 <6 n.# t        $ r"}t         j#                  d|       d}Y d}~nd}~ww xY w|r-|D ]'  }| j
                  j%                  |j                         ) y|D cg c]  }|j                  | j                  vs| nc c}w }}| j&                  j)                          |D ]  }| j+                  |       d{  7    | j,                  j/                         D cg c]  }|j                  | j                  v s| nc c}w c}D ]4  }| j1                  || j                  |j                            d{  7   6 |D cg c]6  }|j                  | j                  vs|j                  | j,                  vs5|8 nc c}w }}|r|s| j&                  j3                          yyyw)a  Read full history and enqueue every tool-call event still unanswered.

        Two-pass: read the whole history before emitting so a tool-call whose
        result appears later in the same history is not re-dispatched. Pairs
        ``agent.tool_use`` with ``user.tool_result`` and ``agent.custom_tool_use``
        with ``user.custom_tool_result`` when computing which calls are answered.
        Fi  )limitr   Nagent.tool_user   r   r   r@   rA   rB   r?   rC   z8reconcile list failed; skipping pending enqueue error=%sT)r   listr   r   r?   r   addr   rx   r   ra   r   r_   r   rD   r   r   warningdiscardr   rF   _route_tool_eventr   values_apply_verdictrE   )	r6   pendinglast_was_end_turnlist_failedrG   e
unansweredheldoutstandings	            r7   
_reconcilezSessionToolRunner._reconcile)  s     13!"	 LL--dooTY]YkYk-l  b77.."''=T2T
 JJNN255)NN2&WW 22NN&&r~~6WW 99NN&&r'<'<=WW 88 ~~T^^;>@ii++BNN;GG44 ^M4 @&$OS]] "-l4  	 KKRTUVK	   *

""255)*#*JRbee4>>.IbJJ
J 	! 	-B((,,,	-
 #'"="="D"D"FgB"%%SWSfSfJfRgg 	JD%%dD,?,?,HIII	J $
ruuDNN'BruuTXToToGoB
 
 
 [  " &1s   L-2F E? E<E?D8F <E??F  L-	F,
F'"L-'F,,6L-"H H;L-?I #L-#JJ8L-=K >L-	L'L L)L-c                  K   t         }| j                  j                         s	 | j                  j	                  | j
                  | j                         d {   4 d {   }| j                          d {    |2 3 d {   }t         }| j                  j                  |       |j                  dk(  s|j                  dk(  rX|j                  | j                  vsa| j                  j                  |j                         | j                  |       d {    |j                  dk(  r&| j                  j                  |j                          |j                  dk(  r'| j                  j                  |j"                         |j                  dk(  r| j%                  |       d {    5|j                  dv sEt&        j)                  d       | j                  j+                           d d d       d {    y y y 7 7 7 7 7 7 g7 6 d d d       d {  7   n# 1 d {  7  sw Y   nxY wn# t,        $ r}| j                  j                         rY d }~y t/        |      r5t&        j1                  d	|       | j                  j+                          Y d }~y t&        j3                  d
||       Y d }~nd }~ww xY wt5        j6                  |      5  | j                  j9                          d {  7   d d d        n# 1 sw Y   nxY wt;        |dz  t<              }| j                  j                         s)Hw)N)r   r   r   r   r   r@   )zsession.status_terminatedzsession.deletedzsession terminatedz"stream failed permanently error=%sz8stream disconnected, reconnecting backoff=%.1fs error=%sr   )STREAM_BACKOFF_STARTr   is_setr   r   r   r   r   r   rI   r?   r   r   r   r   r   ra   r   _note_confirmationr   r   r<   r   r   errorr   r3   move_on_afterwaitminSTREAM_BACKOFF_CAP)r6   backoffr   rG   r   s        r7   r   zSessionToolRunner._stream_loopw  s    &**##%%d
 "&!4!4T__TXTfTf!4!gg # #kq//+++$* # #b"6
 ((33B777&66"''E\:\!uuDJJ6 $

ruu 5&*&<&<R&@ @ @WW(:: NN..r~~>WW(AA NN..r/D/DEWW(@@"&"9"9""===WW(XXHH%9: JJNN,"-# # # & h #+# !A >%#$*# # # # #. $ 	d::$$&(+ IIBAFJJNN$VX_abcc	d $$W- (jjoo'''( ( ('A+'9:GS **##%sD  "M4I H	I "H#I &H.:H;H.HHH	AH."9H.HBH./H0H.0H.6I HI M	I I H.HH.H.I H.I 'H*(I .I 4H75I <I M	KK'M,;K'M,KMKM%LLL		ML4Mc                :  K   t        |dd      }| j                  j                  |j                        }|dk(  r| j	                  |       d{    y|||dk(  r&| j
                  j                  |df       d{    y|j                  | j                  vr^t        j                  d|j                  |j                         || j                  |j                  <   | j                  j                          y| j                  ||       d{    y7 7 7 	w)uq  Enqueue ``ev`` for dispatch, honoring its evaluated permission.

        A builtin call the server gated behind user confirmation
        (``evaluated_permission == "ask"``, e.g. the ``always_ask`` policy) is
        held until the matching ``user.tool_confirmation`` event arrives
        instead of executing immediately. The gate fails closed: only an
        explicit ``allow`` verdict releases a gated call, a call the server
        already evaluated to ``deny`` is never executed regardless of any
        verdict, a stray ``deny`` verdict recorded for a call that never needed
        confirmation also resolves it as denied (any deny signal wins), and —
        because the wire can carry values newer than this SDK's types — an
        unrecognised permission is held like ``ask`` and an unrecognised
        verdict is treated as a denial, never dispatched.
        evaluated_permissionNdenyr+   zWtool %r requires user confirmation; holding tool_use_id=%s until user.tool_confirmation)rD   r   rw   r   _resolve_deniedr   sendr   r   r   rb   r   rO   r   )r6   rG   
permissionverdicts       r7   r   z#SessionToolRunner._route_tool_event  s
    & R!7>
%%))"%%0 &&r***?!Z7%:oo**B:666  d999
 mGGEE
 68++BEE2  %%'!!"g...% + 7 	/s7   ADD.D=D>BDDDDDc                   K   |j                   | j                  |j                  <   | j                  j	                  |j                        }|y| j                  ||j                          d{    y7 w)zHRecord an allow/deny verdict and release the held call it gates, if any.N)r_   r   ra   r   rw   r   )r6   rG   r   s      r7   r   z$SessionToolRunner._note_confirmation  s\     .0iiBNN+**..r~~><
 !!$		222s   A+A5-A3.A5c                  K   | j                   j                  |j                  d      du}|dk(  rmt        j	                  d|j
                  |j                         |s| j                  j                          | j                  j                  |df       d{    y|r| j                  j                          | j                  |       d{    y7 ;7 w)u  Dispatch or resolve a gated call according to the user's verdict.

        The idle-clock hold accounting lives here: a denial drops the held
        call's hold, while an allow keeps one hold on the call (taking it now
        if the verdict was already known when the call was routed, so it was
        never held) until the dispatch loop has finished with it — the
        countdown must not run over gated work that is still in flight.
        Nr+   z*tool call confirmed tool=%s tool_use_id=%s)r   popr   r   r   rb   r   rO   r   r   rQ   r   )r6   rG   r   was_helds       r7   r   z SessionToolRunner._apply_verdict  s      ..22255$?tKgHHA277BEER  %%'//&&G}555   ((*&&r*** 6 +s$   BCC5CCCCc                *  K   | j                   j                  |j                         t        j	                  d|j
                  |j                         | j                  t        |d|j                  |j
                  ddd             d{    y7 w)ud  Resolve a denied call without executing it.

        The denial itself resolves the call server-side — no result event will
        ever be posted for it — so mark it answered to keep reconcile from
        re-surfacing it and the idle accounting from waiting on it, then yield
        the observability call (nothing ran, nothing was posted).
        z6tool call denied; not executing tool=%s tool_use_id=%sNFr   r^   r_   ra   rb   rd   re   rf   )r   r   r   r   r   rb   _surface_callr$   )r6   rG   s     r7   r   z!SessionToolRunner._resolve_denied  sw      	255!I277TVTYTYZ  EEWW#

 
	
 
	
s   B	BBBc                   K   	 | j                   j                  |       d{    y7 # t        j                  t        j                  f$ r Y yw xY ww)u  Yield ``call`` to the consumer, tolerating a consumer that left early.

        ``BrokenResourceError`` — the consumer broke out of the iterator;
        ``ClosedResourceError`` — the dispatch loop already closed the send
        side (possible for the deny path, which runs from the stream loop and
        can outlive the dispatch loop). Either way the underlying work already
        happened; only the observability event is lost.
        N)r   r   r3   BrokenResourceErrorClosedResourceError)r6   r   s     r7   r   zSessionToolRunner._surface_call
  sG     	$$))$///))5+D+DE 		s1   A* (* A* #AAAAc                  K   	 	 	 | j                   j                          d {   \  }}	 |j                  | j                  vr9t        j                  d      5  | j                  ||       d {    d d d        |dk(  r| j                  j                          	 7 z# t        j                  $ rQ Y t        j                  d      5  | j
                  j                          d {  7   d d d        y # 1 sw Y   y xY ww xY w7 # 1 sw Y   xY w# |dk(  r| j                  j                          w w xY w# t        j                  d      5  | j
                  j                          d {  7   d d d        w # 1 sw Y   w xY wxY ww)NTr   r+   )r   receiver3   EndOfStreamr   r   r   r   r   _executer   rQ   )r6   rG   rf   s      r7   r   z SessionToolRunner._dispatch_loop  sc    	2-1__-D-D-F'F$B
3uuDNN2
 #..d; B"&--L"AAAB $w. ((002) 'F((  & ""$/ 2((//1112 2 2- BB B $w. ((002	 / ""$/ 2((//1112 2 2s   FD: B  BB  .D D	0D1D	5D =!D: B   D3D: 4F
C7(C+)C7.	F7D <FDD: D		DD "D77D: :F
E>/E2
0E>5	F
>FF

Fc                  K   t         j                  d|j                  |j                         | j                  j                  |j                        }|2t         j                  d|j                  |j                         d}d}d}nd}t        |j                        }	 t        j                  t              5  t        ||       d{   }ddd       t#        ||      }| j%                  ||j                         d{   }| j'                  t)        |||j                  |j                  |||	             d{    y7 {# 1 sw Y   zxY w# t        $ r d|j                  d}d}Y t        $ r}	t        |	      }d}Y d}	~	d}	~	wt        $ r7}	t         j!                  d|j                         t        |	      }d}Y d}	~	d}	~	ww xY w7 7 w)
un  Run ``ev``'s tool, post its result, and surface the dispatched call.

        ``confirmation`` is the verdict that released the call onto the work
        queue — ``"allow"`` for an ask-gated call the user approved, ``None``
        for a call that needed no confirmation. (Denied calls never reach this
        method; ``_resolve_denied`` surfaces them.)
        z%executing tool tool=%s tool_use_id=%sNzNtool %r not owned by this runner; leaving tool_use_id=%s pending for its ownerFztool z
 timed outTztool %s raisedr   )r   r   rb   r   r   rw   dictinputr3   
fail_afterTOOL_TIMEOUTr   TimeoutErrorr   r   r   	exceptionr   _send_resultr   r$   )
r6   rG   rf   r   tool_resultrd   sentinput_r{   r   s
             r7   r   zSessionToolRunner._execute8  s     	8"''255I""&&rww/< HH`
 KHD H"((^F %%l3 D$5dF$CCGD .b'8DK**;>>D  "EEWW!)

 
	
 
	
 DD D  !"''J7  ,Q/  .8,Q/ 
 ?
	
s   BGE 8EE	EE ,GG<G>G?GEEE G-G/G7F	G	G-GGGGGc                  K   d}t        t              D ]Z  }	 | j                  j                  | j                  |g| j
                         d{    | j                  j                  |        y t        j                  d||       y7 :# t        $ rJ}|}t        |      rY d}~ 6|t        dz
  k  r!t        j                  |dz          d{  7   Y d}~d}~ww xY ww)u$  Post ``tool_result`` back to the session, retrying transient failures.

        ``tool_use_id`` is the originating tool-call event id — passed
        explicitly because the result params key it differently
        (``tool_use_id`` vs ``custom_tool_use_id``) depending on the kind.
        N)r   r   Tr   z2failed to send tool result tool_use_id=%s error=%sF)rangeSEND_RETRIESr   r   r   r   r   r   r   r   r3   sleepr   r   )r6   r   ra   last_errir   s         r7   r   zSessionToolRunner._send_resultx  s      &*|$ 	-A-ll''OO'="&"4"4 (   
 "";/	-  			FU]^ $ -(+|a''++a!e,,,-sX   C!6BB	B.C!	B	CC!C!''CCCC!CC!c                Z  K   | j                   }|J | j                  }| j                  j                         s|j                  }|j
                  }|t        || j                         d{    S|t        j                         |z
  z
  }|dk  r1t        j                  d|       | j                  j                          yt        j                  |      5  t        || j                         d{    ddd       | j                  j                         syy7 7 +# 1 sw Y   *xY ww)ag  Stop the runner once the session has been idle (``end_turn``) for
        ``max_idle`` seconds with no new events.

        Event-driven: it blocks on the idle clock's wake event rather than
        polling. Capturing ``clock.wake`` *before* reading ``clock.end_turn_at``
        closes the race where the clock changes between the read and the wait.
        Nr   z/session idle after end_turn for %.0fs; stopping)r   r   r   r   r/   r.   _wait_firstrK   rL   r   r   r<   r3   r   )r6   r   clockr/   at	remainings         r7   r   z SessionToolRunner._idle_watchdog  s      ==###  **##%::D""Bz!$

333 DNN$4r$9:IA~JHU

  $$Y/ 4!$

3334 **##%
 4 44 4sC   A*D+,D-A*D+D1D2D6"D+D+DD($D+c                   K   | j                   j                          d{    | j                  j                          d{    y7 '7 w)zMWhen ``_stop`` is set, close the work stream so :meth:`_dispatch_loop` exits.N)r   r   r   r   r5   s    r7   r   zSessionToolRunner._stop_watcher  s9     jjoooo$$&&& 	 &s!   AA!AA
A
A)rm   r!   r   r`   r   Sequence[BetaAnyRunnableTool]r   float | Nonern   
str | Noner   Headers | NonerS   rT   r   rR   )rS   0AsyncIterator[AsyncIterator[DispatchedToolCall]])rG   r%   rS   rT   )rG   r   rS   rT   )rG   r%   r   zLiteral['allow', 'deny']rS   rT   )r   r$   rS   rT   )rG   r%   rf   zLiteral['allow'] | NonerS   rT   )r   r&   ra   r`   rS   rc   )rV   rW   rX   rY   r)   r8   r   r   
contextlibasynccontextmanagerr   r   r   r   r   r   r   r   r   r   r   r   r   r[   r9   r7   r#   r#   a  s    =J "2&*(,++ +
 -+ + $+ &+ 
+:
 ##U5 $U5rL#\+;^*/X
3+,
, 2<>
@:4:'r9   r#   c                    K   t        j                         4 d{   dfd}| D ]  }j                  ||        ddd      d{    y7 47 # 1 d{  7  sw Y   yxY ww)z+Return as soon as any of ``events`` is set.Nc                v   K   | j                          d {    j                  j                          y 7 wr;   )r   r   r   )rG   r   s    r7   _waiterz_wait_first.<locals>._waiter  s)     '')OOOO""$ s   97 9)rG   anyio.EventrS   rT   )r3   r   r   )r   r  rG   r   s      @r7   r  r    sh     &&( ' 'B	%  	'BMM'2&	'' ' ' ' ' ' 'sD   A*AA* A A*AA*A*A'AA'#A*r   c                 K   t        | |||||      }|j                         4 d{   }| ddd      d{    y7 7 # 1 d{  7  sw Y   yxY ww)ak  Internal: drive a :class:`SessionToolRunner` as an async context manager.

    Kept as a thin module-level shim because
    :class:`~anthropic.lib.environments.EnvironmentWorker` enters the runner
    inside its own task group and wants the context-manager shape for
    deterministic cleanup. New code should iterate :class:`SessionToolRunner`
    directly.
    )r   r   rn   r   N)r#   r   )rm   r   r   r   rn   r   runnerr   s           r7   r*   r*     se     $ '#F {{}        sA   &AAAAAAAAAAAA)rm   r!   rn   r  rS   r!   )r{   r   rS   zlist[_SessionContent])rG   r%   r{   r   rd   rc   rS   r&   )r   r  rS   rT   )rm   r!   r   r`   r   r  r   r  rn   r  r   r  rS   r  )KrY   
__future__r   ry   r   rK   loggingr  typingr   r   r   r   dataclassesr   collections.abcr	   r
   r3   _retryr   r   _typesr   _tool_dispatchr   r   r   ro   r   _beta_functionsr   r   r   r   r   _stainless_helpersr   types.beta.sessionsr   r   r   Etypes.beta.sessions.beta_managed_agents_user_tool_result_event_paramsr   ru   r   Ltypes.beta.sessions.beta_managed_agents_user_custom_tool_result_event_paramsr    _clientr!   resources.beta.sessions.eventsr"   __all__r'   r%   r&   tupler   r(   r   r   r   r  r)   	getLoggerrV   r   r-   r$   r   r   r#   r  r  r*   r[   r9   r7   <module>r,     s  " #      6 6 ! 3  <  P P :  / 
 )=" ,.CCD  ACkkl ".46  (%0@$0F*GGH	
 2      g!\ \~ $95 95 95x
U<,'   	<T	' T	'n	'  ."&$( )	
    " 6  r9   