Build agents that run for hours, not seconds
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.
Features
Multi-Hour Loops
Cost & Step Ceilings
Resumable State
Streaming Progress
Retry with Backoff
Voice Input
Human-in-the-Loop
Self-Ask & Review
One Loop, Hours of Work
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 '@openrouter-monorepo/lib-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();Voice In, Voice Out
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.
Transcribe
Run the Agent
Speak Back
Voice-Driven Agent in Three Calls
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));How it works
Capture
Take input as text or voice. Whisper-grade STT is one API call away when you need it.
Run
Hand the request to callModel with tools and stop conditions. The SDK handles the loop, retries, and streaming.
Resume
Persist state with a StateAccessor. Pause for human review or restart after a deploy and continue exactly where you left off.
Ship a long-running agent today
Get an API key, copy the cookbook, and have a multi-hour, voice-aware agent in production this week.