Breaking change: pi.getAllTools() now returns Array<{ name, description }>
instead of string[]. Extensions needing just names can use .map(t => t.name).
Removes redundant getToolInfo() method added in original PR.
Fixes#647
- Add SessionInfoEntry type for session metadata
- Add /name <name> command to set session display name
- Add pi.setSessionName() and pi.getSessionName() extension API
- Session selector shows name (in warning color) instead of first message when set
- Session name included in fuzzy search
- /session command displays name when set
closes#650
Claude models accessed through Google Cloud Code Assist API require
explicit id fields in both functionCall and functionResponse parts.
Without these IDs, the API returns 'tool_use.id: Field required' error.
Add requiresToolCallId() helper to centralize the Claude model detection
and include IDs in both tool call and tool result message conversions.
* Avoid cross-provider thought signatures
* Fix Google thought signature replay
Filter thought signatures to same provider with base64 validation and rename the transform helper for clarity.
- Renamed from /models to /scoped-models
- Changes are now session-only by default (Ctrl+S to persist to settings)
- Added search with fuzzy filtering
- Hotkeys: Enter toggle, Ctrl+A enable all, Ctrl+X clear all, Ctrl+P toggle provider
- Ctrl+C clears search (or exits if empty), Escape exits
- Enabled models shown at top of list
- No checkmarks when all models enabled (no scope)
- First toggle when unscoped clears all and selects that model
- Uses current session thinking level instead of settings default
- Reads from session state first (preserves session-only changes across /scoped-models invocations)
Builds on #626
- /resume and --resume now toggle between Current Folder and All sessions with Tab
- SessionManager.list() and listAll() are now async with optional progress callback
- Shows loading progress (e.g. Loading 5/42) while scanning sessions
- SessionInfo.cwd field shows session working directory in All view
- Lazy loading: All sessions only loaded when user presses Tab
closes#619
Co-authored-by: Thomas Mustier <mustierthomas@gmail.com>
Git uses atomic writes (temp file + rename) which changes the inode.
fs.watch on a file stops working after the inode changes.
Now watches the directory containing HEAD and filters for HEAD changes.
The 100ms timeout was causing Kitty protocol detection to fail when the
terminal response was delayed (e.g., due to event loop blocking during
startup). This resulted in shift+enter not working in some scenarios.
Changes:
- Remove timeout-based Kitty detection, process input immediately
- Detect Kitty response in stdinBuffer output (handles split data)
- Add modifyOtherKeys fallback for terminals without Kitty support
(matches xterm format \x1b[27;modifier;keycode~)
- New /models command with toggle UI for each available model
- Changes persist to enabledModels in settings.json
- Updates take effect immediately for Ctrl+P cycling
- Store thoughtSignature on text blocks during streaming (all 3 providers)
- Replay textSignature as thoughtSignature in convertMessages
- Remove redundant conditional since retainThoughtSignature handles undefined
Per Google docs, text part signatures are optional but recommended for
high-quality reasoning in multi-turn conversations.
- isThinkingPart now only checks thought === true, not thoughtSignature
- thoughtSignature is for context replay and can appear on any part type
- Store thoughtSignature on text blocks as textSignature for proper replay
- Remove id from functionCall/functionResponse (unsupported by Vertex/Cloud Code Assist)
Refs: https://ai.google.dev/gemini-api/docs/thought-signatures
Co-authored-by: Amp <amp@ampcode.com>
The problem: I wanted to be able to select my session (either from
`/resume` or `--resume`) with different keybindings.
The issue: when running `pi --resume`, custom keybindings from
`~/.pi/agent/keybindings.json` were not being applied to the session
picker. This happened because `KeybindingsManager.create()` was only
called when `InteractiveMode` initialized, but the session picker runs
before that in `main.ts`.
The session picker uses `getEditorKeybindings()` for navigation
(selectUp/selectDown etc.), which returns the global default keybindings
if `setEditorKeybindings()` hasn't been called yet.
Fix: Call `KeybindingsManager.create()` inside the `--resume` block
before showing the session picker. This loads user keybindings and sets
them globally.
The current fix results in double-init of keybindings when entering
interactive mode which _should_ be harmless, since it's the same same
config loaded twice, but is minimal and only affects the `--resume`
path.
I considered passing keybindings from `main()` to `InteractiveMode` -
it's cleaner but requires API changes.
Also documented the `select*` keybindings in README.md.
Fires when the model changes via /model command, model cycling (Ctrl+P),
or session restore. Includes source field and previousModel.
Add model-status.ts example extension demonstrating status bar updates.
closes#628
- Skills registered as /skill:name commands for quick access
- Toggle via /settings or skills.enableSkillCommands in settings.json
- Fuzzy matching for all slash command autocomplete (type /skbra for /skill:brave-search)
- Moved fuzzy module from coding-agent to tui package for reuse
Closes#630 by @Dwsy (reimplemented with fixes)