> ## Documentation Index
> Fetch the complete documentation index at: https://docs.svantic.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Trace propagation

# Trace propagation

```typescript theme={null}
import {
  parse_traceparent,
  parse_baggage,
  extract_trace_context,
  type ParsedTraceparent,
  type ExtractedTraceContext,
} from '@svantic/sdk';
```

## What it is

A small set of pure functions for working with [W3C Trace Context](https://www.w3.org/TR/trace-context/). Svantic embeds a `traceparent` (and optionally `baggage`) in every dispatch so your agent's spans connect back to the caller's trace tree. The SDK *already* parses those headers for you and surfaces the parent trace-id and span-id on [`CapabilitySessionContext`](./types#capabilitysessioncontext), so you normally don't need these helpers.

You import them only when you need to do one of three things:

1. **Forward the trace downstream** — you're calling a non-Svantic service (REST, gRPC) from inside a capability and want the same trace tree to span both hops.
2. **Inspect trace context in custom transports** — you're writing your own dispatch path and need to extract trace fields from a raw payload.
3. **Read baggage** — you want tenant or user context the upstream caller attached.

## When to use it

* Forwarding trace context to an outbound `fetch` / HTTP client.
* Building a custom exporter or middleware that reads upstream trace fields.
* Writing tests that assert trace context was wired through.

If you're happy with the automatic `ctx.trace_id` / `ctx.parent_span_id` on the session context, you can ignore this module entirely.

## Functional usage

```typescript theme={null}
import { extract_trace_context } from '@svantic/sdk';

agent.define_capability({
  name: 'fetch_external_quote',
  parameters: { /* … */ },
  handler: async (args, ctx) => {
    // ctx.trace_id / ctx.parent_span_id are already available, but if
    // you want the raw header strings (to forward as-is), parse the
    // dispatch payload yourself:
    const trace = extract_trace_context(ctx.raw_dispatch);

    const res = await fetch('https://quotes.example.com/v1/lookup', {
      headers: {
        ...(trace?.traceparent && { traceparent: trace.traceparent }),
        ...(trace?.baggage && { baggage: trace.baggage }),
      },
    });

    return await res.json();
  },
});
```

With this in place, spans from the quotes service will show up as children of the caller's trace in the Svantic dashboard.

## `parse_traceparent(raw)`

```typescript theme={null}
function parse_traceparent(raw: string | undefined | null): ParsedTraceparent | null;
```

Parse a W3C `traceparent` header. Returns `null` if the header is missing, malformed, or uses an unsupported version — never throws.

Only version `00` is accepted. All-zero trace-ids and span-ids are rejected per spec.

### `ParsedTraceparent`

| Field            | Type      | Description                                   |
| ---------------- | --------- | --------------------------------------------- |
| `version`        | `string`  | Always `'00'`.                                |
| `trace_id`       | `string`  | 32-hex lowercase.                             |
| `parent_span_id` | `string`  | 16-hex lowercase.                             |
| `flags`          | `string`  | 2-hex lowercase.                              |
| `sampled`        | `boolean` | `true` iff the `sampled` flag (bit 0) is set. |

## `parse_baggage(raw)`

```typescript theme={null}
function parse_baggage(raw: string | undefined | null): Record<string, string>;
```

Parse a W3C `baggage` header into a plain map. Malformed entries are skipped silently (per spec). Values are percent-decoded. Always returns an object — never `null` — so callers can unconditionally spread it.

## `extract_trace_context(session)`

```typescript theme={null}
function extract_trace_context(session: unknown): ExtractedTraceContext | null;
```

High-level helper that pulls trace context out of a dispatch's `session` blob. Returns `null` when the session has no `propagation_headers`. Never throws — bad headers simply produce missing fields on the result.

### `ExtractedTraceContext`

| Field                 | Type                     | Description                                                                    |
| --------------------- | ------------------------ | ------------------------------------------------------------------------------ |
| `propagation_headers` | `Record<string, string>` | Raw headers as sent by the mesh. Forward verbatim to downstream HTTP services. |
| `parent_trace_id?`    | `string`                 | From `traceparent`, when valid.                                                |
| `parent_span_id?`     | `string`                 | From `traceparent`, when valid.                                                |
| `baggage`             | `Record<string, string>` | Parsed `baggage` map. Empty object when absent or unparseable.                 |

## Example: forward headers to a downstream service

```typescript theme={null}
agent.define_capability({
  name: 'fetch_order',
  description: '…',
  parameters: { /* … */ },
  handler: async (args, ctx) => {
    const res = await fetch('https://legacy.internal/orders/' + args.id, {
      headers: ctx.propagation_headers ?? {},
    });
    return res.json();
  },
});
```

## Example: parent a custom span

```typescript theme={null}
import { trace } from '@opentelemetry/api';

const tracer = trace.getTracer('invoice-agent');

agent.define_capability({
  name: 'summarize_invoice',
  description: '…',
  parameters: { /* … */ },
  handler: async (args, ctx) => {
    return tracer.startActiveSpan('summarize', async (span) => {
      if (ctx.parent_trace_id) span.setAttribute('svantic.parent_trace_id', ctx.parent_trace_id);
      if (ctx.parent_span_id) span.setAttribute('svantic.parent_span_id', ctx.parent_span_id);
      try {
        return await do_summarize(args);
      } finally {
        span.end();
      }
    });
  },
});
```

## See also

* [Telemetry reference](./telemetry)
* [`CapabilitySessionContext`](./types#capabilitysessioncontext)
