@anycast/agent
v0.1.20
Published
TypeScript SDK for Anycast Agents P2P connectivity
Maintainers
Readme
@anycast/agent
TypeScript SDK for Anycast Agents P2P connectivity.
Connect agents to the Anycast network for peer-to-peer communication with relay fallback, powered by the global Anycast edge infrastructure.
Installation
npm install @anycast/agent
# or
pnpm add @anycast/agentQuick Start
import { AnycastAgent } from '@anycast/agent';
const agent = new AnycastAgent({
rendezvousUrl: 'wss://agents.anycast.com/rendezvous',
token: 'agt_your_token_here',
});
agent.on('connect', ({ agentId }) => {
console.log(`Connected as ${agentId}`);
});
agent.on('peer', (peerId, status) => {
console.log(`Peer ${peerId} is ${status}`);
});
agent.on('error', (err) => {
console.error(`Error: ${err.message} (${err.code})`);
});
await agent.connect();
// Request a connection to another agent
const sessionId = agent.requestConnection('target-agent-id');
// Handle incoming WebRTC signals
agent.on('signal', (sessionId, fromAgentId, signal) => {
// Forward to your WebRTC implementation
});
// Send WebRTC signals
agent.sendSignal(sessionId, 'target-agent-id', {
type: 'offer',
data: JSON.stringify(sdpOffer),
});
// Disconnect when done
await agent.disconnect();API Reference
new AnycastAgent(options)
Create a new agent instance.
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| rendezvousUrl | string | required | WebSocket URL of the rendezvous server |
| token | string | required | Agent auth token from the Anycast portal |
| machineId | string | auto-generated | Unique machine identifier |
| publicKey | string | auto-generated | Public key for E2E encryption |
| version | string | — | Agent version string |
| reconnect | boolean | true | Auto-reconnect on disconnect |
| reconnectInterval | number | 3000 | Base reconnect interval (ms) |
| timeout | number | 30000 | Connection timeout (ms) |
| heartbeatInterval | number | 25000 | Heartbeat interval (ms) |
| discoveryMode | string | 'rendezvous' | Discovery mode: rendezvous, auto, or dht |
Properties
| Property | Type | Description |
|----------|------|-------------|
| agentId | string \| null | Assigned agent ID (set after connect) |
| tenantId | string \| null | Tenant ID (set after connect) |
| connected | boolean | Whether the agent is connected |
| connectionState | ConnectionState | Current connection state |
Methods
connect(): Promise<void>
Connect to the rendezvous server. Resolves when registered.
disconnect(): Promise<void>
Disconnect from the server.
requestConnection(targetAgentId: string): string
Request a P2P connection to another agent. Returns a session ID.
sendSignal(sessionId, targetAgentId, signal)
Send a WebRTC signal (offer/answer/ICE candidate) via the rendezvous server.
disconnectSession(sessionId: string)
Close a specific session.
Events
| Event | Payload | Description |
|-------|---------|-------------|
| connect | { agentId, tenantId, name } | Connected and registered |
| disconnect | reason: string | Disconnected |
| reconnecting | attempt: number | Attempting reconnection |
| peer | agentId, status | Peer came online/offline |
| connect_incoming | sessionId, fromAgentId, fromAgentName | Incoming connection request |
| connect_accepted | sessionId, agentId, publicKey | Connection accepted by peer |
| connect_rejected | sessionId, reason | Connection rejected |
| signal | sessionId, fromAgentId, signal | WebRTC signal from peer |
| relay_assigned | sessionId, host, port, token | Relay server assigned |
| error | AnycastError | Error occurred |
| stateChange | ConnectionState | Connection state changed |
| discovery | { mode, fallback } | Discovery mode resolved (emitted before connect) |
ConnectionState
enum ConnectionState {
DISCONNECTED = 'DISCONNECTED',
CONNECTING = 'CONNECTING',
CONNECTED = 'CONNECTED',
RECONNECTING = 'RECONNECTING',
}AnycastError
class AnycastError extends Error {
code: string; // Error code (e.g., 'AUTH_FAILED', 'TIMEOUT')
fatal: boolean; // If true, reconnection won't help
}Usage Tracking & Auto-Instrumentation
Track LLM token usage through the Anycast portal for cost visibility and analytics.
Manual tracking
await agent.trackUsage({
model: 'claude-sonnet-4-6',
promptTokens: 1200,
completionTokens: 340,
triggeredBy: 'user-123',
context: 'slack_thread',
});Anthropic SDK (automatic)
import Anthropic from '@anthropic-ai/sdk';
const anthropic = agent.wrapAnthropic(new Anthropic(), {
triggeredBy: 'user-123',
context: 'slack_thread',
});
// All calls now auto-report usage — no code changes needed
const msg = await anthropic.messages.create({
model: 'claude-sonnet-4-6',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Hello' }],
});OpenAI SDK (automatic)
import OpenAI from 'openai';
const openai = agent.wrapOpenAI(new OpenAI(), { context: 'api' });
const chat = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: 'Hello' }],
});Generic wrapper
const result = await agent.tracked(
() => myLlmCall(prompt),
{
model: 'custom-model',
extractUsage: (r) => ({
promptTokens: r.usage.input,
completionTokens: r.usage.output,
}),
}
);All tracking is opt-in, non-blocking, and never affects the return value or throws.
Discovery Modes
The SDK supports three discovery modes, controlled via the discoveryMode option:
| Mode | Description |
|------|-------------|
| rendezvous | (default) Connects through the managed Anycast rendezvous server. Most reliable, works everywhere, no extra dependencies. |
| auto | Tries DHT (Holepunch) first for direct peer-to-peer discovery. Falls back to rendezvous if hyperswarm is not installed or DHT fails. |
| dht | DHT only via Holepunch. Requires hyperswarm (npm install hyperswarm). Throws if the dependency is missing. Experimental. |
const agent = new AnycastAgent({
rendezvousUrl: 'wss://agents.anycast.com/rendezvous',
token: 'agt_xxx',
discoveryMode: 'auto', // try DHT, fall back to rendezvous
});
agent.on('discovery', ({ mode, fallback }) => {
console.log(`Using ${mode} discovery${fallback ? ' (fallback)' : ''}`);
});
await agent.connect();For the Go binary (any), use --discovery-mode:
any up --token agt_xxx --expose localhost:8080 --discovery-mode auto
# or via environment variable:
ANY_DISCOVERY_MODE=dht any up --token agt_xxx --expose localhost:8080Auto-Reconnection
By default, the agent automatically reconnects with exponential backoff (3s, 6s, 12s, ..., max 30s). Disable with reconnect: false.
Receiving Messages from the Platform
Flows and integrations can send messages directly to your agent and await a reply. Handle incoming messages with the message event:
agent.on('message', async ({ text, context, reply }) => {
// Process the message — you have 30 seconds to reply
const response = await handleQuery(text);
reply(response);
});The reply() function must be called within the timeout window (default 30 seconds). After that, the platform marks the delivery as timed out and the response is discarded.
You can also reply manually using the messageId:
agent.on('message', ({ messageId, text }) => {
processAsync(text).then((result) => {
agent.replyToMessage(messageId, result);
});
});The context field contains metadata from the triggering flow (e.g. Slack channel, thread timestamp, flow ID).
License
MIT
