Commit Graph

257 Commits

Author SHA1 Message Date
can1357 9637a2cb0c Merge PR #7774: fix(tui): gate built-in renderers by tool provenance (@roboomp) 2026-08-07 13:37:57 +02:00
can1357 68dece477f Merge PR #7772: fix(session): handle subscription-cap retry exhaustion (@roboomp) 2026-08-07 13:37:54 +02:00
roboomp 931f61867c fix(tui): gated built-in renderers by tool provenance
- Routed session tool provenance through live and rebuilt transcript render paths.
- Kept same-named extension tools on the generic renderer while preserving native tool rendering.
- Added regression coverage for an external recall result collision.

Fixes #7770
2026-08-06 01:36:25 +00:00
roboomp f6c5a43a1f fix(session): handled subscription-cap retry exhaustion
- Classified subscription and plan rate caps as credential-rotatable usage limits while preserving transient per-minute throttles.

- Applied reason-specific backoff to transient rate limits and collapsed exhausted retry attempts behind one budget-labeled terminal error.

- Covered classification, delay selection, persisted transcript aggregation, and retry event propagation.

Fixes #7767
2026-08-06 01:31:22 +00:00
can1357 1e3419ebac Merge PR #7688: fix(tui): detach plan approval dispatch from serialized event chain (@roboomp) 2026-08-05 22:16:28 +02:00
Mantas Vidutis ebdda043b8 Merge upstream/main into fix/deferred-command-output-feedback 2026-08-05 11:43:17 -07:00
roboomp a785811a64 fix(tui): detach plan approval dispatch from serialized event chain
After the fullscreen Plan Review closed on approve-and-execute, the
conversation view stayed blank while the plan ran. The propose write's
tool_execution_end handler runs inside EventController's serialized
dispatch chain and awaited handlePlanApproval, which awaits session.prompt
for the entire execution turn, so every later agent_start/message_start/
tool/message_update event queued behind it until the run finished.

Detach the approval dispatch so the dispatch link settles immediately and
the execution turn's events render live. Follow-up to #5688, which only
moved the overlay close before the still-blocking dispatch.

Fixes #7684
2026-08-05 09:18:12 +00:00
Slava Zavadsky 326fb24367 fix(coding-agent): chain every queued dispatch onto the current tail
The previous #runSerialized waited on the shared #dispatchTail, then ran
unconditionally: when two or more events queued behind an in-flight run,
each resumed from the same settled await and started its own run in
parallel, defeating the ordering guarantee for a burst landing in one
coalescing window (message_end + agent_end behind a suspended flush).

Each waiter now chains its own link onto the current tail
(tail.then(run, run)), so queued runs start strictly one after another;
the idle path still runs synchronously, preserving the flush timing the
coalescing tests assert on. The in-flight flag clears only when the
settling link is still the tail, so a later chained link's settle does
not clear it early.

Regression test: two message_end events queued behind a suspended window
flush stay serialized (init call count steps 1 -> 2 -> 3 as each gate
opens); fails on the previous implementation.
2026-08-04 17:42:54 -04:00
Slava Zavadsky 50ee839c51 fix(modes): serialize dispatch so a stream tail cannot overtake the coalesced flush
AgentSession.#emit fires listeners fire-and-forget, and the coalesced
message_update flush fires from its own 33ms timer — neither path awaited
the other. A rapid stream tail (message_update -> message_end ->
agent_end) could therefore run the end handlers while the flush was
suspended mid-await, agent_end removing streamingComponent before
#handleMessageEnd finalizes and records the final message (issue #7443
follow-up).

- #runSerialized chains listener dispatch and the timer flush through one
  promise chain; an in-flight run holds later events until it completes.
  Idle dispatch stays synchronous (no added microtask), preserving the
  timing the coalescing tests assert on.
- Regression test: a message_end landing while the window flush is
  suspended on init is queued behind it (initCalls 1 while suspended,
  then 2), where the pristine code ran both concurrently (2 while
  suspended). Fails without the fix.
2026-08-04 16:35:56 -04:00
Mantas Vidutis ced87b907b fix(tui): flush queued command panels at a non-terminal settle
Reaching the `isTerminal === false` branch means the superseded-turn guard
above it already passed, so `session.isStreaming` is false: a command
issued from that point mounts immediately while panels queued earlier in
the turn stay in `#pendingCommandOutput` until some later terminal
agent_end. Newer output rendered ahead of older, and the queued panel
could strand for minutes on an async fan-out that keeps settling
non-terminally.

