Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.xpander.ai/llms.txt

Use this file to discover all available pages before exploring further.

xpander.ai is a platform for building production AI agents. An agent is the platform’s central object: a configured LLM with instructions, tools, knowledge bases, memory, and a deployment target. This page is the SDK companion that tells you which Python class each of those concepts becomes when you import xpander_sdk. The job of this page: when you see Backend, Task, or agent.tools.functions in code, you should know exactly what they are without context-switching back to the conceptual docs.

Product Guides → Core Concepts

The same model from the Agent Studio side. Read that for the concepts; read this for the class names.

The two halves

xpander splits responsibilities between a control plane (cloud or self-hosted) and your runtime. Reading code, you’ll move between three boundaries constantly:
Control plane              SDK objects in your process       Framework
(cloud / self-hosted)
                          ┌────────────────────┐
   Agent definition  ───▶ │  Backend, Agent    │ ─▶  Splatted into AgnoAgent(**args)
   Tools / connectors ──▶ │  ToolsRepository   │ ─▶  agent.tools.functions
   Knowledge bases ────▶  │  KnowledgeBase     │ ─▶  retriever wired into args
   Postgres (sessions) ─▶ │  Agent.aget_db()   │ ─▶  args["db"]
                          │                    │
   Task created ────────▶ │  @on_task → Task   │ ─▶  Your handler runs
                          └────────────────────┘
The SDK objects are thin wrappers around the platform’s HTTP API. They’re how you read and write to it from Python.

Backend

Backend is the gateway. It’s the only class that knows how to talk to the control plane to fetch a fully resolved agent definition. Inside an @on_task handler, the typical use is one line:
from xpander_sdk import Backend

backend = Backend(configuration=task.configuration)
args = await backend.aget_args(task=task)
The returned dict contains everything Agno needs:
  1. Model client with credentials.
  2. Instructions (system prompt, role, goal).
  3. Tools (connectors + your @register_tool functions).
  4. Session DB.
  5. Memory settings.
  6. Output schema.
Splatting it into agno.agent.Agent(**args) is the production pattern. Pass the current task so the SDK can forward task-level overrides (instructions overrides, expected output, output schema) through to the framework. Both get_args (sync) and aget_args (async) accept the same arguments. The async form is what you’ll use inside @on_task and any FastAPI service; the sync form is fine in scripts and notebooks. This async/sync pairing holds across the entire SDK.

Agent

Agent is the loaded, in-memory representation of an agent. It carries everything the control plane knows about it:
  1. Name and unique identifier.
  2. Instructions (role, goal, general).
  3. Framework selection.
  4. Model + provider.
  5. Deployment type (Serverless or Container).
  6. Tools, knowledge bases, sub-agents.
  7. Memory settings.
from xpander_sdk import Agents

agent = Agents().get(agent_id="...")
print(agent.name, agent.model_provider, agent.model_name)
print(agent.deployment_type)              # AgentDeploymentType.Serverless or .Container
print(len(agent.tools.list))              # Tools available, including connectors
Two collection helpers:
  • Agents().get(agent_id=...): returns a fully loaded Agent. Heavyweight.
  • Agents().list(): returns AgentsListItem summaries (just names + IDs). Faster when you’re enumerating. Call .aload() on a list item to upgrade it to a full Agent.

Task

A Task is one execution. It has an ID, a status, an input, and a result.
task = agent.create_task(prompt="Summarize the attached PDF",
                         file_urls=["https://example.com/report.pdf"])

print(task.id, task.status)               # "executing", typically
Status values: pending, executing, completed, failed, plus a few transitional states. Inside @on_task, the platform creates the Task for you and you receive it as a parameter. Your job is to set task.result and return the task. The decorator marks it completed if you return cleanly, or failed if you raise. Helpers on Task for framework integration:
  • task.to_message(): joins input text, file URLs, and any embedded readable file content into a single string ready to feed into Agno.
  • task.get_files(): returns PDFs as agno.media.File objects.
  • task.get_images(): returns image URLs as agno.media.Image objects.
Load a task by ID later with Tasks().get(task_id). That’s how you implement retries, audit logging, or deferred result fetching.

Threads (sessions)

The SDK doesn’t have a class called Thread. What Agent Studio shows as a thread is a session_id shared across multiple Tasks, with the conversation history persisted in the agent’s Postgres schema. If your agent has Agno session storage enabled, you can list and inspect those sessions directly:
sessions = agent.get_user_sessions(user_id="user_123")
for s in sessions:
    print(s.session_id, len(s.messages))

# Load a single session
session = agent.get_session(session_id="sess_abc")

# Wipe it
agent.delete_session(session_id="sess_abc")
Behind the scenes, agent.get_db() returns the underlying agno.db.postgres.AsyncPostgresDb instance scoped to this agent’s schema. Reach for it directly only when you want to do something Agno doesn’t expose, like writing custom Postgres queries against session metadata.

Connectors and tools

