From 004f6055ffeff622b12274c75d693d65c80858ae Mon Sep 17 00:00:00 2001 From: viettranx Date: Tue, 10 Mar 2026 14:02:25 +0700 Subject: [PATCH] fix(tracing): set trace back to running while announce span is active When an announce (child trace) run starts, toggle the parent trace status to "running" so the UI doesn't show "completed" with a running child span. Restore to "completed" when the announce finishes. --- internal/agent/loop_run.go | 16 ++++++++++++++++ internal/tracing/collector.go | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/internal/agent/loop_run.go b/internal/agent/loop_run.go index 0607c877..595d808d 100644 --- a/internal/agent/loop_run.go +++ b/internal/agent/loop_run.go @@ -110,6 +110,13 @@ func (l *Loop) Run(ctx context.Context, req RunRequest) (*RunResult, error) { l.emitAgentSpanStart(ctx, agentSpanID, runStart, req.Message) } + // Child trace (announce run): set parent trace back to "running" while + // this run is active so the trace UI doesn't show "completed" with a + // "running" child span. + if isChildTrace && l.traceCollector != nil && traceID != uuid.Nil { + l.traceCollector.SetTraceStatus(ctx, traceID, store.TraceStatusRunning) + } + result, err := l.runLoop(ctx, req) // Finalize the root agent span. Uses EmitSpanUpdate (channel send) so it @@ -119,6 +126,15 @@ func (l *Loop) Run(ctx context.Context, req RunRequest) (*RunResult, error) { l.emitAgentSpanEnd(ctx, agentSpanID, runStart, result, err) } + // Child trace: restore trace status now that this run is done. + if isChildTrace && l.traceCollector != nil && traceID != uuid.Nil { + status := store.TraceStatusCompleted + if err != nil { + status = store.TraceStatusError + } + l.traceCollector.SetTraceStatus(ctx, traceID, status) + } + if err != nil { emitRun(AgentEvent{ Type: protocol.AgentEventRunFailed, diff --git a/internal/tracing/collector.go b/internal/tracing/collector.go index ffe561f8..33e4b9a3 100644 --- a/internal/tracing/collector.go +++ b/internal/tracing/collector.go @@ -156,6 +156,16 @@ func (c *Collector) EmitSpanUpdate(spanID, traceID uuid.UUID, updates map[string } } +// SetTraceStatus updates only the trace status and marks it dirty for re-aggregation. +// Used by child trace runs (e.g. announce) to toggle the parent trace back to +// "running" while the child is active, then "completed" when done. +func (c *Collector) SetTraceStatus(ctx context.Context, traceID uuid.UUID, status string) { + if err := c.store.UpdateTrace(ctx, traceID, map[string]any{"status": status}); err != nil { + slog.Warn("tracing: failed to set trace status", "trace_id", traceID, "error", err) + } + c.markDirty(traceID) +} + // FinishTrace marks a trace as completed and schedules aggregate update. func (c *Collector) FinishTrace(ctx context.Context, traceID uuid.UUID, status string, errMsg string, outputPreview string) { now := time.Now().UTC()