Actions and Escalation
Guard returns one of four actions — allow, block, modify, or escalate — which tells your code what to do next.
import staso as st
result = st.guard("process_refund", {"amount": 4200, "user_id": "u_42"})
match result.action:
case "allow":
run(tool_input=result.modified_input or original_input)
case "modify":
run(tool_input=result.modified_input)
case "block":
log(result.reason)
case "escalate":
queue_for_human(result.escalation_id)allow
The call is approved — proceed as requested. This is the common path and incurs no extra work.
block
The call is denied. Do not execute the tool.
- In integrations (
patch_anthropic/patch_openai):staso.GuardBlockedis raised. You catch it and fall back. - In manual calls (
st.guard(...)): return early, logresult.reason, and decide how to recover. Logresult.rules_triggeredso you know which policy fired.
modify
Guard has rewritten the input. Use result.modified_input instead of the original arguments.
result = st.guard("send_email", {"to": "[email protected]", "body": "..."})
if result.action == "modify":
send_email(**result.modified_input) # rewritten, safer inputInside patch_anthropic / patch_openai, the integration applies the modification to the provider's tool-call object automatically — your agent loop sees the rewritten input transparently.
escalate
A human must approve the call before it can run. You have two options:
Fire-and-forget. Return immediately with result.escalation_id, surface it in your app, and let the human resolve it in the dashboard. Your code should treat escalate like block and not run the tool.
Synchronous wait. Pass wait_for_escalation=True and Guard polls until the escalation is resolved, returning either allow (approved) or block (denied / timed out).
result = st.guard(
"process_refund",
{"amount": 10000},
wait_for_escalation=True,
escalation_timeout=300.0, # max 5 minutes waiting
escalation_poll_interval=3.0, # check every 3 seconds
)
if result.action == "allow":
run_refund(amount=10000)
else:
log(f"escalation denied: {result.reason}")Defaults: escalation_poll_interval=3.0 seconds, escalation_timeout=300.0 seconds. Tune them for your UX — tight loops for chat-style apps, longer timeouts for batch jobs.
Trace visibility
Every decision lands on the active trace as a child span: guard:blocked:<tool>, guard:modified:<tool>, or guard:would-block:<tool> (for audit-mode rules that fired but let the call through). Open any trace on the dashboard to see what Guard did and why.
Next
- Manual Guard Checks — the full
st.guard(...)signature. - Error Handling — catching
GuardBlocked.
Rules and Policies
Guard ships with proprietary static rules and LLM-judge rules out of the box, plus your own custom rules bundled into policies — all manageable from the Staso dashboard.
Guard Error Handling
Catch staso.GuardBlocked from the Anthropic and OpenAI integrations, inspect which tools and rules fired, and recover gracefully from transport failures.