
    b\j׾                       S r SSKJr  SSKrSSKrSSKrSSKrSSKrSSKJ	r	J
r
JrJr  SSKJr  SSKJrJr  SSKrSSKJrJr  S	S
KJr  SSKJrJrJr  SSKJr  SSKJrJ r J!r!J"r"J#r#  SSK$J%r%  S	SK&J'r'J(r(J)r)  S	SK*J+r,J-r-  S	SK.J/r/  \	(       a  S	SK0J1r1  S	SK2J3r3  / SQr4\
\ \!4   r5\
\'\(4   r6\
\-\/4   r7\8\6\
\S   S4   4   r9Sr:Sr;Sr<Sr=S	r>Sr?\R                  " \A5      rB " S S5      rC\" SS9 " S  S!5      5       rDS*S" jrS+S# jrE        S,S$ jrF " S% S&5      rGS-S' jrH\R                  \?SSS(.             S.S) jj5       rJg)/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                  b    \ rS rSrSrSrSS jrSS jrSS jrSS jr	SS jr
SS	 jrSS
 jrSrg)
_IdleClock   u  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                b    S U l         [        R                  " 5       U l        SU l        SU l        g )Nr   F)r/   anyioEventr0   r1   r2   selfs    ^/var/www/website/venv/lib/python3.13/site-packages/anthropic/lib/tools/_beta_session_runner.py__init___IdleClock.__init__   s&    )-KKM	"    c                l    U R                   R                  5         [        R                  " 5       U l         g N)r0   setr4   r5   r6   s    r8   _signal_IdleClock._signal   s    		KKM	r;   c                    [        USS5      nUS:X  a  gUS:X  a-  [        [        USS5      SS5      S:X  a  U R                  5         gU R                  5         g)uH  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)r7   evev_types      r8   
note_event_IdleClock.note_event   sV     "fd+..++MSW8XZ`bf0gku0uHHJKKMr;   c                    U R                   (       a  SU l        g[        R                  " 5       U l        U R                  5         g)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)r1   r2   time	monotonicr/   r?   r6   s    r8   rH   _IdleClock.arm   s.     ;;!%D>>+r;   c                \    SU l         U R                  b  SU l        U R                  5         gg)z@Cancel the idle countdown; only signals on an actual transition.FN)r2   r/   r?   r6   s    r8   rI   _IdleClock.disarm   s,    "'#DLLN (r;   c                    U =R                   S-  sl         U R                  b  SU l        SU l        U R                  5         gg)z<Pause the countdown while a gated call is held or in flight.r   NT)r1   r/   r2   r?   r6   s    r8   hold_IdleClock.hold   s<    q' "&D#DLLN (r;   c                    U =R                   S-  sl         U R                   S:X  a#  U R                  (       a  U R                  5         ggg)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)r1   r2   rH   r6   s    r8   release_IdleClock.release   s7     	q;;! 2 2HHJ !3r;   )r2   r1   r/   r0   NreturnNone)rJ   objectr[   r\   )__name__
__module____qualname____firstlineno____doc__	__slots__r9   r?   rL   rH   rI   rU   rX   __static_attributes__ r;   r8   r-   r-      s2    . CI#"
 	r;   r-   T)frozenc                  t    \ rS rSr% SrS\S'    S\S'    S\S'    S\S	'    S
