- Mark demoted thinking blocks with a symbol to decouple paragraph separators from the raw text content.
- Update `openai-completions` to conditionally insert a newline only when a demoted thinking block is followed by other content.
- Ensure terminal demoted thinking blocks are trimmed to prevent trailing whitespace that causes rejection by the Anthropic API.
- Added a test case to ensure brace-prefixed chunks remain with their original sibling tool call.
- Validated that parallel function call arguments are correctly routed to their respective tool call blocks.
- Implemented classifyJsonPrefix validation to determine when tool-call JSON chunks are complete.
- Updated delta processing logic to prevent premature chunk advancement by checking if a continuation remains valid or if it forms a distinct sibling call.
- Enabled transient 408, 429, and 5xx retries by removing manual `maxAttempts` overrides.
- Ensured transport retries respect deadlines by leveraging the first-event watchdog to abort the request `signal`.
- Guaranteed that retry backoff periods are bounded by the caller's request deadline.
- Updated authentication URL for the Wafer registry provider.
- Added support for the `retry-after-ms` header in `getRetryAfterMsFromHeaders` to parse millisecond-based retry delays.
- Implemented `parseRetryAfterMsHeader` utility to safely validate and convert header values to milliseconds.
- Updated `extractRetryHint` in `fetch-retry` to prioritize the `retry-after-ms` header during transport response processing.
- Included `x-ratelimit-reset-ms` header support in `extractRetryHint` to better handle rate limit reset timings.
Consulted the assistant provider payload before checking nativeHistory.replay so hidden-empty native turns suppress fallback re-encoding even when the session's native replay is still cold.
Extended the GitHub Copilot regression to cover the cold providerSessionState path.
Fixes#4597
Dropped signed thinking and empty assistant text fallback items when a native Responses payload is rejected as hidden-empty.
Extended the GitHub Copilot replay regression to cover synthesized empty TextContent and signed thinking fallback blocks.
Fixes#4597
Prevented GitHub Copilot OpenAI Responses turns with only hidden reasoning and empty assistant output from replaying native history into later requests.
Added regression coverage for hidden-empty assistant payloads preserving the follow-up user prompt while excluding stale reasoning and empty output_text items.
Fixes#4597
Cursor's model sometimes emits grepArgs with pattern="" and a non-empty glob, expecting grep to enumerate matching files. The downstream coding-agent grep tool then rejects it with a bare "Pattern must not be empty", but by then handleExecServerMessage's grepArgs case has already synthesized a persisted toolCall block whose pattern rendered as "?" in the TUI (grepToolRenderer uses `args.pattern || "?"`).
Handle the empty-pattern case at the Cursor exec dispatch instead: an exported pure helper (emptyGrepPatternRejection) returns an actionable, glob-aware error message; the dispatch turns that into a GrepResult.error and skips the synthesis + resolveExecHandler call entirely, so the model sees a specific recovery hint and the persisted assistant message stays clean.
Adds unit tests around the helper covering non-empty patterns, glob-aware rejection, plain rejection, and whitespace-only patterns; existing streaming/exec tests still pass.
Fixes#4574
- Kept the `isAzure` branch on the Responses `supportsStrictMode` field so
bundled `provider: "azure"` entries with an empty baseUrl (35 bundled
entries) still resolve strict-mode supported, matching pre-#4527 behavior
for every built-in Azure deployment.
- Added a regression asserting that a provider-id-only Azure Responses
model emits `strict: true` on the wire.
Refs #4527
- Switched buildOpenAIResponsesCompat to the shared OpenAI strict-mode
detector so buildModel-resolved Responses models no longer materialize
DeepSeek/Cerebras/Together-style OpenAI-compatible hosts to unsupported
while the completions path marks the same backend supported.
- Replaced the corrupted-compat regression with a buildModel-based DeepSeek
Responses regression that proves author-set strict:false survives through
the supported sparse-spec route.
- Updated the changelog to describe the resolved-compat path.
Fixes#4527
- Swap the pre-fix truthy `model.compat.supportsStrictMode` gate on
buildParams() for `!== false`, mirroring the semantic the completions
builder has been shipping since #4340. A caller-constructed Model that
hasn't materialized `supportsStrictMode` on its compat now behaves the
same way on both provider paths: author-set `strict: false` survives to
the wire, `supportsStrictMode: false` still suppresses it, and the
strict-schema fallback keeps unifying every wire flag to absent.
- Refresh the payload-emission comment to point at #4527 and describe the
aligned rule verbatim.
- Regression test: a Responses Model whose compat lacks
`supportsStrictMode` still emits `strict: false` on an author-opted-out
tool.
Fixes#4527
Made Codex account ids optional for openai-codex-responses custom providers, omitting chatgpt-account-id when opaque API keys cannot provide a ChatGPT account claim.
Added SSE and websocket regression coverage for custom Codex proxy API keys.
Fixes#4526
- Mocked messagePersistenceKey in event-controller-error-banner.test.ts and safe-guarded it in event-controller.ts to prevent TypeError.
- Updated thinking loop retry test expectations to handle new dynamic recoveredErrors structure.
- Updated schema version assertions in auth-storage-email-dedupe.test.ts to v5, preserving v6 for future schema test.
- Simulated scrollback commitment in event-controller-message-start.test.ts by rendering container and committing rows before advancing timers.