@stabgan/openrouter-mcp-multimodal 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +331 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +52 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/model-cache.d.ts +56 -0
  6. package/dist/model-cache.js +143 -0
  7. package/dist/model-cache.js.map +1 -0
  8. package/dist/openrouter-api.d.ts +26 -0
  9. package/dist/openrouter-api.js +119 -0
  10. package/dist/openrouter-api.js.map +1 -0
  11. package/dist/tool-handlers/analyze-image.d.ts +23 -0
  12. package/dist/tool-handlers/analyze-image.js +93 -0
  13. package/dist/tool-handlers/analyze-image.js.map +1 -0
  14. package/dist/tool-handlers/chat-completion.d.ts +24 -0
  15. package/dist/tool-handlers/chat-completion.js +111 -0
  16. package/dist/tool-handlers/chat-completion.js.map +1 -0
  17. package/dist/tool-handlers/get-model-info.d.ts +21 -0
  18. package/dist/tool-handlers/get-model-info.js +44 -0
  19. package/dist/tool-handlers/get-model-info.js.map +1 -0
  20. package/dist/tool-handlers/multi-image-analysis.d.ts +27 -0
  21. package/dist/tool-handlers/multi-image-analysis.js +136 -0
  22. package/dist/tool-handlers/multi-image-analysis.js.map +1 -0
  23. package/dist/tool-handlers/search-models.d.ts +34 -0
  24. package/dist/tool-handlers/search-models.js +44 -0
  25. package/dist/tool-handlers/search-models.js.map +1 -0
  26. package/dist/tool-handlers/validate-model.d.ts +21 -0
  27. package/dist/tool-handlers/validate-model.js +40 -0
  28. package/dist/tool-handlers/validate-model.js.map +1 -0
  29. package/dist/tool-handlers.d.ts +10 -0
  30. package/dist/tool-handlers.js +316 -0
  31. package/dist/tool-handlers.js.map +1 -0
  32. package/package.json +60 -0
