agents: stream cursor InteractionUpdate deltas (text, thinking, tool, shell, token, summary) #951
Labels
No labels
area:agents
area:dashboard
area:database
area:design
area:design-review
area:flows
area:infra
area:meta
area:security
area:sessions
area:webhook
area:workdir
security
type:bug
type:chore
type:meta
type:user-story
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
#952 agents: live token meter — accumulate per-task usage across both providers
charles/claude-hooks
#956 agents: replay event log from Run.conversation() on worker crash (cursor only)
charles/claude-hooks
#957 agents: synthesize shell_output_delta for claude-code via container log stream
charles/claude-hooks
Reference
charles/claude-hooks#951
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
User story
As an operator watching a
provider=cursortask, I want streamed deltas (assistant text typing, thinking deltas, tool start/partial/complete, live shell output, token counter ticking) instead of waiting for whole-message events, so the dashboard feels live and matches the Cursor app's responsiveness.Context
@cursor/sdkexposes a finer-grained delta stream alongsideRun.stream(). Fromdist/cjs/types/delta-types.d.ts:Today
cursor-sdk-adapter.tsonly consumesRun.stream()(wholeSDKMessageevents). Issue #950 closes the visibility gap at message granularity; this issue takes the next step — sub-message streaming.The Claude Code SDK does not expose deltas of equivalent fidelity, so the port should make these events optional (provider may or may not emit them). The runner + UI must handle both cases gracefully (claude-code shows whole-turn events; cursor shows live deltas).
Acceptance criteria
Port (
claude-port.ts) — new optionalTaskEventvariantsTextDeltaEvent { type: "text_delta", sessionId, text }ThinkingDeltaEvent { type: "thinking_delta", sessionId, text }ToolCallStartedEvent { type: "tool_call_started", sessionId, callId, toolName, args }ToolCallProgressEvent { type: "tool_call_progress", sessionId, callId, partial: unknown }— forPartialToolCallUpdateToolCallCompletedEvent { type: "tool_call_completed", sessionId, callId, toolName, result, ok }ShellOutputDeltaEvent { type: "shell_output_delta", sessionId, callId, stream: "stdout"|"stderr", text }UsageDeltaEvent { type: "usage_delta", sessionId, deltaInput, deltaOutput }— forTokenDeltaUpdateSummaryEvent { type: "summary", sessionId, phase: "started"|"completed", text? }— forSummaryStartedUpdate/SummaryCompletedUpdateTurnEndedEvent { type: "turn_ended", sessionId }— to demarcate logical turns in a long-running sessionAssistantTurn/ToolSummaryEventetc. stay; cursor stops emitting them when delta path is active and emits the new ones instead. claude-code keeps emitting the whole-turn events.Cursor adapter (
cursor-sdk-adapter.ts)Run.stream()consumer withagent.onInteraction(...)(or whatever the cursor SDK names the interaction-listener API — verify against the published types). KeepRun.stream()as a fallback if interaction listener is unavailable on the active SDK version.InteractionUpdatesubtype to the matching newTaskEvent. Use thecallIdfromToolCallStartedUpdateso partial / completed updates can be correlated to the started event.ShellOutputDeltaUpdatemust include thecallIdof the in-flightShelltool call so the UI can append to the right output pane.Event log (
event-log.ts)MAX_EVENTS_PER_TASK = 500may be too low once deltas stream; consider per-event-type sub-caps (text deltas coalesced into the most recent assistant turn, shell deltas truncated to last N KB per tool call) rather than blindly raising the global cap.Coalescing
callId"rolling state" over SSE (e.g. accumulateShellOutputDeltaEvent+ToolCallProgressEventinto a single mutable record on the server, broadcast deltas as patches). Otherwise SSE bandwidth + client render cost spikes on long shell outputs.docs/api.mdSSE section.Tests
InteractionUpdate→TaskEventmapping, fixtures per delta type.Out of scope
shell_output_deltafor claude path viadocker logs -f).usage_delta— separate cost issue.References
node_modules/.bun/@cursor+sdk@1.0.12/node_modules/@cursor/sdk/dist/cjs/types/delta-types.d.tsapps/server/src/infrastructure/agent/cursor-sdk-adapter.tsapps/server/src/infrastructure/agent/claude-port.tsapps/server/src/infrastructure/event-log.ts