Read a run
Every run keeps its evidence. By the end of this page you will have read one back step by step withget_trajectory, read a run that paused for a person
as one story with get_run_trajectory, found a sub-agent’s run nested under
the call that started it, and seen exactly what the record does not hold.
Every output on this page is what the code printed when it was run with
gpt-5.4-mini. The model’s wording, the token counts, the prices and the IDs
will differ on your run.One run, step by step
- The harness is what the model ran with: the model, the 15 tools it was
offered (
get_weatherand the built-in workspace file tools, on by default), governance on, andprivacysaying the trace is redacted for credit cards, emails, phone numbers and SSNs. - Step 1: the model asked for
get_weather; the default policy allowed it by its ruleallow_local_tools; the observation is the exact text the model got back. - Step 2: the model answered, and the run ended with
final_answer. - Totals add it up.
evidence_statusiscompleteandcapture_gapsis empty: nothing in this record is missing, redacted, or cut short.
A run that paused: one story
A run that waited for an approval or a budget top-up, or was recovered after a crash, continues in a new trace segment.get_run_trajectory reads every
segment in order. Here a refund waits for a person:
- The first segment ended
suspended, with the callawaiting_approvaland the rule that asked. - The second segment picks up at the same step number, marked
resumed=True: the call is asked again, and allowed becausealiceapproved it. - The story’s
totalsare summed over the segments, with each step and each tool call counted once, by how it finally ended.approvalsandtool_callscome from the run’s record (Durable runs).
get_trajectory(run_id=...) would have returned only the second segment; it
lists the others in other_trace_ids_for_run.
A sub-agent’s run, nested
A delegated run has its own trace. The lead’s trajectory nests it under the tool call that started it, incall["subagent"]["child_trajectory"], down to
max_depth=5 levels:
totals are its own run’s; including_subagents adds its
children’s tokens and cost. Pass include_children=False to leave the
children out; get_trace_family(trace_id=...) lists the raw traces of the
lead and every child (Sub-agents).
What the record does not hold
A trace records the full trajectory by default (capture: "full"). A
deployment that must not keep prompts sets capture: "default", and the
trajectory says exactly what is missing:
- The prompts and responses were not recorded, but the facts were: tokens, cost, finish reason and latency are metadata, kept under every capture setting.
- Under governance, with a capture that records neither prompts nor
responses, tool arguments are recorded as
[REDACTED]: the record shows which arguments a call used, not their values. Withcapture: "full"the model’s own call already holds them, so they are recorded as written, through the privacy filter andredact_keys. - Every payload has a capture state:
available,redacted,truncated,offloaded,not_recorded,missingorinferred.capture_gapslists every record whose payload is not all there, and any gap makesevidence_statuspartial.
Over HTTP
OmniServe serves the same structures. A server on port 8123:run_id and
trace_id the run returned:
An unknown run is a
404 with {"detail":"No run nope"}; an unknown or
pruned trace, {"detail":"Trajectory not found"}.
How it works
1
Every run records typed events and spans
As the run goes, the runtime records a span for each piece of work (the
run, each step, each model call, each tool call) and an event for each
thing that happened in it, into the trace store.
2
Facts are metadata; payloads follow the capture policy
IDs, links between records, tokens, cost, outcomes and policy decisions
are event metadata, kept under every setting. Prompts, responses, tool
arguments and results are payloads, recorded as
capture and the
record_* settings say, redacted, and truncated or offloaded when large.3
The trajectory is built from the stored trace
get_trajectory reads the trace and places every event exactly once: in
the request, a step, a model call, a tool call, the final section, or an
other_events list where it occurred. Nothing is hidden, and nothing is
stored twice: the trajectory is computed when you ask for it.4
A run is its segments
The run’s record keeps the IDs of its traces.
get_run_trajectory reads
each one and sums them.The shape at a glance
A trajectory (omnicoreagent.trajectory/v1) is a plain dict. Every entry of
a list has every field, None when it does not apply.
The harness
The run’srun_configuration event, recorded before the first step under
every capture setting. Never credentials.
Each step
Each model call
facts holds tokens (input, output, total, and cached_input and
reasoning when the provider reports them), estimated_cost_usd with
cost_source (provider_response when the response came with its cost,
as LiteLLM attaches for models it knows, or price_table when it was
computed from LiteLLM’s prices afterwards; either way an estimate, not an
invoice),
latency_ms, time_to_first_delta_ms for streamed text, finish_reason,
refused, provider_model and provider_response_id, request_settings,
policy_version (the model the provider served, with its fingerprint when
reported), attempts and retries (each failed attempt, its message
redacted), and, for a thinking model, continuation (counts and a digest;
signatures and encrypted values are never recorded).
Each tool call
Each
governance entry has effect (allow, ask, deny), capability,
reason_code (matched_allow, matched_ask, approved, denied,
expired_policy, …), matched_rule_ids, and for a person’s decision
approval_id and approved_by or denied_by (system when nobody decided
in time; Approvals).
Totals
steps; model_calls (total, agent_turn, context_summary, failed);
tokens; estimated_cost_usd and cost_complete (False when any call
had no known price); model_latency_ms; model_retries; tool_calls
(total and by_outcome); compressions; runtime_messages by kind;
subagents (count, child_trace_ids); executions (sandbox sessions,
commands, failed, timed_out); workspace_changes, each via a tool
or the sandbox; offloaded_results; duration_ms; and
including_subagents (tokens, cost, cost_complete with the children).
A whole run
get_run_trajectory(run_id) returns run_id, session_id, agent_name,
status (the run’s), attempt and previous_attempts, segments (each
with trace_id, status, trajectory and trace_kept), traces_missing,
totals, tool_calls and approvals (from the run’s record), and usage.
The run’s saved conversation is not included.
Traces are kept 7 days by default and run records 30. After a segment’s trace
is pruned, it stays in the story with trace_kept: False and trajectory: None; traces_missing counts them, and totals cover only the traces still
kept (empty, not zero, when none is). The record’s usage remains. See how
long a run’s evidence is
kept.
Options
What is recorded is set by
telemetry_config: capture ("full" by
default, or "default"), the record_* switches, and retention_days
(telemetry settings). Every method is in
the OmniCoreAgent reference.
When things go wrong
get_trajectory returns None
get_trajectory returns None
No stored trace has that ID: a typo, a trace from another store (another
workspace, or
storage: "memory" in another process), or one pruned
after retention_days (7 by default). get_run_trajectory returns
None when no run record has that ID; a record whose traces are gone
has trace_kept: False segments instead.TypeError: get_trajectory() requires trace_id or run_id
TypeError: get_trajectory() requires trace_id or run_id
Pass one of them:The second is a positional ID together with
run_id=.The trajectory has only half the run
The trajectory has only half the run
The run paused and resumed:
get_trajectory(run_id=...) is its latest
segment only (the others are in other_trace_ids_for_run). Read the
whole run with get_run_trajectory(run_id).request and response are None, arguments are [REDACTED]
request and response are None, arguments are [REDACTED]
The agent records with
capture: "default", or a record_* switch is
off. Check request_capture and response_capture: not_recorded says
why. Tokens, cost and outcomes are still there.estimated_cost_usd is None, or cost_complete is False
estimated_cost_usd is None, or cost_complete is False
None: nothing was priced, because no model call answered (a run cut off
by its deadline before the first answer) or the model has no published
price (a model behind base_url, for example). cost_complete: False:
some calls could not be priced, so the figure is a lower bound. The
tokens are right either way. including_subagents follows the same
rule. Guard for None before rounding or adding.Next
Telemetry and exporters
What is recorded, where it is kept, the live stream, and exporting to OTLP, LangSmith, Opik and JSONL.
Outcomes and training
Attach what a run turned out to be worth, and read runs back as training records.
Headless runs
Run from the command line and keep the evidence.
Harbor
Run the agent on benchmarks, with each trial’s trajectory.