@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.
@@ -1990,7 +1990,46 @@ var anthropic = (config2) => {
1990
1990
  };
1991
1991
 
1992
1992
  // src/ai/providers/openrouterClient.ts
1993
+ var OPENROUTER_PRICING_KEYS = [
1994
+ "prompt",
1995
+ "completion",
1996
+ "request",
1997
+ "image",
1998
+ "web_search",
1999
+ "internal_reasoning",
2000
+ "input_cache_read",
2001
+ "input_cache_write"
2002
+ ];
2003
+ var estimateOpenRouterCost = (pricing, units) => {
2004
+ const components = {};
2005
+ let total = 0;
2006
+ for (const key of OPENROUTER_PRICING_KEYS) {
2007
+ const quantity = units[key];
2008
+ if (quantity === undefined)
2009
+ continue;
2010
+ if (!Number.isFinite(quantity) || quantity < 0)
2011
+ throw new Error(`OpenRouter ${key} units must be non-negative`);
2012
+ const rawPrice = pricing[key];
2013
+ if (rawPrice === undefined)
2014
+ continue;
2015
+ const price = Number(rawPrice);
2016
+ if (!Number.isFinite(price) || price < 0)
2017
+ throw new Error(`OpenRouter ${key} price must be non-negative`);
2018
+ components[key] = price * quantity;
2019
+ total += components[key];
2020
+ }
2021
+ return { components, total };
2022
+ };
2023
+ var estimateOpenRouterModelCost = (model, units) => estimateOpenRouterCost(model.pricing ?? {}, units);
1993
2024
  var DEFAULT_BASE_URL4 = "https://openrouter.ai/api/v1";
2025
+ var DEFAULT_BATCH_BASE_URL = "https://openrouter.ai/api/beta";
2026
+ var DEFAULT_SITE_URL = "https://openrouter.ai";
2027
+ var TERMINAL_BATCH_STATUSES = new Set([
2028
+ "completed",
2029
+ "failed",
2030
+ "expired",
2031
+ "cancelled"
2032
+ ]);
1994
2033
  var withoutLatestPrefix = (model) => model.startsWith("~") ? model.slice(1) : model;
