# Migrating to @openrouter/agent Source: https://openrouter.ai/docs/agent-sdk/agent-migration Move agent toolkit imports from @openrouter/sdk to the standalone @openrouter/agent package Using an AI coding assistant? Install the migration skill to let your agent handle the import updates for you: `gh skill install OpenRouterTeam/skills openrouter-agent-migration` The agent toolkit (`callModel`, `tool`, stop conditions, etc.) has moved from `@openrouter/sdk` to a standalone **`@openrouter/agent`** package. The agent package includes its own `OpenRouter` client class, so you no longer need `@openrouter/sdk` as a dependency for agent workflows. ## Who needs to migrate? You need to migrate if your code imports any of the following from `@openrouter/sdk`: * `callModel` / `ModelResult` * `tool` / `Tool` / tool type guards * Stop conditions (`stepCountIs`, `hasToolCall`, etc.) * Async parameters (`CallModelInput`, `resolveAsyncFunctions`) * Conversation state helpers * Message format converters (`fromClaudeMessages`, `fromChatMessages`, etc.) If you only use the REST API client for non-agent features (`client.chat.send(...)`, `client.models.list()`, etc.), **no changes are needed**. ## Step 1: Install the new package ```bash title="npm" lines theme={null} npm install @openrouter/agent ``` ```bash title="pnpm" lines theme={null} pnpm add @openrouter/agent ``` ```bash title="yarn" lines theme={null} yarn add @openrouter/agent ``` ```bash title="bun" lines theme={null} bun add @openrouter/agent ``` ```bash title="deno" lines theme={null} deno add npm:@openrouter/agent ``` ## Step 2: Update imports Replace `@openrouter/sdk` subpath imports with the equivalent `@openrouter/agent` subpath. ### Client class `@openrouter/agent` ships its own `OpenRouter` client, so you can drop the `@openrouter/sdk` dependency entirely if you only use agent features: ```diff lines theme={null} - import OpenRouter from '@openrouter/sdk'; - import { callModel } from '@openrouter/sdk/funcs/call-model'; + import { OpenRouter } from '@openrouter/agent'; const client = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); + + const result = client.callModel({ + model: 'openai/gpt-4o', + input: 'Hello', + }); + const text = await result.getText(); ``` You can also import the client from a direct subpath: ```typescript lines theme={null} import { OpenRouter } from '@openrouter/agent/client'; ``` ### Core imports ```diff lines theme={null} - import { callModel } from '@openrouter/sdk/funcs/call-model'; + import { callModel } from '@openrouter/agent/call-model'; - import { ModelResult } from '@openrouter/sdk/lib/model-result'; + import { ModelResult } from '@openrouter/agent/model-result'; - import { tool } from '@openrouter/sdk/lib/tool'; + import { tool } from '@openrouter/agent/tool'; ``` ### Tool types and guards ```diff lines theme={null} - import type { Tool } from '@openrouter/sdk/lib/tool-types'; + import type { Tool } from '@openrouter/agent/tool-types'; - import { - hasExecuteFunction, - isGeneratorTool, - } from '@openrouter/sdk/lib/tool-types'; + import { + hasExecuteFunction, + isGeneratorTool, + } from '@openrouter/agent/tool-types'; ``` ### Stop conditions ```diff lines theme={null} - import { - stepCountIs, - hasToolCall, - maxCost, - } from '@openrouter/sdk/lib/stop-conditions'; + import { + stepCountIs, + hasToolCall, + maxCost, + } from '@openrouter/agent/stop-conditions'; ``` ### Async parameters ```diff lines theme={null} - import type { - CallModelInput, - } from '@openrouter/sdk/lib/async-params'; + import type { + CallModelInput, + } from '@openrouter/agent/async-params'; ``` ### Conversation state and message formats Conversation helpers and message format converters are available from the package barrel: ```diff lines theme={null} - import { - createInitialState, - updateState, - fromClaudeMessages, - fromChatMessages, - } from '@openrouter/sdk'; + import { + createInitialState, + updateState, + fromClaudeMessages, + fromChatMessages, + } from '@openrouter/agent'; ``` ## Step 3: Verify your build Run your type checker and tests to confirm everything resolves correctly: ```bash lines theme={null} npx tsc --noEmit npm test ``` ## Full import mapping reference | Old import path | New import path | | ------------------------------------------- | ------------------------------------------------- | | `@openrouter/sdk` (client class) | `@openrouter/agent` or `@openrouter/agent/client` | | `@openrouter/sdk/funcs/call-model` | `@openrouter/agent/call-model` | | `@openrouter/sdk/lib/model-result` | `@openrouter/agent/model-result` | | `@openrouter/sdk/lib/tool` | `@openrouter/agent/tool` | | `@openrouter/sdk/lib/tool-types` | `@openrouter/agent/tool-types` | | `@openrouter/sdk/lib/stop-conditions` | `@openrouter/agent/stop-conditions` | | `@openrouter/sdk/lib/async-params` | `@openrouter/agent/async-params` | | `@openrouter/sdk` (barrel: state, messages) | `@openrouter/agent` | ## Automated migration The script below handles **subpath imports** automatically. Barrel imports (`from '@openrouter/sdk'`) and client class imports (`import OpenRouter from '@openrouter/sdk'`) must be updated **manually** — a blanket replacement on the bare package name would also match subpath imports and break your code. See the [Client class](#client-class) and [Conversation state](#conversation-state-and-message-formats) sections above for the correct replacements. ```bash lines theme={null} # Using sed (macOS) find src -name '*.ts' -o -name '*.tsx' | xargs sed -i '' \ -e "s|@openrouter/sdk/funcs/call-model|@openrouter/agent/call-model|g" \ -e "s|@openrouter/sdk/lib/model-result|@openrouter/agent/model-result|g" \ -e "s|@openrouter/sdk/lib/tool-types|@openrouter/agent/tool-types|g" \ -e "s|@openrouter/sdk/lib/tool|@openrouter/agent/tool|g" \ -e "s|@openrouter/sdk/lib/stop-conditions|@openrouter/agent/stop-conditions|g" \ -e "s|@openrouter/sdk/lib/async-params|@openrouter/agent/async-params|g" ``` ```bash lines theme={null} # Using sed (Linux) find src -name '*.ts' -o -name '*.tsx' | xargs sed -i \ -e "s|@openrouter/sdk/funcs/call-model|@openrouter/agent/call-model|g" \ -e "s|@openrouter/sdk/lib/model-result|@openrouter/agent/model-result|g" \ -e "s|@openrouter/sdk/lib/tool-types|@openrouter/agent/tool-types|g" \ -e "s|@openrouter/sdk/lib/tool|@openrouter/agent/tool|g" \ -e "s|@openrouter/sdk/lib/stop-conditions|@openrouter/agent/stop-conditions|g" \ -e "s|@openrouter/sdk/lib/async-params|@openrouter/agent/async-params|g" ``` The `tool-types` replacement runs before `tool` to avoid partial matches. After running the script, search your codebase for any remaining `from '@openrouter/sdk'` (without a `/` subpath) to find barrel and client imports that need manual updates. ## FAQ ### Do I still need `@openrouter/sdk`? Only if you use non-agent REST API features like `client.models.list()`, `client.credits.get()`, or `client.chat.send()`. If your code only uses `callModel`, tools, and the agent client, you can remove `@openrouter/sdk` entirely. ### Can I use both packages together? Yes. They are designed to work side by side. Use `@openrouter/sdk` for REST API features and `@openrouter/agent` for the agent toolkit: ```typescript lines theme={null} import { OpenRouter } from '@openrouter/sdk'; import { callModel } from '@openrouter/agent/call-model'; import { tool } from '@openrouter/agent/tool'; ``` ### Will the old imports keep working? The agent exports will be removed from `@openrouter/sdk` in a future major version. Update your imports now to avoid a breaking change later. ### Do I need to change my API key or configuration? No. `@openrouter/agent` uses the same API key and endpoints. No server-side changes are required. # API Reference Source: https://openrouter.ai/docs/agent-sdk/call-model/api-reference Complete reference for the callModel API, ModelResult class, tool types, and helper functions. ## callModel ```typescript lines theme={null} function callModel(request: CallModelInput, options?: RequestOptions): ModelResult ``` Creates a response using the OpenResponses API with multiple consumption patterns. ### CallModelInput | Parameter | Type | Required | Description | | -------------------- | ------------------------------------------ | -------- | ------------------------------------ | | `model` | `string \| ((ctx: TurnContext) => string)` | Yes\* | Model ID (e.g., "openai/gpt-5-nano") | | `models` | `string[]` | Yes\* | Model fallback array | | `input` | `OpenResponsesInput` | Yes | Input messages or string | | `instructions` | `string \| ((ctx: TurnContext) => string)` | No | System instructions | | `tools` | `Tool[]` | No | Tools available to the model | | `maxToolRounds` | `MaxToolRounds` | No | Tool execution limit (deprecated) | | `stopWhen` | `StopWhen` | No | Stop conditions | | `temperature` | `number \| ((ctx: TurnContext) => number)` | No | Sampling temperature (0-2) | | `maxOutputTokens` | `number \| ((ctx: TurnContext) => number)` | No | Maximum tokens to generate | | `topP` | `number` | No | Top-p sampling | | `text` | `ResponseTextConfig` | No | Text format configuration | | `provider` | `ProviderPreferences` | No | Provider routing and configuration | | `topK` | `number` | No | Top-k sampling | | `metadata` | `Record` | No | Request metadata | | `toolChoice` | `ToolChoice` | No | Tool choice configuration | | `parallelToolCalls` | `boolean` | No | Enable parallel tool calling | | `reasoning` | `ReasoningConfig` | No | Reasoning configuration | | `promptCacheKey` | `string` | No | Cache key for prompt caching | | `previousResponseId` | `string` | No | Context from previous response | | `include` | `string[]` | No | Include extra fields in response | | `background` | `boolean` | No | Run request in background | | `safetyIdentifier` | `string` | No | User safety identifier | | `serviceTier` | `string` | No | Service tier preference | | `truncation` | `string` | No | Truncation mode | | `plugins` | `Plugin[]` | No | Enabled plugins | | `user` | `string` | No | End-user identifier | | `sessionId` | `string` | No | Session identifier | | `store` | `boolean` | No | Store request data | | `context` | `ContextInput` | No | Tool context keyed by tool name | \*Either `model` or `models` is required. ### ProviderPreferences Configuration for routing and provider selection. | Parameter | Type | Description | | ------------------------ | ------------------- | ------------------------------------------------------------------ | | `allowFallbacks` | `boolean` | Allow backup providers when primary is unavailable (default: true) | | `requireParameters` | `boolean` | Only use providers that support all requested parameters | | `dataCollection` | `"allow" \| "deny"` | Data collection policy (allow/deny) | | `order` | `string[]` | Custom provider routing order | | `only` | `string[]` | Restrict to specific providers | | `ignore` | `string[]` | Exclude specific providers | | `quantizations` | `string[]` | Filter by quantization levels | | `sort` | `string` | Load balancing strategy (e.g., "throughput") | | `maxPrice` | `object` | Maximum price limits | | `preferredMinThroughput` | `number` | Minimum tokens per second preference | | `preferredMaxLatency` | `number` | Maximum latency preference | ### RequestOptions | Parameter | Type | Description | | --------- | ------------- | ------------------------------- | | `timeout` | `number` | Request timeout in milliseconds | | `signal` | `AbortSignal` | Abort signal for cancellation | *** ## ModelResult Wrapper providing multiple consumption patterns for a response. ### Methods #### getText() ```typescript lines theme={null} getText(): Promise ``` Get text content after tool execution completes. #### getResponse() ```typescript lines theme={null} getResponse(): Promise ``` Get full response with usage data (inputTokens, outputTokens, cachedTokens). #### getTextStream() ```typescript lines theme={null} getTextStream(): AsyncIterableIterator ``` Stream text deltas. #### getReasoningStream() ```typescript lines theme={null} getReasoningStream(): AsyncIterableIterator ``` Stream reasoning deltas (for reasoning models). #### getNewMessagesStream() ```typescript lines theme={null} getNewMessagesStream(): AsyncIterableIterator ``` Stream cumulative message snapshots in OpenResponses format. #### getFullResponsesStream() ```typescript lines theme={null} getFullResponsesStream(): AsyncIterableIterator ``` Stream all events including tool preliminary results. #### getToolCalls() ```typescript lines theme={null} getToolCalls(): Promise ``` Get all tool calls from initial response. #### getToolCallsStream() ```typescript lines theme={null} getToolCallsStream(): AsyncIterableIterator ``` Stream tool calls as they complete. #### getToolStream() ```typescript lines theme={null} getToolStream(): AsyncIterableIterator ``` Stream tool deltas and preliminary results. #### getContextUpdates() ```typescript lines theme={null} getContextUpdates(): AsyncGenerator> ``` Stream context snapshots whenever a tool calls `setContext()`. Completes when tool execution finishes. #### cancel() ```typescript lines theme={null} cancel(): Promise ``` Cancel the stream and all consumers. *** ## Tool Types ### tool() ```typescript lines theme={null} function tool(config: ToolConfig): Tool ``` Create a typed tool with Zod schema validation. ### ToolConfig | Parameter | Type | Required | Description | | -------------------- | ------------------------- | -------- | ----------------------------------------------------------- | | `name` | `string` | Yes | Tool name | | `description` | `string` | No | Tool description | | `inputSchema` | `ZodObject` | Yes | Input parameter schema | | `outputSchema` | `ZodType` | No | Output schema | | `eventSchema` | `ZodType` | No | Event schema (triggers generator mode) | | `contextSchema` | `ZodObject` | No | Context data this tool needs | | `execute` | `function \| false` | Yes\* | Execute function, or `false` for manual | | `onToolCalled` | `function` | Yes\* | HITL hook — return value to auto-respond, `null` to pause | | `onResponseReceived` | `function` | No | HITL hook — post-process caller-supplied result (HITL only) | | `nextTurnParams` | `NextTurnParamsFunctions` | No | Parameters to modify next turn | \* Provide exactly one of `execute` or `onToolCalled`. Omitting both (with `execute: false`) makes the tool a manual tool. ### Tool Union type of all tool types: ```typescript lines theme={null} type Tool = | ToolWithExecute | ToolWithGenerator | ManualTool | HITLTool; ``` ### ToolWithExecute Regular tool with execute function: ```typescript lines theme={null} interface ToolWithExecute< TInput, TOutput, TContext, TName > { type: ToolType.Function; function: { name: TName; description?: string; inputSchema: TInput; outputSchema?: TOutput; contextSchema?: ZodObject; execute: ( params: z.infer, context: ToolExecuteContext, ) => Promise>; }; } ``` ### ToolWithGenerator Generator tool with eventSchema: ```typescript lines theme={null} interface ToolWithGenerator< TInput, TEvent, TOutput, TContext, TName > { type: ToolType.Function; function: { name: TName; description?: string; inputSchema: TInput; eventSchema: TEvent; outputSchema: TOutput; contextSchema?: ZodObject; execute: ( params: z.infer, context: ToolExecuteContext, ) => AsyncGenerator>; }; } ``` ### ManualTool Tool without execute function: ```typescript lines theme={null} interface ManualTool { type: ToolType.Function; function: { name: string; description?: string; inputSchema: TInput; outputSchema?: TOutput; }; } ``` ### HITLTool Human-in-the-loop tool with `onToolCalled` and optional `onResponseReceived` hooks. `outputSchema` is required — it validates both the hook's non-null return value and the caller-supplied response delivered via `function_call_output`. ```typescript expandable lines theme={null} interface HITLToolFunction< TInput, TOutput, TContext, TName > { name: TName; description?: string; inputSchema: TInput; outputSchema: TOutput; contextSchema?: ZodObject; onToolCalled: ( params: z.infer, context?: ToolExecuteContext, ) => Promise | null> | z.infer | null; onResponseReceived?: ( rawResult: unknown, context?: ToolExecuteContext, ) => Promise> | z.infer; toModelOutput?: ToModelOutputFunction< z.infer, z.infer >; } type HITLTool = { type: ToolType.Function; function: HITLToolFunction; }; ``` Returning `null` from `onToolCalled` pauses the loop and sets the conversation status to `'awaiting_hitl'`. Throwing from `onToolCalled` is surfaced as a tool error of the form `{ error: ... }`. Throwing from `onResponseReceived` is surfaced as an error payload that includes the caller's original output of the form `{ error: ..., originalOutput: ... }`. *** ## Tool Type Guards ```typescript lines theme={null} function isManualTool(tool: Tool): tool is ManualTool; function isHITLTool(tool: Tool): tool is HITLTool; function isAutoResolvableTool( tool: Tool, ): tool is ToolWithExecute | ToolWithGenerator | HITLTool; ``` * `isManualTool` — no `execute` and no `onToolCalled`. Always pauses the loop. * `isHITLTool` — has an `onToolCalled` function. * `isAutoResolvableTool` — either has an `execute` function (regular/generator) or is a HITL tool. Returns `false` for manual and server tools. *** ## Context Types ### TurnContext ```typescript lines theme={null} interface TurnContext { toolCall?: OpenResponsesFunctionToolCall; numberOfTurns: number; turnRequest?: OpenResponsesRequest; } ``` ### ToolExecuteContext Flat context passed to tool execute functions. Merges `TurnContext` fields with tool-specific context: ```typescript lines theme={null} type ToolExecuteContext = TurnContext & { tools: { readonly [K in TName]: Readonly; }; setContext(partial: Partial): void; }; ``` ### ToolContextMap Context map for `callModel`'s `context` option, keyed by tool name: ```typescript lines theme={null} type ToolContextMap = { [K in T[number] as K['function']['name']]: InferToolContext; }; ``` ### ContextInput Context can be static, a sync function, or an async function: ```typescript lines theme={null} type ContextInput = | T | ((turn: TurnContext) => T) | ((turn: TurnContext) => Promise); ``` ### NextTurnParamsContext ```typescript lines theme={null} interface NextTurnParamsContext { input: OpenResponsesInput; model: string; models: string[]; temperature: number | null; maxOutputTokens: number | null; topP: number | null; topK?: number | undefined; instructions: string | null; } ``` *** ## Stream Event Types ### EnhancedResponseStreamEvent ```typescript lines theme={null} type EnhancedResponseStreamEvent = | OpenResponsesStreamEvent | ToolPreliminaryResultEvent; ``` ### ToolStreamEvent ```typescript lines theme={null} type ToolStreamEvent = | { type: 'delta'; content: string } | { type: 'preliminary_result'; toolCallId: string; result: unknown }; ``` ### ParsedToolCall ```typescript lines theme={null} interface ParsedToolCall { id: string; name: string; arguments: unknown; } ``` ### ToolExecutionResult ```typescript lines theme={null} interface ToolExecutionResult { toolCallId: string; toolName: string; result: unknown; preliminaryResults?: unknown[]; error?: Error; } ``` *** ## Stop Conditions ### StopWhen ```typescript lines theme={null} type StopWhen = | StopCondition | StopCondition[]; ``` ### StopCondition ```typescript lines theme={null} type StopCondition = (context: StopConditionContext) => boolean | Promise; ``` ### StopConditionContext ```typescript lines theme={null} interface StopConditionContext { steps: StepResult[]; } ``` ### StepResult ```typescript lines theme={null} interface StepResult { stepType: 'initial' | 'continue'; text: string; toolCalls: TypedToolCallUnion[]; toolResults: ToolExecutionResultUnion[]; response: OpenResponsesNonStreamingResponse; usage?: OpenResponsesUsage; finishReason?: string; warnings?: Warning[]; experimental_providerMetadata?: Record; } ``` ### Warning ```typescript lines theme={null} interface Warning { type: string; message: string; } ``` ### Built-in Helpers | Function | Signature | Description | | ---------------- | ----------------------------------- | ------------------------ | | `stepCountIs` | `(n: number) => StopCondition` | Stop after n steps | | `hasToolCall` | `(name: string) => StopCondition` | Stop when tool is called | | `maxTokensUsed` | `(n: number) => StopCondition` | Stop after n tokens | | `maxCost` | `(amount: number) => StopCondition` | Stop after cost limit | | `finishReasonIs` | `(reason: string) => StopCondition` | Stop on finish reason | *** ## Format Helpers ### fromChatMessages ```typescript lines theme={null} function fromChatMessages(messages: Message[]): OpenResponsesInput ``` Convert OpenAI chat format to OpenResponses input. ### toChatMessage ```typescript lines theme={null} function toChatMessage(response: OpenResponsesNonStreamingResponse): AssistantMessage ``` Convert response to chat message format. ### fromClaudeMessages ```typescript lines theme={null} function fromClaudeMessages(messages: ClaudeMessageParam[]): OpenResponsesInput ``` Convert Anthropic Claude format to OpenResponses input. ### toClaudeMessage ```typescript lines theme={null} function toClaudeMessage(response: OpenResponsesNonStreamingResponse): ClaudeMessage ``` Convert response to Claude message format. *** ## Type Utilities ### InferToolInput ```typescript lines theme={null} type InferToolInput = T extends { function: { inputSchema: infer S } } ? S extends ZodType ? z.infer : unknown : unknown; ``` ### InferToolOutput ```typescript lines theme={null} type InferToolOutput = T extends { function: { outputSchema: infer S } } ? S extends ZodType ? z.infer : unknown : unknown; ``` ### InferToolEvent ```typescript lines theme={null} type InferToolEvent = T extends { function: { eventSchema: infer S } } ? S extends ZodType ? z.infer : never : never; ``` ### TypedToolCall ```typescript lines theme={null} type TypedToolCall = { id: string; name: T extends { function: { name: infer N } } ? N : string; arguments: InferToolInput; }; ``` *** ## Exports ```typescript expandable lines theme={null} // Agent client export { OpenRouter } from '@openrouter/agent'; // Tool helpers export { tool, ToolType, isManualTool, isHITLTool, isAutoResolvableTool, } from '@openrouter/agent'; // Format helpers export { fromChatMessages, toChatMessage, fromClaudeMessages, toClaudeMessage } from '@openrouter/agent'; // Stop condition helpers export { stepCountIs, hasToolCall, maxTokensUsed, maxCost, finishReasonIs } from '@openrouter/agent'; // Context helpers export { buildToolExecuteContext, ToolContextStore, } from '@openrouter/agent'; // Types export type { CallModelInput, ContextInput, Tool, ToolWithExecute, ToolWithGenerator, ManualTool, HITLTool, HITLToolFunction, ToolExecuteContext, ToolContextMap, TurnContext, ParsedToolCall, ToolExecutionResult, StopCondition, StopWhen, InferToolInput, InferToolOutput, InferToolEvent, } from '@openrouter/agent'; ``` # Dynamic Parameters Source: https://openrouter.ai/docs/agent-sdk/call-model/dynamic-parameters Use async functions for adaptive model behavior across turns ## Basic Usage Any parameter in `callModel` can be a function that computes its value based on conversation context. This enables adaptive behavior - changing models, adjusting temperature, or modifying instructions as the conversation evolves. Pass a function instead of a static value: ```typescript lines theme={null} import { OpenRouter } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const result = openrouter.callModel({ // Dynamic model selection based on turn count model: (ctx) => { return ctx.numberOfTurns > 3 ? 'openai/gpt-5.2' : 'openai/gpt-5-nano'; }, input: 'Hello!', tools: [myTool], }); ``` ## Function Signature Parameter functions receive a `TurnContext` and return the parameter value: ```typescript lines theme={null} type ParameterFunction = (context: TurnContext) => T | Promise; ``` ### TurnContext | Property | Type | Description | | --------------- | -------------------------------------------- | ------------------------------------------------------------- | | `numberOfTurns` | `number` | Current turn number (1-indexed) | | `turnRequest` | `OpenResponsesRequest \| undefined` | Current request object containing messages and model settings | | `toolCall` | `OpenResponsesFunctionToolCall \| undefined` | The specific tool call being executed | ## Async Functions Functions can be async for fetching external data: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', // Fetch user preferences from database temperature: async (ctx) => { const prefs = await fetchUserPreferences(userId); return prefs.preferredTemperature ?? 0.7; }, // Load dynamic instructions instructions: async (ctx) => { const rules = await fetchBusinessRules(); return `Follow these rules:\n${rules.join('\n')}`; }, input: 'Hello!', }); ``` ## Common Patterns ### Progressive Model Upgrade Start with a fast model, upgrade for complex tasks: ```typescript lines theme={null} const result = openrouter.callModel({ model: (ctx) => { // First few turns: fast model if (ctx.numberOfTurns <= 2) { return 'openai/gpt-5-nano'; } // Complex conversations: capable model return 'openai/gpt-5.2'; }, input: 'Let me think through this problem...', tools: [analysisTool], }); ``` ### Adaptive Temperature Adjust creativity based on context: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', temperature: (ctx) => { // Analyze recent messages for task type const lastMessage = JSON.stringify(ctx.turnRequest?.input).toLowerCase(); if (lastMessage.includes('creative') || lastMessage.includes('brainstorm')) { return 1.0; // Creative tasks } if (lastMessage.includes('code') || lastMessage.includes('calculate')) { return 0.2; // Precise tasks } return 0.7; // Default }, input: 'Write a creative story', }); ``` ### Context-Aware Instructions Build instructions based on conversation state: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', instructions: (ctx) => { const base = 'You are a helpful assistant.'; const turnInfo = `This is turn ${ctx.numberOfTurns} of the conversation.`; // Add context based on history length if (ctx.numberOfTurns > 5) { return `${base}\n${turnInfo}\nKeep responses concise - this is a long conversation.`; } return `${base}\n${turnInfo}`; }, input: 'Continue helping me...', tools: [helpTool], }); ``` ### Dynamic Max Tokens Adjust output length based on task: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', maxOutputTokens: (ctx) => { const lastMessage = JSON.stringify(ctx.turnRequest?.input).toLowerCase(); if (lastMessage.includes('summarize') || lastMessage.includes('brief')) { return 200; } if (lastMessage.includes('detailed') || lastMessage.includes('explain')) { return 2000; } return 500; }, input: 'Give me a detailed explanation', }); ``` ### Feature Flags Enable features dynamically: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', // Enable thinking for complex turns provider: async (ctx) => { const enableThinking = ctx.numberOfTurns > 2; return enableThinking ? { anthropic: { thinking: { type: 'enabled', budgetTokens: 1000 }, }, } : undefined; }, input: 'Solve this complex problem', tools: [analysisTool], }); ``` ## Combining with Tools Dynamic parameters work alongside tool execution: ```typescript lines theme={null} const smartAssistant = openrouter.callModel({ // Upgrade model if tools have been used model: (ctx) => { const hasToolUse = JSON.stringify(ctx.turnRequest?.input).includes('function_call'); return hasToolUse ? 'anthropic/claude-sonnet-4.5' : 'openai/gpt-5-nano'; }, // Lower temperature after tool execution temperature: (ctx) => { return ctx.numberOfTurns > 1 ? 0.3 : 0.7; }, input: 'Research and analyze this topic', tools: [searchTool, analysisTool], }); ``` ## Execution Order Dynamic parameters are resolved at the start of each turn: ```lines theme={null} 1. Resolve all parameter functions with current TurnContext 2. Build request with resolved values 3. Send to model 4. Execute tools (if any) 5. Check stop conditions 6. Update TurnContext for next turn 7. Repeat from step 1 ``` ## Error Handling Handle errors in async parameter functions: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', instructions: async (ctx) => { try { const rules = await fetchRules(); return `Follow these rules: ${rules}`; } catch (error) { // Fallback on error console.error('Failed to fetch rules:', error); return 'You are a helpful assistant.'; } }, input: 'Hello!', }); ``` ## Best Practices ### Keep Functions Pure Avoid side effects in parameter functions: ```typescript lines theme={null} // Good: Pure function model: (ctx) => ctx.numberOfTurns > 3 ? 'gpt-4' : 'gpt-4o-mini', // Avoid: Side effects model: (ctx) => { logToDatabase(ctx); // Side effect return 'gpt-4'; }, ``` ### Cache Expensive Operations Cache results for repeated calls: ```typescript lines theme={null} let cachedRules: string | null = null; const result = openrouter.callModel({ instructions: async (ctx) => { if (!cachedRules) { cachedRules = await fetchExpensiveRules(); } return cachedRules; }, input: 'Hello!', }); ``` ### Use Sensible Defaults Always have fallback values: ```typescript lines theme={null} model: (ctx) => { const preferredModel = getPreferredModel(); return preferredModel ?? 'openai/gpt-5-nano'; // Default fallback }, ``` ## See Also * **[nextTurnParams](/docs/agent-sdk/call-model/next-turn-params)** - Tool-driven parameter modification * **[Stop Conditions](/docs/agent-sdk/call-model/stop-conditions)** - Dynamic execution control * **[Tools](/docs/agent-sdk/call-model/tools)** - Multi-turn orchestration # Skills Loader Source: https://openrouter.ai/docs/agent-sdk/call-model/examples/skills-loader A complete implementation of a skills system similar to Claude Code, demonstrating the power of `nextTurnParams` for context injection. ## Overview This example shows how to build encapsulated, self-managing tools that inject domain-specific context into conversations. When a skill is loaded, it automatically enriches subsequent turns with specialized instructions. ## Prerequisites ```bash title="npm" lines theme={null} npm install @openrouter/agent zod ``` ```bash title="pnpm" lines theme={null} pnpm add @openrouter/agent zod ``` ```bash title="yarn" lines theme={null} yarn add @openrouter/agent zod ``` ```bash title="bun" lines theme={null} bun add @openrouter/agent zod ``` ```bash title="deno" lines theme={null} deno add npm:@openrouter/agent npm:zod ``` Create a skills directory: ```bash lines theme={null} mkdir -p ~/.claude/skills/pdf-processing mkdir -p ~/.claude/skills/data-analysis mkdir -p ~/.claude/skills/code-review ``` ## Basic Skills Tool ```typescript expandable lines theme={null} import { OpenRouter, tool } from '@openrouter/agent'; import { readFileSync, existsSync, readdirSync } from 'fs'; import path from 'path'; import { z } from 'zod'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const SKILLS_DIR = path.join(process.env.HOME || '~', '.claude', 'skills'); // List available skills const listAvailableSkills = (): string[] => { if (!existsSync(SKILLS_DIR)) return []; return readdirSync(SKILLS_DIR, { withFileTypes: true }) .filter((dirent) => dirent.isDirectory()) .filter((dirent) => existsSync(path.join(SKILLS_DIR, dirent.name, 'SKILL.md'))) .map((dirent) => dirent.name); }; const skillsTool = tool({ name: 'Skill', description: `Load a specialized skill to enhance the assistant's capabilities. Available skills: ${listAvailableSkills().join(', ') || 'none configured'} Each skill provides domain-specific instructions and capabilities.`, inputSchema: z.object({ type: z.string().describe("The skill type to load (e.g., 'pdf-processing')"), }), outputSchema: z.string(), // This is where the magic happens - modify context for next turn nextTurnParams: { input: (params, context) => { // Prevent duplicate skill loading const skillMarker = `[Skill: ${params.type}]`; if (JSON.stringify(context.input).includes(skillMarker)) { return context.input; } // Load the skill's instructions const skillPath = path.join(SKILLS_DIR, params.type, 'SKILL.md'); if (!existsSync(skillPath)) { return context.input; } const skill = readFileSync(skillPath, 'utf-8'); const skillDir = path.join(SKILLS_DIR, params.type); // Inject skill context into the conversation const currentInput = Array.isArray(context.input) ? context.input : [context.input]; return [ ...currentInput, { role: 'user', content: `${skillMarker} Base directory for this skill: ${skillDir} ${skill}`, }, ]; }, }, execute: async (params, context) => { const skillMarker = `[Skill: ${params.type}]`; // Check if already loaded if (JSON.stringify(context?.turnRequest?.input || []).includes(skillMarker)) { return `Skill ${params.type} is already loaded`; } const skillPath = path.join(SKILLS_DIR, params.type, 'SKILL.md'); if (!existsSync(skillPath)) { const available = listAvailableSkills(); return `Skill "${params.type}" not found. Available skills: ${available.join(', ') || 'none'}`; } return `Launching skill ${params.type}`; }, }); ``` ## Usage ```typescript lines theme={null} const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', input: 'I need to process a PDF and extract tables from it', tools: [skillsTool], }); const text = await result.getText(); // The model will call the Skill tool, loading pdf-processing context // Subsequent responses will have access to the skill's instructions ``` ## Example Skill File Create `~/.claude/skills/pdf-processing/SKILL.md`: ```markdown expandable lines theme={null} # PDF Processing Skill You are now equipped with PDF processing capabilities. ## Available Tools When processing PDFs, you have access to: - `extract_text`: Extract all text from a PDF - `extract_tables`: Extract tables as structured data - `extract_images`: Extract embedded images - `split_pdf`: Split PDF into individual pages ## Best Practices 1. Always check PDF file size before processing 2. For large PDFs (>50 pages), process in chunks 3. OCR may be needed for scanned documents 4. Tables may span multiple pages - handle accordingly ## Output Formats - Text: Plain text or markdown - Tables: JSON, CSV, or markdown tables - Images: PNG with sequential naming ## Error Handling - If a PDF is encrypted, request the password - If OCR fails, suggest alternative approaches - Report page numbers for any extraction errors ``` ## Extended: Multi-Skill Loader Load multiple skills in a single call: ```typescript expandable lines theme={null} const multiSkillLoader = tool({ name: 'load_skills', description: 'Load multiple skills at once for complex tasks', inputSchema: z.object({ skills: z.array(z.string()).describe('Array of skill names to load'), }), outputSchema: z.object({ loaded: z.array(z.string()), failed: z.array( z.object({ name: z.string(), reason: z.string(), }) ), }), nextTurnParams: { input: (params, context) => { let newInput = Array.isArray(context.input) ? context.input : [context.input]; for (const skillName of params.skills) { const skillMarker = `[Skill: ${skillName}]`; // Skip if already loaded if (JSON.stringify(newInput).includes(skillMarker)) { continue; } const skillPath = path.join(SKILLS_DIR, skillName, 'SKILL.md'); if (!existsSync(skillPath)) { continue; } const skillContent = readFileSync(skillPath, 'utf-8'); const skillDir = path.join(SKILLS_DIR, skillName); newInput = [ ...newInput, { role: 'user', content: `${skillMarker} Base directory: ${skillDir} ${skillContent}`, }, ]; } return newInput; }, }, execute: async ({ skills }) => { const loaded: string[] = []; const failed: Array<{ name: string; reason: string }> = []; for (const skill of skills) { const skillPath = path.join(SKILLS_DIR, skill, 'SKILL.md'); if (existsSync(skillPath)) { loaded.push(skill); } else { failed.push({ name: skill, reason: 'Skill not found' }); } } return { loaded, failed }; }, }); // Usage const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', input: 'I need to analyze a PDF report and create visualizations', tools: [multiSkillLoader], }); // Model might call: load_skills({ skills: ['pdf-processing', 'data-analysis'] }) ``` ## Extended: Skill with Options Skills that accept configuration: ```typescript expandable lines theme={null} const configurableSkillLoader = tool({ name: 'configure_skill', description: 'Load a skill with custom configuration options', inputSchema: z.object({ skillName: z.string(), options: z .object({ verbosity: z.enum(['minimal', 'normal', 'detailed']).default('normal'), strictMode: z.boolean().default(false), outputFormat: z.enum(['json', 'markdown', 'plain']).default('markdown'), }) .optional(), }), outputSchema: z.object({ status: z.enum(['loaded', 'already_loaded', 'not_found']), message: z.string(), configuration: z.record(z.unknown()).optional(), }), nextTurnParams: { input: (params, context) => { const skillMarker = `[Skill: ${params.skillName}]`; if (JSON.stringify(context.input).includes(skillMarker)) { return context.input; } const skillPath = path.join(SKILLS_DIR, params.skillName, 'SKILL.md'); if (!existsSync(skillPath)) { return context.input; } const skillContent = readFileSync(skillPath, 'utf-8'); const options = params.options || {}; // Build configuration header const configHeader = ` ## Skill Configuration - Verbosity: ${options.verbosity || 'normal'} - Strict Mode: ${options.strictMode || false} - Output Format: ${options.outputFormat || 'markdown'} `; const currentInput = Array.isArray(context.input) ? context.input : [context.input]; return [ ...currentInput, { role: 'user', content: `${skillMarker} ${configHeader} ${skillContent}`, }, ]; }, // Adjust model behavior based on skill temperature: (params, context) => { // Lower temperature for strict mode if (params.options?.strictMode) { return 0.3; } return context.temperature; }, }, execute: async ({ skillName, options }) => { const skillPath = path.join(SKILLS_DIR, skillName, 'SKILL.md'); if (!existsSync(skillPath)) { return { status: 'not_found' as const, message: `Skill "${skillName}" not found`, }; } return { status: 'loaded' as const, message: `Skill "${skillName}" loaded with configuration`, configuration: options || {}, }; }, }); ``` ## Skill Discovery Tool List and describe available skills: ```typescript expandable lines theme={null} const skillDiscoveryTool = tool({ name: 'list_skills', description: 'List all available skills with their descriptions', inputSchema: z.object({ category: z.string().optional().describe('Filter by category'), }), outputSchema: z.object({ skills: z.array( z.object({ name: z.string(), description: z.string(), hasConfig: z.boolean(), }) ), totalCount: z.number(), }), execute: async ({ category }) => { const availableSkills = listAvailableSkills(); const skills = []; for (const skillName of availableSkills) { const skillPath = path.join(SKILLS_DIR, skillName, 'SKILL.md'); const content = readFileSync(skillPath, 'utf-8'); // Extract first paragraph as description const lines = content.split('\n').filter((l) => l.trim()); const description = lines.find((l) => !l.startsWith('#')) || 'No description'; // Check for config file const configPath = path.join(SKILLS_DIR, skillName, 'config.json'); const hasConfig = existsSync(configPath); skills.push({ name: skillName, description: description.slice(0, 100), hasConfig, }); } return { skills, totalCount: skills.length, }; }, }); ``` ## Complete Example Putting it all together: ```typescript expandable lines theme={null} import { OpenRouter, tool, stepCountIs } from '@openrouter/agent'; import { readFileSync, existsSync, readdirSync } from 'fs'; import path from 'path'; import { z } from 'zod'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const SKILLS_DIR = path.join(process.env.HOME || '~', '.claude', 'skills'); // ... (include skillsTool, multiSkillLoader, skillDiscoveryTool from above) // Use all skill tools together const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', input: `I have a complex task: 1. First, show me what skills are available 2. Load the appropriate skills for PDF analysis 3. Then help me extract and analyze data from report.pdf`, tools: [skillDiscoveryTool, skillsTool, multiSkillLoader], stopWhen: stepCountIs(10), }); const text = await result.getText(); console.log(text); ``` ## Key Patterns ### 1. Idempotency Always check if a skill is already loaded: ```typescript lines theme={null} nextTurnParams: { input: (params, context) => { const marker = `[Skill: ${params.type}]`; if (JSON.stringify(context.input).includes(marker)) { return context.input; // Don't add again } // ... add skill }, }, ``` ### 2. Graceful Fallbacks Handle missing skills gracefully: ```typescript lines theme={null} execute: async (params) => { if (!existsSync(skillPath)) { return `Skill not found. Available: ${listAvailableSkills().join(', ')}`; } // ... }, ``` ### 3. Context Preservation Always preserve existing input: ```typescript lines theme={null} nextTurnParams: { input: (params, context) => { const currentInput = Array.isArray(context.input) ? context.input : [context.input]; return [...currentInput, newMessage]; // Append, don't replace }, }, ``` ### 4. Clear Markers Use unique markers to identify injected content: ```typescript lines theme={null} const skillMarker = `[Skill: ${params.type}]`; // Makes detection reliable and content clearly labeled ``` ## See Also * **[nextTurnParams Guide](/docs/agent-sdk/call-model/next-turn-params)** - Context injection patterns * **[Dynamic Parameters](/docs/agent-sdk/call-model/dynamic-parameters)** - Adaptive behavior * **[Tools](/docs/agent-sdk/call-model/tools)** - Multi-turn orchestration # Weather Tool Source: https://openrouter.ai/docs/agent-sdk/call-model/examples/weather-tool A complete weather tool demonstrating external API integration, proper validation, and error handling. ## Prerequisites ```bash title="npm" lines theme={null} npm install @openrouter/agent zod ``` ```bash title="pnpm" lines theme={null} pnpm add @openrouter/agent zod ``` ```bash title="yarn" lines theme={null} yarn add @openrouter/agent zod ``` ```bash title="bun" lines theme={null} bun add @openrouter/agent zod ``` ```bash title="deno" lines theme={null} deno add npm:@openrouter/agent npm:zod ``` You'll need a weather API key. This example uses [WeatherAPI](https://www.weatherapi.com/) (free tier available). ```bash lines theme={null} export WEATHER_API_KEY=your_api_key_here export OPENROUTER_API_KEY=your_openrouter_key ``` ## Basic Implementation ```typescript expandable lines theme={null} import { OpenRouter, tool } from '@openrouter/agent'; import { z } from 'zod'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const weatherTool = tool({ name: 'get_weather', description: 'Get current weather conditions for any city worldwide', inputSchema: z.object({ city: z.string().describe('City name, e.g., "San Francisco" or "London, UK"'), units: z .enum(['celsius', 'fahrenheit']) .default('celsius') .describe('Temperature units'), }), outputSchema: z.object({ temperature: z.number(), feelsLike: z.number(), conditions: z.string(), humidity: z.number(), windSpeed: z.number(), windDirection: z.string(), location: z.object({ name: z.string(), region: z.string(), country: z.string(), }), }), execute: async ({ city, units }) => { const apiKey = process.env.WEATHER_API_KEY; if (!apiKey) { throw new Error('WEATHER_API_KEY environment variable not set'); } const response = await fetch( `https://api.weatherapi.com/v1/current.json?key=${apiKey}&q=${encodeURIComponent(city)}` ); if (!response.ok) { if (response.status === 400) { throw new Error(`City not found: ${city}`); } throw new Error(`Weather API error: ${response.status}`); } const data = await response.json(); return { temperature: units === 'celsius' ? data.current.temp_c : data.current.temp_f, feelsLike: units === 'celsius' ? data.current.feelslike_c : data.current.feelslike_f, conditions: data.current.condition.text, humidity: data.current.humidity, windSpeed: data.current.wind_kph, windDirection: data.current.wind_dir, location: { name: data.location.name, region: data.location.region, country: data.location.country, }, }; }, }); ``` ## Usage ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the weather like in Tokyo?', tools: [weatherTool], }); const text = await result.getText(); console.log(text); // "The current weather in Tokyo, Japan is partly cloudy with a temperature // of 22°C (feels like 24°C). Humidity is at 65% with winds from the SW // at 15 km/h." ``` ## With Multiple Cities ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Compare the weather in New York and Los Angeles', tools: [weatherTool], }); // The model will call the tool twice, once for each city const text = await result.getText(); ``` ## Extended Version with Forecast ```typescript expandable lines theme={null} const forecastTool = tool({ name: 'get_forecast', description: 'Get weather forecast for the next few days', inputSchema: z.object({ city: z.string().describe('City name'), days: z.number().min(1).max(7).default(3).describe('Number of forecast days'), units: z.enum(['celsius', 'fahrenheit']).default('celsius'), }), outputSchema: z.object({ location: z.string(), forecast: z.array( z.object({ date: z.string(), maxTemp: z.number(), minTemp: z.number(), conditions: z.string(), chanceOfRain: z.number(), }) ), }), execute: async ({ city, days, units }) => { const apiKey = process.env.WEATHER_API_KEY; if (!apiKey) { throw new Error('WEATHER_API_KEY environment variable not set'); } const response = await fetch( `https://api.weatherapi.com/v1/forecast.json?key=${apiKey}&q=${encodeURIComponent(city)}&days=${days}` ); if (!response.ok) { throw new Error(`Weather API error: ${response.status}`); } const data = await response.json(); return { location: `${data.location.name}, ${data.location.country}`, forecast: data.forecast.forecastday.map((day: any) => ({ date: day.date, maxTemp: units === 'celsius' ? day.day.maxtemp_c : day.day.maxtemp_f, minTemp: units === 'celsius' ? day.day.mintemp_c : day.day.mintemp_f, conditions: day.day.condition.text, chanceOfRain: day.day.daily_chance_of_rain, })), }; }, }); // Use both tools together const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the weather in Paris today and for the next 3 days?', tools: [weatherTool, forecastTool], }); ``` ## Error Handling The tool includes proper error handling: ```typescript expandable lines theme={null} const weatherToolWithRetry = tool({ name: 'get_weather', description: 'Get current weather with retry logic', inputSchema: z.object({ city: z.string(), units: z.enum(['celsius', 'fahrenheit']).default('celsius'), }), outputSchema: z.object({ temperature: z.number(), conditions: z.string(), error: z.string().optional(), }), execute: async ({ city, units }) => { const maxRetries = 3; let lastError: Error | null = null; for (let attempt = 1; attempt <= maxRetries; attempt++) { try { const response = await fetch( `https://api.weatherapi.com/v1/current.json?key=${process.env.WEATHER_API_KEY}&q=${encodeURIComponent(city)}` ); if (response.status === 429) { // Rate limited, wait and retry await new Promise((resolve) => setTimeout(resolve, 1000 * attempt)); continue; } if (!response.ok) { throw new Error(`API error: ${response.status}`); } const data = await response.json(); return { temperature: units === 'celsius' ? data.current.temp_c : data.current.temp_f, conditions: data.current.condition.text, }; } catch (error) { lastError = error as Error; } } // Return error in output rather than throwing return { temperature: 0, conditions: 'Unknown', error: `Failed after ${maxRetries} attempts: ${lastError?.message}`, }; }, }); ``` ## Testing ```typescript expandable lines theme={null} import { describe, it, expect, mock } from 'bun:test'; describe('weatherTool', () => { it('returns weather data for valid city', async () => { // Mock the fetch response global.fetch = mock(() => Promise.resolve({ ok: true, json: () => Promise.resolve({ current: { temp_c: 22, temp_f: 72, feelslike_c: 24, feelslike_f: 75, condition: { text: 'Sunny' }, humidity: 45, wind_kph: 10, wind_dir: 'NW', }, location: { name: 'London', region: 'City of London', country: 'UK', }, }), }) ); const result = await weatherTool.function.execute( { city: 'London', units: 'celsius' }, { numberOfTurns: 1 } ); expect(result.temperature).toBe(22); expect(result.conditions).toBe('Sunny'); expect(result.location.name).toBe('London'); }); it('handles city not found', async () => { global.fetch = mock(() => Promise.resolve({ ok: false, status: 400, }) ); await expect( weatherTool.function.execute( { city: 'InvalidCity123', units: 'celsius' }, { numberOfTurns: 1 } ) ).rejects.toThrow('City not found'); }); }); ``` ## See Also * **[Tools Guide](/docs/agent-sdk/call-model/tools)** - Tool creation fundamentals * **[API Reference](/docs/agent-sdk/call-model/api-reference)** - Complete type definitions # Working with Items Source: https://openrouter.ai/docs/agent-sdk/call-model/items Understanding the items-based streaming paradigm for callModel ## The Items Paradigm `callModel` is built on OpenRouter's Responses API which uses an **items-based model** rather than the messages-based model used by OpenAI Chat or Vercel AI SDK. The key insight: **items are emitted multiple times with the same ID but progressively updated content**. You replace the entire item by ID rather than accumulating stream chunks. ## Messages vs Items | Traditional (OpenAI Chat, Vercel AI) | callModel (Items-native) | | ------------------------------------ | --------------------------- | | Stream chunks, accumulate text | Stream items, replace by ID | | Single message type | Multiple item types | | Reconstruct content at end | Each emission is complete | | Manual state management | Natural React state updates | ## Item Types `getItemsStream()` yields these item types: | Type | Description | | ----------------------- | ---------------------------------- | | `message` | Assistant text responses | | `function_call` | Tool invocations with arguments | | `reasoning` | Model thinking (extended thinking) | | `web_search_call` | Web search operations | | `file_search_call` | File search operations | | `image_generation_call` | Image generation operations | | `function_call_output` | Results from executed tools | ## How Streaming Works Each iteration yields a **complete item** with the same ID but updated content: ```typescript lines theme={null} // Iteration 1 { id: "msg_123", type: "message", content: [{ type: "output_text", text: "Hello" }] } // Iteration 2 { id: "msg_123", type: "message", content: [{ type: "output_text", text: "Hello world" }] } // Iteration 3 { id: "msg_123", type: "message", content: [{ type: "output_text", text: "Hello world!" }] } ``` The same pattern applies to function calls: ```typescript lines theme={null} // Iteration 1 { type: "function_call", callId: "call_456", arguments: "{\"q" } // Iteration 2 { type: "function_call", callId: "call_456", arguments: "{\"query\": \"weather" } // Iteration 3 { type: "function_call", callId: "call_456", arguments: "{\"query\": \"weather in Paris\"}" } ``` ## React Integration The items paradigm eliminates manual chunk accumulation. Use a Map keyed by item ID and let React's reconciliation handle updates: ```tsx expandable lines theme={null} import { useState } from 'react'; import type { StreamableOutputItem } from '@openrouter/agent'; import { OpenRouter } from '@openrouter/agent'; const client = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY }); function Chat() { const [items, setItems] = useState>( new Map() ); async function handleSubmit(input: string) { const result = client.callModel({ model: 'anthropic/claude-sonnet-4', input, }); for await (const item of result.getItemsStream()) { // Replace the entire item by ID - React re-renders automatically setItems((prev) => new Map(prev).set(item.id, item)); } } return ( { e.preventDefault(); handleSubmit(input); }}> {/* input field */} {[...items.values()].map((item) => ( ))} ); } function ItemRenderer({ item }: { item: StreamableOutputItem }) { switch (item.type) { case 'message': return ; case 'function_call': return ; case 'reasoning': return ; default: return null; } } ``` ### Benefits * **No chunk accumulation** - Each item emission is complete * **Natural React updates** - Setting state triggers re-render automatically * **Concurrent item handling** - Function calls and messages stream in parallel * **Works with React 18+** - Compatible with concurrent features and Suspense * **Type-safe** - Full TypeScript inference for all item types ## Comparison with Chunk Accumulation Traditional streaming requires manual accumulation: ```tsx lines theme={null} // Traditional approach - manual accumulation const [text, setText] = useState(''); for await (const chunk of result.getTextStream()) { setText((prev) => prev + chunk); // Must accumulate manually } ``` With items, each emission replaces the previous: ```tsx lines theme={null} // Items approach - replace by ID for await (const item of result.getItemsStream()) { setItems((prev) => new Map(prev).set(item.id, item)); // Complete replacement } ``` The items approach is especially powerful when the model produces multiple outputs simultaneously (e.g., thinking + tool calls + text). ## Migrating from getNewMessagesStream() `getNewMessagesStream()` is deprecated in favor of `getItemsStream()`. The migration is straightforward: ```typescript lines theme={null} // Before (deprecated) for await (const message of result.getNewMessagesStream()) { if (message.type === 'message') { console.log(message.content); } } // After for await (const item of result.getItemsStream()) { if (item.type === 'message') { console.log(item.content); } } ``` The key difference: `getItemsStream()` includes all item types (reasoning, function calls, etc.), not just messages. ## Next Steps * **[Streaming](/docs/agent-sdk/call-model/streaming)** - All streaming methods including getItemsStream() * **[Tools](/docs/agent-sdk/call-model/tools)** - Creating typed tools with Zod schemas # Message Formats Source: https://openrouter.ai/docs/agent-sdk/call-model/message-formats The OpenRouter SDK provides helper functions to convert between popular message formats. This makes it easy to migrate existing code or integrate with different APIs. ## OpenAI Chat Format ### fromChatMessages() Convert OpenAI chat-style messages to OpenResponses input: ```typescript lines theme={null} import { OpenRouter, fromChatMessages } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); // OpenAI chat format const chatMessages = [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Hello!' }, { role: 'assistant', content: 'Hi there! How can I help you?' }, { role: 'user', content: 'What is the weather like?' }, ]; const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: fromChatMessages(chatMessages), }); const text = await result.getText(); ``` ### toChatMessage() Convert an OpenResponses response to chat message format: ```typescript lines theme={null} import { toChatMessage } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Hello!', }); const response = await result.getResponse(); const chatMessage = toChatMessage(response); // chatMessage is now: { role: 'assistant', content: '...' } console.log(chatMessage.role); // 'assistant' console.log(chatMessage.content); // Response text ``` ### Supported Message Types | Chat Role | Description | | ----------- | ---------------------- | | `system` | System instructions | | `user` | User messages | | `assistant` | Assistant responses | | `developer` | Developer instructions | | `tool` | Tool response messages | ### Tool Messages Tool responses are converted to function call outputs: ```typescript lines theme={null} const chatMessages = [ { role: 'user', content: 'What is the weather?' }, { role: 'assistant', content: null, tool_calls: [{ id: 'call_123', type: 'function', function: { name: 'get_weather', arguments: '{"location":"Paris"}' }, }], }, { role: 'tool', tool_call_id: 'call_123', content: '{"temperature": 20}', }, ]; const input = fromChatMessages(chatMessages); ``` ## Anthropic Claude Format ### fromClaudeMessages() Convert Anthropic Claude-style messages to OpenResponses input: ```typescript lines theme={null} import { OpenRouter, fromClaudeMessages } from '@openrouter/agent'; // Claude format const claudeMessages = [ { role: 'user', content: 'Hello!' }, { role: 'assistant', content: 'Hi there!' }, { role: 'user', content: 'Tell me about TypeScript.' }, ]; const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', input: fromClaudeMessages(claudeMessages), }); ``` ### toClaudeMessage() Convert an OpenResponses response to Claude message format: ```typescript lines theme={null} import { toClaudeMessage } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', input: 'Hello!', }); const response = await result.getResponse(); const claudeMessage = toClaudeMessage(response); // Compatible with Anthropic SDK types ``` ### Content Blocks Claude's content block format is supported: ```typescript lines theme={null} const claudeMessages = [ { role: 'user', content: [ { type: 'text', text: 'What is in this image?' }, { type: 'image', source: { type: 'url', url: 'https://example.com/image.jpg', }, }, ], }, ]; const input = fromClaudeMessages(claudeMessages); ``` ### Tool Use Blocks Claude's tool use format is converted: ```typescript expandable lines theme={null} const claudeMessages = [ { role: 'user', content: 'What is the weather?' }, { role: 'assistant', content: [ { type: 'tool_use', id: 'tool_123', name: 'get_weather', input: { location: 'Paris' }, }, ], }, { role: 'user', content: [ { type: 'tool_result', tool_use_id: 'tool_123', content: '{"temperature": 20}', }, ], }, ]; const input = fromClaudeMessages(claudeMessages); ``` ### Base64 Images Both URL and base64 images are supported: ```typescript lines theme={null} const claudeMessages = [ { role: 'user', content: [ { type: 'text', text: 'Describe this image.' }, { type: 'image', source: { type: 'base64', media_type: 'image/png', data: 'iVBORw0KGgo...', }, }, ], }, ]; ``` ### Limitations Some Claude features are not preserved in conversion. e.g. `is_error` flag on tool\_result blocks These features are Claude-specific and not supported by OpenRouter. ## Migration Examples ### From OpenAI SDK ```typescript expandable lines theme={null} // Before: OpenAI SDK import OpenAI from 'openai'; const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); const completion = await openai.chat.completions.create({ model: 'gpt-4', messages: [ { role: 'system', content: 'You are helpful.' }, { role: 'user', content: 'Hello!' }, ], }); // After: OpenRouter SDK import { OpenRouter, fromChatMessages } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY }); const result = openrouter.callModel({ model: 'openai/gpt-5.2', input: fromChatMessages([ { role: 'system', content: 'You are helpful.' }, { role: 'user', content: 'Hello!' }, ]), }); const text = await result.getText(); ``` ### From Anthropic SDK ```typescript expandable lines theme={null} // Before: Anthropic SDK import Anthropic from '@anthropic-ai/sdk'; const anthropic = new Anthropic(); const message = await anthropic.messages.create({ model: 'claude-sonnet-4-20250514', max_tokens: 1024, messages: [ { role: 'user', content: 'Hello!' }, ], }); // After: OpenRouter SDK import { OpenRouter, fromClaudeMessages } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY }); const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', input: fromClaudeMessages([ { role: 'user', content: 'Hello!' }, ]), maxOutputTokens: 1024, }); const text = await result.getText(); ``` ## Building Conversations Accumulate messages across multiple calls: ```typescript expandable lines theme={null} import { fromChatMessages, toChatMessage } from '@openrouter/agent'; // Start with initial message let messages = [ { role: 'system', content: 'You are a helpful assistant.' }, { role: 'user', content: 'Hello!' }, ]; // First call let result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: fromChatMessages(messages), }); let response = await result.getResponse(); let assistantMessage = toChatMessage(response); // Add to history messages.push(assistantMessage); messages.push({ role: 'user', content: 'What can you help me with?' }); // Continue conversation result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: fromChatMessages(messages), }); ``` ## Next Steps * **[Text Generation](/docs/agent-sdk/call-model/text-generation)** - Input formats and parameters * **[Tools](/docs/agent-sdk/call-model/tools)** - Add tool capabilities * **[Streaming](/docs/agent-sdk/call-model/streaming)** - Stream format-converted responses # Next Turn Params Source: https://openrouter.ai/docs/agent-sdk/call-model/next-turn-params Build encapsulated, context-aware tools with `nextTurnParams`. Create skills systems, plugins, and adaptive multi-turn agents. ## Why nextTurnParams? Traditional tool execution returns results to the model, but sometimes you need more: * **Skills/Plugins**: Load domain-specific instructions when a skill is activated * **Progressive Context**: Build up context as tools are used * **Adaptive Behavior**: Adjust model parameters based on tool results * **Clean Separation**: Tools manage their own context requirements With `nextTurnParams`, tools can modify any `callModel` parameter for the next turn. ## Basic Example ```typescript expandable lines theme={null} import { tool } from '@openrouter/agent'; import { z } from 'zod'; const expertModeTool = tool({ name: 'enable_expert_mode', description: 'Enable expert mode for detailed technical responses', inputSchema: z.object({ domain: z.string().describe('Technical domain (e.g., "kubernetes", "react")'), }), outputSchema: z.object({ enabled: z.boolean() }), nextTurnParams: { instructions: (params, context) => { const base = context.instructions ?? ''; return `${base} EXPERT MODE ENABLED for ${params.domain}: - Provide detailed technical explanations - Include code examples and best practices - Reference official documentation - Assume advanced knowledge`; }, temperature: () => 0.3, // More precise for technical content }, execute: async (params) => { return { enabled: true }; }, }); ``` ## The Claude Code Skills Pattern This example shows how to recreate Claude Code's skills system as a single encapsulated tool: ```typescript expandable lines theme={null} import { tool } from '@openrouter/agent'; import { readFileSync } from 'fs'; import { z } from 'zod'; const skillsTool = tool({ name: "skill", description: `Load a specialized skill to enhance the assistant's capabilities. Available skills: pdf-processing, data-analysis, code-review, etc. Each skill provides domain-specific instructions and capabilities.`, inputSchema: z.object({ type: z.string().describe("The skill type to load (e.g., 'pdf-processing')"), }), outputSchema: z.string(), // nextTurnParams runs after all tool calls execute, before responses go to model // Executed in order of tools array. This is where the magic happens. nextTurnParams: { input: (params, context) => { // Prevent duplicate skill loading if (JSON.stringify(context.input).includes(`Skill ${params.type} is already loaded`)) { return context.input; } // Load the skill's instructions from file system const skill = readFileSync( `~/.claude/skills/${params.type}/SKILL.md`, "utf-8" ); // Inject skill context into the conversation return [ ...context.input, { role: "user", content: `Base directory for this skill: ~/.claude/skills/${params.type}/ ${skill}`, }, ]; }, }, execute: async (params, context) => { // Check if already loaded if (JSON.stringify(context.input).includes(`Skill ${params.type} is already loaded`)) { return `Skill ${params.type} is already loaded`; } return `Launching skill ${params.type}`; }, }); // Usage - the skill automatically enriches future turns const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', input: 'Process this PDF and extract the key findings', tools: [skillsTool], }); ``` ### Key Benefits 1. **Encapsulation**: Skill loading logic is entirely contained in the tool 2. **Idempotency**: Built-in check prevents loading the same skill twice 3. **Clean API**: Callers don't need to know about skill file locations 4. **Composability**: Multiple skills can be loaded across turns ## Execution Order Understanding when `nextTurnParams` runs is crucial: ```lines theme={null} 1. Model generates tool calls ↓ 2. All tool `execute` functions run ↓ 3. `nextTurnParams` functions run for each tool (in tools array order) ↓ 4. Modified parameters used for next model turn ↓ 5. Repeat until model stops calling tools ``` ## Available Context `nextTurnParams` functions receive two arguments: ### params The validated input parameters that were passed to the tool: ```typescript lines theme={null} nextTurnParams: { instructions: (params, context) => { // params is typed based on inputSchema console.log(params.type); // e.g., "pdf-processing" return `Handle ${params.type}`; }, }, ``` ### context The current request context, including: | Property | Type | Description | | ----------------- | ----------------------- | --------------------------- | | `input` | `OpenResponsesInput` | Current message history | | `model` | `string \| undefined` | Current model selection | | `models` | `string[] \| undefined` | Model fallback array | | `instructions` | `string \| undefined` | Current system instructions | | `temperature` | `number \| undefined` | Current temperature | | `maxOutputTokens` | `number \| undefined` | Current max tokens | | `topP` | `number \| undefined` | Current top-p sampling | | `topK` | `number \| undefined` | Current top-k sampling | ## Modifiable Parameters You can modify `CallModelInput` parameters: ```typescript lines theme={null} nextTurnParams: { // Modify message history input: (params, ctx) => [...ctx.input, newMessage], // Change model model: (params, ctx) => 'anthropic/claude-sonnet-4.5', // Update instructions instructions: (params, ctx) => `${ctx.instructions}\n\nNew context...`, // Adjust generation parameters temperature: (params, ctx) => 0.5, maxOutputTokens: (params, ctx) => 2000, }, ``` ## Patterns ### Research Context Accumulation Build up context as research progresses: ```typescript lines theme={null} const researchTool = tool({ name: "research", inputSchema: z.object({ topic: z.string() }), outputSchema: z.object({ findings: z.array(z.string()) }), nextTurnParams: { instructions: (params, context) => { const base = context.instructions ?? ''; return `${base} Previous research on "${params.topic}" found important context. Build upon these findings in your response.`; }, }, execute: async (params) => { const results = await searchDatabase(params.topic); return { findings: results }; }, }); ``` ### Complexity-Based Model Selection Upgrade to better models when needed: ```typescript expandable lines theme={null} const complexityAnalyzer = tool({ name: "analyze_complexity", inputSchema: z.object({ code: z.string() }), outputSchema: z.object({ complexity: z.enum(['low', 'medium', 'high']) }), nextTurnParams: { model: (params, context) => { // Upgrade to more capable model for complex code if (params.complexity === 'high') { return 'anthropic/claude-sonnet-4.5'; } return context.model ?? 'openai/gpt-5-nano'; }, temperature: (params, context) => { // Lower temperature for complex analysis return params.complexity === 'high' ? 0.3 : 0.7; }, }, execute: async (params) => { return analyzeCodeComplexity(params.code); }, }); ``` ### Multi-Skill Loading Load multiple skills at once: ```typescript expandable lines theme={null} const multiSkillLoader = tool({ name: 'load_skills', description: 'Load multiple skills at once', inputSchema: z.object({ skills: z.array(z.string()).describe('Array of skill names to load'), }), outputSchema: z.object({ loaded: z.array(z.string()), failed: z.array(z.object({ name: z.string(), reason: z.string() })), }), nextTurnParams: { input: (params, context) => { let newInput = context.input; for (const skillName of params.skills) { const skillPath = `~/.skills/${skillName}/SKILL.md`; if (!existsSync(skillPath)) continue; const skillMarker = `[Skill: ${skillName}]`; if (JSON.stringify(newInput).includes(skillMarker)) continue; const skillContent = readFileSync(skillPath, 'utf-8'); newInput = [ ...(Array.isArray(newInput) ? newInput : [newInput]), { role: 'user', content: `${skillMarker}\n${skillContent}` }, ]; } return newInput; }, }, execute: async ({ skills }) => { const loaded = []; const failed = []; for (const skill of skills) { if (existsSync(`~/.skills/${skill}/SKILL.md`)) { loaded.push(skill); } else { failed.push({ name: skill, reason: 'Not found' }); } } return { loaded, failed }; }, }); ``` ### Language/Locale Switching Adapt to user language preferences: ```typescript expandable lines theme={null} const languageTool = tool({ name: 'set_language', inputSchema: z.object({ language: z.enum(['en', 'es', 'fr', 'de', 'ja']), }), outputSchema: z.object({ set: z.boolean() }), nextTurnParams: { instructions: (params, context) => { const base = context.instructions ?? ''; const languageInstructions = { en: 'Respond in English.', es: 'Responde en español.', fr: 'Répondez en français.', de: 'Antworten Sie auf Deutsch.', ja: '日本語で回答してください。', }; return `${base}\n\n${languageInstructions[params.language]}`; }, }, execute: async (params) => ({ set: true }), }); ``` ## Best Practices ### Idempotency Checks Always check if context was already added: ```typescript lines theme={null} nextTurnParams: { input: (params, context) => { const marker = `[Context: ${params.id}]`; // Don't add if already present if (JSON.stringify(context.input).includes(marker)) { return context.input; } return [...context.input, { role: 'user', content: `${marker}\n${newContent}`, }]; }, }, ``` ### Type Safety Use proper typing for context access: ```typescript lines theme={null} nextTurnParams: { instructions: (params, context) => { // Safe access with fallback const base = context.instructions ?? 'You are a helpful assistant.'; return `${base}\n\nAdditional context: ${params.data}`; }, }, ``` ### Minimal Modifications Only modify what's necessary: ```typescript lines theme={null} // Good: Minimal, targeted change nextTurnParams: { temperature: (params) => params.needsPrecision ? 0.2 : undefined, }, // Avoid: Unnecessary spreading nextTurnParams: { temperature: (params, ctx) => { return params.needsPrecision ? 0.2 : ctx.temperature; }, }, ``` ## See Also * **[Skills Loader Example](/docs/agent-sdk/call-model/examples/skills-loader)** - Complete implementation * **[Dynamic Parameters](/docs/agent-sdk/call-model/dynamic-parameters)** - Async parameter functions * **[Stop Conditions](/docs/agent-sdk/call-model/stop-conditions)** - Execution control # Call Model (Typescript) Source: https://openrouter.ai/docs/agent-sdk/call-model/overview A unified API for calling any LLM with automatic tool execution and multiple consumption patterns ## Why callModel? * **Items-Based Model**: Built on OpenRouter's Responses API with structured items (messages, tool calls, reasoning) instead of raw message chunks * **Multiple Consumption Patterns**: Get text, stream responses, or access structured data - all from a single call * **Automatic Tool Execution**: Define tools with Zod schemas and let the SDK handle execution loops * **Type Safety**: Full TypeScript inference for tool inputs, outputs, and events * **Format Compatibility**: Convert to/from OpenAI chat and Anthropic Claude message formats * **Streaming First**: Built on a reusable stream architecture that supports concurrent consumers ## Quick Start ```typescript lines theme={null} import { OpenRouter } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the capital of France?', }); // Get text (simplest pattern) const text = await result.getText(); console.log(text); // "The capital of France is Paris." ``` ## Consumption Patterns callModel returns a `ModelResult` object that provides multiple ways to consume the response: ### Text Methods ```typescript lines theme={null} // Get just the text content const text = await result.getText(); // Get the full response with usage data const response = await result.getResponse(); console.log(response.usage); // { inputTokens, outputTokens, cachedTokens } ``` ### Streaming Methods ```typescript lines theme={null} // Stream text deltas for await (const delta of result.getTextStream()) { process.stdout.write(delta); } // Stream reasoning (for reasoning models) for await (const delta of result.getReasoningStream()) { console.log('Reasoning:', delta); } // Stream complete items by ID (recommended) for await (const item of result.getItemsStream()) { console.log('Item update:', item.type, item.id); } // Stream all events (including tool preliminary results) for await (const event of result.getFullResponsesStream()) { console.log('Event:', event.type); } ``` ### Tool Methods ```typescript lines theme={null} // Get all tool calls from the response const toolCalls = await result.getToolCalls(); // Stream tool calls as they complete for await (const toolCall of result.getToolCallsStream()) { console.log(`Tool: ${toolCall.name}`, toolCall.arguments); } // Stream tool deltas and preliminary results for await (const event of result.getToolStream()) { if (event.type === 'delta') { process.stdout.write(event.content); } else if (event.type === 'preliminary_result') { console.log('Progress:', event.result); } } ``` ## Input Formats callModel accepts multiple input formats: ```typescript lines theme={null} // Simple string const result1 = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Hello!', }); // Message array (OpenResponses format) const result2 = openrouter.callModel({ model: 'openai/gpt-5-nano', input: [ { role: 'user', content: 'Hello!' }, ], }); // With system instructions const result3 = openrouter.callModel({ model: 'openai/gpt-5-nano', instructions: 'You are a helpful assistant.', input: 'Hello!', }); ``` ## What's Next? Explore the guides to learn more about specific features: * **[Working with Items](/docs/agent-sdk/call-model/items)** - Understand the items-based streaming paradigm * **[Text Generation](/docs/agent-sdk/call-model/text-generation)** - Input formats, model selection, and response handling * **[Streaming](/docs/agent-sdk/call-model/streaming)** - All streaming methods and patterns * **[Tools](/docs/agent-sdk/call-model/tools)** - Creating typed tools with Zod schemas and multi-turn orchestration * **[nextTurnParams](/docs/agent-sdk/call-model/next-turn-params)** - Tool-driven context injection for skills and plugins * **[Message Formats](/docs/agent-sdk/call-model/message-formats)** - Converting to/from OpenAI and Claude formats * **[Dynamic Parameters](/docs/agent-sdk/call-model/dynamic-parameters)** \- Async functions for adaptive behavior * **[Stop Conditions](/docs/agent-sdk/call-model/stop-conditions)** - Intelligent execution control * **[API Reference](/docs/agent-sdk/call-model/api-reference)** - Complete type definitions and method signatures ### Example Tools Ready-to-use tool implementations: * **[Weather Tool](/docs/agent-sdk/call-model/examples/weather-tool)** - Basic API integration * **[Skills Loader](/docs/agent-sdk/call-model/examples/skills-loader)** - Claude Code skills pattern # Stop Conditions Source: https://openrouter.ai/docs/agent-sdk/call-model/stop-conditions Control multi-turn execution with `stopWhen`. Use built-in helpers or custom conditions to stop by step count, tool calls, cost, or tokens. ## Basic Usage ```typescript lines theme={null} import { OpenRouter, stepCountIs } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Research this topic thoroughly', tools: [searchTool, analysisTool], stopWhen: stepCountIs(5), // Stop after 5 steps }); ``` ## Built-in Stop Conditions ### stepCountIs(n) Stop after a specific number of steps: ```typescript lines theme={null} import { stepCountIs } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Analyze this data', tools: [analysisTool], stopWhen: stepCountIs(10), // Stop after 10 steps }); ``` ### hasToolCall(name) Stop when a specific tool is called: ```typescript lines theme={null} import { hasToolCall } from '@openrouter/agent'; const finishTool = tool({ name: 'finish', description: 'Call this when the task is complete', inputSchema: z.object({ summary: z.string(), }), execute: async (params) => ({ done: true }), }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Research until you have enough information, then call finish', tools: [searchTool, finishTool], stopWhen: hasToolCall('finish'), // Stop when finish tool is called }); ``` ### maxTokensUsed(n) Stop after using a certain number of tokens: ```typescript lines theme={null} import { maxTokensUsed } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Generate content', tools: [writingTool], stopWhen: maxTokensUsed(5000), // Stop after 5000 total tokens }); ``` ### maxCost(amount) Stop after reaching a cost threshold: ```typescript lines theme={null} import { maxCost } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'openai/gpt-5.2', input: 'Perform extensive analysis', tools: [analysisTool], stopWhen: maxCost(1.00), // Stop after $1.00 spent }); ``` ### finishReasonIs(reason) Stop on a specific finish reason: ```typescript lines theme={null} import { finishReasonIs } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Complete this task', tools: [taskTool], stopWhen: finishReasonIs('stop'), // Stop when model finishes naturally }); ``` ## Combining Conditions Pass an array to stop on any condition: ```typescript lines theme={null} import { stepCountIs, hasToolCall, maxCost } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'openai/gpt-5.2', input: 'Research thoroughly but stay within budget', tools: [searchTool, finishTool], stopWhen: [ stepCountIs(10), // Maximum 10 steps maxCost(0.50), // Maximum $0.50 hasToolCall('finish'), // Or when finish is called ], }); ``` Execution stops when **any** condition is met. ## Custom Stop Conditions Create custom conditions with a function: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Process data', tools: [processTool], stopWhen: ({ steps }) => { // Stop after 20 steps if (steps.length >= 20) return true; // Stop if last step had no tool calls const lastStep = steps[steps.length - 1]; if (lastStep && !lastStep.toolCalls?.length) return true; // Continue otherwise return false; }, }); ``` ### StopConditionContext Custom functions receive: | Property | Type | Description | | -------- | -------------- | ----------------------------------------------- | | `steps` | `StepResult[]` | All completed steps including results and usage | ### StepResult Each step contains: ```typescript lines theme={null} interface StepResult { response: Response; toolCalls?: ParsedToolCall[]; toolResults?: ToolExecutionResult[]; tokens: { input: number; output: number; cached: number; }; cost: number; } ``` ## Advanced Patterns ### Time-Based Stopping Stop after a time limit: ```typescript lines theme={null} const startTime = Date.now(); const maxDuration = 30000; // 30 seconds const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Work on this task', tools: [workTool], stopWhen: () => { return Date.now() - startTime > maxDuration; }, }); ``` ### Content-Based Stopping Stop based on response content: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Search until you find the answer', tools: [searchTool], stopWhen: ({ steps }) => { const lastStep = steps[steps.length - 1]; if (!lastStep) return false; // Check if response contains certain keywords const content = JSON.stringify(lastStep.response); return content.includes('ANSWER FOUND') || content.includes('TASK COMPLETE'); }, }); ``` ### Quality-Based Stopping Stop when results meet quality threshold: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Improve this text until it scores above 0.9', tools: [improverTool, scorerTool], stopWhen: ({ steps }) => { // Look for score in tool results for (const step of steps) { for (const result of step.toolResults ?? []) { if (result.toolName === 'scorer' && result.result?.score > 0.9) { return true; } } } return false; }, }); ``` ### Combination with Early Exit Combine conditions for complex logic: ```typescript expandable lines theme={null} import { stepCountIs, maxCost } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'openai/gpt-5.2', input: 'Complex research task', tools: [searchTool, analysisTool, summarizeTool], stopWhen: [ // Hard limits stepCountIs(50), maxCost(5.00), // Custom success condition ({ steps }) => { const lastStep = steps[steps.length - 1]; const hasSummary = lastStep?.toolCalls?.some( tc => tc.name === 'summarize' ); return hasSummary; }, ], }); ``` ## Migration from maxToolRounds If you were using `maxToolRounds`, migrate to `stopWhen`: ```typescript lines theme={null} // Before: maxToolRounds const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Hello', tools: [myTool], maxToolRounds: 5, }); // After: stopWhen import { stepCountIs } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Hello', tools: [myTool], stopWhen: stepCountIs(5), }); ``` ### Default Behavior If `stopWhen` is not specified, the default is `stepCountIs(5)`. ## Best Practices ### Always Set Limits Always include a hard limit to prevent runaway execution: ```typescript lines theme={null} stopWhen: [ stepCountIs(100), // Hard limit maxCost(10.00), // Budget limit customCondition, // Your logic ], ``` ### Log Stop Reasons Track why execution stopped: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Task', tools: [taskTool], stopWhen: ({ steps }) => { if (steps.length >= 10) { console.log('Stopped: step limit'); return true; } const totalCost = steps.reduce((sum, step) => sum + (step.cost ?? 0), 0); if (totalCost >= 1.00) { console.log('Stopped: cost limit'); return true; } return false; }, }); ``` ### Test Conditions Verify conditions work as expected: ```typescript lines theme={null} // Test with low limits first const testResult = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Test task', tools: [testTool], stopWhen: stepCountIs(2), // Low limit for testing }); ``` ## See Also * **[Tools](/docs/agent-sdk/call-model/tools)** - Multi-turn orchestration * **[Dynamic Parameters](/docs/agent-sdk/call-model/dynamic-parameters)** - Adaptive behavior * **[nextTurnParams](/docs/agent-sdk/call-model/next-turn-params)** - Tool-driven modifications # Streaming Source: https://openrouter.ai/docs/agent-sdk/call-model/streaming Stream responses in real-time with multiple consumption patterns. All streams are built on a reusable stream architecture that supports concurrent consumers. ## Text Streaming ### getTextStream() Stream text content as it's generated: ```typescript lines theme={null} import { OpenRouter } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Write a short poem about the ocean.', }); for await (const delta of result.getTextStream()) { process.stdout.write(delta); } ``` Each iteration yields a small chunk of text (typically a few characters or a word). ## Reasoning Streaming ### getReasoningStream() For models that support reasoning (like o1 or Claude with thinking), stream the reasoning process: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/o1-preview', input: 'Solve this step by step: If x + 5 = 12, what is x?', }); console.log('Reasoning:'); for await (const delta of result.getReasoningStream()) { process.stdout.write(delta); } console.log('\n\nFinal answer:'); const text = await result.getText(); console.log(text); ``` ## Items Streaming ### getItemsStream() Stream complete items as they update. This is the **recommended way** to handle streaming when you need structured access to all output types (messages, tool calls, reasoning, etc.). See [Working with Items](/docs/agent-sdk/call-model/items) for the full paradigm explanation. ```typescript expandable lines theme={null} import type { StreamableOutputItem } from '@openrouter/agent'; const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4', input: 'Hello!', tools: [myTool], }); for await (const item of result.getItemsStream()) { switch (item.type) { case 'message': console.log('Message:', item.content); break; case 'function_call': console.log('Tool call:', item.name, item.arguments); break; case 'reasoning': console.log('Thinking:', item.summary); break; case 'function_call_output': console.log('Tool result:', item.output); break; } } ``` **Key insight**: Each iteration yields a **complete item** with the same ID but updated content. Replace items by ID rather than accumulating deltas. This stream yields all item types: | Type | Description | | ----------------------- | ---------------------------------- | | `message` | Assistant text responses | | `function_call` | Tool invocations with arguments | | `reasoning` | Model thinking (extended thinking) | | `web_search_call` | Web search operations | | `file_search_call` | File search operations | | `image_generation_call` | Image generation operations | | `function_call_output` | Results from executed tools | ## Message Streaming (Deprecated) ### getNewMessagesStream() `getNewMessagesStream()` is deprecated. Use `getItemsStream()` instead, which includes all item types and follows the items-based paradigm. Stream cumulative message snapshots in the OpenResponses format: ```typescript lines theme={null} // Deprecated - use getItemsStream() instead const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Hello!', tools: [myTool], }); for await (const message of result.getNewMessagesStream()) { if (message.type === 'message') { console.log('Assistant message:', message.content); } else if (message.type === 'function_call_output') { console.log('Tool result:', message.output); } } ``` This stream yields: * `ResponsesOutputMessage` - Assistant text/content updates * `OpenResponsesFunctionCallOutput` - Tool execution results (after tools complete) ## Full Event Streaming ### getFullResponsesStream() Stream all response events including tool preliminary results: ```typescript expandable lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Search for documents', tools: [searchTool], // Generator tool with eventSchema }); for await (const event of result.getFullResponsesStream()) { switch (event.type) { case 'response.output_text.delta': process.stdout.write(event.delta); break; case 'response.function_call_arguments.delta': console.log('Tool argument delta:', event.delta); break; case 'response.completed': console.log('Response complete'); break; case 'tool.preliminary_result': // Intermediate progress from generator tools console.log('Progress:', event.result); break; case 'tool.result': // Final result when tool execution completes console.log('Tool completed:', event.toolCallId); console.log('Result:', event.result); // Access any preliminary results that were emitted if (event.preliminaryResults) { console.log('Preliminary results:', event.preliminaryResults); } break; } } ``` ### Event Types The full stream includes these event types: | Event Type | Description | | ---------------------------------------- | --------------------------------------------------- | | `response.created` | Response object created | | `response.in_progress` | Generation started | | `response.output_text.delta` | Text content chunk | | `response.output_text.done` | Text content complete | | `response.reasoning.delta` | Reasoning content chunk | | `response.reasoning.done` | Reasoning complete | | `response.function_call_arguments.delta` | Tool call argument chunk | | `response.function_call_arguments.done` | Tool call arguments complete | | `response.completed` | Full response complete | | `tool.preliminary_result` | Progress from generator tools (intermediate yields) | | `tool.result` | Final result from tool execution | ## Tool Call Streaming ### getToolCallsStream() Stream structured tool calls as they complete: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the weather in Paris and Tokyo?', tools: [weatherTool], maxToolRounds: 0, // Don't auto-execute, just get tool calls }); for await (const toolCall of result.getToolCallsStream()) { console.log(`Tool: ${toolCall.name}`); console.log(`Arguments:`, toolCall.arguments); console.log(`ID: ${toolCall.id}`); } ``` ### getToolStream() Stream tool deltas and preliminary results: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Search for TypeScript tutorials', tools: [searchTool], // Generator tool }); for await (const event of result.getToolStream()) { if (event.type === 'delta') { // Raw argument deltas process.stdout.write(event.content); } else if (event.type === 'preliminary_result') { // Progress from generator tools console.log(`\nProgress (${event.toolCallId}):`, event.result); } } ``` ## Concurrent Consumers Multiple consumers can read from the same result: ```typescript expandable lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Write a story.', }); // Start both consumers concurrently const [text, response] = await Promise.all([ // Consumer 1: Collect text (async () => { let text = ''; for await (const delta of result.getTextStream()) { text += delta; } return text; })(), // Consumer 2: Get full response result.getResponse(), ]); console.log('Text length:', text.length); console.log('Token usage:', response.usage); ``` The underlying `ReusableReadableStream` ensures each consumer receives all events. ## Cancellation Cancel a stream to stop generation: ```typescript expandable lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Write a very long essay...', }); // Start streaming const streamPromise = (async () => { let charCount = 0; for await (const delta of result.getTextStream()) { process.stdout.write(delta); charCount += delta.length; // Cancel after 500 characters if (charCount > 500) { await result.cancel(); break; } } })(); await streamPromise; console.log('\nCancelled!'); ``` ## Streaming with UI Frameworks ### React Example ```typescript expandable lines theme={null} import { useState, useEffect } from 'react'; function ChatResponse({ prompt }: { prompt: string }) { const [text, setText] = useState(''); const [isStreaming, setIsStreaming] = useState(true); useEffect(() => { const openrouter = new OpenRouter({ apiKey: API_KEY }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: prompt, }); (async () => { for await (const delta of result.getTextStream()) { setText(prev => prev + delta); } setIsStreaming(false); })(); return () => { result.cancel(); }; }, [prompt]); return ( {text} {isStreaming && |} ); } ``` ### Server-Sent Events (SSE) ```typescript expandable lines theme={null} import { Hono } from 'hono'; import { streamSSE } from 'hono/streaming'; const app = new Hono(); app.get('/stream', (c) => { return streamSSE(c, async (stream) => { const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: c.req.query('prompt') || 'Hello!', }); for await (const delta of result.getTextStream()) { await stream.writeSSE({ data: JSON.stringify({ delta }), event: 'delta', }); } await stream.writeSSE({ data: JSON.stringify({ done: true }), event: 'done', }); }); }); ``` ## Next Steps * **[Working with Items](/docs/agent-sdk/call-model/items)** - Understand the items-based streaming paradigm * **[Tools](/docs/agent-sdk/call-model/tools)** - Create tools and multi-turn streaming with tools # Text Generation Source: https://openrouter.ai/docs/agent-sdk/call-model/text-generation Generate text with callModel using various input formats and model configurations. Supports multiple consumption patterns including text, streaming, and structured output. ## Basic Usage The simplest way to generate text: ```typescript lines theme={null} import { OpenRouter } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Explain quantum computing in one sentence.', }); const text = await result.getText(); ``` ## Input Formats callModel accepts several input formats to match your use case. ### String Input The simplest format - a single string becomes a user message: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the speed of light?', }); ``` ### Message Array For multi-turn conversations, pass an array of messages: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: [ { role: 'user', content: 'My name is Alice.' }, { role: 'assistant', content: 'Hello Alice! How can I help you today?' }, { role: 'user', content: 'What is my name?' }, ], }); ``` ### Multimodal For rich content including images: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5.2', input: [ { type: 'message', role: 'user', content: [ { type: 'input_text', text: 'What is in this image?' }, { type: 'input_image', imageUrl: 'https://example.com/image.jpg', detail: 'auto', }, ], }, ], }); ``` ## System Instructions Set the model's behavior with the `instructions` parameter: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', instructions: 'You are a helpful coding assistant. Be concise and provide working code examples.', input: 'How do I read a file in Node.js?', }); ``` ## Model Selection ### Single Model Specify a model by its OpenRouter ID: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4.5', input: 'Hello!', }); ``` ### Model Fallback Provide multiple models for automatic fallback: ```typescript lines theme={null} const result = openrouter.callModel({ models: ['anthropic/claude-sonnet-4.5', 'openai/gpt-5.2', 'google/gemini-pro'], input: 'Hello!', }); ``` The SDK will try each model in order until one succeeds. ## Response Methods ### getText() Returns just the text content after tool execution completes: ```typescript lines theme={null} const text = await result.getText(); console.log(text); // "The speed of light is approximately 299,792 km/s." ``` ### getResponse() Returns the full response object including usage data: ```typescript lines theme={null} const response = await result.getResponse(); console.log(response.output); // Full output array console.log(response.usage); // Token usage information // Usage includes: // - inputTokens: tokens in the prompt // - outputTokens: tokens generated // - cachedTokens: tokens served from cache (cost savings) ``` ## Generation Parameters Control the generation behavior: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Write a creative story.', // Temperature: 0 = deterministic, 2 = very creative temperature: 0.7, // Maximum tokens to generate maxOutputTokens: 1000, // Top-p sampling topP: 0.9, }); ``` ## Response Format Request structured output: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'List three programming languages.', text: { format: { type: 'json_object', }, }, }); const text = await result.getText(); const data = JSON.parse(text); ``` ## Error Handling Handle common error cases: ```typescript lines theme={null} try { const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Hello!', }); const text = await result.getText(); } catch (error) { if (error instanceof Error && 'statusCode' in error) { if (error.statusCode === 401) { console.error('Invalid API key'); } else if (error.statusCode === 429) { console.error('Rate limited - try again later'); } else if (error.statusCode === 503) { console.error('Model unavailable'); } } else { console.error('Unexpected error:', error); } } ``` ## Concurrent Requests Each callModel invocation is independent: ```typescript lines theme={null} const [result1, result2, result3] = await Promise.all([ openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Question 1' }).getText(), openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Question 2' }).getText(), openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Question 3' }).getText(), ]); ``` ## Next Steps * **[Streaming](/docs/agent-sdk/call-model/streaming)** - Stream responses in real-time * **[Tools](/docs/agent-sdk/call-model/tools)** - Add tool capabilities to your generation * **[Message Formats](/docs/agent-sdk/call-model/message-formats)** - Convert from OpenAI/Claude formats # Tool Approval & State Persistence Source: https://openrouter.ai/docs/agent-sdk/call-model/tool-approval-state Add human-in-the-loop approval gates for sensitive tools and persist conversation state across callModel invocations. ## Why Approval Gates? Some tools — sending emails, making payments, deleting records — should not auto-execute without human review. The SDK provides two mechanisms to control this: * **`requireApproval`** — pause execution when the model calls sensitive tools, giving users a chance to approve or reject each call * **`StateAccessor`** — persist conversation state between `callModel` invocations so approval decisions, message history, and tool results survive across runs Together, these enable human-in-the-loop workflows where a user reviews tool calls before they execute, even across separate request/response cycles (e.g., in a web application). ## Tool-Level Approval Add `requireApproval` directly on a tool definition. It accepts a boolean or a function: ### Always Require Approval ```typescript lines theme={null} import { tool } from '@openrouter/agent'; import { z } from 'zod'; const sendEmailTool = tool({ name: 'send_email', description: 'Send an email to a recipient', inputSchema: z.object({ to: z.string().email(), subject: z.string(), body: z.string(), }), outputSchema: z.object({ sent: z.boolean() }), requireApproval: true, execute: async (params) => { await sendEmail(params); return { sent: true }; }, }); ``` ### Conditional Approval Pass a function to require approval only in certain cases: ```typescript lines theme={null} const deleteRecordTool = tool({ name: 'delete_record', description: 'Delete a record from the database', inputSchema: z.object({ id: z.string(), environment: z.enum(['staging', 'production']), }), outputSchema: z.object({ deleted: z.boolean() }), requireApproval: (params, context) => { // Only require approval for production deletions return params.environment === 'production'; }, execute: async (params) => { await deleteRecord(params.id); return { deleted: true }; }, }); ``` The function receives the parsed tool arguments and a `TurnContext`, and can return a boolean or `Promise`. ## Call-Level Approval Override tool-level settings with a `requireApproval` callback on `callModel` itself: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-4o', input: 'Send an email and search for documents', tools: [sendEmailTool, searchTool], state: myStateAccessor, requireApproval: (toolCall, context) => { // Require approval for any tool that modifies data return toolCall.name === 'send_email' || toolCall.name === 'delete_record'; }, }); ``` The call-level callback takes priority over tool-level `requireApproval` settings when both are present. ## How the Approval Flow Works When tools with approval gates are called by the model, the SDK follows this flow: 1. **Model generates tool calls** — the model decides which tools to invoke 2. **SDK partitions tool calls** — each call is checked against `requireApproval` and split into two groups: those requiring approval and those that can auto-execute 3. **Auto-execute tools run immediately** — tools that don't need approval execute in parallel as normal 4. **State saves with pending approvals** — the conversation state updates to `status: 'awaiting_approval'` with the pending tool calls stored 5. **Control returns to the caller** — check `result.requiresApproval()` and inspect pending calls with `result.getPendingToolCalls()` 6. **Resume with decisions** — call `callModel` again with the same `state`, passing `approveToolCalls` and/or `rejectToolCalls` arrays of tool call IDs 7. **Approved tools execute** — the SDK runs approved tools and sends results to the model. Rejected tools send an error message to the model explaining the rejection 8. **Conversation continues** — the model processes tool results and generates the next response ## StateAccessor Interface The `StateAccessor` interface enables any storage backend: ```typescript lines theme={null} import type { StateAccessor, ConversationState } from '@openrouter/agent'; interface StateAccessor { /** Load the current conversation state, or null if none exists */ load: () => Promise | null>; /** Save the conversation state */ save: (state: ConversationState) => Promise; } ``` ### In-Memory Implementation ```typescript lines theme={null} const conversations = new Map(); function createStateAccessor(conversationId: string): StateAccessor { return { load: async () => conversations.get(conversationId) ?? null, save: async (state) => { conversations.set(conversationId, state); }, }; } ``` For production use, implement `StateAccessor` with a persistent backend like Redis, a database, or file storage to survive process restarts. ## ConversationState The state object tracks everything needed to resume a conversation: | Field | Type | Description | | -------------------- | ------------------------- | -------------------------------------------------------------------------- | | `id` | `string` | Unique conversation identifier | | `messages` | `OpenResponsesInputUnion` | Full message history | | `previousResponseId` | `string?` | Previous response ID for server-side chaining | | `pendingToolCalls` | `ParsedToolCall[]?` | Tool calls awaiting human input, such as approval/rejection or HITL output | | `unsentToolResults` | `UnsentToolResult[]?` | Executed results not yet sent to model | | `partialResponse` | `PartialResponse?` | Data captured during interruption | | `interruptedBy` | `string?` | Signal from a new request that interrupted this conversation | | `status` | `ConversationStatus` | Current state of the conversation | | `createdAt` | `number` | Creation timestamp (Unix ms) | | `updatedAt` | `number` | Last update timestamp (Unix ms) | ### Status Values | Status | Meaning | | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `'in_progress'` | Conversation is actively processing | | `'awaiting_approval'` | Paused, waiting for tool call approval/rejection | | `'awaiting_hitl'` | Paused by a [HITL tool](/docs/agent-sdk/call-model/tools#human-in-the-loop-hitl-tools) whose `onToolCalled` hook returned `null`; resume by supplying a `function_call_output` for each paused call | | `'complete'` | Conversation finished normally | | `'interrupted'` | Conversation was interrupted and can be resumed | ## Complete Example Here is an end-to-end example showing approval gates with state persistence: ```typescript expandable lines theme={null} import { OpenRouter, tool } from '@openrouter/agent'; import type { ConversationState, StateAccessor } from '@openrouter/agent'; import { z } from 'zod'; // 1. Define a tool with approval required const sendEmailTool = tool({ name: 'send_email', description: 'Send an email', inputSchema: z.object({ to: z.string().email(), subject: z.string(), body: z.string(), }), outputSchema: z.object({ sent: z.boolean(), messageId: z.string() }), requireApproval: true, execute: async (params) => { const result = await sendEmail(params); return { sent: true, messageId: result.id }; }, }); // 2. Create a state accessor (in-memory for this example) const store = new Map(); const conversationId = 'conv-123'; const state: StateAccessor = { load: async () => store.get(conversationId) ?? null, save: async (s) => { store.set(conversationId, s); }, }; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY }); // 3. First callModel — model will try to call the tool const result = openrouter.callModel({ model: 'openai/gpt-4o', input: 'Send a welcome email to alice@example.com', tools: [sendEmailTool] as const, state, }); // 4. Check if approval is needed if (await result.requiresApproval()) { const pending = await result.getPendingToolCalls(); for (const call of pending) { console.log(`Tool: ${call.name}`); console.log(`To: ${call.arguments.to}`); console.log(`Subject: ${call.arguments.subject}`); console.log(`ID: ${call.id}`); } // 5. Present to user for decision, then resume const approved = await askUserForApproval(pending); const approvedIds = approved.filter(a => a.decision === 'approve').map(a => a.id); const rejectedIds = approved.filter(a => a.decision === 'reject').map(a => a.id); // 6. Second callModel — resume with approval decisions const resumed = openrouter.callModel({ model: 'openai/gpt-4o', input: [], // No new user input needed for resumption tools: [sendEmailTool] as const, state, approveToolCalls: approvedIds, rejectToolCalls: rejectedIds, }); // 7. Get the final response const text = await resumed.getText(); console.log(text); // "I've sent the welcome email to alice@example.com." } else { // No approval needed — tool ran automatically const text = await result.getText(); console.log(text); } ``` ## Resumption Patterns ### Resuming from Approval When the state has `status: 'awaiting_approval'`, pass `approveToolCalls` and/or `rejectToolCalls` to resume: ```typescript lines theme={null} // Load existing state const loaded = await state.load(); if (loaded?.status === 'awaiting_approval') { const pending = loaded.pendingToolCalls ?? []; // Approve all pending calls const result = openrouter.callModel({ model: 'openai/gpt-4o', input: [], tools: [sendEmailTool] as const, state, approveToolCalls: pending.map(c => c.id), }); const text = await result.getText(); } ``` ### Resuming from Interruption If a conversation was interrupted (`status: 'interrupted'`), calling `callModel` with the same state resumes automatically. The SDK clears the interruption flag and continues where it left off: ```typescript lines theme={null} const loaded = await state.load(); if (loaded?.status === 'interrupted') { // Resume — the SDK picks up from the interruption point const result = openrouter.callModel({ model: 'openai/gpt-4o', input: 'Continue where you left off', tools: myTools, state, }); const text = await result.getText(); } ``` ### Multi-Run Conversations Messages accumulate automatically across `callModel` runs that share the same `StateAccessor`. Each run appends its input and response to the state's message history: ```typescript expandable lines theme={null} const state: StateAccessor = createStateAccessor('conv-456'); // Turn 1 const r1 = openrouter.callModel({ model: 'openai/gpt-4o', input: 'What is the weather in Tokyo?', tools: [weatherTool] as const, state, }); console.log(await r1.getText()); // "The weather in Tokyo is 22°C and sunny." // Turn 2 — state has full history from turn 1 const r2 = openrouter.callModel({ model: 'openai/gpt-4o', input: 'And in Paris?', tools: [weatherTool] as const, state, }); console.log(await r2.getText()); // "The weather in Paris is 15°C and cloudy." // Turn 3 — state has history from both prior turns const r3 = openrouter.callModel({ model: 'openai/gpt-4o', input: 'Which city is warmer?', tools: [weatherTool] as const, state, }); console.log(await r3.getText()); // "Tokyo is warmer at 22°C compared to Paris at 15°C." ``` ## Next Steps * **[Tools](/docs/agent-sdk/call-model/tools)** - Tool definitions and the `tool()` helper * **[Stop Conditions](/docs/agent-sdk/call-model/stop-conditions)** - Control when tool execution loops terminate * **[Dynamic Parameters](/docs/agent-sdk/call-model/dynamic-parameters)** - Adjust parameters between turns * **[Examples](/docs/agent-sdk/call-model/examples/weather-tool)** - Complete tool implementations # Tools Source: https://openrouter.ai/docs/agent-sdk/call-model/tools Create type-safe tools with Zod schemas and automatic execution. Supports regular tools, generator tools with progress, manual tools, human-in-the-loop tools, and automatic multi-turn execution. ## The tool() Helper The `tool()` function creates type-safe tools with Zod schema validation: ```typescript expandable lines theme={null} import { OpenRouter, tool } from '@openrouter/agent'; import { z } from 'zod'; const weatherTool = tool({ name: 'get_weather', description: 'Get the current weather for a location', inputSchema: z.object({ location: z.string().describe('City name, e.g., "San Francisco, CA"'), }), outputSchema: z.object({ temperature: z.number(), conditions: z.string(), }), execute: async (params) => { // params is typed as { location: string } const weather = await fetchWeather(params.location); return { temperature: weather.temp, conditions: weather.description, }; }, }); ``` ## Tool Types The SDK supports four types of tools, automatically detected from your configuration: ### Regular Tools Standard tools with an execute function: ```typescript lines theme={null} const calculatorTool = tool({ name: 'calculate', description: 'Perform a mathematical calculation', inputSchema: z.object({ expression: z.string().describe('Math expression like "2 + 2"'), }), outputSchema: z.object({ result: z.number(), }), execute: async (params) => { const result = eval(params.expression); // Use a safer eval in production return { result }; }, }); ``` ### Generator Tools Tools that yield progress updates during execution. Add `eventSchema` to enable generator mode: ```typescript expandable lines theme={null} const searchTool = tool({ name: 'search_database', description: 'Search documents with progress updates', inputSchema: z.object({ query: z.string(), limit: z.number().default(10), }), // eventSchema triggers generator mode eventSchema: z.object({ progress: z.number().min(0).max(100), message: z.string(), }), outputSchema: z.object({ results: z.array(z.string()), totalFound: z.number(), }), // execute is now an async generator execute: async function* (params) { yield { progress: 0, message: 'Starting search...' }; const results = []; for (let i = 0; i < 5; i++) { yield { progress: (i + 1) * 20, message: `Searching batch ${i + 1}...` }; results.push(...await searchBatch(params.query, i)); } // Final yield is the output yield { progress: 100, message: 'Complete!' }; // Return the final result (or yield it as last value) return { results: results.slice(0, params.limit), totalFound: results.length, }; }, }); ``` Progress events are streamed to consumers via `getToolStream()` and `getFullResponsesStream()`. ### Manual Tools Tools without automatic execution - you handle the tool calls yourself: ```typescript lines theme={null} const manualTool = tool({ name: 'send_email', description: 'Send an email (requires user confirmation)', inputSchema: z.object({ to: z.string().email(), subject: z.string(), body: z.string(), }), execute: false, // Manual handling required }); ``` Use `getToolCalls()` to retrieve manual tool calls for processing. ### Human-in-the-Loop (HITL) Tools HITL tools extend manual-tool semantics with two sync-or-async hooks that let you decide per call whether to respond programmatically or pause for a human: * `onToolCalled` — fires when the model invokes the tool. Return a value to feed the model directly (like a regular `execute`), or return `null` to pause the loop like a manual tool. The caller resumes later by supplying a `function_call_output` item. * `onResponseReceived` — optional. Fires on a later turn when an incoming `function_call_output` matches a prior call of this tool (by `callId → function_call.name`). It receives the caller-supplied raw result and returns the value sent to the model. Throwing surfaces as a tool error to the model. An `outputSchema` is required for HITL tools — it validates both the `onToolCalled` return value (when non-null) and the value delivered via `function_call_output` (whether transformed by `onResponseReceived` or passed through directly). ```typescript expandable lines theme={null} const approvePaymentTool = tool({ name: 'approve_payment', description: 'Approve a payment, escalating large amounts to a human', inputSchema: z.object({ amount: z.number(), recipient: z.string(), }), outputSchema: z.object({ ok: z.boolean(), reviewedAt: z.number().optional(), }), onToolCalled: async (input) => { // Auto-approve small amounts if (input.amount < 100) { return { ok: true }; } // Escalate to a human — pauses the loop return null; }, onResponseReceived: async (raw) => { // Post-process the caller-supplied result before the model sees it return { ...(raw as object), reviewedAt: Date.now() }; }, }); ``` When `onToolCalled` returns `null`, the conversation state moves to `status: 'awaiting_hitl'` and the paused call surfaces via `getToolCalls()` / `getPendingToolCalls()`. Resume by calling `callModel` again with a `function_call_output` item for each paused call in the input. HITL tools differ from `requireApproval`: approval gates pause *before* execution for a yes/no decision, while HITL tools let `onToolCalled` run arbitrary logic first and only pause when it returns `null`. Use HITL when the decision is data-driven (e.g., amount thresholds, risk scoring); use `requireApproval` when you always want explicit human consent. See [Tool Approval & State](/docs/agent-sdk/call-model/tool-approval-state). ## Schema Definition ### Input Schema Define what parameters the tool accepts: ```typescript expandable lines theme={null} const inputSchema = z.object({ // Required parameters query: z.string().describe('Search query'), // Optional with default limit: z.number().default(10).describe('Max results'), // Optional without default filter: z.string().optional().describe('Filter expression'), // Enum values sortBy: z.enum(['relevance', 'date', 'popularity']).default('relevance'), // Nested objects options: z.object({ caseSensitive: z.boolean().default(false), wholeWord: z.boolean().default(false), }).optional(), // Arrays tags: z.array(z.string()).optional(), }); ``` ### Output Schema Define the structure of results returned to the model: ```typescript lines theme={null} const outputSchema = z.object({ results: z.array(z.object({ id: z.string(), title: z.string(), score: z.number(), })), metadata: z.object({ totalCount: z.number(), searchTimeMs: z.number(), }), }); ``` ### Event Schema (Generator Tools) Define progress/status events for generator tools: ```typescript lines theme={null} const eventSchema = z.object({ stage: z.enum(['initializing', 'processing', 'finalizing']), progress: z.number(), currentItem: z.string().optional(), }); ``` ## Type Inference The SDK provides utilities to extract types from tools: ```typescript lines theme={null} import type { InferToolInput, InferToolOutput, InferToolEvent } from '@openrouter/agent'; // Get the input type type WeatherInput = InferToolInput; // { location: string } // Get the output type type WeatherOutput = InferToolOutput; // { temperature: number; conditions: string } // Get event type (generator tools only) type SearchEvent = InferToolEvent; // { progress: number; message: string } ``` ## Using Tools with callModel ### Single Tool ```typescript lines theme={null} const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the weather in Tokyo?', tools: [weatherTool], }); // Tools are automatically executed const text = await result.getText(); // "The weather in Tokyo is 22°C and sunny." ``` ### Multiple Tools ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Search for TypeScript tutorials and calculate 2+2', tools: [searchTool, calculatorTool], }); ``` ### Type-Safe Tool Calls with `as const` Use `as const` for full type inference on tool calls: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the weather?', tools: [weatherTool, searchTool] as const, maxToolRounds: 0, // Get tool calls without executing }); // Tool calls are typed as union of tool inputs for await (const toolCall of result.getToolCallsStream()) { if (toolCall.name === 'get_weather') { // toolCall.arguments is typed as { location: string } console.log('Weather for:', toolCall.arguments.location); } } ``` ## Execute Context Tool execute functions receive a flat context object as their second argument. It merges `TurnContext` fields with a `tools` map and a `setContext()` method: ```typescript lines theme={null} const contextAwareTool = tool({ name: 'context_tool', inputSchema: z.object({ data: z.string() }), outputSchema: z.object({ result: z.string() }), execute: async (params, context) => { // TurnContext fields are available directly console.log('Turn:', context.numberOfTurns); console.log('History:', context.turnRequest?.input); console.log('Model:', context.turnRequest?.model); return { result: `Processed on turn ${context.numberOfTurns}`, }; }, }); ``` ### Context Properties | Property | Type | Description | | ------------------ | -------------------------------------------- | ----------------------------------- | | `numberOfTurns` | `number` | Current turn number (1-indexed) | | `turnRequest` | `OpenResponsesRequest \| undefined` | Current request object | | `toolCall` | `OpenResponsesFunctionToolCall \| undefined` | The tool call being executed | | `local` | `Readonly` | This tool's own context (read-only) | | `setContext` | `(partial: Partial) => void` | Mutate this tool's context | | `shared` | `Readonly` | Shared context visible to all tools | | `setSharedContext` | `(partial: Partial) => void` | Mutate shared context | ## Tool Context Tools can declare a `contextSchema` to receive typed, persistent context data from the caller. Context is keyed by tool name and persists across turns. ### Declaring contextSchema ```typescript expandable lines theme={null} const weatherTool = tool({ name: 'get_weather', description: 'Get weather for a location', inputSchema: z.object({ location: z.string(), }), outputSchema: z.object({ temperature: z.number(), }), // Declare what context this tool needs contextSchema: z.object({ apiKey: z.string(), units: z.enum(['celsius', 'fahrenheit']), }), execute: async (params, context) => { // Access this tool's own context via local const { apiKey, units } = context.local; const weather = await fetchWeather( params.location, apiKey, units, ); return { temperature: weather.temp }; }, }); ``` ### Providing Context in callModel Pass context keyed by tool name: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the weather in Tokyo?', tools: [weatherTool, dbTool] as const, // Static context — keyed by tool name context: { get_weather: { apiKey: 'sk-...', units: 'celsius' }, db_query: { connectionString: 'postgres://...' }, }, }); ``` ### Dynamic Context Use an async function for one-time initialization that needs to fetch data: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the weather?', tools: [weatherTool] as const, // Resolved once at turn 0 to seed the store context: async () => ({ get_weather: { apiKey: await fetchApiKey(), units: 'celsius', }, }), }); ``` `resolveContext` runs once at turn 0 to seed the context store. For per-turn mutations, use `setContext()` inside your tool's `execute` function. ### Mutating Context with setContext Tools can update their own context using `setContext()`. Changes persist across turns via the shared store and are visible immediately — `context.local` is a live getter that always reads the latest values: ```typescript expandable lines theme={null} const authTool = tool({ name: 'auth', inputSchema: z.object({ action: z.string() }), contextSchema: z.object({ token: z.string(), refreshCount: z.number(), }), execute: async (params, context) => { const { token } = context.local; if (isExpired(token)) { const newToken = await refreshToken(token); // Mutate own context — persists to next turn context.setContext({ token: newToken, refreshCount: context.local.refreshCount + 1, }); } return { success: true }; }, }); ``` ### Observing Context Changes Use `getContextUpdates()` on `ModelResult` to observe context mutations in real time: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Authenticate and fetch data', tools: [authTool] as const, context: { auth: { token: 'initial', refreshCount: 0 }, }, }); for await (const snapshot of result.getContextUpdates()) { console.log('Context changed:', snapshot); // { auth: { token: 'new-token', refreshCount: 1 } } } ``` ### Shared Context Use `sharedSchema` on `tool()` and `sharedContextSchema` on `callModel` to share typed state across tools: ```typescript expandable lines theme={null} const SharedContextSchema = z.object({ _sessionId: z.string().optional(), }); const execTool = tool({ name: 'sandbox_exec', inputSchema: z.object({ command: z.string() }), sharedSchema: SharedContextSchema, execute: async (input, ctx) => { // Read shared state set by any tool const sid = ctx.shared._sessionId; const session = await connect(sid); // Write shared state for other tools ctx.setSharedContext({ _sessionId: session.id }); return await session.exec(input.command); }, }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Run a command', tools: [execTool] as const, sharedContextSchema: SharedContextSchema, context: { shared: { _sessionId: 'existing-session' }, sandbox_exec: {}, }, }); ``` `context.local` is scoped to one tool. `context.shared` is visible to all tools and persists across turns. Pass the same `sharedSchema` to each tool for typed access, and `sharedContextSchema` to `callModel` for runtime validation. ## Tool Execution callModel automatically executes tools and handles multi-turn conversations. When the model calls a tool, the SDK executes it, sends the result back, and continues until the model provides a final response. ### Automatic Execution Flow When you provide tools with execute functions: ```typescript expandable lines theme={null} import { OpenRouter, tool } from '@openrouter/agent'; import { z } from 'zod'; const weatherTool = tool({ name: 'get_weather', inputSchema: z.object({ location: z.string() }), outputSchema: z.object({ temperature: z.number() }), execute: async ({ location }) => { return { temperature: await fetchTemperature(location) }; }, }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the weather in Paris?', tools: [weatherTool], }); // getText() waits for all tool execution to complete const text = await result.getText(); // "The weather in Paris is 18°C." ``` ### Execution Sequence 1. Model receives prompt and generates tool call 2. SDK extracts tool call and validates arguments 3. Tool's execute function runs 4. Result is formatted and sent back to model 5. Model generates final response (or more tool calls) 6. Process repeats until model is done ### Controlling Execution Rounds #### maxToolRounds (Number) Limit the maximum number of tool execution rounds: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Research this topic thoroughly', tools: [searchTool, analyzeTool], maxToolRounds: 3, // Stop after 3 rounds of tool execution }); ``` Setting `maxToolRounds: 0` disables automatic execution - you get raw tool calls. #### maxToolRounds (Function) Use a function for dynamic control: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Research and analyze', tools: [searchTool], maxToolRounds: (context) => { // Continue if under 5 turns return context.numberOfTurns < 5; }, }); ``` The function receives `TurnContext` and returns `true` to continue or `false` to stop. ### Accessing Tool Calls #### getToolCalls() Get all tool calls from the initial response (before auto-execution): ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is the weather in Tokyo and Paris?', tools: [weatherTool], maxToolRounds: 0, // Don't auto-execute }); const toolCalls = await result.getToolCalls(); for (const call of toolCalls) { console.log(`Tool: ${call.name}`); console.log(`ID: ${call.id}`); console.log(`Arguments:`, call.arguments); } ``` #### getToolCallsStream() Stream tool calls as they complete: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Check weather in multiple cities', tools: [weatherTool], maxToolRounds: 0, }); for await (const toolCall of result.getToolCallsStream()) { console.log(`Received tool call: ${toolCall.name}`); // Process each tool call as it arrives const weatherResult = await processWeatherRequest(toolCall.arguments); console.log('Result:', weatherResult); } ``` ### Tool Stream Events #### getToolStream() Stream both argument deltas and preliminary results: ```typescript expandable lines theme={null} const searchTool = tool({ name: 'search', inputSchema: z.object({ query: z.string() }), eventSchema: z.object({ progress: z.number(), status: z.string() }), outputSchema: z.object({ results: z.array(z.string()) }), execute: async function* ({ query }) { yield { progress: 25, status: 'Searching...' }; yield { progress: 50, status: 'Processing...' }; yield { progress: 75, status: 'Ranking...' }; yield { progress: 100, status: 'Complete' }; return { results: ['result1', 'result2'] }; }, }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Search for TypeScript tutorials', tools: [searchTool], }); for await (const event of result.getToolStream()) { switch (event.type) { case 'delta': // Raw argument delta from the model process.stdout.write(event.content); break; case 'preliminary_result': // Progress from generator tool console.log(`Progress: ${event.result.progress}% - ${event.result.status}`); break; } } ``` #### Event Types | Type | Description | | -------------------- | ---------------------------------------------------------- | | `delta` | Raw tool call argument chunks from model | | `preliminary_result` | Progress events from generator tools (intermediate yields) | ### Tool Result Events When using `getFullResponsesStream()`, you can also receive `tool.result` events that fire when a tool execution completes: ```typescript lines theme={null} for await (const event of result.getFullResponsesStream()) { switch (event.type) { case 'tool.preliminary_result': // Intermediate progress from generator tools console.log(`Progress (${event.toolCallId}):`, event.result); break; case 'tool.result': // Final result when tool execution completes console.log(`Tool ${event.toolCallId} completed`); console.log('Result:', event.result); // Access any preliminary results that were emitted during execution if (event.preliminaryResults) { console.log('All progress events:', event.preliminaryResults); } break; } } ``` #### ToolResultEvent Type ```typescript lines theme={null} type ToolResultEvent = { type: 'tool.result'; toolCallId: string; result: TResult; timestamp: number; preliminaryResults?: TPreliminaryResults[]; }; ``` The `tool.result` event provides the final output from tool execution along with all intermediate `preliminaryResults` that were yielded during execution (for generator tools). This is useful when you need both real-time progress updates and a summary of all progress at completion. ### Parallel Tool Execution When the model calls multiple tools, they execute in parallel: ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Get weather in Paris, Tokyo, and New York simultaneously', tools: [weatherTool], }); // All three weather calls execute in parallel const text = await result.getText(); ``` ### Manual Tool Handling For tools without execute functions: ```typescript expandable lines theme={null} const confirmTool = tool({ name: 'send_email', description: 'Send an email (requires confirmation)', inputSchema: z.object({ to: z.string().email(), subject: z.string(), body: z.string(), }), execute: false, // Manual handling }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Send an email to alice@example.com', tools: [confirmTool], maxToolRounds: 0, }); const toolCalls = await result.getToolCalls(); for (const call of toolCalls) { if (call.name === 'send_email') { // Show confirmation UI const confirmed = await showConfirmDialog(call.arguments); if (confirmed) { await sendEmail(call.arguments); } } } ``` ### Execution Results Access execution metadata through getResponse(): ```typescript lines theme={null} const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'What is 2+2 and the weather in Paris?', tools: [calculatorTool, weatherTool], }); const response = await result.getResponse(); // Response includes all execution rounds console.log('Final output:', response.output); console.log('Usage:', response.usage); ``` ## Error Handling ### Tool Execution Errors Errors in execute functions are caught and sent back to the model: ```typescript expandable lines theme={null} const riskyTool = tool({ name: 'risky_operation', inputSchema: z.object({ input: z.string() }), outputSchema: z.object({ result: z.string() }), execute: async (params) => { if (params.input === 'fail') { throw new Error('Operation failed: invalid input'); } return { result: 'success' }; }, }); const result = openrouter.callModel({ model: 'openai/gpt-5-nano', input: 'Try the risky operation with "fail"', tools: [riskyTool], }); // Model receives error message and can respond appropriately const text = await result.getText(); // "I tried the operation but it failed with: Operation failed: invalid input" ``` ### Validation Errors Invalid tool arguments are caught before execution: ```typescript lines theme={null} const strictTool = tool({ name: 'strict', inputSchema: z.object({ email: z.string().email(), age: z.number().min(0).max(150), }), execute: async (params) => { // Only runs with valid input return { valid: true }; }, }); ``` ### Graceful Error Handling Handle errors gracefully in execute functions: ```typescript lines theme={null} const robustTool = tool({ name: 'fetch_data', inputSchema: z.object({ url: z.string().url() }), outputSchema: z.object({ data: z.unknown().optional(), error: z.string().optional(), }), execute: async (params) => { try { const response = await fetch(params.url); if (!response.ok) { return { error: `HTTP ${response.status}: ${response.statusText}` }; } return { data: await response.json() }; } catch (error) { return { error: `Failed to fetch: ${error.message}` }; } }, }); ``` ## Best Practices ### Descriptive Names and Descriptions ```typescript lines theme={null} // Good: Clear name and description const tool1 = tool({ name: 'search_knowledge_base', description: 'Search the company knowledge base for documents, FAQs, and policies. Returns relevant articles with snippets.', // ... }); // Avoid: Vague or generic const tool2 = tool({ name: 'search', description: 'Searches stuff', // ... }); ``` ### Schema Descriptions Add `.describe()` to help the model understand parameters: ```typescript lines theme={null} const inputSchema = z.object({ query: z.string().describe('Natural language search query'), maxResults: z.number() .min(1) .max(100) .default(10) .describe('Maximum number of results to return (1-100)'), dateRange: z.enum(['day', 'week', 'month', 'year', 'all']) .default('all') .describe('Filter results by time period'), }); ``` ### Idempotent Tools Design tools to be safely re-executable: ```typescript lines theme={null} const createUserTool = tool({ name: 'create_user', inputSchema: z.object({ email: z.string().email(), name: z.string(), }), execute: async (params) => { // Check if user exists first const existing = await findUserByEmail(params.email); if (existing) { return { userId: existing.id, created: false }; } const user = await createUser(params); return { userId: user.id, created: true }; }, }); ``` ### Timeout Handling Wrap long-running operations: ```typescript lines theme={null} const longRunningTool = tool({ name: 'process_data', inputSchema: z.object({ dataId: z.string() }), execute: async (params) => { const timeoutMs = 30000; const result = await Promise.race([ processData(params.dataId), new Promise((_, reject) => setTimeout(() => reject(new Error('Operation timed out')), timeoutMs) ), ]); return result; }, }); ``` ## Next Steps * **[Tool Approval & State](/docs/agent-sdk/call-model/tool-approval-state)** - Human-in-the-loop approval and conversation persistence * **[nextTurnParams](/docs/agent-sdk/call-model/next-turn-params)** - Tool-driven context injection * **[Stop Conditions](/docs/agent-sdk/call-model/stop-conditions)** - Advanced execution control * **[Examples](/docs/agent-sdk/call-model/examples/weather-tool)** - Complete tool implementations # DevTools Source: https://openrouter.ai/docs/agent-sdk/dev-tools/devtools SDK Development Tools for telemetry capture and visualization The DevTools SDK and CLI are currently in pre-release status. DevTools is designed for development use only and should never be deployed in production environments. The OpenRouter DevTools provide a comprehensive solution for SDK telemetry capture and visualization during development. Monitor your AI application's requests, responses, token usage, and errors in real-time with a beautiful web interface. ## Why use DevTools? Building with AI SDKs requires visibility into what's happening under the hood. The OpenRouter DevTools give you complete insight into your SDK operations without adding complexity or impacting performance. **Two main components:** 1. **SDK Telemetry Hooks** - Automatically capture all SDK operations in development 2. **DevTools Viewer** - Beautiful web UI for visualizing captured telemetry data ## Key Features ### SDK DevTools Viewer Launch a web-based interface to visualize your SDK telemetry: * **Real-time run tracking** - View all SDK operations (chat, embeddings, etc.) as they happen * **Detailed step analysis** - Inspect request/response data, timing, and errors for each step * **Token usage insights** - Track prompt and completion tokens across all requests * **Error debugging** - Easily identify and debug failed requests with full error details * **Multi-run comparison** - Compare different SDK runs side-by-side * **Dark/Light mode** - Full theme support with automatic system preference detection ### SDK Telemetry Hooks Developer-friendly hooks that automatically capture: * All chat completions with full request/response data * Token usage and costs * Timing information for performance analysis * Errors and failure modes * Tool/function calls * Current directory, git branch, and model information ## Installation Install the DevTools package as a development dependency: ```bash title="npm" lines theme={null} npm install --save-dev @openrouter/devtools ``` ```bash title="pnpm" lines theme={null} pnpm add -D @openrouter/devtools ``` ```bash title="yarn" lines theme={null} yarn add -D @openrouter/devtools ``` ```bash title="bun" lines theme={null} bun add -d @openrouter/devtools ``` ```bash title="deno" lines theme={null} deno add --dev npm:@openrouter/devtools ``` **Important:** DevTools is designed for development only. It will throw an error if `NODE_ENV === 'production'` to prevent accidental production deployment. ## Quick Start - SDK Hooks Integrate DevTools hooks into your SDK client to start capturing telemetry: ### Basic Usage ```typescript lines theme={null} import { createOpenRouterDevtools } from '@openrouter/devtools'; import { OpenRouter } from '@openrouter/sdk'; const sdk = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, hooks: createOpenRouterDevtools() }); // Now all SDK operations are automatically captured const response = await sdk.chat.send({ model: "openai/gpt-5", messages: [ { role: "user", content: "Explain quantum computing" } ] }); ``` ### Custom Configuration ```typescript lines theme={null} const sdk = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, hooks: createOpenRouterDevtools({ storagePath: '.custom-path/generations.json', // Default: '.devtools/openrouter-generations.json' serverUrl: 'http://localhost:5000/api/notify', // Default: 'http://localhost:4983/api/notify' }) }); ``` ## Quick Start - DevTools Viewer Launch the DevTools web interface to visualize captured telemetry: ```bash lines theme={null} openrouter devtools ``` This starts a local server on port 4983 and opens your browser to view: * All SDK runs with timestamps and status * Step-by-step request/response details * Token usage and costs * Error messages and stack traces * Performance timing information The viewer automatically refreshes when new telemetry data is captured. ## How It Works ### Telemetry Capture Flow 1. SDK hooks intercept requests before they're sent 2. Telemetry data is captured asynchronously (non-blocking) 3. Data is stored in `.devtools/openrouter-generations.json` 4. A notification is sent to the local DevTools server (if running) 5. The DevTools viewer updates in real-time ### Non-Intrusive Design * **Zero SDK impact** - Telemetry capture is async and never blocks SDK operations * **Graceful degradation** - Errors in DevTools never break your SDK calls * **Development-only** - Throws error if used in production (`NODE_ENV === 'production'`) ### Storage Location By default, telemetry is stored in: ```lines theme={null} .devtools/openrouter-generations.json ``` This file contains: * **Runs** - Top-level tracking of SDK operations * **Steps** - Individual request/response pairs within each run * **Metadata** - Timestamps, status, token usage, errors ## Configuration Options ### Hook Configuration When calling `createOpenRouterDevtools()`, you can customize: | Option | Type | Default | Description | | ------------- | -------- | ----------------------------------------- | ------------------------------------- | | `storagePath` | `string` | `'.devtools/openrouter-generations.json'` | Where to store captured telemetry | | `serverUrl` | `string` | `'http://localhost:4983/api/notify'` | DevTools server notification endpoint | ### DevTools Server Configuration The DevTools viewer runs on port 4983 by default. This can be configured in your OpenRouter CLI configuration at `~/.openrouter/claude-code-proxy.json`: ```json lines theme={null} { "DEVTOOLS_PORT": 4983 } ``` ## Operations Captured The DevTools hooks automatically capture these SDK operations: * `chat.send()` - Chat completions API calls * `chat.createResponses()` - Responses API calls * `embeddings.create()` - Embeddings API calls All other SDK operations are currently ignored. ## Data Captured Per Step For each SDK operation, DevTools captures: **Request Data:** * Model name * Messages/prompts * Parameters (temperature, max\_tokens, etc.) **Response Data:** * Generated content * Token usage (prompt + completion tokens) * Provider and model used * Finish reason * Tool calls (if any) **Metadata:** * Start and completion timestamps * Duration in milliseconds * Status (success, error, in\_progress) * Error details (if failed) ## Safety & Best Practices ### Production Environment Protection DevTools will throw an error if initialized when `NODE_ENV === 'production'`: ```typescript lines theme={null} // This will throw an error in production const sdk = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, hooks: createOpenRouterDevtools() // ERROR in production! }); ``` ### Non-Blocking Architecture * All telemetry capture happens asynchronously * DevTools errors never propagate to your SDK calls * Failed writes are logged but don't break your application ### Error Handling DevTools failures are handled gracefully: ```typescript lines theme={null} // If DevTools fails, your SDK call still works try { await sdk.chat.send({ /* ... */ }); // SDK call succeeds even if DevTools capture fails } catch (error) { // Only SDK errors are thrown, never DevTools errors } ``` ## Troubleshooting ### Port Already in Use If port 4983 is already in use: ```bash lines theme={null} Error: listen EADDRINUSE: address already in use :::4983 ``` **Solution:** Either stop the process using port 4983, or configure a different port in `~/.openrouter/claude-code-proxy.json`: ```json lines theme={null} { "DEVTOOLS_PORT": 5000 } ``` Then update your hook configuration: ```typescript lines theme={null} hooks: createOpenRouterDevtools({ serverUrl: 'http://localhost:5000/api/notify' }) ``` ### Storage Location Issues If you can't find the telemetry file: 1. Check the default location: `.devtools/openrouter-generations.json` 2. Ensure you have write permissions in your working directory 3. Check for custom `storagePath` configuration ### DevTools Viewer Not Updating If the viewer doesn't show new requests: 1. Verify the DevTools server is running (`openrouter devtools`) 2. Check that `serverUrl` matches the DevTools server port 3. Ensure the telemetry file is being written (check `.devtools/` directory) 4. Try refreshing the browser manually ### Common Setup Issues **Issue:** DevTools package not found ```bash lines theme={null} Cannot find module '@openrouter/devtools' ``` **Solution:** Install the package: ```bash title="npm" lines theme={null} npm install --save-dev @openrouter/devtools ``` ```bash title="pnpm" lines theme={null} pnpm add -D @openrouter/devtools ``` ```bash title="yarn" lines theme={null} yarn add -D @openrouter/devtools ``` ```bash title="bun" lines theme={null} bun add -d @openrouter/devtools ``` ```bash title="deno" lines theme={null} deno add --dev npm:@openrouter/devtools ``` *** **Issue:** Accidental production usage ```bash lines theme={null} Error: DevTools should not be used in production ``` **Solution:** Only initialize DevTools in development: ```typescript lines theme={null} const hooks = process.env.NODE_ENV === 'development' ? createOpenRouterDevtools() : undefined; const sdk = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, hooks }); ``` # Agent SDK Source: https://openrouter.ai/docs/agent-sdk/overview Build AI agents with multi-turn loops, tools, and conversation state The Agent SDK (`@openrouter/agent`) provides the primitives you need to build agentic applications on OpenRouter. Instead of manually wiring up conversation loops, tool dispatch, and state tracking, the Agent SDK handles all of that so you can focus on defining *what* your agent does. The Agent SDK is built to work alongside the [Client SDKs](/docs/client-sdks/overview). Installing `@openrouter/agent` automatically includes the Client SDKs as well, but each package can work independently. ## When to use the Agent SDK Choose the Agent SDK when you need **agentic behavior** — multi-step reasoning where the model calls tools, processes results, and decides what to do next: * **Multi-turn agent loops** — `callModel` automatically loops until a stop condition is met * **Tool definitions** — define tools with the `tool()` helper and the SDK executes them for you * **Stop conditions** — control when the loop ends with `stepCountIs`, `hasToolCall`, `maxCost`, and more * **Conversation state** — the SDK tracks messages, tool results, and context across turns * **Streaming** — real-time token output within each agent step * **Dynamic parameters** — change model, temperature, or tools between turns based on context If you only need simple request/response calls to a model without agent loops, the [Client SDKs](/docs/client-sdks/overview) are a lighter-weight option. ## Installation ```bash title="npm" lines theme={null} npm install @openrouter/agent ``` ```bash title="pnpm" lines theme={null} pnpm add @openrouter/agent ``` ```bash title="yarn" lines theme={null} yarn add @openrouter/agent ``` ```bash title="bun" lines theme={null} bun add @openrouter/agent ``` ```bash title="deno" lines theme={null} deno add npm:@openrouter/agent ``` ## Quick example ```typescript expandable lines theme={null} import { OpenRouter, tool } from '@openrouter/agent'; import { z } from 'zod'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const weatherTool = tool({ name: 'get_weather', description: 'Get the current weather for a location', inputSchema: z.object({ location: z.string().describe('City name'), }), execute: async ({ location }) => { return { temperature: 72, condition: 'sunny', location }; }, }); const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4', messages: [ { role: 'user', content: 'What is the weather in San Francisco?' }, ], tools: [weatherTool], }); const text = await result.getText(); console.log(text); ``` The SDK sends the message to the model, receives a tool call, executes `get_weather`, feeds the result back, and returns the final response — all in one `callModel` invocation. ## Core concepts ### `callModel` The main entry point. It runs an inference loop that: 1. Sends messages to the model 2. If the model returns tool calls, executes them automatically 3. Appends tool results to the conversation 4. Repeats until a stop condition is met or no more tool calls are made See the [Call Model documentation](/docs/agent-sdk/call-model) for the full API. ### Tools Define tools with the `tool()` helper. Each tool has a name, description, Zod parameter schema, and an `execute` function. The SDK handles serialization, validation, and dispatch. ```typescript lines theme={null} import { tool } from '@openrouter/agent'; import { z } from 'zod'; const searchTool = tool({ name: 'search', description: 'Search the web', inputSchema: z.object({ query: z.string() }), execute: async ({ query }) => { // Your search implementation return { results: ['...'] }; }, }); ``` ### Stop conditions Control when the agent loop terminates: ```typescript lines theme={null} import { OpenRouter, stepCountIs, maxCost } from '@openrouter/agent'; const openrouter = new OpenRouter({ apiKey: process.env.OPENROUTER_API_KEY, }); const result = openrouter.callModel({ model: 'anthropic/claude-sonnet-4', messages: [{ role: 'user', content: 'Research this topic thoroughly' }], tools: [searchTool], stopWhen: [stepCountIs(10), maxCost(0.50)], }); ``` ## Agent SDK vs Client SDKs | | Agent SDK | Client SDKs | | ---------------------- | ------------------------------------------------------------------- | ------------------------------------------------------------- | | **Focus** | Agentic primitives — multi-turn loops, tools, stop conditions | Lean API client — mirrors the REST API with full type safety | | **Use when** | You want built-in agent loops, tool execution, and state management | You want direct model calls and manage orchestration yourself | | **Conversation state** | Managed for you via `callModel` | You manage it | | **Tool execution** | Automatic with the `tool()` helper | You dispatch tool calls | | **Languages** | TypeScript | TypeScript, Python, Go | ## Next steps * [Call Model](/docs/agent-sdk/call-model) — the complete `callModel` API reference * [Tools](/docs/agent-sdk/call-model/tools) — defining and using tools * [Stop Conditions](/docs/agent-sdk/call-model/stop-conditions) — controlling agent loop termination * [Streaming](/docs/agent-sdk/call-model/streaming) — real-time token output * [DevTools](/docs/agent-sdk/dev-tools/devtools) — telemetry capture and visualization for development * [Migrating from @openrouter/sdk](/docs/agent-sdk/agent-migration) — move agent imports to the standalone package # Analytics - TypeScript SDK Source: https://openrouter.ai/docs/agent-sdk/typescript/api-reference/analytics Analytics method reference The TypeScript SDK and docs are currently in beta. Report issues on [GitHub](https://github.com/OpenRouterTeam/typescript-sdk/issues). ## Overview Analytics and usage endpoints ### Available Operations * [getUserActivity](#getuseractivity) - Get user activity grouped by endpoint ## getUserActivity Returns user activity data grouped by endpoint for the last 30 (completed) UTC days. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.analytics.getUserActivity(); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { analyticsGetUserActivity } from "@openrouter/sdk/funcs/analyticsGetUserActivity.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await analyticsGetUserActivity(openRouter); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("analyticsGetUserActivity failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.GetUserActivityRequest](/docs/agent-sdk/typescript/api-reference/operations/getuseractivityrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.ActivityResponse](/docs/agent-sdk/typescript/api-reference/models/activityresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.ForbiddenResponseError | 403 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | # APIKeys - TypeScript SDK Source: https://openrouter.ai/docs/agent-sdk/typescript/api-reference/apikeys APIKeys method reference The TypeScript SDK and docs are currently in beta. Report issues on [GitHub](https://github.com/OpenRouterTeam/typescript-sdk/issues). ## Overview API key management endpoints ### Available Operations * [getCurrentKeyMetadata](#getcurrentkeymetadata) - Get current API key * [list](#list) - List API keys * [create](#create) - Create a new API key * [delete](#delete) - Delete an API key * [get](#get) - Get a single API key * [update](#update) - Update an API key ## getCurrentKeyMetadata Get information on the API key associated with the current authentication session ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.apiKeys.getCurrentKeyMetadata(); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { apiKeysGetCurrentKeyMetadata } from "@openrouter/sdk/funcs/apiKeysGetCurrentKeyMetadata.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await apiKeysGetCurrentKeyMetadata(openRouter); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("apiKeysGetCurrentKeyMetadata failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.GetCurrentKeyRequest](/docs/agent-sdk/typescript/api-reference/operations/getcurrentkeyrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.GetCurrentKeyResponse](/docs/agent-sdk/typescript/api-reference/operations/getcurrentkeyresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## list List all API keys for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.apiKeys.list(); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { apiKeysList } from "@openrouter/sdk/funcs/apiKeysList.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await apiKeysList(openRouter); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("apiKeysList failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | --------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListRequest](/docs/agent-sdk/typescript/api-reference/operations/listrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.ListResponse](/docs/agent-sdk/typescript/api-reference/operations/listresponse)>** ### Errors | Error Type | Status Code | Content Type | | ----------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## create Create a new API key for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.apiKeys.create({ requestBody: { expiresAt: new Date("2027-12-31T23:59:59Z"), includeByokInLimit: true, limit: 50, limitReset: "monthly", name: "My New API Key", }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { apiKeysCreate } from "@openrouter/sdk/funcs/apiKeysCreate.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await apiKeysCreate(openRouter, { requestBody: { expiresAt: new Date("2027-12-31T23:59:59Z"), includeByokInLimit: true, limit: 50, limitReset: "monthly", name: "My New API Key", }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("apiKeysCreate failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.CreateKeysRequest](/docs/agent-sdk/typescript/api-reference/operations/createkeysrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.CreateKeysResponse](/docs/agent-sdk/typescript/api-reference/operations/createkeysresponse)>** ### Errors | Error Type | Status Code | Content Type | | ----------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.ForbiddenResponseError | 403 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## delete Delete an existing API key. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.apiKeys.delete({ hash: "f01d52606dc8f0a8303a7b5cc3fa07109c2e346cec7c0a16b40de462992ce943", }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { apiKeysDelete } from "@openrouter/sdk/funcs/apiKeysDelete.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await apiKeysDelete(openRouter, { hash: "f01d52606dc8f0a8303a7b5cc3fa07109c2e346cec7c0a16b40de462992ce943", }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("apiKeysDelete failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.DeleteKeysRequest](/docs/agent-sdk/typescript/api-reference/operations/deletekeysrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.DeleteKeysResponse](/docs/agent-sdk/typescript/api-reference/operations/deletekeysresponse)>** ### Errors | Error Type | Status Code | Content Type | | ----------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## get Get a single API key by hash. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.apiKeys.get({ hash: "f01d52606dc8f0a8303a7b5cc3fa07109c2e346cec7c0a16b40de462992ce943", }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { apiKeysGet } from "@openrouter/sdk/funcs/apiKeysGet.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await apiKeysGet(openRouter, { hash: "f01d52606dc8f0a8303a7b5cc3fa07109c2e346cec7c0a16b40de462992ce943", }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("apiKeysGet failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.GetKeyRequest](/docs/agent-sdk/typescript/api-reference/operations/getkeyrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.GetKeyResponse](/docs/agent-sdk/typescript/api-reference/operations/getkeyresponse)>** ### Errors | Error Type | Status Code | Content Type | | ----------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## update Update an existing API key. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.apiKeys.update({ hash: "f01d52606dc8f0a8303a7b5cc3fa07109c2e346cec7c0a16b40de462992ce943", requestBody: { disabled: false, includeByokInLimit: true, limit: 75, limitReset: "daily", name: "Updated API Key Name", }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { apiKeysUpdate } from "@openrouter/sdk/funcs/apiKeysUpdate.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await apiKeysUpdate(openRouter, { hash: "f01d52606dc8f0a8303a7b5cc3fa07109c2e346cec7c0a16b40de462992ce943", requestBody: { disabled: false, includeByokInLimit: true, limit: 75, limitReset: "daily", name: "Updated API Key Name", }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("apiKeysUpdate failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.UpdateKeysRequest](/docs/agent-sdk/typescript/api-reference/operations/updatekeysrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.UpdateKeysResponse](/docs/agent-sdk/typescript/api-reference/operations/updatekeysresponse)>** ### Errors | Error Type | Status Code | Content Type | | ----------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | # Chat - TypeScript SDK Source: https://openrouter.ai/docs/agent-sdk/typescript/api-reference/chat Chat method reference The TypeScript SDK and docs are currently in beta. Report issues on [GitHub](https://github.com/OpenRouterTeam/typescript-sdk/issues). ## Overview ### Available Operations * [send](#send) - Create a chat completion ## send Sends a request for a model response for the given chat conversation. Supports both streaming and non-streaming modes. ### Example Usage: guardrail-blocked ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.chat.send({ chatRequest: { messages: [ { content: "You are a helpful assistant.", role: "system", }, { content: "What is the capital of France?", role: "user", }, ], }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { chatSend } from "@openrouter/sdk/funcs/chatSend.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await chatSend(openRouter, { chatRequest: { messages: [ { content: "You are a helpful assistant.", role: "system", }, { content: "What is the capital of France?", role: "user", }, ], }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("chatSend failed:", res.error); } } run(); ``` ### Example Usage: insufficient-permissions ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.chat.send({ chatRequest: { messages: [ { content: "You are a helpful assistant.", role: "system", }, { content: "What is the capital of France?", role: "user", }, ], }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { chatSend } from "@openrouter/sdk/funcs/chatSend.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await chatSend(openRouter, { chatRequest: { messages: [ { content: "You are a helpful assistant.", role: "system", }, { content: "What is the capital of France?", role: "user", }, ], }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("chatSend failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.SendChatCompletionRequestRequest](/docs/agent-sdk/typescript/api-reference/operations/sendchatcompletionrequestrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.SendChatCompletionRequestResponse](/docs/agent-sdk/typescript/api-reference/operations/sendchatcompletionrequestresponse)>** ### Errors | Error Type | Status Code | Content Type | | --------------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.PaymentRequiredResponseError | 402 | application/json | | errors.ForbiddenResponseError | 403 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.RequestTimeoutResponseError | 408 | application/json | | errors.PayloadTooLargeResponseError | 413 | application/json | | errors.UnprocessableEntityResponseError | 422 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.BadGatewayResponseError | 502 | application/json | | errors.ServiceUnavailableResponseError | 503 | application/json | | errors.EdgeNetworkTimeoutResponseError | 524 | application/json | | errors.ProviderOverloadedResponseError | 529 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | # Credits - TypeScript SDK Source: https://openrouter.ai/docs/agent-sdk/typescript/api-reference/credits Credits method reference The TypeScript SDK and docs are currently in beta. Report issues on [GitHub](https://github.com/OpenRouterTeam/typescript-sdk/issues). ## Overview Credit management endpoints ### Available Operations * [getCredits](#getcredits) - Get remaining credits ## getCredits Get total credits purchased and used for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.credits.getCredits(); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { creditsGetCredits } from "@openrouter/sdk/funcs/creditsGetCredits.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await creditsGetCredits(openRouter); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("creditsGetCredits failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.GetCreditsRequest](/docs/agent-sdk/typescript/api-reference/operations/getcreditsrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.GetCreditsResponse](/docs/agent-sdk/typescript/api-reference/operations/getcreditsresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.ForbiddenResponseError | 403 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | # Embeddings - TypeScript SDK Source: https://openrouter.ai/docs/agent-sdk/typescript/api-reference/embeddings Embeddings method reference The TypeScript SDK and docs are currently in beta. Report issues on [GitHub](https://github.com/OpenRouterTeam/typescript-sdk/issues). ## Overview Text embedding endpoints ### Available Operations * [generate](#generate) - Submit an embedding request * [listModels](#listmodels) - List all embeddings models ## generate Submits an embedding request to the embeddings router ### Example Usage ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.embeddings.generate({ requestBody: { input: "The quick brown fox jumps over the lazy dog", model: "openai/text-embedding-3-small", }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { embeddingsGenerate } from "@openrouter/sdk/funcs/embeddingsGenerate.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await embeddingsGenerate(openRouter, { requestBody: { input: "The quick brown fox jumps over the lazy dog", model: "openai/text-embedding-3-small", }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("embeddingsGenerate failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.CreateEmbeddingsRequest](/docs/agent-sdk/typescript/api-reference/operations/createembeddingsrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.CreateEmbeddingsResponse](/docs/agent-sdk/typescript/api-reference/operations/createembeddingsresponse)>** ### Errors | Error Type | Status Code | Content Type | | -------------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.PaymentRequiredResponseError | 402 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.BadGatewayResponseError | 502 | application/json | | errors.ServiceUnavailableResponseError | 503 | application/json | | errors.EdgeNetworkTimeoutResponseError | 524 | application/json | | errors.ProviderOverloadedResponseError | 529 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## listModels Returns a list of all available embeddings models and their properties ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.embeddings.listModels(); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { embeddingsListModels } from "@openrouter/sdk/funcs/embeddingsListModels.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await embeddingsListModels(openRouter); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("embeddingsListModels failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | -------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListEmbeddingsModelsRequest](/docs/agent-sdk/typescript/api-reference/operations/listembeddingsmodelsrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.ModelsListResponse](/docs/agent-sdk/typescript/api-reference/models/modelslistresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | # Endpoints - TypeScript SDK Source: https://openrouter.ai/docs/agent-sdk/typescript/api-reference/endpoints Endpoints method reference The TypeScript SDK and docs are currently in beta. Report issues on [GitHub](https://github.com/OpenRouterTeam/typescript-sdk/issues). ## Overview Endpoint information ### Available Operations * [listZdrEndpoints](#listzdrendpoints) - Preview the impact of ZDR on the available endpoints * [list](#list) - List all endpoints for a model ## listZdrEndpoints Preview the impact of ZDR on the available endpoints ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.endpoints.listZdrEndpoints(); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { endpointsListZdrEndpoints } from "@openrouter/sdk/funcs/endpointsListZdrEndpoints.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await endpointsListZdrEndpoints(openRouter); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("endpointsListZdrEndpoints failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListEndpointsZdrRequest](/docs/agent-sdk/typescript/api-reference/operations/listendpointszdrrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.ListEndpointsZdrResponse](/docs/agent-sdk/typescript/api-reference/operations/listendpointszdrresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## list List all endpoints for a model ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.endpoints.list({ author: "", slug: "", }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { endpointsList } from "@openrouter/sdk/funcs/endpointsList.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await endpointsList(openRouter, { author: "", slug: "", }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("endpointsList failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListEndpointsRequest](/docs/agent-sdk/typescript/api-reference/operations/listendpointsrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.ListEndpointsResponse](/docs/agent-sdk/typescript/api-reference/operations/listendpointsresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | # Generations - TypeScript SDK Source: https://openrouter.ai/docs/agent-sdk/typescript/api-reference/generations Generations method reference The TypeScript SDK and docs are currently in beta. Report issues on [GitHub](https://github.com/OpenRouterTeam/typescript-sdk/issues). ## Overview Generation history endpoints ### Available Operations * [getGeneration](#getgeneration) - Get request & usage metadata for a generation * [listGenerationContent](#listgenerationcontent) - Get stored prompt and completion content for a generation ## getGeneration Get request & usage metadata for a generation ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.generations.getGeneration({ id: "", }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { generationsGetGeneration } from "@openrouter/sdk/funcs/generationsGetGeneration.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await generationsGetGeneration(openRouter, { id: "", }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("generationsGetGeneration failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.GetGenerationRequest](/docs/agent-sdk/typescript/api-reference/operations/getgenerationrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.GenerationResponse](/docs/agent-sdk/typescript/api-reference/models/generationresponse)>** ### Errors | Error Type | Status Code | Content Type | | -------------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.PaymentRequiredResponseError | 402 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.BadGatewayResponseError | 502 | application/json | | errors.EdgeNetworkTimeoutResponseError | 524 | application/json | | errors.ProviderOverloadedResponseError | 529 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## listGenerationContent Get stored prompt and completion content for a generation ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.generations.listGenerationContent({ id: "gen-1234567890", }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { generationsListGenerationContent } from "@openrouter/sdk/funcs/generationsListGenerationContent.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await generationsListGenerationContent(openRouter, { id: "gen-1234567890", }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("generationsListGenerationContent failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListGenerationContentRequest](/docs/agent-sdk/typescript/api-reference/operations/listgenerationcontentrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.GenerationContentResponse](/docs/agent-sdk/typescript/api-reference/models/generationcontentresponse)>** ### Errors | Error Type | Status Code | Content Type | | -------------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.ForbiddenResponseError | 403 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.TooManyRequestsResponseError | 429 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.BadGatewayResponseError | 502 | application/json | | errors.EdgeNetworkTimeoutResponseError | 524 | application/json | | errors.ProviderOverloadedResponseError | 529 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | # Guardrails - TypeScript SDK Source: https://openrouter.ai/docs/agent-sdk/typescript/api-reference/guardrails Guardrails method reference The TypeScript SDK and docs are currently in beta. Report issues on [GitHub](https://github.com/OpenRouterTeam/typescript-sdk/issues). ## Overview Guardrails endpoints ### Available Operations * [list](#list) - List guardrails * [create](#create) - Create a guardrail * [delete](#delete) - Delete a guardrail * [get](#get) - Get a guardrail * [update](#update) - Update a guardrail * [listGuardrailKeyAssignments](#listguardrailkeyassignments) - List key assignments for a guardrail * [bulkAssignKeys](#bulkassignkeys) - Bulk assign keys to a guardrail * [bulkUnassignKeys](#bulkunassignkeys) - Bulk unassign keys from a guardrail * [listGuardrailMemberAssignments](#listguardrailmemberassignments) - List member assignments for a guardrail * [bulkAssignMembers](#bulkassignmembers) - Bulk assign members to a guardrail * [bulkUnassignMembers](#bulkunassignmembers) - Bulk unassign members from a guardrail * [listKeyAssignments](#listkeyassignments) - List all key assignments * [listMemberAssignments](#listmemberassignments) - List all member assignments ## list List all guardrails for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.list(); for await (const page of result) { console.log(page); } } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsList } from "@openrouter/sdk/funcs/guardrailsList.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsList(openRouter); if (res.ok) { const { value: result } = res; for await (const page of result) { console.log(page); } } else { console.log("guardrailsList failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | -------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListGuardrailsRequest](/docs/agent-sdk/typescript/api-reference/operations/listguardrailsrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.ListGuardrailsResponse](/docs/agent-sdk/typescript/api-reference/operations/listguardrailsresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## create Create a new guardrail for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.create({ createGuardrailRequest: { allowedModels: null, allowedProviders: [ "openai", "anthropic", "deepseek", ], description: "A guardrail for limiting API usage", enforceZdrAnthropic: true, enforceZdrGoogle: false, enforceZdrOpenai: true, enforceZdrOther: false, ignoredModels: null, ignoredProviders: null, limitUsd: 50, name: "My New Guardrail", resetInterval: "monthly", }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsCreate } from "@openrouter/sdk/funcs/guardrailsCreate.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsCreate(openRouter, { createGuardrailRequest: { allowedModels: null, allowedProviders: [ "openai", "anthropic", "deepseek", ], description: "A guardrail for limiting API usage", enforceZdrAnthropic: true, enforceZdrGoogle: false, enforceZdrOpenai: true, enforceZdrOther: false, ignoredModels: null, ignoredProviders: null, limitUsd: 50, name: "My New Guardrail", resetInterval: "monthly", }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("guardrailsCreate failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.CreateGuardrailRequest](/docs/agent-sdk/typescript/api-reference/operations/createguardrailrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.CreateGuardrailResponse](/docs/agent-sdk/typescript/api-reference/models/createguardrailresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.ForbiddenResponseError | 403 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## delete Delete an existing guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.delete({ id: "550e8400-e29b-41d4-a716-446655440000", }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsDelete } from "@openrouter/sdk/funcs/guardrailsDelete.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsDelete(openRouter, { id: "550e8400-e29b-41d4-a716-446655440000", }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("guardrailsDelete failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.DeleteGuardrailRequest](/docs/agent-sdk/typescript/api-reference/operations/deleteguardrailrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.DeleteGuardrailResponse](/docs/agent-sdk/typescript/api-reference/models/deleteguardrailresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## get Get a single guardrail by ID. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.get({ id: "550e8400-e29b-41d4-a716-446655440000", }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsGet } from "@openrouter/sdk/funcs/guardrailsGet.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsGet(openRouter, { id: "550e8400-e29b-41d4-a716-446655440000", }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("guardrailsGet failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.GetGuardrailRequest](/docs/agent-sdk/typescript/api-reference/operations/getguardrailrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.GetGuardrailResponse](/docs/agent-sdk/typescript/api-reference/models/getguardrailresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## update Update an existing guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.update({ id: "550e8400-e29b-41d4-a716-446655440000", updateGuardrailRequest: { description: "Updated description", limitUsd: 75, name: "Updated Guardrail Name", resetInterval: "weekly", }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsUpdate } from "@openrouter/sdk/funcs/guardrailsUpdate.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsUpdate(openRouter, { id: "550e8400-e29b-41d4-a716-446655440000", updateGuardrailRequest: { description: "Updated description", limitUsd: 75, name: "Updated Guardrail Name", resetInterval: "weekly", }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("guardrailsUpdate failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.UpdateGuardrailRequest](/docs/agent-sdk/typescript/api-reference/operations/updateguardrailrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.UpdateGuardrailResponse](/docs/agent-sdk/typescript/api-reference/models/updateguardrailresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## listGuardrailKeyAssignments List all API key assignments for a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.listGuardrailKeyAssignments({ id: "550e8400-e29b-41d4-a716-446655440000", }); for await (const page of result) { console.log(page); } } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsListGuardrailKeyAssignments } from "@openrouter/sdk/funcs/guardrailsListGuardrailKeyAssignments.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsListGuardrailKeyAssignments(openRouter, { id: "550e8400-e29b-41d4-a716-446655440000", }); if (res.ok) { const { value: result } = res; for await (const page of result) { console.log(page); } } else { console.log("guardrailsListGuardrailKeyAssignments failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListGuardrailKeyAssignmentsRequest](/docs/agent-sdk/typescript/api-reference/operations/listguardrailkeyassignmentsrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.ListGuardrailKeyAssignmentsResponse](/docs/agent-sdk/typescript/api-reference/operations/listguardrailkeyassignmentsresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## bulkAssignKeys Assign multiple API keys to a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.bulkAssignKeys({ id: "550e8400-e29b-41d4-a716-446655440000", bulkAssignKeysRequest: { keyHashes: [ "c56454edb818d6b14bc0d61c46025f1450b0f4012d12304ab40aacb519fcbc93", ], }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsBulkAssignKeys } from "@openrouter/sdk/funcs/guardrailsBulkAssignKeys.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsBulkAssignKeys(openRouter, { id: "550e8400-e29b-41d4-a716-446655440000", bulkAssignKeysRequest: { keyHashes: [ "c56454edb818d6b14bc0d61c46025f1450b0f4012d12304ab40aacb519fcbc93", ], }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("guardrailsBulkAssignKeys failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.BulkAssignKeysToGuardrailRequest](/docs/agent-sdk/typescript/api-reference/operations/bulkassignkeystoguardrailrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.BulkAssignKeysResponse](/docs/agent-sdk/typescript/api-reference/models/bulkassignkeysresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## bulkUnassignKeys Unassign multiple API keys from a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.bulkUnassignKeys({ id: "550e8400-e29b-41d4-a716-446655440000", bulkUnassignKeysRequest: { keyHashes: [ "c56454edb818d6b14bc0d61c46025f1450b0f4012d12304ab40aacb519fcbc93", ], }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsBulkUnassignKeys } from "@openrouter/sdk/funcs/guardrailsBulkUnassignKeys.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsBulkUnassignKeys(openRouter, { id: "550e8400-e29b-41d4-a716-446655440000", bulkUnassignKeysRequest: { keyHashes: [ "c56454edb818d6b14bc0d61c46025f1450b0f4012d12304ab40aacb519fcbc93", ], }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("guardrailsBulkUnassignKeys failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.BulkUnassignKeysFromGuardrailRequest](/docs/agent-sdk/typescript/api-reference/operations/bulkunassignkeysfromguardrailrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.BulkUnassignKeysResponse](/docs/agent-sdk/typescript/api-reference/models/bulkunassignkeysresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## listGuardrailMemberAssignments List all organization member assignments for a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.listGuardrailMemberAssignments({ id: "550e8400-e29b-41d4-a716-446655440000", }); for await (const page of result) { console.log(page); } } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsListGuardrailMemberAssignments } from "@openrouter/sdk/funcs/guardrailsListGuardrailMemberAssignments.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsListGuardrailMemberAssignments(openRouter, { id: "550e8400-e29b-41d4-a716-446655440000", }); if (res.ok) { const { value: result } = res; for await (const page of result) { console.log(page); } } else { console.log("guardrailsListGuardrailMemberAssignments failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListGuardrailMemberAssignmentsRequest](/docs/agent-sdk/typescript/api-reference/operations/listguardrailmemberassignmentsrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.ListGuardrailMemberAssignmentsResponse](/docs/agent-sdk/typescript/api-reference/operations/listguardrailmemberassignmentsresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## bulkAssignMembers Assign multiple organization members to a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.bulkAssignMembers({ id: "550e8400-e29b-41d4-a716-446655440000", bulkAssignMembersRequest: { memberUserIds: [ "user_abc123", "user_def456", ], }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsBulkAssignMembers } from "@openrouter/sdk/funcs/guardrailsBulkAssignMembers.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsBulkAssignMembers(openRouter, { id: "550e8400-e29b-41d4-a716-446655440000", bulkAssignMembersRequest: { memberUserIds: [ "user_abc123", "user_def456", ], }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("guardrailsBulkAssignMembers failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.BulkAssignMembersToGuardrailRequest](/docs/agent-sdk/typescript/api-reference/operations/bulkassignmemberstoguardrailrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.BulkAssignMembersResponse](/docs/agent-sdk/typescript/api-reference/models/bulkassignmembersresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## bulkUnassignMembers Unassign multiple organization members from a specific guardrail. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript expandable lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.bulkUnassignMembers({ id: "550e8400-e29b-41d4-a716-446655440000", bulkUnassignMembersRequest: { memberUserIds: [ "user_abc123", "user_def456", ], }, }); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsBulkUnassignMembers } from "@openrouter/sdk/funcs/guardrailsBulkUnassignMembers.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsBulkUnassignMembers(openRouter, { id: "550e8400-e29b-41d4-a716-446655440000", bulkUnassignMembersRequest: { memberUserIds: [ "user_abc123", "user_def456", ], }, }); if (res.ok) { const { value: result } = res; console.log(result); } else { console.log("guardrailsBulkUnassignMembers failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.BulkUnassignMembersFromGuardrailRequest](/docs/agent-sdk/typescript/api-reference/operations/bulkunassignmembersfromguardrailrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[models.BulkUnassignMembersResponse](/docs/agent-sdk/typescript/api-reference/models/bulkunassignmembersresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.BadRequestResponseError | 400 | application/json | | errors.UnauthorizedResponseError | 401 | application/json | | errors.NotFoundResponseError | 404 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## listKeyAssignments List all API key guardrail assignments for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.listKeyAssignments(); for await (const page of result) { console.log(page); } } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsListKeyAssignments } from "@openrouter/sdk/funcs/guardrailsListKeyAssignments.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsListKeyAssignments(openRouter); if (res.ok) { const { value: result } = res; for await (const page of result) { console.log(page); } } else { console.log("guardrailsListKeyAssignments failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListKeyAssignmentsRequest](/docs/agent-sdk/typescript/api-reference/operations/listkeyassignmentsrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.ListKeyAssignmentsResponse](/docs/agent-sdk/typescript/api-reference/operations/listkeyassignmentsresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | ## listMemberAssignments List all organization member guardrail assignments for the authenticated user. [Management key](/docs/guides/overview/auth/management-api-keys) required. ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.guardrails.listMemberAssignments(); for await (const page of result) { console.log(page); } } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { guardrailsListMemberAssignments } from "@openrouter/sdk/funcs/guardrailsListMemberAssignments.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const res = await guardrailsListMemberAssignments(openRouter); if (res.ok) { const { value: result } = res; for await (const page of result) { console.log(page); } } else { console.log("guardrailsListMemberAssignments failed:", res.error); } } run(); ``` ### Parameters | Parameter | Type | Required | Description | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `request` | [operations.ListMemberAssignmentsRequest](/docs/agent-sdk/typescript/api-reference/operations/listmemberassignmentsrequest) | :heavy\_check\_mark: | The request object to use for the request. | | `options` | RequestOptions | :heavy\_minus\_sign: | Used to set various options for making HTTP requests. | | `options.fetchOptions` | [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/Request/Request#options) | :heavy\_minus\_sign: | Options that are passed to the underlying HTTP request. This can be used to inject extra headers for examples. All `Request` options, except `method` and `body`, are allowed. | | `options.retries` | [RetryConfig](/docs/agent-sdk/typescript/api-reference/lib/retryconfig) | :heavy\_minus\_sign: | Enables retrying HTTP requests under certain failure conditions. | ### Response **Promise\<[operations.ListMemberAssignmentsResponse](/docs/agent-sdk/typescript/api-reference/operations/listmemberassignmentsresponse)>** ### Errors | Error Type | Status Code | Content Type | | ---------------------------------- | ----------- | ---------------- | | errors.UnauthorizedResponseError | 401 | application/json | | errors.InternalServerResponseError | 500 | application/json | | errors.OpenRouterDefaultError | 4XX, 5XX | \*/\* | # Models - TypeScript SDK Source: https://openrouter.ai/docs/agent-sdk/typescript/api-reference/models Models method reference The TypeScript SDK and docs are currently in beta. Report issues on [GitHub](https://github.com/OpenRouterTeam/typescript-sdk/issues). ## Overview Model information endpoints ### Available Operations * [list](#list) - List all models and their properties * [count](#count) - Get total count of available models * [listForUser](#listforuser) - List models filtered by user provider preferences, privacy settings, and guardrails ## list List all models and their properties ### Example Usage ```typescript lines theme={null} import { OpenRouter } from "@openrouter/sdk"; const openRouter = new OpenRouter({ httpReferer: "", appTitle: "", appCategories: "", apiKey: process.env["OPENROUTER_API_KEY"] ?? "", }); async function run() { const result = await openRouter.models.list(); console.log(result); } run(); ``` ### Standalone function The standalone function version of this method: ```typescript expandable lines theme={null} import { OpenRouterCore } from "@openrouter/sdk/core.js"; import { modelsList } from "@openrouter/sdk/funcs/modelsList.js"; // Use `OpenRouterCore` for best tree-shaking performance. // You can create one instance of it to use across an application. const openRouter = new OpenRouterCore({ httpReferer: "
{text}