Interrupting the model during its visible output produced an assistant turn
whose thinking block had already finished streaming (fully signed) followed
by partial text. `transformMessages` stripped the signature from every
thinking block of an aborted/errored turn, so the valid signature was
replayed empty (`signature: ""`) and signature-enforcing Anthropic
rejected the next request with HTTP 400 "Invalid `signature` in
`thinking` block" — including when routed through an LLM gateway baseUrl.
Anthropic delivers a block's signature at `content_block_stop` before the
next block's `content_block_start`, so a thinking block followed by
text/tool_use is necessarily complete and valid. Only the single mid-stream
block at the abort point can hold a partial signature. Strip just that
final block now; completed thinking blocks keep their replayable
signatures. Abandoned end_turn+tool_use turns are unchanged (all their
signatures remain stripped).
Co-authored-by: DeprecatedLuke <16418011+DeprecatedLuke@users.noreply.github.com>
Fixes#2144
The auth-gateway client now sends `${provider}/${id}` (008981112) and the
gateway registry keys on the qualified id first. Update the stale request-shape
assertion that still expected the bare `claude-sonnet-4-5`.
On kitty (Linux/Wayland) and any terminal supporting OSC 5522 enhanced
paste, the /login API-key prompt for OpenCode Zen — and any other modal
Input prompt (Perplexity OTP, GitHub Enterprise URL, manual OAuth
redirect URL, …) — silently dropped pasted content. The user could not
paste their API key; on Enter or Esc the key surfaced in the main
prompt.
Cause: InputController.#setupEnhancedPaste enables kitty's enhanced
clipboard protocol on TUI start and consumes the resulting OSC 5522
packets in an addInputListener that runs *before* focus dispatch in
tui.#handleInput. The controller's pasteText callback then routed
unconditionally to this.ctx.editor.pasteText(text) — the main
CustomEditor — even when selector-controller had cleared editorContainer
and focused a temporary Input. The text accumulated in the detached
editor and only resurfaced when the modal was dismissed.
Fix:
- TUI.getFocused() exposes the currently focused component.
- Input.pasteText(text) mirrors Editor.pasteText so any Input can absorb
a payload from a non-bracketed transport.
- InputController's enhanced-paste callback consults getFocused() and
routes text to the focused component when it exposes pasteText,
falling back to the editor only when no modal target is in focus.
- Image pastes refuse with a status message when a modal Input is
focused, instead of stuffing a binary blob into the hidden editor.
Regression tests in packages/tui/test/input.test.ts and
packages/coding-agent/test/issue-2127-repro.test.ts pin both the new
TUI/Input contract and the InputController routing source.
Fixes#2127
Inside tmux/screen/zellij, rewinding/branching after a streamed reply had
grown past the viewport permanently anchored the input box to the pane
top: every subsequent frame repainted the visible viewport blank and
parked the cursor at screen row 0.
`requestRender(true, { clearScrollback: true })` dispatches the
`sessionReplace` intent, which re-emits the entire transcript through
`#emitFullPaint` with `options.clearScrollback === false` inside
multiplexers (ED 3 is a no-op in pane history). `#emitFullPaint` only
reset `#scrollbackHighWater` inside the `clearScrollback` branch and
otherwise raised it monotonically (`if (pushedNow > #scrollbackHighWater)`),
so the high-water from the pre-rewind streaming peak survived the
shrink. On the next frame `#planLiveRegionPinnedRender` saw
`#scrollbackHighWater` far above the new natural viewport top, computed
`renderViewportTop` past the actual content, and `#emitLiveRegionPinnedRepaint`
clamped `viewportTop` to `lines.length` — writing eight empty viewport
rows and parking the cursor at screen row 0.
A full repaint with `clearViewport: true` physically re-emits the entire
transcript from row 0, so the rows committed to native scrollback by that
paint are exactly `max(0, lines.length - height)` regardless of whether
ED 3 cleared pre-paint scrollback. Mirror the existing `#maxLinesRendered`
pattern and assign instead of monotonic-max so the renderer's bookkeeping
matches the freshly painted transcript in both mux and non-mux modes.
Fixes#2130
Threshold-driven auto-compaction with strategy=shake auto-continued even when
the shake reclaimed nothing material, and the next agent turn re-triggered the
same shake (which had nothing new to drop on a second pass), spinning forever.
After shake completes, recompute the post-shake context estimate; when it
still exceeds the auto-compact threshold (or shake reclaimed nothing on overflow
recovery), emit a one-shot fallback warning and hand off to the summarization
driven context-full path so progress actually resumes. Idle is exempt — its
60s+ timer self-throttles and cannot dead-loop on its own.
Fixes#2119
Rendered the MCP OAuth fallback as a short terminal hyperlink plus a single unwrapped copy URL line so terminals do not receive hard-broken authorization URLs.\n\nFixes #2121
Skill prompt custom messages now scan user-authored skill args for magic keywords and turn budgets, matching normal prompt steering behavior without scanning skill body text.
Added a regression test for workflowz and hard turn-budget args on skill prompts.
Fixes#2128
- In _run_rpc_blocking, added a check for an assistant_message stopReason after timeout handling.
- When stopReason is "error", the worker now reads errorMessage (or a default message) and raises a RuntimeError.
- Updated PI native streaming requests to send model identifiers as provider-qualified keys.
- Updated the auth-gateway model registry to store `${provider}/${id}` first and retain legacy bare IDs as fallback keys.
- Added an `openPlanReview` flow that selected the newest `local://<slug>-plan.md`, resolved its title, and reopened approval.
- Registered a new `/plan-review` builtin slash command that invokes that flow and clears the editor text.
- Added tests covering latest-plan selection plus warnings when plan mode is inactive or when no local plan file exists.
- Updated `renderResult` to inspect `isError` on detail-less task results and render an error state with the error glyph.
- Replaced success/completed status symbols in agent, review, and result outputs with the shared `status.done` symbol.
- Added tests for detail-less task rendering to verify failed results show error and successful results show the done glyph.
- Introduced filterInitialToolsForDiscoveryAll() to centralize tool filtering when discovery mode is "all", replacing inline logic in createAgentSession.
- Added forceActive parameter to ensure tools required by forced tool_choice features (e.g., eager todo) remain active in the request, preventing provider 400 errors.
- Updated eager todo enforcement to check active tool set instead of registry, ensuring it respects tool discovery hiding.
- Derived descriptors, default-model map, env keys, login list, and refresh dispatch from one ProviderDefinition per provider.
- Disabled OpenAI Codex stream obfuscation and interrupted whitespace-only tool-call argument deltas.
- Derived auth-broker callback ports and paste-code login set from the registry.
- Kept committed tool-call blocks on TTSR/user-interrupt aborts, pairing them with a labeled placeholder result.
- Dropped incomplete tool calls only on anonymous `abort()` where partial args are unsafe to replay.
- Added status.done and tool.* symbols to theme mappings and presets.
- Replaced generic success glyphs with contextual +/-, tool icons, and warnings.
- Mapped tool/task/job completions to status.done or status.enabled with icon overrides.
- Triggered runtime provider refresh after extension registration and warned on failure.
- Ran the operand as an ordinary descendant so it is reaped with the host instead of leaking as an orphan.
- Propagated the command's exit status; reported missing operand and exit 125 with no operand.
- Updated the bash tool prompt's daemon guidance away from nohup/setsid/disown detachment.
- Switched shell renderer success icon/state to "done".
- Matched the `bash` tool's max in the Zod schema and runtime clamp.
- Allowed heavy local-compute cells to request budgets above 10 minutes.
- Updated docs and prompt to reflect the new 1-3600s range.
- Added fc editor mode, history -n/-r, and mapfile callbacks.
- Implemented symbolic umask parsing, unset namerefs, and declare -I.
- Rendered builtin man pages and replaced unimp errors with diagnostics.
- Added regex/substring tests, nameref unset, and exec-in-subshell paths.
- Added process ID resolution and selectors for waited jobs.
- Implemented terminate-only waits and next-job polling.
- Recorded completed job IDs into the variable named by -p.
- Added shell integration tests covering the new wait paths.