Skip to content
agentFast
The production layer

Observability

Step trees, cost and latency per step, OTEL and LangSmith export.

In short: every step the agent took, what it cost, and how long it took — recorded as it happens and readable afterwards. When someone asks "why did it do that," this is the answer.

Every run produces a step tree: an ordered record of what the agent did, what it cost, and how long each part took. It's written to Postgres as the run happens, which is what makes it survive the process that produced it.

The step record

class StepRecord(BaseModel):
    run_id: str
    idx: int
    type: StepType        # llm | tool | guardrail | memory | hitl | eval | planning
    name: str
    input: dict           # post-redaction
    output: dict          # post-redaction
    ok: bool
    error_code: str | None
    tokens_in: int
    tokens_out: int
    cost_usd: float
    latency_ms: int

Inputs and outputs are stored post-redaction — the trace can never contain PII the model wasn't allowed to see either. That single invariant is why the live stream can be fed from step records without a second redaction pass.

Cost accounting

Per step, including prompt-cache reads, which most tooling gets wrong:

observability:
  pricing:
    claude-sonnet-4-5:
      input_per_1m: 3.00
      output_per_1m: 15.00
      cache_read_per_1m: 0.30

Cache reads are billed at a fraction of input tokens. Counting them as normal input can overstate a cached run's cost by an order of magnitude — and cached runs are exactly the ones you're likely to have a lot of.

NoteUnpriced models cost zero

A model with no pricing entry logs a warning and costs $0. If your dashboard shows a suspiciously free run, check the model id is in observability.pricing.

Export

OTEL — the finished step tree exported as a span tree:

observability:
  otel_endpoint: https://otlp.example.com/v1/traces
  otel_headers:
    authorization: Bearer ${OTEL_TOKEN}

LangSmith — a first-class exporter, not an OTLP shim:

observability:
  langsmith:
    api_key: ${LANGSMITH_API_KEY}
    project: agentfast-prod

When both are configured, LangSmith wins. Export is fire-and-forget by contract — telemetry failing never takes down a run.

The canonical run record

One telemetry record per run, assembled at run_end:

curl localhost:8321/api/runs/run_abc/telemetry

Totals, per-step-type breakdowns, and the outcome — the thing to ship to a warehouse when you want to ask "what did support agents cost last week" without replaying every step.

Watching a run happen

The dashboard renders the step tree live, and streaming pushes the same steps over SSE as they're written. Same data, two latencies: the stream is a view, Postgres is the record. If they ever disagree, Postgres is right.

TipThe tracer has a spare hook

TelemetryHub takes optional on_step and on_run_event callbacks. If you want to fan run activity somewhere agentFast doesn't ship an exporter for — a queue, a webhook, your own metrics pipeline — that's the seam, and it's fire-and-forget like everything else here.