github can1357/oh-my-pi v15.10.5

latest releases: v15.10.7, v15.10.6
7 hours ago

@oh-my-pi/pi-agent-core

Removed

  • Removed the maxToolCallsPerTurn option from AgentOptions and AgentLoopConfig, so assistant turns are no longer capped after a configured number of completed tool calls

Fixed

  • Fixed stalled aborted assistant responses so the run now stops without waiting for provider iterator cleanup and returns the aborted message promptly
  • Fixed afterToolCall handling so it now runs for completed tool executions even after a run is aborted so tool post-processing still applies
  • Fixed agentLoopDetailed().detailed() so run telemetry and coverage are captured before stream.result() resolves.
  • Fixed agent-loop stream invariants so agentLoopContinue no longer mutates the caller's message array, emitted assistant events snapshot mutable provider content, terminal provider events win over late abort signals, transformed tool arguments are reflected consistently in hooks/events, and successful run-end telemetry fires from the same finalization path as failures.
  • Fixed tool result parsing to mark assistant tool outputs with unsupported content block shapes as errors and include a diagnostic text block
  • Fixed GPT-5 Harmony leakage handling by recovering valid leaked tool calls when possible and discarding leaked partial assistant output before retrying
  • Fixed tool-call cancellation handling so aborted tools are marked aborted with an explicit reason and do not report generic errors
  • Fixed tool-call completion so assistant messages on abort keep only completed tool-call blocks and continue processing tool calls when a length stop still included results
  • Fixed deliberate aborts (TTSR rule matches, user-interrupt labels) so a mid-stream tool-call block that never reached toolcall_end is retained on the aborted assistant message and paired with a placeholder result labeled by the abort reason, instead of being dropped; anonymous aborts (bare abort()) still drop incomplete tool calls whose partial arguments are unsafe to replay
  • Fixed runs that stopped with reason length after returning tool results so execution continues to handle additional tool calls

@oh-my-pi/pi-ai

