Staso Docs
Python SDK

Decorators

Three decorators — pick by intent. All work with sync and async.

import staso as st

@st.agent
def handle_ticket(ticket_id: str) -> str:
    return draft_reply(fetch(ticket_id))

@st.tool
def fetch(ticket_id: str) -> dict:
    return db.lookup(ticket_id)

@st.agent

Marks an agent entry point. Produces a span of kind agent and overrides the agent name for everything nested inside — the primary way to label per-agent traces when one process runs more than one agent.

@st.agent
def research_agent(query: str) -> str: ...

@st.agent(name="billing-agent", tags=["v2"])
async def billing_agent(user_id: str) -> str: ...

@st.tool

Wraps a tool function. Produces a span of kind tool.

@st.tool
def search_docs(query: str) -> list[str]: ...

@st.tool(name="stripe.refund")
async def refund(charge_id: str) -> bool: ...

@st.trace

Generic. Produces a chain span by default; override kind for retrievers, custom steps, etc.

@st.trace(kind="retriever")
def embed_and_search(query: str) -> list[str]: ...

Valid kind: "llm", "tool", "chain", "retriever", "agent", "custom".

Parameters

All three accept the same keyword args:

ParameterDefaultDescription
namefunction nameSpan name.
kindvariesagent / tool / chain. @st.trace lets you override.
tagsNoneFree-form tags.
metadataNoneJSON-serializable metadata.
capture_inputTrueRecord arguments.
capture_outputTrueRecord return value.

Capture flags

Disable when the payload contains PII, secrets, or megabyte blobs. For a global kill switch on LLM message content, use capture_messages=False in st.init.

@st.tool(capture_input=False)
def charge_card(card_number: str, amount_cents: int) -> str: ...

Exceptions

If the function raises, the span is marked error, the exception message is recorded, and the exception propagates.

Next