Flush there too. The transcript is quiescent at a settle, which is the
condition #4806 wanted, and the notice now says "until the agent pauses"
rather than promising the current turn.
2026-08-04 11:47:54 -07:00
Slava Zavadsky 84813ad37a fix(coding-agent): handle timer-triggered message update flush rejections (#7443) 2026-08-03 14:14:07 -04:00
Slava Zavadsky fed51f1ffc fix(coding-agent): coalesce streaming message_update handler work per render window (#7443) 2026-08-03 14:06:48 -04:00
Daniel Anderson-Little a20690a40b feat(tui): add hidden tool activity mode 2026-08-02 22:59:48 -04:00
roboomp 84135e9fed fix(tui): flush deferred model switch on non-terminal settle
The isTerminal:false early-return skipped #finishAgentEnd, the only site
that flushes a deferred plan-mode model switch, so an automatic continuation
(async wake) ran on the old model/thinking level until the terminal settle.
Flush the pending switch on the non-terminal branch before returning; the
title/loader teardown stays deferred to the terminal agent_end.
2026-08-02 12:24:01 +00:00
roboomp 4e4c5564c9 fix(tui): keep working title across non-terminal agent_end
EventController.#handleAgentEnd guarded only on session.isStreaming, so a
non-terminal agent_end (isTerminal:false, emitted while an async job will
re-wake the loop) flipped the terminal title to idle and tore down the
working loader while a /vibe worker or async bash job was still running.

Early-return on event.isTerminal === false, matching the guard every other
agent_end consumer already applies; the later terminal agent_end performs
the normal teardown.

Fixes #7386
2026-08-02 12:18:08 +00:00
can1357 3fd042c38b fix(coding-agent): preserve grouped reads during retraction 2026-08-01 20:14:40 +02:00
can1357 191872990e Merge PR #6881: fix(coding-agent): retract superseded turn's tool cards to stop double render (@roboomp) 2026-08-01 20:14:40 +02:00
roboomp 18594e01d8 fix(coding-agent): keep terminal-failure tool cards; settle re-keyed completions
Address Codex review on #6881. Retraction of never-run tool cards no longer runs eagerly at message_end: only a TTSR rewind (known via isTtsrAbortPending) retracts there. A terminal error/abort lets agent-loop's synthetic tool_execution_end settle each card in place so the failure stays visible, and an auto-retry removes those synthetic-settled cards only when auto_retry_start actually supersedes the turn.

Also settle a held server-resolved (Cursor/todo) completion after a mid-stream tool-call id re-key, so the migrated card is not stranded pending.

Fixes #6879
2026-07-30 21:29:54 +00:00
can1357 9aada058ee feat(hashline): implemented clipboard operations in hashline engine
- Implemented clipboard register management, parsing, and execution rules for CUT, COPY, and PASTE operations in the hashline engine.
- Added session-persistent clipboard state and integration across agent session execution, diff previews, and streaming tools.
- Added comprehensive validation, error messages, recovery handling, and test coverage for clipboard and block operations.
2026-07-30 07:21:43 +02:00
can1357 756e872f64 Merge PR #6946: fix(tui): nest usage metrics in grouped reads (@joshrzemien) 2026-07-29 23:08:42 +02:00
joshrzemien daf1557b3d fix(tui): seal mixed read groups before usage
(cherry picked from commit 576b950b80583d8fd028edd08967b537f4eb18f0)
2026-07-29 23:08:42 +02:00
joshrzemien a3e90b3d95 fix(tui): nest usage metrics in read groups
(cherry picked from commit 101268adc632e80bb3f8304b95497ac7bd884131)
2026-07-29 23:08:41 +02:00
Márton Danóczy 80c32cf16a fix(tui): request a render on model_changed, not just cache invalidation
handleEvent has no blanket pre-render (removed for issue #4353), so
each handler must explicitly schedule one when it changes something
visible -- every other statusLine.invalidate() call site in this file
pairs it with ui.requestRender(). The new model_changed handler only
invalidated the cache, so an internal model switch (prewalk hand-off,
retry-fallback) while the TUI was otherwise idle left the status line
showing the stale model until an unrelated event happened to render.

Flagged by @chatgpt-codex-connector on PR #6908.

(cherry picked from commit f565e3a4956bda467b6679a3c3f1e48379395a78)
2026-07-29 23:08:26 +02:00
Márton Danóczy bce1ff55a7 feat(session): emit model_changed event on every internal model switch
AgentSession#setModelWithProviderSessionReset is the single choke point
every model mutation runs through (explicit /model, prewalk hand-offs,
retry-fallback, model cycling). It previously changed agent.state.model
silently — no session event told subscribers (ACP, RPC, TUI) that the
active model moved.

Emit a new model_changed AgentSessionEvent from that choke point
whenever the model actually changes, and wire it into every consumer
that must exhaustively handle AgentSessionEvent: the TUI event
controller (invalidates the status line, same as thinking_level_changed)
and the RPC client's forwarded-event allowlist.

(cherry picked from commit f76325de2c7821dd7046ddb67546577c3575a263)
2026-07-29 23:08:25 +02:00
roboomp 7cb608b72a fix(coding-agent): re-key streamed tool cards on mid-stream id change
GitHub Copilot's call_id|id transport (and any stream that delivers a tool's name/args before its id) makes a streamed tool-call block appear with an empty or partial id, then rewrites it in a later delta. The transcript keyed the live card by that mutable content.id, so the changed id passed the creation guard and spawned a second card: the old-id card orphaned as a blue pending preview while the new-id card took the result.

Track the streamed id per tool-call block position (reset per assistant message) and migrate the live card's id-keyed trackers (pendingTools, tool timeline, args reveal, read tracking, and the shared read group's entry) when the id changes, so the populated id reuses the existing card.

Fixes #6879
2026-07-29 14:32:51 +00:00
roboomp cd716e1896 fix(coding-agent): prevented duplicate fallback reads
When a successful read result was persisted before its live tool_execution_end reached the UI, a transcript rebuild replayed the completed card and removed the pending handle. The delayed read completion then created a fallback ReadToolGroupComponent beside replay.

Treat the existing tool timeline entry as proof that the read already had a card; clear stale read tracking and skip fallback creation. Added an exact memory:// success -> persisted replay -> delayed completion regression.

Fixes #6879
2026-07-28 09:01:09 +00:00
roboomp 01a44f180b fix(coding-agent): absorbed retracted tool completions
Track tool-call ids whose failed-attempt cards were retracted until agent-loop emits their synthetic skipped-tool completion. Ignore the synthetic start and consume the matching end so the no-pending handler cannot recreate the failed card.

Extended the retry regression through the exact message_end -> synthetic tool start/end -> auto-retry sequence.

Fixes #6879
2026-07-28 08:51:47 +00:00
roboomp 036bb5ac08 fix(coding-agent): stopped detached tool animations
Seal an uncommitted pending tool card before removing it from the transcript so ToolExecutionComponent cancels its spinner, todo strike, and edit-preview work instead of continuing to schedule renders while detached.

Added a fake-timer regression proving an animated write card renders while pending and stops component-scoped renders after an aborted turn retracts it.

Fixes #6879
2026-07-28 08:42:55 +00:00
roboomp 451dfcc954 fix(coding-agent): cleared detached read group before retry
Reset #lastReadGroup before retracting a superseded grouped read so the retry creates and mounts a fresh group instead of updating the detached component. Clear the removed call's read tracking as well.

Added regression coverage for an aborted grouped read followed by a visible successful retry.

Fixes #6879
2026-07-28 08:38:45 +00:00
roboomp 4d23b972d9 fix(coding-agent): retract superseded turn's tool cards to stop double render
An assistant turn that streamed tool calls and then ended with error/aborted
(a provider blip that auto-retries, a TTSR rewind) has its never-run cards
dropped from the active context, but EventController#handleMessageEnd only
sealed them in place. The retry re-streamed fresh cards below, so each call
rendered twice.

Retract the never-run pending tool cards still in the live region (never
committed to native scrollback, so removable) and forget them from pendingTools
and the timeline map at message_end; a card already on the scrollback tape is
still sealed in place. Follow-up to #6516 / #6519.

Fixes #6879
2026-07-28 08:28:25 +00:00
Diogo Soares Rodrigues c7c375f5e1 fix(cursor): settle todo cards whose completion outruns the streamed block
When Cursor packs toolCallStarted and toolCallCompleted into one HTTP/2
chunk, the bridge tool_execution_end (synchronous callback, fired
mid-parse) reaches the interactive controller before the streamed
toolcall_start (queued on AssistantMessageEventStream, delivered a
microtask later). The controller found no pendingTools entry, dropped
the completion, and the card created afterwards animated forever.

Two halves, each necessary:

- Hold an early todo completion in #orphanedToolCompletions and replay
  it when the streamed block creates its component.
- Guard card creation from cumulative message_update frames with the
  turn-scoped #toolTimelineComponents map. Without this, the update
  after the replay re-lists the same toolCall block, finds pendingTools
  empty again, and spawns a second, permanently pending card. This is
  also why emitting a synthetic tool_execution_start from the bridge
  (previous attempt, reverted) could not work.

Both maps are cleared together at the existing transcript-anchor reset
sites. The normal ordering (start first) is covered by a control test.
2026-07-26 09:29:13 -03:00
Diogo Soares Rodrigues cc210094ef fix(cursor): refuse todo dependency graphs and sanitize failure text
Two review findings on the native todo sync.

- TodoItem.dependencies is a graph the local model cannot store: rows
  are keyed by content, carry no id, and hold no edges. An imported
  dependent row files as plain pending and nextActionableTask then
  offers work the server considers blocked. Refuse snapshots with an
  edge pointing at an unfinished row; edges whose blockers already
  finished constrain nothing and still mirror.

- The todo failure warning interpolated the provider error verbatim.
  Collapse and truncate it at the render boundary.

Also documents two known, unfixed defects: an async cursorOnToolResult
transformer resolving after the buffer drain, and the todo card
lifecycle race. Emitting a synthetic tool_execution_start for the
latter was measured and rejected -- the completion deletes the entry it
creates, so the late streamed block adds a second card.
2026-07-26 09:29:13 -03:00
can1357 ca8c9eb69f Merge PR #6396: fix(tts): preserve playback across internal turns (@roboomp) 2026-07-24 02:24:04 +02:00
roboomp 741725612b fix(tts): gated playback clearing to user messages
Moved vocalizer interruption from agent_start to user message_start so agentLoopContinue preserves queued speech.

Expanded regression coverage for continuation starts and user prompt boundaries.

Fixes #6375
2026-07-23 20:05:49 +00:00
roboomp bdceb660d3 fix(tts): preserved playback across internal turns
Moved vocalizer clearing from each assistant/tool continuation boundary to the start of a new agent run.

Added regression coverage for uninterrupted internal turns and new-run interruption.

Fixes #6375
2026-07-23 18:39:11 +00:00
can1357 3829bff31a Merge PR #4637: feat(notifications): add error turn notifications (@Mathews-Tom)
# Conflicts:
#	packages/coding-agent/src/modes/controllers/event-controller.ts
#	packages/coding-agent/src/prompts/tools/eval.md
#	packages/coding-agent/src/session/agent-session.ts
#	packages/coding-agent/src/task/index.ts
2026-07-23 17:49:06 +02:00
can1357 08be77c483 fix: repaired mis-applied conflict resolutions from title-state merge 2026-07-23 17:34:13 +02:00
can1357 8490654df3 refactor(coding-agent): expressed run state via the title separator instead of prefix glyphs
Kept the bare 'π' brand per owner direction: the separator between the
brand and the session label now carries the state — '>' when it's the
user's turn (idle), animated spinner frames while working, '!' when the
agent is blocked on the user. Disabled ('tui.titleState' off) renders the
pre-state 'π: label' layout. Updated the state/runtime tests to the new
contract.
2026-07-23 17:31:30 +02:00
can1357 e1e5e0b530 fix(coding-agent): kept attention title until the last approval prompt resolved 2026-07-23 17:31:30 +02:00
can1357 0dac3d45b5 Merge PR #4451: feat(coding-agent): reflect agent run state in terminal title (@mattwilkinsonn)
# Conflicts:
#	packages/coding-agent/src/modes/controllers/event-controller.ts
#	packages/coding-agent/src/modes/interactive-mode.ts
2026-07-23 17:31:30 +02:00
can1357 e1173b8aeb Merge PR #6199: fix(tui): reuse settled components after compaction (@roboomp) 2026-07-22 21:13:17 +02:00
roboomp 13039b7bdf fix(tui): reused settled components after compaction
Preserved settled user and assistant component instances during compaction-only transcript rebuilds so warmed Markdown and layout caches remain valid.

Covered both manual and automatic compaction paths with focused regression tests.

Fixes #6033
2026-07-21 20:25:35 +00:00
can1357 60cbcc8c9d Merge PR #5055: feat(coding-agent): add timestamp to per-turn token-usage row (@zommiommy) 2026-07-20 22:50:05 +02:00
Derek Zeng 9a452077b2 fix(coding-agent): clear inline images when disabled 2026-07-18 18:12:08 +08:00
robomp-bot 8a6017847b fix(coding-agent): mark session_stop continuations as willContinue 2026-07-16 20:35:01 +09:00
robomp-bot b7e21155cd fix(coding-agent): skip legacy completion notify under Warp protocol 2026-07-16 20:12:25 +09:00
can1357 e0c717e07f merged PR #5427: fix(tui): defer command output during streaming 2026-07-16 03:32:03 +02:00
Mathews-Tom 9f44e2bf32 fix(coding-agent): notify only on terminal errors 2026-07-16 00:28:42 +05:30
Mathews-Tom 6c38f9f259 fix(coding-agent): reset retry state on view changes 2026-07-15 22:30:15 +05:30
Mathews-Tom 2c56d23e4f fix(coding-agent): retain retry notification suppression 2026-07-15 22:21:26 +05:30