from fastcore import toolsdialoghelper
Re-export asdict:
find_var
find_var (var:str)
Search for var in all frames of the call stack
a = 1
find_var('a')1
call_endp
call_endp (path, dname='', json=False, raiseex=False, **data)
find_dname
find_dname ()
*Get the message id by searching the call stack for __dialog_id.*
find_msg_id
find_msg_id ()
*Get the message id by searching the call stack for __dialog_id.*
find_msg_id()'_9cbd170d'
curr_dialog
curr_dialog (with_messages:bool=False, dname:str='')
Get the current dialog info.
| Type | Default | Details | |
|---|---|---|---|
| with_messages | bool | False | Include messages as well? |
| dname | str | Running dialog to get info for; defaults to current dialog |
find_msgs
find_msgs (re_pattern:str='', msg_type:str=None, limit:int=None, include_output:bool=True, dname:str='')
Find list[dict] of messages in current specific dialog that contain the given information. To refer to a message found later, use its id field.
| Type | Default | Details | |
|---|---|---|---|
| re_pattern | str | Optional regex to search for (re.DOTALL+re.MULTILINE is used) | |
| msg_type | str | None | optional limit by message type (‘code’, ‘note’, or ‘prompt’) |
| limit | int | None | Optionally limit number of returned items |
| include_output | bool | True | Include output in returned dict? |
| dname | str | Running dialog to get info for; defaults to current dialog |
# NB: must have a dialogue open including a message with this text in its content
txt = 'tools'
found = find_msgs(txt)
found[0]['content']'from fastcore import tools'
msg_idx
msg_idx (msgid=None, dname:str='')
Get absolute index of message in dialog.
| Type | Default | Details | |
|---|---|---|---|
| msgid | NoneType | None | Message id to find (defaults to current message) |
| dname | str | Running dialog to get info for; defaults to current dialog |
msg_idx()16
add_html
add_html (content:str, dname:str='')
Send HTML to the browser to be swapped into the DOM
| Type | Default | Details | |
|---|---|---|---|
| content | str | The HTML to send to the client (generally should include hx-swap-oob) | |
| dname | str | Running dialog to get info for; defaults to current dialog |
from fasthtml.common import *add_html(Div(P('Hi'), hx_swap_oob='beforeend:#dialog-container'))add_msg
add_msg (content:str, placement:str='add_after', msgid:str=None, msg_type:str='note', output:str='', time_run:str|None='', is_exported:int|None=0, skipped:int|None=0, i_collapsed:int|None=0, o_collapsed:int|None=0, heading_collapsed:int|None=0, pinned:int|None=0, dname:str='')
Add/update a message to the queue to show after code execution completes.
| Type | Default | Details | |
|---|---|---|---|
| content | str | Content of the message (i.e the message prompt, code, or note text) | |
| placement | str | add_after | Can be ‘add_after’, ‘add_before’, ‘at_start’, ‘at_end’ |
| msgid | str | None | id of message that placement is relative to (if None, uses current message) |
| msg_type | str | note | Message type, can be ‘code’, ‘note’, or ‘prompt’ |
| output | str | For prompts/code, initial output | |
| time_run | str | None | When was message executed | |
| is_exported | int | None | 0 | Export message to a module? |
| skipped | int | None | 0 | Hide message from prompt? |
| i_collapsed | int | None | 0 | Collapse input? |
| o_collapsed | int | None | 0 | Collapse output? |
| heading_collapsed | int | None | 0 | Collapse heading section? |
| pinned | int | None | 0 | Pin to context? |
| dname | str | Running dialog to get info for; defaults to current dialog |
_id = add_msg('testing')del_msg
del_msg (msgid:str=None, dname:str='')
Delete a message from the dialog.
| Type | Default | Details | |
|---|---|---|---|
| msgid | str | None | id of message to delete |
| dname | str | Running dialog to get info for; defaults to current dialog |
del_msg(_id)_id = _add_msg_unsafe('1+1', run=True, msg_type='code')del_msg(_id)_id = _add_msg_unsafe('Hi', run=True, msg_type='prompt')del_msg(_id)update_msg
update_msg (msgid:str=None, msg:Optional[Dict]=None, dname:str='', content:str|None=None, msg_type:str|None=None, output:str|None=None, time_run:str|None=None, is_exported:int|None=None, skipped:int|None=None, i_collapsed:int|None=None, o_collapsed:int|None=None, heading_collapsed:int|None=None, pinned:int|None=None)
Update an existing message. Provide either msg OR field key/values to update. Use content param to update contents. Only include parameters to update–missing ones will be left unchanged.
| Type | Default | Details | |
|---|---|---|---|
| msgid | str | None | id of message to update (if None, uses current message) |
| msg | Optional | None | Dictionary of field keys/values to update |
| dname | str | Running dialog to get info for; defaults to current dialog | |
| content | str | None | None | Content of the message (i.e the message prompt, code, or note text) |
| msg_type | str | None | None | Message type, can be ‘code’, ‘note’, or ‘prompt’ |
| output | str | None | None | For prompts/code, the output |
| time_run | str | None | None | When was message executed |
| is_exported | int | None | None | Export message to a module? |
| skipped | int | None | None | Hide message from prompt? |
| i_collapsed | int | None | None | Collapse input? |
| o_collapsed | int | None | None | Collapse output? |
| heading_collapsed | int | None | None | Collapse heading section? |
| pinned | int | None | None | Pin to context? |
_id = add_msg('testing')_id = update_msg(_id, content='toasting')_id = update_msg(_id, skipped=1)del_msg(_id)url2note
url2note (url:str, extract_section:bool=True, selector:str=None)
Read URL as markdown, and add a note below current message with the result
| Type | Default | Details | |
|---|---|---|---|
| url | str | URL to read | |
| extract_section | bool | True | If url has an anchor, return only that section |
| selector | str | None | Select section(s) using BeautifulSoup.select (overrides extract_section) |
_id = url2note('https://www.example.org')del_msg(_id)ast_py
ast_py (code:str)
Get an SgRoot root node for python code
node = ast_py("print('hello world')")
stmt = node.find(pattern="print($A)")
res = stmt.get_match('A')
res.text(),res.range()("'hello world'",
Range(start=Pos(line=0, col=6, index=6), end=Pos(line=0, col=19, index=19)))
ast_grep
ast_grep (pattern:str, path='.', lang='python')
Use the ast-grep command to find pattern in path
| Type | Default | Details | |
|---|---|---|---|
| pattern | str | ast-grep pattern to search | |
| path | str | . | path to recursively search for files |
| lang | str | python | language to search/scan |
res = ast_grep(r"xpost($A, data=$B)", '..')
[(o['text'],o['metaVariables']['single'],o['file']) for o in res][("xpost(f'http://localhost:5001/{path}', data=data)",
{'A': {'text': "f'http://localhost:5001/{path}'",
'range': {'byteOffset': {'start': 1651, 'end': 1682},
'start': {'line': 43, 'column': 16},
'end': {'line': 43, 'column': 47}}},
'B': {'text': 'data',
'range': {'byteOffset': {'start': 1689, 'end': 1693},
'start': {'line': 43, 'column': 54},
'end': {'line': 43, 'column': 58}}}},
'dialoghelper/core.py')]
read_msg
read_msg (n:int=-1, relative:bool=True, msgid:str=None, view_range:list[int,int]=None, nums:bool=False, dname:str='')
Get the Message object indexed in the current dialog.
| Type | Default | Details | |
|---|---|---|---|
| n | int | -1 | Message index (if relative, +ve is downwards) |
| relative | bool | True | Is n relative to current message (True) or absolute (False)? |
| msgid | str | None | Message id to find (defaults to current message) |
| view_range | list | None | Optional 1-indexed (start, end) line range for files, end=-1 for EOF |
| nums | bool | False | Whether to show line numbers |
| dname | str | Running dialog to get info for; defaults to current dialog |
_edit_id = add_msg('This message should be found.\n\nThis is a multiline message.')print(read_msg()['msg']['content'])This message should be found.
This is a multiline message.
print(read_msg(n=0, msgid=_edit_id, nums=True)['msg']['content']) 1 │ This message should be found.
2 │
3 │ This is a multiline message.
print(read_msg(n=0, msgid=_edit_id, nums=True, view_range=[2,3])['msg']['content']) 2 │
3 │ This is a multiline message.
run_msg
run_msg (msgid:str=None, dname:str='')
Adds a message to the run queue. Use read_msg to see the output once it runs.
| Type | Default | Details | |
|---|---|---|---|
| msgid | str | None | id of message to execute |
| dname | str | Running dialog to get info for; defaults to current dialog |
1+12
codeid = read_msg()['msg']['id']run_msg(codeid)'{"status":"queued"}'
Text Edit
msg_insert_line
msg_insert_line (msgid:str, insert_line:int, new_str:str, dname:str='')
Insert text at a specific line number in a message
| Type | Default | Details | |
|---|---|---|---|
| msgid | str | Message id to edit | |
| insert_line | int | The line number after which to insert the text (0 for beginning of file) | |
| new_str | str | The text to insert | |
| dname | str | Running dialog to get info for; defaults to current dialog |
msg_insert_line(_edit_id, 0, 'This should go to the first line')
msg_insert_line(_edit_id, 3, 'This should go to the 4th line')
msg_insert_line(_edit_id, 5, 'This should go to the last line'){'success': 'Inserted text after line 5 in message _c3e8e7f8'}
print(read_msg(n=0, msgid=_edit_id, nums=True)['msg']['content']) 1 │ This should go to the first line
2 │ This message should be found.
3 │
4 │ This should go to the 4th line
5 │ This is a multiline message.
6 │ This should go to the last line
msg_str_replace
msg_str_replace (msgid:str, old_str:str, new_str:str, dname:str='')
Replace first occurrence of old_str with new_str in a message
| Type | Default | Details | |
|---|---|---|---|
| msgid | str | Message id to edit | |
| old_str | str | Text to find and replace | |
| new_str | str | Text to replace with | |
| dname | str | Running dialog to get info for; defaults to current dialog |
msg_str_replace(_edit_id, 'This should go to the first line', 'This should go to the 1st line'){'success': 'Replaced text in message _c3e8e7f8'}
print(read_msg(n=0, msgid=_edit_id, nums=True)['msg']['content']) 1 │ This should go to the 1st line
2 │ This message should be found.
3 │
4 │ This should go to the 4th line
5 │ This is a multiline message.
6 │ This should go to the last line
msg_strs_replace
msg_strs_replace (msgid:str, old_strs:list[str], new_strs:list[str], dname:str='')
Replace multiple strings simultaneously in a message
| Type | Default | Details | |
|---|---|---|---|
| msgid | str | Message id to edit | |
| old_strs | list | List of strings to find and replace | |
| new_strs | list | List of replacement strings (must match length of old_strs) | |
| dname | str | Running dialog to get info for; defaults to current dialog |
msg_strs_replace(_edit_id, ['This is a multiline message.', 'This should go to the last line'], ['5th line', 'last line']){'success': 'Successfully replaced all the strings in message _c3e8e7f8'}
print(read_msg(n=0, msgid=_edit_id, nums=True)['msg']['content']) 1 │ This should go to the 1st line
2 │ This message should be found.
3 │
4 │ This should go to the 4th line
5 │ 5th line
6 │ last line
msg_replace_lines
msg_replace_lines (msgid:str, start_line:int, end_line:int, new_content:str, dname:str='')
Replace a range of lines with new content in a message
| Type | Default | Details | |
|---|---|---|---|
| msgid | str | Message id to edit | |
| 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 | |
| dname | str | Running dialog to get info for; defaults to current dialog |
msg_replace_lines(_edit_id, 2, 4,'line 2\nline 3\nline 4\n'){'success': 'Replaced lines 2 to 4 in message _c3e8e7f8'}
print(read_msg(n=0, msgid=_edit_id, nums=True)['msg']['content']) 1 │ This should go to the 1st line
2 │ line 2
3 │ line 3
4 │ line 4
5 │ 5th line
6 │ last line
del_msg(_edit_id)Gists
load_gist
load_gist (gist_id:str)
Retrieve a gist
gistid = 'jph00/e7cfd4ded593e8ef6217e78a0131960c'
gist = load_gist(gistid)
gist.html_urlgist_file
gist_file (gist_id:str)
Get the first file from a gist
gfile = gist_file(gistid)
print(gfile.content[:100]+"…")import_string
import_string (code:str, name:str)
| Type | Details | |
|---|---|---|
| code | str | Code to import as a module |
| name | str | Name of module to create |
is_usable_tool
is_usable_tool (func:<built-infunctioncallable>)
True if the function has a docstring and all parameters have types, meaning that it can be used as an LLM tool.
def hi(who:str):
"Say hi to `who`"
return f"Hello {who}"
def hi2(who):
"Say hi to `who`"
return f"Hello {who}"
def hi3(who:str):
return f"Hello {who}"
bye = "bye"assert is_usable_tool(hi)
assert not is_usable_tool(hi2)
assert not is_usable_tool(hi3)
assert not is_usable_tool(bye)mk_toollist
mk_toollist (syms)
Markdown(mk_toollist([hi]))import_gist
import_gist (gist_id:str, mod_name:str=None, add_global:bool=True, import_wildcard:bool=False, create_msg:bool=False)
Import gist directly from string without saving to disk
| Type | Default | Details | |
|---|---|---|---|
| gist_id | str | user/id or just id of gist to import as a module | |
| mod_name | str | None | module name to create (taken from gist filename if not passed) |
| add_global | bool | True | add module to caller’s globals? |
| import_wildcard | bool | False | import all exported symbols to caller’s globals |
| create_msg | bool | False | Add a message that lists usable tools |
import_gist(gistid)
importtest.testfooimport_gist.__doc__import_gist(gistid, import_wildcard=True)
importtest.testfoohi("Sarah")importtest.__all__Tool info
This is how we get a superset of tools to include:
tool_info
tool_info ()
for o in _all:
s = globals()[o]
if s.__name__[0]=='_' or not s.__doc__: continue
print(f'- &`{s.__name__}`: {s.__doc__}')fc_tool_info
fc_tool_info ()
for o in tools.__all__:
s = getattr(tools, o)
print(f'- &`{s.__name__}`: {s.__doc__}')