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.
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.
Disabling the Advisor from /settings persisted the setting but left the
live Advisor runtime running until the session restarted.
SelectorController.handleSettingChange had no case for "advisor.enabled",
unlike other session-managed toggles (autoCompact, steeringMode, ...), so
the change never reached session.setAdvisorEnabled — the same call /advisor
off already uses to stop the runtime immediately.
- Large-paste menu now saves pastes as local://paste-N.md instead of
local://attachment-N, giving the artifact a markdown extension and a
clearer name.
- Add `CodexAttestationProvider` hook and `getCodexAttestationHeader` resolver that gates on ChatGPT-OAuth credentials.
- Integrate attestation into WebSocket transport, SSE event stream, and OpenAI compaction requests.
- Wire `setCodexAttestationProvider(generateCodexAttestation)` in model-registry init for OAuth sessions.
- Added `LIVE_DELEGATION_MESSAGE_TYPE` constant and delegation message handling for voice sessions.
- Implemented turn-based transcript coalescing with user and assistant turn counters.
- Added transcript display row with normalized rendering in the live visualizer.
- Refactored controller to send delegation messages via `sendCustomMessage` with configurable frame styling.
- Removed microphone permission error reporting from silence detection logic.
- Switched from `miniaudio` to `maudio` Rust crate and added `AudioCapture` and `AudioPlayback` native classes.
- Removed browser-side audio infrastructure including Web Audio API, audio worklet processor, and WebRTC runtime.
- Migrated STT recorder and transcriber modules to use native `AudioCapture` with callback-based streaming.
- Replaced streaming audio player with native `AudioPlayback` that writes PCM directly without TypeScript intermediaries.
- Removed ffmpeg, wav, and platform-specific playback commands from the audio toolchain.
- Add `pinSessionOAuthAccount` storage method and active account flag to the auth storage API.
- Introduce session account selector component, controller logic, and interactive mode delegation.
- Implement the `/session pin` builtin slash command with text listing and account pinning capabilities.
- Add unit tests covering session account selection, component navigation, and command handling.
Scheduling agent.continue() inside navigateTree started a post-prompt
task before the interactive /tree handler rebuilt its transcript, so a
fast provider's agent_start/turn_start could render against the stale
pre-rebuild UI and then be clobbered by renderInitialMessages.
navigateTree now reports the commit via askReanswerCommitted instead of
resuming, and SelectorController.showTreeSelector calls the new
AgentSession.resumeAfterAskReanswer() only after renderInitialMessages +
reloadTodos, so the resumed turn always renders against the rebuilt
transcript.
Addresses chatgpt-codex-connector review on #6484.
Fixes#6483
The first interactive submit fired session.generateTitle() before
startPendingSubmission() painted the optimistic user row, and
tinyTitleClient.generate() spawned the local tiny-title subprocess
synchronously in #ensureWorker() before its first await. With a local
providers.tinyModel configured, subprocess-spawn latency therefore landed
ahead of the first frame, stalling the first prompt.
Paint the pending row before starting titling, and prewarm an idle,
unref'd worker at TUI startup via a no-op ping (no model load) so the
first submit reuses a live subprocess.
Fixes#6462
- Added `src/live/` subsystem with WebRTC transport, protocol parser, session controller, and headless Chromium audio injection.
- Added `LiveVisualizer` component with phase states, transcript display, and animated waveform rendering.
- Added `/live` slash command and `LiveCommandController` to toggle live voice sessions.
- Suppressed local TTS via `vocalizer.suspend()` during live mode to prevent audio conflicts.
- Added live-instructions and agent-final-message prompts for agent messaging context.
- Added `protocol.test.ts` covering event parsing, chunking, and context message construction.
A single hung/slow poll now aborts with TimeoutError after 30s; without
this, that one timeout escaped #waitForSmitheryCliApiKey and dropped the
browser login to the manual API-key fallback instead of retrying until
the 5-minute deadline. Catch isTimeoutError in the poll loop and
continue; export SmitheryCliPollResponse to type the retried response.
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
- Serialized backend transitions across runtime state, tools, and prompts.
- Rehydrated Mnemopi listeners after clear and enqueue maintenance.
- Made memory.backend the sole post-migration local runtime gate.
Fixes#5638
Status presenters (showWarning/showError/showStatus and extension/tool
error presenters) baked theme.fg() into Text at construction, so a
warning shown while the auto-theme default guess was dark kept the
dark-mode color after async appearance detection switched the active
theme to light — dark-catppuccin Mocha yellow on the light Latte
background (1.12:1 contrast, effectively invisible).
Add Text.setStyleFn(), a foreground styler evaluated at render time, and
route the transient status presenters through it. Because the coding
agent invalidates status components on onThemeChange, a theme swap now
re-shapes them against the live theme instead of replaying the palette
active when they were constructed.
Fixes#6337
- Replaced single-provider preferences with ordered priority lists for web search and image generation.
- Added a `MultiSelectSubmenu` component supporting toggle and reordering interactions in settings.
- Implemented migration logic to convert legacy single-provider preferences into ordered priority lists.
- Updated setup wizard scenes, image generation fallback logic, and search provider chains to use priority lists.
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
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.
Servers may allow the unauthenticated MCP handshake yet protect individual
tool calls via _meta["mcp/www_authenticate"]. The 'reauthorization is not
required' guard would silently abort the tool-challenge reauth path.
/usage and omp usage now report Synthetic (synthetic.new) quota state
via GET /v2/quotas (free, does not consume quota): the rolling 5-hour
request limit with per-tick regeneration rate, and the weekly credit
quota in USD. Applies to API-key credentials for the synthetic
provider; every payload section is parsed defensively since only
subscription is documented.
The new global smart-paste listener reused handleImagePaste(), whose
image branches insert [Image #N] into the hidden main editor when a
login/API-key prompt is focused. Mirror the enhanced-paste behavior:
show 'Image paste is not supported in this prompt' and skip image-path
detection so only clipboard text reaches the focused prompt.