Stream Claude Code subagent activity inline in the transcript

This commit is contained in:
Ian Gulliver
2026-10-15 11:08:53 -07:00
parent 0e43a99115
commit d83212d46b
11 changed files with 325 additions and 35 deletions
+27 -9
View File
@@ -757,12 +757,19 @@ func (m *Manager) handle(ctx context.Context, l *live, ev claude.Event) error {
if err != nil {
return err
}
parent, err := ev.ParentToolUseID()
if err != nil {
return err
}
for _, b := range blocks {
err = m.handleAssistantBlock(ctx, l, b)
err = m.handleAssistantBlock(ctx, l, b, parent)
if err != nil {
return err
}
}
if parent != "" {
return nil
}
usage, err := ev.ContextUsage()
if err != nil {
return err
@@ -778,6 +785,10 @@ func (m *Manager) handle(ctx context.Context, l *live, ev claude.Event) error {
if err != nil {
return err
}
parent, err := ev.ParentToolUseID()
if err != nil {
return err
}
for _, b := range blocks {
if b.Type != "tool_result" {
continue
@@ -786,11 +797,11 @@ func (m *Manager) handle(ctx context.Context, l *live, ev claude.Event) error {
if err != nil {
return err
}
err = m.emit(ctx, l, agentActor, "agent.tool_result", map[string]any{
err = m.emit(ctx, l, agentActor, "agent.tool_result", withParent(map[string]any{
"tool_use_id": b.ToolUseID,
"is_error": b.IsError,
"content": content,
})
}, parent))
if err != nil {
return err
}
@@ -943,30 +954,37 @@ func (m *Manager) updateContext(ctx context.Context, l *live, used, window int)
return m.emit(ctx, l, agentActor, "session.context", map[string]any{"model": l.contextModel, "used": used, "window": window})
}
func (m *Manager) handleAssistantBlock(ctx context.Context, l *live, b claude.Block) error {
func (m *Manager) handleAssistantBlock(ctx context.Context, l *live, b claude.Block, parent string) error {
switch b.Type {
case "text":
return m.emit(ctx, l, agentActor, "agent.message", map[string]any{"text": b.Text})
return m.emit(ctx, l, agentActor, "agent.message", withParent(map[string]any{"text": b.Text}, parent))
case "thinking":
if b.Thinking == "" {
return nil
}
return m.emit(ctx, l, agentActor, "agent.thinking", map[string]any{"text": b.Thinking})
return m.emit(ctx, l, agentActor, "agent.thinking", withParent(map[string]any{"text": b.Thinking}, parent))
case "tool_use":
input, err := decode(b.Input)
if err != nil {
return err
}
return m.emit(ctx, l, agentActor, "agent.tool_call", map[string]any{
return m.emit(ctx, l, agentActor, "agent.tool_call", withParent(map[string]any{
"id": b.ID,
"name": b.Name,
"input": input,
})
}, parent))
}
return m.emit(ctx, l, agentActor, "agent.vendor", store.ToPayload(b))
return m.emit(ctx, l, agentActor, "agent.vendor", withParent(store.ToPayload(b), parent))
}
func withParent(payload map[string]any, parent string) map[string]any {
if parent != "" {
payload["parent_tool_use_id"] = parent
}
return payload
}
func (m *Manager) emit(ctx context.Context, l *live, actor, kind string, payload map[string]any) error {