MCPcopy Index your code
hub / github.com/simstudioai/sim / stampSseReadLoopSpan

Function stampSseReadLoopSpan

apps/sim/lib/copilot/request/go/stream.ts:609–708  ·  view source on GitHub ↗

* Ship a one-shot `copilot.sse.read_loop` OTel span with the aggregate * counters collected during the read loop. Uses `startTime` so the * span's duration reflects the actual loop wall clock even though we * only talk to OTel once at the end. * * Deliberately synchronous, no per-chunk span cal

(
  startPerfMs: number,
  counters: SseReadLoopCounters,
  closeReason: string,
  fetchUrl: string,
  pathname: string,
  opts: { idleGapEventThresholdMs: number; expectedTerminal: boolean }
)

Source from the content-addressed store, hash-verified

607 * chunk count.
608 */
609function stampSseReadLoopSpan(
610 startPerfMs: number,
611 counters: SseReadLoopCounters,
612 closeReason: string,
613 fetchUrl: string,
614 pathname: string,
615 opts: { idleGapEventThresholdMs: number; expectedTerminal: boolean }
616): void {
617 // Translate performance.now() values into wall-clock Date values so
618 // the span's timestamps land in real time (OTel accepts both, but we
619 // need to pair startTime with a matching "now" for .end()).
620 const nowPerf = performance.now()
621 const nowWall = Date.now()
622 const startWall = nowWall - (nowPerf - startPerfMs)
623
624 const terminalEventSeen = counters.eventsByType.complete > 0 || counters.eventsByType.error > 0
625 // `terminal_event_missing` is the single-attribute dashboard signal
626 // for the "disappeared response" bug class: the caller considered
627 // this leg to be the final one (`context.streamComplete === true`)
628 // but no terminal `complete` or `error` event arrived on the wire.
629 // Tool-pause legs have expectedTerminal=false and never trip this, so
630 // dashboards can filter on `{ .copilot.sse.terminal_event_missing = true }`
631 // without false positives.
632 const terminalEventMissing = opts.expectedTerminal && !terminalEventSeen
633
634 const tracer = getCopilotTracer()
635 const span = tracer.startSpan(TraceSpan.CopilotSseReadLoop, {
636 startTime: startWall,
637 attributes: {
638 [TraceAttr.HttpUrl]: fetchUrl,
639 [TraceAttr.HttpPath]: pathname,
640 [TraceAttr.CopilotSseBytesReceived]: counters.bytes,
641 [TraceAttr.CopilotSseChunksReceived]: counters.chunks,
642 [TraceAttr.CopilotSseEventsReceived]: counters.events,
643 [TraceAttr.CopilotSseEventsSession]: counters.eventsByType.session,
644 [TraceAttr.CopilotSseEventsText]: counters.eventsByType.text,
645 [TraceAttr.CopilotSseEventsTool]: counters.eventsByType.tool,
646 [TraceAttr.CopilotSseEventsSpan]: counters.eventsByType.span,
647 [TraceAttr.CopilotSseEventsResource]: counters.eventsByType.resource,
648 [TraceAttr.CopilotSseEventsRun]: counters.eventsByType.run,
649 [TraceAttr.CopilotSseEventsError]: counters.eventsByType.error,
650 [TraceAttr.CopilotSseEventsComplete]: counters.eventsByType.complete,
651 [TraceAttr.CopilotSseLongestInboundGapMs]: Math.round(counters.longestInboundGapMs),
652 [TraceAttr.CopilotSseLongestDispatchMs]: Math.round(counters.longestDispatchMs),
653 [TraceAttr.CopilotSseTotalDispatchMs]: Math.round(counters.totalDispatchMs),
654 [TraceAttr.CopilotSseCloseReason]: closeReason,
655 [TraceAttr.CopilotSseExpectedTerminal]: opts.expectedTerminal,
656 [TraceAttr.CopilotSseTerminalEventSeen]: terminalEventSeen,
657 [TraceAttr.CopilotSseTerminalEventMissing]: terminalEventMissing,
658 },
659 })
660
661 if (counters.firstEventMs !== undefined) {
662 span.setAttribute(TraceAttr.CopilotSseFirstEventMs, counters.firstEventMs)
663 // Anchor the event to the moment the first SSE event was actually
664 // received (startWall + firstEventMs), not `now`, so a trace
665 // waterfall shows the diamond at the TTFT point — not at span end.
666 span.addEvent(

Callers 1

runStreamLoopFunction · 0.85

Calls 2

getCopilotTracerFunction · 0.90
startSpanMethod · 0.80

Tested by

no test coverage detected