github can1357/oh-my-pi v15.10.0

2 hours ago

@oh-my-pi/pi-ai

Added

  • Added a dependency-free @oh-my-pi/pi-ai/effort module exporting the Effort enum and THINKING_EFFORTS, split out of model-thinking so hot-path consumers can import the thinking levels without pulling in model-thinking and 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 email and accountId in metadata, so the /usage display and the deduplicator can associate reports with their credentials.

  • Fixed usage-report dedup ignoring projectId for Google Cloud providers, preventing duplicate credential entries from being recognized as the same account.

  • Fixed Cloud Code Assist (Antigravity / Gemini CLI) rejecting the github tool with HTTP 400 when the pr parameter schema contained anyOf: [string, array]. The CCA mixed-type combiner collapse picked the first non-null type (string) but indiscriminately copied type-specific keys from variant branches — items from 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 placeholder function_call_output/custom_tool_call_output immediately after any unpaired function_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 thinking blocks. convertAnthropicMessages treated unknown endpoints as signature-enforcing and demoted unsigned reasoning to type: "text", which destabilized tool-call argument serialization on the next turn — the upstream symptom behind the args?.ops?.map is not a function crash reported against the todo tool. Official api.anthropic.com keeps the conservative text fallback; non-official anthropic-messages reasoning models now replay unsigned reasoning as native type: "thinking" (#2005).

@oh-my-pi/pi-coding-agent

Breaking Changes

  • Replaced the providers.parallelFetch boolean setting with the providers.fetch enum (auto / native / trafilatura / lynx / parallel / jina) that selects the URL reader-backend priority for the read/fetch tool, mirroring providers.image/providers.webSearch. Existing configs are migrated automatically: the legacy key is dropped and the new auto default applies.

Added

  • Added a GitHub Actions read handler to the read/web-fetch GitHub scraper. Fetching github.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 the actions/jobs/{id}/logs redirect using GITHUB_TOKEN/GH_TOKEN when 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 the task.maxRuntimeMs wall-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. runEvalAgent now passes maxRuntimeMs: 0 to runSubprocess, which honors an explicit ExecutorOptions.maxRuntimeMs override over the inherited setting.
  • Changed interactive timing behavior so PI_TIMING=x pi preloads the module timer before the CLI graph loads and includes the (modules) report. PI_TIMING=full now also exits after printing, matching PI_TIMING=x, so full module reports are usable for cold-start measurement without launching the TUI. Added the root dev:timing script for the same profiled startup path.
  • Changed coding-agent startup imports so normal TUI launch imports InteractiveMode directly, 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-free modes/setup-version module, 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-ai barrel: commands/launch.ts and cli/args.ts import THINKING_EFFORTS/Effort from the tiny @oh-my-pi/pi-ai/effort module, and config/model-registry.ts now 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/fetch HTML reader-backend priority to native > trafilatura > lynx > parallel > jina (was parallel > jina > trafilatura > lynx > native). The in-process native htmlToMarkdown runs 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 via providers.fetch tries it first, then the rest fall back. The low-quality gate (>100 chars and not isLowQualityOutput) now applies uniformly to every backend; when none clears it, the highest-priority substantial-but-low-quality output is still surfaced so the llms.txt / document-extraction fallbacks keep running.

Fixed

  • Fixed eval agent() failures surfacing as an opaque RuntimeError: bridge call '__agent__' failed with no reason. When a subagent aborted, runEvalAgent built its failure message with result.error ?? result.stderr ?? result.abortReason ?? …, but result.stderr is the empty string on a clean abort (and result.error is gated on a non-empty stderr), so the nullish chain stopped at "" and never reached abortReason. The empty string propagated through the loopback bridge and the Python prelude's RuntimeError(msg or "bridge call … failed"), discarding the real reason. The chain now uses || so an empty stderr falls through to abortReason.
  • 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). runSubprocess now prefers the aborted assistant message's errorMessage (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 streaming write (content streaming in) and a streaming eval (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. ToolExecutionComponent now implements isTranscriptBlockAppendOnly() (gated on isTranscriptBlockFinalized(), so it also covers partial-result streams like eval), delegating to a renderer-declared isStreamingPreviewAppendOnly predicate 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/fetch silently 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 empty Added/Changed sections; the native in-process renderer now runs first and preserves the full content.
  • Fixed /usage aggregate amount fallback using raw limits.length as account count — now counts unique accountId values from limit scopes, so N limits from a single account no longer display as "N accts".
  • Fixed /usage account labeling falling back to "account N" for providers that use projectId as their primary identity (e.g. Google Antigravity, Gemini CLI) — projectId from report metadata is now considered before the generic fallback.
  • Fixed the todo tool's TUI renderer crashing with TypeError: args?.ops?.map is not a function when a streaming tool-call delta surfaced a non-array ops field (mid-stream parseStreamingJson shapes like { ops: "[{" }, or [null] entries before fields arrive). The renderer now treats non-array ops, non-object entries, and non-array items as 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 in packages/ai (#2005).
  • Fixed Python eval agent() collapsing subagent runtime-limit aborts (and other empty-stderr aborts) into a generic RuntimeError: bridge call '__agent__' failed. runEvalAgent coalesced the failure message with ??, which stopped at the empty stderr and never reached abortReason, shipping an empty error through the loopback bridge. The bridge now prefers abortReason for aborts and trims empty stderr/error out 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_FEATURES Sy advertisement and WT_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. Added synchronizedOutputUserOverride() 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() (the PI_TIMING startup 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 and Total is no longer swallowed. Total is now labelled (since first marker) to make the window explicit. The restored module-timer.ts preload can feed module spans into the report: each module records onLoad → final top-level marker as total, a prepended body marker → final marker as body/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

Don't miss a new oh-my-pi release

NewReleases is sending notifications on new releases.