SDK setup
Use this path when your own Python application calls a model provider. For Claude Code or Codex, use coding agent setup.
Install
pip install "staso[openai]"
# or
pip install "staso[anthropic]"
# or
pip install "staso[litellm]"Python 3.11 or newer is required. The supported paths are non-streaming OpenAI Chat Completions, Anthropic Messages, and direct LiteLLM completion() / acompletion() calls on the tested OpenAI route. Choose the extra for the provider your application imports. Streaming is outside the supported launch path.
Initialize
import staso as st
st.init(api_key="ak_...", agent_name="support-agent")You can provide the credentials through environment variables:
export STASO_API_KEY=ak_...
export STASO_AGENT_NAME=support-agentSet STASO_ENVIRONMENT and STASO_WORKSPACE_SLUG to the selected dashboard workspace. Call st.init() before constructing OpenAI or Anthropic clients, or before the first LiteLLM call. Installed integrations are patched automatically. Set STASO_AUTO_PATCH=false only when you plan to patch manually.
Wrap an agent entry point with @st.agent, run one real provider call, then open Traces → Traces in the selected workspace. st.flush() or st.shutdown() confirms delivery acceptance; the trace is ready when it is query-visible in the dashboard.
Signature
st.init(
*,
api_key: str | None = None,
agent_name: str | None = None,
agent_version: str | None = None,
base_url: str | None = None,
batch_size: int = 100,
flush_interval: float = 0.5,
max_queue_size: int = 10_000,
enabled: bool = True,
debug: bool | None = None,
environment: str | None = None,
workspace_slug: str | None = None,
capture_messages: bool | None = None,
capture_request: bool | None = None,
capture_system_prompt: bool | None = None,
capture_tool_schema: bool | None = None,
capture_tool_arguments: bool | None = None,
capture_output: bool | None = None,
capture_git: bool = True,
) -> Client| Name | Default | Purpose |
|---|---|---|
api_key | STASO_API_KEY | Required Staso API key. |
agent_name | STASO_AGENT_NAME | Required process-level agent name. |
agent_version | STASO_AGENT_VERSION or "" | Free-form version label on emitted spans. |
base_url | STASO_BASE_URL or https://api.staso.ai | Staso service endpoint override. |
batch_size | 100 | Maximum spans grouped before a flush. |
flush_interval | 0.5 | Seconds between background flush attempts. |
max_queue_size | 10_000 | In-memory queue limit; spans beyond it are rejected locally and surfaced in delivery reports. |
enabled | True | False makes tracing a no-op. |
debug | STASO_DEBUG or False | SDK debug logging. |
environment | STASO_ENVIRONMENT or default | Environment label. |
workspace_slug | STASO_WORKSPACE_SLUG or default | Target workspace. |
capture_messages | None | Deprecated compatibility control for request messages and system prompts. |
capture_request | None | Override request-content capture. |
capture_system_prompt | None | Override standalone system-prompt capture. |
capture_tool_schema | None | Override tool and structured-response schema capture. |
capture_tool_arguments | None | Override proposed and executed tool-argument capture. |
capture_output | None | Override assistant and tool-result capture. |
capture_git | True | Attempt to attach detected VCS metadata to roots. |
See environment variables for the full mapping.
Define the supported root and tools
@st.tool
def search(query: str) -> list[str]:
return index.search(query)
@st.agent
def answer(question: str) -> str:
results = search(question)
return summarize(results)Use explicit decorators for all three provider integrations. @st.agent gives the run a root, and @st.tool records a Python function that actually executed. A model's tool proposal is separate from execution.
Capture suppression
All five capture categories default to enabled:
| Category | Controls |
|---|---|
request | Agent arguments, user/request messages, request-derived labels, and caller metadata. |
system_prompt | OpenAI system/developer messages and Anthropic system. |
tool_schema | Tool definitions and structured-response schemas. |
tool_arguments | Proposed or executed tool arguments, including arguments sent for Guard evaluation. |
output | Assistant content, tool results, return values, and Guard reason prose. |
Configure categories independently:
st.init(
api_key="ak_...",
agent_name="support-agent",
capture_request=False,
capture_tool_arguments=False,
capture_output=True,
)Resolution is deterministic: an explicit capture_<category> argument wins, then its STASO_CAPTURE_<CATEGORY> environment variable, then the deprecated capture_messages argument or STASO_CAPTURE_MESSAGES for request and system_prompt only, then True. An explicit category setting always wins over the compatibility control.
Suppression removes the governed value before SDK payload serialization. It does not add hashes, excerpts, lengths, or placeholders. Enabled content may be redacted by the backend before storage; redacted is a backend storage state, not a setting or state emitted by this SDK.
Guard respects the same controls before sending an evaluation request. A rule that needs suppressed arguments, schemas, or history cannot use that missing evidence to produce a finding. See Guard evidence and capture.
When a value crosses categories, each relevant category must be enabled. For example, tool-call arguments embedded in an assistant response require both tool_arguments and output.
Use decorator controls for a function payload:
@st.tool(capture_input=False, capture_output=False)
def read_secret(secret_id: str) -> str:
return vault.read(secret_id)Decorator capture is the global category setting and its local flag. With input capture disabled, the decorator does not build an argument payload.
Delivery lifecycle
report = st.shutdown(timeout=5)
if not report.ok:
raise RuntimeError(f"Trace delivery incomplete: {report.last_failure}")Call st.shutdown() when a short-lived process is done. It stops the client, attempts to drain within the timeout, and returns a DeliveryReport. report.ok is false for failed or pending delivery, a timeout, or a local queue rejection; inspect last_failure, rejected, and last_rejection for safe failure categories.
Use st.flush(timeout=5) in a warm serverless worker. It waits for events accepted before the call and keeps the client ready for the next invocation.
Calling st.init() again retires the previous client and attempts its bounded drain. Inspect new_client.previous_shutdown_report; it is None on the first initialization.