package/README.md ADDED
@@ -0,0 +1,331 @@
1
+ # OpenRouter MCP Multimodal Server
2
+
3
+ [![Build Status](https://github.com/stabgan/openrouter-mcp-multimodal/actions/workflows/publish.yml/badge.svg)](https://github.com/stabgan/openrouter-mcp-multimodal/actions/workflows/publish.yml)
4
+ [![npm version](https://img.shields.io/npm/v/@stabgan/openrouter-mcp-multimodal.svg)](https://www.npmjs.com/package/@stabgan/openrouter-mcp-multimodal)
5
+ [![Docker Pulls](https://img.shields.io/docker/pulls/stabgandocker/openrouter-mcp-multimodal.svg)](https://hub.docker.com/r/stabgandocker/openrouter-mcp-multimodal)
6
+
7
+ An MCP (Model Context Protocol) server that provides chat and image analysis capabilities through OpenRouter.ai's diverse model ecosystem. This server combines text chat functionality with powerful image analysis capabilities.
8
+
9
+ ## Features
10
+
11
+ - **Text Chat:**
12
+ - Direct access to all OpenRouter.ai chat models
13
+ - Support for simple text and multimodal conversations
14
+ - Configurable temperature and other parameters
15
+
16
+ - **Image Analysis:**
17
+ - Analyze single images with custom questions
18
+ - Process multiple images simultaneously
19
+ - Automatic image resizing and optimization
20
+ - Support for various image sources (local files, URLs, data URLs)
21
+
22
+ - **Model Selection:**
23
+ - Search and filter available models
24
+ - Validate model IDs
25
+ - Get detailed model information
26
+ - Support for default model configuration
27
+
28
+ - **Performance Optimization:**
29
+ - Smart model information caching
30
+ - Exponential backoff for retries
31
+ - Automatic rate limit handling
32
+
33
+ ## Installation
34
+
35
+ ### Option 1: Install via npm
36
+
37
+ ```bash
38
+ npm install -g @stabgan/openrouter-mcp-multimodal
39
+ ```
40
+
41
+ ### Option 2: Run via Docker
42
+
43
+ ```bash
44
+ docker run -i -e OPENROUTER_API_KEY=your-api-key-here stabgandocker/openrouter-mcp-multimodal:latest
45
+ ```
46
+
47
+ ## Quick Start Configuration
48
+
49
+ ### Prerequisites
50
+
51
+ 1. Get your OpenRouter API key from [OpenRouter Keys](https://openrouter.ai/keys)
52
+ 2. Choose a default model (optional)
53
+
54
+ ### MCP Configuration Options
55
+
56
+ Add one of the following configurations to your MCP settings file (e.g., `cline_mcp_settings.json` or `claude_desktop_config.json`):
57
+
58
+ #### Option 1: Using npx (Node.js)
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "openrouter": {
64
+ "command": "npx",
65
+ "args": [
66
+ "-y",
67
+ "@stabgan/openrouter-mcp-multimodal"
68
+ ],
69
+ "env": {
70
+ "OPENROUTER_API_KEY": "your-api-key-here",
71
+ "OPENROUTER_DEFAULT_MODEL": "anthropic/claude-3.5-sonnet"
72
+ }
73
+ }
74
+ }
75
+ }
76
+ ```
77
+
78
+ #### Option 2: Using uv (Python Package Manager)
79
+
80
+ ```json
81
+ {
82
+ "mcpServers": {
83
+ "openrouter": {
84
+ "command": "uv",
85
+ "args": [
86
+ "run",
87
+ "-m",
88
+ "openrouter_mcp_multimodal"
89
+ ],
90
+ "env": {
91
+ "OPENROUTER_API_KEY": "your-api-key-here",
92
+ "OPENROUTER_DEFAULT_MODEL": "anthropic/claude-3.5-sonnet"
93
+ }
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ #### Option 3: Using Docker
100
+
101
+ ```json
102
+ {
103
+ "mcpServers": {
104
+ "openrouter": {
105
+ "command": "docker",
106
+ "args": [
107
+ "run",
108
+ "--rm",
109
+ "-i",
110
+ "-e", "OPENROUTER_API_KEY=your-api-key-here",
111
+ "-e", "OPENROUTER_DEFAULT_MODEL=anthropic/claude-3.5-sonnet",
112
+ "stabgandocker/openrouter-mcp-multimodal:latest"
113
+ ]
114
+ }
115
+ }
116
+ }
117
+ ```
118
+
119
+ #### Option 4: Using Smithery (recommended)
120
+
121
+ ```json
122
+ {
123
+ "mcpServers": {
124
+ "openrouter": {
125
+ "command": "smithery",
126
+ "args": [
127
+ "run",
128
+ "stabgan/openrouter-mcp-multimodal"
129
+ ],
130
+ "env": {
131
+ "OPENROUTER_API_KEY": "your-api-key-here",
132
+ "OPENROUTER_DEFAULT_MODEL": "anthropic/claude-3.5-sonnet"
133
+ }
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ ## Available Tools
140
+
141
+ ### chat_completion
142
+
143
+ Send text or multimodal messages to OpenRouter models:
144
+
145
+ ```javascript
146
+ use_mcp_tool({
147
+ server_name: "openrouter",
148
+ tool_name: "chat_completion",
149
+ arguments: {
150
+ model: "google/gemini-2.5-pro-exp-03-25:free", // Optional if default is set
151
+ messages: [
152
+ {
153
+ role: "system",
154
+ content: "You are a helpful assistant."
155
+ },
156
+ {
157
+ role: "user",
158
+ content: "What is the capital of France?"
159
+ }
160
+ ],
161
+ temperature: 0.7 // Optional, defaults to 1.0
162
+ }
163
+ });
164
+ ```
165
+
166
+ For multimodal messages with images:
167
+
168
+ ```javascript
169
+ use_mcp_tool({
170
+ server_name: "openrouter",
171
+ tool_name: "chat_completion",
172
+ arguments: {
173
+ model: "anthropic/claude-3.5-sonnet",
174
+ messages: [
175
+ {
176
+ role: "user",
177
+ content: [
178
+ {
179
+ type: "text",
180
+ text: "What's in this image?"
181
+ },
182
+ {
183
+ type: "image_url",
184
+ image_url: {
185
+ url: "https://example.com/image.jpg"
186
+ }
187
+ }
188
+ ]
189
+ }
190
+ ]
191
+ }
192
+ });
193
+ ```
194
+
195
+ ### analyze_image
196
+
197
+ Analyze a single image with an optional question:
198
+
199
+ ```javascript
200
+ use_mcp_tool({
201
+ server_name: "openrouter",
202
+ tool_name: "analyze_image",
203
+ arguments: {
204
+ image_path: "/absolute/path/to/image.jpg",
205
+ question: "What objects are in this image?", // Optional
206
+ model: "anthropic/claude-3.5-sonnet" // Optional if default is set
207
+ }
208
+ });
209
+ ```
210
+
211
+ ### multi_image_analysis
212
+
213
+ Analyze multiple images with a single prompt:
214
+
215
+ ```javascript
216
+ use_mcp_tool({
217
+ server_name: "openrouter",
218
+ tool_name: "multi_image_analysis",
219
+ arguments: {
220
+ images: [
221
+ { url: "https://example.com/image1.jpg" },
222
+ { url: "file:///absolute/path/to/image2.jpg" },
223
+ {
224
+ url: "https://example.com/image3.jpg",
225
+ alt: "Optional description of image 3"
226
+ }
227
+ ],
228
+ prompt: "Compare these images and tell me their similarities and differences",
229
+ markdown_response: true, // Optional, defaults to true
230
+ model: "anthropic/claude-3-opus" // Optional if default is set
231
+ }
232
+ });
233
+ ```
234
+
235
+ ### search_models
236
+
237
+ Search and filter available models:
238
+
239
+ ```javascript
240
+ use_mcp_tool({
241
+ server_name: "openrouter",
242
+ tool_name: "search_models",
243
+ arguments: {
244
+ query: "claude", // Optional text search
245
+ provider: "anthropic", // Optional provider filter
246
+ capabilities: {
247
+ vision: true // Filter for models with vision capabilities
248
+ },
249
+ limit: 5 // Optional, defaults to 10
250
+ }
251
+ });
252
+ ```
253
+
254
+ ### get_model_info
255
+
256
+ Get detailed information about a specific model:
257
+
258
+ ```javascript
259
+ use_mcp_tool({
260
+ server_name: "openrouter",
261
+ tool_name: "get_model_info",
262
+ arguments: {
263
+ model: "anthropic/claude-3.5-sonnet"
264
+ }
265
+ });
266
+ ```
267
+
268
+ ### validate_model
269
+
270
+ Check if a model ID is valid:
271
+
272
+ ```javascript
273
+ use_mcp_tool({
274
+ server_name: "openrouter",
275
+ tool_name: "validate_model",
276
+ arguments: {
277
+ model: "google/gemini-2.5-pro-exp-03-25:free"
278
+ }
279
+ });
280
+ ```
281
+
282
+ ## Error Handling
283
+
284
+ The server provides detailed error messages for various failure cases:
285
+
286
+ - Invalid input parameters
287
+ - Network errors
288
+ - Rate limiting issues
289
+ - Invalid image formats
290
+ - Authentication problems
291
+
292
+ ## Troubleshooting
293
+
294
+ ### Common Issues
295
+
296
+ - **"fetch is not defined" error**: This often occurs when the Node.js environment doesn't have global fetch. Use Node.js v18+ or add the PATH environment variable to your configuration as shown below:
297
+
298
+ ```json
299
+ {
300
+ "mcpServers": {
301
+ "openrouter": {
302
+ "command": "npx",
303
+ "args": [
304
+ "-y",
305
+ "@stabgan/openrouter-mcp-multimodal"
306
+ ],
307
+ "env": {
308
+ "OPENROUTER_API_KEY": "your-api-key-here",
309
+ "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
310
+ }
311
+ }
312
+ }
313
+ }
314
+ ```
315
+
316
+ - **Image analysis failures**: Make sure your image path is absolute and the file format is supported.
317
+
318
+ ## Development
319
+
320
+ To build from source:
321
+
322
+ ```bash
323
+ git clone https://github.com/stabgan/openrouter-mcp-multimodal.git
324
+ cd openrouter-mcp-multimodal
325
+ npm install
326
+ npm run build
327
+ ```
328
+
329
+ ## License
330
+
331
+ MIT License
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ // OpenRouter Multimodal MCP Server
3
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
4
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
5
+ import { ToolHandlers } from './tool-handlers.js';
6
+ class OpenRouterMultimodalServer {
7
+ server;
8
+ toolHandlers; // Using definite assignment assertion
9
+ constructor() {
10
+ // Get API key and default model from environment variables
11
+ const apiKey = process.env.OPENROUTER_API_KEY;
12
+ const defaultModel = process.env.OPENROUTER_DEFAULT_MODEL;
13
+ // Check if API key is provided
14
+ if (!apiKey) {
15
+ throw new Error('OPENROUTER_API_KEY environment variable is required');
16
+ }
17
+ // Initialize the server
18
+ this.server = new Server({
19
+ name: 'openrouter-multimodal-server',
20
+ version: '1.0.0',
21
+ }, {
22
+ capabilities: {
23
+ tools: {},
24
+ },
25
+ });
26
+ // Set up error handling
27
+ this.server.onerror = (error) => console.error('[MCP Error]', error);
28
+ // Initialize tool handlers
29
+ this.toolHandlers = new ToolHandlers(this.server, apiKey, defaultModel);
30
+ process.on('SIGINT', async () => {
31
+ await this.server.close();
32
+ process.exit(0);
33
+ });
34
+ }
35
+ async run() {
36
+ const transport = new StdioServerTransport();
37
+ await this.server.connect(transport);
38
+ console.error('OpenRouter Multimodal MCP server running on stdio');
39
+ console.error('Using API key from environment variable');
40
+ console.error('Note: To use OpenRouter Multimodal, add the API key to your environment variables:');
41
+ console.error(' OPENROUTER_API_KEY=your-api-key');
42
+ if (process.env.OPENROUTER_DEFAULT_MODEL) {
43
+ console.error(` Using default model: ${process.env.OPENROUTER_DEFAULT_MODEL}`);
44
+ }
45
+ else {
46
+ console.error(' No default model set. You will need to specify a model in each request.');
47
+ }
48
+ }
49
+ }
50
+ const server = new OpenRouterMultimodalServer();
51
+ server.run().catch(console.error);
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,mCAAmC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,0BAA0B;IACtB,MAAM,CAAS;IACf,YAAY,CAAgB,CAAC,sCAAsC;IAE3E;QACE,2DAA2D;QAC3D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;QAC9C,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC;QAE1D,+BAA+B;QAC/B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;QACzE,CAAC;QAED,wBAAwB;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CACtB;YACE,IAAI,EAAE,8BAA8B;YACpC,OAAO,EAAE,OAAO;SACjB,EACD;YACE,YAAY,EAAE;gBACZ,KAAK,EAAE,EAAE;aACV;SACF,CACF,CAAC;QAEF,wBAAwB;QACxB,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;QAErE,2BAA2B;QAC3B,IAAI,CAAC,YAAY,GAAG,IAAI,YAAY,CAClC,IAAI,CAAC,MAAM,EACX,MAAM,EACN,YAAY,CACb,CAAC;QAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;YAC9B,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YAC1B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG;QACP,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QACrC,OAAO,CAAC,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACnE,OAAO,CAAC,KAAK,CAAC,yCAAyC,CAAC,CAAC;QACzD,OAAO,CAAC,KAAK,CAAC,oFAAoF,CAAC,CAAC;QACpG,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACvD,IAAI,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,CAAC;YACzC,OAAO,CAAC,KAAK,CAAC,8BAA8B,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,CAAC,CAAC;QACtF,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,+EAA+E,CAAC,CAAC;QACjG,CAAC;IACH,CAAC;CACF;AAED,MAAM,MAAM,GAAG,IAAI,0BAA0B,EAAE,CAAC;AAChD,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * ModelCache - Caches OpenRouter model data to reduce API calls
3
+ */
4
+ export declare class ModelCache {
5
+ private static instance;
6
+ private models;
7
+ private lastFetchTime;
8
+ private cacheExpiryTime;
9
+ private constructor();
10
+ /**
11
+ * Get singleton instance
12
+ */
13
+ static getInstance(): ModelCache;
14
+ /**
15
+ * Check if the cache is valid
16
+ */
17
+ isCacheValid(): boolean;
18
+ /**
19
+ * Store all models
20
+ */
21
+ setModels(models: any[]): void;
22
+ /**
23
+ * Get all cached models
24
+ */
25
+ getAllModels(): any[];
26
+ /**
27
+ * Get a specific model by ID
28
+ */
29
+ getModel(modelId: string): any | null;
30
+ /**
31
+ * Check if a model exists
32
+ */
33
+ hasModel(modelId: string): boolean;
34
+ /**
35
+ * Search models based on criteria
36
+ */
37
+ searchModels(params: {
38
+ query?: string;
39
+ provider?: string;
40
+ minContextLength?: number | string;
41
+ maxContextLength?: number | string;
42
+ maxPromptPrice?: number | string;
43
+ maxCompletionPrice?: number | string;
44
+ capabilities?: {
45
+ functions?: boolean;
46
+ tools?: boolean;
47
+ vision?: boolean;
48
+ json_mode?: boolean;
49
+ };
50
+ limit?: number | string;
51
+ }): any[];
52
+ /**
53
+ * Reset the cache
54
+ */
55
+ resetCache(): void;
56
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * ModelCache - Caches OpenRouter model data to reduce API calls
3
+ */
4
+ export class ModelCache {
5
+ static instance;
6
+ models;
7
+ lastFetchTime;
8
+ cacheExpiryTime; // in milliseconds (1 hour = 3600000)
9
+ constructor() {
10
+ this.models = {};
11
+ this.lastFetchTime = 0;
12
+ this.cacheExpiryTime = 3600000; // 1 hour
13
+ }
14
+ /**
15
+ * Get singleton instance
16
+ */
17
+ static getInstance() {
18
+ if (!ModelCache.instance) {
19
+ ModelCache.instance = new ModelCache();
20
+ }
21
+ return ModelCache.instance;
22
+ }
23
+ /**
24
+ * Check if the cache is valid
25
+ */
26
+ isCacheValid() {
27
+ return (Object.keys(this.models).length > 0 &&
28
+ Date.now() - this.lastFetchTime < this.cacheExpiryTime);
29
+ }
30
+ /**
31
+ * Store all models
32
+ */
33
+ setModels(models) {
34
+ this.models = {};
35
+ for (const model of models) {
36
+ this.models[model.id] = model;
37
+ }
38
+ this.lastFetchTime = Date.now();
39
+ }
40
+ /**
41
+ * Get all cached models
42
+ */
43
+ getAllModels() {
44
+ return Object.values(this.models);
45
+ }
46
+ /**
47
+ * Get a specific model by ID
48
+ */
49
+ getModel(modelId) {
50
+ return this.models[modelId] || null;
51
+ }
52
+ /**
53
+ * Check if a model exists
54
+ */
55
+ hasModel(modelId) {
56
+ return !!this.models[modelId];
57
+ }
58
+ /**
59
+ * Search models based on criteria
60
+ */
61
+ searchModels(params) {
62
+ let results = this.getAllModels();
63
+ // Apply text search
64
+ if (params.query) {
65
+ const query = params.query.toLowerCase();
66
+ results = results.filter((model) => model.id.toLowerCase().includes(query) ||
67
+ (model.description && model.description.toLowerCase().includes(query)) ||
68
+ (model.provider && model.provider.toLowerCase().includes(query)));
69
+ }
70
+ // Filter by provider
71
+ if (params.provider) {
72
+ results = results.filter((model) => model.provider && model.provider.toLowerCase() === params.provider.toLowerCase());
73
+ }
74
+ // Filter by context length
75
+ if (params.minContextLength !== undefined) {
76
+ const minContextLength = typeof params.minContextLength === 'string'
77
+ ? parseInt(params.minContextLength, 10)
78
+ : params.minContextLength;
79
+ if (!isNaN(minContextLength)) {
80
+ results = results.filter((model) => model.context_length >= minContextLength);
81
+ }
82
+ }
83
+ if (params.maxContextLength !== undefined) {
84
+ const maxContextLength = typeof params.maxContextLength === 'string'
85
+ ? parseInt(params.maxContextLength, 10)
86
+ : params.maxContextLength;
87
+ if (!isNaN(maxContextLength)) {
88
+ results = results.filter((model) => model.context_length <= maxContextLength);
89
+ }
90
+ }
91
+ // Filter by price
92
+ if (params.maxPromptPrice !== undefined) {
93
+ const maxPromptPrice = typeof params.maxPromptPrice === 'string'
94
+ ? parseFloat(params.maxPromptPrice)
95
+ : params.maxPromptPrice;
96
+ if (!isNaN(maxPromptPrice)) {
97
+ results = results.filter((model) => !model.pricing?.prompt || model.pricing.prompt <= maxPromptPrice);
98
+ }
99
+ }
100
+ if (params.maxCompletionPrice !== undefined) {
101
+ const maxCompletionPrice = typeof params.maxCompletionPrice === 'string'
102
+ ? parseFloat(params.maxCompletionPrice)
103
+ : params.maxCompletionPrice;
104
+ if (!isNaN(maxCompletionPrice)) {
105
+ results = results.filter((model) => !model.pricing?.completion ||
106
+ model.pricing.completion <= maxCompletionPrice);
107
+ }
108
+ }
109
+ // Filter by capabilities
110
+ if (params.capabilities) {
111
+ if (params.capabilities.functions) {
112
+ results = results.filter((model) => model.capabilities?.function_calling);
113
+ }
114
+ if (params.capabilities.tools) {
115
+ results = results.filter((model) => model.capabilities?.tools);
116
+ }
117
+ if (params.capabilities.vision) {
118
+ results = results.filter((model) => model.capabilities?.vision);
119
+ }
120
+ if (params.capabilities.json_mode) {
121
+ results = results.filter((model) => model.capabilities?.json_mode);
122
+ }
123
+ }
124
+ // Apply limit
125
+ if (params.limit !== undefined) {
126
+ const limit = typeof params.limit === 'string'
127
+ ? parseInt(params.limit, 10)
128
+ : params.limit;
129
+ if (!isNaN(limit) && limit > 0) {
130
+ results = results.slice(0, limit);
131
+ }
132
+ }
133
+ return results;
134
+ }
135
+ /**
136
+ * Reset the cache
137
+ */
138
+ resetCache() {
139
+ this.models = {};
140
+ this.lastFetchTime = 0;
141
+ }
142
+ }
143
+ //# sourceMappingURL=model-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-cache.js","sourceRoot":"","sources":["../src/model-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Client for interacting with the OpenRouter API
3
+ */
4
+ export declare class OpenRouterAPIClient {
5
+ private apiKey;
6
+ private axiosInstance;
7
+ private retryCount;
8
+ private retryDelay;
9
+ constructor(apiKey: string);
10
+ /**
11
+ * Get all available models from OpenRouter
12
+ */
13
+ getModels(): Promise<any[]>;
14
+ /**
15
+ * Send a request to the OpenRouter API with retry functionality
16
+ */
17
+ request(endpoint: string, method: string, data?: any): Promise<any>;
18
+ /**
19
+ * Handle retryable errors
20
+ */
21
+ private handleRetryableError;
22
+ /**
23
+ * Handle request errors
24
+ */
25
+ private handleRequestError;
26
+ }