1995
2034
  var openRouterModelMatchesRule = (model, rule) => {
1996
2035
  const normalizedModel = withoutLatestPrefix(model);
@@ -2004,6 +2043,22 @@ var assertAllowedModel = (model, allowedModels) => {
2004
2043
  return;
2005
2044
  throw new Error(`OpenRouter model "${model}" is not allowed`);
2006
2045
  };
2046
+ var assertAllowedModelsInValue = (value, allowedModels, key = "") => {
2047
+ if (key === "model" && typeof value === "string")
2048
+ assertAllowedModel(value, allowedModels);
2049
+ if ((key === "models" || key === "analysis_models" || key === "allowed_models") && Array.isArray(value)) {
2050
+ for (const model of value)
2051
+ if (typeof model === "string")
2052
+ assertAllowedModel(model, allowedModels);
2053
+ }
2054
+ if (Array.isArray(value)) {
2055
+ for (const item of value)
2056
+ assertAllowedModelsInValue(item, allowedModels);
2057
+ } else if (value && typeof value === "object") {
2058
+ for (const [childKey, child] of Object.entries(value))
2059
+ assertAllowedModelsInValue(child, allowedModels, childKey);
2060
+ }
2061
+ };
2007
2062
  var normalizePath = (path) => path.startsWith("/") ? path : `/${path}`;
2008
2063
  var encodeModelPath = (model) => model.split("/").map(encodeURIComponent).join("/");
2009
2064
  var withQuery = (url, query) => {
@@ -2054,6 +2109,54 @@ var parseImageSSE = async function* (response) {
2054
2109
  }
2055
2110
  };
2056
2111
  var toBytes = (value) => typeof value === "string" ? new TextEncoder().encode(value) : value;
2112
+ var toBase64Url = (bytes) => {
2113
+ let binary = "";
2114
+ for (const byte of bytes)
2115
+ binary += String.fromCharCode(byte);
2116
+ return btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/u, "");
2117
+ };
2118
+ var generateOpenRouterPKCE = async () => {
2119
+ const random = crypto.getRandomValues(new Uint8Array(32));
2120
+ const codeVerifier = toBase64Url(random);
2121
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(codeVerifier));
2122
+ return {
2123
+ codeChallenge: toBase64Url(new Uint8Array(digest)),
2124
+ codeChallengeMethod: "S256",
2125
+ codeVerifier
2126
+ };
2127
+ };
2128
+ var createOpenRouterAuthorizationUrl = (options = {}) => {
2129
+ const url = new URL("/auth", options.baseUrl ?? DEFAULT_SITE_URL);
2130
+ if (options.callbackUrl)
2131
+ url.searchParams.set("callback_url", options.callbackUrl);
2132
+ if (options.codeChallenge)
2133
+ url.searchParams.set("code_challenge", options.codeChallenge);
2134
+ if (options.codeChallengeMethod)
2135
+ url.searchParams.set("code_challenge_method", options.codeChallengeMethod);
2136
+ if (options.keyLabel)
2137
+ url.searchParams.set("key_label", options.keyLabel);
2138
+ return url.toString();
2139
+ };
2140
+ var exchangeOpenRouterAuthCode = async (body, options = {}) => {
2141
+ const response = await (options.fetch ?? globalThis.fetch)(`${(options.baseUrl ?? DEFAULT_BASE_URL4).replace(/\/$/, "")}/auth/keys`, {
2142
+ body: JSON.stringify(body),
2143
+ headers: { "Content-Type": "application/json" },
2144
+ method: "POST"
2145
+ });
2146
+ if (!response.ok)
2147
+ throw ProviderError.fromResponse("openrouter", response.status, await response.text());
2148
+ return response.json();
2149
+ };
2150
+ var createOpenRouterKeyLinks = async (key, siteUrl = DEFAULT_SITE_URL) => {
2151
+ const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(key)));
2152
+ const hash = Array.from(digest, (byte) => byte.toString(16).padStart(2, "0")).join("");
2153
+ const root = siteUrl.replace(/\/$/, "");
2154
+ return {
2155
+ hash,
2156
+ logsUrl: `${root}/logs?api_key_hash=${hash}`,
2157
+ settingsUrl: `${root}/keys/${hash}`
2158
+ };
2159
+ };
2057
2160
  var hexToBytes = (hex) => {
2058
2161
  if (!/^[0-9a-f]+$/iu.test(hex) || hex.length % 2 !== 0)
2059
2162
  return;
@@ -2099,9 +2202,11 @@ var createOpenRouterClient = (config2) => {
2099
2202
  if (!config2.apiKey && !config2.tokenSource)
2100
2203
  throw new Error("createOpenRouterClient() requires either apiKey or tokenSource");
2101
2204
  const baseUrl = (config2.baseUrl ?? DEFAULT_BASE_URL4).replace(/\/$/, "");
2205
+ const batchBaseUrl = (config2.batchBaseUrl ?? (config2.baseUrl ? new URL("../beta", `${baseUrl}/`).toString() : DEFAULT_BATCH_BASE_URL)).replace(/\/$/, "");
2102
2206
  const fetchImpl = config2.fetch ?? globalThis.fetch;
2103
2207
  const allowedModels = config2.allowedModels ? [...config2.allowedModels] : undefined;
2104
- const requestRaw = async (path, options = {}) => {
2208
+ const defaultWorkspaceId = config2.workspaceId;
2209
+ const requestRawAt = async (rootUrl, path, options = {}) => {
2105
2210
  const token = config2.tokenSource ? await Promise.resolve(config2.tokenSource()) : config2.apiKey;
2106
2211
  const suppliedHeaders = typeof config2.headers === "function" ? await config2.headers() : config2.headers ?? {};
2107
2212
  const headers = new Headers(suppliedHeaders);
@@ -2115,13 +2220,16 @@ var createOpenRouterClient = (config2) => {
2115
2220
  body = JSON.stringify(options.body);
2116
2221
  }
2117
2222
  const { query, ...requestInit } = options;
2118
- const response = await fetchImpl(withQuery(`${baseUrl}${normalizePath(path)}`, options.query), { ...requestInit, body, headers });
2223
+ const response = await fetchImpl(withQuery(`${rootUrl}${normalizePath(path)}`, options.query), { ...requestInit, body, headers });
2119
2224
  if (!response.ok) {
2120
2225
  throw ProviderError.fromResponse("openrouter", response.status, await response.text());
2121
2226
  }
2122
2227
  return response;
2123
2228
  };
2229
+ const requestRaw = (path, options = {}) => requestRawAt(baseUrl, path, options);
2124
2230
  const request = async (path, options = {}) => (await requestRaw(path, options)).json();
2231
+ const requestBatch = async (path, options = {}) => (await requestRawAt(batchBaseUrl, path, options)).json();
2232
+ const getBatch = (id) => requestBatch(`/batches/${encodeURIComponent(id)}`);
2125
2233
  const listModels = async (query) => {
2126
2234
  const result = await request("/models", { query });
2127
2235
  if (!allowedModels)
@@ -2140,10 +2248,52 @@ var createOpenRouterClient = (config2) => {
2140
2248
  };
2141
2249
  };
2142
2250
  return {
2143
- cancelBatch: (id) => request(`/batches/${encodeURIComponent(id)}/cancel`, {
2251
+ addWorkspaceMembers: (id, userIds) => request(`/workspaces/${encodeURIComponent(id)}/members/add`, { body: { user_ids: [...userIds] }, method: "POST" }),
2252
+ createAuthCode: (body) => request("/auth/keys/code", {
2253
+ body: {
2254
+ ...body,
2255
+ workspace_id: body.workspace_id ?? defaultWorkspaceId
2256
+ },
2144
2257
  method: "POST"
2145
2258
  }),
2146
- createBatch: (body) => request("/batches", { body, method: "POST" }),
2259
+ chat: (body) => {
2260
+ assertAllowedModelsInValue(body, allowedModels);
2261
+ return request("/chat/completions", {
2262
+ body: { ...body, stream: false },
2263
+ method: "POST"
2264
+ });
2265
+ },
2266
+ createPresetFromChatCompletions: (slug, body) => {
2267
+ assertAllowedModelsInValue(body, allowedModels);
2268
+ return request(`/presets/${encodeURIComponent(slug)}/chat/completions`, { body, method: "POST" });
2269
+ },
2270
+ createPresetFromMessages: (slug, body) => {
2271
+ assertAllowedModelsInValue(body, allowedModels);
2272
+ return request(`/presets/${encodeURIComponent(slug)}/messages`, { body, method: "POST" });
2273
+ },
2274
+ createPresetFromResponses: (slug, body) => {
2275
+ assertAllowedModelsInValue(body, allowedModels);
2276
+ return request(`/presets/${encodeURIComponent(slug)}/responses`, { body, method: "POST" });
2277
+ },
2278
+ createWorkspace: (body) => {
2279
+ assertAllowedModelsInValue(body, allowedModels);
2280
+ return request("/workspaces", {
2281
+ body,
2282
+ method: "POST"
2283
+ });
2284
+ },
2285
+ createBatch: (body) => {
2286
+ assertAllowedModel(body.model, allowedModels);
2287
+ return requestBatch("/batches", {
2288
+ body: {
2289
+ endpoint: body.endpoint,
2290
+ model: body.model,
2291
+ requests: body.requests,
2292
+ ...body.completion_window ? { completion_window: body.completion_window } : {}
2293
+ },
2294
+ method: "POST"
2295
+ });
2296
+ },
2147
2297
  createEmbedding: (body) => {
2148
2298
  assertAllowedModel(body.model, allowedModels);
2149
2299
  return request("/embeddings", {
@@ -2158,8 +2308,12 @@ var createOpenRouterClient = (config2) => {
2158
2308
  method: "POST"
2159
2309
  });
2160
2310
  },
2161
- deleteFile: (id, workspaceId) => request(`/files/${encodeURIComponent(id)}`, { method: "DELETE", query: { workspace_id: workspaceId } }),
2162
- downloadFile: (id, workspaceId) => requestRaw(`/files/${encodeURIComponent(id)}/content`, {
2311
+ deleteFile: (id, workspaceId = defaultWorkspaceId) => request(`/files/${encodeURIComponent(id)}`, { method: "DELETE", query: { workspace_id: workspaceId } }),
2312
+ deleteWorkspace: (id) => request(`/workspaces/${encodeURIComponent(id)}`, {
2313
+ method: "DELETE"
2314
+ }),
2315
+ deleteWorkspaceBudget: (id, interval) => request(`/workspaces/${encodeURIComponent(id)}/budgets/${interval}`, { method: "DELETE" }),
2316
+ downloadFile: (id, workspaceId = defaultWorkspaceId) => requestRaw(`/files/${encodeURIComponent(id)}/content`, {
2163
2317
  query: { workspace_id: workspaceId }
2164
2318
  }),
2165
2319
  downloadVideo: (id, index = 0) => requestRaw(`/videos/${encodeURIComponent(id)}/content`, {
@@ -2172,15 +2326,25 @@ var createOpenRouterClient = (config2) => {
2172
2326
  method: "POST"
2173
2327
  });
2174
2328
  },
2175
- getBatch: (id) => request(`/batches/${encodeURIComponent(id)}`),
2329
+ getBatch,
2330
+ getActivity: (query) => request("/activity", {
2331
+ query: {
2332
+ ...query,
2333
+ workspace_id: query?.workspace_id ?? defaultWorkspaceId
2334
+ }
2335
+ }),
2336
+ getAnalyticsMeta: () => request("/analytics/meta"),
2176
2337
  getCredits: () => request("/credits"),
2177
2338
  getCurrentKey: () => request("/key"),
2178
- getFile: (id, workspaceId) => request(`/files/${encodeURIComponent(id)}`, {
2339
+ getFile: (id, workspaceId = defaultWorkspaceId) => request(`/files/${encodeURIComponent(id)}`, {
2179
2340
  query: { workspace_id: workspaceId }
2180
2341
  }),
2181
2342
  getGeneration: (id) => request("/generation", {
2182
2343
  query: { id }
2183
2344
  }),
2345
+ getGenerationContent: (id) => request("/generation/content", {
2346
+ query: { id }
2347
+ }),
2184
2348
  getModelEndpoints: (model) => {
2185
2349
  assertAllowedModel(model, allowedModels);
2186
2350
  return request(`/models/${encodeModelPath(model)}/endpoints`);
@@ -2193,9 +2357,21 @@ var createOpenRouterClient = (config2) => {
2193
2357
  assertAllowedModel(model, allowedModels);
2194
2358
  return request(`/images/models/${encodeModelPath(model)}/endpoints`);
2195
2359
  },
2360
+ getPreset: (slug) => request(`/presets/${encodeURIComponent(slug)}`),
2361
+ getPresetVersion: (slug, version) => request(`/presets/${encodeURIComponent(slug)}/versions/${encodeURIComponent(String(version))}`),
2362
+ getTaskClassifications: (window = "7d") => request("/classifications/task", {
2363
+ query: { window }
2364
+ }),
2196
2365
  getVideo: (id) => request(`/videos/${encodeURIComponent(id)}`),
2366
+ getWorkspace: (id) => request(`/workspaces/${encodeURIComponent(id)}`),
2197
2367
  listImageModels: async () => filterModelList(await request("/images/models")),
2198
- listFiles: (query) => request("/files", { query }),
2368
+ listEmbeddingModels: async () => filterModelList(await request("/embeddings/models")),
2369
+ listFiles: (query) => request("/files", {
2370
+ query: {
2371
+ ...query,
2372
+ workspace_id: query?.workspace_id ?? defaultWorkspaceId
2373
+ }
2374
+ }),
2199
2375
  listModels,
2200
2376
  listUserModels: async () => filterModelList(await request("/models/user")),
2201
2377
  listZdrEndpoints: async () => {
@@ -2210,11 +2386,20 @@ var createOpenRouterClient = (config2) => {
2210
2386
  countModels: (outputModalities) => request("/models/count", {
2211
2387
  query: { output_modalities: outputModalities }
2212
2388
  }),
2213
- listPresets: (offset = 0, limit = 100) => request("/presets", { query: { limit, offset } }),
2389
+ listPresets: (offset = 0, limit = 100) => request("/presets", {
2390
+ query: { limit, offset }
2391
+ }),
2214
2392
  listPresetVersions: (slug, offset = 0, limit = 100) => request(`/presets/${encodeURIComponent(slug)}/versions`, { query: { limit, offset } }),
2215
2393
  listProviders: () => request("/providers"),
2216
2394
  listRerankModels: async () => filterModelList(await request("/rerank/models")),
2217
2395
  listVideoModels: async () => filterModelList(await request("/videos/models")),
2396
+ listWorkspaceBudgets: (id) => request(`/workspaces/${encodeURIComponent(id)}/budgets`),
2397
+ listWorkspaces: (offset = 0, limit = 100) => request("/workspaces", { query: { limit, offset } }),
2398
+ queryAnalytics: (body) => request("/analytics/query", {
2399
+ body,
2400
+ method: "POST"
2401
+ }),
2402
+ removeWorkspaceMembers: (id, userIds) => request(`/workspaces/${encodeURIComponent(id)}/members/remove`, { body: { user_ids: [...userIds] }, method: "POST" }),
2218
2403
  request,
2219
2404
  requestRaw,
2220
2405
  streamImage: async function* (body, options = {}) {
@@ -2267,8 +2452,41 @@ var createOpenRouterClient = (config2) => {
2267
2452
  return request("/files", {
2268
2453
  body,
2269
2454
  method: "POST",
2270
- query: { workspace_id: options.workspaceId }
2455
+ query: { workspace_id: options.workspaceId ?? defaultWorkspaceId }
2271
2456
  });
2457
+ },
2458
+ updateWorkspace: (id, body) => {
2459
+ assertAllowedModelsInValue(body, allowedModels);
2460
+ return request(`/workspaces/${encodeURIComponent(id)}`, { body, method: "PATCH" });
2461
+ },
2462
+ upsertWorkspaceBudget: (id, interval, limitUsd) => request(`/workspaces/${encodeURIComponent(id)}/budgets/${interval}`, { body: { limit_usd: limitUsd }, method: "PUT" }),
2463
+ waitForBatch: async (id, options = {}) => {
2464
+ const intervalMs = options.intervalMs ?? 1000;
2465
+ const timeoutMs = options.timeoutMs;
2466
+ if (!Number.isFinite(intervalMs) || intervalMs < 0)
2467
+ throw new Error("OpenRouter batch intervalMs must be non-negative");
2468
+ if (timeoutMs !== undefined && (!Number.isFinite(timeoutMs) || timeoutMs < 0))
2469
+ throw new Error("OpenRouter batch timeoutMs must be non-negative");
2470
+ const startedAt = Date.now();
2471
+ for (;; ) {
2472
+ options.signal?.throwIfAborted();
2473
+ const batch = await getBatch(id);
2474
+ if (TERMINAL_BATCH_STATUSES.has(batch.status))
2475
+ return batch;
2476
+ if (timeoutMs !== undefined && Date.now() - startedAt + intervalMs > timeoutMs)
2477
+ throw new Error(`Timed out waiting for OpenRouter batch "${id}"`);
2478
+ await new Promise((resolve, reject) => {
2479
+ const onAbort = () => {
2480
+ clearTimeout(timeout);
2481
+ reject(options.signal?.reason);
2482
+ };
2483
+ const timeout = setTimeout(() => {
2484
+ options.signal?.removeEventListener("abort", onAbort);
2485
+ resolve();
2486
+ }, intervalMs);
2487
+ options.signal?.addEventListener("abort", onAbort, { once: true });
2488
+ });
2489
+ }
2272
2490
  }
2273
2491
  };
2274
2492
  };
@@ -2405,7 +2623,7 @@ var assertAllowedPreset = (preset, allowedPresets) => {
2405
2623
  var assertIndirectModels = (value, allowedModels, key = "") => {
2406
2624
  if (key === "model" && typeof value === "string")
2407
2625
  assertAllowedModel2(value, allowedModels);
2408
- if ((key === "models" || key === "analysis_models") && Array.isArray(value)) {
2626
+ if ((key === "models" || key === "analysis_models" || key === "allowed_models") && Array.isArray(value)) {
2409
2627
  for (const model of value) {
2410
2628
  if (typeof model === "string")
2411
2629
  assertAllowedModel2(model, allowedModels);
@@ -2419,6 +2637,84 @@ var assertIndirectModels = (value, allowedModels, key = "") => {
2419
2637
  assertIndirectModels(child, allowedModels, childKey);
2420
2638
  }
2421
2639
  };
2640
+ var assertIntegerRange = (label, value, minimum, maximum) => {
2641
+ if (value === undefined)
2642
+ return;
2643
+ if (!Number.isInteger(value) || value < minimum || maximum !== undefined && value > maximum)
2644
+ throw new Error(`OpenRouter ${label} must be an integer from ${minimum}${maximum === undefined ? " or greater" : ` to ${maximum}`}`);
2645
+ };
2646
+ var assertPluginOptions = (plugins) => {
2647
+ for (const plugin of plugins ?? []) {
2648
+ if (plugin.id === "response-healing")
2649
+ throw new Error("OpenRouter response-healing requires a non-streaming request; use createOpenRouterClient().chat()");
2650
+ if (plugin.id === "fusion") {
2651
+ const fusion = plugin;
2652
+ if (fusion.analysis_models && (fusion.analysis_models.length < 1 || fusion.analysis_models.length > 8))
2653
+ throw new Error("OpenRouter Fusion analysis_models must contain 1-8 models");
2654
+ assertIntegerRange("Fusion max_tool_calls", fusion.max_tool_calls, 1, 16);
2655
+ }
2656
+ if (plugin.id === "web") {
2657
+ const web = plugin;
2658
+ assertIntegerRange("web plugin max_results", web.max_results, 1, web.engine === "perplexity" ? 20 : 25);
2659
+ if (web.include_domains?.length && web.exclude_domains?.length && (web.engine === "firecrawl" || web.engine === "parallel" || web.engine === "perplexity"))
2660
+ throw new Error(`OpenRouter ${web.engine} web plugin cannot combine include_domains and exclude_domains`);
2661
+ }
2662
+ }
2663
+ };
2664
+ var assertServerToolOptions = (tools) => {
2665
+ for (const tool of tools ?? []) {
2666
+ if (tool.type === "openrouter:web_search") {
2667
+ const parameters = tool.parameters;
2668
+ assertIntegerRange("web search max_results", parameters?.max_results, 1, 25);
2669
+ if (parameters?.engine === "perplexity" && (parameters.max_results ?? 0) > 20)
2670
+ throw new Error("OpenRouter Perplexity web search max_results must be at most 20");
2671
+ assertIntegerRange("web search max_characters", parameters?.max_characters, 1, 1e5);
2672
+ assertIntegerRange("web search max_total_results", parameters?.max_total_results, 1);
2673
+ }
2674
+ if (tool.type === "openrouter:web_fetch") {
2675
+ assertIntegerRange("web fetch max_uses", tool.parameters?.max_uses, 1);
2676
+ assertIntegerRange("web fetch max_content_tokens", tool.parameters?.max_content_tokens, 1);
2677
+ }
2678
+ if (tool.type === "openrouter:image_generation") {
2679
+ const compression = tool.parameters?.output_compression;
2680
+ if (compression !== undefined && (!Number.isFinite(compression) || compression < 0 || compression > 100))
2681
+ throw new Error("OpenRouter image generation output_compression must be 0-100");
2682
+ }
2683
+ if (tool.type === "openrouter:subagent") {
2684
+ assertIntegerRange("subagent max_completion_tokens", tool.parameters.max_completion_tokens, 1);
2685
+ assertIntegerRange("subagent max_tool_calls", tool.parameters.max_tool_calls, 1, 25);
2686
+ const temperature = tool.parameters.temperature;
2687
+ if (temperature !== undefined && (!Number.isFinite(temperature) || temperature < 0 || temperature > 2))
2688
+ throw new Error("OpenRouter subagent temperature must be 0-2");
2689
+ assertServerToolOptions(tool.parameters.tools);
2690
+ }
2691
+ if (tool.type === "openrouter:advisor") {
2692
+ assertIntegerRange("advisor max_completion_tokens", tool.parameters?.max_completion_tokens, 1);
2693
+ const temperature = tool.parameters?.temperature;
2694
+ if (temperature !== undefined && (!Number.isFinite(temperature) || temperature < 0 || temperature > 2))
2695
+ throw new Error("OpenRouter advisor temperature must be 0-2");
2696
+ }
2697
+ if (tool.type === "openrouter:fusion") {
2698
+ const analysisModels = tool.parameters?.analysis_models;
2699
+ if (analysisModels && (analysisModels.length < 1 || analysisModels.length > 8))
2700
+ throw new Error("OpenRouter Fusion server tool analysis_models must contain 1-8 models");
2701
+ assertIntegerRange("Fusion server tool max_completion_tokens", tool.parameters?.max_completion_tokens, 1);
2702
+ assertIntegerRange("Fusion server tool max_tool_calls", tool.parameters?.max_tool_calls, 1, 16);
2703
+ const temperature = tool.parameters?.temperature;
2704
+ if (temperature !== undefined && (!Number.isFinite(temperature) || temperature < 0 || temperature > 2))
2705
+ throw new Error("OpenRouter Fusion server tool temperature must be 0-2");
2706
+ assertServerToolOptions(tool.parameters?.tools);
2707
+ }
2708
+ if (tool.type === "openrouter:shell") {
2709
+ assertIntegerRange("shell sleep_after_seconds", tool.parameters?.sleep_after_seconds, 0, 2592000);
2710
+ const environment = tool.parameters?.environment;
2711
+ if (environment?.type === "container_reference" && (environment.container_id.length < 1 || environment.container_id.length > 20))
2712
+ throw new Error("OpenRouter shell container_id must contain 1-20 characters");
2713
+ }
2714
+ if (tool.type === "openrouter:experimental__search_models")
2715
+ assertIntegerRange("model search max_results", tool.parameters?.max_results, 1, 20);
2716
+ }
2717
+ };
2422
2718
  var assertRequestOptions = (options, allowedModels, allowedPresets, allowedProviders) => {
2423
2719
  assertAllowedPreset(options.preset, allowedPresets);
2424
2720
  assertRequestRoutingPolicy(options.routing, allowedProviders);
@@ -2438,6 +2734,8 @@ var assertRequestOptions = (options, allowedModels, allowedPresets, allowedProvi
2438
2734
  assertIndirectModels(options.serverTools, allowedModels);
2439
2735
  assertIndirectModels(options.messagesTools, allowedModels);
2440
2736
  assertIndirectModels(options.plugins, allowedModels);
2737
+ assertPluginOptions(options.plugins);
2738
+ assertServerToolOptions(options.serverTools);
2441
2739
  if (options.extraBody) {
2442
2740
  const unsafe = Object.keys(options.extraBody).find((key) => SECURITY_SENSITIVE_EXTRA_BODY_FIELDS.has(key));
2443
2741
  if (unsafe)
@@ -2600,8 +2898,14 @@ export {
2600
2898
  openrouterMessages,
2601
2899
  openrouter,
2602
2900
  openRouterModelMatchesRule,
2603
- createOpenRouterClient
2901
+ generateOpenRouterPKCE,
2902
+ exchangeOpenRouterAuthCode,
2903
+ estimateOpenRouterModelCost,
2904
+ estimateOpenRouterCost,
2905
+ createOpenRouterKeyLinks,
2906
+ createOpenRouterClient,
2907
+ createOpenRouterAuthorizationUrl
2604
2908
  };
2605
2909
 
2606
- //# debugId=29E9DB40EA495C0E64756E2164756E21
2910
+ //# debugId=438B311BAC94C67664756E2164756E21
2607
2911
  //# sourceMappingURL=openrouter.js.map