SDK integration
Build complete JavaScript and Python agent runtimes with real credentials.
The SDK is the recommended way to build a custom local agent. It handles the repetitive runtime work:
- connecting your process to Pacerelle
- using the agent id and token from the app
- incoming message parsing
- replies
- widgets
- file and media uploads
Required environment
PACERELLE_AGENT_ID="agent id copied from the New agent dialog"
PACERELLE_AGENT_TOKEN="token copied from the New agent dialog"
Hosted Pacerelle users only need these two values.
JavaScript SDK
Install
npm i @pacerelle/sdk
Create the agent file
import { AgentGatewayClient } from "@pacerelle/sdk";
const client = new AgentGatewayClient({
agentId: process.env.PACERELLE_AGENT_ID!,
token: process.env.PACERELLE_AGENT_TOKEN!,
baseUrl: process.env.PACERELLE_BASE_URL,
wsUrl: process.env.PACERELLE_WS_URL,
e2ee: true,
});
client.onMessage(async (message, agent) => {
await agent.sendMessage({
conversationId: message.conversationId,
to: message.from,
replyToMessageId: message.id,
text: `Received: ${message.text}`,
});
});
await client.connect();
Run the agent
node --env-file=.env agent.mjs
JavaScript handler contract
The handler receives message and agent.
client.onMessage(async (message, agent) => {
console.log(message.id);
console.log(message.conversationId);
console.log(message.from);
console.log(message.text);
console.log(message.attachments);
console.log(message.widgetResponse);
});
When replying, always use the inbound conversationId and from:
await agent.sendMessage({
conversationId: message.conversationId,
to: message.from,
replyToMessageId: message.id,
text: "Done.",
});
Connect your own logic
Replace the echo with your model, script, or workflow:
client.onMessage(async (message, agent) => {
const answer = await runLocalWorkflow(message.text);
await agent.sendMessage({
conversationId: message.conversationId,
to: message.from,
replyToMessageId: message.id,
text: answer,
});
});
Python SDK
Install
pip install --pre pacerelle
Create the agent file
import asyncio
import os
from pacerelle import AgentGatewayClient
client = AgentGatewayClient(
agent_id=os.environ["PACERELLE_AGENT_ID"],
token=os.environ["PACERELLE_AGENT_TOKEN"],
base_url=os.environ.get("PACERELLE_BASE_URL"),
ws_url=os.environ.get("PACERELLE_WS_URL"),
e2ee=True,
)
async def handle(message, agent):
await agent.send_message(
conversation_id=message.conversation_id,
to=message.from_id,
reply_to_message_id=message.id,
text=f"Received: {message.text}",
)
client.on_message(handle)
asyncio.run(client.connect())
Python requirements
- Python 3.12 for the current alpha wheels.
- Windows x64, Linux x64, Linux ARM64, or macOS ARM64.
Long-running agents
For long-running agents, persist SDK state between restarts:
- JavaScript: save the SDK snapshot callback output and pass it back on startup.
- Python: the SDK uses a local store by default under the user's home directory unless a different store root is configured.
This makes reconnects smoother and avoids making the user repeat setup work.
Error handling checklist
- Store agent tokens in environment variables or a secret manager.
- Add
onOpen,onClose, andonErrorcallbacks in JavaScript. - Keep the process alive; the SDK listens continuously over WebSocket.
- Do not log decrypted user messages in production.
- Reconnect after network drops.
- Rotate the token if authentication fails because the token was replaced.
When to use MCP instead
Use the SDK when you are building your own runtime. Use MCP server when you want an MCP-compatible desktop client to host the local bridge for you.