A trace records the full trajectory of an agent run. A review marks the outcome and triggers memory creation. Together they form the learning loop that makes future memory queries more useful.
Create a trace
submission = client.create_trace(
task="Parse the CSV and return the top 5 rows",
trajectory=[
{"role": "user", "content": "Parse the CSV..."},
{"role": "assistant", "content": "Here are the top 5 rows: ..."},
],
retrieved_memory_ids=["mem-abc", "mem-def"],
model="gpt-5.4-mini",
metadata={"source": "cli", "run_id": "run-123"},
# final_response is optional — auto-extracted from the last assistant message
)
print(submission.id) # trace UUID
print(submission.ingest_status) # "completed" (no review) or "queued" (with review)
| Parameter | Type | Default | Description |
|---|
task | str | required | The task given to the agent |
trajectory | list[dict] | str | required | The conversation between user and agent — role/content message dicts or a JSON string |
final_response | str | None | None | The agent’s final answer. When omitted, extracted from the last assistant message in the trajectory. |
retrieved_memory_ids | Sequence[str] | () | IDs of memories used during this run (Q-values will be updated on review) |
model | str | None | None | Model identifier |
metadata | dict | None | None | Arbitrary key-value pairs |
review_result | str | None | None | Inline review result: "pass", "fail", "success", or "failure" |
feedback_text | str | None | None | Optional feedback text (typically added by judge/platform workflows) |
create_trace returns a TraceSubmission (not a full Trace). Use wait_for_trace or get_trace to fetch the complete object.
Inline review
Include the review when creating the trace. The review is processed asynchronously:
submission = client.create_trace(
task="...",
trajectory=[...],
retrieved_memory_ids=["mem-abc"],
review_result="success",
)
# submission.ingest_status == "queued"
The SDK accepts "success" / "failure" as aliases for the API’s "pass" / "fail".
Deferred review
Create the trace without a review, then submit one later when feedback is available:
submission = client.create_trace(
task="...",
trajectory=[...],
)
# Later, after human evaluation:
trace = client.review_trace(
trace_id=submission.id,
result="failure",
)
# trace.review_status == "reviewed"
# trace.created_memory_id is set
Deferred reviews are processed synchronously — the returned Trace includes the review and created memory ID.
Waiting for ingestion
Inline reviews are processed in the background. Poll until the trace is fully ingested:
trace = client.wait_for_trace(
submission.id,
require_reviewed=True,
poll_interval=0.25,
wait_timeout=60.0,
)
| Parameter | Type | Default | Description |
|---|
trace_id | str | required | Trace to wait for |
require_reviewed | bool | False | If True, wait until review_status == "reviewed" |
poll_interval | float | 0.25 | Seconds between polls |
wait_timeout | float | 60.0 | Maximum seconds to wait before raising TimeoutError |
Raises RuntimeError if ingestion fails, TimeoutError if the deadline is exceeded.
Create and wait
Combine trace creation and polling in one call:
trace = client.create_trace_and_wait(
task="...",
trajectory=[...],
review_result="pass",
poll_interval=0.5,
wait_timeout=30.0,
)
# Returns the fully processed Trace
List and fetch traces
pending = client.list_traces(review_status="pending")
reviewed = client.list_traces(review_status="reviewed")
all_traces = client.list_traces()
trace = client.get_trace(trace_id="abc-123")
Each returned Trace includes the attached Review (if reviewed), the created_memory_id, and ingestion status.
In production flows, feedback text is generally generated by an LLM judge pipeline or entered in the platform UI. SDK/API usage usually submits just the pass/fail result.