SDKCustom agents

Agents in your own apps

A support chat on your site, an intake form that talks, an assistant inside your product. A sealed agent can only use the tools your app gives it, so it can face the public.

How it fits together

  1. Visitoron your site
  2. Your websitechat widget
  3. Your gatewayholds the token, answers tools
  4. Sealed agenton your Swarm machine
  5. Modelyour provider
Your server sits between the visitor and the agent, and answers every tool call itself.
  • Tool calls are checked against the tool's schema before your server sees them, and what your server answers goes back to the model marked as untrusted.
  • Identity never comes from the model. Your gateway decides whose order a call may see; the model only supplies inputs like an order code.
  • The token is narrow. It can start and use that agent's conversations and answer its tool calls. It can't list conversations, reach another agent, approve anything or change tools. If someone later gives the agent a built-in tool, the token stops working.

1 · Define the agent and its tools

A tool is a name, a description, a JSON Schema for its input and an effect. The agent names the tools it may call. Loaded on the machine with swarmctl setup sealed-agent --stdin, or from code with agents.defineClientTool and agents.defineSealedAgent.

support_desk.json
{
  "tools": [{
    "name": "get_order",
    "description": "Look up the visitor's order by its code.",
    "input_schema": {
      "type": "object",
      "properties": { "order_id": { "type": "string", "pattern": "^[A-Z0-9]{6}$" } },
      "required": ["order_id"],
      "additionalProperties": false
    },
    "effect": "read",
    "timeout_ms": 5000
  }],
  "agent": {
    "name": "support_desk",
    "prompt": "You answer visitors' questions about their orders.",
    "tools": ["get_order"]
  }
}

2 · Serve it from your app

gateway.ts
import { SwarmClient } from '@swarm-agent/sdk';

// The gateway token reaches this one agent and nothing else.
const swarm = new SwarmClient({ baseUrl: process.env.SWARM_API_URL, token: process.env.SWARM_GATEWAY_TOKEN });

// One conversation per visitor.
const chat = await swarm.sessions.create({ agent_name: 'support_desk', workspace_path: '/project', title: 'Visitor chat' });

// Per message: send it, answer the agent's tool calls, get the reply.
const { reply } = await swarm.agents.converse(chat.id, visitorMessage, {
  // Who the visitor is comes from your session, never from the model.
  get_order: ({ order_id }) => orders.findForVisitor(order_id, visitor),
});

agents.converse is the whole loop a gateway needs per message. Lower level: agents.serve answers tool calls until stopped, or pendingCalls, answer and fail one at a time.

3 · A person can take over

When a conversation needs a human, someone on your team takes it: the agent stops replying, they answer as themselves, and hand it back.

staff.ts
// With an operator token for this agent:
await swarm.agents.takeOver(chat.id);           // the agent stops replying
await swarm.agents.replyAsOperator(chat.id, 'Hi, this is Sam. I have refunded it.');
await swarm.agents.handBack(chat.id);           // the agent answers the next message

Limits, whatever the model does

LimitDefault
Model calls per message4
Output tokens per call1,024
History sent to the model40 messages
Time per reply60 seconds
Messages per gateway token120 a minute
New conversations per gateway token300 an hour
Spend per dayoff until you set it

Limits per visitor (per person, per IP address, bursts) belong in your gateway.

Deploy it safely

Its own sealed runtime

The sealed image has no shell. Run it read-only with every capability dropped.

Only the gateway is public

The agent's port stays on loopback or a private network.

Outbound to the model only

Block every other destination at the network.

Keys in a secret store

Never in browser code or chat. Tokens expire; mint a new one before they do.

Say this to your AI

Put a support chat on my shop that can look up orders and start returns. Nothing else.

  • sealed-agent
  • sdk-token --agent
  • gateway.ts

It's running on staging. Try “where's my order?” with order K7Q2PL. Returns need a person to approve; I set that as a takeover.

Full details for your AI: ai/custom-agents.md.