Skip to main content
The Python SDK is in preview. It’s for building in-product agents — agents you write in Python and embed in your own product — and custom agents built on other frameworks (Agno, LangChain, OpenAI Agents, AWS Strands). To invoke or integrate xpander agents from an application, use the REST API, which is stable and works from any language.
The xpander.ai SDK is a typed Python client for the xpander.ai platform. It exposes six core modules (Backend, Agents, Tasks, ToolsRepository, KnowledgeBases, Events), plus a set of decorators (@on_task, @on_boot, @on_shutdown, @on_auth_event, @on_tool_*, @register_tool) for wiring your code into the agent runtime. Every method comes in two flavors: an async coroutine (e.g. aget, acreate_task) and a synchronous wrapper (get, create_task). Use the async forms in production; sync wrappers are convenient for scripts and notebooks.

Install

For Agno (the recommended framework), install the optional extras:

Authenticate

The SDK reads credentials from environment variables by default:
Or instantiate Configuration explicitly and pass it into any module:
See the Configuration reference for the full attribute list and self-hosted setup.

Initialize and call

For framework integration (Agno, OpenAI Agents, LangChain, Google ADK, AWS Strands), use Backend.aget_args() to resolve framework-specific kwargs from a stored agent configuration:

Async vs sync

Every coroutine has a sync sibling: same parameters, blocks until complete: Async methods are coroutines: wrap them in async def and call with await. Sync wrappers internally call run_sync(), so don’t call them from inside an existing event loop (FastAPI, asyncio scripts): use the a* form there.

Self-hosted

Point base_url at your Agent Controller endpoint and use the API key generated during your Helm install:
The SDK auto-detects when the URL points at a self-hosted controller (agent-controller in the host or port 9016) and prefixes paths with the organization ID. See the Configuration reference for details.

Where to next

Backend

Resolve framework args, invoke agents directly, report external runs.

Agents

List, load, and interact with agents.

Tasks

Create, stream, and inspect task executions.

Decorators

@on_task, @on_boot, @on_shutdown, and tool hooks.

Configuration

Configuration is the credentials object every SDK module accepts. By default each module instantiates its own Configuration from environment variables, so most code never touches it directly. Construct one explicitly when you need to override credentials or point at a self-hosted controller.

Constructor

Attributes

Environment variables

The SDK reads these on import. Setting them once via .env or your shell removes the need to construct Configuration manually.

Methods

get_full_url() -> str

Returns the API URL, with the organization ID appended when the controller requires it.
The org ID is appended automatically when base_url contains agent-controller or port 9016. You don’t need to do this yourself.

Self-hosted

Use the Agent Controller API key generated during your Helm install (not your cloud API key) and point base_url at the controller:
Or via environment:
The base_url must point at the Agent Controller endpoint (e.g. https://agent-controller.{your-domain}), not the root domain. The SDK detects this URL pattern and prefixes paths with the organization ID via get_full_url().

Sharing config across modules

Pass the same Configuration to every module so they hit the same endpoint and use the same credentials:
Loaded objects (Agent, Task, KnowledgeBase) carry the Configuration they were loaded with, so subsequent method calls on them reuse it automatically.

Types

A consolidated reference for every enum and Pydantic model exposed at the top level of xpander_sdk. Methods that take or return these types link here.

Enums

OutputFormat

ThinkMode

AgentExecutionStatus

See the task lifecycle.

AgentDeploymentType

AgentStatus

AgentAccessScope

AgentType

LLMReasoningEffort

Framework

Today only Agno is fully wired through Backend.aget_args; other values are reserved.

MCPServerType, MCPServerAuthType, MCPServerTransport

See MCP types.

TaskUpdateEventType

See streaming events.

KnowledgeBaseType

Models

Configuration

See Configuration.

User

End-user context. Pass to acreate_task(user_details=...) to scope memory and connector authentication to a specific user.

Tokens

Used in Backend.areport_external_task and Task.areport_metrics.

ExecutionTokens

Used internally for metrics aggregation.

AgentInstructions

Computed properties: description (= general), instructions (formatted XML block), goal_str, full.

AgentExecutionInput

Stored on task.input. Constructed automatically by acreate_task.

LocalTaskTest

Pass to @on_task(test_task=...) to invoke the handler once locally instead of subscribing to the platform.

TaskUpdateEvent

See streaming events.

ToolInvocationResult

See Tool class: ToolInvocationResult.

MCPServerDetails

See MCP types.

KnowledgeBaseSearchResult

Returned by KnowledgeBase.asearch.

KnowledgeBaseDocumentItem

See the KnowledgeBase reference.

AgnoSettings

Per-agent Agno configuration stored on agent.agno_settings. Modify in the Workbench; mutating in code only affects the in-memory instance.

AgentsListItem / TasksListItem

Summary objects returned by agents.alist() and tasks.alist(). See agents.list and tasks.list.

Exceptions

ModuleException

Raised by every SDK module on API failure. Carries status_code: int and description: str. See Error Handling.

Constants

MAX_PLAN_RETRIES

The maximum number of times the @on_task runtime retries a handler when deep-planning tasks remain incomplete after the first run.

Type aliases

LLMModelT

Marker type used internally for typing model classes.

Error Handling

Every SDK module raises ModuleException when an API call fails. The exception bundles the HTTP status code with a description so you can branch on the underlying cause.

ModuleException

The exception’s string form is [{status_code}] {description}.

Common status codes

Branching on status

Retry strategy

The SDK does not retry failed requests automatically (except inside Events.start(), which retries SSE connections internally). For idempotent operations, wrap calls in your own retry loop:
Avoid retrying:
  • 400 / 404: the request will keep failing.
  • acreate / acreate_task without an existing_task_id: you may create duplicate resources. Pass existing_task_id=... to make creation idempotent.

Validation errors from Tool.ainvoke

Tool invocations validate the payload against the tool’s auto-generated Pydantic schema before sending the request. A schema mismatch raises ValueError (not ModuleException):
Successful invocations still set is_error=True on the returned ToolInvocationResult if the remote endpoint returned an HTTP error. Check the result, not just exceptions:

Streaming errors

task.aevents() raises ValueError if the task wasn’t created with events_streaming=True. The underlying SSE connection logs warnings on parse failures and drops malformed events; it does not raise. Network failures propagate after the SDK’s internal retry budget is exhausted (see Events).