dialoghelper

from fastcore import tools

source

add_styles

 add_styles (s:str, cls_map:dict=None)

Add solveit styles to s

import mistletoe
from fasthtml.common import show
s = mistletoe.markdown("### hi\n\n- first\n- *second*")
s
'<h3>hi</h3>\n<ul>\n<li>first</li>\n<li><em>second</em></li>\n</ul>\n'
show(s)

hi

  • first
  • second
show(add_styles(s))

hi

  • first
  • second

Basics


source

set_var

 set_var (var:str, val)

Set var to val after finding it in all frames of the call stack


source

find_var

 find_var (var:str)

Search for var in all frames of the call stack

a = 1
find_var('a')
1
set_var('a', 42)
a
42

source

call_endp

 call_endp (path, dname='', json=False, raiseex=False, **data)

source

find_dname

 find_dname ()

*Get the message id by searching the call stack for __dialog_id.*


source

find_msg_id

 find_msg_id ()

*Get the message id by searching the call stack for __dialog_id.*

find_msg_id()
'_9cbd170d'

source

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

source

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()
19

View/edit dialog


source

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'

source

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'))

source

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 indexed in the current dialog. - To get the exact message use n=0 and relative=True together with msgid. - To get a relative message use n (relative position index). - To get the nth message use n with relative=False, e.g n=0 first message, n=-1 last message.

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

source

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
print(__msg_id)
_id = add_msg('testing')
print(__msg_id)
_9c544573
_2ee79b12

source

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)

source

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)
_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.

source

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+1
2
codeid = read_msg()['msg']['id']
run_msg(codeid)
'{"status":"queued"}'

source

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)

source

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)))

source

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('http://localhost:5001/pop_data_blocking_', data={'data_id': idx})",
  {'B': {'text': "{'data_id': idx}",
    'range': {'byteOffset': {'start': 1185, 'end': 1201},
     'start': {'line': 38, 'column': 72},
     'end': {'line': 38, 'column': 88}}},
   'A': {'text': "'http://localhost:5001/pop_data_blocking_'",
    'range': {'byteOffset': {'start': 1136, 'end': 1178},
     'start': {'line': 38, 'column': 23},
     'end': {'line': 38, 'column': 65}}}},
  'dialoghelper/experimental.py'),
 ('xpost(f\'http://localhost:{dh_settings["port"]}/{path}\', data=data)',
  {'A': {'text': 'f\'http://localhost:{dh_settings["port"]}/{path}\'',
    'range': {'byteOffset': {'start': 2624, 'end': 2672},
     'start': {'line': 70, 'column': 16},
     'end': {'line': 70, 'column': 64}}},
   'B': {'text': 'data',
    'range': {'byteOffset': {'start': 2679, 'end': 2683},
     'start': {'line': 70, 'column': 71},
     'end': {'line': 70, 'column': 75}}}},
  'dialoghelper/core.py')]

Text Edit


source

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 _c3581eea'}
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

source

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 _c3581eea'}
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

source

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 _c3581eea'}
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

source

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 _c3581eea'}
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


source

load_gist

 load_gist (gist_id:str)

Retrieve a gist

gistid = 'jph00/e7cfd4ded593e8ef6217e78a0131960c'
gist = load_gist(gistid)
gist.html_url
'https://gist.github.com/jph00/e7cfd4ded593e8ef6217e78a0131960c'

source

gist_file

 gist_file (gist_id:str)

Get the first file from a gist

gfile = gist_file(gistid)
print(gfile.content[:100]+"…")
"This is a test module which makes some simple tools available."
__all__ = ["hi","whoami"]

testfoo=…

source

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

source

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)

source

mk_toollist

 mk_toollist (syms)
Markdown(mk_toollist([hi]))
  • &hi: Say hi to who

source

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.testfoo
'testbar'
import_gist.__doc__
'Import gist directly from string without saving to disk'
import_gist(gistid, import_wildcard=True)
importtest.testfoo
'testbar'
hi("Sarah")
'Hello Sarah'
importtest.__all__
['hi', 'whoami']

Tool info

from dialoghelper.core import __all__ as _all

This is how we get a superset of tools to include:


source

tool_info

 tool_info ()

source

fc_tool_info

 fc_tool_info ()
for o in _all:
    s = globals()[o]
    if not hasattr(s, '__name__') or s.__name__[0]=='_' or not s.__doc__: continue
    print(f'- &`{s.__name__}`: {s.__doc__}')
- &`add_styles`: Add solveit styles to `s`
- &`find_var`: Search for var in all frames of the call stack
- &`set_var`: Set var to val after finding it in all frames of the call stack
- &`find_dname`: Get the message id by searching the call stack for __dialog_id.
- &`find_msg_id`: Get the message id by searching the call stack for __dialog_id.
- &`curr_dialog`: Get the current dialog info.
- &`msg_idx`: Get absolute index of message in dialog.
- &`find_msgs`: 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.
- &`add_html`: Send HTML to the browser to be swapped into the DOM
- &`read_msg`: Get the message indexed in the current dialog.
    - To get the exact message use `n=0` and `relative=True` together with `msgid`.
    - To get a relative message use `n` (relative position index).
    - To get the nth message use `n` with `relative=False`, e.g `n=0` first message, `n=-1` last message.
- &`add_msg`: Add/update a message to the queue to show after code execution completes.
- &`del_msg`: Delete a message from the dialog.
- &`update_msg`: 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.
- &`run_msg`: Adds a message to the run queue. Use read_msg to see the output once it runs.
- &`url2note`: Read URL as markdown, and add a note below current message with the result
- &`ast_py`: Get an SgRoot root node for python `code`
- &`ast_grep`: Use the `ast-grep` command to find `pattern` in `path`
- &`msg_insert_line`: Insert text at a specific line number in a message
- &`msg_str_replace`: Replace first occurrence of old_str with new_str in a message
- &`msg_strs_replace`: Replace multiple strings simultaneously in a message
- &`msg_replace_lines`: Replace a range of lines with new content in a message
- &`load_gist`: Retrieve a gist
- &`gist_file`: Get the first file from a gist
- &`is_usable_tool`: True if the function has a docstring and all parameters have types, meaning that it can be used as an LLM tool.
- &`import_gist`: Import gist directly from string without saving to disk
for o in tools.__all__:
    s = getattr(tools, o)
    print(f'- &`{s.__name__}`: {s.__doc__}')
- &`run_cmd`: Run `cmd` passing split `argstr`, optionally checking for allowed argstr
- &`rg`: Run the `rg` command with the args in `argstr` (no need to backslash escape)
- &`sed`: Run the `sed` command with the args in `argstr` (e.g for reading a section of a file)
- &`view`: View directory or file contents with optional line range and numbers
- &`create`: Creates a new file with the given content at the specified path
- &`insert`: Insert new_str at specified line number
- &`str_replace`: Replace first occurrence of old_str with new_str in file
- &`strs_replace`: Replace for each str pair in old_strs,new_strs
- &`replace_lines`: Replace lines in file using start and end line-numbers (index starting at 1)