
    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rSSK	J
r
  SSKJrJrJrJrJrJr  SSKJrJr  SSKJr  SSKJr  SS	KJr  SS
KJrJr  SSKJrJ r J!r!J"r"  SSK#r#SSK$r#SSK%J&r&  SSK'J(r(J)r)  SSK*J+r+J,r,  SSK-J.r.  SSK/J0r0J1r1J2r2J3r3J4r4J5r5  SSK6J7r7J8r8J9r9  \(       a  SSK:J;r;  / SQr<Sr=Sr>Sr?\?r@SrASrBSrCSrD\R                  " S5      rFS2S jrG\R                  " S5      rIS3S jrJS4S  jrKS5S! jrL\ " S" S#5      5       rMS6S$ jrN " S% S&\5      rO " S' S(5      rPS7S) jrQS7S* jrRS7S+ jrSS7S, jrTS8S- jrUS7S. jrVS7S/ jrWS9S0 jrXS:S1 jrYg);u>  Reference implementations of the ``agent_toolset_20260401`` tools — ``bash``,
``read``, ``write``, ``edit``, ``glob``, ``grep`` — plus the workdir/skills
:class:`AgentToolContext`.

This sits next to the other ``lib/tools`` helpers (the Messages tool runner, the
memory tool, …). Importing it pulls in ``subprocess`` etc., so it is kept out of
``anthropic.lib.tools.__init__`` — depend on it explicitly
(``from anthropic.lib.tools.agent_toolset import beta_agent_toolset_20260401``).

The result of :func:`beta_agent_toolset_20260401` is a plain
``list[BetaAsyncFunctionTool]`` — *async* function tools, so it is for the
**async** runners only: ``client.beta.sessions.events.tool_runner(...)`` (the
``SessionToolRunner``, always async) for a managed-agents session, or — via the
:class:`~anthropic.lib.environments.EnvironmentWorker` — the self-hosted
environment worker. The sync ``Anthropic`` ``messages.tool_runner`` accepts
``BetaRunnableTool``, which excludes the async function tools this returns, so
it cannot consume this toolset.

.. warning::
   ``bash`` is **stateful**: it owns a persistent ``/bin/bash`` subprocess that
   is only torn down by its ``close`` cleanup hook. Only ``SessionToolRunner``
   (and the ``EnvironmentWorker`` built on it) invoke that hook. The Messages
   ``client.beta.messages.tool_runner(...)`` does **not** call ``close``, so
   handing this toolset to the Messages tool runner leaks the bash subprocess
   (one orphaned shell per run). Run stateful tools under
   ``client.beta.sessions.events.tool_runner(...)`` / the environment worker,
   or drop ``bash`` from the toolset before using the Messages tool runner.

Trust model: the file tools confine to ``workdir`` (symlink-aware) and are safe
without a sandbox; ``bash`` is unrestricted and should run inside one. See
:class:`AgentToolContext`.
    )annotationsN)S_ISREG)TYPE_CHECKINGAnyListOptional
