LLM tools

Helpful tools for running cli commands and reading, modifying, and creating files in python. This is used primarily for AI’s in tool loops for automating tasks involving the filesystem.

Bash Tools


source

run_cmd

 run_cmd (cmd:str, argstr:str='', disallow_re:str=None, allow_re:str=None)

Run cmd passing split argstr, optionally checking for allowed argstr

Type Default Details
cmd str The command name to run
argstr str All args to the command, will be split with shlex
disallow_re str None optional regex which, if matched on argstr, will disallow the command
allow_re str None optional regex which, if not matched on argstr, will disallow the command

With this little function, we can now run any cli command:

print(run_cmd('ls')[:128])
000_tour.ipynb
00_test.ipynb
01_basics.ipynb
02_foundation.ipynb
03_xtras.ipynb
03a_parallel.ipynb
03b_net.ipynb
04_docments.ipy

Note that, for tool safety, this is not passed through the shell, so wildcards, env vars, etc will not work:

print(run_cmd('ls', 'f*')[:128])
ls: f*: No such file or directory

Let’s create some useful functions from this that will allow for searching, reading and modifing content on the file system.


source

rg

 rg (argstr:str, disallow_re:str=None, allow_re:str=None)

Run the rg command with the args in argstr (no need to backslash escape)

Type Default Details
argstr str All args to the command, will be split with shlex
disallow_re str None optional regex which, if matched on argstr, will disallow the command
allow_re str None optional regex which, if not matched on argstr, will disallow the command
rg('fast.ai CNAME')
'1:fastcore.fast.ai\n'

Functions implemented with run_cmd like this one can be passed regexps to allow or disallow arg strs, i.e to block parent or root directories:

disallowed = r' /|\.\.'
rg('[email protected] ..', disallow_re=disallowed)
'Error: args disallowed'
rg('[email protected] /', disallow_re=disallowed)
'Error: args disallowed'
print(rg('fast.ai CNAME', disallow_re=disallowed))
1:fastcore.fast.ai

NB: These tools have special behavior around errors. Since these have been speficially designed for work with LLMs, any exceptions created from there use is returned as a string to help them debug their work.

run_cmd('asdfe')
"Error running cmd: [Errno 2] No such file or directory: 'asdfe'"

source

sed

 sed (argstr:str, disallow_re:str=None, allow_re:str=None)

Run the sed command with the args in argstr (e.g for reading a section of a file)

Type Default Details
argstr str All args to the command, will be split with shlex
disallow_re str None optional regex which, if matched on argstr, will disallow the command
allow_re str None optional regex which, if not matched on argstr, will disallow the command
print(sed('-n "1,5 p" _quarto.yml'))
project:
  type: website
  pre-render: 
    - pysym2md --output_file apilist.txt fastcore
  post-render: 
# Print line numbers too
print(sed('-n "1,5 {=;p;}" _quarto.yml'))
1
project:
2
  type: website
3
  pre-render: 
4
    - pysym2md --output_file apilist.txt fastcore
5
  post-render: 

Text Edit Tools

Python implementations of the text editor tools from Anthropic. These tools are especially useful in an AI’s tool loop. See claudette for examples.


source

view

 view (path:str, view_range:tuple[int,int]=None, nums:bool=False)

View directory or file contents with optional line range and numbers

Type Default Details
path str Path to directory or file to view
view_range tuple None Optional 1-indexed (start, end) line range for files, end=-1 for EOF
nums bool False Whether to show line numbers

You can specify line ranges and whether to have the output contain line numbers:

print(view('_quarto.yml', (1,10), nums=True))
     1 │ project:
     2 │   type: website
     3 │   pre-render: 
     4 │     - pysym2md --output_file apilist.txt fastcore
     5 │   post-render: 
     6 │     - llms_txt2ctx llms.txt --optional true --save_nbdev_fname llms-ctx-full.txt
     7 │     - llms_txt2ctx llms.txt --save_nbdev_fname llms-ctx.txt
     8 │   resources: 
     9 │     - "*.txt"
    10 │   preview:

Here’s what the output looks like when viewing a directory:

print(view('.', (1,5)))
Directory contents of /Users/jhoward/aai-ws/fastcore/nbs:
/Users/jhoward/aai-ws/fastcore/nbs/llms.txt
/Users/jhoward/aai-ws/fastcore/nbs/000_tour.ipynb
/Users/jhoward/aai-ws/fastcore/nbs/parallel_test.py
/Users/jhoward/aai-ws/fastcore/nbs/_quarto.yml
/Users/jhoward/aai-ws/fastcore/nbs/08_style.ipynb

source

create

 create (path:str, file_text:str, overwrite:bool=False)

Creates a new file with the given content at the specified path

Type Default Details
path str Path where the new file should be created
file_text str Content to write to the file
overwrite bool False Whether to overwrite existing files
Returns str
print(create('test.txt', 'Hello, world!'))
f = Path('test.txt')
test_eq(f.exists(), True)
print('Contents:\n', view(f, nums=True))
Created file test.txt.
Contents:
      1 │ Hello, world!

source

insert

 insert (path:str, insert_line:int, new_str:str)

Insert new_str at specified line number

Type Details
path str Path to the file to modify
insert_line int Line number where to insert (0-based indexing)
new_str str Text to insert at the specified line
Returns str
insert(f, 0, 'Let\'s add a new line')
print(view(f, nums=True))
     1 │ Let's add a new line
     2 │ Hello, world!

source

str_replace

 str_replace (path:str, old_str:str, new_str:str)

Replace first occurrence of old_str with new_str in file

Type Details
path str Path to the file to modify
old_str str Text to find and replace
new_str str Text to replace with
Returns str
str_replace(f, 'new line', '')
print(view(f, nums=True))
     1 │ Let's add a 
     2 │ Hello, world!

source

strs_replace

 strs_replace (path:str, old_strs:list[str], new_strs:list[str])

Replace for each str pair in old_strs,new_strs call `str_replace

Type Details
path str Path to the file to modify
old_strs list List of strings to find and replace
new_strs list List of replacement strings (must match length of old_strs)
strs_replace(f, ["add a new line", "world!"], ["just say", "friends!\nNice to see you."])
print(view(f, nums=True))
     1 │ Let's add a 
     2 │ Hello, friends!
     3 │ Nice to see you.

source

replace_lines

 replace_lines (path:str, start_line:int, end_line:int, new_content:str)

Replace lines in file using start and end line-numbers (index starting at 1)

Type Details
path str Path to the file to modify
start_line int Starting line number to replace (1-based indexing)
end_line int Ending line number to replace (1-based indexing, inclusive)
new_content str New content to replace the specified lines
replace_lines('test.txt', 1, 2, 'Replaced first two lines')
print(view('test.txt', nums=True))
     1 │ Replaced first two lines
     2 │ Nice to see you.
f.unlink()