Live tool visibility: pending cards, sub-agent step log
Backend:
- ToolStarted event: emitted before tool execution begins so client
  can render a pending card with spinner immediately
- ToolEvent gains is_subagent flag; ToolStarted same
- current_event_sink ContextVar in tools/base.py — run_stream() sets it
  to an asyncio.Queue before create_task(); run_ephemeral() reads it and
  puts ToolStarted/ToolEvent into the queue as each sub-agent step runs
- run_stream() tool loop: sequential execution via create_task() +
  polling drain loop (20ms sleep); yields ToolStarted → sub-agent events
  from sink → ToolEvent (completed) for each tool call
- run_ephemeral() rewritten to inline sequential tool execution with
  sink emission (replaces _execute_tool_calls gather)
- _run_single_tool() helper extracted for run_stream()
- websocket.py handles tool_started and adds is_subagent to tool_call

Frontend:
- appendPendingToolCard(): creates card with spinner; spawn_agent opens
  body immediately to show sub-agent log as it fills
- finalizeToolCard(): fills result, removes spinner, adds toggle; strips
  "[Sub-agent result — ...]" reminder prefix from displayed text
- appendSubagentStep() / finalizeSubagentStep(): live step log inside
  spawn_agent card — each sub-agent tool call gets a ↳ row
- app.js: tool_started → pending card; tool_call → finalize card;
  is_subagent routing to sub-step vs main card; abandonStream() resets
  pendingToolCard/pendingSubStep
- CSS: .spinner-inline for card headers; .subagent-log / .subagent-step
  for nested step display; .tool-body-open for always-open spawn_agent
  body; .tool-card.pending suppresses chevron

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent ae4efaa commit 4112e36aad5fbe26cfef446d57c4db4c719d74a5
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored on 9 Apr
Showing 7 changed files
View
client/js/app.js
View
client/js/chat.js
View
client/style.css
View
navi/api/websocket.py
View
navi/core/agent.py
View
navi/core/events.py
View
navi/tools/base.py