@contextmanager
def Live(start, **kw):
print(start)
def update(s, refresh=False): clear_output(True);print(s)
yield NS(update=update)Core
Imports
CodeBlock.__rich_console__
CodeBlock.__rich_console__ (console, options)
Chat
Chat (*arg, **kw)
Lazy load lisette to make ssage more responsive
Jupyter does work with rich.live.Live, this fixes it.
def print_md(md_stream):
"Print streamed markdown"
with Live(Spinner("dots", text="Connecting..."), auto_refresh=False) as live:
for part in md_stream: live.update(Markdown(part), refresh=True)Model Setup
System Environment
# aliases = _aliases('bash')
# print(aliases)# print(_sys_info())Tmux
get_pane
get_pane (n, pid=None)
Get output from a tmux pane
# p = get_pane(20)
# print(p[:512])get_panes
get_panes (n)
# ps = get_panes(20)
# print(ps[:512])co(['tmux', 'display-message', '-p', '#{history-limit}'], text=True).strip()'2000'
tmux_history_lim
tmux_history_lim ()
tmux_history_lim()2000
get_history
get_history (n, pid='current')
Options and ShellSage
get_opts
get_opts (**opts)
# opts = get_opts(model=None, log=None, api_base=None, api_key=''); optswith_permission
with_permission (action_desc)
print(tools[1]('.'))Directory contents of /Users/jhoward/aai-ws/shell_sage/nbs: /Users/jhoward/aai-ws/shell_sage/nbs/00_core.ipynb /Users/jhoward/aai-ws/shell_sage/nbs/_quarto.yml /Users/jhoward/aai-ws/shell_sage/nbs/sidebar.yml /Users/jhoward/aai-ws/shell_sage/nbs/styles.css /Users/jhoward/aai-ws/shell_sage/nbs/CNAME /Users/jhoward/aai-ws/shell_sage/nbs/01_config.ipynb /Users/jhoward/aai-ws/shell_sage/nbs/nbdev.yml /Users/jhoward/aai-ws/shell_sage/nbs/index.ipynb
get_sage
get_sage (model, mode='default', search=False)
# m = 'ollama_chat/qwen3:8b'
# ssage = get_sage(m)
# ssage('Howdy!')m = 'claude-sonnet-4-5'
ssage = get_sage(m, search='l')
ssage('Hi, how are ya?', think='l')Hey there! Doing well, ready to help with any shell commands or system questions you’ve got. What can I help you with today?
- id:
chatcmpl-30420d10-6b60-492d-9c90-0933442e7e6c - model:
claude-sonnet-4-5-20250929 - finish_reason:
stop - usage:
Usage(completion_tokens=91, prompt_tokens=3387, total_tokens=3478, completion_tokens_details=CompletionTokensDetailsWrapper(accepted_prediction_tokens=None, audio_tokens=None, reasoning_tokens=46, rejected_prediction_tokens=None, text_tokens=None, image_tokens=None), prompt_tokens_details=PromptTokensDetailsWrapper(audio_tokens=None, cached_tokens=0, text_tokens=None, image_tokens=None, cache_creation_tokens=0, cache_creation_token_details=CacheCreationTokenDetails(ephemeral_5m_input_tokens=0, ephemeral_1h_input_tokens=0)), cache_creation_input_tokens=0, cache_read_input_tokens=0)
get_res
get_res (sage, q, opts)
opts=NS(api_base='', api_key='', think='l')
list(get_res(ssage, 'Use tools to check if we have a .git in the current directory. Respond with yes/no', opts))['', '', '', '', '', '', '', '', '', '', '', '', '', '', 'No', 'No']
print_md(get_res(ssage, 'Hi!', opts))Hey! What can I help you with?
print_md(get_res(ssage, 'Please use your view command to see what files are in the current directory. Only respond with a single paragraph', opts))The current directory contains several files related to what appears to be an nbdev project: three Jupyter notebooks (00_core.ipynb, 01_config.ipynb, and index.ipynb), along with configuration files for Quarto (_quarto.yml, sidebar.yml, styles.css), a CNAME file for custom domain hosting, and an nbdev.yml configuration file.
print_md(get_res(ssage, 'Please search the web for interesting facts about Linux. Only respond with a single paragraph.', opts));Linux, created in 1991 as an open-source Unix-like operating system, has revolutionized the world and become the dominant OS in cloud computing, IoT, and mobile devices, with all 500 of the world's fastest supercomputers running Linux. The operating system almost wasn't called "Linux" — Linus Torvalds originally wanted to name it "FreaX" but was persuaded by the server owner hosting his early code to use "Linux" instead, and the International Space Station has been running Linux since 2013. The penguin mascot Tux has an amusing origin story: Linus claims he was once bitten by an angry penguin, and Linux has even made its mark in Hollywood, with the visual effects for Avatar and Titanic developed on the Linux platform.
Logging
mk_db
mk_db ()
Log
Log ()
Initialize self. See help(type(self)) for accurate signature.
# db = mk_db()
# log = db.logs.insert(Log(timestamp=datetime.now().isoformat(), query='Hi, who are you?', model='llama3.2',
# response='I am ShellSage, a command-line teaching assistant!', mode='default'))
# logMain
main
main (query:str<ThequerytosendtotheLLM>, v:<Printversion>='%(prog)s 1.0.2', pid:str='current', skip_system:bool=False, history_lines:int=None, mode:str='default', model:str=None, search:str=None, api_base:str=None, api_key:str=None, think:str=None, trust:str=None, code_theme:str=None, code_lexer:str=None)
| Type | Default | Details | |
|---|---|---|---|
| query | str |
||
| v | %(prog)s 1.0.2 | ||
| pid | str | current | current, all or tmux pane_id (e.g. %0) for context |
| skip_system | bool | False | Whether to skip system information in the AI’s context |
| history_lines | int | None | Number of history lines. Defaults to tmux scrollback history length |
| mode | str | default | Available ShellSage modes: [‘default’, ‘sassy’] |
| model | str | None | The LLM model that will be invoked on the LLM provider |
| search | str | None | Wheather to allow the LLM to search the internet |
| api_base | str | None | |
| api_key | str | None | |
| think | str | None | Reasoning effort level: ‘l’, ‘m’, ‘h’ (for supported models) |
| trust | str | None | Comma-delimited list of tools to always allow (e.g. “view,rg”) |
| code_theme | str | None | The code theme to use when rendering ShellSage’s responses |
| code_lexer | str | None | The lexer to use for inline code markdown blocks |
main(['Teach me about rsync. Reply with a single paragraph.'], history_lines=0)rsync is a fast, versatile file-copying tool that efficiently transfers files by only sending differences between source and destination (delta transfer). Common usage: rsync -avz source/ dest/ where -a is archive mode (preserves permissions, timestamps, symlinks), -v is verbose, and -z compresses during transfer. For remote sync: rsync -avz local/ user@host:/remote/path/. Key gotcha: trailing slash matters—source/ copies contents, source copies the directory itself. Use --dry-run to preview changes before committing, and --delete to remove files from dest that don't exist in source (destructive). See man rsync for the full 100+ options.
r = f'''
Hello, user! Here are some code blocks:
```python
for i in range(10): print(i)
```
```
This doesn't even have a language definition!
```
```bash
ls **/*
```
'''db = mk_db()
db.logs.insert(Log(timestamp=datetime.now().isoformat(), query='', response=r, model='', mode=''))Log(id=1, timestamp='2025-12-03T04:46:49.790878', query='', response="\nHello, user! Here are some code blocks:\n\n```python\nfor i in range(10): print(i)\n```\n\n```\nThis doesn't even have a language definition!\n```\n\n```bash\nls **/*\n```\n", model='', mode='')
extract_cf
extract_cf (idx)
extract_cf(0)'for i in range(10): print(i)'
extract
extract (idx:int, copy:bool=False)
| Type | Default | Details | |
|---|---|---|---|
| idx | int | Index of code block to extract | |
| copy | bool | False | Copy to clipboard vs send to tmux |