@oh-my-pi/pi-ai
Fixed
- Fixed Ollama/Ollama Cloud native chat responses that finish with
done_reason: "length"and no assistant content surfacing as a normal empty stop; they now become a context-window error instead of entering empty-stop retry recovery. (#3464) - Fixed direct Anthropic Claude Sonnet/Haiku 4.5 requests serializing
output_config.effort. The catalog classification (packages/catalog/src/model-thinking.ts) drove theanthropic-budget-effortbranch inbuildParams, which Anthropic's first-party Messages API rejects on Sonnet/Haiku 4.5 with HTTP 400This model does not support the effort parameter.Sonnet/Haiku 4.5 now use plainthinking.budget_tokens; Opus 4.5 still emitsoutput_config.effortbecause Anthropic supports it there. (#3497)
@oh-my-pi/pi-catalog
Fixed
- Fixed direct Anthropic Claude Sonnet/Haiku 4.5 advisor/agent turns crashing every call with HTTP 400
This model does not support the effort parameter.The catalog classified the whole Claude 4.5 family onanthropic-messages(andbedrock-converse-stream) asanthropic-budget-effort, which made the Anthropic provider serializeoutput_config.effortalongsidethinking.budget_tokens. Anthropic only honorsoutput_config.efforton Opus 4.5 and adaptive (4.6+) Messages-API models, so Sonnet 4.5 / Haiku 4.5 rejected the field.inferThinkingControlModenow gatesanthropic-budget-efforttoparsedModel.kind === "opus" && semverGte(version, "4.5")on both Anthropic-routed APIs, so Sonnet 4.5 / Haiku 4.5 on direct Anthropic + Cloudflare-AI-Gateway + Vertex + GitLab-Duo + Copilot + Bedrock fall through to plainmode: "budget"(thinking budget still scales with the selected effort tier). Opus 4.5 keepsanthropic-budget-effort.anthropic-budget-effortalso stays in use for Anthropic-compatible third-party backends that natively support the field (Umans GLM 5.2). (#3497)
@oh-my-pi/pi-coding-agent
Fixed
- Fixed Ctrl+Z hanging the terminal after any tool call had run: the TUI tore down (
ui.stop()) but the process kept running inSl+state, leaving the user with a dead terminal recoverable only viakill -9. The embeddedbrush-coreshell behind every bash tool call installs a tokio SIGTSTP listener onProcess::wait(crates/brush-core-vendored/src/sys/unix/signal.rs::tstp_signal_listener→tokio::signal::unix::signal(SIGTSTP)); per tokio's contract, the first call for a SignalKind permanently replaces the kernel-default handler for the lifetime of the process. So the first bash invocation — even/usr/bin/true— silently overrode SIGTSTP's "stop" default, andInputController.handleCtrlZ's subsequentprocess.kill(0, "SIGTSTP")was swallowed by tokio. The handler now sendsSIGSTOP(uncatchable, unblockable, unignorable) to the foreground process group, so the kernel parks omp regardless of installed handlers and the shell sees the whole job stop even when omp runs behind a wrapper (npx,pnpm exec,bunx, …) or as one stage of a pipeline. MCP stdio servers now spawn detached into their own session — they're insulated both from terminal job-control signals (which used to stop their process trees and leave the JSONL read loop blocked on silent pipes) and from the new pgid=0 suspend itself (#3461). - Fixed image-only composer submissions while the agent is streaming being treated as empty input, which dropped the image or aborted the active turn when another message was queued. Pending pasted images now count as submit content for Enter and Ctrl+Enter follow-ups. (#3467)
- Fixed
omp gallery --stateaccepting lifecycle tokens that did not match displayed state labels and rendering unknown state values as· undefined; displayed labels now work as aliases, invalid values fail with a valid-token list, and failed gallery fixtures visibly render failures. (#3473) - Fixed the bash tool's snapshotted
mise()shell function dying withcommand: command not found:because$__MISE_EXEwas empty in the replay shell.generateSnapshotScriptcaptured the function viadeclare -f/typeset -fbut only ever re-exportedPATH, so every other env var the rc file set (notably the*_EXEsidecarmise activateexports) was lost; the function body then expandedcommand "$__MISE_EXE" "$@"tocommand "" …and died with exit 127. The snapshot script now scans captured function bodies for$VAR/${VAR…}references and re-emitsexport NAME='value'for each referenced var that is currently set (with a denylist for shell-internal names likePATH/HOME/BASH_*/LC_*plus a likely-secret denylist for*TOKEN*/*SECRET*/*API_KEY*/*PASSWORD*/*PRIVATE_KEY*/*ACCESS_KEY*/*CREDENTIAL*/*SESSION_KEY*), the snapshot scriptumask 077s itself and the JS caller chmods the snapshot file/dir to0600/0700so the new export pass can't leak secrets into a shared tmp dir. Fixes mise, asdf shims, direnv-style helpers, and other activation idioms that pair a function with a helper env var.getShellConfigFilenow also honoursenv.HOME(falling back toos.homedir()) so sandboxed callers can target a non-default rc. (#3470) - Fixed concise
history://transcript rendering forfindandsearchso scopedpathsarguments are visible instead of being hidden behind JSON fallback output or omitted when a searchpatternis present. (#3482) - Fixed manual
/compactleavingsession.isCompactingfalse while active-turn abort teardown awaited, so the first steer/follow-up typed during compaction startup now routes through the compaction queue instead of being lost. (#3485) - Fixed ollama-cloud task/subagent fan-out exceeding the provider's three-request concurrency cap by adding a provider-specific subagent limiter, and let configured task/smol/advisor model roles inherit the default retry fallback chain when they do not define their own chain. (#3464)
- Fixed the per-provider subagent concurrency limiter (e.g.
providers.ollama-cloud.maxConcurrency) being replaced with a fresh semaphore whenever the configured limit changed, which orphaned the in-flight slots on the old instance and let a runtime or mixed limit value exceed the cap. The limiter now resizes a single shared semaphore in place — raising the ceiling admits queued waiters immediately, lowering it drains in-flight holders without admitting past the new cap. (#3464) - Fixed a background-task spawn slot leaking from the
task.maxConcurrencylimiter when progress reporting threw between acquiring the slot and entering the guarded run:markRunning/reportProgressnow run inside the try whosefinallyreleases the semaphore, so a failed progress report can no longer permanently shrink subagent concurrency. (#3464) - Fixed active goal runs that successfully call
yieldand then receive a trailing empty assistantstopskipping threshold compaction; post-yield empty-stop suppression now still anchors active-goal compaction on the yield-bearing assistant turn, so long-running tasks continue after maintenance instead of settling early.
@oh-my-pi/pi-tui
Fixed
- Recognized Warp (
TERM_PROGRAM=WarpTerminal) as a first-class terminal, enabling Kitty inline images on macOS/Linux while keeping Warp's unsafe OSC 8 hyperlinks and Windows Kitty graphics disabled (#3471). - Kept queued interrupt keys ahead of ordinary repaints so a slow long-transcript frame cannot consume the Ctrl+C/Esc double-press window before the second key is handled.
What's Changed
- fix(coding-agent): switched ctrl-z handler to SIGSTOP-self to defeat brush tokio SIGTSTP hijack by @roboomp in #3463
- fix(agent): handle ollama-cloud task backoff by @roboomp in #3466
- fix(tui): queue image-only streaming submissions by @roboomp in #3468
- fix(bash): re-export env vars referenced by snapshotted shell functions by @roboomp in #3474
- fix(tui): recognize Warp terminal capabilities by @roboomp in #3475
- fix(cli): align gallery state labels by @roboomp in #3477
- fix(coding-agent): surface transcript search paths by @roboomp in #3486
- fix(agent): queue input during manual compact startup by @roboomp in #3489
- fix(catalog): classify direct Anthropic Claude 4.5 as plain budget thinking by @roboomp in #3498
- Fix active goal compaction after yield stop by @cexll in #3428
- fix(tui): keep interrupts ahead of repaint by @cexll in #3465
Full Changelog: v16.1.19...v16.1.20