@aeye/openrouter 0.1.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.
@@ -0,0 +1,203 @@
1
+ /**
2
+ * OpenRouter Provider Integration Tests
3
+ *
4
+ * Tests that make REAL API calls to OpenRouter.
5
+ * Requires OPENROUTER_API_KEY environment variable.
6
+ */
7
+ import { OpenRouterProvider } from '../openrouter';
8
+ import { getAPIKey, skipIfNoAPIKey } from './setup';
9
+ const describeIntegration = skipIfNoAPIKey();
10
+ describeIntegration('OpenRouter Integration', () => {
11
+ let provider;
12
+ beforeAll(() => {
13
+ provider = new OpenRouterProvider({
14
+ apiKey: getAPIKey()
15
+ });
16
+ });
17
+ describe('Model Listing', () => {
18
+ it('should list real models from OpenRouter', async () => {
19
+ const models = await provider.listModels({
20
+ apiKey: getAPIKey()
21
+ });
22
+ expect(models.length).toBeGreaterThan(0);
23
+ console.log(` Found ${models.length} models`);
24
+ console.log(` Sample: ${models.slice(0, 5).map(m => m.id).join(', ')}`);
25
+ }, 30000);
26
+ it('should include models from multiple providers', async () => {
27
+ const models = await provider.listModels({
28
+ apiKey: getAPIKey()
29
+ });
30
+ // OpenRouter aggregates models from multiple providers
31
+ const providers = new Set(models.map(m => m.id.split('/')[0]));
32
+ expect(providers.size).toBeGreaterThan(1);
33
+ console.log(` Model providers: ${Array.from(providers).slice(0, 5).join(', ')}`);
34
+ }, 30000);
35
+ it('should include model pricing', async () => {
36
+ const models = await provider.listModels({
37
+ apiKey: getAPIKey()
38
+ });
39
+ const modelsWithPricing = models.filter(m => (m.pricing.text?.input || 0) > 0 || (m.pricing.text?.output || 0) > 0);
40
+ expect(modelsWithPricing.length).toBeGreaterThan(0);
41
+ console.log(` Models with pricing: ${modelsWithPricing.length}/${models.length}`);
42
+ }, 30000);
43
+ });
44
+ describe('Health Check', () => {
45
+ it('should pass health check', async () => {
46
+ const isHealthy = await provider.checkHealth();
47
+ expect(isHealthy).toBe(true);
48
+ }, 30000);
49
+ });
50
+ describe('Chat Completion', () => {
51
+ it('should complete a simple chat with a free model', async () => {
52
+ const executor = provider.createExecutor();
53
+ const request = {
54
+ messages: [
55
+ {
56
+ role: 'user',
57
+ content: 'Reply with exactly: "Test successful"'
58
+ }
59
+ ]
60
+ };
61
+ // Use a free model to avoid charges
62
+ const response = await executor(request, {}, { model: 'google/gemini-flash-1.5' });
63
+ expect(response.content).toBeTruthy();
64
+ expect(typeof response.content).toBe('string');
65
+ expect(response.finishReason).toBeTruthy();
66
+ expect(response.usage).toBeDefined();
67
+ console.log(` Response: ${response.content}`);
68
+ const totalTokens = (response.usage?.text?.input || 0) + (response.usage?.text?.output || 0);
69
+ console.log(` Tokens: ${totalTokens}`);
70
+ }, 30000);
71
+ it('should stream chat completion', async () => {
72
+ const streamer = provider.createStreamer();
73
+ const request = {
74
+ messages: [
75
+ {
76
+ role: 'user',
77
+ content: 'Count from 1 to 3'
78
+ }
79
+ ]
80
+ };
81
+ const chunks = [];
82
+ let finalUsage = null;
83
+ for await (const chunk of streamer(request, {}, { model: 'google/gemini-flash-1.5' })) {
84
+ if (chunk.content) {
85
+ chunks.push(chunk.content);
86
+ }
87
+ if (chunk.usage) {
88
+ finalUsage = chunk.usage;
89
+ }
90
+ }
91
+ expect(chunks.length).toBeGreaterThan(0);
92
+ const fullText = chunks.join('');
93
+ console.log(` Received ${chunks.length} chunks`);
94
+ console.log(` Full response: ${fullText}`);
95
+ }, 30000);
96
+ it('should use model from context metadata', async () => {
97
+ const executor = provider.createExecutor();
98
+ const request = {
99
+ messages: [
100
+ {
101
+ role: 'user',
102
+ content: 'Say "hi"'
103
+ }
104
+ ]
105
+ };
106
+ const ctx = {
107
+ metadata: {
108
+ model: 'google/gemini-flash-1.5'
109
+ }
110
+ };
111
+ const response = await executor(request, ctx, {});
112
+ expect(response.content).toBeTruthy();
113
+ console.log(` Used model from context`);
114
+ console.log(` Response: ${response.content}`);
115
+ }, 30000);
116
+ it('should work with different model providers on OpenRouter', async () => {
117
+ const executor = provider.createExecutor();
118
+ // Test models from different providers available on OpenRouter
119
+ const testModels = [
120
+ 'google/gemini-flash-1.5',
121
+ 'meta-llama/llama-3.2-3b-instruct:free'
122
+ ];
123
+ for (const model of testModels) {
124
+ try {
125
+ const response = await executor({ messages: [{ role: 'user', content: 'Hi' }] }, {}, { model });
126
+ expect(response.content).toBeTruthy();
127
+ console.log(` ${model}: ✓`);
128
+ }
129
+ catch (error) {
130
+ console.log(` ${model}: ✗ (${error.message})`);
131
+ }
132
+ }
133
+ }, 60000);
134
+ });
135
+ describe('Model Selection', () => {
136
+ it('should find free models', async () => {
137
+ const models = await provider.listModels({
138
+ apiKey: getAPIKey()
139
+ });
140
+ const freeModels = models.filter(m => m.pricing.text?.input && !m.pricing.text?.output);
141
+ expect(freeModels.length).toBeGreaterThan(0);
142
+ console.log(` Free models: ${freeModels.length}`);
143
+ console.log(` Examples: ${freeModels.slice(0, 3).map(m => m.id).join(', ')}`);
144
+ }, 30000);
145
+ it('should find models with vision capability', async () => {
146
+ const models = await provider.listModels({
147
+ apiKey: getAPIKey()
148
+ });
149
+ const visionModels = models.filter(m => m.capabilities.has('vision'));
150
+ if (visionModels.length > 0) {
151
+ console.log(` Vision models: ${visionModels.length}`);
152
+ console.log(` Examples: ${visionModels.slice(0, 3).map(m => m.id).join(', ')}`);
153
+ expect(visionModels.length).toBeGreaterThan(0);
154
+ }
155
+ else {
156
+ console.log(` No vision models detected (may need API update)`);
157
+ }
158
+ }, 30000);
159
+ });
160
+ describe('Error Handling', () => {
161
+ it('should handle invalid model', async () => {
162
+ const executor = provider.createExecutor();
163
+ const request = {
164
+ messages: [{ role: 'user', content: 'Test' }]
165
+ };
166
+ await expect(executor(request, {}, { model: 'invalid/model/name' })).rejects.toThrow();
167
+ }, 30000);
168
+ it('should handle rate limiting gracefully', async () => {
169
+ const executor = provider.createExecutor();
170
+ const request = {
171
+ messages: [{ role: 'user', content: 'Hi' }]
172
+ };
173
+ // Make multiple rapid requests using free model
174
+ const promises = Array(3).fill(null).map(() => executor(request, {}, { model: 'google/gemini-flash-1.5' }));
175
+ // At least some should succeed
176
+ const results = await Promise.allSettled(promises);
177
+ const succeeded = results.filter(r => r.status === 'fulfilled').length;
178
+ expect(succeeded).toBeGreaterThan(0);
179
+ console.log(` ${succeeded}/3 requests succeeded`);
180
+ }, 60000);
181
+ });
182
+ describe('Cost Comparison', () => {
183
+ it('should show cost range across available models', async () => {
184
+ const models = await provider.listModels({
185
+ apiKey: getAPIKey()
186
+ });
187
+ const paidModels = models.filter(m => (m.pricing.text?.input || 0) > 0 || (m.pricing.text?.output || 0) > 0);
188
+ if (paidModels.length > 0) {
189
+ // Find cheapest and most expensive
190
+ paidModels.sort((a, b) => ((a.pricing.text?.input || 0) + (a.pricing.text?.output || 0)) -
191
+ ((b.pricing.text?.input || 0) + (b.pricing.text?.output || 0)));
192
+ const cheapest = paidModels[0];
193
+ const mostExpensive = paidModels[paidModels.length - 1];
194
+ console.log(` Cheapest: ${cheapest.id}`);
195
+ console.log(` $${cheapest.pricing.text?.input}/M input, $${cheapest.pricing.text?.output}/M output`);
196
+ console.log(` Most expensive: ${mostExpensive.id}`);
197
+ console.log(` $${mostExpensive.pricing.text?.input}/M input, $${mostExpensive.pricing.text?.output}/M output`);
198
+ expect(paidModels.length).toBeGreaterThan(0);
199
+ }
200
+ }, 30000);
201
+ });
202
+ });
203
+ //# sourceMappingURL=openrouter.integration.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.integration.test.js","sourceRoot":"","sources":["../../src/__integration__/openrouter.integration.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * OpenRouter Integration Test Setup
3
+ */
4
+ export declare const getAPIKey: () => string;
5
+ export declare const hasAPIKey: () => boolean;
6
+ export declare const skipIfNoAPIKey: () => jest.Describe;
7
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../../src/__integration__/setup.ts"],"names":[],"mappings":"AAAA;;GAEG;AAQH,eAAO,MAAM,SAAS,QAAO,MAW5B,CAAC;AAEF,eAAO,MAAM,SAAS,QAAO,OAE5B,CAAC;AAEF,eAAO,MAAM,cAAc,qBAM1B,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * OpenRouter Integration Test Setup
3
+ */
4
+ import dotenv from 'dotenv';
5
+ import path from 'path';
6
+ // Load .env.test from root
7
+ dotenv.config({ path: path.resolve(__dirname, '../../../../.env.test') });
8
+ export const getAPIKey = () => {
9
+ const key = process.env.OPENROUTER_API_KEY;
10
+ if (!key) {
11
+ throw new Error('Missing OPENROUTER_API_KEY in environment. ' +
12
+ 'Add it to .env.test or set it as an environment variable.');
13
+ }
14
+ return key;
15
+ };
16
+ export const hasAPIKey = () => {
17
+ return !!process.env.OPENROUTER_API_KEY;
18
+ };
19
+ export const skipIfNoAPIKey = () => {
20
+ if (!hasAPIKey()) {
21
+ console.warn('Skipping OpenRouter integration tests - no API key found');
22
+ return describe.skip;
23
+ }
24
+ return describe;
25
+ };
26
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../../src/__integration__/setup.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,2BAA2B;AAC3B,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,uBAAuB,CAAC,EAAE,CAAC,CAAC;AAE1E,MAAM,CAAC,MAAM,SAAS,GAAG,GAAW,EAAE;IACpC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAE3C,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,6CAA6C;YAC7C,2DAA2D,CAC5D,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,GAAY,EAAE;IACrC,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;AAC1C,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE;IACjC,IAAI,CAAC,SAAS,EAAE,EAAE,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;QACzE,OAAO,QAAQ,CAAC,IAAI,CAAC;IACvB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './openrouter';
2
+ export * from './source';
3
+ export * from './types';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from './openrouter';
2
+ export * from './source';
3
+ export * from './types';
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * OpenRouter Provider
3
+ *
4
+ * Provider for OpenRouter API with provider-specific routing and fallback options.
5
+ */
6
+ import type { ModelInfo, Provider } from '@aeye/ai';
7
+ import type { Chunk, Request, Response } from '@aeye/core';
8
+ import { OpenAIConfig, OpenAIProvider } from '@aeye/openai';
9
+ import OpenAI from 'openai';
10
+ import { OpenRouterChatChunk, OpenRouterChatRequest, OpenRouterChatResponse, OpenRouterModel } from './types';
11
+ /**
12
+ * OpenRouter provider configuration
13
+ */
14
+ export interface OpenRouterConfig extends OpenAIConfig {
15
+ defaultParams?: {
16
+ siteUrl?: string;
17
+ appName?: string;
18
+ providers?: {
19
+ order?: string[];
20
+ allowFallbacks?: boolean;
21
+ requireParameters?: boolean;
22
+ dataCollection?: 'deny' | 'allow';
23
+ zdr?: boolean;
24
+ only?: string[];
25
+ ignore?: string[];
26
+ quantizations?: ('int4' | 'int8' | 'fp4' | 'fp6' | 'fp8' | 'fp16' | 'bf16' | 'fp32' | 'unknown')[];
27
+ sort?: 'price' | 'throughput' | 'latency';
28
+ maxPrice?: {
29
+ prompt?: number;
30
+ completion?: number;
31
+ image?: number;
32
+ };
33
+ };
34
+ transforms?: string[];
35
+ };
36
+ }
37
+ /**
38
+ * Convert OpenRouter model to ModelInfo with full details
39
+ */
40
+ export declare function convertOpenRouterModel(model: OpenRouterModel, zdrModelIds: Set<string>, metrics?: {
41
+ latency?: number;
42
+ throughput?: number;
43
+ uptime?: number;
44
+ } | null): ModelInfo;
45
+ /**
46
+ * OpenRouter provider implementation extending base OpenAI-compatible provider
47
+ */
48
+ export declare class OpenRouterProvider extends OpenAIProvider<OpenRouterConfig> implements Provider<OpenRouterConfig> {
49
+ readonly name = "openrouter";
50
+ protected createClient(config: OpenRouterConfig): OpenAI;
51
+ protected convertModel(model: OpenAI.Model): ModelInfo;
52
+ /**
53
+ * Augment chat request with OpenRouter-specific parameters
54
+ */
55
+ protected augmentChatRequest(params: OpenRouterChatRequest, request: Request, config: OpenRouterConfig): void;
56
+ /**
57
+ *
58
+ * @param expected
59
+ * @param response
60
+ */
61
+ protected augmentChatResponse(expected: OpenRouterChatResponse, response: Response, config: OpenRouterConfig): void;
62
+ protected augmentChatChunk(expected: OpenRouterChatChunk, chunk: Chunk, config: OpenRouterConfig): void;
63
+ /**
64
+ * OpenRouter does not support image generation
65
+ */
66
+ generateImage: undefined;
67
+ /**
68
+ * OpenRouter does not support image generation streaming
69
+ */
70
+ generateImageStream: undefined;
71
+ /**
72
+ * OpenRouter does not support image editing
73
+ */
74
+ editImage: undefined;
75
+ /**
76
+ * OpenRouter does not support image editing
77
+ */
78
+ editImageStream: undefined;
79
+ /**
80
+ * OpenRouter does not support audio transcription
81
+ */
82
+ transcribe: undefined;
83
+ /**
84
+ * OpenRouter does not support audio transcription streaming
85
+ */
86
+ transcribeStream: undefined;
87
+ /**
88
+ * OpenRouter does not support speech synthesis
89
+ */
90
+ speech: undefined;
91
+ /**
92
+ * OpenRouter does not support embeddings
93
+ */
94
+ embed: undefined;
95
+ /**
96
+ * Override listModels to use OpenRouter's model API with ZDR support
97
+ */
98
+ listModels(config: OpenRouterConfig): Promise<ModelInfo[]>;
99
+ }
100
+ //# sourceMappingURL=openrouter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openrouter.d.ts","sourceRoot":"","sources":["../src/openrouter.ts"],"names":[],"mappings":"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"}