Repository navigation
Show startup progress before the agent's first message - #1692
Conversation
PR Summary by QodoShow observable startup progress and richer tool activity
AI Description
Diagram
High-Level Assessment
Files changed (12)
|
Code Review by Qodo
1.
|
|
Triage of the Qodo review (head
Bugbot: passed with no findings. Also in |
The Activity pane showed only "Starting investigationâĶ" and a timer for the 20+ seconds until the agent's first message, although three real signals exist before it. Report the two that are observable: - "Connected to Radar's tools": the private investigation mount marks the turn's evidence scope connected on the MCP handshake (initialize or tools/list). The runner watches the scope and emits one `connected` phase per turn. internal/mcp still does not import internal/ai; the seam is a channel on the investigationrefs scope. - "<agent> ready · <model> · <n> Radar tools": Claude Code's stream-json system/init line carries the model, the tool list and each MCP server's status. It becomes a `ready` phase with Model, ToolCount and MCPServers. Cursor's init names the model only. A server that is not connected renders as a warning in the Activity pane; it never aborts the run. The pending status line shows the latest startup phase while the first turn has no items, keeps the elapsed timer, yields to tool activity once items arrive, and never renders on a replayed finished turn. Phase events were already persisted in the run log; the new fields are optional. Tool rows: hide durations under 2s on the collapsed row and show whole seconds above it, keep the exact milliseconds in the expanded result header, and show the producer's failure reason inline on a failed row.
Mark the investigation scope connected after initialize or tools/list returns without error, not before, so a rejected handshake never renders as connected. Keep the handshake watcher alive until the agent process exits, so a handshake landing between stdout EOF and exit is still reported before the turn returns. Use the semantic warning and error tokens for the startup warning and the inline failure reason, and only claim a server's tools were absent when the CLI reported a definite failure; pending states get conditional wording. A ready phase without init facts renders the bare ready label.
âĶentifiers The running status appended the turn's elapsed seconds to each startup label, which read as the duration of that phase. The counter is now a row-level "Ns elapsed" figure set apart from the label. On a collapsed failed tool row the arguments now give way before the reason, Radar's retry hints after the em dash are dropped, and a long reason is middle-truncated so the identifier at its tail survives.
db57153 to
8d78513
Compare
Summary
After an investigation starts, the Activity pane showed only "Starting investigationâĶ" and a timer for the 20+ seconds until the agent's first message. Three real signals exist before that message and none was shown. This PR reports the two Radar can observe honestly, with no timer-based labels:
system/initline. A non-connected MCP server becomes a visible warning in the Activity pane instead of a silent tool-less investigation. Cursor's init names the model only.Also on the same Activity rows: sub-2s tool durations are hidden on the collapsed row (whole seconds above that), the exact milliseconds stay in the expanded result header, and a failed tool row shows the producer's own failure reason inline.
What changed
internal/investigationrefs: a scope now carries aConnected()channel;Registry.MarkConnected(scope)closes it once for a live scope. This is the seam between the MCP mount and the runner, sointernal/mcpstill does not importinternal/ai.internal/mcp/server.go: the investigation middleware marks the scope connected afterinitializeortools/listreturns without error â a rejected handshake never reports as connected.internal/ai/diagnoser.go:StreamEventgains optionalModel,ToolCount,MCPServers(phase events were already persisted in the run log; no migration). The runner watches the scope and emits onephase: connectedper turn, serialized with the parser's events and always before the turn returns â including when the handshake and the stream's end coincide. The watcher stays alive until process exit.parseStreamhandlessystem/initand emitsphase: readywith the model, themcp__radar__tool count and every MCP server status. Cursor emits the model.web/src/api/diagnose.ts,parts.tsx,InvestigationView.tsx: thephaseevent folds intoturn.startup(furthest phase wins, since the handshake and init are reported by different goroutines). The pending status line shows the startup label only while the turn is running with no items, so it never renders on a replayed finished turn and never becomes a transcript item. The MCP warning is attributed to startup and survives replay, since it is a fact of the run; its copy is conditional on the server's state and reads in past tense on a replayed run.toolDurationLabel(hidden under 2s, whole seconds above),toolErrorReason(JSONerrorfield or first non-empty line of the producer text, with Radar's retry hints after the em dash dropped),middleTruncateso a long reason keeps its identifier tail, arguments shrink before the reason on the collapsed row,PayloadBlockheader detail for the exact ms.Testing
make tsc,make build,go test ./...(both modules),git diff --checkâ pass. New Go tests: the Claude init parser, the handshake-emitted-once runner path including the short-turn race, the registry handshake, the middleware's success-only marking, and Cursor's init model.packages/k8s-ui: 3549 passed.web: 1023 passed across 87 files, including the startup-signal merge (furthest phase wins, init facts kept), the barereadylabel with no init facts, replay suppression, and the tool-row duration/reason rendering.dev/cloud-provisioner, real Claude Code run). Observed from the click: 0.4s "Claude Code startingâĶ", 0.9s "Connected to Radar's tools", 5.0s "Claude Code ready · claude-sonnet-5 · 23 Radar tools", 23.2s first tool row. Reloading a finished run shows no startup label. A follow-up turn on the same run repeated the progression without special-casing.resource not found: secret "âĶ" not foundinline after the arguments. Every live call finished under 2s, so the slow row was verified against a saved run whosesearchtook 3754ms â the collapsed row reads4s, the expanded headerORIGINAL RESULT · 3754ms.Scope and tradeoffs
codex exec --json) only emitsthread.started; it carries no model or MCP data, so it gets the agent-agnostic "connected" signal only.AlertBanner. That component is the drawer-scale renderer surface (mb-4 p-3, 14px title plus message); the Activity pane is an 11px transcript and every warning inparts.tsx(consent, apply, truncation notes) is hand-rolled at that scale, so the banner would be out of register there.phaseevents, so a hosted run shows the bare "<agent> ready" label with no model, tool count or warning. That is the same code path with fields absent â there is no version fallback.--include-partial-messages, which is the planned follow-up.ðĪ Generated with Claude Code
https://claude.ai/code/session_0125QDX24TNuod7FKLwTDhvW
Note
Medium Risk
Touches investigation streaming, MCP handshake signaling, and live UI state; race handling is new but heavily testedâno auth or data-model changes.
Overview
Investigation Activity now surfaces real startup progress before the first agent message, instead of a generic âStarting investigationâĶâ line.
The backend emits new
phasestream events:investigating, thenconnectedwhen the agent completes MCP handshake on the private investigation mount (viainvestigationrefs.MarkConnected+ middleware on successfulinitialize/tools/list), thenreadyfrom the CLIâssystem/initline with model, Radar tool count (mcp__radar__prefix), and MCP server statuses. Events are mutex-serialized so handshake and parser callbacks donât interleave; the handshake watcher still fires once on short turns. Cursor maps init toreadywith model only.The UI folds phases into
turn.startup(mergeStartupSignalkeeps the furthest phase), shows agent-specific pending labels while the turn is running and the transcript is empty, and warns when MCP servers arenâtconnected(warning persists on replay). Tool rows hide sub-2s durations on the collapsed row (seconds + exact ms in expanded header), show inline failure reasons, and move the elapsed timer to a separate âNs elapsedâ figure beside the status label.Reviewed by Cursor Bugbot for commit 8d78513. Bugbot is set up for automated code reviews on this repo. Configure here.