Python SDK
Manual Spans
st.span is a context manager for when decorators are too coarse. Use it for sub-steps, conditional tracing, or anything you need to mutate while it runs.
import staso as st
with st.span("embed-query", kind="retriever") as s:
s.metadata["query"] = query
result = embed(query)
s.metadata["hit_count"] = len(result)Signature
st.span(
name: str,
*,
kind: str | SpanKind = SpanKind.CHAIN,
) -> ContextManager[Span]Valid kind values: "llm", "tool", "chain", "retriever", "agent", "custom".
When to use manual spans vs decorators
| Use decorators when | Use manual spans when |
|---|---|
| You want to trace a whole function. | You need to trace only a block inside a function. |
| Inputs and outputs match what you want to record. | You want to attach metadata that isn't a function argument. |
| The call site is stable. | Tracing is conditional — only if a feature flag is on, for example. |
| One unit of work per function. | You need to update span fields mid-execution. |
Decorators and manual spans compose freely. A decorated function can open manual spans inside itself.
Span methods
The object yielded by with st.span(...) as s exposes a small set of user-facing methods and fields.
| Method / field | Purpose |
|---|---|
s.metadata[key] = value | Attach arbitrary JSON-serializable metadata. |
s.input = {...} | Record a custom input payload. |
s.output = {...} | Record a custom output payload. |
s.annotate(name, value=..., data_type=..., comment=...) | Attach a score or label to this span's trace. See annotations. |
s.set_status(status, description=None) | Force the span status (ok, error, timeout). |
s.record_exception(exc) | Mark the span as errored and record the exception message. |
Exceptions raised inside the with block are automatically recorded — you only need record_exception if you are catching the exception and still want it logged on the span.
with st.span("call-stripe", kind="tool") as s:
try:
charge = stripe.charge(...)
s.output = {"charge_id": charge.id}
except stripe.error.CardError as exc:
s.record_exception(exc)
s.set_status("error", "card declined")
raise