diff --git a/.story_kit/work/1_upcoming/147_bug_activity_indicator_still_only_shows_thinking_despite_bug_140_fix.md b/.story_kit/work/1_upcoming/147_bug_activity_indicator_still_only_shows_thinking_despite_bug_140_fix.md index 76f5a0f..3b5fad0 100644 --- a/.story_kit/work/1_upcoming/147_bug_activity_indicator_still_only_shows_thinking_despite_bug_140_fix.md +++ b/.story_kit/work/1_upcoming/147_bug_activity_indicator_still_only_shows_thinking_despite_bug_140_fix.md @@ -6,17 +6,50 @@ name: "Activity indicator still only shows Thinking despite bug 140 fix" ## Description -Bug 140 fixed the frontend display condition but activity labels still never appear. The likely root cause is that Claude Code stream-json PTY output does not emit raw Anthropic API format events (content_block_start with type tool_use) inside stream_event wrappers. The handle_stream_event function in server/src/llm/providers/claude_code.rs line 486 only matches content_block_start, which is the Anthropic streaming API format. Claude Code CLI stream-json may use a different event structure for tool calls. +Bug 140 fixed the frontend display condition but activity labels still never appear. The full data path has been traced and the suspected failure point identified. -Investigation needed: -1. Add temporary logging in process_json_event (line 327) to dump all event types received from the PTY -2. Determine the actual event format Claude Code uses for tool calls in stream-json mode -3. Add matching for that format in handle_stream_event or process_json_event to fire activity_tx +## End-to-End Data Path -Key files: -- server/src/llm/providers/claude_code.rs line 327: process_json_event -- server/src/llm/providers/claude_code.rs line 486: handle_stream_event -- server/src/http/ws.rs line 251: activity callback wiring +### 1. Frontend display (FIXED by bug 140) +- `frontend/src/components/Chat.tsx` line 686: `{loading && (activityStatus != null || !streamingContent) && (` +- `frontend/src/components/Chat.tsx` line 697: `{activityStatus ?? "Thinking..."}` +- `frontend/src/components/Chat.tsx` line 204: `setActivityStatus(formatToolActivity(toolName))` — called by `onActivity` callback + +### 2. WebSocket client receives event +- `frontend/src/api/client.ts` line 350: `if (data.type === "tool_activity") this.onActivity?.(data.tool_name)` + +### 3. Server sends ToolActivity over WebSocket (WIRED CORRECTLY) +- `server/src/http/ws.rs` line 251-254: activity callback sends `WsResponse::ToolActivity { tool_name }` +- This callback is passed to `chat::chat()` as the `on_activity` closure + +### 4. chat::chat passes callback to Claude Code provider +- `server/src/llm/chat.rs`: passes `on_activity` through to `claude_code::chat_stream` +- `server/src/llm/providers/claude_code.rs` line 47: `mut on_activity: A` parameter +- `server/src/llm/providers/claude_code.rs` line 70: creates internal `activity_tx` channel +- `server/src/llm/providers/claude_code.rs` line 94: drains channel and calls `on_activity(&name)` + +### 5. PTY event processing (SUSPECTED FAILURE POINT) +- `server/src/llm/providers/claude_code.rs` line 327: `process_json_event()` dispatches parsed JSON +- Line 348-353: matches `"stream_event"` type → extracts inner `event` → calls `handle_stream_event()` +- `server/src/llm/providers/claude_code.rs` line 486: `handle_stream_event()` matches on event type +- Line 494-500: matches `"content_block_start"` with `content_block.type == "tool_use"` → sends to `activity_tx` + +### 6. The problem +`handle_stream_event` only matches `content_block_start` — this is the **raw Anthropic streaming API format**. But Claude Code's `--output-format stream-json` may NOT emit raw Anthropic events wrapped in `stream_event`. It likely uses its own event types for tool calls (e.g. `tool_use_begin`, `tool_use`, or similar). + +The existing `process_json_event` also matches `"assistant"` (line 355) and `"user"` (line 363) event types from stream-json, but these are complete messages — they arrive after the tool call is done, not when it starts. So there's no event being caught at tool-call-start time. + +## Investigation Steps + +1. Add logging in `process_json_event` (line 334) to print every `event_type` received from the PTY during a chat session with tool use +2. Identify which event type Claude Code emits when it starts a tool call +3. Add matching for that event type to fire `activity_tx.send(tool_name)` + +## Key Files +- `server/src/llm/providers/claude_code.rs` line 327: `process_json_event` — event dispatcher +- `server/src/llm/providers/claude_code.rs` line 486: `handle_stream_event` — only handles Anthropic API format +- `server/src/http/ws.rs` line 251: activity callback wiring to WebSocket +- `frontend/src/components/Chat.tsx` line 203: `onActivity` handler that sets display state ## How to Reproduce @@ -27,7 +60,7 @@ Key files: ## Actual Result -Indicator always shows Thinking and never changes to tool activity labels like Reading file or Executing command +Indicator always shows "Thinking..." and never changes to tool activity labels like "Reading file..." or "Executing command..." ## Expected Result @@ -35,4 +68,6 @@ Indicator should cycle through tool activity labels as the agent calls tools ## Acceptance Criteria -- [ ] Bug is fixed and verified +- [ ] Activity indicator shows tool names (e.g. "Reading file...", "Executing command...") when the web UI agent calls tools +- [ ] Indicator still falls back to "Thinking..." when no tool activity is in progress +- [ ] Works for all tool types (Read, Write, Bash, Glob, Grep, etc.)