xenovia-sdk) sends an agent’s actions to Xenovia for a decision before they happen: tool calls and tool results, memory writes, context summaries, and — for agents that call their model directly — the model request and reply. Each check runs the guardrails configured on the agent for that stage; model_request, model_response, and tool_call checks also run the agent’s policies.
Use it alongside the agent endpoint: the endpoint governs model traffic, and the SDK governs the steps your code takes around it. Tool, memory, and summary guardrails only run when the SDK sends those stages.
Install:
How it works
Every SDK call is aPOST /v1/execute to the Xenovia runtime, authenticated with the agent’s xe_ API key. The key identifies the agent, so the request body does not name it.
decision["escalated"] is true when a guardrail escalated the step. The step is still allowed, and an escalation is queued for review (see Escalations).
Initialise the client
Constructor parameters
unreachable_mode values:
The
"block" and "allow" fallbacks are produced by the SDK on your machine, not by Xenovia. You can tell them apart from a real decision: decision["rule_id"] is SDK_UNREACHABLE_BLOCK or SDK_UNREACHABLE_ALLOW, trace_id is None, and no trace appears in the platform.Hooks
Hooks are the main API. Each one sends one stage and returns aXenoviaResponse. Hooks never skip work for you: check the response and act on it.
Every hook also accepts
session_id=.
payload["arguments"]; a redacted tool result, memory write, or reply returns masked text in payload["content"] or payload["response"].
If your model calls already go through the agent endpoint, leave
model_pre and model_post off: the runtime checks the model request and reply there. Use them only for agents that call their model provider directly.model_pre accepts messages with string content or a list of content parts (OpenAI or Anthropic style), and tools as flat {name, description} objects or OpenAI function tools. Only text is checked: text parts, refusal parts, and the text of Anthropic tool_result, mcp_tool_result and search_result blocks (string content or nested text parts) are joined. Media and file parts, the model’s own tool calls (tool_use, server_tool_use, mcp_tool_use) and thinking, and Anthropic server tool results (web search, web fetch, code execution) are not sent, so their content is not checked. On success, payload["messages"] and payload["tools"] are your own objects, with any redaction written back into the part it came from.
model_pre, and model_post when you pass messages, raise ValueError, and send nothing, when messages are not a list of dicts, a role is not a string, content is not a string, a list, or None, or a content part is malformed or of a type not listed above. model_pre also raises it when a tool is not a dict or has no name.
execute() — a single check
execute() is the call the hooks are built on. Use it for actions that are not a tool, memory, or model step.
stage is one of model_request, model_response, tool_call, tool_result, memory_write, or context_summary. If operation is omitted, the SDK uses the caller’s module.function name.
capability= was renamed to operation= in 0.2.0. In 0.2.1 capability= still works on execute() and @guard() as a deprecated alias and emits a DeprecationWarning.@guard() — decorator
@guard() checks a function call as a tool_call before the body runs. The decorated function returns a XenoviaResponse; read .result for the function’s return value.
- The payload sent is
{"arguments": {...}}, with every bound argument (including defaults). - On
allow, the function runs with its original arguments. Onredact, it runs with the masked arguments. Ondenyorerror, it does not run. async deffunctions are supported.mode="enforce"is the only mode. The SDK has no observe mode: to trial a rule without blocking, set the policy or guardrail to Monitor in the console. Monitor evaluations returnallow.
Roles and subagents
Setagent_role on the client, or create a child client with subagent():
subagent() returns a new client with the same key and endpoint, the given role, and agent_depth one higher. It gets its own session, but because it uses the same key it is the same Xenovia agent: its checks run that agent’s policies and guardrails. Give a subagent its own agent and key when it needs a separate identity.
XenoviaResponse
trace_id in the platform to see which policy or guardrail fired.
Sessions
The runtime issues the session and returns it in theX-Xenovia-Session-Id response header; the SDK stores it on the client.
- With
auto_session=True, the first call lets the runtime create a session and later calls reuse it. - Otherwise, pass
session_id=(a UUID) on each call, or share a session ID with your agent endpoint traffic so SDK steps and model turns appear in one session. - If the runtime returns a different session than the one you sent, the SDK raises
XenoviaExecutionError. next_turn()only advances a local counter. To report a turn number, passturn=toexecute().
Error handling
ValueError before any request is sent, for example a model_pre message part the SDK cannot read.
Wire format
session_id, agent_role, and agent_depth are sent only when set.
Security
- HTTPS is required unless
allow_insecure_http=True, which is limited to loopback addresses. - The API key is sent only in the
Authorizationheader, never in payloads or logs. - Debug output prints the decision outcome and trace ID, not payloads.