@oh-my-pi/pi-ai
Added
- Added a dependency-free
@oh-my-pi/pi-ai/effortmodule exporting theEffortenum andTHINKING_EFFORTS, split out ofmodel-thinkingso hot-path consumers can import the thinking levels without pulling inmodel-thinkingand its provider-compat dependency graph. The package barrel still re-exports both names, so existing imports are unaffected.
Fixed
-
Fixed Antigravity usage provider emitting one bar per model instead of deduplicating by tier — a single account's 15+ model entries now collapse to one bar per tier, matching the shared-quota reality of the upstream API.
-
Fixed Antigravity usage reports missing
emailandaccountIdin metadata, so the/usagedisplay and the deduplicator can associate reports with their credentials. -
Fixed usage-report dedup ignoring
projectIdfor Google Cloud providers, preventing duplicate credential entries from being recognized as the same account. -
Fixed Cloud Code Assist (Antigravity / Gemini CLI) rejecting the
githubtool with HTTP 400 when theprparameter schema containedanyOf: [string, array]. The CCA mixed-type combiner collapse picked the first non-null type (string) but indiscriminately copied type-specific keys from variant branches —itemsfrom the array variant leaked onto the string-typed result, producing{type: "string", items: {...}}which Google's API rejects as invalid. The collapse now filters merged variant fields against the winning type's allowed key set. (#2002) -
Fixed OpenAI Responses-family providers (Codex, OpenAI Responses, Azure Responses) rejecting requests with
400 No tool output found for function call …after the user branched/navigated the session tree to a node that ends on a tool call (the tool-result child is dropped from the reconstructed history) or after a turn was aborted/crashed between the call streaming and its result persisting. The converters now synthesize a placeholderfunction_call_output/custom_tool_call_outputimmediately after any unpairedfunction_call/custom_tool_call, symmetric to the existing orphan-output repair, so the model still sees the call and can recover instead of the whole request 400ing. -
Fixed Anthropic-compatible reasoning endpoints losing prior-turn reasoning on continuation requests when they emit unsigned
thinkingblocks.convertAnthropicMessagestreated unknown endpoints as signature-enforcing and demoted unsigned reasoning totype: "text", which destabilized tool-call argument serialization on the next turn — the upstream symptom behind theargs?.ops?.map is not a functioncrash reported against thetodotool. Officialapi.anthropic.comkeeps the conservative text fallback; non-officialanthropic-messagesreasoning models now replay unsigned reasoning as nativetype: "thinking"(#2005).
@oh-my-pi/pi-coding-agent
Breaking Changes
- Replaced the
providers.parallelFetchboolean setting with theproviders.fetchenum (auto/native/trafilatura/lynx/parallel/jina) that selects the URL reader-backend priority for theread/fetchtool, mirroringproviders.image/providers.webSearch. Existing configs are migrated automatically: the legacy key is dropped and the newautodefault applies.
Added
- Added a GitHub Actions read handler to the
read/web-fetch GitHub scraper. Fetchinggithub.com/{owner}/{repo}/actions/runs/{id}renders the run metadata plus a per-job breakdown (steps listed for any job that did not succeed), and…/actions/runs/{id}/job/{id}(also the API-style…/jobs/{id}) renders a single job's metadata, step table, and full plain-text logs. Logs are fetched via theactions/jobs/{id}/logsredirect usingGITHUB_TOKEN/GH_TOKENwhen present, with the per-line ISO timestamp prefix and leading BOM stripped; the section degrades to an explicit notice when logs are unavailable (no token, private repo, or expired/unfinalized run).
Changed
- Changed eval
agent()subagents so they are never subject to thetask.maxRuntimeMswall-clock cap. The parent cell's idle watchdog is already suspended for the entire bridge call (withBridgeTimeoutPause), so a long-running fan-out/recovery workflow must not be killed by a per-subagent runtime limit.runEvalAgentnow passesmaxRuntimeMs: 0torunSubprocess, which honors an explicitExecutorOptions.maxRuntimeMsoverride over the inherited setting. - Changed interactive timing behavior so
PI_TIMING=x pipreloads the module timer before the CLI graph loads and includes the(modules)report.PI_TIMING=fullnow also exits after printing, matchingPI_TIMING=x, so full module reports are usable for cold-start measurement without launching the TUI. Added the rootdev:timingscript for the same profiled startup path. - Changed coding-agent startup imports so normal TUI launch imports
InteractiveModedirectly, keeps print/RPC/ACP runners on their branch-only paths, and moves marketplace auto-update work behind a lightweight deferred starter. - Changed cold-launch setup gating so the full setup wizard (every scene plus the overlay and their TUI/OAuth/web-search/theme dependencies) is no longer statically imported by
main.ts. The current setup version now lives in a tiny dependency-freemodes/setup-versionmodule, and the wizard barrel is lazy-loaded only when the stored setup version is stale or the wizard is forced — the common up-to-date launch skips loading it entirely. - Changed cold-launch startup imports so the hot-path CLI files no longer pull the full
@oh-my-pi/pi-aibarrel:commands/launch.tsandcli/args.tsimportTHINKING_EFFORTS/Effortfrom the tiny@oh-my-pi/pi-ai/effortmodule, andconfig/model-registry.tsnow imports its ~20 symbols from narrow subpaths (api-registry,model-cache,model-manager,model-thinking,models,provider-models,types,utils/event-stream) instead of the barrel — so launching no longer eagerly loads every provider, auth, OAuth, and usage module re-exported by the barrel. - Changed the
read/fetchHTML reader-backend priority tonative > trafilatura > lynx > parallel > jina(wasparallel > jina > trafilatura > lynx > native). The in-process nativehtmlToMarkdownruns first — instant, no network, full-fidelity — so the common case no longer depends on a remote service, and a stalled remote backend can no longer mask it. Selecting a specific backend viaproviders.fetchtries it first, then the rest fall back. The low-quality gate (>100chars and notisLowQualityOutput) now applies uniformly to every backend; when none clears it, the highest-priority substantial-but-low-quality output is still surfaced so thellms.txt/ document-extraction fallbacks keep running.
Fixed
- Fixed eval
agent()failures surfacing as an opaqueRuntimeError: bridge call '__agent__' failedwith no reason. When a subagent aborted,runEvalAgentbuilt its failure message withresult.error ?? result.stderr ?? result.abortReason ?? …, butresult.stderris the empty string on a clean abort (andresult.erroris gated on a non-emptystderr), so the nullish chain stopped at""and never reachedabortReason. The empty string propagated through the loopback bridge and the Python prelude'sRuntimeError(msg or "bridge call … failed"), discarding the real reason. The chain now uses||so an emptystderrfalls through toabortReason. - Fixed subagent aborts being mislabeled as the generic "Cancelled by caller" when the abort originated inside the subagent's own turn (
stopReason: "aborted"with no caller signal and no runtime-limit timer).runSubprocessnow prefers the aborted assistant message'serrorMessage(e.g. "Request was aborted" or a specific stream error) for that case, while a real caller signal or wall-clock abort still reports its precise reason. - Fixed a long streaming tool preview that alone overflows the viewport dropping its scrolled-off head on ED3-risk terminals (ghostty/kitty/iTerm2/…). When expanded with
Ctrl+O, a streamingwrite(content streaming in) and a streamingeval(stdout streaming below its fixed code cell) render top-anchored and grow append-only, but the tool block never reported itself append-only to the transcript, so the renderer's commit-as-you-go boundary stopped at the block start and the earlier rows that scrolled above the viewport were committed nowhere — they vanished, leaving the preview looking like a viewport-tall circular buffer.ToolExecutionComponentnow implementsisTranscriptBlockAppendOnly()(gated onisTranscriptBlockFinalized(), so it also covers partial-result streams likeeval), delegating to a renderer-declaredisStreamingPreviewAppendOnlypredicate so the expanded stream commits its head exactly like a streamed assistant reply. Collapsed previews (bounded sliding tail windows) and finalized/result previews (which can collapse to a capped view) stay deferred. - Fixed
read/fetchsilently dropping whole list sections on pages with malformed list markup — stray<img>, text, or<video>nodes as direct children of<ul>(e.g. the Alacritty changelog). The Jina reader (previously tried before the local renderers) mis-extracts such lists, returning emptyAdded/Changedsections; the native in-process renderer now runs first and preserves the full content. - Fixed
/usageaggregate amount fallback using rawlimits.lengthas account count — now counts uniqueaccountIdvalues from limit scopes, so N limits from a single account no longer display as "N accts". - Fixed
/usageaccount labeling falling back to "account N" for providers that useprojectIdas their primary identity (e.g. Google Antigravity, Gemini CLI) —projectIdfrom report metadata is now considered before the generic fallback. - Fixed the
todotool's TUI renderer crashing withTypeError: args?.ops?.map is not a functionwhen a streaming tool-call delta surfaced a non-arrayopsfield (mid-streamparseStreamingJsonshapes like{ ops: "[{" }, or[null]entries before fields arrive). The renderer now treats non-arrayops, non-object entries, and non-arrayitemsas missing structure instead of crashing, which also stops the spam-warn cascade that followed each malformed delta. Paired with the Anthropic-side reasoning-replay fix inpackages/ai(#2005). - Fixed Python eval
agent()collapsing subagent runtime-limit aborts (and other empty-stderr aborts) into a genericRuntimeError: bridge call '__agent__' failed.runEvalAgentcoalesced the failure message with??, which stopped at the emptystderrand never reachedabortReason, shipping an empty error through the loopback bridge. The bridge now prefersabortReasonfor aborts and trims emptystderr/errorout of the fallback chain, so Python surfaces the actionable reason (e.g.Subagent runtime limit exceeded (task.maxRuntimeMs=900000)) (#2006).
@oh-my-pi/pi-tui
Changed
- Reworked the DEC 2026 synchronized-output default policy: a positive DECRQM mode-2026 report now enables sync (previously a report could only disable it), so conservatively defaulted-off hosts that actually support it — current Zellij, tmux master, foot, contour, mintty — are upgraded at runtime. The static allowlist also covers Alacritty and the VS Code terminal, honors a
TERM_FEATURESSyadvertisement andWT_SESSION(Windows Terminal / WSL), and no longer blanket-disables SSH (DEC 2026 passes through to the outer terminal). Risky multiplexers still start off and rely on the probe. AddedsynchronizedOutputUserOverride()as the shared opt-out/force resolver.
Fixed
- Fixed WSL/Windows Terminal row flicker while typing by repainting changed text rows before clearing only their stale suffix (#2011).
- Fixed terminals that support DEC 2026 still tearing/flickering because the renderer ignored a positive DECRQM capability report and kept synchronized output off — most visibly WSL + Windows Terminal, Alacritty (≥0.13), and the VS Code terminal (≥1.108), which were detected yet refused sync.
@oh-my-pi/pi-utils
Changed
logger.printTimings()(thePI_TIMINGstartup tree) now surfaces two previously-invisible regions: a(before instrumentation)line for runtime init / uncaptured pre-marker work, and an(unattributed self)line for the root span's own untimed work so the gap between visible top-level spans andTotalis no longer swallowed.Totalis now labelled(since first marker)to make the window explicit. The restoredmodule-timer.tspreload can feed module spans into the report: each module recordsonLoad→ final top-level marker astotal, a prepended body marker → final marker asbody/TLA, and resolved static imports as a bounded dependency tree so the report separates graph wait from actual top-level module work.
What's Changed
- fix(ai): strip type-specific keys when CCA mixed-type collapse picks non-matching type by @basedcorp99 in #2002
- fix(usage): sanitize Antigravity /usage display — dedupe by tier, fix account count, merge window data by @basedcorp99 in #2004
- fix(coding-agent): harden todo renderer against malformed streaming args by @roboomp in #2007
- fix(eval): surface subagent abort reason through Python agent() bridge by @roboomp in #2008
- docs(web-search): updated kagi description to v1 endpoint by @roboomp in #2010
- fix(tui): reduce WSL row flicker while typing by @roboomp in #2012
- fix(debug): wait for dlv unix socket before connecting by @roboomp in #2014
Full Changelog: v15.9.69...v15.10.0