NamedTuplecast)PathPurePosixPath)partial)islice)asynccontextmanager)field	dataclass)MappingCallable	AwaitableAsyncIterator)run_sync   )_withindownload_session_skills   )NotGiven	not_given)is_given).BetaManagedAgentsAgentToolset20260401BashInput.BetaManagedAgentsAgentToolset20260401EditInput.BetaManagedAgentsAgentToolset20260401GlobInput.BetaManagedAgentsAgentToolset20260401GrepInput.BetaManagedAgentsAgentToolset20260401ReadInput/BetaManagedAgentsAgentToolset20260401WriteInput)	ToolErrorBetaAsyncFunctionToolbeta_async_tool)AsyncAnthropic)AgentToolContextBashSession
BashResultresolve_pathbeta_agent_toolset_20260401beta_bash_toolbeta_read_toolbeta_write_toolbeta_edit_toolbeta_glob_toolbeta_grep_tooli  g      ^@i   i     iP  z\x1b\[[0-9;?]*[ -/]*[@-~]c                2    [        U 5      (       a  U $ [        $ )u   Resolve a configured cap to an effective size limit.

``not_given`` selects ``DEFAULT_MAX_FILE_BYTES``; ``None`` disables the size
check (uncapped); a positive int is the cap. Governs only the size guard —
callers still reject non-regular files.
)r   DEFAULT_MAX_FILE_BYTES)
configureds    W/var/www/website/venv/lib/python3.13/site-packages/anthropic/lib/tools/agent_toolset.py_resolve_max_bytesr8   `   s     "*--:I3II    z!anthropic.lib.tools.agent_toolsetc                     [         R                  R                  5        V Vs0 s H  u  pU R                  S5      (       a  M  X_M!     snn $ s  snn f )u  The environment for the bash subprocess, with the runner's own
credentials scrubbed.

The bash tool runs model-issued commands, so it must never inherit the
runner's ``ANTHROPIC_*`` variables (API key, environment key, per-work
session tokens): a prompt-injected ``echo $ANTHROPIC_API_KEY`` would
otherwise land the credential straight in the session transcript. Passing
an explicit ``env`` to :class:`AgentToolContext` does NOT add to this
default — it FULLY REPLACES it. The provided mapping becomes the entire
bash environment verbatim; nothing here is merged in, so callers who want
the scrubbed process environment plus extras must build that mapping
themselves.

ANTHROPIC_)osenvironitems
startswith)kvs     r7   _default_bash_envrB   m   s<      ZZ--/R/TQq||L7QDAD/RRRs   AAc                ^   [        U[        5      (       a  SnO[        U[        5      (       a  SnOk[        U[        5      (       a  SnOS[        U[        5      (       a  SnO;[        U[
        5      (       a  SnO#UR                  =(       d    SR                  5       n[        U  SU SU 35      $ )zMap a filesystem ``OSError`` to a consistent, runtime-independent message.

The raw ``OSError`` string is platform-specific (``[Errno 2] ENOENT: ...``);
normalise the common cases so the model sees the same wording everywhere.
zno such file or directoryznot a directoryzis a directoryzpermission deniedzfile already existsz	i/o errorz: )	
isinstanceFileNotFoundErrorNotADirectoryErrorIsADirectoryErrorPermissionErrorFileExistsErrorstrerrorlowerr$   )op	file_pathereasons       r7   	_fs_errorrP   ~   s     !&'',	A)	*	*"	A(	)	)!	A	'	'$	A	'	'&**+224t2i[6(344r9   c                     / $ N rS   r9   r7   _empty_skill_dirsrT      s    Ir9   c                      \ rS rSr% Sr\" \R                  S9rS\	S'   Sr
S\	S'   S	rS
\	S'   S	rS\	S'   S	rS\	S'   \rS\	S'   \" S	SSS9rS\	S'   \" \SSS9rS\	S'   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(      ub	  Workdir + path-policy for the agent toolset.

Trust model — two tiers:

- The file tools (:func:`beta_read_tool`, :func:`beta_write_tool`,
  :func:`beta_edit_tool`, :func:`beta_glob_tool`, :func:`beta_grep_tool`)
  resolve paths against ``workdir`` and reject escapes unless
  ``unrestricted_paths`` is set. :func:`resolve_path` follows every symlink
  (including the leaf, even a dangling one) before the check and returns
  that canonical path for the operation, so a symlink inside the workdir
  that points outside it can neither pass the check nor be followed
  afterwards — a real boundary, consistent with the memory tool, so the
  file tools are safe to use without a sandbox.
- :func:`beta_bash_tool` runs an unrestricted ``/bin/bash`` regardless of
  ``unrestricted_paths``. Confinement for it must come from the OS layer
  (e.g. a self-hosted environment runner).

Attributes:
    workdir: Base directory for resolving relative tool paths. Defaults to
        :func:`os.getcwd` captured when the context is constructed (TS
        parity: ``process.cwd()`` at construction), so a ``chdir`` between
        constructing this context and the first tool call does not move
        where paths resolve. Pass an explicit path to override.
    unrestricted_paths: When ``False`` (default), the file tools reject
        paths that resolve outside ``workdir``. Does **not**
        constrain :func:`beta_bash_tool`.
    env: Optional environment for the bash subprocess. When unset, the bash
        tool inherits the process environment with the runner's
        ``ANTHROPIC_*`` credentials scrubbed. When provided, it FULLY
        REPLACES that default environment — the mapping is used verbatim
        and is NOT merged with or added to the scrubbed process
        environment. To keep the defaults plus extra vars, build the
        combined mapping yourself before passing it.
    max_file_bytes: Size cap for the ``read`` and ``edit`` tools, which both
        load the whole file into memory. ``not_given`` (default) uses the
        built-in 256 KiB cap; a positive int sets a custom cap; ``None``
        disables the cap entirely. Disabling it reintroduces the OOM risk on
        a model-controlled path, so pass ``None`` only when the sandbox can
        absorb arbitrarily large files. The non-regular-file (FIFO/device)
        guard always applies regardless of this value.
)default_factorystr | os.PathLike[str]workdirFboolunrestricted_pathsNzAsyncAnthropic | Noneclientz
str | None
session_idOptional[Mapping[str, str]]envint | None | NotGivenmax_file_bytes)defaultinitreprzBashSession | None_bash)rW   rc   rd   
list[Path]_skill_dirsc                   #    U R                   c5  [        R                  U R                  U R                  S9I S h  vN U l         U R                   $  N7fNr_   )re   r)   startrY   r_   selfs    r7   bashAgentToolContext.bash   sA     ::*004880LLDJzz Ms   9AAAc                ~   #    U R                   b*  U R                   R                  5       I S h  vN   S U l         g g  N7frR   )re   closerl   s    r7   rq   AgentToolContext.close   s4     ::!**""$$$DJ "$s   +=;=c                   #    U R                   b  U R                  c  g[        U R                   U R                  U R                  S9I Sh  vN U l        g N
7f)zDownload the session agent's skills into ``{workdir}/skills/<name>/``.

No-op unless both :attr:`client` and :attr:`session_id` are set. The
download + safe archive extraction lives in
:mod:`anthropic.lib.tools._skills`.
N)r]   rY   )r\   r]   r   rY   rg   rl   s    r7   setup_skillsAgentToolContext.setup_skills   sF      ;;$//"9!8QUQ`Q`jnjvjv!wwws   AA
AAc           	        #    U R                    H.  n [        [        [        R                  USS95      I Sh  vN   M0     / U l         g N! [
         a!  n[        R                  SX5         SnAMb  SnAff = f7f)u   Remove the skill directories :meth:`setup_skills` downloaded.

Only the directories this context created are removed — a pre-existing
``{workdir}/skills`` tree is left untouched.
T)ignore_errorsNz,failed to remove downloaded skill dir %s: %s)rg   r   r   shutilrmtree	Exceptionlogwarning)rm   	skill_dirrN   s      r7   _cleanup_skills AgentToolContext._cleanup_skills   sk      ))IZwv}}itTUUU *  V ZJIYYZs=   A9%AA	AA9	A
A6A1+A91A66A9c                B   #    U R                  5       I S h  vN   U $  N7frR   )rt   rl   s    r7   
__aenter__AgentToolContext.__aenter__   s!     !!! 	"s   c                   #     U R                  5       I S h  vN   U R                  5       I S h  vN   g  N N! U R                  5       I S h  vN    f = f7frR   )rq   r~   )rm   excs     r7   	__aexit__AgentToolContext.__aexit__   sE     	)**,&&((( ($&&(((s?   A9 59 A7A9 AAAAA)re   rg   returnr)   r   None)r   r(   )r   objectr   r   )__name__
__module____qualname____firstlineno____doc__r   r<   getcwdrY   __annotations__r[   r\   r]   r_   r   ra   re   rT   rg   rn   rq   rt   r~   r   r   __static_attributes__rS   r9   r7   r(   r(      s    (Z ',BII&FG#F$$ %)F!(!J
!'+C	$+,5N)5 %dU KEK $4EEX]^K^

	x)r9   r(   c                   [        U5      nU R                  (       a%  UR                  5       (       a  UR                  5       $ [        U R                  5      R                  5       nUR                  5       (       a  UOX2-  R                  5       nU R                  (       d   [        XC5      (       d  [        SU< S35      eU$ )uQ  Resolve ``p`` against the workdir; reject results that escape it.

Absolute and relative inputs go through the same canonicalise-then-contain
check — an absolute path that lands inside the workdir is permitted, only
paths that resolve *outside* are rejected. ``Path.resolve()`` follows every
symlink (including the leaf, even a dangling one) before the containment
check, so a symlink under the workdir that targets ``/etc`` is rejected —
and the resolved path is what the tool then operates on, so it can't be
followed afterwards either. See the trust model on :class:`AgentToolContext`.
zpath z escapes workdir)r   r[   is_absoluteresolverY   r   
ValueError)ctxp	candidaterootfulls        r7   r+   r+     s     QI
)"7"7"9"9  ""$$&D"..00Id6FOOQD!!'$*=*=5%5677Kr9   c                  0    \ rS rSr% SrS\S'    S\S'   Srg)	r*   i  u   Result of :meth:`BashSession.exec` — the captured output and exit code.

A ``NamedTuple`` so it unpacks positionally (``out, code = await s.exec(...)``)
and reads by name (``result.output`` / ``result.exit_code``) interchangeably.
stroutputint	exit_coderS   N)r   r   r   r   r   r   r   rS   r9   r7   r*   r*     s     K? N8r9   r*   c                  l    \ rS rSrSrSS jr\SS.SS jj5       r\SS j5       r	\
4SS jjrSS	 jrS
rg)r)   i'  u  A persistent ``/bin/bash`` process; cwd, env and jobs survive across calls.

.. warning::
    :class:`BashSession` is **stateful and not safe to share concurrently**.
    Interleaved :meth:`exec` calls would race for the same stdin/stdout
    pipes (mixed input, output read by the wrong caller, and corrupted
    sentinel detection). Each :class:`AgentToolContext` creates its own
    session, so the safe pattern is *one context per session* — never a
    single ``AgentToolContext`` (or hand-constructed ``BashSession``) shared
    across multiple sessions running on different self-hosted environments.
    Holding the shared instance behind a per-call lock would serialize all
    bash work and is almost certainly not what you want.
c                    Xl         g)u~   Use :meth:`BashSession.start` to construct — ``__init__`` takes an
already-spawned process and is intended for internal use.N_proc)rm   procs     r7   __init__BashSession.__init__6  s	     
r9   Nrj   c          	        #    Ub  [        U5      O	[        5       n[        R                  " / SQU0 UESSSS.E[        R
                  [        R
                  [        R                  S9I S h  vN nU " U5      $  N7f)N)z	/bin/bashz--noprofilez--norc dumb)PS1PS2TERM)cwdr_   stdinstdoutstderr)dictrB   anyioopen_process
subprocessPIPESTDOUT)clsrY   r_   baser   s        r7   rk   BashSession.start;  sl     OtCy1B1D''2>4>2v>//??$$
 
 4y
s   A)A:+A8,A:c                2    U R                   R                  SL$ )u   Whether the underlying bash process has exited / been torn down.

Inverse of "alive". Named ``closed`` (not ``alive``) to match the TS
``BashSession.closed`` boolean — porting code between the two SDKs
should not have to flip the sense of this check.
N)r   
returncoderl   s    r7   closedBashSession.closedH  s     zz$$D00r9   c                  ^^^^#    U R                   (       a  [        S5      eU R                  R                  b  U R                  R                  c   eU R                  R                  nU R                  R                  mS[
        R                  " 5       R                   S3nUS S  SUSS   3nSU SU S3nUR                  UR                  5       5      I S h  vN   [        5       mS	mUR                  5       mSUUUU4S
 jjn [        R                  " U5         U" 5       I S h  vN   S S S 5        ["        R%                  STR'                  SS95      n	U	R)                  U5      n
U
S:  a  [+        U	R-                  5       S5      $ U	S U
 R/                  S5      nX[1        U5      -   S  R-                  5       n U(       a  [3        UR5                  5       S   5      OSnT(       a  SU-   n[+        X5      $  GN N! , (       d  f       N= f! [         a]  n[        R                  " SS9   U R                  5       I S h  vN    S S S 5        O! , (       d  f       O= f[        SU S35      UeS nAf[        R                   " 5        aI    [        R                  " SS9   U R                  5       I S h  vN    S S S 5        e ! , (       d  f       e = ff = f! [6         a    Sn GNf = f7f)Nz)bash session terminated; restart required
__ANT_CMD__DONE__   z''z{ z
} </dev/null 2>&1; printf '\nz	%d\n' $?
Fc                   >#      TR                  S5      I S h  vN n U (       d  g TR                  U 5        [	        T5      [
        :  a  TS [	        T5      [
        -
  2	 SmTT;   a  g Mf   NP! [        R                   a     g f = f7f)NTi   )receiver   EndOfStreamextendlenBASH_OUTPUT_LIMIT)chunkbufmarkerr   	truncateds    r7   read_until_sentinel-BashSession.exec.<locals>.read_until_sentinelf  s     "(.."66E 

5!s8// :c#h):::; $IS= 6(( s8   BA- A+A- AB+A- -BBBBTshieldzbash command timed out after sr   replaceerrorsr   
z[output truncated]
r   )r   RuntimeErrorr   r   r   uuiduuid4hexsendencode	bytearrayr   
fail_afterTimeoutErrorCancelScoperq   get_cancelled_exc_class_ANSIsubdecoderfindr*   striprstripr   r   
splitlinesr   )rm   cmdtimeoutr   sentinelsentinel_splitwrappedr   rN   textidxouttailcoder   r   r   r   s                 @@@@r7   execBashSession.execR  s|    ;;JKKzz+

0A0A0MMM

  ""  

 0 019$RaL>HQRL>: u=n=M[Yjj)***k	"	 	$	!!'*)+++ +. yySZZyZ9:jj"7djjlB//4Cj%#h-')*002	043t(+,"D (3.C#$$y 	+4 , +* 	R ""$/jjl"" 0//!>wiqIJPQQ,,. 	 ""$/jjl"" 0 0/	,  	D	s   CK+G8+K+H G=(G;)G=-H 5BK+<%K !K+;G==
HH 
K+H 
KI0,I II	I0
I	I000K K4J75K:	K
K	KK+K($K+'K((K+c                  #    U R                   R                  bJ  [        R                  " SS9    U R                   R                  R	                  5       I S h  vN   S S S 5        U R                   R                  c[  U R                   R                  5         [        R                  " S5         U R                   R                  5       I S h  vN   S S S 5        [        R                  " SS9    U R                   R	                  5       I S h  vN   S S S 5        g  N! [
         a     Nf = f! , (       d  f       N= f Np! , (       d  f       Nt= f NC! [
         a     NMf = f! , (       d  f       g = f7f)NTr      )
r   r   r   r   acloserz   r   killmove_on_afterwaitrl   s    r7   rq   BashSession.close  s    ::'""$/****11333 0
 ::  (JJOO$$Q'jjoo''' (d+jj''))) ,+ 4   0/ ( (' *  ,+s   ,E0D)'DDDAE0+D<	D:
D<E0*E,E	E
E	E0D
D&#D)%D&&D))
D73E0:D<<
E
E0E
EEEE
E-)E0r   )r   zanyio.abc.Processr   r   )rY   rX   r_   r^   r   r)   )r   rZ   )r   r   r   floatr   r*   r   )r   r   r   r   r   r   classmethodrk   propertyr   BASH_DEFAULT_TIMEOUTr   rq   r   rS   r9   r7   r)   r)   '  sI    
 `d 
 
 1 1 5I J%Xr9   r)   c                j   ^  [         SU 4S jj5       n[        S[        S9" [        [        U5      5      $ )Nc                   >^^#    SmSUU4S jjm S       SUU4S jjjn  U 7v   Tb  TR                  5       I Sh  vN   gg N! Tb  TR                  5       I Sh  vN    f f = f7f)z)Run a command in a persistent bash shell.Nc                 z   >#    Tc0  [         R                  T R                  T R                  S9I S h  vN mT$  N7fri   )r)   rk   rY   r_   )r   sessions   r7   _session3beta_bash_tool.<locals>.bash_tool.<locals>._session  s6      + 1 1#++377 1 KKN Ls   /;9;c                  >#    U(       a-  T	b  T	R                  5       I S h  vN   S m	T" 5       I S h  vN   gU (       d  [        S5      eU(       a  US-  O[        n T" 5       I S h  vN nUR                  XS9I S h  vN u  pVUS:w  a  [        U5      eU$  Nv Ng N4 N! [        [
        4 a  n[        SU 35      UeS nAff = f7f)Nzbash session restartedzbash: command is requiredg     @@)r   zbash: r   )rq   r$   r   r   r   r   )
commandrestart
timeout_msr   r   r   r   rN   r  r  s
           r7   rn   /beta_bash_tool.<locals>.bash_tool.<locals>.bash  s      &!--/))"Gj  / ;<<-7j6)=QG5"*$"#&&&"BB	 qyn$J *  %B ,/ 5&-145sg   CBCB)C
B  'B(B  >B?B  CCB  B   C0B??CCr   )NNN)r  Optional[str]r	  Optional[bool]r
  zOptional[int]r   r   )rq   )rn   r  r  r   s    @@r7   	bash_tool!beta_bash_tool.<locals>.bash_tool  s      '+	 	 hl	"	4B	Wd		 	,	&J"mmo%% #% "mmo%% #s3   A+A	 A+ AA+	A( A#!A((A+rn   nameinput_schema)r   z,AsyncIterator[Callable[..., Awaitable[str]]])r   r&   r   r
   r   )r   r  s   ` r7   r-   r-     s<    ,& ,&f C 3	 r9   c                >   ^  [        S[        S9SSU 4S jjj5       nU$ )Nreadr  c           	       >#     [        TU 5      n UR                  5       n[	        UR
                  5      (       d  [        SU  S35      e[        TR                  5      nUb/  UR                  U:  a  [        SU  SUR                   SU S35      eUR                  5       nU(       d  U$ [        U5      S:w  a  [        S	5      eUu  pxUR                  S
5      n	[        SUS-
  5      n
US:  a  UO
[        U	5      nS
R                  XU 5      $ ! [         a  n[        SU 35      UeSnAff = f! [         a    e [         a  n[        SX5      UeSnAff = f7f)z,Read a file rooted at the working directory.zread: N: not a regular file is  bytes, exceeds z6-byte limit. Use bash (head/tail/sed) to read a slice.r  r   z/read: view_range must be [start_line, end_line]r   r   r   )r+   r   r$   statr   st_moder8   ra   st_size	read_textOSErrorrP   r   splitmaxjoin)rM   
view_rangetargetrN   stlimitr   
start_lineend_linelinesrk   endr   s               r7   r  beta_read_tool.<locals>.read  sl    	1!#y1F	9 B2::&&&3G HII&s'9'9:E RZZ%%7YKtBJJ<7Gw O@ @  ##%D
 Kz?aMNN)


4 AzA~&"Q,hCJyyS)**9  	1fQCL)q0	1   	 	9FI1q8	9sG   ED BD0 "A-E
D-D((D--E0EEEErR   )rM   r   r!  zOptional[List[int]]r   r   )r&   r"   )r   r  s   ` r7   r.   r.     s+    &/]^ +  + _ +D Kr9   c                :   ^  [        S[        S9SU 4S jj5       nU$ )Nwriter  c                   >#     [        TU 5      n UR                  R	                  SSS9  UR                  U5        S[        U5       SU  3$ ! [         a  n[        SU 35      UeSnAff = f! [         a  n[        SX5      UeSnAff = f7f)z4Write a file, creating parent directories as needed.zwrite: NT)parentsexist_okr+  zwrote z
 bytes to )	r+   r   r$   parentmkdir
