Print-mode assistant-error/aborted exit, RPC pi.shutdown() and stdin-EOF
shutdowns, and the extension command-context shutdown() called
process.exit() before (or racing) session.dispose(), skipping the bounded
browser reaper (releaseTabsForOwner) installed in dispose(). An OMP-owned
Chromium could survive the parent and reparent to PID 1.
Route all four graceful paths through the idempotent, promise-memoized
session.dispose() and await it before the final exit. The RPC
performShutdown no longer emits session_shutdown directly (dispose() emits
it), avoiding a double emit.
Fixes#5643
- restored capability reset import in agent-session refreshSkills
- fixed renamed credential entry reference in auth-storage org fields
- aligned xai web-search fetch mock and refresh-race test with current typings
`#recordAdvisorInterruptDelivered()` ran before the plan-mode and ACP-defer
preserve branches, so a blocker that was merely preserved (never interrupting
or starting a turn) still armed the post-interrupt immune window. With the
default `advisor.immuneTurns = 3`, the next three turns' concerns/blockers
were then downgraded to skip-idle-flush asides and could again be deferred.
Move the cooldown arm below every preserve branch so it fires only on the
actual steer/trigger path.
Fixes#5628
An idle ACP session sets `deferAgentInitiatedTurns`, so a steered terminal
blocker routed through `sendCustomMessage({ triggerTurn: true })` was buried
in `#pendingNextTurnMessages` instead of starting a turn — invisible and
deferred to the next user prompt, the exact regression #5628 avoids.
`#routeAdvice` now preserves the blocker as a visible card when a turn cannot
auto-trigger (idle + ACP defer without an explicit allow), folding the
existing plan-mode preserve branch into the same guard.
Fixes#5628
- Updated schema and runtime paths to use `dev.autoqaConsent` and `todo.remindersMax`, including auto-QA consent reads/persistence and todo reminder limit checks.
- Adjusted settings expectations so obsolete BM25-discovery keys were dropped on load and `tools.xdev` now kept its default unless explicitly set.
- Added/updated tests for the setting key migration and refreshed issue-consent flows, plus a new `refreshMCPTools` test for steered `xdev-mount-notice` updates without prompt rebuilds.
Instead of including the xd:// device inventory in the system-prompt signature, mount/unmount events now inject a steered `xdev-mount-notice` message so the system prompt (and its provider cache prefix) stays byte-stable across MCP connects and disconnects. Full device docs are picked up opportunistically on the next unrelated rebuild.
Also caps external (dynamic-mount) device descriptions to 200 chars in `docsAll` to prevent server-controlled prose from consuming prompt budget; built-ins keep their full curated docs, and `read xd://` always returns the untruncated text.
Legacy `discoveryMode: "off"` → `tools.xdev: false` migration is removed; the setting keeps its own default without inference from the deprecated key.
- Added the `xd://` virtual device protocol (`internal-urls/xd-protocol.ts`, `tools/xdev.ts`): tools declaring `loadMode: "discoverable"` are unmounted from the request tools array and driven via `read xd://` (list/docs+schema) and `write xd://<tool>` (execute), gated by the `tools.xdev` setting (default on) and inlined into the system prompt.
- Merged the `irc`, `job`, and `launch` tools into a single `hub` tool (`tools/hub/`, `async/job-manager.ts`): messaging keeps `send`/`inbox`/`list`, job control maps to `wait`/`cancel`/`jobs`, process supervision keeps `start`/`logs`/`stop`/`restart`/`describe` with `ps`, and the unified `wait` races background jobs against peer messages; SDK `IrcTool`/`JobTool`/`LaunchTool` are replaced by `HubTool`.
- Removed the hidden `resolve` tool in favor of the `xd://resolve`/`xd://reject`/`xd://propose` resolution devices, auto-including `write` whenever a deferrable tool or plan mode is present.
- Removed the BM25 tool-discovery system: the `search_tool_bm25` tool, the `tool-discovery` module, the `tools.discoveryMode`/`mcp.discoveryMode`/`mcp.discoveryDefaultServers`/`tools.essentialOverride` settings, per-tool MCP selection, and the `mcp_tool_selection` message type.
- Unified tool presentation on `ToolLoadMode` (`essential`|`discoverable`), replacing the custom-tool `xdev?: boolean` opt-out; custom, extension, MCP, RPC host, image-generation, and TTS tools now default to `discoverable`, and added a `satisfies` predicate to `SoftToolRequirement`.
- Removed the standalone `ssh` command tool and `ssh/ssh-executor` (the `ssh://` read/write/search protocol stays), and made `--tools` address hidden built-ins.
- Updated collab-web to render `xd://` dispatches and `hub` op families, dropped the `search_tool_bm25`/`ssh`/`report-finding` renderers, refreshed tool docs and prompts, and migrated the affected tests and changelogs.
- Renamed the system prompt's project-context section wrapper from `<context>` to `<repo-rules>` in `project-prompt.md`, so it no longer collides with the `task` tool's `context` parameter under in-band XML tool dialects.
- Updated `snapcompact-inline`'s context-section strip pattern to match `<repo-rules>`.
- Updated the `snapcompact-inline` test fixture to the new wrapper.
- Changelog entry for this rename rides with the fused device-migration commit (adjacent changelog lines).
Each tool-result turn now re-arms one text-only continuation while prewalk is pending. Consecutive prose replies without intervening tool progress terminate naturally, preserving multi-step plan detours without restoring the completion loop.
Fixes#5551
A prose plan and a bash-only completion are structurally identical after any pre-implementation tool detour, so the net now stays armed across every such turn and fires exactly once on the first text-only reply. This bridges read/record/bash detours before the plan while bounding a genuine no-edit completion to a single continuation instead of looping.
Fixes#5551
The continuation net now stays armed across a todo-only turn and disarms only when a non-planning tool runs without a prose plan, so the normal plan-nudge to todo to prose to edit flow still reaches implementation while a bash-only completion no longer loops.
Fixes#5551
Used centralized internal-URL detection so filesystem-only streaming edit work does not resolve ssh:// paths through the cwd.
Added a replace-mode regression covering controlled tool dispatch for an ssh:// path.
Fixes#5552
Limited the hidden continuation safety net to the assistant turn immediately following the plan nudge, so later bash-only completion ends normally.
Added regression coverage for commit-style flows that never call edit or write.
Fixes#5551
- Updated prewalk gating in `AgentSession` to key the todo gate on active tools instead of registry presence, so deactivated todo tools no longer block prewalk handoff.
- Changed subprocess tool filtering so `todo` is stripped for normal subagents but retained when prewalk is armed, and propagated the prewalk state through tool-session setup.
- Added regression tests for restricted active-tool slates and prewalk/non-prewalk subagent tool propagation to verify todo is handled correctly in each case.
wantsSnapcompact is true for both the default strategy and an explicit
/compact snapcompact mode override. The prior fix downgraded both to LLM
compaction, which silently shipped the transcript to a provider for users
who deliberately requested the local-only no-LLM archive path. Only the
default-configured strategy now falls back; explicit snapcompact keeps
failing locally. Added a regression test for the explicit path.
Fixes#5064
Switching from a vision model to a text-only model kept replaying
historical image content blocks to the new provider, which rejected them
with invalid_argument. The convertToLlm wrapper in sdk.ts only filtered
images when images.blockImages was set, never by model capability, so
the outbound request carried image blocks the active model could not
accept.
Add replaceLlmImagesWithText() to scrub image blocks out of the
already-converted LLM message view, and call it from the sdk wrapper
when the active model's input lacks "image". History on disk keeps its
images; only the provider request is scrubbed, and the check reads the
active model dynamically so a /model switch takes effect next turn.
Fixes#5400
A stalled or dropped provider stream that surfaces as stopReason:"error"
carrying the bare "Request was aborted" sentinel fell through both retry
gates: #isRetryableReasonlessAbort required stopReason:"aborted", and
#isRetryableError's classifier returns no retriable kinds for the generic
sentinel. The turn died immediately despite retry.enabled.
- Relaxed #isRetryableReasonlessAbort to accept an empty generic-abort
sentinel turn under stopReason "aborted" or "error", tagging it Abort so
#handleRetryableError retries it without model fallback.
- Kept the deliberate-abort guards intact: user interrupts and silent aborts
carry their own markers (not the generic sentinel), and #abortInProgress /
#isDisposed / #streamingEditAbortTriggered still settle without retry.
- Rewrote the stale fallback test that froze the buggy no-retry behavior to
assert retry-and-recover for the error-stop sentinel.
Fixes#5375
navigateTree() treated every custom_message entry as a re-editable user
turn, setting the leaf to the injection's parent and dumping the expanded
skill body into the editor. A /skill:<name> invocation is persisted as a
skill-prompt custom_message, so selecting it in /tree dropped the skill off
the active branch. Skip the parent-leaf/editor-prefill path for
skill-prompt entries so the leaf lands on the injection node itself.
Fixes#5374
- Added a Codex rate-limit parser for `x-codex-*` headers and registered it with the Codex usage provider.
- Updated auth-storage to require parsed usage headers before ingesting usage data, treated exhaustion as non-throttled, and renamed ranked candidate drain fields.
- Reworked key ranking math to use `headroom / remainingHours` with a 1-minute minimum, then applied measured-usage precedence with hot-window demotion behavior.
- Updated session handling and tests to support provider-aware header ingestion with deterministic, exhaustion-aware account selection.
Manual /compact with the snapcompact strategy hard-threw when the active
model lacked image input, unlike the auto-compaction path which downgrades
to LLM-backed compaction. Clear snapcompactReady instead of throwing so the
flow falls through to #compactWithFallbackModel (active text-only model
tried first for text->text summarization).
Fixes#5064
Per-line column cap trims individual lines with a `…` marker but does not
truncate the output window. OutputSink.dump() nonetheless set truncated=true
whenever a line was capped, and truncationFromSummary then reported a byte
tail-window truncation, appending a bogus "Showing lines X-Y of Z (…B limit).
Read artifact://N for full output" footer even though every line was shown.
- OutputSink no longer flips #truncated on column-cap-only drops.
- OutputSummary carries columnMax; truncationFromSummary surfaces it as the
"Some lines truncated to N chars" limit notice regardless of window state.
Fixes#4735
- Normalized completed image_generation_call results into assistant image blocks.
- Persisted image bytes through the session blob store and rendered them in live, replay, ACP, proxy, telemetry, and HTML paths.
- Added response normalization, persistence, and TUI rendering regressions.
Fixes#4768
- Added `tui.scrollbackRebuild` configuration with interactive startup/controller wiring to apply `setScrollbackRebuild`.
- Exposed prewalk session state in `SegmentContext` and rendered a dedicated prewalk segment/icon in the status line.
- Added divergence-aware TUI full-paint logic that enables scrollback erase-and-replay rebuilds for non-multiplexer divergence cases.
- Updated rendering and streaming tests to verify rebuild behavior (`3J`) and eliminate stale marker expectations under drift scenarios.