New Features
- TypeBox 1.x migration for extensions and SDK integrations, including TypeBox-native tool argument validation that now works in eval-restricted runtimes such as Cloudflare Workers. See docs/extensions.md and docs/sdk.md.
- Stacked extension autocomplete providers via
ctx.ui.addAutocompleteProvider(...), allowing extensions to layer custom completion logic on top of built-in slash and path completion. See docs/extensions.md#autocomplete-providers and examples/extensions/github-issue-autocomplete.ts. - Terminating tool results via
terminate: true, allowing custom tools to end on a final tool call without paying for an automatic follow-up LLM turn. See docs/extensions.md and examples/extensions/structured-output.ts. - OSC 9;4 terminal progress indicators during agent streaming and compaction for supporting terminals.
Breaking Changes
- Migrated first-party coding-agent code, SDK/examples/docs, and package metadata from
@sinclair/typebox0.34.x totypebox1.x. New extensions, SDK integrations, and pi packages should depend on and import fromtypebox. Legacy extension loading still aliases the root@sinclair/typeboxpackage, but@sinclair/typebox/compileris no longer shimmed. This migration also picks up the new@mariozechner/pi-aiTypeBox-native validator path, so tool argument validation now works in eval-restricted runtimes such as Cloudflare Workers instead of being skipped (#3112) - Session-replacement commands now invalidate captured pre-replacement session-bound extension objects after
ctx.newSession(),ctx.fork(), andctx.switchSession(). Oldpiand commandctxreferences now throw instead of silently targeting the replaced session. Migration: if code needs to keep working in the replacement session after one of those calls, passwithSessionto that same method and do the post-switch work there. In practice, move post-switchpi.sendUserMessage(),pi.sendMessage(), and command-ctx/session-manager access intowithSession, and use only theReplacedSessionContextpassed to that callback for session-bound operations. Footguns:withSessionruns after the old extension instance has already receivedsession_shutdown, old cleanup may already have invalidated captured state, captured oldpi/ old commandctxare stale, and previously extracted raw objects such asconst sm = ctx.sessionManagerremain the caller's responsibility and must not be reused after the switch.
Added
- Added support for terminating tool results via
terminate: true, allowing custom tools to end the current tool batch without an automatic follow-up LLM call, plus astructured-output.tsextension example and extension docs showing the pattern (#3525) - Added OSC 9;4 terminal progress indicators during agent streaming and compaction, so terminals like iTerm2, WezTerm, Windows Terminal, and Kitty show activity in their tab bar
- Added
ctx.ui.addAutocompleteProvider(...)for stacking extension autocomplete providers on top of the built-in slash/path provider, plus agithub-issue-autocomplete.tsexample and extension docs (#2983)
Fixed
- Fixed exported session HTML to sanitize markdown link URLs before rendering them into anchor tags, blocking
javascript:-style payloads while preserving safe links in shared/exported sessions (#3532) - Fixed
ctx.getSystemPrompt()insidebefore_agent_startto reflect chained system-prompt changes made by earlierbefore_agent_starthandlers, and clarified the extension docs around provider-payload rewrites and whatctx.getSystemPrompt()does and does not report (#3539) - Fixed built-in
google-gemini-climodel lists and selector entries to includegemini-3.1-flash-lite-preview, so Cloud Code Assist users no longer need manual--modelfallback selection to use it (#3545) - Fixed extension session-replacement flows so
ctx.newSession(),ctx.fork(),ctx.switchSession(), and imported-session replacements fully rebind before post-switch work runs, addedwithSessionreplacement callbacks with freshReplacedSessionContexthelpers, and make stale pre-replacementpi/ctxsession-bound accesses throw instead of silently targeting the wrong session (#2860) - Fixed
models.jsonbuilt-in provider overrides to acceptheaderswithout requiringbaseUrl, so request-header-only overrides now load and apply correctly (#3538)