
openrouter-kit
Powerful & flexible TypeScript SDK for the OpenRouter API. Streamlines building LLM applications with easy chat, adapter-based history, secure tool calling (function calling), cost tracking, and plugin support.
Stars: 59

README:
π·πΊ Π ΡΡΡΠΊΠΈΠΉ | π¬π§ English
OpenRouter Kit is a powerful, flexible, and user-friendly TypeScript/JavaScript library for interacting with the OpenRouter API. It significantly simplifies working with LLMs by providing a high-level API for chats, automatic dialogue history management (when an adapter is configured), seamless handling of tool calls (function calling) with structured error handling, a robust and configurable security module, and optional request cost tracking. It's ideal for building chatbots, AI agents, and integrating LLMs into your applications.
-
Simplicity: Complex API interactions, history management, and tool handling are hidden behind a simple
client.chat()
method. - Flexibility: Configure models, generation parameters, history storage (requires adapter), security, and much more.
- Security: The built-in security module helps protect your applications and users when using tools.
- Extensibility: Use plugins and middleware to add custom logic without modifying the library core.
- Reliability: Fully typed with TypeScript, predictable error handling (including structured tool errors), and resource management.
- π Key Features
- π¦ Installation
- β¨ Basic Usage
- π Example: Taxi Bot
- βοΈ API and Concepts
- π License
-
π€ Universal Chat: Simple and powerful API (
client.chat
) for interacting with any model available via OpenRouter.- Returns a structured
ChatCompletionResult
object with content (content
), token usage info (usage
), model used (model
), number of tool calls (toolCallsCount
), finish reason (finishReason
), execution time (durationMs
), request ID (id
), and calculated cost (cost
, optional).
- Returns a structured
-
π History Management (via Adapters): Requires
historyAdapter
configuration. Automatic loading, saving, and (potentially) trimming of dialogue history for each user or group whenuser
is passed toclient.chat()
.- Flexible history system based on adapters (
IHistoryStorage
). - Includes built-in adapters for memory (
MemoryHistoryStorage
) and disk (DiskHistoryStorage
, JSON files). Exported from the main module. - Easily plug in custom adapters (Redis, MongoDB, API, etc.) or use the provided plugin (
createRedisHistoryPlugin
). - Configure cache TTL and cleanup intervals via client options (
historyTtl
,historyCleanupInterval
). History limit management is delegated to the adapter.
- Flexible history system based on adapters (
-
π οΈ Tool Handling (Function Calling): Seamless integration for model-invoked calls to your functions.
- Define tools using the
Tool
interface and JSON Schema for argument validation. - Automatic argument parsing, schema validation, and security checks.
- Execution of your
execute
functions with context (ToolContext
, includinguserInfo
). - Automatic sending of results back to the model to get the final response.
-
Structured Tool Error Handling: Errors occurring during parsing, validation, security checks, or tool execution are formatted as a JSON string (
{"errorType": "...", "errorMessage": "...", "details": ...}
) and sent back to the model in therole: 'tool'
message, potentially allowing the LLM to understand and react to the issue better. - Configurable limit on the maximum number of tool call rounds (
maxToolCalls
) to prevent infinite loops.
- Define tools using the
-
π‘οΈ Security Module: Comprehensive and configurable protection for your applications.
-
Authentication: Built-in JWT support (generation, validation, caching) via
AuthManager
. Easily extensible for other methods (api-key
,custom
). -
Access Control (ACL): Flexible configuration of tool access (
AccessControlManager
) based on roles (roles
), API keys (allowedApiKeys
), permissions (scopes
), or explicit rules (allow
/deny
). Default policy (deny-all
/allow-all
). -
Rate Limiting: Apply limits (
RateLimitManager
) on tool calls for users or roles with configurable periods and limits. Important: The defaultRateLimitManager
implementation stores state in memory and is not suitable for distributed systems (multiple processes/servers). Custom adapters or plugins using external storage (e.g., Redis) are required for such scenarios. -
Argument Sanitization: Checks (
ArgumentSanitizer
) tool arguments for potentially dangerous patterns (SQLi, XSS, command injection, etc.) using global, tool-specific, and custom rules. Supports audit-only mode (auditOnlyMode
). -
Event System: Subscribe to security events (
access:denied
,ratelimit:exceeded
,security:dangerous_args
,token:invalid
,user:authenticated
, etc.) for monitoring and logging.
-
Authentication: Built-in JWT support (generation, validation, caching) via
-
π Cost Tracking: (Optional)
- Automatic calculation of approximate cost for each
chat()
call based on token usage (usage
) and OpenRouter model pricing. - Periodic background updates of model prices from the OpenRouter API (
/models
). -
getCreditBalance()
method to check your current OpenRouter credit balance. - Access cached prices via
getModelPrices()
.
- Automatic calculation of approximate cost for each
-
βοΈ Flexible Configuration: Configure API key, default model, endpoint (
apiEndpoint
for chat, base URL for other requests determined automatically), timeouts, proxy, headers (Referer
,X-Title
), fallback models (modelFallbacks
), response format (responseFormat
), tool call limit (maxToolCalls
), cost tracking (enableCostTracking
), history adapter (historyAdapter
), and many other parameters viaOpenRouterConfig
. - π‘ Typing: Fully written in TypeScript, providing strong typing, autocompletion, and type checking during development.
-
π¦ Error Handling: Clear hierarchy of custom errors (
APIError
,ValidationError
,SecurityError
,RateLimitError
,ToolError
,ConfigError
, etc.) inheriting fromOpenRouterError
, with codes (ErrorCode
) and details for easy handling. Includes amapError
function for normalizing errors. -
π Logging: Built-in flexible logger (
Logger
) with prefix support and debug mode (debug
). - β¨ Ease of Use: High-level API hiding the complexity of underlying interactions with LLMs, history, and tools.
-
π§Ή Resource Management:
client.destroy()
method for proper resource cleanup (timers, caches, event listeners), preventing leaks in long-running applications. -
𧩠Plugin System: Extend client capabilities without modifying the core.
- Support for external and custom plugins via
client.use(plugin)
. - Plugins can add middleware, replace managers (history, security, cost), subscribe to events, and extend the client API.
- Support for external and custom plugins via
-
π Middleware Chain: Flexible request and response processing before and after API calls.
- Add middleware functions via
client.useMiddleware(fn)
. - Middleware can modify requests (
ctx.request
), responses (ctx.response
), implement auditing, access control, logging, cost limiting, caching, and more.
- Add middleware functions via
npm install openrouter-kit
# or
yarn add openrouter-kit
# or
pnpm add openrouter-kit
TypeScript:
import { OpenRouterClient, MemoryHistoryStorage } from 'openrouter-kit'; // Import directly
const client = new OpenRouterClient({
apiKey: process.env.OPENROUTER_API_KEY || 'sk-or-v1-...',
// !!! IMPORTANT: Provide an adapter to enable history !!!
historyAdapter: new MemoryHistoryStorage(), // Use the imported class
enableCostTracking: true,
debug: false,
});
async function main() {
try {
console.log('Sending request...');
const result = await client.chat({
prompt: 'Say hi to the world!',
model: 'google/gemini-2.0-flash-001',
user: 'test-user-1', // User ID for history tracking
});
console.log('--- Result ---');
console.log('Model Response:', result.content);
console.log('Token Usage:', result.usage);
console.log('Model Used:', result.model);
console.log('Tool Calls Count:', result.toolCallsCount);
console.log('Finish Reason:', result.finishReason);
console.log('Duration (ms):', result.durationMs);
if (result.cost !== null) {
console.log('Estimated Cost (USD):', result.cost.toFixed(8));
}
console.log('Request ID:', result.id);
console.log('\nChecking balance...');
const balance = await client.getCreditBalance();
console.log(`Credit Balance: Used $${balance.usage.toFixed(4)} of $${balance.limit.toFixed(2)}`);
// Get history (will work since historyAdapter was provided)
const historyManager = client.getHistoryManager();
if (historyManager) {
// Key is generated internally by the client, but showing format for example
const historyKey = `user:test-user-1`;
const history = await historyManager.getHistory(historyKey);
console.log(`\nMessages stored in history for ${historyKey}: ${history.length}`);
}
} catch (error: any) {
console.error(`\n--- Error ---`);
console.error(`Message: ${error.message}`);
if (error.code) console.error(`Error Code: ${error.code}`);
if (error.statusCode) console.error(`HTTP Status: ${error.statusCode}`);
if (error.details) console.error(`Details:`, error.details);
// console.error(error.stack);
} finally {
console.log('\nShutting down and releasing resources...');
await client.destroy();
console.log('Resources released.');
}
}
main();
JavaScript (CommonJS):
const { OpenRouterClient, MemoryHistoryStorage } = require("openrouter-kit"); // Destructure from main export
const client = new OpenRouterClient({
apiKey: process.env.OPENROUTER_API_KEY || 'sk-or-v1-...',
// !!! IMPORTANT: Provide an adapter to enable history !!!
historyAdapter: new MemoryHistoryStorage(), // Use the imported class
enableCostTracking: true,
});
async function main() {
try {
const result = await client.chat({
prompt: 'Hello, world!',
user: 'commonjs-user' // Specify user for history saving
});
console.log('Model Response:', result.content);
console.log('Usage:', result.usage);
console.log('Cost:', result.cost);
// Get history
const historyManager = client.getHistoryManager();
if (historyManager) {
// Key is generated internally, showing format for example
const historyKey = 'user:commonjs-user';
const history = await historyManager.getHistory(historyKey);
console.log(`\nHistory for '${historyKey}': ${history.length} messages`);
}
} catch (error) {
console.error(`Error: ${error.message}`, error.details || error);
} finally {
await client.destroy();
}
}
main();
This example demonstrates using dialogue history and tool calling. Note the required historyAdapter
and the corresponding require
.
// taxi-bot.js (CommonJS)
const { OpenRouterClient, MemoryHistoryStorage } = require("openrouter-kit"); // Destructure
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
// Example proxy config (if needed)
// const proxyConfig = {
// host: "",
// port: "",
// user: "",
// pass: "",
// };
const client = new OpenRouterClient({
apiKey: process.env.OPENROUTER_API_KEY || "sk-or-v1-...", // Replace!
model: "google/gemini-2.0-flash-001",
// !!! IMPORTANT: Provide an adapter to enable history !!!
historyAdapter: new MemoryHistoryStorage(), // Use imported class
// proxy: proxyConfig,
enableCostTracking: true,
debug: false, // Set true for verbose logs
// security: { /* ... */ } // Security config can be added here
});
let orderAccepted = false;
// --- Tool Definitions ---
const taxiTools = [
{
type: "function",
function: {
name: "estimateRideCost",
description: "Estimates the cost of a taxi ride between two addresses.",
parameters: {
type: "object",
properties: {
from: { type: "string", description: "Pickup address (e.g., '1 Lenin St, Moscow')" },
to: { type: "string", description: "Destination address (e.g., '10 Tverskaya St, Moscow')" }
},
required: ["from", "to"]
},
},
// Executable function for the tool
execute: async (args) => {
console.log(`[Tool estimateRideCost] Calculating cost from ${args.from} to ${args.to}...`);
// Simulate cost calculation
const cost = Math.floor(Math.random() * 900) + 100;
console.log(`[Tool estimateRideCost] Calculated cost: ${cost} RUB`);
// Return an object to be serialized to JSON
return { estimatedCost: cost, currency: "RUB" };
}
},
{
type: "function",
function: {
name: "acceptOrder",
description: "Accepts and confirms a taxi order, assigns a driver.",
parameters: {
type: "object",
properties: {
from: { type: "string", description: "Confirmed pickup address" },
to: { type: "string", description: "Confirmed destination address" },
estimatedCost: { type: "number", description: "Approximate ride cost (if known)"}
},
required: ["from", "to"]
},
},
// Executable function with context access
execute: async (args, context) => {
console.log(`[Tool acceptOrder] Accepting order from ${args.from} to ${args.to}...`);
// Example of using context (if security is configured)
console.log(`[Tool acceptOrder] Order initiated by user: ${context?.userInfo?.userId || 'anonymous'}`);
// Simulate driver assignment
const driverNumber = Math.floor(Math.random() * 100) + 1;
orderAccepted = true; // Set flag to end the loop
// Return a string for the model to relay to the user
return `Order successfully accepted! Driver #${driverNumber} has been assigned and will arrive shortly at ${args.from}. Destination: ${args.to}.`;
}
}
];
function askQuestion(query) {
return new Promise((resolve) => {
readline.question(query, (answer) => {
resolve(answer);
});
});
}
const systemPrompt = `You are a friendly and efficient taxi service operator named "Kit". Your task is to help the customer book a taxi.
1. Clarify the pickup address ('from') and destination address ('to') if the customer hasn't provided them. Be polite.
2. Once the addresses are known, you MUST use the 'estimateRideCost' tool to inform the customer of the approximate cost.
3. Wait for the customer to confirm they accept the cost and are ready to order (e.g., with words like "book it", "okay", "yes", "sounds good").
4. After customer confirmation, use the 'acceptOrder' tool, passing it the 'from' and 'to' addresses.
5. After calling 'acceptOrder', inform the customer of the result returned by the tool.
6. Do not invent driver numbers or order statuses yourself; rely on the response from the 'acceptOrder' tool.
7. If the user asks something unrelated to booking a taxi, politely steer the conversation back to the topic.`;
async function chatWithTaxiBot() {
const userId = `taxi-user-${Date.now()}`;
console.log(`\nKit Bot: Hello! I'm your virtual assistant... (Session ID: ${userId})`);
try {
while (!orderAccepted) {
const userMessage = await askQuestion("You: ");
if (userMessage.toLowerCase() === 'exit' || userMessage.toLowerCase() === 'quit') {
console.log("Kit Bot: Thank you for contacting us! Goodbye.");
break;
}
console.log("Kit Bot: One moment, processing your request...");
// Pass user: userId, history will be managed automatically
// because historyAdapter was provided
const result = await client.chat({
user: userId, // Key for history
prompt: userMessage,
systemPrompt: systemPrompt,
tools: taxiTools, // Provide available tools
temperature: 0.5,
maxToolCalls: 5 // Limit tool call cycles
});
// Output the assistant's final response
console.log(`\nKit Bot: ${result.content}\n`);
// Output debug info if enabled
if (client.isDebugMode()) {
console.log(`[Debug] Model: ${result.model}, Tool Calls: ${result.toolCallsCount}, Cost: ${result.cost !== null ? '$' + result.cost.toFixed(8) : 'N/A'}, Reason: ${result.finishReason}`);
}
// Check the flag set by the acceptOrder tool
if (orderAccepted) {
console.log("Kit Bot: If you have any more questions, I'm here to help!");
// Optionally break here if the conversation should end after ordering
}
}
} catch (error) {
console.error("\n--- An Error Occurred ---");
// Use instanceof to check error type
if (error instanceof Error) {
console.error(`Type: ${error.constructor.name}`);
console.error(`Message: ${error.message}`);
// Access custom fields via 'any' or type assertion
if ((error as any).code) console.error(`Code: ${(error as any).code}`);
if ((error as any).statusCode) console.error(`Status: ${(error as any).statusCode}`);
if ((error as any).details) console.error(`Details:`, (error as any).details);
} else {
console.error("Unknown error:", error);
}
} finally {
readline.close();
await client.destroy(); // Release resources
console.log("\nClient stopped. Session ended.");
}
}
chatWithTaxiBot();
The main class for interacting with the library.
An object passed when creating the client (new OpenRouterClient(config)
). Key fields:
-
apiKey
(string, required): Your OpenRouter API key. -
apiEndpoint?
(string): Override the chat completions API endpoint URL (default:https://openrouter.ai/api/v1/chat/completions
). -
model?
(string): Default model identifier for requests. -
debug?
(boolean): Enable detailed logging (default:false
). -
proxy?
(string | object): HTTP/HTTPS proxy settings. -
referer?
(string): Value for theHTTP-Referer
header. -
title?
(string): Value for theX-Title
header. -
axiosConfig?
(object): Additional configuration passed directly to Axios. -
historyAdapter?
(IHistoryStorage): Required for history management. An instance of a history storage adapter (e.g.,new MemoryHistoryStorage()
). -
historyTtl?
(number): Time-to-live (TTL) for entries in theUnifiedHistoryManager
cache (milliseconds). -
historyCleanupInterval?
(number): Interval for cleaning expired entries from theUnifiedHistoryManager
cache (milliseconds). -
providerPreferences?
(object): Settings specific to OpenRouter model providers. -
modelFallbacks?
(string[]): List of fallback models to try if the primary model fails. -
responseFormat?
(ResponseFormat | null): Default response format for all requests. -
maxToolCalls?
(number): Default maximum tool call cycles perchat()
invocation (default: 10). -
strictJsonParsing?
(boolean): Throw an error on invalid JSON response (if JSON format requested)? (default:false
, returnsnull
). -
security?
(SecurityConfig): Configuration for the security module (uses the baseSecurityConfig
type from./types
). -
enableCostTracking?
(boolean): Enable cost tracking (default:false
). -
priceRefreshIntervalMs?
(number): Interval for refreshing model prices (default: 6 hours). -
initialModelPrices?
(object): Provide initial model prices to avoid the first price fetch. -
Deprecated fields (ignored if
historyAdapter
is present):historyStorage
,chatsFolder
,maxHistoryEntries
,historyAutoSave
.
-
chat(options: OpenRouterRequestOptions): Promise<ChatCompletionResult>
: The primary method for sending chat requests. Takes anoptions
object (seeOpenRouterRequestOptions
intypes/index.ts
). Manages history only ifuser
is passed ANDhistoryAdapter
is configured. -
getHistoryManager(): UnifiedHistoryManager
: Returns the history manager instance (if created). -
getSecurityManager(): SecurityManager | null
: Returns the security manager instance (if configured). -
getCostTracker(): CostTracker | null
: Returns the cost tracker instance (if enabled). -
getCreditBalance(): Promise<CreditBalance>
: Fetches the OpenRouter account credit balance. -
getModelPrices(): Record<string, ModelPricingInfo>
: Returns the cached model prices. -
refreshModelPrices(): Promise<void>
: Forces a background refresh of model prices. -
createAccessToken(userInfo, expiresIn?): string
: Generates a JWT (ifsecurity.userAuthentication.type === 'jwt'
). -
use(plugin): Promise<void>
: Registers a plugin. -
useMiddleware(fn): void
: Registers middleware. -
on(event, handler)
/off(event, handler)
: Subscribe/unsubscribe from client events ('error'
) or security module events (prefixed events likesecurity:
,user:
,token:
,access:
,ratelimit:
,tool:
). -
destroy(): Promise<void>
: Releases resources (timers, listeners).
-
Plugins: Modules extending client functionality. Registered via
client.use(plugin)
. Can initialize services, replace standard managers (setSecurityManager
,setCostTracker
), add middleware. -
Middleware: Functions executed sequentially for each
client.chat()
call. Allow modification of requests (ctx.request
), responses (ctx.response
), or performing side effects (logging, auditing). Registered viaclient.useMiddleware(fn)
.
To enable automatic dialogue history management (loading, saving, trimming when user
is passed to client.chat()
), you MUST configure historyAdapter
in OpenRouterConfig
. Without it, history features will not work.
-
Adapter (
IHistoryStorage
): Defines the interface for storage (load
,save
,delete
,listKeys
,destroy?
). -
UnifiedHistoryManager
: Internal component using the adapter and managing an in-memory cache (with TTL and cleanup). -
Built-in Adapters:
-
MemoryHistoryStorage
: Stores history in RAM (default if no adapter specified). -
DiskHistoryStorage
: Stores history in JSON files on disk.
-
-
Usage:
import { OpenRouterClient, MemoryHistoryStorage, DiskHistoryStorage } from 'openrouter-kit'; // Using MemoryHistoryStorage const clientMemory = new OpenRouterClient({ /*...,*/ historyAdapter: new MemoryHistoryStorage() }); // Using DiskHistoryStorage const clientDisk = new OpenRouterClient({ /*...,*/ historyAdapter: new DiskHistoryStorage('./my-chat-histories') });
-
Redis Plugin: Use
createRedisHistoryPlugin
for easy Redis integration (requiresioredis
). -
Cache Settings:
historyTtl
,historyCleanupInterval
inOpenRouterConfig
control theUnifiedHistoryManager
's cache behavior.
Allows LLM models to invoke your JavaScript/TypeScript functions to retrieve external information, interact with other APIs, or perform real-world actions.
-
Defining a Tool (
Tool
): Define each tool as an object conforming to theTool
interface. Key fields:-
type: 'function'
(currently the only supported type). -
function
: An object describing the function for the LLM:-
name
(string): A unique name the model will use to call the function. -
description
(string, optional): A clear description of what the function does and when to use it. Crucial for the model to understand the tool's purpose. -
parameters
(object, optional): A JSON Schema object describing the structure, types, and required fields of the arguments your function expects. The library uses this schema to validate arguments received from the model. Omit if no arguments are needed.
-
-
execute: (args: any, context?: ToolContext) => Promise<any> | any
: Your async or sync function that gets executed when the model requests this tool call.-
args
: An object containing the arguments passed by the model, already parsed from the JSON string and (if a schema was provided) validated againstparameters
. -
context?
: An optionalToolContext
object containing additional call information, such as:-
userInfo?
: TheUserAuthInfo
object for the authenticated user (ifSecurityManager
is used andaccessToken
was passed). -
securityManager?
: TheSecurityManager
instance (if used).
-
-
-
security
(ToolSecurity, optional): An object defining tool-specific security rules likerequiredRole
,requiredScopes
, orrateLimit
. These are checked by theSecurityManager
beforeexecute
is called.
-
-
Using in
client.chat()
:- Pass an array of your defined tools to the
tools
option of theclient.chat()
method. - The library handles the complex interaction flow:
- Sends tool definitions (name, description, parameters schema) to the model with your prompt.
- If the model decides to call one or more tools, it returns a response with
finish_reason: 'tool_calls'
and a list oftool_calls
. - The library intercepts this response. For each requested
toolCall
:- Finds the corresponding tool in your
tools
array by name. - Parses the arguments string (
toolCall.function.arguments
) into a JavaScript object. - Validates the arguments object against the JSON Schema in
tool.function.parameters
(if provided). -
Performs security checks via
SecurityManager
(if configured): verifies user (userInfo
) access rights, applies rate limits, and checks arguments for dangerous content. - If all checks pass, calls your
tool.execute(parsedArgs, context)
function. - Waits for the result (or catches errors) from your
execute
function. -
Formats the result (or a structured error) into a JSON string and sends it back to the model in a new message with
role: 'tool'
and the correspondingtool_call_id
.
- Finds the corresponding tool in your
- The model receives the tool call results and generates the final, coherent response to the user (now with
role: 'assistant'
).
- The
maxToolCalls
option (inclient.chat()
or client config) limits the maximum number of these request-call-result cycles to prevent infinite loops if the model keeps requesting tools. - The
toolChoice
option controls the model's tool usage:'auto'
(default),'none'
(disallow calls), or force a specific function call{ type: "function", function: { name: "my_tool_name" } }
.
- Pass an array of your defined tools to the
-
Result: The final model response (after all potential tool calls) is available in
ChatCompletionResult.content
. TheChatCompletionResult.toolCallsCount
field indicates how many tools were successfully called and executed during the singleclient.chat()
invocation.
Provides multi-layered protection when using tools, crucial if tools perform actions or access data. Activated by passing a security: SecurityConfig
object to the OpenRouterClient
constructor.
Components:
-
AuthManager
: Handles user authentication. Supports JWT out-of-the-box (generation, validation, caching). UsesjwtSecret
from config. Extensible viacustomAuthenticator
. -
AccessControlManager
: Checks if the authenticated (or anonymous, if allowed) user has permission to call a specific tool based onsecurity.toolAccess
andsecurity.roles
rules. ConsidersdefaultPolicy
. -
RateLimitManager
: Tracks and enforces tool call frequency limits per user based on configuration (security.roles
,security.toolAccess
, ortool.security
). Important: Default implementation is in-memory and not suitable for distributed systems. -
ArgumentSanitizer
: Analyzes arguments passed to toolexecute
functions for potentially harmful patterns (SQLi, XSS, OS commands, etc.) using regex and blocklists defined insecurity.dangerousArguments
. Supports blocking or audit-only (auditOnlyMode
).
Configuration (SecurityConfig
):
Defines the security module's behavior in detail. Uses extended types (ExtendedSecurityConfig
, ExtendedUserAuthInfo
, etc.) exported by the library. Key fields:
-
defaultPolicy
('deny-all'
|'allow-all'
): Action if no explicit access rule matches?'deny-all'
recommended. -
requireAuthentication
(boolean): Must a validaccessToken
be present for any tool call? -
allowUnauthenticatedAccess
(boolean): IfrequireAuthentication: false
, can anonymous users call tools (if the tool itself allows it)? -
userAuthentication
(UserAuthConfig
): Authentication method setup (type: 'jwt'
,jwtSecret
,customAuthenticator
). Set a strongjwtSecret
if using JWT! -
toolAccess
(Record<string, ToolAccessConfig>
): Access rules per tool name or for all ('*'
). Includesallow
,roles
,scopes
,rateLimit
,allowedApiKeys
. -
roles
(RolesConfig
): Definitions of roles and their permissions/limits (allowedTools
,rateLimits
). -
dangerousArguments
(ExtendedDangerousArgumentsConfig
): Argument sanitization settings (globalPatterns
,toolSpecificPatterns
,blockedValues
,auditOnlyMode
).
Usage:
- Pass the
securityConfig
object to theOpenRouterClient
constructor. - For authenticated requests, pass the access token via
client.chat({ accessToken: '...' })
. - The library automatically calls
securityManager.checkToolAccessAndArgs()
before executing any tool. This performs all configured checks (auth, ACL, rate limits, args). - If any check fails, an appropriate error (
AuthorizationError
,AccessDeniedError
,RateLimitError
,SecurityError
) is thrown, and theexecute
function is not called. - Use
client.createAccessToken()
to generate JWTs (if configured). - Subscribe to security events (
client.on('access:denied', ...)
etc.) for monitoring.
Provides an approximate cost estimate for each client.chat()
call based on token usage and OpenRouter model prices.
-
Enabling: Set
enableCostTracking: true
inOpenRouterConfig
. -
Mechanism:
-
CostTracker
instance is created on client initialization. - It fetches current prices for all models from the OpenRouter API (
/models
) initially (unlessinitialModelPrices
is provided) and periodically thereafter (priceRefreshIntervalMs
, default 6 hours). - Prices (cost per million input/output tokens) are cached in memory.
- After a successful
client.chat()
call, the library gets token usage (usage
) from the API response. -
costTracker.calculateCost(model, usage)
is called, using cached prices and usage data to compute the cost. It accounts for prompt, completion, and intermediate tool call tokens. - The calculated value (USD number) or
null
(if prices are unknown or tracking is off) is added to thecost
field of the returnedChatCompletionResult
.
-
-
Related Client Methods:
-
getCreditBalance(): Promise<CreditBalance>
: Fetches current credit limit and usage from your OpenRouter account. -
getModelPrices(): Record<string, ModelPricingInfo>
: Returns the current cache of model prices used by the tracker. -
refreshModelPrices(): Promise<void>
: Manually triggers a background refresh of the model price cache. -
getCostTracker(): CostTracker | null
: Accesses theCostTracker
instance (if enabled).
-
- Accuracy: Remember this is an estimate. Actual billing might differ slightly due to rounding or price changes not yet reflected in the cache.
Instructs the model to generate its response content in JSON format, useful for structured data extraction.
-
Configuration: Set via the
responseFormat
option inOpenRouterConfig
(for a default) or in theclient.chat()
options (for a specific request). -
Types:
-
{ type: 'json_object' }
: Instructs the model to return any valid JSON object. -
{ type: 'json_schema', json_schema: { name: string, schema: object, strict?: boolean, description?: string } }
: Requires the model to return JSON conforming to the provided JSON Schema.-
name
: An arbitrary name for your schema. -
schema
: The JSON Schema object describing the expected JSON structure. -
strict
(optional): Request strict schema adherence (model-dependent). -
description
(optional): A description of the schema for the model.
-
-
-
Example:
import { OpenRouterClient, MemoryHistoryStorage } from 'openrouter-kit'; const client = new OpenRouterClient({ /* ... */ historyAdapter: new MemoryHistoryStorage() }); const userSchema = { type: "object", properties: { name: { type: "string"}, age: {type: "number"} }, required: ["name", "age"] }; async function getUserData() { const result = await client.chat({ prompt: 'Generate JSON for a user: name Alice, age 30.', responseFormat: { type: 'json_schema', json_schema: { name: 'UserData', schema: userSchema } } }); console.log(result.content); // Expect { name: "Alice", age: 30 } }
-
Parsing Error Handling:
- If
strictJsonParsing: false
(default): If the model returns invalid JSON or JSON not matching the schema,ChatCompletionResult.content
will benull
. - If
strictJsonParsing: true
: AValidationError
will be thrown in the same situation.
- If
-
Model Support: Not all models guarantee support for
responseFormat
. Check specific model documentation.
The library uses a structured error system for easier debugging and control flow.
-
Base Class
OpenRouterError
: All library errors inherit from this. Contains:-
message
: Human-readable error description. -
code
(ErrorCode
): String code for programmatic identification (e.g.,API_ERROR
,VALIDATION_ERROR
,RATE_LIMIT_ERROR
). -
statusCode?
(number): HTTP status code from the API response, if applicable. -
details?
(any): Additional context or the original error.
-
-
Subclasses: Specific error types for different situations:
-
APIError
: Error returned by the OpenRouter API (status >= 400). -
ValidationError
: Data validation failure (config, args, JSON/schema response). -
NetworkError
: Network issue connecting to the API. -
AuthenticationError
: Invalid API key or missing authentication (typically 401). -
AuthorizationError
: Invalid or expired access token (typically 401). -
AccessDeniedError
: Authenticated user lacks permissions (typically 403). -
RateLimitError
: Request limit exceeded (typically 429). Containsdetails.timeLeft
(ms). -
ToolError
: Error during toolexecute
function execution. -
ConfigError
: Invalid library configuration. -
SecurityError
: General security failure (includesDANGEROUS_ARGS
). -
TimeoutError
: API request timed out.
-
-
Enum
ErrorCode
: Contains all possible string error codes (e.g.,ErrorCode.API_ERROR
,ErrorCode.TOOL_ERROR
). -
Function
mapError(error)
: Internally used to convert Axios and standardError
objects into anOpenRouterError
subclass. Exported for potential external use. -
Handling Recommendations:
- Use
try...catch
blocks around client method calls (client.chat()
,client.getCreditBalance()
, etc.). - Check error type using
instanceof
(e.g.,if (error instanceof RateLimitError)
) or the code (if (error.code === ErrorCode.VALIDATION_ERROR)
). - Inspect
error.statusCode
anderror.details
for more context. - Subscribe to the global client
'error'
event (client.on('error', handler)
) for centralized logging or monitoring of unexpected errors.
- Use
import { OpenRouterClient, MemoryHistoryStorage, OpenRouterError, RateLimitError, ValidationError, ErrorCode } from 'openrouter-kit';
const client = new OpenRouterClient({ /* ... */ historyAdapter: new MemoryHistoryStorage() });
async function safeChat() {
try {
const result = await client.chat({ prompt: "..." });
// ... process successful result ...
} catch (error: any) {
if (error instanceof RateLimitError) {
const retryAfter = Math.ceil((error.details?.timeLeft || 1000) / 1000); // Seconds
console.warn(`Rate limit exceeded! Please try again in ${retryAfter} seconds.`);
} else if (error.code === ErrorCode.VALIDATION_ERROR) {
console.error(`Validation Error: ${error.message}`, error.details);
} else if (error.code === ErrorCode.TOOL_ERROR && error.message.includes('Maximum tool call depth')) {
console.error(`Tool call limit reached: ${error.message}`);
} else if (error instanceof OpenRouterError) {
console.error(`OpenRouter Kit Error (${error.code}, Status: ${error.statusCode || 'N/A'}): ${error.message}`);
if(error.details) console.error('Details:', error.details);
} else {
console.error(`Unknown error: ${error.message}`);
}
}
}
The library uses a built-in logger for debug information and event messages.
-
Activation: Set
debug: true
inOpenRouterConfig
when creating the client. -
Levels: Uses standard console levels:
console.debug
,console.log
,console.warn
,console.error
. Whendebug: false
, only critical initialization warnings or errors are shown. -
Prefixes: Messages are automatically prefixed with the component source (e.g.,
[OpenRouterClient]
,[SecurityManager]
,[CostTracker]
,[UnifiedHistoryManager]
) for easier debugging. -
Customization: While direct logger replacement isn't a standard API feature, you can pass custom loggers to some components (like
HistoryManager
if created manually) or use plugins/middleware to intercept and redirect logs. -
isDebugMode()
Method: Check the client's current debug status usingclient.isDebugMode()
.
Route requests to the OpenRouter API through an HTTP/HTTPS proxy using the proxy
option in OpenRouterConfig
.
-
Formats:
-
URL String: Full proxy URL, including protocol, optional authentication, host, and port.
proxy: 'http://user:[email protected]:8080'
proxy: 'https://secureproxy.com:9000'
-
Object: A structured object with fields:
-
host
(string, required): Proxy server hostname or IP. -
port
(number | string, required): Proxy server port. -
user?
(string, optional): Username for proxy authentication. -
pass?
(string, optional): Password for proxy authentication.
proxy: { host: '192.168.1.100', port: 8888, // can also be '8888' user: 'proxyUser', pass: 'proxyPassword' }
-
-
URL String: Full proxy URL, including protocol, optional authentication, host, and port.
-
Mechanism: The library uses
https-proxy-agent
to route HTTPS traffic through the specified HTTP/HTTPS proxy.
For Tasks:
Click tags to check more tools for each tasksFor Jobs:
Alternative AI tools for openrouter-kit
Similar Open Source Tools

generative-ai-python
The Google AI Python SDK is the easiest way for Python developers to build with the Gemini API. The Gemini API gives you access to Gemini models created by Google DeepMind. Gemini models are built from the ground up to be multimodal, so you can reason seamlessly across text, images, and code.

llm-scraper
LLM Scraper is a TypeScript library that allows you to convert any webpages into structured data using LLMs. It supports Local (GGUF), OpenAI, Groq chat models, and schemas defined with Zod. With full type-safety in TypeScript and based on the Playwright framework, it offers streaming when crawling multiple pages and supports four input modes: html, markdown, text, and image.

rust-genai
genai is a multi-AI providers library for Rust that aims to provide a common and ergonomic single API to various generative AI providers such as OpenAI, Anthropic, Cohere, Ollama, and Gemini. It focuses on standardizing chat completion APIs across major AI services, prioritizing ergonomics and commonality. The library initially focuses on text chat APIs and plans to expand to support images, function calling, and more in the future versions. Version 0.1.x will have breaking changes in patches, while version 0.2.x will follow semver more strictly. genai does not provide a full representation of a given AI provider but aims to simplify the differences at a lower layer for ease of use.

dashscope-sdk
DashScope SDK for .NET is an unofficial SDK maintained by Cnblogs, providing various APIs for text embedding, generation, multimodal generation, image synthesis, and more. Users can interact with the SDK to perform tasks such as text completion, chat generation, function calls, file operations, and more. The project is under active development, and users are advised to check the Release Notes before upgrading.

Webscout
WebScout is a versatile tool that allows users to search for anything using Google, DuckDuckGo, and phind.com. It contains AI models, can transcribe YouTube videos, generate temporary email and phone numbers, has TTS support, webai (terminal GPT and open interpreter), and offline LLMs. It also supports features like weather forecasting, YT video downloading, temp mail and number generation, text-to-speech, advanced web searches, and more.

openai-scala-client
This is a no-nonsense async Scala client for OpenAI API supporting all the available endpoints and params including streaming, chat completion, vision, and voice routines. It provides a single service called OpenAIService that supports various calls such as Models, Completions, Chat Completions, Edits, Images, Embeddings, Batches, Audio, Files, Fine-tunes, Moderations, Assistants, Threads, Thread Messages, Runs, Run Steps, Vector Stores, Vector Store Files, and Vector Store File Batches. The library aims to be self-contained with minimal dependencies and supports API-compatible providers like Azure OpenAI, Azure AI, Anthropic, Google Vertex AI, Groq, Grok, Fireworks AI, OctoAI, TogetherAI, Cerebras, Mistral, Deepseek, Ollama, FastChat, and more.

aiocache
Aiocache is an asyncio cache library that supports multiple backends such as memory, redis, and memcached. It provides a simple interface for functions like add, get, set, multi_get, multi_set, exists, increment, delete, clear, and raw. Users can easily install and use the library for caching data in Python applications. Aiocache allows for easy instantiation of caches and setup of cache aliases for reusing configurations. It also provides support for backends, serializers, and plugins to customize cache operations. The library offers detailed documentation and examples for different use cases and configurations.

llm.nvim
llm.nvim is a universal plugin for a large language model (LLM) designed to enable users to interact with LLM within neovim. Users can customize various LLMs such as gpt, glm, kimi, and local LLM. The plugin provides tools for optimizing code, comparing code, translating text, and more. It also supports integration with free models from Cloudflare, Github models, siliconflow, and others. Users can customize tools, chat with LLM, quickly translate text, and explain code snippets. The plugin offers a flexible window interface for easy interaction and customization.

ai00_server
AI00 RWKV Server is an inference API server for the RWKV language model based upon the web-rwkv inference engine. It supports VULKAN parallel and concurrent batched inference and can run on all GPUs that support VULKAN. No need for Nvidia cards!!! AMD cards and even integrated graphics can be accelerated!!! No need for bulky pytorch, CUDA and other runtime environments, it's compact and ready to use out of the box! Compatible with OpenAI's ChatGPT API interface. 100% open source and commercially usable, under the MIT license. If you are looking for a fast, efficient, and easy-to-use LLM API server, then AI00 RWKV Server is your best choice. It can be used for various tasks, including chatbots, text generation, translation, and Q&A.

python-genai
The Google Gen AI SDK is a Python library that provides access to Google AI and Vertex AI services. It allows users to create clients for different services, work with parameter types, models, generate content, call functions, handle JSON response schemas, stream text and image content, perform async operations, count and compute tokens, embed content, generate and upscale images, edit images, work with files, create and get cached content, tune models, distill models, perform batch predictions, and more. The SDK supports various features like automatic function support, manual function declaration, JSON response schema support, streaming for text and image content, async methods, tuning job APIs, distillation, batch prediction, and more.

candle-vllm
Candle-vllm is an efficient and easy-to-use platform designed for inference and serving local LLMs, featuring an OpenAI compatible API server. It offers a highly extensible trait-based system for rapid implementation of new module pipelines, streaming support in generation, efficient management of key-value cache with PagedAttention, and continuous batching. The tool supports chat serving for various models and provides a seamless experience for users to interact with LLMs through different interfaces.

openapi
The `@samchon/openapi` repository is a collection of OpenAPI types and converters for various versions of OpenAPI specifications. It includes an 'emended' OpenAPI v3.1 specification that enhances clarity by removing ambiguous and duplicated expressions. The repository also provides an application composer for LLM (Large Language Model) function calling from OpenAPI documents, allowing users to easily perform LLM function calls based on the Swagger document. Conversions to different versions of OpenAPI documents are also supported, all based on the emended OpenAPI v3.1 specification. Users can validate their OpenAPI documents using the `typia` library with `@samchon/openapi` types, ensuring compliance with standard specifications.

aiotdlib
aiotdlib is a Python asyncio Telegram client based on TDLib. It provides automatic generation of types and functions from tl schema, validation, good IDE type hinting, and high-level API methods for simpler work with tdlib. The package includes prebuilt TDLib binaries for macOS (arm64) and Debian Bullseye (amd64). Users can use their own binary by passing `library_path` argument to `Client` class constructor. Compatibility with other versions of the library is not guaranteed. The tool requires Python 3.9+ and users need to get their `api_id` and `api_hash` from Telegram docs for installation and usage.

pocketgroq
PocketGroq is a tool that provides advanced functionalities for text generation, web scraping, web search, and AI response evaluation. It includes features like an Autonomous Agent for answering questions, web crawling and scraping capabilities, enhanced web search functionality, and flexible integration with Ollama server. Users can customize the agent's behavior, evaluate responses using AI, and utilize various methods for text generation, conversation management, and Chain of Thought reasoning. The tool offers comprehensive methods for different tasks, such as initializing RAG, error handling, and tool management. PocketGroq is designed to enhance development processes and enable the creation of AI-powered applications with ease.