@oh-my-pi/pi-agent-core
Added
- Added per-tool abort metadata so stream-wide aborts can label matching tool-call placeholders separately from unaffected sibling calls (#2783).
Fixed
- Fixed handoff generation retrying with
toolChoice: "auto"when custom OpenAI-compatible providers rejecttoolChoice: "none"with an auto-only 400. (#4715) - Fixed generic remote compaction against OpenAI-compatible
/chat/completionsendpoints (for example llama.cppopenai-completions) by sending chat messages instead of the custom{ systemPrompt, prompt }summarizer payload. (#4630)
@oh-my-pi/pi-ai
Added
- Added
AssistantMessage.toolCallAbortMessagesfor per-tool placeholder labels on aborted assistant turns (#2783).
Fixed
- Fixed Anthropic replay 400s (
tool_use ids were found without tool_result blocks immediately after) when a persisted assistant turn carries content after a completed tool call — such as a mid-turnserver-side-fallbackhandoff (fallback block plus continued text/tool calls after the primary model'stool_use) or trailing text from cross-provider replays — by stable-partitioning assistant content so alltool_useblocks trail the non-tool_usechain. (#4781, #544) - Fixed access-token-only OAuth credentials attempting token refresh with an empty refresh token after expiry.
- Fixed gateway usage-limit retries falling through to cross-provider model fallback before trying a sibling credential from the same provider.
- Fixed Codex usage-limit rotation treating Plus and K-12 accounts as separate quota groups for shared 5-hour/7-day windows.
- Fixed OpenAI Responses streams that end with
response.donebeing misclassified as premature stream closures. - Fixed OpenCode Go
/logincredentials being shadowed by an existingOPENCODE_API_KEYenv fallback after switching accounts. (#4688) - Fixed OpenAI Codex WebSocket continuations to treat proxy stale-anchor codes such as
codex_previous_response_staleas an expiredprevious_response_idchain — same recovery class as the OpenAI-standardprevious_response_not_found— so the turn is retried with full context instead of surfacing the error to the user (#4624). - Fixed Azure Foundry Anthropic utility requests to omit the structured-output beta whenever strict tools are disabled, preventing
structured_outputs not supported in your workspacefailures for Sonnet 5 compaction (#4679). - Fixed OAuth
launchUrladvertisement for flows whose redirect never returns to the local callback server: custom-scheme redirects (e.g. GitLab Duo'svscode://URI, whichnew URLparses without complaint) and fixed non-loopback hosts no longer receive ahttp://localhost:<port>/launchcopy target that misrepresents the callback endpoint and resolves nowhere for remote users. - Codex load balancing: clear stale persisted and in-memory usage-limit blocks for an
openai-codexaccount when a fresh live usage report shows it is allowed and below all limits, including broker-backed gateway snapshots, so traffic returns to recovered accounts instead of funneling to one sibling.
@oh-my-pi/pi-catalog
Fixed
- Fixed LiteLLM discovery stopping at
/model_group/infowhen that endpoint omittedsupports_vision; it now continues to/model/infoand preservesmodel_info.supports_vision=truefor vision-capable proxy models. (#4747) - Fixed LiteLLM discovery to fall back to bundled catalog metadata when
models.devlacks a model reference, preserving reasoning and thinking support for models such asglm-5.2. (#4695) - Detected Azure AI Inference / Foundry Anthropic routes as strict-tool-incompatible so resolved Anthropic compat disables strict tools before request construction (#4679).
@oh-my-pi/pi-coding-agent
Added
- Typing
#<number>(e.g.#3164) in the prompt now offers PR and Issue autocomplete candidates that rewrite to thepr:///issue://internal URL, resolved from the current repo's git remote via the existingreadtool → InternalUrlRouter →ghpipeline. Naming the type (pr #3164/issue #3164) constrains the candidates to that kind, and embedded hashes likeowner/repo#N,foo#N, or URL fragments are left untouched (#3218)
Changed
- Memoized non-message token totals (system prompt, tool schemas, skills) so the per-turn compaction and context-threshold paths recompute them at most once per input change instead of on every call.
getContextBreakdownand#estimateStoredContextTokenspreviously re-tokenized the system prompt and every tool's wire schema (per-toolJSON.stringify) several times per turn over inputs that change at most once per turn.
Fixed
- Improved handling of unawaited promises in JS eval cells to prevent process crashes
- Added warning logs for unhandled rejections originating from finished eval cells
- Improved advisor robustness by blocking exhausted accounts during consecutive turn failures
- Fixed advisor turns hammering the same usage-limited account: a failed advisor turn now marks the exhausted credential blocked (with the provider's retry hint and usage-report reset time), so the next retry rotates to a sibling instead of re-picking the blocked account every few seconds. Previously the in-stream auth retry rotated within a request but never blocked the last failing credential, and the advisor loop — unlike the primary retry pipeline — never called
markUsageLimitReached. - Added the account key to the
codex-auto-reset: skippeddebug log so skip reasons (e.g.weekly-not-exhausted) can be attributed to the evaluated account. - Fixed unawaited promise rejections in JS eval cells crashing the session: a floating rejection now fails the owning cell run (
Unhandled rejection (missing await?): …) instead of escaping to the globalunhandledRejectionhandler, which printed[Unhandled Rejection]and killed the process (inline fallback) or tore down the eval worker (dedicated worker). Rejections surfacing after a cell settled are downgraded to a warn log attributed to the finished cell. - Fixed project
.omp/RULES.mdsticky rules being shadowed by user~/.omp/agent/RULES.mdrules with the same synthesizedRULESname, so both user and project sticky rules now inject (#4739). - Fixed bash internal-URL expansion so unresolved literal
memory:///skill://text stays verbatim instead of aborting command execution (#4737). - Fixed
agent://<id>(and theoutput()eval helper) failing withNot foundfor a subagent spawned by another subagent (any spawn chain 2+ levels deep).artifactsDirsFromRegistryscanned only each ref's adopted (root-wide)ArtifactManagerdir, but a subagent's own children are written one level deeper under itssessionFile-derived dir — so a live, addressable nested peer's output was unresolvable. The resolver now collects both candidate dirs per registered agent. (#4650) - Fixed plan mode to document
local://artifacts as writable session-local planning files and to carry every pre-approvallocal://artifact into the fresh session created by Approve and Execute. - Fixed the browser tool failing to launch Microsoft Edge-only Windows installs with Puppeteer's empty
Code: 0launch error by keeping Edge's required--enable-automationdefault while preserving Chrome/Chromium stealth launch defaults. - Fixed bash/tool command environments inheriting Bun-autoloaded launch
.env.localvalues, so nested apps can load their own dotenv values without parent deployment variables taking precedence. (#4723) - Fixed legacy plugin validation for extension graphs that import JSON with
with { type: "json" }, leaving JSON files on Bun's native loader instead of parsing them as JavaScript (#4687). - Fixed pasted terminal transcripts beginning with a shell prompt (
$ ...) being mistaken for local Python shortcuts instead of being submitted as normal prompts (#4678). - Fixed wrapped OAuth copy-URL rows corrupting on paste: continuation chunks no longer carry a leading indent, so a multi-row terminal selection reassembles to the exact authorize URL (browsers strip newlines on paste but preserve or percent-encode embedded spaces, which previously corrupted the URL at every chunk boundary).
- Fixed Windows browser-launch failures being unobservable: the opener now uses
%SystemRoot%-resolved PowerShellStart-Process(via-EncodedCommand) instead ofrundll32, which exits 0 unconditionally. Failures ShellExecute itself reports — missing target, no handler executable, access denied — now surface as non-zero exits and are logged; the encoded payload also keeps OAuth query strings (&-bearing) opaque to shell metacharacter parsing. - Fixed system prompt date rendering to use the host local calendar date instead of UTC.
- Fixed
bashtooltimeout: 0so it disables the command deadline instead of falling back to the minimum timeout. - Fixed
readandgreprefusing to access filesystem paths whose names end in a selector-shaped suffix (e.g.test:1-2,log:raw) by preferring a literal match over the trailing:<selector>peel when the raw path exists on disk (#4618). - Fixed wrapped Edit-diff rows leaking inverse video into the result card's right-edge padding: a row that broke inside an intra-line highlight left inverse active at the row end, so the frame padding after it rendered as a default-foreground block (#4616 by @chan1103)
- Fixed Edit-diff continuation rows escaping into the line-number column when the row's gutter was left-padded (line number narrower than the widest in the diff) or blanked by the gutter dedup (the bare
+row of a single-line replacement); such rows now wrap behind a continuation gutter, while body lines that merely start with|keep wrapping generically (#4616 by @chan1103) - Fixed live advisors continuing to use a stale
modelRoles.advisorselection after/modelchanged the advisor model. (#4612) - Fixed Claude plugin slash commands and skills silently vanishing when the plugin manifest declares
commands/slash-commands/skillsas a JSON array — the shape the Claude plugins reference documents and real plugins likeaddyosmani/agent-skillsship.resolvePluginDirinpackages/coding-agent/src/discovery/claude-plugins.tstyped those fields asstringand dropped array values on the floor; it now normalizes both shapes, loads every in-root entry, and reports one out-of-plugin-root warning per bad entry. The resolver also now honours Claude's per-field merge semantic —skillsadds to the defaultskills/scan;commands/slash-commandsreplace the defaultcommands/— so plugins like{"skills":["./extra-skills"]}no longer lose their defaultskills/folder while{"commands":["./admin"]}still replacescommands/as documented. (#4609) - Fixed macOS Backspace on empty search not deleting sessions in the
/resumepicker; Fn+Backspace terminals that deliver\x7finstead of\e[3~now reach the delete confirmation dialog. (#4580 by @JagravNaik) - Fixed
/renametitle arguments treating#prompt-action tokens as autocomplete triggers instead of literal session title text. (#4600) - Fixed empty session
.jsonlfiles accumulating in~/.omp/agent/sessions/<cwd>/after a draft-then-clear exit cycle.SessionManager.saveDraft(text)materializes the session file so the draft sidecar has a parent; a subsequentsaveDraft("")unlinked the sidecar but left the metadata-only JSONL behind (title slot + session header + startup selector entries, ~500–750 B), and#shouldHaveSessionFile()could no longer prune it once#fileIsCurrent/#forceFileCreationwere latched.SessionManager.close()now drops only draft-owned metadata-only sessions with no saved draft sidecar to reattach to, while keeping real conversations, meaningful non-message entries such as handoff custom messages, explicitensureOnDisk()sessions, drafts still pending for--resume, and never-materialized sessions untouched (#4571). - Fixed the advisor being disabled for the entire session when the advisor role resolves to a reasoning model that exposes no controllable effort surface (Devin
devin/glm-5-2*:reasoning: true,thinking: undefined— Cascade routes by sibling model id rather than a wire param).#resolveAdvisorRuntimeDescriptorsinpackages/coding-agent/src/session/agent-session.tsused to hardcodeThinkingLevel.Medium, which trippedrequireSupportedEfforton the first advisor prompt withThinking effort medium is not supported by devin/glm-5-2. Supported efforts:(empty list). The advisor descriptor now clamps the requested effort against the resolved model viaresolveThinkingLevelForModeland forwards no explicit effort when the model has no controllable efforts — matching theauto-path fix (clampAutoThinkingEffort) and the Autonomous Memory stage fix (clampThinkingLevelForModel). Explicit:offstill disables reasoning, and models that supportmedium(e.g. Anthropic) keep receiving it (#4579). - Fixed legacy extension plugin validation failing with
Export named 'calculateCost' not found in module '.../legacy-pi-ai-shim.ts'when the extension importscalculateCost(ormodelsAreEqual/getBundledProviders) from@oh-my-pi/pi-ai. Those symbols were relocated to@oh-my-pi/pi-catalog/modelsduring the catalog split but were never bridged back through the legacypi-airoot shim; the shim now re-exports them alongside the existinggetModel/getModelsaliases so plugins written against pre-split pi-ai load again (#4584). - Fixed legacy extension plugin validation failing with
Export named 'calculateCost' not found in module '.../legacy-pi-ai-shim.ts'when the extension imports relocated catalog symbols such ascalculateCost,modelsAreEqual,getBundledProviders,getBundledModel, orgetBundledModelsfrom@oh-my-pi/pi-ai. Those symbols were relocated to@oh-my-pi/pi-catalog/modelsduring the catalog split but were never bridged back through the legacypi-airoot shim; the shim now re-exports them alongside the existinggetModel/getModelsaliases so plugins written against pre-split pi-ai load again (#4584). - Fixed legacy pi extension imports of
DefaultResourceLoaderfrom@mariozechner/pi-coding-agent/@earendil-works/pi-coding-agentby adding a compatibility loader shim that translatesresourceLoaderinto OMP's native session discovery options. (#4567) - Fixed legacy Pi extension reloads on POSIX so
loadLegacyPiModuleimports the entry through a cache-busting filesystem path, refreshes load-time graph hooks when reloads add new modules, and threads the current load's?mtimetag through the extension source graph — relative./helper.tssiblings,#alias/*package-imports, extension-local bare dependency entries, and their relative children all rekey per reload, so same-process re-imports pick up edits across the whole graph. (#4565) - Fixed bash tool pipeline execution preserving stale upstream output when the final stage was a stripped
head/taillimiter; the tool now runs the command as written soseq 1 5 | head -n2returns only1and2. (#4562) - Fixed the status-line token-rate segment rendering as
<number>/s, which Ghostty auto-detected as a hyperlink on Ctrl+hover. (#4541) - Fixed retry fallback model recovery by exposing
retry.fallbackChainsin/settings, adding a/modelaction to assign the selected default fallback model, and clearing a selected model's retry cooldown marker on manual model switches. (#4533) - Fixed
/handoffand auto-handoff skipping extension lifecycle hooks by emitting cancellablesession_before_switchhooks and asession_switchwithreason: "handoff"after the replacement session is ready (#4434). - Fixed TTSR stream interrupts so only the tool call whose stream matched a rule receives the rule-named abort result; sibling tool-call placeholders now use a neutral abort reason (#2783).
@oh-my-pi/pi-natives
Fixed
- Fixed the native build script failing to locate the
@napi-rs/clinapibinary on Windows because thePATHlookup joined entries with a Unix:separator instead of the platform delimiter (path.delimiter). - Fixed a Windows regression where an abnormal
ompexit or bash cancellation couldTerminateProcessunrelatedpwsh.exe/powershell.exesessions (including other Cursor terminal tabs).SpawnRegistrystored only the raw pid of each brush-spawned child and re-opened it viaProcess::from_pidat cancellation time; between those two moments Windows could recycle a freed pid onto an unrelated PowerShell, andsignal_treethen walked the wrong subtree via Toolhelp. The observer now pins a stableProcesshandle at spawn time — on Windows the open handle keeps the pid slot reserved, on Linux the pidfd carries identity, on macOS the(pid, start_time)triple detects impersonation — so cancellation can only reach children this run actually launched. The registry sweeps exited entries once the recorded set crosses a small threshold so a long bash loop of short external commands cannot pin one owned OS handle per historical spawn. (#4605)
@oh-my-pi/pi-tui
Fixed
- Fixed selector rendering when a legacy theme omits symbol settings by falling back to an ASCII cursor instead of crashing (#4745).
- Kept slash command autocomplete rows compact by truncating descriptions instead of wrapping them into multi-line blocks.
- Fixed mid-prompt skill autocomplete so Tab and Enter accept the highlighted
/skill:<name>suggestion and Backspace dismisses the popup immediately after removing the triggering slash (#4619). - Fixed submitted slash-command arguments treating
@file-reference tokens as prompt-composer autocomplete triggers when the command does not define argument completions. (#4600) - Fixed box-drawing tree lines (
├── item— directory layouts, decision trees) in prose shearing apart when they wrap: continuation rows now hang under the node text with ancestor rails carried through (├→│,└→ blank) instead of restarting at column 0. Applies to prose paragraphs (including inside blockquotes) only when a line with a branch-connector prefix (├──,└─, …) actually overflows; fitting lines, non-tree prose, and code blocks render byte-for-byte as before.
@oh-my-pi/pi-utils
Added
- Added
postmortem.interceptUnhandledRejections()to register interceptors consulted before an unhandled rejection tears the process down; a consuming interceptor (e.g. the JS eval runtime claiming rejections floated by user cell code) keeps the process alive and owns reporting.
Fixed
- Fixed child shell environment filtering to drop launch-directory
.env.localvalues that Bun auto-loaded before OMP starts command shells. (#4723)
What's Changed
- Perf/memoize non message tokens by @H4vC in #4775
- fix(tui): dispose stale session UI renderers by @roboomp in #4693
- fix(agent): retry handoff auto-only tool choice errors by @roboomp in #4720
- fix(cli): stop exporting launch .env.local into commands by @roboomp in #4729
- fix(coding-agent): preserve literal bash internal URLs by @roboomp in #4738
- fix(agent): keep project sticky RULES active by @roboomp in #4742
- fix(Dockerfile): Do bun run gen:tool-views alongside gen:docs by @moutazhaq in #4743
- fix(tui): guard selector cursor symbol by @roboomp in #4746
- fix(catalog): preserve LiteLLM vision metadata by @roboomp in #4749
- fix(ai): keep assistant tool_use blocks trailing on Anthropic replay by @any-victor in #4782
- fix(plan): carry local artifacts into approve execute by @vmcall in #4785
- fix(coding-agent): resolve agent:// for nested subagent output by @any-victor in #4791
- fix(auth): rotate Codex credentials before provider fallback by @cagedbird043 in #4799
- Fix browser launch on Microsoft Edge installs by @qfrtt in #4804
- Fix JS eval worker cwd conflict handling by @cexll in #4839
- feat(coding-agent): recognize # as a GitHub issue/PR reference by @oldschoola in #3224
- fix(agent): emit session_switch for handoff by @roboomp in #4435
- fix(coding-agent): restore fallback model selection by @roboomp in #4535
- fix(pi-shell): pin spawn observer identity against Windows pid reuse by @roboomp in #4606
- fix(tui): hang wrapped box-drawing tree lines under their node text by @chan1103 in #4607
- fix(discovery): accept array-form Claude plugin manifest paths by @roboomp in #4610
- fix(coding-agent): refresh advisor on model role changes by @roboomp in #4613
- fix(coding-agent/edit): sealed inverse video and preserved gutters in wrapped diff rows by @chan1103 in #4616
- fix(tui): accept mid-prompt slash skill autocomplete by @roboomp in #4620
- fix(tools): prefer literal filesystem match over trailing
:selectorpeel by @roboomp in #4622 - fix(ai): recognize proxy stale-anchor codes for codex websocket previous_response chain by @roboomp in #4625
- fix(agent): support chat completions remote compaction endpoints by @roboomp in #4633
- fix: cramped slash autocomplete menu by @paralin in #4641
- fix(bash): support disabled command deadlines by @paralin in #4642
- fix(coding-agent): use local date in system prompt by @paralin in #4643
- fix(prompting): hide eval guidance when disabled by @paralin in #4644
- fix(coding-agent): guard pasted shell prompts from python by @roboomp in #4681
- Fix Azure Foundry Anthropic strict tools by @roboomp in #4682
- Fix legacy plugin JSON import validation by @roboomp in #4690
- fix(ai): accept response.done terminal event by @cexll in #4692
- fix(auth): prioritize login API keys over env fallbacks by @roboomp in #4694
- fix(catalog): restore LiteLLM bundled metadata fallback by @roboomp in #4701
- fix(coding-agent): hide marketplace temp clone paths by @roboomp in #4704
- fix: preserve status line path under overflow by @jeffscottward in #4728
- fix(coding-agent): scoped TTSR abort reason to matching tool call by @roboomp in #4542
- fix(ai): self-heal stale Codex usage-limit blocks by @joswha in #4844
New Contributors
- @moutazhaq made their first contribution in #4743
- @any-victor made their first contribution in #4782
- @paralin made their first contribution in #4641
Full Changelog: v16.3.11...v16.3.12