\S'    SrS
\S'    SrS\S'   Srg)r$      uS  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confirmationre   )	r^   r_   r`   ra   rb   __annotations__rp   rq   rd   re   r;   r8   r$   r$      se     "!3 .-/ - IJN& FD9 59L185r;   r$   c                L    Ub
  [        XSS9$ U R                  [        S5      S9$ )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     r8   _scoped_clientrz      s2     ",VXmnn}=R/STTr;   c                   [        U [        5      (       a  SU =(       d    SS./$ / nU  H  nUR                  S5      nUS:X  a:  [        SUR                  S5      =(       d    S5      nUR	                  SUS.5        MT  US;   a  UR	                  [        SU5      5        Mw  UR	                  S[
        R                  " U5      S.5        M     U=(       d    SS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))rB   r|   rB   rk   )imagedocumentsearch_result_SessionContent)
isinstancerk   getr   appendjsondumps)contentoutblockkindr|   s        r8   _to_session_contentr   -  s     '3)AMBCC!#Cyy 6>uyy0AMBDJJ56;;JJt-u56JJ

50ABC  ;FM:;;r;   c                    [        U5      nU R                  S:X  a  SU R                  UUS.nU$ SU R                  UUS.nU$ )aO  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)rB   custom_tool_use_idro   r   user.tool_result)rB   rl   ro   r   )r   rB   id)rJ   r   ro   session_contentcustom_resultbuiltin_results         r8   _build_result_eventr   C  s[     *'2O	ww))-"$%% &	K
 "uu"	BN r;   c                      \ rS rSrSr\SSS.             SS jjrSS jrSS jr\	R                  SS j5       rSS	 jrSS
 jrSS jrSS jrSS jrSS jrSS jrSS jrSS jrSS jrSS jrSS jrSrg) r#   ia  u  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-fulfilment 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_idlery   extra_headersc               T    X l         X0l        X@l        [        X5      U l        X`l        g r=   )
session_idtoolsr   rz   _scopedr   )r7   rx   r   r   r   ry   r   s          r8   r9   SessionToolRunner.__init__  s)     %49
  &f> +r;   c                  #    U R                  5        IS h  vN nU  S h  vN nU7v   M   N N
 S S S 5      IS h  vN    g ! , IS h  vN  (       d  f       g = f7fr=   )_run)r7   callscalls      r8   	__aiter__SessionToolRunner.__aiter__  s<     99;;%# d
 e ;;;;;sY   A.AA202AA2AAAAAAAAc                ,   #    U   Sh  vN nM   N
 g7f)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.
