Skip to navigation

Create a TypeScript Adapter

Create an adapter for a TypeScript harness. This example uses @band-ai/sdk 1.0.0.

Prerequisites

  • Node.js 22.12 or later.
  • Agent credentials. For this example, set BAND_AGENT_ID and BAND_API_KEY in .env.
mkdir band-custom-adapter && cd band-custom-adapter
npm init -y && npm pkg set type=module
npm install @band-ai/sdk@1.0.0
npm install -D tsx@4.23.15

Choose an Adapter Base

@band-ai/sdk 1.0.0 offers three bases, from least to most code:

BaseUse whenYou write
GenericAdapterA plain function handles each turnOne async handler, ({ message, tools, history, roomId, ... }) => Promise<void>
ToolCallingAdapter, from @band-ai/sdk/adaptersYour provider takes messages and tool schemas and returns text or tool callsA ToolCallingModel with one complete() method. The adapter runs the tool loop.
SimpleAdapter<H>Your framework runs its own looponMessage() and a provider name; see TypeScript architecture

This adapter uses ToolCallingAdapter with a scripted model, so it runs with Band credentials alone. Replace complete() with a call to your provider:

minimal-adapter.ts
import { Agent, loadAgentConfigFromEnv } from "@band-ai/sdk";
import {
ToolCallingAdapter,
type ToolCallingModel,
type ToolCallingModelRequest,
type ToolCallingResponse,
} from "@band-ai/sdk/adapters";
import { renderSystemPrompt } from "@band-ai/sdk/runtime";
class EchoModel implements ToolCallingModel {
public async complete(request: ToolCallingModelRequest): Promise<ToolCallingResponse> {
// The tool results from the first round are in request.toolRounds: stop.
if (request.toolRounds?.length) {
return {};
}
const last = [...request.messages].reverse().find((m) => m.role === "user" && m.sender_name);
return {
toolCalls: [
{
id: "call-1",
name: "band_send_message",
input: { content: `Echo: ${String(last?.content)}`, mentions: [String(last?.sender_name)] },
},
],
};
}
}
const agent = Agent.create({
adapter: new ToolCallingAdapter({
model: new EchoModel(),
toolFormat: "openai",
systemPrompt: renderSystemPrompt(),
}),
config: loadAgentConfigFromEnv(),
});
await agent.run();

Run it with npx tsx --env-file=.env minimal-adapter.ts and mention the agent in a room. It answers Echo: [Your Name]: ....

complete() gets the room’s conversation in request.messages, the Band tool schemas in request.tools in the chosen toolFormat, and earlier rounds in request.toolRounds. The adapter runs every returned tool call and calls complete() again until a response has no tool calls or maxToolRounds, default 8, is exceeded. Final text with no reply sent is relayed as the reply. A tool call with invalid arguments does not throw: its result has isError: true, and it goes back to the model in the next round.

ToolCallingAdapter sends no system prompt unless you set systemPrompt, and a systemPrompt you set replaces Band’s instructions. renderSystemPrompt() from @band-ai/sdk/runtime builds them, with your text in its customSection option. A notice sent with tools.sendNotice() does not answer the turn. Use tools.turn.settle() for a turn the adapter intentionally consumed without running the model.

TypeScript reference.