- Removed vim edit mode and automatically map existing vim configurations to hashline mode.
- Deleted VimTool class, VimEngine implementation, and all vim-specific editing logic (2409 lines).
- Removed vim mode from EditMode union type, edit tool strategies, and configuration schemas.
- Deleted vim parser, command handler, buffer manager, and renderer modules.
- Updated documentation and tests to remove vim mode references and add deprecation mapping.
- Added a `console.table` helper in the JS prelude that forwards calls to the runtime `__omp_table__` hook.
- Implemented `__omp_table__` in the runtime to render tables through `node:console.Console` and emit text via `onText`.
- Added tests verifying `console.table` produced formatted table output and respected the optional columns filter.
- Handled successful `main()` resolution by calling `process.exit(0)`.
- Preserved existing benchmark failure handling by logging the error and exiting with status 1.
Ignored the agent auth sentinel when selecting Bedrock bearer auth so AWS credential sources still use SigV4.
Added regression coverage for sentinel forwarding with AWS_BEARER_TOKEN_BEDROCK and static AWS credentials.
Fixes#1399
- Updated OpenAI completions compatibility to set `supportsDeveloperRole` only for OpenAI and Azure hosts.
- Added regression tests for host-specific `supportsDeveloperRole` defaults across OpenAI, Azure, and alternative providers.
- Added a Moonshot regression test confirming reasoning message conversion emits the system role.
Bedrock now sends AWS_BEARER_TOKEN_BEDROCK as Authorization: Bearer before resolving SigV4 credentials, so failing profile credential_process hooks cannot block bearer-token requests.
Added regression coverage for a default profile credential_process failure with AWS_BEARER_TOKEN_BEDROCK set.
Fixes#1399
- Updated Moonshot login validation to use a `models-endpoint` check instead of `chat-completions`.
- Changed the Moonshot key verification target to `https://api.moonshot.ai/v1/models` to avoid model-specific chat parameter validation failures.
- Added helpers to synthesize RawSseEvent records for inbound, outbound, and malformed Codex WebSocket traffic.
- Passed onSseEvent through websocket transport and stream setup so frames are forwarded to the raw-SSE debug pipeline during streaming.
- Added a stream test that verifies outbound and inbound websocket frames are emitted with SSE-style raw lines for the debug viewer.
- Updated hashline markers to `¶` headers and `^/v/->` operators across constants, prompts, docs, and tests.
- Reworked hashline grammar and parser to support `ANCHOR<SIGIL>[INLINE_PAYLOAD]` with optional inline bodies and `A-B` ranges.
- Changed range and marker syntax from `..`/`"` to `-` and suffix `^/v/->` forms like `7v` and `A->`.
- Aligned `sameLineRange()` output and BOF/EOF handling so `|TEXT` remains cosmetic and payload now follows the op line.
- Centralized op-line detection by replacing local regex helpers with `isHashlineOpLineText` for payload terminator and bad-op checks.
- Adjusted `#emitViewportRepaint` to use `viewportTop + height - 1` as the cursor target row instead of clamping to `lines.length - 1`.
- This kept `#cursorControlSequence` row-delta math consistent with the hardware cursor after blank padding rows, preventing the IME cursor from staying stuck at the viewport bottom on height-grow resizes.
- Added a regression test and terminal cursor accessor to verify the focused `CURSOR_MARKER` row remains active after terminal expansion.
- Expanded transient error matching for Bun HTTP2StreamReset, RefusedStream, and EnhanceYourCalm.
- Dropped thinking-only/error/aborted turns without text/toolCall, reset aborted tool-call map, and stored timestamps.
- Updated TUI render planning to track scrollback high-water and suppress suffix-scroll artifacts in non-multiplexer sessions.
- Added regression tests and changelog notes for Bun HTTP/2 retry handling, thinking-only filtering, and scrollback regressions.
- Added a custom JSON replacer that unwraps `Error` instances in logger output, preserving name, message, stack, cause, and enumerable fields.
- Updated uncaught-exception and unhandled-rejection logging paths to pass only `{ err }`, relying on the logger serializer for full error details.
- Extended transient socket-close matching to detect HTTP2 stream reset/refused/calm errors and added regression tests for logger error serialization behavior.
- Added shared timeout helpers in `sdk-stream-timeout` and removed duplicated inline stream timeout logic.
- Replaced inline provider timeout math with `resolveSdkTimeoutMs` and shared request-option builders.
- Added Codex websocket first-event and idle timeout settings via env-backed options.
- Updated Codex stream polling to apply per-phase time limits, return timeout errors, and fallback to SSE.
- Expanded `abortable-iterator` tests for preflight, in-flight, and leak cases around abort handling.
- Updated `streamFirstEventTimeoutMs` docs to document provider support and deprecated `streamIdleTimeoutMs`.
- Deleted the `ValidationVerdict` type and `evaluateOutputAgainstSchema` API from the output schema validator.
- Updated `yield.ts` to bind `buildOutputValidator`'s error directly to `schemaError` during validator setup.
- Removed the obsolete evaluator tests and adjusted validation success fixture to match the raw summary input shape.
Mapped streamFirstEventTimeoutMs onto OpenAI Responses request timeout options so explicit caller deadlines are not ignored after removing provider-stream watchdogs.
Fixes#1392
Checked provider abort signals at the start of each iteration so aborts fired between yielded stream events cannot be missed before the next iterator wait is armed.
Fixes#1392
Removed OMP-owned first-event and idle watchdogs from provider stream consumption while preserving caller abort handling. Updated provider stream tests to assert slow/silent streams wait for provider output or caller abort instead of surfacing watchdog errors.
Fixes#1392
- Unified output schema construction and validation by adding buildOutputValidator and using it in YieldTool and task executor.
- Added MAX_SCHEMA_RETRIES so YieldTool now retries schema failures three times with hints before overriding.
- Updated failure handling to use shared summarizeValidationFailure and formatters for required-field reporting.
- Added tests for output-schema-validator and YieldTool covering malformed schemas and nested-array retry edge cases.
Terminals clamp the hardware cursor to the visible viewport on resize, but TUI committed cursor rows from the prior geometry. Subsequent relative cursor moves (diff/shrink/append-tail) then wrote to wrong rows, producing duplicate or shifted content on screen. Clamp `prevHardwareCursorRow` to `prevViewportTop + height - 1` in each emitter that uses relative cursor math, and add a regression for height + content storms.
Fixes#1295
Centralizing OAuth refresh in AuthStorage (e6893515) introduced five
follow-on bugs surfaced by an audit of the commit; this fixes all of
them and updates the tests that relied on the old refresh seam.
1. packages/ai/src/auth-storage.ts (#tryOAuthCredential):
For built-in providers the path went directly to `getOAuthApiKey`
with the (possibly still-expired) selection.credential when the
pre-refresh at line 2587 caught a transient error. `getOAuthApiKey`
then threw the "expired … must be refreshed via AuthStorage"
precondition error, which the disable classifier matched against
`/expired.*refresh/` and soft-disabled the row. A single network
blip during refresh could permanently kill a still-valid Anthropic /
OpenAI / Gemini-CLI / Copilot credential. Built-in providers now
route through the broker-aware single-flighted
`#refreshOAuthCredential` first, so transient failures surface as
network errors (5-min temp block) instead of definitive auth
failures.
2. packages/ai/src/auth-storage.ts (#fetchUsageUncached):
The usage refresh check only fired once `Date.now() >= expiresAt`,
missing the 60-second skew that `getApiKey` honors. A token
expiring inside the skew window was posted to the usage endpoint
and 401'd mid-flight, briefly hiding quota in the UI. Aligned with
`OAUTH_REFRESH_SKEW_MS`.
3. packages/coding-agent/src/web/search/index.ts (webSearchCustomTool):
The CustomTool counterpart of WebSearchTool dropped sessionId so
SDK callers that opted into `web_search` via toolNames lost
per-session credential stickiness — multi-account users saw the
provider round-robin between searches in the same session. Threads
`ctx.sessionManager.getSessionId()` through to `executeSearch`.
4. packages/coding-agent/src/web/search/providers/perplexity.ts
(findOAuthToken):
`authStorage.getApiKey("perplexity")` returns runtime/config
overrides, stored api_key credentials, OAuth bearers, and env keys.
Filtering only env keys meant a config-pinned `pplx-…` API key was
POSTed to `www.perplexity.ai/rest/sse/perplexity_ask` (the OAuth
endpoint) instead of falling through to
`api.perplexity.ai/chat/completions`, producing 401s. Switched to
`getOAuthAccess` so only true OAuth bearers reach the OAuth
branch; api_key credentials/overrides correctly fall through.
5. packages/ai/scripts/generate-models.ts:
`getOAuthApiKey` was being called directly with possibly-expired
credentials. The new contract throws on expired, the broad catch
swallowed it, and the build silently fell back to bundled models
instead of refreshing. Both helpers now route through
AuthStorage's `getApiKey` / `getOAuthAccess`, which trigger the
full broker-aware refresh pipeline.
Test updates:
- auth-storage-credential-disabled-event.test.ts,
sdk-credential-disabled-bridge.test.ts: the `failOAuthRefresh`
helper used to spy on `getOAuthApiKey` to inject invalid_grant.
With refresh now happening before that helper, the spy never fired.
Switched to spying on `refreshOAuthToken` so the simulated failure
reaches the disable classifier.
- auth-storage-rotation.test.ts: stub `refreshOAuthToken` so the test
doesn't hit a real OAuth endpoint when the seeded credential lands
inside the 60s skew window.
- Handled the case where Anthropic sends a refusal/sensitive stop_reason but omits stop_details, previously falling through to a generic "unknown error."
- Added human-readable fallback messages per stop_reason type (refusal, sensitive, or raw value).
- Added test covering the null stop_details refusal scenario.
- Added optional per-provider fallback parameters to stream timeout helper functions so callers can widen default watchdog values safely.
- Threaded provider-specific lazy stream limits into stream creation and set Google Gemini CLI to a 300000ms first-event fallback by default.
- Added tests covering fallback defaults, env precedence, and global-default behavior for both idle and first-event timeouts.
Split `#doRender` into a planner plus one emitter per intent: `initial`, `sessionReplace`, `historyRebuild`, `viewportRepaint` (optionally prefixed with an append-to-scrollback), `shrink`, `diff`, `noop`. Cursor, viewport, and scrollback state now flow through a single `#commit` checkpoint at the end of every emitter.
Fixes#1295
Combined task.enableLsp with the parent session enableLsp gate before spawning subagents, so --no-lsp remains authoritative even when subagent LSP is enabled in settings.
Fixes#1385
Added task.enableLsp (boolean, default false) and routed both regular and isolated subagent dispatch through it. Keeps subagents cheap by default while letting users opt in to LSP-aware delegation. Updated regression tests to cover the default-off, opt-in, plan-mode, and isolated paths.
Fixes#1385
Subagents now inherit the parent session's enableLsp value, so a top-level --no-lsp invocation propagates into spawned tasks instead of falling back to the executor's default of true.
Fixes#1385
Removed the hardcoded subagent LSP disable flag so executor defaults and user settings control LSP availability. Passed the effective plan-mode agent definition into both regular and isolated subagent dispatch so plan-mode tool restrictions apply consistently.
Fixes#1385
- packages/ai/test/issue-957-repro.test.ts now tests:
- refreshKimiToken applies the 5-minute server-side skew (Kimi-specific)
- AuthStorage refreshes kimi-code credentials inside its 60s skew window
- packages/ai/test/anthropic-stream-timeout.test.ts: raise the
streamFirstEventTimeoutMs from 10ms to 5000ms so slow CI scheduling
cannot fire the first-event watchdog before the mocked events arrive.
The test still exercises the (1ms) idle path it was written for.
fix(web): allow Parallel extract via PARALLEL_API_KEY env var without storage
The fetch tool and YouTube scraper previously gated the Parallel extract
branch behind `storage && findParallelApiKey(storage)`. With no
AgentStorage the env key was never consulted, so callers that ran
without a per-session storage (e.g. ReadTool sessions in unit tests, and
in practice any caller that has only an env API key) silently fell back
to raw-html / no-ytdlp paths.
- findCredential/findParallelApiKey now accept null or undefined storage
and rely solely on the env-first path when no storage is supplied.
- searchWithParallel/extractWithParallel mirror the same nullable shape.
- Drop the redundant `storage && ` guards in fetch.ts and youtube.ts;
the inner findParallelApiKey call already returns null when no
credential is available.
Clear the viewport on the initial TUI paint so stale shell rows are not left onscreen. When a width change affects offscreen transcript rows, clear terminal history and replay the resized transcript so historical components do not remain in the old geometry.
Fixes#1295
When offscreen transcript changes require a viewport repaint in the same frame as appended output, emit the appended tail first so terminal history advances before repainting the visible rows.
Fixes#1295
- Centralized OAuth access lifecycle in `AuthStorage`, returning identity metadata and new access-result types.
- Added 60-second skew and strict expiry checks, returning undefined/throws for stale or expired OAuth credentials.
- Removed provider-local token refresh flows from Gemini, Gemini CLI, Antigravity, Kimi, and related OAuth helpers.
- Migrated web-search providers from `AgentStorage` to `AuthStorage` session-aware lookup with `authStorage`/`sessionId`/`signal` flow.
- Replaced `findAnthropicAuth`/DB auth lookup with `buildAnthropicAuthConfig` and explicit base-url override/env fallback ordering.
`ref` is a JTD-reserved keyword (RFC 8927) used by the schema-reference
form, so the JTD-to-JSON-Schema converter on releases prior to 15.3.2
silently dropped it from the generated JSON Schema and required it at
the same time. Every explore-agent invocation then failed validation
with `schema_violation: files.0.ref: must not be present`.
The converter side was hardened in #1345 (shipped in 15.3.2). This
rename is defense-in-depth at the prompt level: the explore agent's
output contract no longer relies on the converter recognising a
user-named property that collides with a JTD keyword, and the field
name now matches what it actually carries.
Fixes#1379
- Serialized image user content into Cursor root prompt history.
- Preserved image-only historical turns in Cursor conversation turn blobs.
- Added regression coverage for image-only history rebuilds.
Fixes#1376
- Encoded image-only Cursor user turns as userMessageAction with selected image context instead of resumeAction.
- Added regression coverage for image-only Cursor payloads.
Fixes#1376
- Sent Cursor resumeAction for empty or whitespace current user turns instead of throwing before the request was built.
- Added Cursor payload regression coverage for empty resume turns and normal user message turns.
Fixes#1376
- Added OpenAI Codex and Gemini web search provider options with updated setup/auth descriptions.
- Updated Codex OAuth flow to refresh near-expiry tokens during web_search and persist the refreshed credentials.
- Plumbed AgentStorage through search orchestrator, scrapers, and fetch paths so providers share session credentials.
- Refactored web provider and credential helpers to accept caller-provided AgentStorage and resolve keys synchronously.
- Updated `terminate_new_descendants` to require the `Sync` marker on its hash-set hasher.
- This tightened async helper bounds without changing its termination-wave logic.
Anthropic silently switched adaptive-thinking's display default to
"omitted" starting with Claude Opus 4.7, so the Bedrock provider
stopped surfacing any reasoning content — observed in the wild as
silent streams and timeouts on long reasoning runs.
Mirrors the existing direct-Anthropic behavior in this repo:
- For adaptive-thinking models that accept the field (Opus 4.7+),
emit { type: "adaptive", display: "summarized" } by default.
- For older adaptive-thinking models (Opus 4.6, Sonnet 4.6+) that
reject the field, keep emitting just { type: "adaptive" }.
- For budget-based Claude models, always set display.
- Expose BedrockOptions.thinkingDisplay ("summarized" | "omitted")
so callers can opt out, and wire hideThinkingSummary into the
bedrock-converse-stream case in stream.ts.
Fixes#1373