Tracing
Grounded tracing is built around four objects:
tracespaneventscore
The tracing SDK sends completed traces into:
POST /api/traces/batchGET /api/tracesGET /api/traces/:traceIdGET /api/traces/:traceId/spansGET /api/traces/:traceId/scores
Core Flow
const trace = tracing.startTrace({
traceId: 'chat_123',
sessionId: 'chat_123',
anonymousId: 'anon_123',
userId: 'user_123',
name: 'support.reply',
resource: {
snapshotId: 'snap_456',
},
tags: ['support', 'prod'],
metadata: {
channel: 'api',
},
input: {
message: 'where is my refund?',
},
});
const span = trace.startSpan({
name: 'policy.lookup',
kind: 'retrieval',
input: {
source: 'faq',
},
});
span.recordEvent('cache_hit', {
index: 'policy-cache',
});
span.end({
status: 'ok',
output: {
articleId: 'refund-policy-v3',
},
});
trace.score({
name: 'resolved',
value: true,
dataType: 'boolean',
});
trace.recordEvent('handoff_skipped', {
reason: 'policy answered directly',
});
await trace.end({
status: 'ok',
output: {
text: 'your refund is processing',
},
});
await tracing.flush();Correlation Rules
For real ingestion, every trace must resolve:
- an agent
- pass
agentIdtonew GroundedTracing(...), or - pass
resource.agentIdonstartTrace(...)
- pass
- and at least one stitch key
sessionId, oranonymousId, oruserIdplus non-emptycorrelationKeys
The SDK now fails fast if a trace cannot be linked into Grounded's session model.
Trace Shape
The SDK writes the backend TraceWrite model:
type TraceWrite = {
traceId: string;
sessionId?: string;
anonymousId?: string;
userId?: string;
name: string;
startTime: string;
endTime: string;
status?: 'ok' | 'error';
source?: 'sdk' | 'otel' | 'connector';
ingestMode?: 'direct' | 'mirror' | 'import';
provider?: string;
providerTraceId?: string;
providerSessionId?: string;
correlationKeys?: Record<string, unknown>;
metadata?: Record<string, unknown>;
resource?: {
agentId?: string;
snapshotId?: string;
environment?: string;
release?: string;
};
tags?: string[];
input?: unknown;
output?: unknown;
error?: {
message: string;
type?: string;
stack?: string;
};
spans?: TraceWriteSpan[];
scores?: TraceWriteScore[];
events?: TraceEvent[];
};Span Kinds
Current span kinds:
llmtoolretrievalguardrailapp
Scores
Scores are lightweight outcome annotations attached to a trace:
trace.score({
name: 'resolved',
value: true,
dataType: 'boolean',
});
trace.score({
name: 'groundedness',
value: 0.91,
dataType: 'numeric',
});Readback
You can inspect raw stored trace data through @grounded/client:
const traces = await grounded.traces.list({
agentId: 'agt_123',
});
const detail = await grounded.traces.get(traces.data[0]!.id);
const spans = await grounded.traces.listSpans(detail.id);
const scores = await grounded.traces.listScores(detail.id);OpenTelemetry Mirroring
@grounded/tracing includes a lightweight exporter bridge for already-instrumented apps:
const exporter = tracing.createOpenTelemetryExporter();
await exporter.export(spans);
await tracing.flush();This is the main "sit on top of an existing runtime" path. It lets you mirror already-instrumented spans into Grounded without replacing your upstream OTel pipeline.
Normalization Into Sessions
If Grounded can resolve a snapshot for the target agent, a direct trace is converted into an internal session record.
That session then becomes visible to:
- sessions
- insights
- evals
- snapshot optimization workflows