
    b\jrZ                       % S r SSKJr  SSKrSSKrSSKrSSKJrJrJ	r	  SSK
Jr  SSKrSSKJr  SS	KJrJrJr  S
SKJrJrJr  SSKJr  S
SKJrJr  SSKJrJrJr  \(       a  S
SK J!r!  SSK"J#r#  S
SK$J%r%  SS/r&\RN                  " \(5      r)Sr*Sr+Sr,\\\   \	S/\\   4   4   r-/ \Q\.P7r/S\0S'   SS.           SS jjr1SS jr2 " S S5      r3g) u  The self-hosted environment worker — the full composition of the
control-plane poller and the per-session tool runner.

:class:`EnvironmentWorker` claims work items from a self-hosted environment, and
for each claimed ``session`` work item: builds the per-session
:class:`~anthropic.lib.tools.agent_toolset.AgentToolContext` and downloads the
session agent's skills, then runs a
:class:`~anthropic.lib.tools._beta_session_runner.SessionToolRunner` for the
session *while* heartbeating the work-item lease in parallel; on exit it
force-stops the work item and loops to the next one. The lease heartbeat
reporting ``state == "stopping"`` (or a lost lease) ends the session run.

Build one from the generated work resource::

    client.beta.environments.work.worker(environment_id=..., environment_key=...)

or construct it directly::

    from anthropic.lib.environments import EnvironmentWorker

    EnvironmentWorker(client, environment_id=..., environment_key=...)

:meth:`EnvironmentWorker.handle_item` runs that same per-work-item flow for a
single work item you've already claimed (e.g. a ``worker poll --on-work`` script
handed one to a fresh process); with no arguments it reads the ``ANTHROPIC_*``
env vars that command sets.
    )annotationsN)TYPE_CHECKINGUnionCallable)Sequence   )TRANSIENT_ERRORS   )
_is_status
aiter_work_is_fatal_4xx   )HeadersNotGiven	not_given)_copy_client_with_bearer_auth)BetaSelfHostedWorkBetaSessionWorkData)DEFAULT_MAX_IDLEBetaAnyRunnableTool_run_session_tools)AsyncAnthropicAgentToolContext)	AsyncWorkEnvironmentWorkerEnvironmentWorkerToolsg      >@g     V@NO_HEARTBEATr   ztuple[type[Exception], ...]_HEARTBEAT_TRANSIENT_ERRORS)extra_headersc                 #    [         n[        n[        n[        R                  " 5       nUR                  5       (       GdL   [        R                  " U5         U R                  UUUUS9I Sh  vN n	SSS5        W	R                  n[        R                  " 5       nU	R                  S:  a3  U	R                  n[        S[        U	R                  S-  [         5      5      nU	R                  S;   d  U	R                  (       d<  [        R!                  SU	R                  U	R                  5        UR#                  5         g [        R,                  " U5         UR/                  5       I Sh  vN   SSS5        UR                  5       (       d  GMK  gg GN ! , (       d  f       GN%= f! [$         a  n
['        U
5      (       a+  [        R)                  SU
5        UR#                  5          Sn
A
g[        R                  " 5       U-
  U:  a+  [        R)                  S	Xj5        UR#                  5          Sn
A
g[        R+                  S
U
5         Sn
A
GNSn
A
ff = f N! , (       d  f       N= f7f)a  Keep the work-item lease alive while a session is being served.

``work`` must be bound to a sub-client authenticated for the environment;
this loop adds no auth of its own. Sets ``stop`` when the control plane
reports the work is ``stopping`` / ``stopped``, when the lease is no
longer extended, on a permanent heartbeat failure, or when transient
failures have run long enough that the lease must be assumed lost (so two
runners don't end up serving the same work).
)environment_idexpected_last_heartbeatr    Nr   g      ?r   )stoppingstoppedz5heartbeat signals shutdown state=%s lease_extended=%sz$permanent heartbeat failure error=%sz=lease assumed lost: no successful heartbeat in %.0fs error=%sz$transient heartbeat failure error=%s)_HEARTBEAT_DEFAULT_HEARTBEAT_TTL_DEFAULT_NO_HEARTBEAT_SENTINELtime	monotonicis_setanyio
fail_after	heartbeatlast_heartbeatttl_secondsmaxminstatelease_extendedloginfosetr   r   errorwarningmove_on_afterwait)workwork_idr"   stopr    intervalttllastlast_successrespes              X/var/www/website/venv/lib/python3.13/site-packages/anthropic/lib/environments/_worker.py_heartbeat_looprF   Z   s    " "H
 C!D>>#Lkkmm$	 !!(+!^^#1,0"/	 ,   ,0 &&D>>+L!#&&sC(8(81(<>P$QRzz44D<O<OPRVR\R\^b^q^qr
 =P
   *))+ +O kkmm ,+ + 	CQ		@!D
 ~~,.4		Y[^b
KK>BB	C2  +*s   >I%F" F-F.F2F" :CI%I&I'I+I%I%F
FF" "
I,6I
"I%'AI
)I%.I
I%
II%I
I"I%c                   U =(       d    [         R                  R                  U5      nU(       d  [        SU SU 35      eU$ )zFall back to ``env_var`` for ``value``; raise a clear error if still empty.