Whatever you select in Agent Studio under “Tools” becomes available in code as part of agent.tools. There are three flavors and one container:
  • Connectors: pre-built integrations from the catalog (Slack, Gmail, GitHub, 2,000+). Authenticated and configured in Agent Studio.
  • Custom tools: Python functions you’ve decorated with @register_tool in your handler.
  • MCP servers: model-context-protocol servers, either remote (URL) or local (process), wired in through Agent Studio.
  • agent.tools: the unified ToolsRepository that flattens all three into one list. agent.tools.list enumerates Tool objects; agent.tools.functions returns normalized callables ready to bind to LangChain, OpenAI Agents SDK, or any framework that accepts plain Python functions.
@register_tool
def lookup_customer(customer_id: str) -> dict:
    """Fetch a customer record from the internal API."""
    ...

# After the agent loads, lookup_customer shows up alongside connectors:
[t.name for t in agent.tools.list]
# -> ['SlackPostMessage', 'GmailSend', 'lookup_customer', ...]
Each Tool has a parameters JSON schema that the agent’s LLM uses to call it. The SDK auto-generates that schema from your function’s type hints and docstring, which is why annotation matters more than usual here.
agent.tools.functions is framework-agnostic. You can import an xpander agent’s tool list into any LLM client that accepts plain Python callables, including raw openai.OpenAI().chat.completions.create(tools=[...]) calls or a homegrown ReAct loop. This is the escape hatch when none of the supported framework adapters fit your stack.

Knowledge bases

KnowledgeBase represents one document collection. The platform-managed type is the default; external KBs (your own vector store) are an advanced setup.
from xpander_sdk import KnowledgeBases

kbs = KnowledgeBases()
kb = kbs.get(knowledge_base_id="...")

kb.add_documents([
    "https://example.com/handbook.pdf",
    "https://example.com/runbook.md",
])
results = kb.search(search_query="how do we handle refunds?", top_k=5)
Inside an agent, a KB is attached through agent.knowledge_bases and queried automatically by the framework. Call kb.search directly only when you’re building something outside the agent loop, like a search box or a one-off enrichment job.

Memory

There are three memory layers, and they’re not the same thing. The Agno framework configures all of them through agent.agno_settings:
  • Session storage (session_storage=True, default): keeps conversation history within a single thread. Postgres-backed, scoped per agent.
  • User memories (user_memories=True or agentic_memory=True): facts the agent should remember about a specific user, across all their sessions. The two flags select between manual and agentic-managed mode.
  • Agent memories (agent_memories=True or agentic_culture=True): organization-wide knowledge the agent should carry into every conversation. Same two-flag pattern.
Each layer is a separate switch because they each have a cost and a use case:
  1. Session storage is essentially free.
  2. User and agent memories cost LLM calls to maintain.
Pick what you need, leave the rest off. The deep dive is in Memory & State.

Decorators

The SDK exports a small set of decorators that handle the lifecycle for you:
from xpander_sdk import on_task, on_boot, on_shutdown, register_tool
from xpander_sdk import on_tool_before, on_tool_after, on_tool_error
from xpander_sdk import on_auth_event
What each one does:
  • @on_task: the entry point. Stands up the HTTP server and subscribes to the platform task stream.
  • @on_boot / @on_shutdown: lifecycle hooks that run before and after the handler is registered.
  • @register_tool: turns a Python function into an agent tool. SDK generates the JSON schema from your type hints.
  • @on_tool_before / @on_tool_after / @on_tool_error: observe tool calls without modifying the tools themselves. Use for logging, metrics, alerting.
  • @on_auth_event: fires when an MCP OAuth flow needs the user to log in.
You’ll typically need @on_task plus @register_tool. The rest are situational and covered in their own pages.

Configuration

Configuration is the explicit form of the credentials and base URL. Most code never instantiates it: the SDK reads from XPANDER_API_KEY, XPANDER_ORGANIZATION_ID, and XPANDER_BASE_URL automatically.
from xpander_sdk import Configuration

config = Configuration(
    api_key="...",
    organization_id="...",
    base_url="https://agent-controller.acme.com",  # for self-hosted
)
backend = Backend(configuration=config)
Self-hosted deployments are the main reason to construct one explicitly. You need a custom base_url, and the agent controller’s API key, not your cloud key. See SDK configuration for the full setup.

Cheat sheet

A one-line answer for the questions you’ll have most often:
QuestionAnswer
Where do I configure the agent’s behavior?Agent Studio. The SDK reads it.
Where do my custom tools live?In your xpander_handler.py, decorated with @register_tool.
How do I run an agent in code?Inside @on_task: Agent(**(await Backend(...).aget_args(task=task))). Framework-specific for others.
How do I receive incoming tasks?A function decorated with @on_task.
How do I find session data?agent.get_user_sessions(user_id) or agent.get_session(session_id).
How do I add a document to a KB?KnowledgeBases().get(kb_id).add_documents([url]).
Async or sync?Every method has both. Async in production, sync in scripts.

Next steps

Frameworks: Agno

What Backend.aget_args() actually wires up, with the AgnoSettings reference.

Custom Tools

The full @register_tool decorator surface.

Memory & State

Session storage, user memories, and agent memories explained.

SDK Reference

Per-method reference for every class on this page.