Adds a Context Overflow Errors subsection to custom-provider.md showing how a custom provider extension can rewrite unrecognized overflow errors via a message_end handler so pi's native compact-and-retry path triggers. Includes guard rails for provider scoping, idempotency, and avoiding rate-limit phrases.
The notify() API only accepts "info" | "warning" | "error" — "success"
was a copy-paste error in the example.
Co-Authored-By: julien-agent <Agents+cyolo@huggingface.co>
packages/tui/src/stdin-buffer.ts — in extractCompleteSequences, after finding \x1b\x1b as "complete" (legacy meta-key), check if the next character in the buffer would start a new escape sequence ([, ], O, P, _). If so, emit only the first \x1b and let the second ESC begin a new parse iteration.
packages/tui/test/stdin-buffer.test.ts — three new cases in the Kitty section:
- \x1b\x1b[27;129:3u (num_lock) splits into ["\x1b", "\x1b[27;129:3u"]
- \x1b\x1b[27;1:3u (no num_lock) splits into ["\x1b", "\x1b[27;1:3u"]
- \x1b\x1b alone (no following CSI) still emits as ["\x1b\x1b"] — preserves ctrl+alt+[
Mercury 2 in instant mode (reasoning_effort: "none") disables tool calling.
The openai-completions provider hardcodes {reasoning:{effort:"none"}} when no
explicit reasoning level is passed and thinkingLevelMap.off isn't null
(openai-completions.ts:575), so every caller that doesn't opt in to a level
silently breaks Mercury 2's agentic use cases.
Setting thinkingLevelMap.off = null on the Mercury 2 catalog entry causes the
provider to omit the reasoning param entirely, letting Mercury 2's own default
take over. Low/medium/high pass through verbatim; OpenRouter normalizes them
to Mercury's vocabulary.
Prefix-matched on "inception/mercury-2" so future Mercury 2 variants on
OpenRouter inherit the fix.
When an uncaught exception fires in interactive mode, the process dies with
stdin still in raw mode and the cursor hidden, leaving the user with a
"borked" terminal that needs `stty sane && reset` to recover. The most
common trigger is an extension's async ChildProcess `exit` callback that
throws (e.g. from accessing a stale ctx after session replacement), but
this affects any uncaught throw from anywhere in pi.
Add an uncaughtException handler in registerSignalHandlers that calls
ui.stop() before exiting, mirroring the existing emergencyTerminalExit
pattern. The handler is registered with prependListener and tracked in
signalCleanupHandlers, so it is removed on graceful shutdown the same way
the other handlers are.
Unlike emergencyTerminalExit (used for SIGHUP / dead-terminal EIO), the
terminal is still alive on uncaughtException, so we run the normal
ui.stop() to restore cooked mode, the cursor, bracketed paste mode, and
Kitty / modifyOtherKeys sequences.