The ``ANTHROPIC_*`` env vars are the ones the ``ant worker poll --on-work``
command sets on the process it spawns for a claimed work item.
zhandle_item: u     is required — pass it or set )osenvironget
ValueError)valuenameenv_varresolveds       rE   _requirerP      s<     /

w/H=.NwiXYYO    c            
          \ rS rSrSrSSSSS\\SSS.	                     SS jjrSS jrSS jr	SSSSS	.         SS
 jjr
SS jrSrg)r      u  Run a self-hosted environment worker.

Composed from the control-plane poller (``client.beta.environments.work.poller``)
and the per-session :class:`SessionToolRunner`. For each claimed ``session``
work item it builds the per-session :class:`AgentToolContext` and downloads
the session agent's skills, then runs a session tool runner for the session
*while* heartbeating the work-item lease in parallel; on exit it force-stops
the work item and loops to the next one.

A single ``environment_key`` is the worker's only credential: a Bearer-only
scoped sub-client is built once per call (one for polling, one for
heartbeat / force-stop, and the session tool runner builds its own
internally), so every request the worker issues is authenticated by the
environment key with the parent client's ``X-Api-Key`` cleared.

Async only — :meth:`run` loops forever, so bound it (cancel the task or wrap
it in :func:`asyncio.wait_for`) when you want it to stop.

Use :meth:`handle_item` if you already hold a claimed work item (e.g. a
``worker poll --on-work`` script handed one to a fresh process) and just
want the per-item flow without the poll loop — with no arguments it reads the
``ANTHROPIC_*`` env vars that command sets, so ``environment_id`` (only used
by :meth:`run`) isn't needed.

Prefer ``client.beta.environments.work.worker(...)`` to build one; the direct
constructor below is equivalent.

Example::

    from anthropic import AsyncAnthropic

    client = AsyncAnthropic()

    # Long-running daemon: poll for work, serve each session, loop.
    await client.beta.environments.work.worker(
        environment_id=environment_id,
        environment_key=environment_key,
        workdir="/workspace",
    ).run()

    # Already-claimed item (e.g. inside `ant worker poll --on-work ...`):
    await client.beta.environments.work.worker(workdir="/workspace").handle_item()

    # Equivalent, constructing the worker directly:
    from anthropic.lib.environments import EnvironmentWorker

    await EnvironmentWorker(client, workdir="/workspace").handle_item()

