Skip to main content

The ownership model

The Python SDK exposes two top-level building blocks:
  • SovaraClient owns project identity and trace-scoped helpers.
  • trace wraps application functions that should appear as steps.
All trace, subtrace, logging, lesson, and control operations go through that client. The project is not inferred from the working directory.

Top-level traces

Use a top-level trace for a workflow, evaluation sample, batch job, or durable conversation. A recording session opens that trace for appending work; a turn groups one interaction within it.
The SDK registers the trace with the exec server when the context opens and finalizes it when the context exits. The same context works with with and async with. For a durable conversation or workflow, pass your own stable identifier as trace_id, or reuse the trace ID yielded by a previous SDK trace. Reuse either value to add new steps to the same trace in that project.
Keep prompts, messages, and secrets out of trace_id; use a stable ID such as a chat, ticket, or job ID. The context yields the trace ID. Omit trace_id to create a new trace. Pass that ID to the CLI, here as TRACE_ID:

Steps and explicit tracing

Inside a trace, supported provider and MCP calls become ordered steps with input, output, latency, status, and error data. trace adds the same visibility to important application work that automatic instrumentation does not capture.
Place explicit tracing at shared tool or dispatch chokepoints. A trace filled with miscellaneous helper calls is harder to understand than one that exposes the agent’s decisions and meaningful actions.

Subtraces

Subtraces organize child agents, delegated branches, parallel work, and coherent multi-step phases under the active trace.
Use subtrace() for child work. Nesting trace() does not create a child trace.

Trace metadata

Use log() to attach input, output, and custom fields to a trace.
Input and output must be strings; serialize structured values with json.dumps(). Custom fields accept booleans, integers, finite floats, or strings. Omit absent values instead of passing None. If recording is unavailable, trace_id is None; skip logging for that trace. See the API reference for details. To group sample traces and record verdicts, follow the Evaluations guide.

Lessons

When automatic injection is enabled and the required models are configured, supported model calls retrieve from the project’s production lessons. Unapplied proposals are not used. Narrow retrieval with lesson_scope on a trace or subtrace:
Temporarily replace the active scope inside a smaller block:
See runtime retrieval for project settings.

Controls and concurrency

Async tasks inherit context. Create the with_context(...) wrapper inside the active trace before submitting it to a thread pool:
Await tasks and consume provider streams before leaving the recording context. For concurrent top-level traces, set capture_logs=False to avoid mixing process stdout/stderr between traces.

Run the application

Run the application normally. The SDK records the trace:
Open Sovara to inspect the recorded trace. Use the API reference for exact signatures.

Explicit conversation turns

trace() opens a recording session; it does not create an implicit turn. Declare interactions with scoped turn() blocks. Setup, cleanup, and other work outside those blocks are still captured, with no turn membership.
For one recording per interaction, reuse the same trace_id and declare the interaction explicitly:
Both trace() and turn() support async with. turn_input is an optional string for the interaction; logged input and output describe the whole trace. Do not nest turns in the same trace. Await tasks and consume streams before leaving the recording context.