- Added an `isAnthropicAdaptiveGenAtLeast` utility to classify adaptive-thinking Claude generations at or above a given version threshold.
- Enabled adaptive thinking display, sampling restrictions, and mid-conversation system message flags for Claude Sonnet 5+ models.
- Updated Bedrock and OpenRouter adaptive reasoning effort maps to support five-tier scales on Sonnet 5+ models.
- Added a hidden system notice prompt to instruct the model to break repetitive behaviors when a thinking or response loop is detected.
- Injected the redirect notice into the retried turn's context when resetting the active context after a loop retry.
- Added unit tests to verify the custom redirect message is appended, configured as non-displaying, and visible in subsequent LLM contexts.
- Added comprehensive integration tests verifying Speech-to-Text submit triggers in STTController under different configuration settings.
- Cleaned up unused imports and types from the stt-controller source file.
- Documented Speech-to-Text submit trigger updates and programmatic editor submission changes in package changelogs.
- Added `stt.submitTrigger` setting to control automatic dictation submission.
- Introduced `evaluateSubmitTrigger` to process sentence punctuation and spoken cues.
- Integrated trigger evaluation into batch and streaming `STTController` pipelines.
- Implemented trailing word trimming to strip trigger words like "submit" before sending.
- Added comprehensive unit tests for all trigger evaluation behaviors.
- Renamed references to the `quick_task` subagent to `sonic` across docs, agent definitions, prompts, and test files.
- Updated the parallel file analysis tool to spawn `sonic` subagents instead of `quick_task`.
- Documented the breaking change in the changelog along with additions and removals of other built-in subagents.
The CPU profiler called node:v8 setFlagsFromString("--allow-natives-syntax")
unconditionally and crashed on Bun (oven-sh/bun#1702), surfacing as
"Failed to start profiler: node:v8 setFlagsFromString is not yet
implemented in Bun". The flag is only needed for ad-hoc V8 natives such
as %GetOptimizationStatus, not for the CDP Profiler session that actually
collects samples — so swallow the error and let the inspector path run.
Added a Bun-runtime regression test that would have caught the crash:
without the guard, startCpuProfile() throws before returning a session.
Fixes#3897
Esc and wizard abort signals now race the MCP OAuth login promise directly, so cancellation wins even before OAuthCallbackFlow reaches its callback wait and registers an abort listener. OAuthCallbackFlow also checks pre-aborted signals before opening/waiting on the callback server and its wait path handles already-aborted signals.
Threaded the abort signal into MCP OAuth fetches so dynamic client registration, metadata discovery, authorization probes, and token exchange unblock promptly when the user cancels.
Added a regression test where MCPOAuthFlow.login never observes ctrl.signal, matching the pre-wait race called out in review.
Fixes#3888
PR review pointed out that the unconditional opt-out blocks the safe case: when no static `client_id` is set, `MCPOAuthFlow.#tryRegisterClient` does DCR with whichever loopback URI we actually bound, so the provider issues a `client_id` tied to the fallback port and the authorize request is accepted. First-install users whose default port 3000 is busy could no longer authenticate.
Gate `allowPortFallback` on `staticClientIdFromConfig(config) === undefined`: pinned client ids (config-supplied or embedded in the authorization URL) keep the strict-port behavior that fixes#3887; unresolved client ids fall back as before. Factored the static client-id resolution into a module-level helper so `MCPOAuthFlow.#resolveClientId` and `resolveCallbackOptions` share the same logic.
Added an oauth-flow.test.ts case that wires a mock registration endpoint + occupies the preferred port and asserts the fallback URI is what DCR registers and what the authorize request advertises. Tightened the existing strict-port test's title to call out the static-clientId trigger.
#handleOAuthFlow now installs an editor.onEscape hook that aborts its
AbortController, and accepts an external abortSignal so the add-wizard
can thread its own controller through (the wizard owns focus and absorbs
Esc itself). Cancellation surfaces as MCPOAuthCancelledError, which the
reauth and add catches translate into a neutral status line instead of
the generic OAuth failure banner. Disambiguated from the existing 5-min
timeout via a userCancelled flag so timeouts still read as errors.
The wizard intercepts Esc/Ctrl+C while #oauthAbort is set so its own
"Press Esc to cancel" advertisement now matches the behaviour, and
renames its error heading + tip when the failure is a user cancel. Also
fixed the misleading "(Press Ctrl+C to cancel)" message in the chat
transcript onAuth block to say "Press Esc" — Ctrl+C is bound to the
editor clear action, not interrupt.
Fixes#3888
When the MCP OAuth callback server's preferred port (default 3000) was unavailable, `OAuthCallbackFlow.#startCallbackServer` silently bound a random port and forwarded the mismatched `redirect_uri` to the authorization server. Providers that validate redirect URIs against a registered callback (e.g. Atlassian) returned an opaque HTTP 500, leaving the local flow waiting for a callback that never arrived until the 5-minute timeout fired.
Added `OAuthCallbackFlowOptions.allowPortFallback` (default `true`, preserving every existing AI-provider flow) and threaded `allowPortFallback: false` through `MCPOAuthFlow`'s `resolveCallbackOptions`. With fallback disabled, login now throws a `ConfigurationError` that names the busy port and the remediation (free the port, or set `oauth.callbackPort`/`oauth.redirectUri` in `mcp.json`) before opening the browser. The existing `oauth.redirectUri`-strict path is reworded along the same lines so callers see one consistent message family.
Fixes#3887
- Added a last-resort recovery step to run `shake("elide")` on oversized message tails when auto-compaction cannot otherwise free enough context.
- Re-tests the context headroom and auto-continue predicates after a successful rescue before falling back to pausing maintenance.
- Updated the dead-end warning message to suggest running `/shake images` for irreducible, image-only tails.
ToolArgsRevealController.setTarget initialized new entries with revealed=0, so the first message_update returned { __partialJson: "" } even when the provider had already parsed a complete chunk. For renderers without exposeRawPartialJson (e.g. write), the throttled re-parse + cached displayArgs short-circuited every subsequent setTarget, leaving the preview body blank until tool_execution_end.
Seed revealed with the full incoming partialJson length on entry creation (clamped to a surrogate-safe boundary). The first frame now carries the parsed path/content immediately; subsequent message_updates extend target and the reveal ticks pace only the newly arrived bytes — no field is ever truncated because the seeded prefix is the longest the entry has seen so far.
Fixes#3881
fix(compaction): cap snapcompact frame payloads (#3866)
Bound rebuilt snapcompact image payloads by a per-request base64 byte
budget so long sessions stop re-sending multi-megabyte standing image
archives on every provider request; auto-compaction falls back to
context-full summaries when snapcompact output is too large.
Resolved snapcompact.ts conflict against the main font-rendering refactor
by keeping both renderabilityProbeText and the frame-budget helpers.
Fixed historyBlocks to emit the omitted-frame notice before the kept
(newer) images, since the byte budget drops the oldest frames — keeping
reconstructed blocks oldest-to-newest (addresses Codex P2 review).
Fixes#3792
- Added eight new Go-specific rules to the discovery package.
- Registered the new Go rules in the default rule source index.
- Covered the new Go AST matching conditions with test cases in `builtin-defaults.test.ts`.
Forwarded persisted provider stream timeout settings into model requests so slow local LLM streams can widen or disable first-event and idle watchdogs without environment variables.
Fixes#3878
Normalized string-encoded JSON arrays in grep/search path handling so direct execute paths match validated tool-call behavior.
Added regression coverage for direct GrepTool.execute paths supplied as a JSON-array-shaped string.
Fixes#3873
The yield tool's per-call schema validator was skipped entirely for incremental
yields (`type: ["<label>"]`), so when a subagent emitted a non-conforming value
for a known section (e.g. DeepSeek-v4-pro returning "Correct"/"correct."/"approved"
for the reviewer's `overall_correctness` enum), the call succeeded locally and
the model got no retry feedback. The mismatch only surfaced post-mortem in
`finalizeSubprocessOutput` as a fatal `schema_violation` — the parent agent
lost the entire result, with no recourse for the subagent to fix it.
Build a per-label sub-validator map alongside the full-schema validator: each
entry validates one section's `data` against its top-level property's sub-schema
(items schema for array-typed labels like `findings`). The yield tool runs this
map for incremental yields and routes failures through the same MAX_SCHEMA_RETRIES
budget the terminal path uses, so the model sees up to three corrective retries
and the existing schema-override safety net accepts the value with
SUBAGENT_WARNING_SCHEMA_OVERRIDDEN after exhaustion. Unknown labels remain
unconstrained so scratchpad/streaming sections still pass.
Fixes#3870
When legacy snapcompact archives exceed the per-request byte budget, retain frames from the newest end of the archived middle and restore oldest-to-newest order for the kept subset.
Apply the snapcompact frame byte-budget cap even when the active model has no known context window, avoiding 80-frame archives on custom vision models.
Bounded persisted snapcompact image archives by base64 byte size so large sessions stop re-sending multi-megabyte frame walls on every provider request.
Auto snapcompact now falls back to context-full summaries when rendered frame payloads exceed the byte budget, and legacy oversized archives omit over-budget frames during LLM context rebuilds.
Fixes#3792
- Updated the default browser User-Agent string to emulate a modern version of Chrome.
- Added typical browser headers to the outgoing fetch request, including Sec-Ch-Ua, Sec-Fetch flags, and Referer.
- Added a blank "b" parameter to the form body to match native DuckDuckGo HTML search behavior.
StdinBuffer held a bare `\x1b\x1b` chunk and timer-flushed it as one
sequence. `parseKey("\x1b\x1b")` returns undefined, so CustomEditor
fell through to the base editor and never fired the configured `onEscape` —
the double-escape gesture and the second-press single-Esc handler both went
dead whenever the terminal batched the two presses into one stdin read.
Split an exact bare `\x1b\x1b` into two ESC events only after the
flush window proves no follower arrived. If a follower does arrive, emit the
first ESC and restart parsing at the second ESC so legacy Alt chords
(`\x1bd`, `\x1b\x7f`) remain one downstream keypress. Meta-CSI/SS3
chords (`\x1b\x1b[A`, `\x1b\x1bO…`) still emit as one combined
sequence.
EventController.tool_execution_update re-armed the working loader when a
transient overlay (auto-compaction / auto-retry / handoff) had torn it down
mid-tool; tool_execution_end did not. A subagent (`task`) call only fires
_end, so a task result landing after such an overlay left the UI looking
idle even though the session was still streaming. Mirror the reconciler
call in #handleToolExecutionEnd.
Fixes#3857
`tool_execution_end` for a long-running tool (`task` subagent, async bash
poll, …) is the next streaming event on the parent session when an inner
transient overlay (auto-snapcompact, auto-context-full, auto-retry) nulled the
working loader between the tool's start and end. The overlay-end handlers are
the only loader restorers keyed off the missing reference; if the subagent's
`tool_execution_end` lands while the overlay is still active (or its end
handler errored before re-arming), the spinner stays gone for the rest of the
parent turn even though the agent keeps streaming.
`#handleToolExecutionEnd` now calls `#ensureWorkingLoaderWhileStreaming()`
at the top, mirroring `tool_execution_update` so the working loader survives
a subagent completing inside the overlay window.
Refs #3858
StdinBuffer held a bare `\x1b\x1b` chunk (or emitted it as one when followed by
a non-CSI byte). `parseKey("\x1b\x1b")` returns undefined, so CustomEditor
fell through to the base editor and never fired the configured `onEscape` —
the double-escape gesture and the second-press single-Esc handler both went
dead whenever the terminal batched the two presses into one stdin read.
Split a bare `\x1b\x1b` into two ESC events at the buffer layer, mirroring
the existing split for ESC + SGR mouse report. Meta-CSI/SS3 chords
(`\x1b\x1b[A`, `\x1b\x1bO…`) still emit as one combined sequence.
EventController.tool_execution_update re-armed the working loader when a
transient overlay (auto-compaction / auto-retry / handoff) had torn it down
mid-tool; tool_execution_end did not. A subagent (`task`) call only fires
_end, so a task result landing after such an overlay left the UI looking
idle even though the session was still streaming. Mirror the reconciler
call in #handleToolExecutionEnd.
Fixes#3857
- Migrated global service tier settings to a per-model-family architecture (OpenAI, Anthropic, Google).
- Implemented `ServiceTierByFamily` mapping to allow independent configuration and resolution per provider.
- Added automatic migration logic for legacy service tier and fast-mode application settings.
- Updated telemetry, session management, and task execution to support provider-specific tier resolution.