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:
| Field | Meaning |
|---|---|
trace_id | A UUID you choose, shared by every event of the prompt |
events[].kind | llm_call, tool_call, db_action, policy_evaluation, authorization_decision, egress, guardrail_block or observation |
events[].ok | Whether the step succeeded |
events[].duration_ms | How long it took |
events[].summary | A short label, at most 500 characters |
events[].detail | An object with specifics. Every string in it is masked. |
events[].parent_index | The 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
"""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.