@aeye/openrouter 0.5.0 → 0.7.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 (3) hide show
  1. package/README.md +652 -643
  2. package/aeye-openrouter.md +179 -175
  3. package/package.json +71 -71
@@ -1,175 +1,179 @@
1
- # @aeye/openrouter
2
-
3
- One-line purpose: OpenRouter provider for `@aeye/ai` — one API key, hundreds of models from many upstream providers (OpenAI, Anthropic, Google, xAI, Meta, Mistral, …) with provider routing, fallback models, plugins, server tools, ZDR, reasoning, media endpoints, and real cost reporting. Built as a subclass of `@aeye/openai`'s `OpenAIProvider`.
4
-
5
- ## When to use
6
-
7
- - You want access to many models/providers through a single endpoint and key.
8
- - You need routing control (preferred providers, fallbacks, price/throughput/latency sorting) or Zero Data Retention.
9
- - You want a dynamic model registry with pricing/capabilities pulled from OpenRouter.
10
-
11
- It also serves image generation/editing (through chat with the image modality), speech, transcription, and embeddings (through OpenRouter's OpenAI-compatible endpoints). Image and transcription streaming are not offered; those fall back to the non-streaming methods.
12
-
13
- ## Install / import
14
-
15
- ```bash
16
- npm install @aeye/openrouter
17
- ```
18
-
19
- `@aeye/openai`, `@aeye/ai`, `@aeye/core`, and `openai` (v7) ship as dependencies. Requires Node >= 22.
20
-
21
- ```typescript
22
- import {
23
- OpenRouterProvider,
24
- type OpenRouterConfig,
25
- // dynamic model registry
26
- OpenRouterModelSource,
27
- type OpenRouterSourceConfig,
28
- fetchModels,
29
- fetchZDRModels,
30
- fetchEndpointMetrics,
31
- convertOpenRouterModel,
32
- } from '@aeye/openrouter';
33
- ```
34
-
35
- The provider's registry name is `openrouter`.
36
-
37
- ## Register with an `@aeye/ai` instance
38
-
39
- ```typescript
40
- import { AI } from '@aeye/ai';
41
- import { OpenRouterProvider } from '@aeye/openrouter';
42
-
43
- const openrouter = new OpenRouterProvider({
44
- apiKey: process.env.OPENROUTER_API_KEY!,
45
- });
46
-
47
- const ai = AI.with().providers({ openrouter }).create({ /* ... */ });
48
-
49
- // Model ids use provider/model form
50
- await ai.chat.get(
51
- { messages: [{ role: 'user', content: 'Hi' }] },
52
- { metadata: { model: 'anthropic/claude-sonnet-4.5' } }
53
- );
54
-
55
- await ai.chat.get(
56
- { messages: [{ role: 'user', content: 'Hi' }] },
57
- { metadata: { model: 'google/gemini-2.5-flash' } }
58
- );
59
- ```
60
-
61
- ## Authentication / credentials
62
-
63
- - `apiKey` is required on the config (inherited from `OpenAIConfig`). Use `process.env.OPENROUTER_API_KEY`.
64
- - `createClient` sets the base URL to `https://openrouter.ai/api/v1` (override via `baseURL`).
65
- - The standalone `OpenRouterModelSource`, `fetchModels`, and `fetchZDRModels` will fall back to `process.env.OPENROUTER_API_KEY` if no key is passed.
66
- - Optional attribution headers: `defaultParams.siteUrl` → `HTTP-Referer`, `defaultParams.appName` → `X-Title`.
67
-
68
- ## Configuration (`OpenRouterConfig`)
69
-
70
- `OpenRouterConfig extends Omit<OpenAIConfig, 'api'>`, so the OpenAI fields apply (`apiKey`, `baseURL`, `organization`, `project`, `store`, `retry`, `retryEvents`, `hooks`, `defaultModels`) except `api`: requests always go through Chat Completions. It adds `defaultParams`:
71
-
72
- ```typescript
73
- const openrouter = new OpenRouterProvider({
74
- apiKey: process.env.OPENROUTER_API_KEY!,
75
- defaultParams: {
76
- siteUrl: 'https://myapp.com', // -> HTTP-Referer
77
- appName: 'my-app', // -> X-Title
78
- providers: {
79
- order: ['Anthropic', 'OpenAI'], // preferred upstream order
80
- allowFallbacks: true, // -> allow_fallbacks
81
- requireParameters: false, // -> require_parameters
82
- dataCollection: 'deny', // 'deny' | 'allow' -> data_collection
83
- zdr: true, // zero data retention
84
- enforceDistillableText: false, // -> enforce_distillable_text
85
- only: ['Anthropic'], // whitelist upstreams
86
- ignore: ['Together'], // blacklist upstreams
87
- quantizations: ['bf16', 'fp16'], // int4|int8|fp4|mxfp4|nvfp4|fp6|fp8|mxfp8|fp16|bf16|fp32|unknown
88
- sort: 'price', // 'price' | 'throughput' | 'latency' | 'exacto', or { by, partition: 'model' | 'none' }
89
- preferredMinThroughput: 50, // -> preferred_min_throughput (tokens/s, median)
90
- preferredMaxLatency: 2, // -> preferred_max_latency (seconds, median)
91
- maxPrice: { prompt: 10, completion: 30, image: 0 }, // $/M tokens (image: $/image); also audio, request
92
- },
93
- fallbackModels: ['openai/gpt-5.4-mini'], // -> models
94
- plugins: [{ id: 'response-healing' }], // file-parser | response-healing | context-compression
95
- },
96
- });
97
- ```
98
-
99
- `defaultParams.providers` is mapped onto OpenRouter's `provider` request object (camelCase → snake_case is handled internally). `transforms` is deprecated: `transforms: ['middle-out']` is sent as the `context-compression` plugin. `requireParameters` left undefined is switched on automatically for strict `json_schema` requests.
100
-
101
- ## Provider routing
102
-
103
- ```typescript
104
- const openrouter = new OpenRouterProvider({
105
- apiKey: process.env.OPENROUTER_API_KEY!,
106
- defaultParams: {
107
- providers: {
108
- order: ['Anthropic'], // try Anthropic first
109
- allowFallbacks: true, // then fall back to others
110
- sort: 'throughput', // optimize for speed
111
- },
112
- },
113
- });
114
- ```
115
-
116
- ## Reasoning
117
-
118
- If a request sets `request.reason`, the provider emits OpenRouter's `reasoning` object: `enabled: true`, either `max_tokens` (from `maxTokens`) or `effort` (clamped to the model's `reasoningEfforts`), never both, plus `exclude`, `summary`, `mode`, and `context`. No separate `reasoning_effort` is sent. Reasoning text and `reasoning_details` are parsed back onto `response.reasoning` (and streamed via chunks), and replayed from assistant messages on later turns.
119
-
120
- ## Server tools and other request features
121
-
122
- - `hostedTools` run as OpenRouter server tools through chat: `web_search` → `openrouter:web_search` (`maxResults`, `allowedDomains`, `blockedDomains` → `excluded_domains`), `web_fetch` → `openrouter:web_fetch`, `image_generation` → `openrouter:image_generation`. `file_search`, `code_interpreter`, and `mcp` throw `ProviderError`. Calls are counted in `usage.tools`.
123
- - `cacheBreakpoint` on content goes as `cache_control: { type: 'ephemeral' }`.
124
- - `modalities` with `'image'` is passed through; images come back on `response.images` (streamed or not).
125
- - `userKey` goes as `user`. `moderate` is not sent (OpenRouter ignores OpenAI's inline moderation).
126
-
127
- ## Dynamic model registry (`OpenRouterModelSource`)
128
-
129
- Use OpenRouter as a `ModelSource` to populate the registry with live pricing, capabilities, context windows, and ZDR flags. It lists every output modality (chat, image, speech, transcription, and embedding models); capabilities come from each modality (`vision`, `files`, `videoInput`, `hearing`, `image`, `audio`, `embedding`); pricing covers cache read/write, audio, image tokens, and web search per call; `reasoningEfforts` and `retiresAt` (from `expiration_date`) are filled in:
130
-
131
- ```typescript
132
- import { OpenRouterModelSource } from '@aeye/openrouter';
133
-
134
- const ai = AI.with()
135
- .providers({ openrouter })
136
- .create({
137
- modelSources: [
138
- new OpenRouterModelSource({
139
- apiKey: process.env.OPENROUTER_API_KEY!,
140
- includeZDR: true, // default true; fetches the ZDR endpoint too
141
- }),
142
- ],
143
- });
144
-
145
- await ai.models.refresh();
146
- ```
147
-
148
- `fetchModels(apiKey?)`, `fetchZDRModels(apiKey?)`, and `fetchEndpointMetrics(modelId, apiKey?)` (best median latency in ms, throughput in tokens/s, and uptime across a model's providers) are exported for direct use.
149
-
150
- ## Supported capabilities
151
-
152
- Capabilities depend on the selected model, but the provider class supports: **chat, streaming, tools, hosted (server) tools, structured output / JSON mode, reasoning, vision, files, video input, image generation and editing, audio output, speech, transcription, embeddings** (per model). Capabilities are auto-detected from each model's input/output modalities and `supported_parameters` during model conversion.
153
-
154
- Default models: `google/gemini-2.5-flash-image` (image generate/edit), `openai/gpt-5.4-mini` (image analysis), `openai/gpt-transcribe`, `openai/text-embedding-3-small`; speech and chat have none.
155
-
156
- Not offered (overridden to `undefined`, so the non-streaming method is used): image generation streaming, image edit streaming, transcription streaming.
157
-
158
- ## Cost tracking
159
-
160
- OpenRouter returns actual spend, surfaced on usage:
161
-
162
- ```typescript
163
- const response = await ai.chat.get({ messages });
164
- console.log(response.usage?.cost); // real cost reported by OpenRouter, including the upstream bill for BYOK requests
165
- ```
166
-
167
- (Available on both non-streaming responses and streamed usage chunks.)
168
-
169
- ## Gotchas
170
-
171
- - **Images go through chat.** `generateImage` / `editImage` send a chat request with `modalities: ['image', 'text']` (running through the chat hooks); `size` becomes an `image_config.aspect_ratio`, and an edit's `image` + `references` are sent as input images. GPT Image options such as `quality` and `outputFormat` are not sent.
172
- - Model ids are `provider/model` slugs (e.g. `anthropic/claude-sonnet-4.5`), not raw OpenAI ids.
173
- - Strict/structured output behavior is inherited from `OpenAIProvider` (best-effort, silent fallback to the family's non-strict descriptor), but the accepted dialects are widened here: `supportedStrictFamilies = {'openai', 'anthropic', 'google', 'xai'}`, because the model id's `family/…` prefix names the upstream that actually serves the request. This applies to **tool** schemas as well as `response_format`; before 0.4.x the inherited `{'openai'}` quietly forced every non-OpenAI model's tools through LENIENT.
174
- - Assistant reasoning is split into a separate preceding message during conversion to work around OpenRouter not round-tripping reasoning attached to content — expect an extra assistant message in transformed payloads.
175
- - ZDR (`zdr: true` / `dataCollection: 'deny'`) only constrains upstreams that honor it; combine with `only`/`ignore` for strict guarantees.
1
+ # @aeye/openrouter
2
+
3
+ One-line purpose: OpenRouter provider for `@aeye/ai` — one API key, hundreds of models from many upstream providers (OpenAI, Anthropic, Google, xAI, Meta, Mistral, …) with provider routing, fallback models, plugins, server tools, ZDR, reasoning, media endpoints, and real cost reporting. Built as a subclass of `@aeye/openai`'s `OpenAIProvider`.
4
+
5
+ ## When to use
6
+
7
+ - You want access to many models/providers through a single endpoint and key.
8
+ - You need routing control (preferred providers, fallbacks, price/throughput/latency sorting) or Zero Data Retention.
9
+ - You want a dynamic model registry with pricing/capabilities pulled from OpenRouter.
10
+
11
+ It also serves image generation/editing (through chat with the image modality), speech, transcription, and embeddings (through OpenRouter's OpenAI-compatible endpoints). Image and transcription streaming are not offered; those fall back to the non-streaming methods.
12
+
13
+ ## Install / import
14
+
15
+ ```bash
16
+ npm install @aeye/openrouter
17
+ ```
18
+
19
+ `@aeye/openai`, `@aeye/ai`, `@aeye/core`, and `openai` (v7) ship as dependencies. Requires Node >= 22.
20
+
21
+ ```typescript
22
+ import {
23
+ OpenRouterProvider,
24
+ type OpenRouterConfig,
25
+ // dynamic model registry
26
+ OpenRouterModelSource,
27
+ type OpenRouterSourceConfig,
28
+ fetchModels,
29
+ fetchZDRModels,
30
+ fetchEndpointMetrics,
31
+ convertOpenRouterModel,
32
+ } from '@aeye/openrouter';
33
+ ```
34
+
35
+ The provider's registry name is `openrouter`.
36
+
37
+ ## Register with an `@aeye/ai` instance
38
+
39
+ ```typescript
40
+ import { AI } from '@aeye/ai';
41
+ import { OpenRouterProvider } from '@aeye/openrouter';
42
+
43
+ const openrouter = new OpenRouterProvider({
44
+ apiKey: process.env.OPENROUTER_API_KEY!,
45
+ });
46
+
47
+ const ai = AI.with().providers({ openrouter }).create({ /* ... */ });
48
+
49
+ // Model ids use provider/model form
50
+ await ai.chat.get(
51
+ { messages: [{ role: 'user', content: 'Hi' }] },
52
+ { metadata: { model: 'anthropic/claude-sonnet-4.5' } }
53
+ );
54
+
55
+ await ai.chat.get(
56
+ { messages: [{ role: 'user', content: 'Hi' }] },
57
+ { metadata: { model: 'google/gemini-2.5-flash' } }
58
+ );
59
+ ```
60
+
61
+ ## Authentication / credentials
62
+
63
+ - `apiKey` is required on the config (inherited from `OpenAIConfig`). Use `process.env.OPENROUTER_API_KEY`.
64
+ - `createClient` sets the base URL to `https://openrouter.ai/api/v1` (override via `baseURL`).
65
+ - The standalone `OpenRouterModelSource`, `fetchModels`, and `fetchZDRModels` will fall back to `process.env.OPENROUTER_API_KEY` if no key is passed.
66
+ - Optional attribution headers: `defaultParams.siteUrl` → `HTTP-Referer`, `defaultParams.appName` → `X-Title`.
67
+
68
+ ## Configuration (`OpenRouterConfig`)
69
+
70
+ `OpenRouterConfig extends Omit<OpenAIConfig, 'api'>`, so the OpenAI fields apply (`apiKey`, `baseURL`, `organization`, `project`, `store`, `retry`, `retryEvents`, `hooks`, `defaultModels`) except `api`: requests always go through Chat Completions. It adds `defaultParams`:
71
+
72
+ ```typescript
73
+ const openrouter = new OpenRouterProvider({
74
+ apiKey: process.env.OPENROUTER_API_KEY!,
75
+ defaultParams: {
76
+ siteUrl: 'https://myapp.com', // -> HTTP-Referer
77
+ appName: 'my-app', // -> X-Title
78
+ providers: {
79
+ order: ['Anthropic', 'OpenAI'], // preferred upstream order
80
+ allowFallbacks: true, // -> allow_fallbacks
81
+ requireParameters: false, // -> require_parameters
82
+ dataCollection: 'deny', // 'deny' | 'allow' -> data_collection
83
+ zdr: true, // zero data retention
84
+ enforceDistillableText: false, // -> enforce_distillable_text
85
+ only: ['Anthropic'], // whitelist upstreams
86
+ ignore: ['Together'], // blacklist upstreams
87
+ quantizations: ['bf16', 'fp16'], // int4|int8|fp4|mxfp4|nvfp4|fp6|fp8|mxfp8|fp16|bf16|fp32|unknown
88
+ sort: 'price', // 'price' | 'throughput' | 'latency' | 'exacto', or { by, partition: 'model' | 'none' }
89
+ preferredMinThroughput: 50, // -> preferred_min_throughput (tokens/s, median)
90
+ preferredMaxLatency: 2, // -> preferred_max_latency (seconds, median)
91
+ maxPrice: { prompt: 10, completion: 30, image: 0 }, // $/M tokens (image: $/image); also audio, request
92
+ },
93
+ fallbackModels: ['openai/gpt-5.4-mini'], // -> models
94
+ plugins: [{ id: 'response-healing' }], // file-parser | response-healing | context-compression
95
+ },
96
+ });
97
+ ```
98
+
99
+ `defaultParams.providers` is mapped onto OpenRouter's `provider` request object (camelCase → snake_case is handled internally). `transforms` is deprecated: `transforms: ['middle-out']` is sent as the `context-compression` plugin. `requireParameters` left undefined is switched on automatically for strict `json_schema` requests.
100
+
101
+ ## Provider routing
102
+
103
+ ```typescript
104
+ const openrouter = new OpenRouterProvider({
105
+ apiKey: process.env.OPENROUTER_API_KEY!,
106
+ defaultParams: {
107
+ providers: {
108
+ order: ['Anthropic'], // try Anthropic first
109
+ allowFallbacks: true, // then fall back to others
110
+ sort: 'throughput', // optimize for speed
111
+ },
112
+ },
113
+ });
114
+ ```
115
+
116
+ ## Reasoning
117
+
118
+ If a request sets `request.reason`, the provider emits OpenRouter's `reasoning` object: `enabled: true`, either `max_tokens` (from `maxTokens`) or `effort` (clamped to the model's `reasoningEfforts`), never both, plus `exclude`, `summary`, `mode`, and `context`. No separate `reasoning_effort` is sent. Reasoning text and `reasoning_details` are parsed back onto `response.reasoning` (and streamed via chunks) with `provider: 'openrouter'`, and replayed on the same assistant message on later turns. Reasoning that names another provider (OpenAI directly, Bedrock) is not replayed.
119
+
120
+ ## Server tools and other request features
121
+
122
+ - `hostedTools` run as OpenRouter server tools through chat: `web_search` → `openrouter:web_search` (`maxResults`, `allowedDomains`, `blockedDomains` → `excluded_domains`), `web_fetch` → `openrouter:web_fetch`, `image_generation` → `openrouter:image_generation`. `file_search`, `code_interpreter`, and `mcp` throw `ProviderError`. Calls are counted in `usage.tools`.
123
+ - `cacheBreakpoint` on content goes as `cache_control: { type: 'ephemeral' }`.
124
+ - `modalities` with `'image'` is passed through; images come back on `response.images` (streamed or not).
125
+ - `userKey` goes as `user`. `moderate` is not sent (OpenRouter ignores OpenAI's inline moderation).
126
+ - A strict tool adds the `x-anthropic-beta: structured-outputs-2025-11-13` header (via `chatHeaders`), without which OpenRouter strips `strict` from tools bound for Anthropic.
127
+ - A JSON or schema response format adds a `Respond in JSON.` system message when no message mentions JSON (Alibaba's Qwen rejects JSON mode otherwise).
128
+ - Assistant turns of only tool calls are sent with no content (Qwen's upstream rejects empty text).
129
+ - `rerank` (`/rerank`) and `decide` (alpha decisions endpoint, System One shape) run through `hooks.rerank` / `hooks.decide`. Batches go inline to `/batches`; the whole batch's cost comes back as `job.cost` (results carry token counts only).
130
+
131
+ ## Dynamic model registry (`OpenRouterModelSource`)
132
+
133
+ Use OpenRouter as a `ModelSource` to populate the registry with live pricing, capabilities, context windows, and ZDR flags. It lists every output modality (chat, image, speech, transcription, and embedding models); capabilities come from each modality (`vision`, `files`, `videoInput`, `hearing`, `image`, `audio`, `embedding`); pricing covers cache read/write, audio, image tokens, and web search per call; `reasoningEfforts` and `retiresAt` (from `expiration_date`) are filled in:
134
+
135
+ ```typescript
136
+ import { OpenRouterModelSource } from '@aeye/openrouter';
137
+
138
+ const ai = AI.with()
139
+ .providers({ openrouter })
140
+ .create({
141
+ modelSources: [
142
+ new OpenRouterModelSource({
143
+ apiKey: process.env.OPENROUTER_API_KEY!,
144
+ includeZDR: true, // default true; fetches the ZDR endpoint too
145
+ }),
146
+ ],
147
+ });
148
+
149
+ await ai.models.refresh();
150
+ ```
151
+
152
+ `fetchModels(apiKey?)`, `fetchZDRModels(apiKey?)`, and `fetchEndpointMetrics(modelId, apiKey?)` (best median latency in ms, throughput in tokens/s, and uptime across a model's providers) are exported for direct use.
153
+
154
+ ## Supported capabilities
155
+
156
+ Capabilities depend on the selected model, but the provider class supports: **chat, streaming, tools, hosted (server) tools, structured output / JSON mode, reasoning, vision, files, video input, image generation and editing, audio output, speech, transcription, embeddings** (per model). Capabilities are auto-detected from each model's input/output modalities and `supported_parameters` during model conversion.
157
+
158
+ Default models: `google/gemini-2.5-flash-image` (image generate/edit), `openai/gpt-5.4-mini` (image analysis), `openai/gpt-transcribe`, `openai/text-embedding-3-small`, `cohere/rerank-v3.5` (rerank), `typesafe/jev-1.14` (decision); speech and chat have none.
159
+
160
+ Not offered (overridden to `undefined`, so the non-streaming method is used): image generation streaming, image edit streaming, transcription streaming.
161
+
162
+ ## Cost tracking
163
+
164
+ OpenRouter returns actual spend, surfaced on usage:
165
+
166
+ ```typescript
167
+ const response = await ai.chat.get({ messages });
168
+ console.log(response.usage?.cost); // real cost reported by OpenRouter, including the upstream bill for BYOK requests
169
+ ```
170
+
171
+ (Available on both non-streaming responses and streamed usage chunks.)
172
+
173
+ ## Gotchas
174
+
175
+ - **Images go through chat.** `generateImage` / `editImage` send a chat request with `modalities: ['image', 'text']` (running through the chat hooks); `size` becomes an `image_config.aspect_ratio`, and an edit's `image` + `references` are sent as input images. GPT Image options such as `quality` and `outputFormat` are not sent.
176
+ - Model ids are `provider/model` slugs (e.g. `anthropic/claude-sonnet-4.5`), not raw OpenAI ids.
177
+ - Strict/structured output behavior is inherited from `OpenAIProvider` (best-effort, silent fallback to the family's non-strict descriptor), but the accepted dialects are widened here: `supportedStrictFamilies = {'openai', 'anthropic', 'google', 'xai'}`, because the model id's `family/…` prefix names the upstream that actually serves the request. This applies to **tool** schemas as well as `response_format`; before 0.4.x the inherited `{'openai'}` quietly forced every non-OpenAI model's tools through LENIENT.
178
+ - Assistant reasoning rides on its own assistant message (with that turn's text and tool calls), once even when the message is split into parts; it is not split into a separate message.
179
+ - ZDR (`zdr: true` / `dataCollection: 'deny'`) only constrains upstreams that honor it; combine with `only`/`ignore` for strict guarantees.
package/package.json CHANGED
@@ -1,71 +1,71 @@
1
- {
2
- "name": "@aeye/openrouter",
3
- "version": "0.5.0",
4
- "description": "@aeye OpenRouter - OpenRouter integration for @aeye",
5
- "type": "module",
6
- "main": "dist/index.js",
7
- "types": "dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": {
11
- "types": "./dist/index.d.ts",
12
- "default": "./dist/index.js"
13
- },
14
- "require": {
15
- "types": "./dist/index.d.ts",
16
- "default": "./dist/index.js"
17
- },
18
- "default": "./dist/index.js"
19
- }
20
- },
21
- "scripts": {
22
- "build": "tsc",
23
- "test": "jest",
24
- "test:unit": "jest --testPathIgnorePatterns=__integration__",
25
- "test:integration": "jest --testPathPattern=__integration__",
26
- "test:coverage": "jest --coverage --testPathIgnorePatterns=__integration__",
27
- "test:watch": "jest --watch",
28
- "clean": "rimraf dist tsconfig.tsbuildinfo",
29
- "typecheck": "tsc --noEmit"
30
- },
31
- "keywords": [
32
- "ai",
33
- "openrouter",
34
- "typescript"
35
- ],
36
- "author": "ClickerMonkey",
37
- "license": "GPL-3.0",
38
- "repository": {
39
- "type": "git",
40
- "url": "https://github.com/ClickerMonkey/aeye.git",
41
- "directory": "packages/openrouter"
42
- },
43
- "files": [
44
- "dist",
45
- "README.md",
46
- "LICENSE",
47
- "aeye-*.md"
48
- ],
49
- "dependencies": {
50
- "@aeye/ai": "^0.4.0",
51
- "@aeye/core": "^0.6.0",
52
- "@aeye/openai": "^0.4.0",
53
- "openai": "^7.45.1"
54
- },
55
- "devDependencies": {
56
- "@types/jest": "^30.0.0",
57
- "jest": "^30.2.0",
58
- "ts-jest": "^29.4.5",
59
- "typescript": "^5.9.3"
60
- },
61
- "publishConfig": {
62
- "access": "public"
63
- },
64
- "engines": {
65
- "node": ">=22.0.0"
66
- },
67
- "homepage": "https://github.com/ClickerMonkey/aeye#readme",
68
- "bugs": {
69
- "url": "https://github.com/ClickerMonkey/aeye/issues"
70
- }
71
- }
1
+ {
2
+ "name": "@aeye/openrouter",
3
+ "version": "0.7.0",
4
+ "description": "@aeye OpenRouter - OpenRouter integration for @aeye",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.ts",
16
+ "default": "./dist/index.js"
17
+ },
18
+ "default": "./dist/index.js"
19
+ }
20
+ },
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "test": "jest",
24
+ "test:unit": "jest --testPathIgnorePatterns=__integration__",
25
+ "test:integration": "jest --testPathPattern=__integration__",
26
+ "test:coverage": "jest --coverage --testPathIgnorePatterns=__integration__",
27
+ "test:watch": "jest --watch",
28
+ "clean": "rimraf dist tsconfig.tsbuildinfo",
29
+ "typecheck": "tsc --noEmit"
30
+ },
31
+ "keywords": [
32
+ "ai",
33
+ "openrouter",
34
+ "typescript"
35
+ ],
36
+ "author": "ClickerMonkey",
37
+ "license": "GPL-3.0",
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/ClickerMonkey/aeye.git",
41
+ "directory": "packages/openrouter"
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "README.md",
46
+ "LICENSE",
47
+ "aeye-*.md"
48
+ ],
49
+ "dependencies": {
50
+ "@aeye/ai": "^0.7.0",
51
+ "@aeye/core": "^0.7.0",
52
+ "@aeye/openai": "^0.7.0",
53
+ "openai": "^7.45.1"
54
+ },
55
+ "devDependencies": {
56
+ "@types/jest": "^30.0.0",
57
+ "jest": "^30.2.0",
58
+ "ts-jest": "^29.4.5",
59
+ "typescript": "^5.9.3"
60
+ },
61
+ "publishConfig": {
62
+ "access": "public"
63
+ },
64
+ "engines": {
65
+ "node": ">=22.0.0"
66
+ },
67
+ "homepage": "https://github.com/ClickerMonkey/aeye#readme",
68
+ "bugs": {
69
+ "url": "https://github.com/ClickerMonkey/aeye/issues"
70
+ }
71
+ }