@absolutejs/ai 0.0.51 → 0.0.52

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 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. Avoid `openrouter/auto` under a strict policy unless it is deliberately
115
- allowed.
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
@@ -161,8 +182,9 @@ metadata when reported.
161
182
 
162
183
  `createOpenRouterClient()` covers model/provider discovery, embeddings,
163
184
  reranking, streamed and non-streamed image generation, reusable files,
164
- Responses, speech, transcription, video jobs and downloads, batches, presets,
165
- credits, key metadata, and generation metadata. It also exports
185
+ Responses, speech, typed transcription, video jobs and downloads, beta batches,
186
+ presets, workspaces and budgets, activity/analytics, task classifications,
187
+ credits, key metadata, and generation content. It also exports
166
188
  `verifyOpenRouterWebhookSignature()` for video completion webhooks. Its typed
167
189
  operations enforce the same model allowlist. `request()` and `requestRaw()` are
168
190
  forward-compatible access to new or administrative OpenRouter endpoints.
@@ -190,6 +212,41 @@ const reranked = await openrouterClient.rerank({
190
212
  query: "cost controls",
191
213
  documents: ["response caching", "CSS layout"],
192
214
  });
215
+
216
+ const batch = await openrouterClient.createBatch({
217
+ endpoint: "/v1/chat/completions",
218
+ model: "anthropic/claude-sonnet-4.6",
219
+ requests: [
220
+ { custom_id: "one", body: { messages: [{ role: "user", content: "Hi" }] } },
221
+ ],
222
+ });
223
+ const completed = await openrouterClient.waitForBatch(batch.id, {
224
+ signal: abortController.signal,
225
+ timeoutMs: 60_000,
226
+ });
227
+ ```
228
+
229
+ Batch traffic uses OpenRouter's separate `/api/beta/batches` API and returns
230
+ inline typed results. `estimateOpenRouterModelCost()` calculates prompt,
231
+ completion, request, image, web-search, reasoning, and cache costs directly from
232
+ model-discovery pricing fields.
233
+
234
+ OAuth helpers cover S256 PKCE, web and headless authorization URLs, code
235
+ exchange, authenticated code creation, and user key deep-links:
236
+
237
+ ```ts
238
+ const pkce = await generateOpenRouterPKCE();
239
+ const authorizationUrl = createOpenRouterAuthorizationUrl({
240
+ callbackUrl: "https://example.com/openrouter/callback",
241
+ codeChallenge: pkce.codeChallenge,
242
+ codeChallengeMethod: pkce.codeChallengeMethod,
243
+ });
244
+
245
+ const { key } = await exchangeOpenRouterAuthCode({
246
+ code,
247
+ code_verifier: pkce.codeVerifier,
248
+ code_challenge_method: pkce.codeChallengeMethod,
249
+ });
193
250
  ```
194
251
 
195
252
  For a strict model-origin policy, also assign an OpenRouter key/workspace
@@ -197,9 +254,11 @@ guardrail with the same model allowlist. Provider allowlists restrict where a
197
254
  model runs; they do not identify who developed it. Presets and router aliases
198
255
  must be explicitly allowed, because their resolved model is controlled outside
199
256
  the request. The raw client is intentionally unopinionated and should be limited
200
- to trusted server-side administration code. OpenRouter's official SDK can be
201
- used alongside this package for its complete organization, SSO, SCIM, BYOK, and
202
- analytics type surface.
257
+ to trusted server-side administration code. OpenRouter currently documents
258
+ reporting generation feedback through Chatroom and Logs, not through a public
259
+ feedback API, so AbsoluteJS exposes generation IDs/content without inventing an
260
+ unstable endpoint. OpenRouter's official SDK can be used alongside this package
261
+ for specialized organization, SSO, SCIM, and BYOK administration.
203
262
 
204
263
  Use `openrouterResponses(config)` when an AbsoluteJS agent should stream through
205
264
  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 requestRaw = async (path, options = {}) => {
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(`${baseUrl}${normalizePath(path)}`, options.query), { ...requestInit, body, headers });
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,45 @@ var createOpenRouterClient = (config2) => {
2734
2842
  };
2735
2843
  };
2736
2844
  return {
2737
- cancelBatch: (id) => request(`/batches/${encodeURIComponent(id)}/cancel`, {
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
- createBatch: (body) => request("/batches", { body, method: "POST" }),
2853
+ createPresetFromChatCompletions: (slug, body) => {
2854
+ assertAllowedModelsInValue(body, allowedModels);
2855
+ return request(`/presets/${encodeURIComponent(slug)}/chat/completions`, { body, method: "POST" });
2856
+ },
2857
+ createPresetFromMessages: (slug, body) => {
2858
+ assertAllowedModelsInValue(body, allowedModels);
2859
+ return request(`/presets/${encodeURIComponent(slug)}/messages`, { body, method: "POST" });
2860
+ },
2861
+ createPresetFromResponses: (slug, body) => {
2862
+ assertAllowedModelsInValue(body, allowedModels);
2863
+ return request(`/presets/${encodeURIComponent(slug)}/responses`, { body, method: "POST" });
2864
+ },
2865
+ createWorkspace: (body) => {
2866
+ assertAllowedModelsInValue(body, allowedModels);
2867
+ return request("/workspaces", {
2868
+ body,
2869
+ method: "POST"
2870
+ });
2871
+ },
2872
+ createBatch: (body) => {
2873
+ assertAllowedModel(body.model, allowedModels);
2874
+ return requestBatch("/batches", {
2875
+ body: {
2876
+ endpoint: body.endpoint,
2877
+ model: body.model,
2878
+ requests: body.requests,
2879
+ ...body.completion_window ? { completion_window: body.completion_window } : {}
2880
+ },
2881
+ method: "POST"
2882
+ });
2883
+ },
2741
2884
  createEmbedding: (body) => {
2742
2885
  assertAllowedModel(body.model, allowedModels);
2743
2886
  return request("/embeddings", {
@@ -2752,8 +2895,12 @@ var createOpenRouterClient = (config2) => {
2752
2895
  method: "POST"
2753
2896
  });
2754
2897
  },
2755
- deleteFile: (id, workspaceId) => request(`/files/${encodeURIComponent(id)}`, { method: "DELETE", query: { workspace_id: workspaceId } }),
2756
- downloadFile: (id, workspaceId) => requestRaw(`/files/${encodeURIComponent(id)}/content`, {
2898
+ deleteFile: (id, workspaceId = defaultWorkspaceId) => request(`/files/${encodeURIComponent(id)}`, { method: "DELETE", query: { workspace_id: workspaceId } }),
2899
+ deleteWorkspace: (id) => request(`/workspaces/${encodeURIComponent(id)}`, {
2900
+ method: "DELETE"
2901
+ }),
2902
+ deleteWorkspaceBudget: (id, interval) => request(`/workspaces/${encodeURIComponent(id)}/budgets/${interval}`, { method: "DELETE" }),
2903
+ downloadFile: (id, workspaceId = defaultWorkspaceId) => requestRaw(`/files/${encodeURIComponent(id)}/content`, {
2757
2904
  query: { workspace_id: workspaceId }
2758
2905
  }),
2759
2906
  downloadVideo: (id, index = 0) => requestRaw(`/videos/${encodeURIComponent(id)}/content`, {
@@ -2766,15 +2913,25 @@ var createOpenRouterClient = (config2) => {
2766
2913
  method: "POST"
2767
2914
  });
2768
2915
  },
2769
- getBatch: (id) => request(`/batches/${encodeURIComponent(id)}`),
2916
+ getBatch,
2917
+ getActivity: (query) => request("/activity", {
2918
+ query: {
2919
+ ...query,
2920
+ workspace_id: query?.workspace_id ?? defaultWorkspaceId
2921
+ }
2922
+ }),
2923
+ getAnalyticsMeta: () => request("/analytics/meta"),
2770
2924
  getCredits: () => request("/credits"),
2771
2925
  getCurrentKey: () => request("/key"),
2772
- getFile: (id, workspaceId) => request(`/files/${encodeURIComponent(id)}`, {
2926
+ getFile: (id, workspaceId = defaultWorkspaceId) => request(`/files/${encodeURIComponent(id)}`, {
2773
2927
  query: { workspace_id: workspaceId }
2774
2928
  }),
2775
2929
  getGeneration: (id) => request("/generation", {
2776
2930
  query: { id }
2777
2931
  }),
2932
+ getGenerationContent: (id) => request("/generation/content", {
2933
+ query: { id }
2934
+ }),
2778
2935
  getModelEndpoints: (model) => {
2779
2936
  assertAllowedModel(model, allowedModels);
2780
2937
  return request(`/models/${encodeModelPath(model)}/endpoints`);
@@ -2787,9 +2944,20 @@ var createOpenRouterClient = (config2) => {
2787
2944
  assertAllowedModel(model, allowedModels);
2788
2945
  return request(`/images/models/${encodeModelPath(model)}/endpoints`);
2789
2946
  },
2947
+ getPreset: (slug) => request(`/presets/${encodeURIComponent(slug)}`),
2948
+ getPresetVersion: (slug, version) => request(`/presets/${encodeURIComponent(slug)}/versions/${encodeURIComponent(String(version))}`),
2949
+ getTaskClassifications: (window2 = "7d") => request("/classifications/task", {
2950
+ query: { window: window2 }
2951
+ }),
2790
2952
  getVideo: (id) => request(`/videos/${encodeURIComponent(id)}`),
2953
+ getWorkspace: (id) => request(`/workspaces/${encodeURIComponent(id)}`),
2791
2954
  listImageModels: async () => filterModelList(await request("/images/models")),
2792
- listFiles: (query) => request("/files", { query }),
2955
+ listFiles: (query) => request("/files", {
2956
+ query: {
2957
+ ...query,
2958
+ workspace_id: query?.workspace_id ?? defaultWorkspaceId
2959
+ }
2960
+ }),
2793
2961
  listModels,
2794
2962
  listUserModels: async () => filterModelList(await request("/models/user")),
2795
2963
  listZdrEndpoints: async () => {
@@ -2804,11 +2972,20 @@ var createOpenRouterClient = (config2) => {
2804
2972
  countModels: (outputModalities) => request("/models/count", {
2805
2973
  query: { output_modalities: outputModalities }
2806
2974
  }),
2807
- listPresets: (offset = 0, limit = 100) => request("/presets", { query: { limit, offset } }),
2975
+ listPresets: (offset = 0, limit = 100) => request("/presets", {
2976
+ query: { limit, offset }
2977
+ }),
2808
2978
  listPresetVersions: (slug, offset = 0, limit = 100) => request(`/presets/${encodeURIComponent(slug)}/versions`, { query: { limit, offset } }),
2809
2979
  listProviders: () => request("/providers"),
2810
2980
  listRerankModels: async () => filterModelList(await request("/rerank/models")),
2811
2981
  listVideoModels: async () => filterModelList(await request("/videos/models")),
2982
+ listWorkspaceBudgets: (id) => request(`/workspaces/${encodeURIComponent(id)}/budgets`),
2983
+ listWorkspaces: (offset = 0, limit = 100) => request("/workspaces", { query: { limit, offset } }),
2984
+ queryAnalytics: (body) => request("/analytics/query", {
2985
+ body,
2986
+ method: "POST"
2987
+ }),
2988
+ removeWorkspaceMembers: (id, userIds) => request(`/workspaces/${encodeURIComponent(id)}/members/remove`, { body: { user_ids: [...userIds] }, method: "POST" }),
2812
2989
  request,
2813
2990
  requestRaw,
2814
2991
  streamImage: async function* (body, options = {}) {
@@ -2861,8 +3038,41 @@ var createOpenRouterClient = (config2) => {
2861
3038
  return request("/files", {
2862
3039
  body,
2863
3040
  method: "POST",
2864
- query: { workspace_id: options.workspaceId }
3041
+ query: { workspace_id: options.workspaceId ?? defaultWorkspaceId }
2865
3042
  });
3043
+ },
3044
+ updateWorkspace: (id, body) => {
3045
+ assertAllowedModelsInValue(body, allowedModels);
3046
+ return request(`/workspaces/${encodeURIComponent(id)}`, { body, method: "PATCH" });
3047
+ },
3048
+ upsertWorkspaceBudget: (id, interval, limitUsd) => request(`/workspaces/${encodeURIComponent(id)}/budgets/${interval}`, { body: { limit_usd: limitUsd }, method: "PUT" }),
3049
+ waitForBatch: async (id, options = {}) => {
3050
+ const intervalMs = options.intervalMs ?? 1000;
3051
+ const timeoutMs = options.timeoutMs;
3052
+ if (!Number.isFinite(intervalMs) || intervalMs < 0)
3053
+ throw new Error("OpenRouter batch intervalMs must be non-negative");
3054
+ if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs < 0))
3055
+ throw new Error("OpenRouter batch timeoutMs must be non-negative");
3056
+ const startedAt = Date.now();
3057
+ for (;; ) {
3058
+ options.signal?.throwIfAborted();
3059
+ const batch = await getBatch(id);
3060
+ if (TERMINAL_BATCH_STATUSES.has(batch.status))
3061
+ return batch;
3062
+ if (timeoutMs !== undefined && Date.now() - startedAt + intervalMs > timeoutMs)
3063
+ throw new Error(`Timed out waiting for OpenRouter batch "${id}"`);
3064
+ await new Promise((resolve, reject) => {
3065
+ const onAbort = () => {
3066
+ clearTimeout(timeout);
3067
+ reject(options.signal?.reason);
3068
+ };
3069
+ const timeout = setTimeout(() => {
3070
+ options.signal?.removeEventListener("abort", onAbort);
3071
+ resolve();
3072
+ }, intervalMs);
3073
+ options.signal?.addEventListener("abort", onAbort, { once: true });
3074
+ });
3075
+ }
2866
3076
  }
2867
3077
  };
2868
3078
  };
@@ -2999,7 +3209,7 @@ var assertAllowedPreset = (preset, allowedPresets) => {
2999
3209
  var assertIndirectModels = (value, allowedModels, key = "") => {
3000
3210
  if (key === "model" && typeof value === "string")
3001
3211
  assertAllowedModel2(value, allowedModels);
3002
- if ((key === "models" || key === "analysis_models") && Array.isArray(value)) {
3212
+ if ((key === "models" || key === "analysis_models" || key === "allowed_models") && Array.isArray(value)) {
3003
3213
  for (const model of value) {
3004
3214
  if (typeof model === "string")
3005
3215
  assertAllowedModel2(model, allowedModels);
@@ -7313,6 +7523,7 @@ export {
7313
7523
  meta,
7314
7524
  google,
7315
7525
  getProviderHealth,
7526
+ generateOpenRouterPKCE,
7316
7527
  generateObjectAI,
7317
7528
  generateId,
7318
7529
  generateAIWithTools,
@@ -7320,13 +7531,18 @@ export {
7320
7531
  gemini,
7321
7532
  formCard,
7322
7533
  fetchProviderApiStatus,
7534
+ exchangeOpenRouterAuthCode,
7535
+ estimateOpenRouterModelCost,
7536
+ estimateOpenRouterCost,
7323
7537
  diffCard,
7324
7538
  deepseek,
7325
7539
  credentialCard,
7326
7540
  createUiCards,
7327
7541
  createSyncConversationStore,
7328
7542
  createProviderProxyResponse,
7543
+ createOpenRouterKeyLinks,
7329
7544
  createOpenRouterClient,
7545
+ createOpenRouterAuthorizationUrl,
7330
7546
  createOAuth2ClientCredentialsTokenSource,
7331
7547
  createMemoryStore,
7332
7548
  createConversationManager,
@@ -7364,5 +7580,5 @@ export {
7364
7580
  BUILTIN_UI_CARDS
7365
7581
  };
7366
7582
 
7367
- //# debugId=3B5ACA11D1118B9564756E2164756E21
7583
+ //# debugId=25187F8D2370EC5064756E2164756E21
7368
7584
  //# sourceMappingURL=index.js.map