Nre   )r7   _s     r8   
until_doneSessionToolRunner.until_done  s       	!	ts   c                 ^ #    T R                   R                  R                  R                  T l        [
        R                  ST R                  5        [        T R                  5      T l
        [        5       T l        [        5       T l        0 T l        0 T l        [         R"                  " 5       T l        ['        5       T l        [         R*                  [,           " SS9u  T l        T l        [         R*                  [2           " [4        R6                  S9u  T l        T l        SU 4S jjn [         R<                  " 5          [         R>                  " 5        ISh  vN nURA                  T RB                  5        URA                  T RD                  5        URA                  T RF                  5        T RH                  b  URA                  T RJ                  5         U" 5       7v   T R$                  R                  5         URL                  RO                  5         SSS5      ISh  vN   SSS5        [         R<                  " SS9   T R:                  T R8                  T R0                  T R.                  4 H  n URQ                  5       I Sh  vN   M     SSS5        [         R<                  " SS9   T R                   H  n[U        U5      I Sh  vN   M     SSS5        g GN! T R$                  R                  5         URL                  RO                  5         f = f N! , ISh  vN  (       d  f       GN= f! , (       d  f       GN= f N! [R         a     M  f = f! , (       d  f       N= f N! , (       d  f       g= f! [         R<                  " SS9   T R:                  T R8                  T R0                  T R.                  4 H.  n URQ                  5       I Sh  vN    M  ! [R         a     M,  f = f   SSS5        O! , (       d  f       O= f[         R<                  " SS9   T R                   H  n[U        U5      I Sh  vN    M     SSS5        f ! , (       d  f       f = f= f7f)	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                L   >#    TR                     S h  vN n U 7v   M   N
 g 7fr=   )_recv_results)r   r7   s    r8   iterator(SessionToolRunner._run.<locals>.iterator  s%      #00 d
0s   $" "$"$NTshieldr[   z!AsyncIterator[DispatchedToolCall])+r   betasessionsevents_eventsloginfor   r   r   _tools_by_namer>   _seen	_answered_confirmations_awaiting_confirmationr4   r5   _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   )r7   r   tgstreamtools   `    r8   r   SessionToolRunner._run  s$     %)LL$5$5$>$>$E$E=tO>KDJJ>W  #u
#&5 DFIK#[[]
%<+0+L+LY+W,
( 271R1RSe1f HH2
.D.	(	5 ""$ 2244
 MM$"4"45MM$"3"34MM$"5"56}}0d&9&9:	1&j( 

(..0' 54 %2 ""$/#1143E3EtX\XgXghF$mmo-- i 0 ""$/ JJD.t444 ' 0/C 5$ 

(..0' 5444 %$8 .$ 	 0/ 5 0/ ""$/#1143E3EtX\XgXghF$mmo--$  i 0// ""$/ JJD.t444 ' 0//s{  D%Q')M> >L5KL5A:L
K!4LL5 L!L5%M> -Q'2M4M	MM	MQ',M-
M+M-	Q'L56LLL5L2	 L#!L2	-L55
M?M> M		
MMMM
M($Q'+M--
M;7Q'>Q$2O=O!OO!O=!
O/+O=.O//O=4	Q$=
PQ$"Q Q	Q
	Q$
Q!Q$$Q'c                  #    / nSnSn U R                   R                  U R                  SU R                  S9  Sh  vN nUR                  S:X  d  UR                  S:X  a7  U R
                  R                  UR                  5        UR                  U5        OUR                  S:X  a&  U R                  R                  UR                  5        OUR                  S:X  a&  U R                  R                  UR                  5        OMUR                  S	:X  a=  UR                  U R                  ;  a#  UR                  U R                  UR                  '   UR                  S
:H  =(       a    [        [        USS5      SS5      S:H  nGMM   GNI
 O/! [         a"  n[         R#                  SU5        Sn SnAOSnAff = fU(       a/  U H(  nU R
                  R%                  UR                  5        M*     gU Vs/ s H   oDR                  U R                  ;  d  M  UPM"     Os  snf nnU R&                  R)                  5         U H  nU R+                  U5      I Sh  vN    M     U R,                  R/                  5        Vs/ s H   oDR                  U R                  ;   d  M  UPM"     Os  snf sn H4  nU R1                  XpR                  UR                     5      I Sh  vN    M6     U Vs/ s H<  oDR                  U R                  ;  d  M  UR                  U R,                  ;  d  M:  UPM>     Os  snf nnU(       a#  U(       d  U R&                  R3                  5         ggg7f)ag  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   rC   rD   rE   rB   rF   z8reconcile list failed; skipping pending enqueue error=%sT)r   listr   r   rB   r   addr   r   r   rl   r   rj   r   rG   r   r   warningdiscardr   rI   _route_tool_eventr   values_apply_verdictrH   )	r7   pendinglast_was_end_turnlist_failedrJ   e
unansweredheldoutstandings	            r8   
_reconcile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) #*J7Ree4>>.Ib7J
J 	!B((,,, 
 #'"="="D"D"Fg"FB%%SWSfSfJfR"FgD%%d,?,?,HIII h $
#2uuDNN'BBruuTXToToGoB
 
 [  " &1s   M/F F	FF	EF F		F 
M
F7F2-M2F77=M4HH;MI%M<J$J$#7MKM(L,	L,%L,+3Mc                  #    [         nU R                  R                  5       (       Gd   U R                  R	                  U R
                  U R                  S9I S h  vN  IS h  vN nU R                  5       I S h  vN   U  S h  vN n[         nU R                  R                  U5        UR                  S:X  d  UR                  S:X  a\  UR                  U R                  ;  a@  U R                  R                  UR                  5        U R                  U5      I S h  vN   M  M  UR                  S:X  a'  U R                  R                  UR                   5        M  UR                  S:X  a(  U R                  R                  UR"                  5        GM  UR                  S:X  a  U R%                  U5      I S h  vN   GMA  UR                  S;   d  GMT  [&        R)                  S5        U R                  R+                  5           S S S 5      IS h  vN   g g  GN GN GN GN GN Nk N
 S S S 5      IS h  vN    O! , IS h  vN  (       d  f       O= f! [,         a  nU R                  R                  5       (       a   S nAg [/        U5      (       a5  [&        R1                  S	U5        U R                  R+                  5          S nAg [&        R3                  S
X5         S nAOS nAff = f[4        R6                  " U5         U R                  R9                  5       I S h  vN    S S S 5        O! , (       d  f       O= f[;        US-  [<        5      nU R                  R                  5       (       d  GMO  g 7f)N)r   r   r   r   r   rC   )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   rL   rB   r   r   r   r   r   rl   r   _note_confirmationr   r   r>   r   r   errorr   r4   move_on_afterwaitminSTREAM_BACKOFF_CAP)r7   backoffr   rJ   r   s        r8   r   SessionToolRunner._stream_loopw  s}    &**##%%%d
 "&!4!4T__TXTfTf!4!ggggkq//+++$* #b"6
 ((33B777&66"''E\:\!uuDJJ6 $

ruu 5&*&<&<R&@ @ @  7  WW(:: NN..r~~>WW(AA NN..r/D/DEWW(@@"&"9"9""===WW(XXHH%9: JJNN,"- hgg & h+# !A >% h$* hggggg. $ 	d::$$&&(++ IIBAFJJNN$VX_cc	d $$W-jjoo''' .--'A+'9:GS **##%%sQ  'M91I HI $H%I (H?<H=H?H,H"H,BH? H%!BH?<H(=H?0H?I H*I M9I I H?"H,%H?(H?*I ,H?-I 8H;9I >M9?IIII M9I 
K,#K'M9A K'M9K'"M9'K,,M9L2#L&$L2)	M92
M <9M98M9c                B  #    [        USS5      nU R                  R                  UR                  5      nUS:X  a  U R	                  U5      I Sh  vN   gUc  Ub  US:X  a&  U R
                  R                  US45      I Sh  vN   gUR                  U R                  ;  a]  [        R                  SUR                  UR                  5        XR                  UR                  '   U R                  R                  5         gU R                  X5      I Sh  vN   g N N N	7f)u  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)rG   r   r   r   _resolve_deniedr   sendr   r   r   rm   r   rU   r   )r7   rJ   
permissionverdicts       r8   r   #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  %%'!!"...% + 7 	/s7   ADD1DDBDDDDDc                   #    UR                   U R                  UR                  '   U R                  R	                  UR                  5      nUc  gU R                  X!R                   5      I Sh  vN   g N7f)zHRecord an allow/deny verdict and release the held call it gates, if any.N)rj   r   rl   r   r   r   )r7   rJ   r   s      r8   r   $SessionToolRunner._note_confirmation  sY     .0iiBNN+**..r~~><
 !!$		222s   A+A5-A3.A5c                  #    U R                   R                  UR                  S5      SLnUS:X  ar  [        R	                  SUR
                  UR                  5        U(       d  U R                  R                  5         U R                  R                  US45      I Sh  vN   gU(       a  U R                  R                  5         U R                  U5      I Sh  vN   g N@ N7f)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   rm   r   rU   r   r   rX   r   )r7   rJ   r   was_helds       r8   r    SessionToolRunner._apply_verdict  s      ..22255$?tKgHHA277BEER  %%'//&&G}555   ((*&&r*** 6 +s$   BC"C:C"C C" C"c                $  #    U R                   R                  UR                  5        [        R	                  SUR
                  UR                  5        U R                  [        USUR                  UR
                  SSSS95      I Sh  vN   g N7f)u<  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   ri   rj   rl   rm   ro   rp   rq   )r   r   r   r   r   rm   _surface_callr$   )r7   rJ   s     r8   r   !SessionToolRunner._resolve_denied  sv      	255!I277TVTYTYZ  EEWW#

 
	
 
	
s   BBB	Bc                   #     U R                   R                  U5      I Sh  vN   g N! [        R                  [        R                  4 a     gf = f7f)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   r4   BrokenResourceErrorClosedResourceError)r7   r   s     r8   r  SessionToolRunner._surface_call
  sF     	$$))$///))5+D+DE 		s1   A* (* A* $AAAAc                6  #       U R                   R                  5       I S h  vN u  p UR                  U R                  ;  a6  [        R                  " SS9   U R                  X5      I S h  vN   S S S 5        US:X  a  U R                  R                  5         M   Ny! [        R                   aT     [        R                  " SS9   U R
                  R                  5       I S h  vN    S S S 5        g ! , (       d  f       g = ff = f N! , (       d  f       N= f! US:X  a  U R                  R                  5         f f = f! [        R                  " SS9   U R
                  R                  5       I S h  vN    S S S 5        f ! , (       d  f       f = f= f7f)NTr   r+   )r   receiver4   EndOfStreamr   r   r   r   r   _executer   rX   )r7   rJ   rq   s      r8   r    SessionToolRunner._dispatch_loop  s@    	2-1__-D-D-F'F$B
3uuDNN2
 #..d;"&--"AAA < $w. ((002) 'F((  & ""$/((//111 0//- B <; $w. ((002	 / ""$/((//111 0//s   FE B BB .D D.D
/D3D ;"E B D3E 4FC5&C)'C5,	F5
D?FDE 
D
DD #E  E FF6E9
7F<	F
FFFc                  #    [         R                  SUR                  UR                  5        U R                  R                  UR                  5      nUc2  [         R                  SUR                  UR                  5        SnSnSnO~Sn[        UR                  5      n [        R                  " [        5         [        X75      I Sh  vN nSSS5        [#        UWU5      nU R%                  XAR                  5      I Sh  vN nU R'                  [)        UUUR                  UR                  UUUS	95      I Sh  vN   g Nw! , (       d  f       N{= f! [         a    SUR                  < S3nSn N[         a  n	[        U	5      nSn Sn	A	NSn	A	f[         a7  n	[         R!                  SUR                  5        [        U	5      nSn Sn	A	NSn	A	ff = f N N7f)
uF  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   rm   r   r   r   dictinputr4   
fail_afterTOOL_TIMEOUTr   TimeoutErrorr   r   r   	exceptionr   _send_resultr  r$   )
r7   rJ   rq   r   tool_resultro   sentinput_r   r   s
             r8   r  SessionToolRunner._execute8  s     	8"''255I""&&rww/< HH`
 KHD H"((^F %%l3$5d$CCG 4 .b'8DK**;>>D  "EEWW!)

 
	
 
	
 D 43  !"''J7  ,Q/  .8,Q/ 
 ?
	
s   BG E :E	E
EE +GG9G;G<GE
EE GE G1G3	G<F	GG-GGGGGc                  #    Sn[        [        5       HW  n U R                  R                  U R                  U/U R
                  S9I Sh  vN   U R                  R                  U5          g   [        R                  SX#5        g N:! [         aY  nUn[        U5      (       a   SnA  M<  U[        S-
  :  a(  [        R                  " US-   5      I Sh  vN     SnAM   SnAM  SnAff = f7f)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   r4   sleepr   r   )r7   r  rl   last_errir   s         r8   r  SessionToolRunner._send_resultx  s      &*|$A-ll''OO'="&"4"4 (   
 "";/ %  			F^ $ -(++|a''++a!e,,, (-sX   C.3BBB+C.B
C+C&$C.+)C&CC&C.&C++C.c                  #    U R                   nUc   eU R                  nU R                  R                  5       (       d  UR                  nUR
                  nUc  [        X0R                  5      I Sh  vN   MY  U[        R                  " 5       U-
  -
  nUS::  a1  [        R                  SU5        U R                  R                  5         g[        R                  " U5         [        X0R                  5      I Sh  vN   SSS5        U R                  R                  5       (       d  M  gg N N1! , (       d  f       N5= f7f)a?  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   r0   r/   _wait_firstrO   rP   r   r   r>   r4   r   )r7   r   clockr0   at	remainings         r8   r    SessionToolRunner._idle_watchdog  s      ==###  **##%%::D""Bz!$

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

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

333 0 **##%%
 4 4 0/sC   A0D?2D*3A.D?!D.:D,;D.?'D?(D?,D..
D<8D?c                   #    U R                   R                  5       I Sh  vN   U R                  R                  5       I Sh  vN   g N' N7f)zMWhen ``_stop`` is set, close the work stream so :meth:`_dispatch_loop` exits.N)r   r   r   r   r6   s    r8   r   SessionToolRunner._stop_watcher  s7     jjoooo$$&&& 	 &s!   AA!AA
A
A)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )rx   r!   r   rk   r   Sequence[BetaAnyRunnableTool]r   float | Nonery   
str | Noner   Headers | Noner[   r\   r   rZ   )r[   0AsyncIterator[AsyncIterator[DispatchedToolCall]])rJ   r%   r[   r\   )rJ   r   r[   r\   )rJ   r%   r   zLiteral['allow', 'deny']r[   r\   )r   r$   r[   r\   )rJ   r%   rq   zLiteral['allow'] | Noner[   r\   )r  r&   rl   rk   r[   rn   )r^   r_   r`   ra   rb   r)   r9   r   r   
contextlibasynccontextmanagerr   r   r   r   r   r   r   r  r   r  r  r   r   rd   re   r;   r8   r#   r#   a  s    =J "2&*(,++ +
 -+ + $+ &+ 
+:
 ##U5 $U5rL#\+;^*/X
3+,
, 2<>
@:4:'r;   r#   c                    ^#    [         R                  " 5        ISh  vN mSU4S jjnU  H  nTR                  X5        M     SSS5      ISh  vN   g N7 N! , ISh  vN  (       d  f       g= f7f)z+Return as soon as any of ``events`` is set.Nc                v   >#    U R                  5       I S h  vN   TR                  R                  5         g  N7fr=   )r   r   r   )rJ   r   s    r8   _waiter_wait_first.<locals>._waiter  s(     '')OOOO""$ s   97 9)rJ   anyio.Eventr[   r\   )r4   r   r   )r   r2  rJ   r   s      @r8   r"  r"    sH     &&((B	% BMM'&  )(((((sD   A3AA3#AA3AA3A3A0A" A0,A3r   c          	       #    [        U UUUUUS9nUR                  5        ISh  vN nU7v   SSS5      ISh  vN   g N N! , ISh  vN  (       d  f       g= f7f)aS  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   ry   r   N)r#   r   )rx   r   r   r   ry   r   runnerr   s           r8   r*   r*     sF     $ '#F {{}} }}}}}sA   #AA AAAAAAA
AAA)rx   r!   ry   r+  r[   r!   )r   r   r[   zlist[_SessionContent])rJ   r%   r   r   ro   rn   r[   r&   )r   r4  r[   r\   )rx   r!   r   rk   r   r)  r   r*  ry   r+  r   r,  r[   r-  )Krb   
__future__r   r   r   rO   loggingr.  typingr   r   r   r   dataclassesr   collections.abcr	   r
   r4   _retryr   r   _typesr   _tool_dispatchr   r   r   rz   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   r   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)   	getLoggerr^   r   r-   r$   r   r   r#   r"  r/  r*   re   r;   r8   <module>rI     s  " #      6 6 ! 3  <  P P :  / 
 )=" ,.CCD  ACkkl ".46  (%0@$0F*GGH	
 2      !\ \~ $95 95 95x
U<,'   	<T	' T	'n	'  ."&$( )	
    " 6  r;   