Args:
  client: The async Anthropic client.
  environment_id: The self-hosted environment to poll for work. Required by
    :meth:`run`; not used by :meth:`handle_item`.
  environment_key: The environment key — the worker's single credential.
    Used as the Bearer credential on the scoped sub-clients the worker
    constructs for the control-plane (poll / ack / stop) and session-level
    (events stream / list / send + heartbeat / force-stop) calls.
    Required by :meth:`run`; :meth:`handle_item` falls back to it (then to
    ``ANTHROPIC_ENVIRONMENT_KEY``) when not passed one.
  tools: Tools to expose to each claimed session. Either a fixed list, or a
    factory invoked once per session with that session's
    :class:`AgentToolContext`. Defaults to
    ``beta_agent_toolset_20260401(env)`` (the standard
    ``agent_toolset_20260401`` set bound to the per-session context).
  workdir: Base directory for the per-session :class:`AgentToolContext`.
    Defaults to :func:`os.getcwd` captured when the worker is constructed
    (matches the TS worker's ``process.cwd()``-at-construction), so a
    ``chdir`` between constructing the worker and serving a session does not
    change where tools resolve paths.
  unrestricted_paths: Forwarded to the per-session :class:`AgentToolContext`.
  max_idle: Forwarded to the session tool runner — seconds to keep running
    after the session goes idle with ``stop_reason`` ``end_turn``. Defaults
    to :data:`~anthropic.lib.environments.DEFAULT_MAX_IDLE` (60s). ``None``
    disables it.
  worker_id: Optional identifier sent on each poll. Defaults to a unique,
    hostname-prefixed id.
  extra_headers: Optional headers passed through per request on every
    call the worker makes (poll / ack / stop / heartbeat and the session
    tool runner's event stream / list / send). They are threaded into
    each call's ``extra_headers=`` and never assigned onto the client, so
    client state is not mutated. Auth and ``x-stainless-helper`` are
    supplied by the worker's scoped sub-clients (and the parent client's
    ``default_headers`` propagate via their ``client.copy()``); a header
    given here overrides a scoped client's same-named default for that
    request, so use it for caller passthrough (e.g. trace ids), not auth.
NF)	r"   environment_keytoolsworkdirunrestricted_pathsmax_file_bytesmax_idle	worker_idr    c       	            Xl         X l        X0l        X@l        Uc  [        R
                  " 5       OUU l        X`l        Xpl        Xl	        Xl
        Xl        g )N)_client_environment_id_environment_key_toolsrH   getcwd_workdir_unrestricted_paths_max_file_bytes	_max_idle
_worker_id_extra_headers)selfclientr"   rT   rU   rV   rW   rX   rY   rZ   r    s              rE   __init__EnvironmentWorker.__init__   sN     - / @G		T[#5 -!#+rQ   c                    [        U R                  5      (       a  U R                  U5      $ U R                  b  U R                  $ SSKJn  U" U5      $ )Nr   )beta_agent_toolset_20260401)callabler_   tools.agent_toolsetrl   )rg   envrl   s      rE   
_tools_forEnvironmentWorker._tools_for  sE    DKK  ;;s##;;";; 	F*3//rQ   c                X  #    U R                   nU R                  nUb  Uc  [        S5      e[        U R                  USS9n[        UR                  R                  R                  UU R                  SU R                  S9  Sh  vN nU R                  XB5      I Sh  vN   M$   N N
 g7f)a~  Poll the environment and service each claimed session until cancelled.

Loops forever; cancel the task (or wrap it in :func:`asyncio.wait_for`)
to stop it. Equivalent to claiming work items via
``client.beta.environments.work.poller`` and running the per-item flow
for each.

Raises:
  ValueError: if ``environment_id`` / ``environment_key`` were not passed
    to the constructor.
NzWEnvironmentWorker.run: environment_id and environment_key are required to poll for workzenvironments-work-poller
auth_tokenhelperF)r"   rZ   	auto_stopr    )r]   r^   rK   r   r\   r   betaenvironmentsr<   re   rf   _handle_item)rg   r"   rT   poll_client	work_items        rE   runEnvironmentWorker.run$  s      --//!_%<vww 4LL_=W
  *))..)oo-- 
 	@) ##I???	@ @ 
