@absolutejs/ai 0.0.51 → 0.0.53
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.
- package/README.md +107 -8
- package/dist/ai/index.js +317 -13
- package/dist/ai/index.js.map +4 -4
- package/dist/ai/providers/openrouter.js +318 -14
- package/dist/ai/providers/openrouter.js.map +4 -4
- package/dist/ai/providers/openrouterSDK.js +37 -0
- package/dist/ai/providers/openrouterSDK.js.map +10 -0
- package/dist/src/ai/index.d.ts +2 -2
- package/dist/src/ai/providers/openrouter.d.ts +153 -5
- package/dist/src/ai/providers/openrouterClient.d.ts +380 -10
- package/dist/src/ai/providers/openrouterSDK.d.ts +21 -0
- package/package.json +10 -2
package/README.md
CHANGED
|
@@ -111,8 +111,29 @@ const provider = openrouter({
|
|
|
111
111
|
The adapter intentionally has no built-in geopolitical model list. Omitting
|
|
112
112
|
`allowedModels` exposes the full OpenRouter catalog; applications that need a
|
|
113
113
|
restricted catalog can define their own `allowedModels` and `allowedProviders`
|
|
114
|
-
policy.
|
|
115
|
-
|
|
114
|
+
policy. Auto Router is fully supported with `openrouter/auto` (or
|
|
115
|
+
`openrouter/auto-beta`), a sticky `sessionId`, and its typed plugin controls:
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
const provider = openrouter({
|
|
119
|
+
apiKey: process.env.OPENROUTER_API_KEY,
|
|
120
|
+
// Omit this for unrestricted access to every OpenRouter model.
|
|
121
|
+
allowedModels: ["openrouter/auto", "anthropic/*", "openai/*"],
|
|
122
|
+
requestOptions: {
|
|
123
|
+
sessionId: conversationId,
|
|
124
|
+
plugins: [
|
|
125
|
+
{
|
|
126
|
+
id: "auto-router",
|
|
127
|
+
cost_tier: "low",
|
|
128
|
+
allowed_models: ["anthropic/*", "openai/*"],
|
|
129
|
+
},
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Under a strict policy, Auto Router's `allowed_models` is checked locally along
|
|
136
|
+
with fallback, Fusion, advisor, subagent, and other indirectly selected models.
|
|
116
137
|
|
|
117
138
|
Provider usage callbacks include OpenRouter's reported `costCredits`,
|
|
118
139
|
`upstreamInferenceCostCredits`, cache-read/write token counts, and reasoning
|
|
@@ -149,7 +170,10 @@ message transforms, native reasoning controls, prompt and response caching,
|
|
|
149
170
|
text-plus-audio output, verbosity, user attribution, and an `extraBody` escape
|
|
150
171
|
hatch for new OpenRouter parameters. The escape hatch cannot replace models,
|
|
151
172
|
fallbacks, providers, presets, messages, plugins, or tools; those fields use
|
|
152
|
-
policy-aware typed options instead.
|
|
173
|
+
policy-aware typed options instead. Advisor, Fusion, Shell, Subagent, model
|
|
174
|
+
search, web search/fetch, image generation, Datetime, and Apply Patch server
|
|
175
|
+
tools have typed wire parameters and documented range checks. OpenRouter's old
|
|
176
|
+
`web` plugin is deprecated; use `openrouter:web_search` instead.
|
|
153
177
|
|
|
154
178
|
URL images and PDFs, base64 audio, and URL/base64 video inputs use the ordinary
|
|
155
179
|
AbsoluteJS content-block contract. URL citations are emitted as `citation`
|
|
@@ -161,8 +185,9 @@ metadata when reported.
|
|
|
161
185
|
|
|
162
186
|
`createOpenRouterClient()` covers model/provider discovery, embeddings,
|
|
163
187
|
reranking, streamed and non-streamed image generation, reusable files,
|
|
164
|
-
Responses, speech, transcription, video jobs and downloads, batches,
|
|
165
|
-
|
|
188
|
+
Responses, speech, typed transcription, video jobs and downloads, beta batches,
|
|
189
|
+
presets, workspaces and budgets, activity/analytics, task classifications,
|
|
190
|
+
credits, key metadata, and generation content. It also exports
|
|
166
191
|
`verifyOpenRouterWebhookSignature()` for video completion webhooks. Its typed
|
|
167
192
|
operations enforce the same model allowlist. `request()` and `requestRaw()` are
|
|
168
193
|
forward-compatible access to new or administrative OpenRouter endpoints.
|
|
@@ -190,16 +215,90 @@ const reranked = await openrouterClient.rerank({
|
|
|
190
215
|
query: "cost controls",
|
|
191
216
|
documents: ["response caching", "CSS layout"],
|
|
192
217
|
});
|
|
218
|
+
|
|
219
|
+
// Response healing is documented for non-streaming structured responses.
|
|
220
|
+
const healed = await openrouterClient.chat({
|
|
221
|
+
model: "anthropic/claude-sonnet-4.6",
|
|
222
|
+
messages: [{ role: "user", content: "Return a JSON object" }],
|
|
223
|
+
response_format: { type: "json_object" },
|
|
224
|
+
plugins: [{ id: "response-healing" }],
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const batch = await openrouterClient.createBatch({
|
|
228
|
+
endpoint: "/v1/chat/completions",
|
|
229
|
+
model: "anthropic/claude-sonnet-4.6",
|
|
230
|
+
requests: [
|
|
231
|
+
{ custom_id: "one", body: { messages: [{ role: "user", content: "Hi" }] } },
|
|
232
|
+
],
|
|
233
|
+
});
|
|
234
|
+
const completed = await openrouterClient.waitForBatch(batch.id, {
|
|
235
|
+
signal: abortController.signal,
|
|
236
|
+
timeoutMs: 60_000,
|
|
237
|
+
});
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Batch traffic uses OpenRouter's separate `/api/beta/batches` API and returns
|
|
241
|
+
inline typed results. `estimateOpenRouterModelCost()` calculates prompt,
|
|
242
|
+
completion, request, image, web-search, reasoning, and cache costs directly from
|
|
243
|
+
model-discovery pricing fields.
|
|
244
|
+
|
|
245
|
+
OAuth helpers cover S256 PKCE, web and headless authorization URLs, code
|
|
246
|
+
exchange, authenticated code creation, and user key deep-links:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
const pkce = await generateOpenRouterPKCE();
|
|
250
|
+
const authorizationUrl = createOpenRouterAuthorizationUrl({
|
|
251
|
+
callbackUrl: "https://example.com/openrouter/callback",
|
|
252
|
+
codeChallenge: pkce.codeChallenge,
|
|
253
|
+
codeChallengeMethod: pkce.codeChallengeMethod,
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
const { key } = await exchangeOpenRouterAuthCode({
|
|
257
|
+
code,
|
|
258
|
+
code_verifier: pkce.codeVerifier,
|
|
259
|
+
code_challenge_method: pkce.codeChallengeMethod,
|
|
260
|
+
});
|
|
193
261
|
```
|
|
194
262
|
|
|
263
|
+
### Complete OpenRouter management SDK
|
|
264
|
+
|
|
265
|
+
The inference adapter stays small and policy-aware. The separate
|
|
266
|
+
`@absolutejs/ai/openrouter/sdk` entry point configures and exposes OpenRouter's
|
|
267
|
+
official OpenAPI-generated TypeScript SDK for the complete administrative and
|
|
268
|
+
data surface:
|
|
269
|
+
|
|
270
|
+
```ts
|
|
271
|
+
import { createOpenRouterSDK } from "@absolutejs/ai/openrouter/sdk";
|
|
272
|
+
|
|
273
|
+
const openrouterAdmin = createOpenRouterSDK({
|
|
274
|
+
tokenSource: getRotatingManagementKey,
|
|
275
|
+
appName: "My AbsoluteJS App",
|
|
276
|
+
appUrl: "https://example.com",
|
|
277
|
+
timeoutMs: 15_000,
|
|
278
|
+
retryConfig: { strategy: "backoff" },
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
const keys = await openrouterAdmin.apiKeys.list();
|
|
282
|
+
const guardrails = await openrouterAdmin.guardrails.list();
|
|
283
|
+
const embeddingModels = await openrouterAdmin.embeddings.listModels();
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
This entry point includes API-key management, BYOK, guardrails and assignments,
|
|
287
|
+
observability destinations, organizations, SCIM, workspaces, public datasets,
|
|
288
|
+
benchmarks, typed pagination, retries, per-call timeouts, and abort signals. It
|
|
289
|
+
tracks compatible patch releases of OpenRouter's generated SDK so new OpenAPI
|
|
290
|
+
fields do not depend on a handwritten AbsoluteJS type update. Normal
|
|
291
|
+
`@absolutejs/ai/openrouter` imports do not load this management surface.
|
|
292
|
+
|
|
195
293
|
For a strict model-origin policy, also assign an OpenRouter key/workspace
|
|
196
294
|
guardrail with the same model allowlist. Provider allowlists restrict where a
|
|
197
295
|
model runs; they do not identify who developed it. Presets and router aliases
|
|
198
296
|
must be explicitly allowed, because their resolved model is controlled outside
|
|
199
297
|
the request. The raw client is intentionally unopinionated and should be limited
|
|
200
|
-
to trusted server-side administration code. OpenRouter
|
|
201
|
-
|
|
202
|
-
|
|
298
|
+
to trusted server-side administration code. OpenRouter currently documents
|
|
299
|
+
reporting generation feedback through Chatroom and Logs, not through a public
|
|
300
|
+
feedback API, so AbsoluteJS exposes generation IDs/content without inventing an
|
|
301
|
+
unstable endpoint.
|
|
203
302
|
|
|
204
303
|
Use `openrouterResponses(config)` when an AbsoluteJS agent should stream through
|
|
205
304
|
OpenRouter's stateless Responses API, or `openrouterMessages(config)` for the
|
package/dist/ai/index.js
CHANGED
|
@@ -2584,7 +2584,46 @@ var ollama = (config2 = {}) => {
|
|
|
2584
2584
|
};
|
|
2585
2585
|
|
|
2586
2586
|
// src/ai/providers/openrouterClient.ts
|
|
2587
|
+
var OPENROUTER_PRICING_KEYS = [
|
|
2588
|
+
"prompt",
|
|
2589
|
+
"completion",
|
|
2590
|
+
"request",
|
|
2591
|
+
"image",
|
|
2592
|
+
"web_search",
|
|
2593
|
+
"internal_reasoning",
|
|
2594
|
+
"input_cache_read",
|
|
2595
|
+
"input_cache_write"
|
|
2596
|
+
];
|
|
2597
|
+
var estimateOpenRouterCost = (pricing, units) => {
|
|
2598
|
+
const components = {};
|
|
2599
|
+
let total = 0;
|
|
2600
|
+
for (const key of OPENROUTER_PRICING_KEYS) {
|
|
2601
|
+
const quantity = units[key];
|
|
2602
|
+
if (quantity === undefined)
|
|
2603
|
+
continue;
|
|
2604
|
+
if (!Number.isFinite(quantity) || quantity < 0)
|
|
2605
|
+
throw new Error(`OpenRouter ${key} units must be non-negative`);
|
|
2606
|
+
const rawPrice = pricing[key];
|
|
2607
|
+
if (rawPrice === undefined)
|
|
2608
|
+
continue;
|
|
2609
|
+
const price = Number(rawPrice);
|
|
2610
|
+
if (!Number.isFinite(price) || price < 0)
|
|
2611
|
+
throw new Error(`OpenRouter ${key} price must be non-negative`);
|
|
2612
|
+
components[key] = price * quantity;
|
|
2613
|
+
total += components[key];
|
|
2614
|
+
}
|
|
2615
|
+
return { components, total };
|
|
2616
|
+
};
|
|
2617
|
+
var estimateOpenRouterModelCost = (model, units) => estimateOpenRouterCost(model.pricing ?? {}, units);
|
|
2587
2618
|
var DEFAULT_BASE_URL6 = "https://openrouter.ai/api/v1";
|
|
2619
|
+
var DEFAULT_BATCH_BASE_URL = "https://openrouter.ai/api/beta";
|
|
2620
|
+
var DEFAULT_SITE_URL = "https://openrouter.ai";
|
|
2621
|
+
var TERMINAL_BATCH_STATUSES = new Set([
|
|
2622
|
+
"completed",
|
|
2623
|
+
"failed",
|
|
2624
|
+
"expired",
|
|
2625
|
+
"cancelled"
|
|
2626
|
+
]);
|
|
2588
2627
|
var withoutLatestPrefix = (model) => model.startsWith("~") ? model.slice(1) : model;
|
|
2589
2628
|
var openRouterModelMatchesRule = (model, rule) => {
|
|
2590
2629
|
const normalizedModel = withoutLatestPrefix(model);
|
|
@@ -2598,6 +2637,22 @@ var assertAllowedModel = (model, allowedModels) => {
|
|
|
2598
2637
|
return;
|
|
2599
2638
|
throw new Error(`OpenRouter model "${model}" is not allowed`);
|
|
2600
2639
|
};
|
|
2640
|
+
var assertAllowedModelsInValue = (value, allowedModels, key = "") => {
|
|
2641
|
+
if (key === "model" && typeof value === "string")
|
|
2642
|
+
assertAllowedModel(value, allowedModels);
|
|
2643
|
+
if ((key === "models" || key === "analysis_models" || key === "allowed_models") && Array.isArray(value)) {
|
|
2644
|
+
for (const model of value)
|
|
2645
|
+
if (typeof model === "string")
|
|
2646
|
+
assertAllowedModel(model, allowedModels);
|
|
2647
|
+
}
|
|
2648
|
+
if (Array.isArray(value)) {
|
|
2649
|
+
for (const item of value)
|
|
2650
|
+
assertAllowedModelsInValue(item, allowedModels);
|
|
2651
|
+
} else if (value && typeof value === "object") {
|
|
2652
|
+
for (const [childKey, child] of Object.entries(value))
|
|
2653
|
+
assertAllowedModelsInValue(child, allowedModels, childKey);
|
|
2654
|
+
}
|
|
2655
|
+
};
|
|
2601
2656
|
var normalizePath = (path) => path.startsWith("/") ? path : `/${path}`;
|
|
2602
2657
|
var encodeModelPath = (model) => model.split("/").map(encodeURIComponent).join("/");
|
|
2603
2658
|
var withQuery = (url, query) => {
|
|
@@ -2648,6 +2703,54 @@ var parseImageSSE = async function* (response) {
|
|
|
2648
2703
|
}
|
|
2649
2704
|
};
|
|
2650
2705
|
var toBytes = (value) => typeof value === "string" ? new TextEncoder().encode(value) : value;
|
|
2706
|
+
var toBase64Url = (bytes) => {
|
|
2707
|
+
let binary = "";
|
|
2708
|
+
for (const byte of bytes)
|
|
2709
|
+
binary += String.fromCharCode(byte);
|
|
2710
|
+
return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
|
|
2711
|
+
};
|
|
2712
|
+
var generateOpenRouterPKCE = async () => {
|
|
2713
|
+
const random = crypto.getRandomValues(new Uint8Array(32));
|
|
2714
|
+
const codeVerifier = toBase64Url(random);
|
|
2715
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(codeVerifier));
|
|
2716
|
+
return {
|
|
2717
|
+
codeChallenge: toBase64Url(new Uint8Array(digest)),
|
|
2718
|
+
codeChallengeMethod: "S256",
|
|
2719
|
+
codeVerifier
|
|
2720
|
+
};
|
|
2721
|
+
};
|
|
2722
|
+
var createOpenRouterAuthorizationUrl = (options = {}) => {
|
|
2723
|
+
const url = new URL("/auth", options.baseUrl ?? DEFAULT_SITE_URL);
|
|
2724
|
+
if (options.callbackUrl)
|
|
2725
|
+
url.searchParams.set("callback_url", options.callbackUrl);
|
|
2726
|
+
if (options.codeChallenge)
|
|
2727
|
+
url.searchParams.set("code_challenge", options.codeChallenge);
|
|
2728
|
+
if (options.codeChallengeMethod)
|
|
2729
|
+
url.searchParams.set("code_challenge_method", options.codeChallengeMethod);
|
|
2730
|
+
if (options.keyLabel)
|
|
2731
|
+
url.searchParams.set("key_label", options.keyLabel);
|
|
2732
|
+
return url.toString();
|
|
2733
|
+
};
|
|
2734
|
+
var exchangeOpenRouterAuthCode = async (body, options = {}) => {
|
|
2735
|
+
const response = await (options.fetch ?? globalThis.fetch)(`${(options.baseUrl ?? DEFAULT_BASE_URL6).replace(/\/$/, "")}/auth/keys`, {
|
|
2736
|
+
body: JSON.stringify(body),
|
|
2737
|
+
headers: { "Content-Type": "application/json" },
|
|
2738
|
+
method: "POST"
|
|
2739
|
+
});
|
|
2740
|
+
if (!response.ok)
|
|
2741
|
+
throw ProviderError.fromResponse("openrouter", response.status, await response.text());
|
|
2742
|
+
return response.json();
|
|
2743
|
+
};
|
|
2744
|
+
var createOpenRouterKeyLinks = async (key, siteUrl = DEFAULT_SITE_URL) => {
|
|
2745
|
+
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(key)));
|
|
2746
|
+
const hash = Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
2747
|
+
const root = siteUrl.replace(/\/$/, "");
|
|
2748
|
+
return {
|
|
2749
|
+
hash,
|
|
2750
|
+
logsUrl: `${root}/logs?api_key_hash=${hash}`,
|
|
2751
|
+
settingsUrl: `${root}/keys/${hash}`
|
|
2752
|
+
};
|
|
2753
|
+
};
|
|
2651
2754
|
var hexToBytes = (hex) => {
|
|
2652
2755
|
if (!/^[0-9a-f]+$/iu.test(hex) || hex.length % 2 !== 0)
|
|
2653
2756
|
return;
|
|
@@ -2693,9 +2796,11 @@ var createOpenRouterClient = (config2) => {
|
|
|
2693
2796
|
if (!config2.apiKey && !config2.tokenSource)
|
|
2694
2797
|
throw new Error("createOpenRouterClient() requires either apiKey or tokenSource");
|
|
2695
2798
|
const baseUrl = (config2.baseUrl ?? DEFAULT_BASE_URL6).replace(/\/$/, "");
|
|
2799
|
+
const batchBaseUrl = (config2.batchBaseUrl ?? (config2.baseUrl ? new URL("../beta", `${baseUrl}/`).toString() : DEFAULT_BATCH_BASE_URL)).replace(/\/$/, "");
|
|
2696
2800
|
const fetchImpl = config2.fetch ?? globalThis.fetch;
|
|
2697
2801
|
const allowedModels = config2.allowedModels ? [...config2.allowedModels] : undefined;
|
|
2698
|
-
const
|
|
2802
|
+
const defaultWorkspaceId = config2.workspaceId;
|
|
2803
|
+
const requestRawAt = async (rootUrl, path, options = {}) => {
|
|
2699
2804
|
const token = config2.tokenSource ? await Promise.resolve(config2.tokenSource()) : config2.apiKey;
|
|
2700
2805
|
const suppliedHeaders = typeof config2.headers === "function" ? await config2.headers() : config2.headers ?? {};
|
|
2701
2806
|
const headers = new Headers(suppliedHeaders);
|
|
@@ -2709,13 +2814,16 @@ var createOpenRouterClient = (config2) => {
|
|
|
2709
2814
|
body = JSON.stringify(options.body);
|
|
2710
2815
|
}
|
|
2711
2816
|
const { query, ...requestInit } = options;
|
|
2712
|
-
const response = await fetchImpl(withQuery(`${
|
|
2817
|
+
const response = await fetchImpl(withQuery(`${rootUrl}${normalizePath(path)}`, options.query), { ...requestInit, body, headers });
|
|
2713
2818
|
if (!response.ok) {
|
|
2714
2819
|
throw ProviderError.fromResponse("openrouter", response.status, await response.text());
|
|
2715
2820
|
}
|
|
2716
2821
|
return response;
|
|
2717
2822
|
};
|
|
2823
|
+
const requestRaw = (path, options = {}) => requestRawAt(baseUrl, path, options);
|
|
2718
2824
|
const request = async (path, options = {}) => (await requestRaw(path, options)).json();
|
|
2825
|
+
const requestBatch = async (path, options = {}) => (await requestRawAt(batchBaseUrl, path, options)).json();
|
|
2826
|
+
const getBatch = (id) => requestBatch(`/batches/${encodeURIComponent(id)}`);
|
|
2719
2827
|
const listModels = async (query) => {
|
|
2720
2828
|
const result = await request("/models", { query });
|
|
2721
2829
|
if (!allowedModels)
|
|
@@ -2734,10 +2842,52 @@ var createOpenRouterClient = (config2) => {
|
|
|
2734
2842
|
};
|
|
2735
2843
|
};
|
|
2736
2844
|
return {
|
|
2737
|
-
|
|
2845
|
+
addWorkspaceMembers: (id, userIds) => request(`/workspaces/${encodeURIComponent(id)}/members/add`, { body: { user_ids: [...userIds] }, method: "POST" }),
|
|
2846
|
+
createAuthCode: (body) => request("/auth/keys/code", {
|
|
2847
|
+
body: {
|
|
2848
|
+
...body,
|
|
2849
|
+
workspace_id: body.workspace_id ?? defaultWorkspaceId
|
|
2850
|
+
},
|
|
2738
2851
|
method: "POST"
|
|
2739
2852
|
}),
|
|
2740
|
-
|
|
2853
|
+
chat: (body) => {
|
|
2854
|
+
assertAllowedModelsInValue(body, allowedModels);
|
|
2855
|
+
return request("/chat/completions", {
|
|
2856
|
+
body: { ...body, stream: false },
|
|
2857
|
+
method: "POST"
|
|
2858
|
+
});
|
|
2859
|
+
},
|
|
2860
|
+
createPresetFromChatCompletions: (slug, body) => {
|
|
2861
|
+
assertAllowedModelsInValue(body, allowedModels);
|
|
2862
|
+
return request(`/presets/${encodeURIComponent(slug)}/chat/completions`, { body, method: "POST" });
|
|
2863
|
+
},
|
|
2864
|
+
createPresetFromMessages: (slug, body) => {
|
|
2865
|
+
assertAllowedModelsInValue(body, allowedModels);
|
|
2866
|
+
return request(`/presets/${encodeURIComponent(slug)}/messages`, { body, method: "POST" });
|
|
2867
|
+
},
|
|
2868
|
+
createPresetFromResponses: (slug, body) => {
|
|
2869
|
+
assertAllowedModelsInValue(body, allowedModels);
|
|
2870
|
+
return request(`/presets/${encodeURIComponent(slug)}/responses`, { body, method: "POST" });
|
|
2871
|
+
},
|
|
2872
|
+
createWorkspace: (body) => {
|
|
2873
|
+
assertAllowedModelsInValue(body, allowedModels);
|
|
2874
|
+
return request("/workspaces", {
|
|
2875
|
+
body,
|
|
2876
|
+
method: "POST"
|
|
2877
|
+
});
|
|
2878
|
+
},
|
|
2879
|
+
createBatch: (body) => {
|
|
2880
|
+
assertAllowedModel(body.model, allowedModels);
|
|
2881
|
+
return requestBatch("/batches", {
|
|
2882
|
+
body: {
|
|
2883
|
+
endpoint: body.endpoint,
|
|
2884
|
+
model: body.model,
|
|
2885
|
+
requests: body.requests,
|
|
2886
|
+
...body.completion_window ? { completion_window: body.completion_window } : {}
|
|
2887
|
+
},
|
|
2888
|
+
method: "POST"
|
|
2889
|
+
});
|
|
2890
|
+
},
|
|
2741
2891
|
createEmbedding: (body) => {
|
|
2742
2892
|
assertAllowedModel(body.model, allowedModels);
|
|
2743
2893
|
return request("/embeddings", {
|
|
@@ -2752,8 +2902,12 @@ var createOpenRouterClient = (config2) => {
|
|
|
2752
2902
|
method: "POST"
|
|
2753
2903
|
});
|
|
2754
2904
|
},
|
|
2755
|
-
deleteFile: (id, workspaceId) => request(`/files/${encodeURIComponent(id)}`, { method: "DELETE", query: { workspace_id: workspaceId } }),
|
|
2756
|
-
|
|
2905
|
+
deleteFile: (id, workspaceId = defaultWorkspaceId) => request(`/files/${encodeURIComponent(id)}`, { method: "DELETE", query: { workspace_id: workspaceId } }),
|
|
2906
|
+
deleteWorkspace: (id) => request(`/workspaces/${encodeURIComponent(id)}`, {
|
|
2907
|
+
method: "DELETE"
|
|
2908
|
+
}),
|
|
2909
|
+
deleteWorkspaceBudget: (id, interval) => request(`/workspaces/${encodeURIComponent(id)}/budgets/${interval}`, { method: "DELETE" }),
|
|
2910
|
+
downloadFile: (id, workspaceId = defaultWorkspaceId) => requestRaw(`/files/${encodeURIComponent(id)}/content`, {
|
|
2757
2911
|
query: { workspace_id: workspaceId }
|
|
2758
2912
|
}),
|
|
2759
2913
|
downloadVideo: (id, index = 0) => requestRaw(`/videos/${encodeURIComponent(id)}/content`, {
|
|
@@ -2766,15 +2920,25 @@ var createOpenRouterClient = (config2) => {
|
|
|
2766
2920
|
method: "POST"
|
|
2767
2921
|
});
|
|
2768
2922
|
},
|
|
2769
|
-
getBatch
|
|
2923
|
+
getBatch,
|
|
2924
|
+
getActivity: (query) => request("/activity", {
|
|
2925
|
+
query: {
|
|
2926
|
+
...query,
|
|
2927
|
+
workspace_id: query?.workspace_id ?? defaultWorkspaceId
|
|
2928
|
+
}
|
|
2929
|
+
}),
|
|
2930
|
+
getAnalyticsMeta: () => request("/analytics/meta"),
|
|
2770
2931
|
getCredits: () => request("/credits"),
|
|
2771
2932
|
getCurrentKey: () => request("/key"),
|
|
2772
|
-
getFile: (id, workspaceId) => request(`/files/${encodeURIComponent(id)}`, {
|
|
2933
|
+
getFile: (id, workspaceId = defaultWorkspaceId) => request(`/files/${encodeURIComponent(id)}`, {
|
|
2773
2934
|
query: { workspace_id: workspaceId }
|
|
2774
2935
|
}),
|
|
2775
2936
|
getGeneration: (id) => request("/generation", {
|
|
2776
2937
|
query: { id }
|
|
2777
2938
|
}),
|
|
2939
|
+
getGenerationContent: (id) => request("/generation/content", {
|
|
2940
|
+
query: { id }
|
|
2941
|
+
}),
|
|
2778
2942
|
getModelEndpoints: (model) => {
|
|
2779
2943
|
assertAllowedModel(model, allowedModels);
|
|
2780
2944
|
return request(`/models/${encodeModelPath(model)}/endpoints`);
|
|
@@ -2787,9 +2951,21 @@ var createOpenRouterClient = (config2) => {
|
|
|
2787
2951
|
assertAllowedModel(model, allowedModels);
|
|
2788
2952
|
return request(`/images/models/${encodeModelPath(model)}/endpoints`);
|
|
2789
2953
|
},
|
|
2954
|
+
getPreset: (slug) => request(`/presets/${encodeURIComponent(slug)}`),
|
|
2955
|
+
getPresetVersion: (slug, version) => request(`/presets/${encodeURIComponent(slug)}/versions/${encodeURIComponent(String(version))}`),
|
|
2956
|
+
getTaskClassifications: (window2 = "7d") => request("/classifications/task", {
|
|
2957
|
+
query: { window: window2 }
|
|
2958
|
+
}),
|
|
2790
2959
|
getVideo: (id) => request(`/videos/${encodeURIComponent(id)}`),
|
|
2960
|
+
getWorkspace: (id) => request(`/workspaces/${encodeURIComponent(id)}`),
|
|
2791
2961
|
listImageModels: async () => filterModelList(await request("/images/models")),
|
|
2792
|
-
|
|
2962
|
+
listEmbeddingModels: async () => filterModelList(await request("/embeddings/models")),
|
|
2963
|
+
listFiles: (query) => request("/files", {
|
|
2964
|
+
query: {
|
|
2965
|
+
...query,
|
|
2966
|
+
workspace_id: query?.workspace_id ?? defaultWorkspaceId
|
|
2967
|
+
}
|
|
2968
|
+
}),
|
|
2793
2969
|
listModels,
|
|
2794
2970
|
listUserModels: async () => filterModelList(await request("/models/user")),
|
|
2795
2971
|
listZdrEndpoints: async () => {
|
|
@@ -2804,11 +2980,20 @@ var createOpenRouterClient = (config2) => {
|
|
|
2804
2980
|
countModels: (outputModalities) => request("/models/count", {
|
|
2805
2981
|
query: { output_modalities: outputModalities }
|
|
2806
2982
|
}),
|
|
2807
|
-
listPresets: (offset = 0, limit = 100) => request("/presets", {
|
|
2983
|
+
listPresets: (offset = 0, limit = 100) => request("/presets", {
|
|
2984
|
+
query: { limit, offset }
|
|
2985
|
+
}),
|
|
2808
2986
|
listPresetVersions: (slug, offset = 0, limit = 100) => request(`/presets/${encodeURIComponent(slug)}/versions`, { query: { limit, offset } }),
|
|
2809
2987
|
listProviders: () => request("/providers"),
|
|
2810
2988
|
listRerankModels: async () => filterModelList(await request("/rerank/models")),
|
|
2811
2989
|
listVideoModels: async () => filterModelList(await request("/videos/models")),
|
|
2990
|
+
listWorkspaceBudgets: (id) => request(`/workspaces/${encodeURIComponent(id)}/budgets`),
|
|
2991
|
+
listWorkspaces: (offset = 0, limit = 100) => request("/workspaces", { query: { limit, offset } }),
|
|
2992
|
+
queryAnalytics: (body) => request("/analytics/query", {
|
|
2993
|
+
body,
|
|
2994
|
+
method: "POST"
|
|
2995
|
+
}),
|
|
2996
|
+
removeWorkspaceMembers: (id, userIds) => request(`/workspaces/${encodeURIComponent(id)}/members/remove`, { body: { user_ids: [...userIds] }, method: "POST" }),
|
|
2812
2997
|
request,
|
|
2813
2998
|
requestRaw,
|
|
2814
2999
|
streamImage: async function* (body, options = {}) {
|
|
@@ -2861,8 +3046,41 @@ var createOpenRouterClient = (config2) => {
|
|
|
2861
3046
|
return request("/files", {
|
|
2862
3047
|
body,
|
|
2863
3048
|
method: "POST",
|
|
2864
|
-
query: { workspace_id: options.workspaceId }
|
|
3049
|
+
query: { workspace_id: options.workspaceId ?? defaultWorkspaceId }
|
|
2865
3050
|
});
|
|
3051
|
+
},
|
|
3052
|
+
updateWorkspace: (id, body) => {
|
|
3053
|
+
assertAllowedModelsInValue(body, allowedModels);
|
|
3054
|
+
return request(`/workspaces/${encodeURIComponent(id)}`, { body, method: "PATCH" });
|
|
3055
|
+
},
|
|
3056
|
+
upsertWorkspaceBudget: (id, interval, limitUsd) => request(`/workspaces/${encodeURIComponent(id)}/budgets/${interval}`, { body: { limit_usd: limitUsd }, method: "PUT" }),
|
|
3057
|
+
waitForBatch: async (id, options = {}) => {
|
|
3058
|
+
const intervalMs = options.intervalMs ?? 1000;
|
|
3059
|
+
const timeoutMs = options.timeoutMs;
|
|
3060
|
+
if (!Number.isFinite(intervalMs) || intervalMs < 0)
|
|
3061
|
+
throw new Error("OpenRouter batch intervalMs must be non-negative");
|
|
3062
|
+
if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs < 0))
|
|
3063
|
+
throw new Error("OpenRouter batch timeoutMs must be non-negative");
|
|
3064
|
+
const startedAt = Date.now();
|
|
3065
|
+
for (;; ) {
|
|
3066
|
+
options.signal?.throwIfAborted();
|
|
3067
|
+
const batch = await getBatch(id);
|
|
3068
|
+
if (TERMINAL_BATCH_STATUSES.has(batch.status))
|
|
3069
|
+
return batch;
|
|
3070
|
+
if (timeoutMs !== undefined && Date.now() - startedAt + intervalMs > timeoutMs)
|
|
3071
|
+
throw new Error(`Timed out waiting for OpenRouter batch "${id}"`);
|
|
3072
|
+
await new Promise((resolve, reject) => {
|
|
3073
|
+
const onAbort = () => {
|
|
3074
|
+
clearTimeout(timeout);
|
|
3075
|
+
reject(options.signal?.reason);
|
|
3076
|
+
};
|
|
3077
|
+
const timeout = setTimeout(() => {
|
|
3078
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
3079
|
+
resolve();
|
|
3080
|
+
}, intervalMs);
|
|
3081
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
3082
|
+
});
|
|
3083
|
+
}
|
|
2866
3084
|
}
|
|
2867
3085
|
};
|
|
2868
3086
|
};
|
|
@@ -2999,7 +3217,7 @@ var assertAllowedPreset = (preset, allowedPresets) => {
|
|
|
2999
3217
|
var assertIndirectModels = (value, allowedModels, key = "") => {
|
|
3000
3218
|
if (key === "model" && typeof value === "string")
|
|
3001
3219
|
assertAllowedModel2(value, allowedModels);
|
|
3002
|
-
if ((key === "models" || key === "analysis_models") && Array.isArray(value)) {
|
|
3220
|
+
if ((key === "models" || key === "analysis_models" || key === "allowed_models") && Array.isArray(value)) {
|
|
3003
3221
|
for (const model of value) {
|
|
3004
3222
|
if (typeof model === "string")
|
|
3005
3223
|
assertAllowedModel2(model, allowedModels);
|
|
@@ -3013,6 +3231,84 @@ var assertIndirectModels = (value, allowedModels, key = "") => {
|
|
|
3013
3231
|
assertIndirectModels(child, allowedModels, childKey);
|
|
3014
3232
|
}
|
|
3015
3233
|
};
|
|
3234
|
+
var assertIntegerRange = (label, value, minimum, maximum) => {
|
|
3235
|
+
if (value === undefined)
|
|
3236
|
+
return;
|
|
3237
|
+
if (!Number.isInteger(value) || value < minimum || maximum !== undefined && value > maximum)
|
|
3238
|
+
throw new Error(`OpenRouter ${label} must be an integer from ${minimum}${maximum === undefined ? " or greater" : ` to ${maximum}`}`);
|
|
3239
|
+
};
|
|
3240
|
+
var assertPluginOptions = (plugins) => {
|
|
3241
|
+
for (const plugin of plugins ?? []) {
|
|
3242
|
+
if (plugin.id === "response-healing")
|
|
3243
|
+
throw new Error("OpenRouter response-healing requires a non-streaming request; use createOpenRouterClient().chat()");
|
|
3244
|
+
if (plugin.id === "fusion") {
|
|
3245
|
+
const fusion = plugin;
|
|
3246
|
+
if (fusion.analysis_models && (fusion.analysis_models.length < 1 || fusion.analysis_models.length > 8))
|
|
3247
|
+
throw new Error("OpenRouter Fusion analysis_models must contain 1-8 models");
|
|
3248
|
+
assertIntegerRange("Fusion max_tool_calls", fusion.max_tool_calls, 1, 16);
|
|
3249
|
+
}
|
|
3250
|
+
if (plugin.id === "web") {
|
|
3251
|
+
const web = plugin;
|
|
3252
|
+
assertIntegerRange("web plugin max_results", web.max_results, 1, web.engine === "perplexity" ? 20 : 25);
|
|
3253
|
+
if (web.include_domains?.length && web.exclude_domains?.length && (web.engine === "firecrawl" || web.engine === "parallel" || web.engine === "perplexity"))
|
|
3254
|
+
throw new Error(`OpenRouter ${web.engine} web plugin cannot combine include_domains and exclude_domains`);
|
|
3255
|
+
}
|
|
3256
|
+
}
|
|
3257
|
+
};
|
|
3258
|
+
var assertServerToolOptions = (tools) => {
|
|
3259
|
+
for (const tool of tools ?? []) {
|
|
3260
|
+
if (tool.type === "openrouter:web_search") {
|
|
3261
|
+
const parameters = tool.parameters;
|
|
3262
|
+
assertIntegerRange("web search max_results", parameters?.max_results, 1, 25);
|
|
3263
|
+
if (parameters?.engine === "perplexity" && (parameters.max_results ?? 0) > 20)
|
|
3264
|
+
throw new Error("OpenRouter Perplexity web search max_results must be at most 20");
|
|
3265
|
+
assertIntegerRange("web search max_characters", parameters?.max_characters, 1, 1e5);
|
|
3266
|
+
assertIntegerRange("web search max_total_results", parameters?.max_total_results, 1);
|
|
3267
|
+
}
|
|
3268
|
+
if (tool.type === "openrouter:web_fetch") {
|
|
3269
|
+
assertIntegerRange("web fetch max_uses", tool.parameters?.max_uses, 1);
|
|
3270
|
+
assertIntegerRange("web fetch max_content_tokens", tool.parameters?.max_content_tokens, 1);
|
|
3271
|
+
}
|
|
3272
|
+
if (tool.type === "openrouter:image_generation") {
|
|
3273
|
+
const compression = tool.parameters?.output_compression;
|
|
3274
|
+
if (compression !== undefined && (!Number.isFinite(compression) || compression < 0 || compression > 100))
|
|
3275
|
+
throw new Error("OpenRouter image generation output_compression must be 0-100");
|
|
3276
|
+
}
|
|
3277
|
+
if (tool.type === "openrouter:subagent") {
|
|
3278
|
+
assertIntegerRange("subagent max_completion_tokens", tool.parameters.max_completion_tokens, 1);
|
|
3279
|
+
assertIntegerRange("subagent max_tool_calls", tool.parameters.max_tool_calls, 1, 25);
|
|
3280
|
+
const temperature = tool.parameters.temperature;
|
|
3281
|
+
if (temperature !== undefined && (!Number.isFinite(temperature) || temperature < 0 || temperature > 2))
|
|
3282
|
+
throw new Error("OpenRouter subagent temperature must be 0-2");
|
|
3283
|
+
assertServerToolOptions(tool.parameters.tools);
|
|
3284
|
+
}
|
|
3285
|
+
if (tool.type === "openrouter:advisor") {
|
|
3286
|
+
assertIntegerRange("advisor max_completion_tokens", tool.parameters?.max_completion_tokens, 1);
|
|
3287
|
+
const temperature = tool.parameters?.temperature;
|
|
3288
|
+
if (temperature !== undefined && (!Number.isFinite(temperature) || temperature < 0 || temperature > 2))
|
|
3289
|
+
throw new Error("OpenRouter advisor temperature must be 0-2");
|
|
3290
|
+
}
|
|
3291
|
+
if (tool.type === "openrouter:fusion") {
|
|
3292
|
+
const analysisModels = tool.parameters?.analysis_models;
|
|
3293
|
+
if (analysisModels && (analysisModels.length < 1 || analysisModels.length > 8))
|
|
3294
|
+
throw new Error("OpenRouter Fusion server tool analysis_models must contain 1-8 models");
|
|
3295
|
+
assertIntegerRange("Fusion server tool max_completion_tokens", tool.parameters?.max_completion_tokens, 1);
|
|
3296
|
+
assertIntegerRange("Fusion server tool max_tool_calls", tool.parameters?.max_tool_calls, 1, 16);
|
|
3297
|
+
const temperature = tool.parameters?.temperature;
|
|
3298
|
+
if (temperature !== undefined && (!Number.isFinite(temperature) || temperature < 0 || temperature > 2))
|
|
3299
|
+
throw new Error("OpenRouter Fusion server tool temperature must be 0-2");
|
|
3300
|
+
assertServerToolOptions(tool.parameters?.tools);
|
|
3301
|
+
}
|
|
3302
|
+
if (tool.type === "openrouter:shell") {
|
|
3303
|
+
assertIntegerRange("shell sleep_after_seconds", tool.parameters?.sleep_after_seconds, 0, 2592000);
|
|
3304
|
+
const environment = tool.parameters?.environment;
|
|
3305
|
+
if (environment?.type === "container_reference" && (environment.container_id.length < 1 || environment.container_id.length > 20))
|
|
3306
|
+
throw new Error("OpenRouter shell container_id must contain 1-20 characters");
|
|
3307
|
+
}
|
|
3308
|
+
if (tool.type === "openrouter:experimental__search_models")
|
|
3309
|
+
assertIntegerRange("model search max_results", tool.parameters?.max_results, 1, 20);
|
|
3310
|
+
}
|
|
3311
|
+
};
|
|
3016
3312
|
var assertRequestOptions = (options, allowedModels, allowedPresets, allowedProviders) => {
|
|
3017
3313
|
assertAllowedPreset(options.preset, allowedPresets);
|
|
3018
3314
|
assertRequestRoutingPolicy(options.routing, allowedProviders);
|
|
@@ -3032,6 +3328,8 @@ var assertRequestOptions = (options, allowedModels, allowedPresets, allowedProvi
|
|
|
3032
3328
|
assertIndirectModels(options.serverTools, allowedModels);
|
|
3033
3329
|
assertIndirectModels(options.messagesTools, allowedModels);
|
|
3034
3330
|
assertIndirectModels(options.plugins, allowedModels);
|
|
3331
|
+
assertPluginOptions(options.plugins);
|
|
3332
|
+
assertServerToolOptions(options.serverTools);
|
|
3035
3333
|
if (options.extraBody) {
|
|
3036
3334
|
const unsafe = Object.keys(options.extraBody).find((key) => SECURITY_SENSITIVE_EXTRA_BODY_FIELDS.has(key));
|
|
3037
3335
|
if (unsafe)
|
|
@@ -7313,6 +7611,7 @@ export {
|
|
|
7313
7611
|
meta,
|
|
7314
7612
|
google,
|
|
7315
7613
|
getProviderHealth,
|
|
7614
|
+
generateOpenRouterPKCE,
|
|
7316
7615
|
generateObjectAI,
|
|
7317
7616
|
generateId,
|
|
7318
7617
|
generateAIWithTools,
|
|
@@ -7320,13 +7619,18 @@ export {
|
|
|
7320
7619
|
gemini,
|
|
7321
7620
|
formCard,
|
|
7322
7621
|
fetchProviderApiStatus,
|
|
7622
|
+
exchangeOpenRouterAuthCode,
|
|
7623
|
+
estimateOpenRouterModelCost,
|
|
7624
|
+
estimateOpenRouterCost,
|
|
7323
7625
|
diffCard,
|
|
7324
7626
|
deepseek,
|
|
7325
7627
|
credentialCard,
|
|
7326
7628
|
createUiCards,
|
|
7327
7629
|
createSyncConversationStore,
|
|
7328
7630
|
createProviderProxyResponse,
|
|
7631
|
+
createOpenRouterKeyLinks,
|
|
7329
7632
|
createOpenRouterClient,
|
|
7633
|
+
createOpenRouterAuthorizationUrl,
|
|
7330
7634
|
createOAuth2ClientCredentialsTokenSource,
|
|
7331
7635
|
createMemoryStore,
|
|
7332
7636
|
createConversationManager,
|
|
@@ -7364,5 +7668,5 @@ export {
|
|
|
7364
7668
|
BUILTIN_UI_CARDS
|
|
7365
7669
|
};
|
|
7366
7670
|
|
|
7367
|
-
//# debugId=
|
|
7671
|
+
//# debugId=1A3329E4751DCFB764756E2164756E21
|
|
7368
7672
|
//# sourceMappingURL=index.js.map
|