Launch quickstart
Run one OpenAI Chat Completions trace that matches the supported launch path: Python 3.11+, sync, non-streaming, explicit @st.agent and @st.tool, Observe, and configured Guard audit/block.
Anthropic Messages is supported with staso[anthropic]==0.5.15, anthropic==1.3.0, messages.create, and claude-haiku-4-5. Use the Anthropic quickstart if Anthropic is your default provider.
Create a requirements.txt
staso[openai]==0.5.15
openai==3.6.0Set the environment
Create a Staso API key in the dashboard for the workspace you selected. Use traces:write for Observe and add guard:evaluate when you test Guard audit/block.
export STASO_API_KEY=ak_...
export OPENAI_API_KEY=sk-...
export STASO_AGENT_NAME=launch-quickstart-agent
export STASO_ENVIRONMENT=production
export STASO_WORKSPACE_SLUG=defaultUse default only if that is the workspace selected in the dashboard.
Run the sample
from __future__ import annotations
import json
import os
from typing import Final
from openai import OpenAI
import staso as st
SESSION_ID: Final = "launch-quickstart-first-trace"
REQUIRED_ENV: Final = (
"STASO_API_KEY",
"OPENAI_API_KEY",
"STASO_AGENT_NAME",
"STASO_ENVIRONMENT",
"STASO_WORKSPACE_SLUG",
)
TOOLS: Final = [
{
"type": "function",
"function": {
"name": "lookup_order",
"description": "Look up the current status for a sample order.",
"parameters": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order ID to look up.",
}
},
"required": ["order_id"],
"additionalProperties": False,
},
},
}
]
def _load_settings() -> dict[str, str]:
missing = [name for name in REQUIRED_ENV if not os.environ.get(name)]
if missing:
raise RuntimeError("Missing required environment variables: " + ", ".join(sorted(missing)))
return {name: os.environ[name] for name in REQUIRED_ENV}
@st.tool(name="lookup_order")
def lookup_order(order_id: str) -> dict[str, str]:
return {
"order_id": order_id,
"status": "paid",
"shipping_state": "ready_to_ship",
}
@st.agent(name="launch-quickstart-agent")
def answer_order_question(order_id: str = "order_123") -> dict[str, object]:
client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
try:
response = client.chat.completions.create(
model="gpt-4o-mini",
messages=[
{
"role": "user",
"content": f"Look up the shipping status for order {order_id}.",
}
],
tools=TOOLS,
tool_choice={"type": "function", "function": {"name": "lookup_order"}},
)
except st.GuardBlocked as blocked:
return {
"status": "blocked",
"tool": blocked.tool_name,
"reason": blocked.reason,
}
tool_calls = response.choices[0].message.tool_calls or []
if len(tool_calls) != 1:
raise RuntimeError("Expected one lookup_order tool proposal from OpenAI.")
tool_call = tool_calls[0]
arguments = json.loads(tool_call.function.arguments)
result = lookup_order(**arguments)
return {"status": "observed", "tool_result": result}
def main() -> None:
settings = _load_settings()
st.init(
api_key=settings["STASO_API_KEY"],
agent_name=settings["STASO_AGENT_NAME"],
environment=settings["STASO_ENVIRONMENT"],
workspace_slug=settings["STASO_WORKSPACE_SLUG"],
)
try:
with st.conversation(SESSION_ID):
result = answer_order_question()
print(json.dumps(result, sort_keys=True))
finally:
delivery = st.shutdown(timeout=10)
if not delivery.ok:
raise RuntimeError(
"Trace delivery incomplete: "
f"last_failure={delivery.last_failure!r}, "
f"failed={delivery.failed}, "
f"pending={delivery.pending}, "
f"rejected={delivery.rejected}, "
f"last_rejection={delivery.last_rejection!r}"
)
print(
"Staso accepted trace delivery for "
f"session_id={SESSION_ID}. The dashboard/backend trace query may take a few "
"seconds to return the durable trace."
)
if __name__ == "__main__":
main()The same code lives in the repository at examples/launch_quickstart/openai_guard_quickstart.py.
The OpenAI client is constructed inside answer_order_question() after st.init() has run, so the traced agent input is only the safe sample order ID.
What the dashboard should show
After the dashboard/backend trace query can see the trace, expect:
session_id = launch-quickstart-first-traceenvironment = productionworkspace_slugequalsSTASO_WORKSPACE_SLUG- root span
kind=agent,name=launch-quickstart-agent,status=ok - LLM child span
kind=llm,provider=openai,requested_model=gpt-4o-mini,name=chat:tool_calls(lookup_order) - tool child span
kind=tool,name=lookup_order,status=okwhen Guard allows or audits - Guard audit adds
guard:would-block:lookup_order - Guard enforce/block adds
guard:blocked:lookup_orderand prevents thelookup_orderexecution span
DeliveryReport.ok means the SDK reached ingest acceptance. The onboarding milestone is satisfied only when the dashboard/backend returns the trace in the selected workspace.
How setup health is interpreted
connection_status=connectedmeans the selected workspace has a query-visible trace.last_successful_ingestion_atis the query-visible trace ingestion time, not client time.provider_patch_status=observedmeans a durably storedkind=llmspan hasprovider=openaiorprovider=anthropic.- Before that provider span appears, patch status is pending or unobserved. It is not guessed from install clicks.
- Setup failures use safe categories such as
invalid_key,forbidden,plan_expired,rate_limited,backend_unavailable,network_unavailable,timeout,malformed_response,queue_full,shutdown, anddisabled.
Guard boundary
Staso checks provider-proposed tool calls before your host code dispatches them.
- Audit records
guard:would-block:<tool>and allows the proposal. - Block records
guard:blocked:<tool>and raisesst.GuardBlocked. @st.toolobserves actual Python execution. It does not enforce Guard by itself.- Direct Python calls need
st.guard(...)when they require enforcement.
API key recovery
Key secrets are shown once. If you lose one, rotate the key or create a replacement in the dashboard, update STASO_API_KEY, restart long-lived processes, and revoke the old key. The SDK cannot show, rotate, revoke, or recover a raw secret.
If the trace does not appear
| Category | What to do |
|---|---|
invalid_key | Create a replacement key and update STASO_API_KEY. |
forbidden | Check workspace scope and traces:write. Add guard:evaluate for Guard. |
plan_expired | Fix the account plan or contact founders. |
rate_limited | Check usage and fair-use limits in the dashboard. |
backend_unavailable, network_unavailable, timeout | Retry after the service or network recovers. |
malformed_response | Contact [email protected] with the safe failure category. |
queue_full | Flush more often, reduce burst size, or contact founders. |
shutdown | Re-run the process after initializing Staso. |
disabled | Check that tracing is enabled in local config. |
Do not send API keys, prompts, tool arguments, provider responses, or customer data when asking for help.