Long-horizon, multi-step agent loops on OpenRouter. Cost and step ceilings, resumable state, streaming progress, voice input, and human-in-the-loop approvals — all in one SDK.
The Agent SDK keeps long-horizon runs compact. Set ceilings, persist state, and stream progress with the same primitives.
import { OpenRouter, tool, stepCountIs, maxCost } from '@openrouter/agent';
import { z } from 'zod';
const openrouter = new OpenRouter();
const searchTool = tool({
name: 'search',
description: 'Search the web for information',
inputSchema: z.object({ query: z.string() }),
execute: async ({ query }) => {
return { results: await fetchResults(query) };
},
});
// Run for up to 200 steps OR $5 — whichever comes first
const result = openrouter.callModel({
model: '~anthropic/claude-opus-latest',
input: 'Research the fusion energy landscape and write a 5-page report.',
tools: [searchTool],
stopWhen: [stepCountIs(200), maxCost(5)],
});
// Stream tool calls as they happen so dashboards stay live
for await (const call of result.getToolCallsStream()) {
console.log('tool', call.name, call.arguments);
}
const text = await result.getText();Drive the same agent loop from a phone call, push-to-talk app, or live mic. OpenRouter ships dedicated /api/v1/audio/transcriptions and /api/v1/audio/speech endpoints.
import { OpenRouter } from '@openrouter/sdk';
import { OpenRouter as Agent, stepCountIs, maxCost } from '@openrouter/agent';
import { readFile, writeFile } from 'node:fs/promises';
const sdk = new OpenRouter();
const agent = new Agent();
// 1. Voice in -> text
const audio = await readFile('./request.wav');
const { text: prompt } = await sdk.stt.createTranscription({
model: 'openai/whisper-1',
inputAudio: { data: audio.toString('base64'), format: 'wav' },
});
// 2. Long-horizon agent loop with ceilings + tool calls
const result = agent.callModel({
model: '~anthropic/claude-opus-latest',
input: prompt,
stopWhen: [stepCountIs(50), maxCost(2)],
});
const reply = await result.getText();
// 3. Text -> voice out
const stream = await sdk.tts.createSpeech({
model: 'openai/gpt-4o-mini-tts-2025-12-15',
input: reply,
voice: 'alloy',
responseFormat: 'mp3',
});
const chunks: Uint8Array[] = [];
const reader = stream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
}
await writeFile('./reply.mp3', Buffer.concat(chunks));Take input as text or voice. Whisper-grade STT is one API call away when you need it.
Hand the request to callModel with tools and stop conditions. The SDK handles the loop, retries, and streaming.
Persist state with a StateAccessor. Pause for human review or restart after a deploy and continue exactly where you left off.
Get an API key, copy the cookbook, and have a multi-hour, voice-aware agent in production this week.