Skip to main content

Report a reasoning trail

Calls that go through the gateway are recorded for you. Many applications do more than call a model: they call tools, query databases and make decisions. Report those steps and Bairav shows one trace per prompt, so a reviewer can see what the agent did and why a policy decided as it did.

You use the same gateway key. Nothing else is needed.

Report events​

POST /gw/{token}/events takes one trace at a time:

FieldMeaning
trace_idA UUID you choose, shared by every event of the prompt
events[].kindllm_call, tool_call, db_action, policy_evaluation, authorization_decision, egress, guardrail_block or observation
events[].okWhether the step succeeded
events[].duration_msHow long it took
events[].summaryA short label, at most 500 characters
events[].detailAn object with specifics. Every string in it is masked.
events[].parent_indexThe position, in this same array, of the event that caused this one. Use it to show fan-out and sub-agents.

Send the X-Bairav-Agent header to attribute events to an agent, and optionally X-Bairav-User for the end user the agent acted for.

Limits: at most 200 events and 256 KB per request. An event with an unknown kind is counted in rejected; it never fails the request. A request with invalid JSON, no trace_id or an empty events list returns 400, and a payload over 256 KB returns 413.

Reporting a db_action event whose detail has a table (and optionally an operation) also feeds the data-lineage graph, so the agent is linked to the table it touched.

Report database queries​

POST /gw/{token}/db accepts up to 200 queries per request, each with operation, table, sql, duration_ms, rows, ok and trace_id. They are stored and mirrored into agent activity so the agent graph shows the real tables.

Read a trace back​

GET /gw/{token}/trace/{trace_id} returns every event of the trace in chronological order, at most 500, scoped to the tenant that owns the key. You can use it to render your own reasoning page without giving your application a Bairav user session. The row shape matches the Portal API's GET /api/lineage/events/traces/{trace_id}.

Try it​

samples/gateway/report_trace.py
"""Report what your agent did to the Bairav reasoning trail, then read the trace back.

Uses only the standard library. BAIRAV_GATEWAY_URL is the openai_base_url of your gateway key.
"""
import json
import os
import urllib.request
import uuid

# The events and trace endpoints sit next to /v1 under the same gateway key.
base = os.environ["BAIRAV_GATEWAY_URL"].removesuffix("/v1").rstrip("/")
trace_id = str(uuid.uuid4())


def call(method: str, url: str, body: dict | None = None) -> dict:
data = json.dumps(body).encode() if body is not None else None
req = urllib.request.Request(url, data=data, method=method, headers={"Content-Type": "application/json", "X-Bairav-Agent": "support-bot"})
with urllib.request.urlopen(req, timeout=15) as resp:
return json.load(resp)


sent = call(
"POST",
f"{base}/events",
{
"trace_id": trace_id,
"events": [
{"kind": "tool_call", "ok": True, "duration_ms": 120, "summary": "lookup_order"},
{"kind": "db_action", "ok": True, "duration_ms": 8, "summary": "SELECT on orders", "parent_index": 0, "detail": {"table": "orders", "operation": "select"}},
],
},
)
print("accepted:", sent["accepted"], "rejected:", sent["rejected"])

trace = call("GET", f"{base}/trace/{trace_id}")
print(f"trace {trace['trace_id']} has {len(trace['items'])} events") # each item is one recorded event, in chronological order

What is never stored​

Bairav records the steps, not the model's private reasoning. Content in detail is masked, and no chain-of-thought is stored or returned.