def calc_div(a:int,b:int):
"Divides a/b - example tool"
try: return a/b
except: return explain_exc("dividing")
calc_div(1,0)'Error: division by zero'
Convert an current exception to an LLM friendly error message.
'Error: division by zero'
Works like assert b, msg but raise ValueError and is not disabled when run with python -O
'Error: B cannot be zero'
Return expanded/resolved Path, raising FileNotFoundError if must_exist and missing
You can add valid paths here:
def run_cmd(
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
):
Run cmd passing split argstr, optionally checking for allowed argstr
With this little function, we can now run any cli command:
aai-ws
Applications
books
cachy.jsonl
chats
CRAFT.ipynb
CRAFT.py
CRAFTs
Note that, for tool safety, this is not passed through the shell, so wildcards, env vars, etc will not work (although ~ will):
Let’s create some useful functions from this that will allow for searching, reading and modifing content on the file system.
def rg(
argstr:str, # All args to the command, will be split with shlex. No shell escaping needed for regex chars like `|`
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
):
Run the rg command with the args in argstr
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'
NB: These tools have special behavior around errors. Since these have been speficially designed for work with LLMs, any exceptions created from their use is returned as a string to help them debug their work.
def sed(
argstr:str, # All args to the command, will be split with shlex. No shell escaping needed for regex chars like `|`
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
):
Run the sed command with the args in argstr (e.g for reading a section of a file)
project:
type: website
pre-render:
- pysym2md --output_file apilist.txt fastcore
post-render:
Python implementations of the text editor tools from Anthropic, plus more. These tools are especially useful in an AI’s tool loop. See claudette for examples.
def view(
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. Do NOT use unless it's known that the file is too big to keep in context—simply view the WHOLE file when possible
nums:bool=False, # Whether to show line numbers
skip_folders:tuple=('_proc', '__pycache__'), # Folder names to skip when listing directories
):
View directory or file contents with optional line range and numbers
You can specify line ranges and whether to have the output contain line numbers:
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:
Directory contents of /path:
/path/llms.txt (3.7k)
/path/000_tour.ipynb (18.2k)
/path/parallel_test.py (0.6k)
/path/_quarto.yml (0.8k)
/path/08_style.ipynb (12.3k)
Creates a new file with the given content at the specified path
Created file /path/test.txt.
Contents:
1 │ Hello, world!
Insert new_str at specified line number
1 │ Let's add a new line
2 │ Hello, world!
Replace first occurrence of old_str with new_str in file
Replaced text in /Users/jhoward/aai-ws/fastcore/nbs/test.txt
1 │ Let's add a new line:
2 │ Hello, world!
Replace for each str pair in old_strs,new_strs
Results for each replacement:
Replaced text in /Users/jhoward/aai-ws/fastcore/nbs/test.txt; Replaced text in /Users/jhoward/aai-ws/fastcore/nbs/test.txt
1 │ Let's just say:
2 │ Hello, friends!
3 │ Nice to see you.
Results for each replacement:
Error: Text "a missing" not found in file; Error: Text "and shoul…" not found in file
1 │ Let's just say:
2 │ Hello, friends!
3 │ Nice to see you.
Replace lines in file using start and end line-numbers (index starting at 1)
1 │ Replaced first two lines
2 │ Nice to see you.
'Error: File not found: /path/missing.txt'
Move lines from start_line:end_line to before dest_line
The move_lines function relocates a range of lines within a file to a new position. It handles the tricky index adjustment when the destination is after the removed chunk.
Let’s test it by creating a simple 5-line file:
1 │ Line 1
2 │ Line 2
3 │ Line 3
4 │ Line 4
5 │ Line 5
Move lines 4-5 up to before line 2:
Moved lines 4-5 to line 2
1 │ Line 1
2 │ Line 4
3 │ Line 5
4 │ Line 2
5 │ Line 3
Move lines down — moving lines 1-2 to the end (line 6) correctly adjusts the destination index after removal:
Moved lines 1-2 to line 4
1 │ Line 5
2 │ Line 2
3 │ Line 3
4 │ Line 1
5 │ Line 4
Error handling — destination within source range, invalid line ranges, and invalid destinations are all caught:
Error: Destination within source range
Error: Invalid range 10-12
Error: Invalid destination 99
Error: File not found: /path/mising.txt
Return callable objects defined in caller’s module