write_textr  rP   r   )rM   contentr"  rN   r   s       r7   r+  beta_write_tool.<locals>.write  s     	2!#y1F	:MMt<g& G~Z	{;;  	2gaSM*1	2
  	:GY29	:sD   BA +A/ B
A,A''A,,B/
B9BBB)rM   r   r2  r   r   r   )r&   r#   )r   r+  s   ` r7   r/   r/     s%    '0_`< a< Lr9   c                >   ^  [        S[        S9SSU 4S jjj5       nU$ )Neditr  c           	     D  >#     [        TU 5      n UR                  5       n[	        UR
                  5      (       d  [        SU  S35      e[        TR                  5      nUb/  UR                  U:  a  [        SU  SUR                   SU S35      eUR                  5       nUR                  U5      n	U	S:X  a  [        S	U  35      eU(       d  U	S
:  a  [        SU	 SU  S35      eU(       a  UR                  X5      OUR                  XS
5      n
 UR                  U
5        SU  SU(       a  U	 S3$ S
 S3$ ! [         a  n[        SU 35      UeSnAff = f! [         a    e [         a  n[        SX5      UeSnAff = f! [         a  n[        SX5      UeSnAff = f7f)z-Replace text in a file by exact string match.zedit: Nr  r  r  z5-byte limit. Use bash (sed/awk) to edit a large file.r5  r   zedit: old_string not found in r   zedit: old_string appears z
 times in z (must be unique)zedited z (z replacement(s)))r+   r   r$   r  r   r  r8   ra   r  r  r  rP   countr   r1  )rM   
old_string
new_stringreplace_allr"  rN   r#  r$  r   r7  updatedr   s              r7   r5  beta_edit_tool.<locals>.edit%  s    	1!#y1F	9
 B2::&&&3G HII&s'9'9:E RZZ%%7YKtBJJ<7Gw O? ?  ##%D
 

:&A:<YKHIIuqy7wjSdeff:E$,,z64<<XbpqKr	9g& 2{e%BBRSS%BBRSS?  	1fQCL)q0	1"  	 	9FI1q8	9  	9FI1q8	9sk   F D7 BE "A.F F "F 7
EEEF E>,E99E>>F 
FFFF rR   )
rM   r   r8  r   r9  r   r:  r  r   r   )r&   r   )r   r5  s   ` r7   r0   r0   $  s.    &/]^#T #T _#TJ Kr9   c                X     U R                  5       R                  $ ! [         a     gf = f)Ng        )r  st_mtimer  )r   s    r7   _mtime_or_zeror?  N  s+    vvx    s    
))c                >   ^  [        S[        S9SSU 4S jjj5       nU$ )Nglobr  c                  >#    Sn[        U 5      R                  5       (       a9  TR                  (       d  [        S5      e[        S5      nU R	                  S5      nOTR                  (       d$  S[        U 5      R                  ;   a  [        S5      eU(       a   [        TU5      nO#[        TR                  5      R                  5       nU nTR                  (       d  Un [        [        UR                  U5      [        5      5      nUb3  U Vs/ s H&  n[!        UR                  5       U5      (       d  M$  UPM(     nnU(       d  gUR#                  [$        SS	9  S
R'                  S US[(          5       5      $ ! [         a  n[        SU 35      UeSnAff = f! [        [        4 a  n[        SU 35      UeSnAff = fs  snf 7f)z1List files matching a glob pattern, newest first.Nz$glob: absolute pattern not permitted/z..z*glob: '..' is not permitted in the patternzglob: 
no matchesT)keyreverser   c              3  8   #    U  H  n[        U5      v   M     g 7frR   )r   ).0ms     r7   	<genexpr>/beta_glob_tool.<locals>.glob.<locals>.<genexpr>}  s     E)DAQ)Ds   )r   r   r[   r$   lstripr   partsr+   r   rY   r   listr   rA  WALK_MAX_ENTRIESr  r   sortr?  r   GLOB_RESULT_LIMIT)	patternpathconfiner   patrN   matchesrI  r   s	           r7   rA  beta_glob_tool.<locals>.globV  s     #'=$$&&)) FGG9D..%C
 ))dmG6L6R6R.R LMM9'T2D CKK(002C))	1 6$))C.2BCDG  #*K'QWQYY['-Jq'GK6yyE1C2C)DEEE+ " 9#fQCL1q89 G$ 	1fQCL)q0	1 Ls`   BGE9 &9G (F G#G6G<=G9
FFFGF>*F99F>>GrR   rR  r   rS  r  r   r   )r&   r    )r   rA  s   ` r7   r1   r1   U  s.    &/]^&F &F _&FP Kr9   c                >   ^  [        S[        S9SSU 4S jjj5       nU$ )Ngrepr  c                  >#     U(       a  [        TU5      O"[        TR                  5      R                  5       n[        R                  " S5      =n(       a  [        R                  " USSSU S[        U5      /SS	9I Sh  vN nUR                  S
:X  a  gUR                  S:w  a%  [        SUR                  R                  SS9 35      eUR                  R                  SS9n[        U5      [         :  a  US[          S[          S3-   nU$  ["        R$                  " U 5      n[)        Xr5      $ ! [         a  n[        SU 35      UeSnAff = f N! ["        R&                   a  n[        SU 35      UeSnAff = f7f)z.Search file contents for a regular expression.zgrep: Nrgz-nz--no-headingz-ez--F)checkr   rD  r   zgrep: rg failed: r   r   z
[output truncated at  bytes]zgrep: invalid regex: )r+   r   rY   r   r   r$   rx   whichr   run_processr   r   r   r   r   r   GREP_OUTPUT_LIMITrecompileerror
_walk_grep)	rR  rS  searchrN   r\  resultr   rxr   s	           r7   rZ  beta_grep_tool.<locals>.grep  s{    	104\#t,$s{{:K:S:S:UF d##2# !,,T>4$FL F   A%#  A%"3FMM4H4HPY4H4Z3[ \]]--&&i&8C3x++,,-2IJ[I\\c0ddJ	@G$B "%%/  	1fQCL)q0	1 xx 	@3A378a?	@sY   E=6D/ AE= EBE=E $E=/
E9EEE=E:&E55E::E=rR   rX  )r&   r!   )r   rZ  s   ` r7   r2   r2     s*    &/]^& & _&: Kr9   c                L  ^ ^
^^ / m[         m
SU
U4S jjmS	UU 4S jjnUR                  5       (       a	  U" U5        OSn[        R                  " U5       H  u  pEnU Vs/ s H/  owS;  d  M
  [	        U5      U-  R                  5       (       a  M-  UPM1     snUS S & U Hb  n[	        U5      U-  n	U	R                  5       (       a  M(  US-  nU[        :  d  U" U	5      (       a  MF  T(       a  SR                  T5      OSs  s  $    M     T(       a  SR                  T5      $ S$ s  snf )
Nc                   > T[        U 5      S-   -  mTS:  a  TR                  S[         S35        gTR                  U 5        g)Nr   r   z[output truncated at r^  FT)r   appendra  )linebudgethitss    r7   push_walk_grep.<locals>.push  sF    #d)a-A:KK/0A/B'JKDr9   c           	       >  U R                  S5       nSUR                  S5      ;   a
   S S S 5        gUR                  S5        [        US5       Ho  u  p#[	        U5      [
        :  a  M  UR                  SS9R                  S	5      nTR                  U5      (       d  MP  T" U  S
U S
U 35      (       a  Mg    S S S 5        g   S S S 5        g! , (       d  f       g= f! [         a     gf = f)Nrb    i   Tr   r   r   r   z
:F)
openr  seek	enumerater   GREP_MAX_LINE_LENGTHr   r   rf  r  )r   firawrm  rp  rh  s        r7   scan_walk_grep.<locals>.scan  s    	4AaffSk) ! q	'1oFA 3x"66 ::Y:7>>vFDyyttfAaS$4H/I/I$ ! .	 !  !   		sQ   C CC A)C!C8C9C CC 
CC C 
C+*C+r   )z.gitnode_modulesr   r   rD  )rm  r   r   rZ   )r   r   r   rZ   )ra  is_filer<   walkr   
is_symlinkrO  r   )rh  rf  r}  seendirpathdirnames	filenamesdr  r   rn  ro  rp  s   `         @@@r7   re  re    s   DF  & ~~V,.GGFO(Gy $#a0H'HRVW^R_bcRcQoQoQq8HQK "G}t+ ??$$	**$t**.2499T?D " -< #499T?44s   	D!,D!D!c                ~    [        U 5      [        U 5      [        U 5      [        U 5      [	        U 5      [        U 5      /$ )u  Return the ``agent_toolset_20260401`` implementations bound to ``ctx``.

The result is a plain list of :class:`~anthropic.lib.tools.BetaAsyncFunctionTool`
instances — *async* function tools, so it is for the **async** runners only:
the ``AsyncAnthropic`` ``client.beta.messages.tool_runner`` and
``client.beta.sessions.events.tool_runner`` (always async). The sync
``Anthropic`` ``messages.tool_runner`` takes ``BetaRunnableTool``, which
excludes the async function tools this returns. Filter or extend it before
passing it on::

    tools = [*beta_agent_toolset_20260401(ctx), my_custom_tool]
    tools = [t for t in beta_agent_toolset_20260401(ctx) if t.name != "grep"]
)r-   r.   r/   r0   r1   r2   )r   s    r7   r,   r,     s>     	sssss r9   )r6   r`   r   z
int | None)r   zdict[str, str])rL   r   rM   r   rN   r  r   r$   )r   rf   )r   r(   r   r   r   r   )r   r(   r   zBetaAsyncFunctionTool[Any])r   r   r   r   )rh  zre.Pattern[str]rf  r   r   r   )r   r(   r   z list[BetaAsyncFunctionTool[Any]])Zr   
__future__r   r<   rb  r   rx   loggingr   r  r   typingr   r   r   r   r	   r
   pathlibr   r   	functoolsr   	itertoolsr   
contextlibr   dataclassesr   r   collections.abcr   r   r   r   r   	anyio.abcanyio.to_threadr   _skillsr   r   _typesr   r   _utilsr   
types.betar   r   r    r!   r"   r#   _beta_functionsr$   r%   r&   _clientr'   __all__r   r   r5   READ_MAX_BYTESra  ry  rQ  rO  rc  r   r8   	getLoggerr{   rB   rP   rT   r(   r+   r*   r)   r-   r.   r/   r0   r?  r1   r2   re  r,   rS   r9   r7   <module>r     sI  B # 	 	      G G '   * ( G G   $ 5 )   O N)   # '    


/0J ;<S"5* g) g) g)T*8 8 F FR8v$N$'T*ZD35lr9   