s<   A>B* B(B$B(B*B&B*$B(&B*(B*)r=   r"   
session_idrT   c          	       #    [        USSS9n[        USSS9n[        USSS9n[        U=(       d    U R                  SS	S9n[        R                  " UU[        R                  " S
US9S9nU R                  XT5      I Sh  vN   g N7f)u  Service a single, already-claimed work item without the poll loop.

Builds the per-session :class:`AgentToolContext` (workdir from this
worker's options) and downloads the session agent's skills, then runs a
:class:`SessionToolRunner` for the session *while* heartbeating the
work-item lease in parallel, and force-stops the work item on exit
(whether the runner finishes normally, raises, or the heartbeat loop
signals shutdown).

Use this when something else does the claiming — e.g. a
``worker poll --on-work`` script that hands an already-claimed item to a
fresh process. ``work_id`` / ``environment_id`` / ``session_id`` fall
back to ``ANTHROPIC_WORK_ID`` / ``ANTHROPIC_ENVIRONMENT_ID`` /
``ANTHROPIC_SESSION_ID`` (the env vars that command sets) when not
passed; ``environment_key`` resolves in order: the explicit argument,
then this worker's own ``environment_key``, then
``ANTHROPIC_ENVIRONMENT_KEY`` — so with no arguments inside that command
it just works. Non-session work items are ignored (but still
force-stopped so the lease doesn't sit until TTL).

Raises:
  ValueError: if any of ``work_id`` / ``environment_id`` / ``session_id``
    / ``environment_key`` is still empty after the fallbacks.
r=   ANTHROPIC_WORK_ID)rM   rN   r"   ANTHROPIC_ENVIRONMENT_IDr~   ANTHROPIC_SESSION_IDrT   ANTHROPIC_ENVIRONMENT_KEYsession)typeid)r   r"   dataN)rP   r^   r   model_constructr   ry   )rg   r=   r"   r~   rT   r{   s         rE   handle_itemEnvironmentWorker.handle_itemC  s     @ 7<OP!.7GQklj|E[\
 #4t44"/
 '66)$44)
S
	
 	;;;s   A=B?B Bc           
     :  ^ ^^#    SSK Jn  [        T R                  USS9nUR                  R
                  R                  m UR                  R                  n[        R                  " 5        ISh  vN m[        R                  " 5       nUR                  UR                  U4       SU UU4S jjjnTR                  U5        U" T R                  T R                  T R                   UUS9n UR#                  5       I Sh  vN   T R%                  U5      n	 ['        T R                  UU	T R(                  UT R*                  S9 ISh  vN n
U
  Sh  vN nM   N NZ N N
 SSS5      ISh  vN    O! , ISh  vN  (       d  f       O= fUR-                  5         TR.                  R1                  5         O/! UR-                  5         TR.                  R1                  5         f = f [        R2                  " S	S
9   UR5                  SSS5      I Sh  vN    SSS5        O`! , (       d  f       OR= f! [        R2                  " S	S
9   UR5                  SSS5      I Sh  vN    SSS5        f ! , (       d  f       f = f= fSSS5      ISh  vN    O! , ISh  vN  (       d  f       O= f[        R2                  " S	S
9    TR7                  UR                  UR                  S	T R*                  S9I Sh  vN    OI! [8         a<  n[;        US5      (       d!  [<        R?                  SUR                  U5         SnAOSnAff = fSSS5        g! , (       d  f       g= f! [        R2                  " S	S
9    TR7                  UR                  UR                  S	T R*                  S9I Sh  vN    OI! [8         a<  n[;        US5      (       d!  [<        R?                  SUR                  U5         SnAOSnAff = fSSS5        f ! , (       d  f       f = f= f7f)u  The per-item body shared by :meth:`run`'s poll loop and :meth:`handle_item`.

Runs a :class:`SessionToolRunner` for the work item's session while
heartbeating its lease, force-stopping the work item on exit. All
control-plane traffic for this work item — heartbeat + force-stop —
flows through a
Bearer-only sub-client built here; the session tool runner builds its
own ``session-tool-runner``-tagged sub-client internally.
r   r   zenvironments-workerrs   Nc                   >#     [        TU UUTR                  S9I S h  vN   TR                  R                  5         g  N! TR                  R                  5         f = f7f)N)r=   r"   r>   r    )rF   rf   cancel_scopecancel)r=   r"   stop_evrg   tgwork_ress      rE   
_heartbeat2EnvironmentWorker._handle_item.<locals>._heartbeat  s\     
	1-$$++9!(*.*=*=   ..0 ..0s)   A A ?A A A AA )rV   rW   rX   rh   r~   )rU   rY   rT   r    T)shield)r"   forcer    i  z-force-stop on exit failed work_id=%s error=%s)r=   strr"   r   r   anyio.EventreturnNone) rn   r   r   r\   rw   rx   r<   r   r   r,   create_task_groupEventr"   
start_soonra   rb   rc   
__aenter__rp   r   rd   rf   r7   r   r   CancelScope	__aexit__r>   	Exceptionr   r5   r8   )rg   r{   rT   r   worker_clientr~   r>   r   ro   rU   calls_rD   r   r   s   `            @@rE   ry   EnvironmentWorker._handle_itemx  s]     	;
 6LL_=R
 !%%2277T	d"**J..00B{{} $-<<*3*B*B+/1 1$'1 )1 	1 14 j) ' MM'+'?'?#'#7#7()>..*** OOC0E1#5 LL&"'%)^^,;*.*=*=$ $ #+0 %a $y 1` +$%5$ $ $ $ $ $ 
..0 
..00**$7!mmD$=== 877**$7!mmD$=== 877C 100000P ""$/	d"--!'0'?'?"&*&9&9	 (    ! d%a--		"QS\S_S_abcd 0//""$/	d"--!'0'?'?"&*&9&9	 (    ! d%a--		"QS\S_S_abcd 0//s  <P/M$ 1E2M$ 5A9J/H6EH60F;	E
F;E6E#E!
E#E6M$ H6F;!E##E6$F;/E20F;6F	<E?=F		F;+H6;,G''H6+J?H%HH%	J%
H3	/J6JI1	"I%#I1	(	J1
I?;JJM$ JM$ J.J J.*M$ 1PM3L:K=;L M
M2M=MMM
	P
M!P$P9P;3N5.N1
/N54P5
O;	?2O6	1P6O;	;P>	P
PPP)
r\   r]   r^   rf   rc   rd   r_   rb   ra   re   )rh   r   r"   
str | NonerT   r   rU   zEnvironmentWorkerTools | NonerV   zstr | os.PathLike[str] | NonerW   boolrX   zint | None | NotGivenrY   zfloat | NonerZ   r   r    Headers | Noner   r   )ro   r   r   zSequence[BetaAnyRunnableTool])r   r   )
r=   r   r"   r   r~   r   rT   r   r   r   )r{   r   rT   r   r   r   )__name__
__module____qualname____firstlineno____doc__r   r   ri   rp   r|   r   ry   __static_attributes__ rQ   rE   r   r      s    Tt &*&*/315#(09!1 $(,,, #	,
 $, -, /, !, ., , , &, 
,8	0@D #%)!%&*3< 3< #	3<
 3< $3< 
3<jidrQ   )r<   r   r=   r   r"   r   r>   r   r    r   r   r   )rL   r   rM   r   rN   r   r   r   )4r   
__future__r   rH   r)   loggingtypingr   r   r   collections.abcr   r,   _retryr	   _pollerr   r   r   _typesr   r   r   _scoped_clientr   types.beta.environmentsr   r   tools._beta_session_runnerr   r   r   r\   r   rn   r    resources.beta.environments.workr   __all__	getLoggerr   r5   r&   r'   r(   r   TimeoutErrorr   __annotations__rF   rP   r   r   rQ   rE   <module>r      s#  8 # 	   1 1 $  % : : 2 2 : N  )6=  8
9!   '   !8-?,@(K^B_,_#``  <]=M;\|;\ 8 \ %)=
= = 	=
 = "= 
=@	{d {drQ   