Breaking Changes

  • Renamed the OAuth subpath export @oh-my-pi/pi-ai/utils/oauth@oh-my-pi/pi-ai/oauth (and @oh-my-pi/pi-ai/utils/oauth/*@oh-my-pi/pi-ai/oauth/*, e.g. oauth/types, oauth/callback-server, oauth/openai-codex) after relocating the OAuth implementation out of utils/oauth/ into registry/oauth/. The high-level OAuth API (getOAuthProviders, refreshOAuthToken, getOAuthApiKey, registerOAuthProvider, unregisterOAuthProviders, getOAuthProvider) and the OAuth* types stay exported from the package root, unchanged.

Changed

  • Changed Anthropic retry handling to avoid retrying 4xx responses other than 408 and 429
  • Optimized the Anthropic cch attestation patch to locate the billing-header placeholder with native Buffer.indexOf (memmem) instead of a hand-rolled byte loop. The marker sits ~99% through the body (messages serializes before system), so the old scan walked almost the entire payload; output bytes are unchanged but the patch is ~7.5x faster (563µs -> 75µs on a 1MB body).
  • Refactored provider configuration to a single-source registry (registry/, renamed from provider-registry/ with its providers/ subdir flattened up). The KnownProvider/OAuthProvider type unions, PROVIDER_DESCRIPTORS, DEFAULT_MODEL_PER_PROVIDER, the serviceProviderMap env-key fallbacks, the /login provider list (builtInOAuthProviders), and the refreshOAuthToken/AuthStorage.login dispatch are all derived from it. Provider defs live directly under registry/; thin provider-specific login flows are inlined into the def file, while heavier provider-local OAuth flows and the shared OAuth flow infra (callback-server, pkce, google-oauth-shared, types, runtime index) now live together under registry/oauth/ (previously split across provider-registry/providers/oauth/ and utils/oauth/). The non-OAuth API-key paste/validation helpers (api-key-login, api-key-validation) sit beside the defs in registry/. Adding a provider that reuses an existing wire API is now one new provider def plus one registry entry in the common case. Exposes PROVIDER_REGISTRY, getProviderDefinition, ProviderDefinition, and PASTE_CODE_LOGIN_PROVIDERS.

Fixed

  • Disabled OpenAI Codex Responses stream obfuscation by sending stream_options.include_obfuscation=false, reducing raw WebSocket/SSE debug noise and bandwidth.
  • Interrupted OpenAI Codex Responses streams that emit long runs of whitespace-only tool-call argument deltas, preventing degenerate WebSocket/SSE responses from filling the raw stream buffer indefinitely.
  • Preserved streaming responses when Anthropic emits unrecognized content_block envelopes by ignoring unknown blocks and continuing to emit known content
  • Applied cache control to the most recent tool result block when building Anthropic OAuth payloads without a preceding text block, enabling ephemeral caching for tool-result-only messages
  • Kept Anthropic sampling parameters (temperature, top_p, top_k) when thinking is explicitly disabled
  • Fixed raw Anthropic SSE handling by parsing event frames with strict JSON parsing and matching event-type validation, surfacing malformed frames as stream errors instead of repairing them
  • Fixed Anthropic stream envelope handling to reject duplicate content_block_start indexes and block deltas/stops for unopened blocks, preventing malformed envelope states from producing partial output
  • Fixed Anthropic image conversion to normalize image/jpg to image/jpeg and emit a placeholder for unsupported image MIME types
  • Fixed Anthropic thinking request preparation by clamping max_tokens to provider/model limits and adjusting thinking budgets to a valid value
  • Fixed Anthropic request shaping around forced tool choice, unsigned thinking replay, prompt-cache marker placement, non-Anthropic bearer gateways, Foundry TLS loading, and strict tool-schema normalization so malformed or incompatible request payloads are rejected locally or shaped consistently before streaming
  • Fixed the Anthropic stream parser shipping a truncated tool call as a completed turn. When a transport drop cut the SSE stream mid-tool_use and a transparent reconnect spliced a fresh message envelope onto the same stream, the duplicate message_start was deduped but the orphaned tool block — which never received its content_block_stop — survived in the assistant message with its seed {} (or partially-parsed) arguments. The terminal stop signal from the reconnect then let it flow through as a normal tool call, so e.g. a read dispatched with {} failed downstream validation (path: expected string, received undefined). The parser now treats any tool block left open at stream end as a truncated envelope and routes it through the existing retry/error path instead of emitting bogus arguments.
  • Fixed the Zhipu Coding Plan login prompt advertising a misleading sk-... placeholder. Zhipu API keys are formatted <id>.<secret> (no sk- prefix), so the placeholder now matches the actual format instead of suggesting the wrong shape. (#2106)
  • Fixed Moonshot kimi-k2.6 (and any future kimi-k2.x) discovered via MOONSHOT_API_KEY stalling on first turn with no output. The moonshotModelManagerOptions discovery mapper only marked ids containing "thinking" as reasoning: true, so dynamic kimi-k2.6 entries fell through with reasoning: false; the openai-completions z.ai branch was then skipped and the request reached Moonshot with no thinking parameter at all. Moonshot K2.6 requires an explicit thinking: {type} field (the same native-API wire shape #1838 introduced thinking.keep for), so the server held the stream silently. The mapper now stamps reasoning: true, vision input, and default thinking metadata on every kimi-k2.x id, restoring the explicit thinking: {type: "disabled"|"enabled"} wire body the Moonshot endpoint expects. (#2113)

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

Added

  • Added Homebrew and mise package-manager update paths to the self-update command so installations launched from those tools are updated through their native workflows
  • Added detection of Homebrew and mise install locations so self-update chooses the manager-specific updater when the active omp binary comes from a package-manager-managed path
  • Added astCondition to TTSR rule frontmatter as a syntax-aware alternative to regex condition, enabling AST-based matching for edit/write tool snapshots
  • Added a built-in ts-redundant-clear-guard rule that flags redundant guards around clearTimeout, clearInterval, and clearImmediate calls
  • Added a built-in ts-no-test-timers rule that flags real timers (Bun.sleep, setTimeout, setInterval) in *.test.ts files, steering toward fake timers (vi.useFakeTimers() / vi.advanceTimersByTime())
  • Added support for paste marker highlighting with accent styling ([Paste #N, +X lines]/[Paste #N, Y chars]) in the prompt editor, matching the visual treatment of image references
  • Added pixel dimensions to pasted/loaded image placeholders in the prompt — the marker now reads [Image #N, WxH] (falling back to [Image #N] when the header can't be decoded).
  • The bundled shell now treats nohup as a builtin: nohup … & runs the command without masking SIGHUP or detaching it, so agent-started daemons stay tied to this agent's lifetime instead of leaking as orphans when the agent exits. Updated the bash tool prompt's daemon guidance to match (dropped the nohup … & / setsid … & / disown detach recommendation in favor of a large timeout plus the persistent session).
  • Added per-tool tool.* theme symbol keys (nerd/unicode/ascii presets) plus a quiet status.done glyph, so each tool's result header can carry a signature icon instead of a generic status mark

Changed

  • Updated pi-ai OAuth imports to the renamed @oh-my-pi/pi-ai/oauth subpath (was @oh-my-pi/pi-ai/utils/oauth) across the login UI, MCP OAuth flow, model registry, setup wizard, and web-search Codex auth. The legacy-plugin specifier shim drops its pi-ai/oauthpi-ai/utils/oauth subpath rewrite, since the canonical @oh-my-pi/pi-ai/oauth export now resolves directly.
  • Changed forced self-updates for Homebrew installs to run brew reinstall and for mise installs to run mise install --force after mise upgrade when --force is requested
  • Changed TTSR rule bucketing and matching so rules with only astCondition are treated as TTSR rules and evaluated in the interrupt flow using reconstructed edit/write source snapshots
  • Normalized image content before it enters model context so attached images are downscaled and preprocessed for prompts, steering messages, follow-ups, and custom agent messages
  • Changed image marker format to include pixel dimensions when available ([Image #N, WxH]), falling back to bare [Image #N] when header cannot be decoded
  • Changed the prompt editor to highlight large-paste placeholders ([Paste #N, +X lines]/[Paste #N, Y chars]) with the same accent styling as image references (bold, no hyperlink), and to delete image/paste markers atomically: a single backspace or forward-delete removes the whole marker instead of leaving a broken [Paste #N, +X lines behind.
  • Browser tool helpers (tab.*) are now individually tracked and time-bounded: when a run cell hits its budget, the timeout error names the still-running helper(s) and how long each has been stalled (e.g. ... (stalled on tab.screenshot({ selector: ".x" }) (29.9s))) instead of the opaque Browser code execution timed out after 30000ms. Page-coupled helpers that should resolve quickly (observe, screenshot, extract) also fail fast with a named per-op error at min(cellBudget, 20s), leaving budget for the rest of the cell, rather than silently consuming the whole budget.
  • Derived the auth-broker OAuth callback ports (CALLBACK_PORTS) and the paste-code login-provider set from the @oh-my-pi/pi-ai provider registry, removing the duplicated CALLBACK_SERVER_PROVIDERS tables in the model selector and the setup-wizard sign-in scene.
  • Raised the eval tool's per-cell timeout ceiling from 600s to 3600s (matching bash), in both the Zod schema and the TOOL_TIMEOUTS.eval runtime clamp, so heavy local-compute cells can request budgets above 10 minutes.
  • Derived the auth-broker OAuth callback ports (CALLBACK_PORTS) and the paste-code login-provider set from the @oh-my-pi/pi-ai provider registry, removing the duplicated CALLBACK_SERVER_PROVIDERS tables in the model selector and the setup-wizard sign-in scene.
  • Reworked tool result-header glyphs to cut the overused success checkmark/dot: each tool now shows its own signature icon on success (terminal for bash, pencil for edit, magnifier/globe for search, plug for MCP, etc.; read keeps the read-group status dot), tools without a custom renderer fall back to a quiet status.done dot, and error/warning/pending states keep the universal cross/warning/spinner
  • Changed steady-state health indicators (LSP server ready, OAuth logged-in, plugin-doctor checks) from a success checkmark to a colored status.enabled dot, so failures stand out instead of every line reading as a check
  • Changed one-shot MCP/SSH/debug confirmation messages from a generic checkmark to contextual action glyphs (add/remove, connect/enable/disable toggles, reload, job-completed), reflecting what happened rather than just "success"
  • Derived the auth-broker OAuth callback ports (CALLBACK_PORTS) and the paste-code login-provider set from the @oh-my-pi/pi-ai provider registry, removing the duplicated CALLBACK_SERVER_PROVIDERS tables in the model selector and the setup-wizard sign-in scene.

Fixed

  • Fixed package subpath exports for status-line, setup-wizard, tool-discovery, and gallery fixture modules so rewritten test imports resolve through @oh-my-pi/pi-coding-agent.
  • Fixed runtime model provider discovery so extension-registered providers are now refreshed after extension load and extension-supplied models appear without restarting
  • Fixed task-row shimmer timing so every running description starts its highlight on the first character together and reaches the last character together, regardless of text length.
  • Fixed the eval tool's read/write/append helpers (both Python and JS backends) treating local:// (and other internal-URL) paths as plain filesystem paths. pathlib.Path/path.resolve collapse local://x.md to local:/x.md, so write("local://x.md", …) created a junk local: directory under the cwd instead of writing where read local://x.md resolves. The helpers now substitute injected on-disk roots for known schemes (currently local://, pinned to the session's own local:// root), reject path traversal and unknown scheme:// paths, and leave plain paths resolving against the cwd.
  • Fixed read and edit previews to surface the enclosing syntactic block's off-window boundary line (behind an ellipsis) when a shown line opens or closes a block whose other end falls outside the displayed range. Powered by a new tree-sitter enclosingBlockBoundaries native, so it covers brace languages and indentation languages (Python) using real syntactic spans, with a lexical bracket scan as fallback for unparseable sources.
  • Fixed tab.screenshot({ selector }) hanging for the entire cell budget on continuously-animating pages (WebGL / backdrop-filter "glass" effects). The element-screenshot path no longer routes through puppeteer's scrollIntoViewIfNeeded(), whose IntersectionObserver promise can stall indefinitely under heavy rendering; it now does a single instant scrollIntoView and captures with scrollIntoView: false (relying on captureBeyondViewport), so off-screen elements are still captured without the stall.
  • Fixed follow-up message submissions to forward pending clipboard-pasted images to session.prompt in both streaming and non-streaming flows
  • Fixed follow-up handling to clear consumed clipboard image state after submission so pasted images are not silently carried into later messages
  • Fixed clipboard-pasted images being rejected when steering or following up during compaction. Instead of bailing with "Retry after it completes to send images", the message and its images are now queued via queueCompactionMessage and forwarded to the session (steer/follow-up/prompt) when the compaction queue flushes.
  • Fixed edit tool result previews to show only current-file lines and collapse long inserted blocks instead of echoing removed content.
  • Fixed generateDiffString to omit the mid-skip ... placeholder between two nearby edits, conveying the elided gap via the jump in line numbers instead (consistent with how leading/trailing context skips already render). The placeholder row was indistinguishable from a genuine ... context line and wasted a row in compact previews.
  • Fixed concurrent interactive dialogs clobbering each other on the shared editor surface. ExtensionUiController presents the selector / input / editor modals by swapping a component into the single editorContainer and stealing focus, with no serialization — so a second select/input/editor request (from a hook, extension, the ask tool, or an internal flow) opened while one was already up would clear the container and re-focus, orphaning the first dialog. Its promise then hung until the caller's signal aborted (surfacing a stray Ask input was cancelled on top of the answered call). These modals are now serialized through #presentDialog: at most one shows at a time and the rest queue (FIFO); a queued request whose signal aborts before its turn resolves undefined and is never shown. The first dialog is still presented synchronously, so single-dialog timing is unchanged.
  • Fixed the ask tool potentially hanging when the model emitted two ask calls in one tool batch. ask now declares concurrency: "exclusive", so the agent loop serializes the batch and each question's selector runs to completion before the next starts, instead of racing for the shared selector surface.
  • Expanded @path/to/file import references in CLAUDE.md / AGENTS.md / GEMINI.md (and the other discovered context-file flavors) when loading them into the system prompt, matching the convention used by Claude Code, Goose, and other agents. Imports resolve relative to the importing file's directory, support ~/..., recurse up to 5 hops, and are skipped inside fenced code blocks and inline code spans so technical examples like npm install @types/node survive intact (#2111).

Removed

  • Removed the special Anthropic claude-opus-4-8 tool-call batch cap; sessions no longer abort an in-flight provider stream after a fixed number of completed tool calls.

@oh-my-pi/hashline

Added

  • Added maxAddedRunContext option to control how many added lines are shown at each side of collapsed inserted runs, with maxUnchangedRun kept as a backward-compatible alias

Changed

  • Changed buildCompactDiffPreview to omit removed lines from the preview while preserving removal counts for offset tracking
  • Changed buildCompactDiffPreview to collapse long contiguous added runs with a bare marker, keeping only the first and last maxAddedRunContext lines visible (the surrounding line numbers convey how many were elided)

Fixed

  • Fixed compact edit previews to omit deleted content, keep visible lines anchored to the current file, and collapse long inserted runs with a bare elision marker.
  • Fixed compact edit previews to render added/current lines without diff-prefix padding and normalize adjacent ASCII/Unicode elision markers to one .

@oh-my-pi/pi-natives

Added

  • Added the enclosingBlockBoundaries native API (with EnclosingBoundaryOptions and LineRange types) that returns, for a set of visible line ranges, the off-window boundary lines of every multi-line tree-sitter node whose span crosses the window — the closer when an opener is shown and the opener when a closer is shown. Covers brace and indentation languages (Python) via real syntactic spans; returns null for unrecognized languages or sources with syntax errors so callers can fall back to a lexical scan.
  • Added a nohup shell builtin to the embedded pi_shell, shadowing the external /usr/bin/nohup. It runs its operand command and propagates that command's exit status (and reports missing operand / exit 125 with no operand), but deliberately does not mask SIGHUP or detach the child into a new session the way real nohup does. Agents reach for nohup … & assuming the shell is one-shot; in this persistent embedded shell that assumption is wrong and the only effect of real nohup was to leak background processes that outlived the host. The builtin keeps such commands as ordinary descendants so they are reaped with the host instead of surviving as orphans.

@oh-my-pi/pi-tui

Added

  • Added atomicTokenPattern to Editor: when set to a global regex matching placeholder tokens such as [Image #1, 800x600] or [Paste #2, +30 lines], a single backspace or forward-delete landing anywhere on a token removes the whole token instead of corrupting it into stray text.

Changed

  • Changed the large-paste placeholder label from [paste #N +X lines]/[paste #N Y chars] to [Paste #N, +X lines]/[Paste #N, Y chars].

Fixed

  • Fixed pasting large text lagging the prompt for hundreds of milliseconds before the [paste #N …] placeholder appeared. StdinBuffer assembled bracketed pastes by re-concatenating and re-scanning the entire accumulated buffer on every incoming stdin chunk (#pasteBuffer += chunk; indexOf(END)), which is O(n²) in the paste size and dominates when the terminal/PTY delivers the paste in many small reads (SSH, tmux, slow hosts) — a 1 MB paste at 1 KB chunks cost ~33 ms and 5 MB ~740 ms. Chunks are now collected in an array and joined once when the end marker arrives, with a short overlap tail carried across chunk boundaries so a marker split between two reads is still detected without rescanning, making assembly O(n) (~1 ms for 5 MB). The Editor paste cleaner also dropped its split("").filter().join("") per-code-unit array allocation in favor of a single control-character regex pass (~20× faster on large pastes).

What's Changed

  • fix(ai): corrected misleading Zhipu API key placeholder by @roboomp in #2107
  • fix(coding-agent): expand @-imports in AGENTS.md / CLAUDE.md context files by @roboomp in #2112
  • fix(ai): mark moonshot kimi-k2.x as reasoning + vision during discovery by @roboomp in #2114

Full Changelog: v15.10.4...v15.10.5

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

NewReleases is sending notifications on new releases.