from dialoghelper import *dialoghelper
from fastcore import tools
from fastcore.test import *Basics
a = 1
find_var('a')1
11
names_containing
def names_containing(
s:str
):
Names containing s in IPython user namespace, or caller globals
names_containing('ipython')['get_ipython', 'load_ipython_extension', 'ipython_shell', 'in_ipython']
find_dname
def find_dname(
dname:NoneType=None, required:bool=True
):
*Get the dialog name by searching the call stack for __dialog_name, and resolving dname if supplied.*
find_dname()'/aai-ws/dialoghelper/nbs/00_core'
async def repro_executor():
return await asyncio.get_event_loop().run_in_executor(None, find_dname)
await repro_executor()'/aai-ws/dialoghelper/nbs/00_core'
find_dname('index')'/aai-ws/dialoghelper/nbs/index'
find_dname('../index')'/aai-ws/dialoghelper/index'
find_dname('/foo/bar')'/foo/bar'
call_endpa
async def call_endpa(
path, dname:str='', json:bool=False, raiseex:bool=False, id:NoneType=None, required:bool=True, timeout:int=10,
data:VAR_KEYWORD
):
Call self as a function.
call_endp
def call_endp(
path, dname:str='', json:bool=False, raiseex:bool=False, id:NoneType=None, required:bool=True, timeout:int=10,
data:VAR_KEYWORD
):
Call self as a function.
curr_dialog
async def curr_dialog(
with_messages:bool=False, # Include messages as well?
dname:str='', # Dialog to get info for; defaults to current dialog
)->dict | str:
Get the current dialog info.
msg_idx
async def msg_idx(
id:str=None, # Message id to find (defaults to current message)
dname:str='', # Dialog to get message index from; defaults to current dialog
)->int:
Get absolute index of message in dialog.
await msg_idx()26
add_html
def add_html(
content:str, # The HTML to send to the client (generally should include hx-swap-oob)
dname:str='', # Dialog to get info for; defaults to current dialog
):
Send HTML to the browser to be swapped into the DOM
add_html_a
async def add_html_a(
content:str, # The HTML to send to the client (generally should include hx-swap-oob)
dname:str='', # Dialog to get info for; defaults to current dialog
):
Send HTML to the browser to be swapped into the DOM
from fasthtml.common import *add_html(Div(P('Hi'), hx_swap_oob='beforeend:#dialog-container')){'success': 'Content added to DOM'}
add_scr
def add_scr(
scr, oob:str='innerHTML:#ephemeral'
):
Swap a script element to the end of the ephemeral element
add_scr_a
async def add_scr_a(
scr, oob:str='innerHTML:#ephemeral'
):
Swap a script element to the end of the ephemeral element
add_mod_a
async def add_mod_a(
s:str
):
Wrap javascript code string in a js script module and add it via add_html
add_mod
def add_mod(
s:str
):
Wrap javascript code string in a js script module and add it via add_html
iife
def iife(
code:str
):
Wrap javascript code string in an IIFE and execute it via add_html
iife_a
async def iife_a(
code:str
):
Wrap javascript code string in an IIFE and execute it via add_html
event_get
def event_get(
evt:str, timeout:int=15, data:VAR_KEYWORD
):
Call fire_event and then pop_data to get a response
event_get_a
async def event_get_a(
evt:str, timeout:int=15, data:VAR_KEYWORD
):
Call fire_event and then pop_data to get a response
trigger_now
def trigger_now(
evt, data:NoneType=None, ttl:int=5000
):
Synchronously trigger a browser event, safe against replay
event_once_a
async def event_once_a(
evt, timeout:int=15, ttl:int=5000, data:VAR_KEYWORD
):
Like event_get_a but with replay/dedup safety via trigger_now
event_once
def event_once(
evt, timeout:int=15, ttl:int=5000, data:VAR_KEYWORD
):
Like event_get but with replay/dedup safety via trigger_now
iife("$('body').one('test_evt', e => pushData(e.detail.idx, {reply: 'it worked!'}));")
event_once('test_evt', data={'hello': 'world'}){'data_id': '1727d927-09f3-4786-9b54-eca2ba13d455', 'reply': 'it worked!'}js_run_a
async def js_run_a(
code
):
Run JS code that calls done() when finished, and wait for result
js_run("fetch('/curr_dialog_', {method:'POST'}).then(r => r.json()).then(done)"){ 'data_id': 'f666f868-289c-4a97-9e1b-ebf3d0a5a241',
'error': 'No active dialog',
'ready': True}js_eval_a
async def js_eval_a(
expr
):
Evaluate a JS expression in the browser and return the result
js_eval("return {width: window.innerWidth}"){'data_id': 'b3f5fb2a-1254-46da-ba76-a1a1b0139241', 'result': {'width': 1449}}js_eval("return document.querySelectorAll('.msg').length"){'data_id': 'f270c22b-1770-4839-ba27-1c6ceaff082b', 'result': 0}js_eval("a=1")
js_eval("return a+1"){'data_id': 'b5d78510-5da2-4b89-a7a3-84d91ffaf0a7', 'result': 2}await js_eval_a("return (await fetch('/curr_dialog_', {method:'POST'})).json()"){ 'data_id': 'bdf67a98-88ec-4968-b96a-e3c3a209375d',
'result': {'error': 'No active dialog'}}display_response
def display_response(
display:str, result:str=None
):
Return a special response where display is added as markdown/HTML to the prompt output, and result is returned to the LLM
connfiles
async def connfiles(
dlg_name:str='', # Name of dialog to get connfile path for; if empty, return dict of all running dialogs with their paths
):
Get a running dialogs’ connection file path (or dict of all of them if no dlg_name.
realpath
async def realpath(
subpath:str='/', # Path under data root (absolute with `/`, else relative to current dialog's folder)
)->str:
Get the real on-disk path to solveit subpath. ‘/’ gets on-disk base path.
await realpath()
await realpath() # run twice to check acache works'/Users/jhoward'
list_dialogs
async def list_dialogs(
subpath:str='', # Path under data root (absolute with `/`, else relative to current dialog's folder)
depth:int=1, # Directory depth
)->dict:
List dialogs and folders under subpath. Folders have / suffix.
(await list_dialogs())['items'][-4:]['05_solve_auth', '06_utils', 'data/', 'index']
(await list_dialogs('/'))['items'][:5]['Applications/', 'CRAFT', 'CRAFTs/', 'Desktop/', 'Documents/']
View/edit dialog
read_msg
async def read_msg(
n:int=-1, # Message index (if relative, +ve is downwards)
relative:bool=True, # Is `n` relative to current message (True) or absolute (False)?
id: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='', # Dialog to get info for; defaults to current dialog
)->dict:
Get the message indexed in the current dialog. NB: Messages in the current dialog above the current message are already visible; use this only when you need line numbers for editing operations, or for messages not in the current dialog or below the current message. - To get the exact message use n=0 and relative=True together with id. - 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. {dname}
find_msgs
async def find_msgs(
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')
before:int=0, # Include additional n msgs before matches
after:int=0, # Include additional n msgs before matches
context:int=0, # Include additional n msgs around matches (recommended: set `context=2` when searching to see ipynb context)
use_case:bool=False, # Use case-sensitive matching?
use_regex:bool=True, # Use regex matching?
only_err:bool=False, # Only return messages that have errors?
only_exp:bool=False, # Only return messages that are exported?
only_chg:bool=False, # Only return messages that have changed vs git HEAD?
ids:str='', # Optionally filter by comma-separated list of message ids
limit:int=None, # Optionally limit number of returned items
include_output:bool=True, # Include output in returned dict?
include_meta:bool=True, # Include all additional message metadata
as_xml:bool=False, # Use concise unescaped XML output format
nums:bool=False, # Show line numbers?
trunc_out:bool=False, # Middle-out truncate code output to 100 characters?
trunc_in:bool=False, # Middle-out truncate cell content to 80 characters?
headers_only:bool=False, # Only return note messages that are headers (first line only); cannot be used together with `header_section`
header_section:str=None, # Find section starting with this header; returns it plus all children
include_skipped:bool=False, # Include messages hidden from AI (skipped)?
dname:str='', # Dialog to get info for; defaults to current dialog
)->list: # Messages in requested dialog that contain the given information
Often it is more efficient to call view_dlg (not find_msgs) to see the whole dialog, so you can use it all from then on. {dname} Message ids are identical to those in LLM chat history, so do NOT call this to view a specific message if it’s in the chat history–instead use view_msg. Do NOT use find_msgs to view message content in the current dialog above the current prompt – these are already provided in LLM context, so just read the content there directly. (NB: LLM context only includes messages above the current prompt, whereas find_msgs can access all messages.) To refer to a found message from code, use its id field.
1+12
r = await find_msgs(r'1\+1', include_meta=False, include_output=True)
r[{'id': '_8ce548d6', 'is_exported': 0, 'content': '1+1', 'output': '2', 'msg_type': 'code'}, {'id': '_372c363d', 'is_exported': 0, 'content': "_id = await add_msg('1+1', run=True, msg_type='code')", 'output': '', 'msg_type': 'code'}]
hl_md(await find_msgs(r'1\+1', include_meta=False, as_xml=True))<msgs><code id="_8ce548d6"><source>1+1<out>2</out></code><code id="_372c363d">_id = await add_msg('1+1', run=True, msg_type='code')</code></msgs>view_dlg
async def view_dlg(
dname:str='', # Dialog to get info for; defaults to current dialog
msg_type:str=None, # optional limit by message type ('code', 'note', or 'prompt')
nums:bool=False, # Whether to show line numbers
include_output:bool=False, # Include output in returned dict?
trunc_out:bool=True, # Middle-out truncate code output to 100 characters (only applies if `include_output`)?
trunc_in:bool=False, # Middle-out truncate cell content to 80 characters?
include_skipped:bool=False, # Include messages hidden from AI (skipped)?
)->str:
Concise XML view of all messages (optionally filtered by type), not including metadata. Often it is more efficient to call this to see the whole dialog at once (including line numbers if needed), instead of running find_msgs or view_msg multiple times.
hl_md((await view_dlg(nums=True))[:500])<msgs><code id="_955b9784"> 1 │ #| default_exp core</code><code id="_a982e24d"> 1 │ from dialoghelper import *</code><note id="_0aafe008"> 1 │ # dialoghelper</note><code id="_4dd4b925" export> 1 │ import os,re,inspect,ast,collections,time,asyncio,json,linecache,importlib,difflib,uuid,builtins,subprocess
2 │
3 │ from typing import Dict
4 │ from tempfile import TemporaryDirectory
5 │ from ipykernel_helper import *
6 │ from dataclasses import dataclass
add_msg
async def add_msg(
content:str, # Content of the message (i.e the message prompt, code, or note text)
msg_type:str='note', # Message type, can be 'code', 'note', or 'prompt'
run:bool=False, # Run the message?
placement:str='', # Location to place message. Can be 'at_start' or 'at_end', and if id provided or in curr dlg can also be 'add_after' or 'add_before'. Defaults to 'at_end' if no id and not targeting curr dlg
id:str=None, # id of message that placement is relative to (if None, uses current message)
dname:str='', # Dialog to add to; defaults to current dialog (`run` only has a effect if dialog is currently running)
wait:bool=False, # Wait for and return response? (if `run`)
poll:float=0.5, # Frequency of polling to check for completion (if `wait`)
output:str='', # Prompt/code output; Code outputs must be .ipynb-compatible JSON array
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?
)->str: # Message ID of newly created message
Add/update a message to the queue to show after code execution completes, and optionally run it. Code messages are run using python’s restricted sandbox. NB: when creating multiple messages in a row, after the 1st message set id to the result of the last add_msg call, otherwise messages will appear in the dialog in REVERSE order. {dname}
_id = await add_msg('testing')
_id'_ea1cf315'
read_msgid
async def read_msgid(
id:str, # Message id to find
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='', # Dialog to get message from; defaults to current dialog
add_to_dlg:bool=False, # Whether to add message content to current dialog (as a raw message)
)->dict:
Get message id. Message IDs can be view directly in LLM chat history/context, or found in find_msgs results. Use add_to_dlg if the LLM or human may need to refer to the message content again later.
r = await read_msg(-2)
print((await read_msg(-2)).content)testing
read_msg (and all endpoints that return json) wrap responses in dict2obj, so you can use either dict or object syntax.
bmsg = await add_msg('at bottom', placement='at_end')assert(await msg_idx(bmsg)>await msg_idx(_id)+10)view_msg
async def view_msg(
id:str, # Message id to view
dname:str='', # Dialog to get message from; defaults to current dialog
nums:bool=True, # Whether to show line numbers
view_range:list=None, # Optional 1-indexed (start, end) line range for files, end=-1 for EOF. Rarely needed--read whole message in nearly all cases instead
add_to_dlg:bool=False, # Whether to add message content to current dialog (as a raw message)
)->str:
Views the content* of message id. Same as read_msgid(...)['content'], defaulting to nums=True.* Use add_to_dlg if the LLM or human may need to refer to the message content again later.
print((await view_msg(r.id))) 1 │ testing
# dh_settings['dname'] = 'tmp'
# _id = await add_msg('testing', placement='at_end')
# print(_id)
# del(dh_settings['dname'])msg_ref
def msg_ref(
id, dname:NoneType=None
):
Markdown ref to a message — same-dialog #id or cross-dialog #dname/id
del_msg
async def del_msg(
id:str=None, # id of message to delete
dname:str='', # Dialog to get info for; defaults to current dialog
log_changed:bool=False, # Add a note showing the deleted content?
)->dict:
Delete a message from the dialog. DO NOT USE THIS unless you have been explicitly instructed to delete messages.
await del_msg(bmsg)
await del_msg(_id){'status': 'success'}
_id = await add_msg('1+1', run=True, msg_type='code')await del_msg(_id){'status': 'success'}
_id = await add_msg('Hi', run=True, msg_type='prompt')await del_msg(_id){'status': 'success'}
run_and_prompt
async def run_and_prompt(
code:str, # Python code to run
prompt:str='Continue.', # Prompt to add after code execution
)->str:
Run code and then run prompt, returning the resulting message ID.
update_msg
async def update_msg(
id:str=None, # id of message to update (if None, uses current message)
msg:Optional=None, # Dictionary of field keys/values to update
dname:str='', # Dialog to get info for; defaults to current dialog
log_changed:bool=False, # Add a note showing the diff?
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, # Prompt/code output; Code outputs must be .ipynb-compatible JSON array
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?
)->str:
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. {dname}
_id = await add_msg('testing')_id = await update_msg(_id, content='toasting')_id = await update_msg(_id, skipped=1)msg = await read_msgid(_id)
msg['content'] = 'toasted'
await update_msg(msg=msg)'_9dd689bd'
await del_msg(_id){'status': 'success'}
_edit_id = await add_msg('This message should be found.\n\nThis is a multiline message.')
_edit_id'_f6a275bf'
print((await read_msg())['content'])This message should be found.
This is a multiline message.
print((await read_msg(n=0, id=_edit_id, nums=True))['content']) 1 │ This message should be found.
2 │
3 │ This is a multiline message.
print((await read_msg(n=0, id=_edit_id, nums=True, view_range=[2,3]))['content']) 2 │
3 │ This is a multiline message.
run_msg
async def run_msg(
ids:str=None, # Comma-separated ids of message(s) to execute
dname:str='', # Running dialog to get info for; defaults to current dialog. (Note dialog *must* be running for this function)
):
Adds a message to the run queue. Use read_msg to see the output once it runs.
codeid = (await read_msg())['id']await run_msg(codeid){'status': 'queued'}
copy_msg
async def copy_msg(
ids:str=None, # Comma-separated ids of message(s) to copy
cut:bool=False, # Cut message(s)? (If not, copies)
dname:str='', # Running dialog to copy messages from; defaults to current dialog. (Note dialog *must* be running for this function)
)->dict:
Add ids to clipboard.
paste_msg
async def paste_msg(
id:str=None, # Message id to paste next to
after:bool=True, # Paste after id? (If not, pastes before)
dname:str='', # Running dialog to copy messages from; defaults to current dialog. (Note dialog *must* be running for this function)
)->dict:
Paste clipboard msg(s) after/before the current selected msg (id).
await copy_msg(codeid){'success': 'complete'}
test_eq((await copy_msg('_fake', dname='/dlg/nonexistent'))['error'], 'Dialog /dlg/nonexistent may not be running, or message not found')tgt = (await read_msg())['id']await paste_msg(tgt){'success': 'complete'}
# TODO fix so this passes
# test_eq((await paste_msg('_fake', dname='/dlg/nonexistent'))['error'], 'Dialog /dlg/nonexistent may not be running, or message not found')newmsg = await read_msg(1, id=tgt)
newmsg['content']'async def run_msg(\n ids:str=None, # Comma-separated ids of message(s) to execute\n dname:str=\'\' # Running dialog to get info for; defaults to current dialog. (Note dialog *must* be running for this function)\n):\n "Adds a message to the run queue. Use read_msg to see the output once it runs."\n return await call_endpa(\'add_runq_\', dname, ids=ids, json=True)'
await del_msg(newmsg['id']){'status': 'success'}
enable_mermaid()mermaid('graph LR; A[Start] --> B[Process]; B --> C[End];')You can also add to a note:
```mermaid
graph LR
A[Start] --> B[Process]
B --> C[End]
```
This renders as:
graph LR
A[Start] --> B[Process]
B --> C[End]
You can also add to a note:
```mermaid
graph LR
A[Start] --> B[Process]
B --> C[End]
```
This renders as:
graph LR
A[Start] --> B[Process]
B --> C[End]
toggle_header
async def toggle_header(
id:str, # id of markdown header note message to toggle collapsed state
dname:str='', # Running dialog to copy messages from; defaults to current dialog. (Note dialog *must* be running for this function)
)->dict:
Toggle collapsed header state for id
toggle_bookmark
async def toggle_bookmark(
id:str, # id of message to toggle bookmark on
n:int, # Bookmark number (1-9)
dname:str='', # Dialog to set bookmark in; defaults to current dialog
)->dict:
Toggle numbered bookmark (1-9) on a message, clearing it from any other message when setting
toggle_comment
async def toggle_comment(
id:str, # id of code message (or comma-separated ids) to toggle comments on
dname:str='', # Dialog to toggle comments in; defaults to current dialog. (Note dialog *must* be running for this function)
)->dict:
Toggle line comments on code message(s). If any lines are uncommented, comments all; otherwise uncomments all.
await toggle_comment(codeid) # comment
await toggle_comment(codeid) # uncomment{'success': 'complete'}
test_eq((await toggle_comment('_fake', dname='/dlg/nonexistent'))['error'], 'Dialog /dlg/nonexistent may not be running, or message not found')test header
header end
hdid = (await read_msg())['id']await toggle_header(hdid){'success': 'complete'}
test_eq((await toggle_header('_fake', dname='/dlg/nonexistent'))['error'], 'Dialog /dlg/nonexistent may not be running, or message not found')Dlg conveniences
url2note
async def url2note(
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)
ai_img:bool=True, # Make images visible to the AI
split_re:str='', # Regex to split content into multiple notes, set to '' for single note
):
Read URL as markdown, and add note(s) below current message with the result
_id = await url2note('https://docs.python.org')await del_msg(_id){'status': 'success'}
create_or_run_dialog
async def create_or_run_dialog(
name:str, # Name/path of the dialog (relative to current dialog's folder, or absolute if starts with '/')
template:bool=True, # Include TEMPLATE.ipynb files when creating a new dialog
):
Create a new dialog, or set an existing one running
await create_or_run_dialog('test_dialog'){'success': '"aai-ws/dialoghelper/nbs/test_dialog" is now running'}
stop_dialog
async def stop_dialog(
name:str, # Name/path of the dialog (relative to current dialog's folder, or absolute if starts with '/')
):
Stop a running dialog kernel
await stop_dialog('test_dialog'){'success': 'dialog stopped'}
load_dialog
async def load_dialog(
src_dname:str, # Dialog to load code from (path relative to solveit data dir, no .ipynb)
dname:str='', # Target dialog; defaults to current dialog
):
Run all code messages from src_dname into the target dialog’s kernel and return dialog contents.
rm_dialog
async def rm_dialog(
name:str, # Name/path of the dialog to delete (relative to current dialog's folder, or absolute if starts with '/')
):
Delete a dialog (or folder) and associated records, stopping the kernel if running
await rm_dialog('test_dialog'){'success': 'deleted "/Users/jhoward/aai-ws/dialoghelper/nbs/test_dialog"'}
run_code_interactive
async def run_code_interactive(
code:str, # Code to have user run
):
Insert code into user’s dialog and request for the user to run it. Use other functions where possible, but if they can not find needed information, ALWAYS use this instead of guessing or giving up. IMPORTANT: This tool is TERMINAL - after calling it, you MUST stop all tool usage and wait for user response. Never call additional tools after this one.
Text Edit
await msg_insert_line(_edit_id, 0, 'This should go to the first line')
await msg_insert_line(_edit_id, 3, 'This should go to the 4th line')
print(await msg_insert_line(_edit_id, 5, 'This should go to the last line'))@@ -5 +5,2 @@
This is a multiline message.
+This should go to the last line
print((await read_msg(n=0, id=_edit_id, nums=True))['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
print(await msg_str_replace(_edit_id, 'This should go to the first line', 'This should go to the 1st line'))@@ -1,2 +1,2 @@
-This should go to the first line
+This should go to the 1st line
This message should be found.
print((await read_msg(n=0, id=_edit_id, nums=True))['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
print(await msg_strs_replace(_edit_id, ['This is a multiline message.', 'This should go to the last line'], ['5th line', 'last line']))@@ -4,3 +4,3 @@
This should go to the 4th line
-This is a multiline message.
-This should go to the last line
+5th line
+last line
print((await read_msg(n=0, id=_edit_id, nums=True))['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
print(await msg_replace_lines(_edit_id, 2, 4,'line 2\nline 3\nline 4\n'))@@ -1,5 +1,5 @@
This should go to the 1st line
-This message should be found.
-
-This should go to the 4th line
+line 2
+line 3
+line 4
5th line
print((await read_msg(n=0, id=_edit_id, nums=True))['content']) 1 │ This should go to the 1st line
2 │ line 2
3 │ line 3
4 │ line 4
5 │ 5th line
6 │ last line
print(await msg_del_lines(_edit_id, 2, 4))@@ -1,5 +1,2 @@
This should go to the 1st line
-line 2
-line 3
-line 4
5th line
print((await read_msg(n=0, id=_edit_id, nums=True)).content) 1 │ This should go to the 1st line
2 │ 5th line
3 │ last line
print(await msg_python(_edit_id, r"'\n'.join(sorted(text.splitlines()))"))@@ -1,3 +1,3 @@
+5th line
This should go to the 1st line
-5th line
last line
print((await read_msg(n=0, id=_edit_id, nums=True)).content) 1 │ 5th line
2 │ This should go to the 1st line
3 │ last line
await del_msg(_edit_id){'status': 'success'}
id1 = await add_msg('hello world')
id2 = await add_msg('hello there', id=id1)results = await msg_str_replace([id1, id2], 'hello', 'hi')
print(results)[('_89541f89', '@@ -1 +1 @@\n-hello world\n+hi world'), ('_f50d9464', '@@ -1 +1 @@\n-hello there\n+hi there')]
await del_msg(id1)
await del_msg(id2){'status': 'success'}
Help
solveit_docs
def solveit_docs(
):
Full reference documentation for Solveit - use this to answer questions about how to use Solveit. NB: The whole docs fit in LLM context, so read the whole thing, don’t search/filter it. Always re-run rather than relying on truncated history or assumptions.
dialog_link
def dialog_link(
dname:str='', # Dialog to link to (relative to current dialog's folder, or absolute if starts with '/'); empty for in-page anchor link
msg_id:str=None, # Optional message id to scroll to
):
Return an IPython HTML link to open a dialog in Solveit. After calling this, output the resulting HTML anchor tag exactly as returned—do not wrap in a fenced code block or convert to markdown link format.
dialog_link(msg_id='_a7d82acd')dialog_link(dname='/CRAFT')dialog_link(dname='/CRAFT', msg_id='_ce727fd8')spawn_agent
async def spawn_agent(
prompt:str
):
Spawn a subagent to complete a task defined by prompt. Must be run as a tool - not from Python. The subagent’s context and tools is defined by the parent prompt’s history
Web Search
# r = await search("Weather Brisbane")
# rsearches
async def searches(
searches:list
):
Get search results for multiple queries in parallel
# r = await searches(["Weather Brisbane", "Weather Sydney", "Weather Melbourne"])
# rweb_answer
async def web_answer(
pr:str, # The prompt - i.e the question to get answered
qs:list, # A list of 1 or more web search queries that might provide useful results. Do not constrain the queries too much - make sure the agent as a range of links to choose from
page_chars:int=50000, # Truncate web pages beyond this size
):
Use a search agent to search for all of qs, choose suitable pages to read, and answer pr based on the page contents.
# r = await web_answer(pr="What's the weather in Brisbane?", qs=["Weather Brisbane"], page_chars=1000)
# r