@dereekb/openrouter 13.37.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 (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/firebase/index.cjs.default.js +1 -0
  4. package/firebase/index.cjs.js +666 -0
  5. package/firebase/index.cjs.mjs +2 -0
  6. package/firebase/index.d.ts +1 -0
  7. package/firebase/index.esm.js +626 -0
  8. package/firebase/package.json +25 -0
  9. package/firebase/src/index.d.ts +1 -0
  10. package/firebase/src/lib/index.d.ts +4 -0
  11. package/firebase/src/lib/openrouter.api.d.ts +226 -0
  12. package/firebase/src/lib/openrouter.id.d.ts +56 -0
  13. package/firebase/src/lib/openrouter.model.d.ts +609 -0
  14. package/firebase/src/lib/openrouter.query.d.ts +121 -0
  15. package/firebase-server/index.cjs.default.js +1 -0
  16. package/firebase-server/index.cjs.js +4520 -0
  17. package/firebase-server/index.cjs.mjs +2 -0
  18. package/firebase-server/index.d.ts +1 -0
  19. package/firebase-server/index.esm.js +4466 -0
  20. package/firebase-server/package.json +38 -0
  21. package/firebase-server/src/index.d.ts +1 -0
  22. package/firebase-server/src/lib/index.d.ts +10 -0
  23. package/firebase-server/src/lib/openrouter.action.server.d.ts +196 -0
  24. package/firebase-server/src/lib/openrouter.broadcast.d.ts +93 -0
  25. package/firebase-server/src/lib/openrouter.call.inline.d.ts +57 -0
  26. package/firebase-server/src/lib/openrouter.file.attachment.d.ts +97 -0
  27. package/firebase-server/src/lib/openrouter.module.d.ts +65 -0
  28. package/firebase-server/src/lib/openrouter.prompt.service.d.ts +109 -0
  29. package/firebase-server/src/lib/openrouter.runtask.handle.d.ts +56 -0
  30. package/firebase-server/src/lib/openrouter.runtask.service.d.ts +380 -0
  31. package/firebase-server/src/lib/openrouter.runtask.sweep.d.ts +170 -0
  32. package/firebase-server/src/lib/openrouter.state.accessor.d.ts +106 -0
  33. package/firebase-server/src/test/openrouter.fake.d.ts +134 -0
  34. package/index.cjs.default.js +1 -0
  35. package/index.cjs.js +1867 -0
  36. package/index.cjs.mjs +2 -0
  37. package/index.d.ts +1 -0
  38. package/index.esm.js +1771 -0
  39. package/package.json +32 -0
  40. package/src/index.d.ts +1 -0
  41. package/src/lib/index.d.ts +10 -0
  42. package/src/lib/openrouter.call.d.ts +268 -0
  43. package/src/lib/openrouter.config.d.ts +314 -0
  44. package/src/lib/openrouter.embedding.d.ts +87 -0
  45. package/src/lib/openrouter.generation.d.ts +46 -0
  46. package/src/lib/openrouter.input.d.ts +238 -0
  47. package/src/lib/openrouter.prompt.d.ts +79 -0
  48. package/src/lib/openrouter.request.d.ts +91 -0
  49. package/src/lib/openrouter.sdk.d.ts +37 -0
  50. package/src/lib/openrouter.tool.d.ts +99 -0
  51. package/src/lib/openrouter.type.d.ts +125 -0
package/index.esm.js ADDED
@@ -0,0 +1,1771 @@
1
+ import { filterUndefinedValues, mergeObjects, arrayToMap } from '@dereekb/util';
2
+ import { callModel } from '@openrouter/sdk/funcs/call-model';
3
+ export { callModel } from '@openrouter/sdk/funcs/call-model';
4
+ import { responsesSend } from '@openrouter/sdk/funcs/responsesSend';
5
+ export { responsesSend } from '@openrouter/sdk/funcs/responsesSend';
6
+ import { unsentResultsToAPIFormat } from '@openrouter/sdk/lib/conversation-state';
7
+ export { unsentResultsToAPIFormat } from '@openrouter/sdk/lib/conversation-state';
8
+ import { embeddingsGenerate } from '@openrouter/sdk/funcs/embeddingsGenerate';
9
+ export { embeddingsGenerate } from '@openrouter/sdk/funcs/embeddingsGenerate';
10
+ import { generationsGetGeneration } from '@openrouter/sdk/funcs/generationsGetGeneration';
11
+ export { generationsGetGeneration } from '@openrouter/sdk/funcs/generationsGetGeneration';
12
+ import { generationsListGenerationContent } from '@openrouter/sdk/funcs/generationsListGenerationContent';
13
+ export { generationsListGenerationContent } from '@openrouter/sdk/funcs/generationsListGenerationContent';
14
+ import { ModelResult } from '@openrouter/sdk/lib/model-result';
15
+ export { ModelResult } from '@openrouter/sdk/lib/model-result';
16
+ export { tool } from '@openrouter/sdk/lib/tool';
17
+ import { convertToolsToAPIFormat } from '@openrouter/sdk/lib/tool-executor';
18
+ export { convertToolsToAPIFormat } from '@openrouter/sdk/lib/tool-executor';
19
+ import { stepCountIs } from '@openrouter/sdk/lib/stop-conditions';
20
+ export { finishReasonIs, hasToolCall, maxCost, maxTokensUsed, stepCountIs } from '@openrouter/sdk/lib/stop-conditions';
21
+ import { isManualTool } from '@openrouter/sdk/lib/tool-types';
22
+ export { ToolType, isManualTool } from '@openrouter/sdk/lib/tool-types';
23
+
24
+ function _array_like_to_array$1(arr, len) {
25
+ if (len == null || len > arr.length) len = arr.length;
26
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
27
+ return arr2;
28
+ }
29
+ function _array_without_holes$1(arr) {
30
+ if (Array.isArray(arr)) return _array_like_to_array$1(arr);
31
+ }
32
+ function asyncGeneratorStep$2(gen, resolve, reject, _next, _throw, key, arg) {
33
+ try {
34
+ var info = gen[key](arg);
35
+ var value = info.value;
36
+ } catch (error) {
37
+ reject(error);
38
+ return;
39
+ }
40
+ if (info.done) {
41
+ resolve(value);
42
+ } else {
43
+ Promise.resolve(value).then(_next, _throw);
44
+ }
45
+ }
46
+ function _async_to_generator$2(fn) {
47
+ return function() {
48
+ var self = this, args = arguments;
49
+ return new Promise(function(resolve, reject) {
50
+ var gen = fn.apply(self, args);
51
+ function _next(value) {
52
+ asyncGeneratorStep$2(gen, resolve, reject, _next, _throw, "next", value);
53
+ }
54
+ function _throw(err) {
55
+ asyncGeneratorStep$2(gen, resolve, reject, _next, _throw, "throw", err);
56
+ }
57
+ _next(undefined);
58
+ });
59
+ };
60
+ }
61
+ function _define_property$2(obj, key, value) {
62
+ if (key in obj) {
63
+ Object.defineProperty(obj, key, {
64
+ value: value,
65
+ enumerable: true,
66
+ configurable: true,
67
+ writable: true
68
+ });
69
+ } else {
70
+ obj[key] = value;
71
+ }
72
+ return obj;
73
+ }
74
+ function _iterable_to_array$1(iter) {
75
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
76
+ }
77
+ function _non_iterable_spread$1() {
78
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
79
+ }
80
+ function _object_spread$2(target) {
81
+ for(var i = 1; i < arguments.length; i++){
82
+ var source = arguments[i] != null ? arguments[i] : {};
83
+ var ownKeys = Object.keys(source);
84
+ if (typeof Object.getOwnPropertySymbols === "function") {
85
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
86
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
87
+ }));
88
+ }
89
+ ownKeys.forEach(function(key) {
90
+ _define_property$2(target, key, source[key]);
91
+ });
92
+ }
93
+ return target;
94
+ }
95
+ function ownKeys$1(object, enumerableOnly) {
96
+ var keys = Object.keys(object);
97
+ if (Object.getOwnPropertySymbols) {
98
+ var symbols = Object.getOwnPropertySymbols(object);
99
+ keys.push.apply(keys, symbols);
100
+ }
101
+ return keys;
102
+ }
103
+ function _object_spread_props$1(target, source) {
104
+ source = source != null ? source : {};
105
+ if (Object.getOwnPropertyDescriptors) {
106
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
107
+ } else {
108
+ ownKeys$1(Object(source)).forEach(function(key) {
109
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
110
+ });
111
+ }
112
+ return target;
113
+ }
114
+ function _object_without_properties$1(source, excluded) {
115
+ if (source == null) return {};
116
+ var target = {}, sourceKeys, key, i;
117
+ if (typeof Reflect !== "undefined" && Reflect.ownKeys) {
118
+ sourceKeys = Reflect.ownKeys(Object(source));
119
+ for(i = 0; i < sourceKeys.length; i++){
120
+ key = sourceKeys[i];
121
+ if (excluded.indexOf(key) >= 0) continue;
122
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
123
+ target[key] = source[key];
124
+ }
125
+ return target;
126
+ }
127
+ target = _object_without_properties_loose$1(source, excluded);
128
+ if (Object.getOwnPropertySymbols) {
129
+ sourceKeys = Object.getOwnPropertySymbols(source);
130
+ for(i = 0; i < sourceKeys.length; i++){
131
+ key = sourceKeys[i];
132
+ if (excluded.indexOf(key) >= 0) continue;
133
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
134
+ target[key] = source[key];
135
+ }
136
+ }
137
+ return target;
138
+ }
139
+ function _object_without_properties_loose$1(source, excluded) {
140
+ if (source == null) return {};
141
+ var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
142
+ for(i = 0; i < sourceKeys.length; i++){
143
+ key = sourceKeys[i];
144
+ if (excluded.indexOf(key) >= 0) continue;
145
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
146
+ target[key] = source[key];
147
+ }
148
+ return target;
149
+ }
150
+ function _to_consumable_array$1(arr) {
151
+ return _array_without_holes$1(arr) || _iterable_to_array$1(arr) || _unsupported_iterable_to_array$1(arr) || _non_iterable_spread$1();
152
+ }
153
+ function _type_of(obj) {
154
+ "@swc/helpers - typeof";
155
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
156
+ }
157
+ function _unsupported_iterable_to_array$1(o, minLen) {
158
+ if (!o) return;
159
+ if (typeof o === "string") return _array_like_to_array$1(o, minLen);
160
+ var n = Object.prototype.toString.call(o).slice(8, -1);
161
+ if (n === "Object" && o.constructor) n = o.constructor.name;
162
+ if (n === "Map" || n === "Set") return Array.from(n);
163
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$1(o, minLen);
164
+ }
165
+ function _ts_generator$2(thisArg, body) {
166
+ var f, y, t, _ = {
167
+ label: 0,
168
+ sent: function() {
169
+ if (t[0] & 1) throw t[1];
170
+ return t[1];
171
+ },
172
+ trys: [],
173
+ ops: []
174
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
175
+ return d(g, "next", {
176
+ value: verb(0)
177
+ }), d(g, "throw", {
178
+ value: verb(1)
179
+ }), d(g, "return", {
180
+ value: verb(2)
181
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
182
+ value: function() {
183
+ return this;
184
+ }
185
+ }), g;
186
+ function verb(n) {
187
+ return function(v) {
188
+ return step([
189
+ n,
190
+ v
191
+ ]);
192
+ };
193
+ }
194
+ function step(op) {
195
+ if (f) throw new TypeError("Generator is already executing.");
196
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
197
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
198
+ if (y = 0, t) op = [
199
+ op[0] & 2,
200
+ t.value
201
+ ];
202
+ switch(op[0]){
203
+ case 0:
204
+ case 1:
205
+ t = op;
206
+ break;
207
+ case 4:
208
+ _.label++;
209
+ return {
210
+ value: op[1],
211
+ done: false
212
+ };
213
+ case 5:
214
+ _.label++;
215
+ y = op[1];
216
+ op = [
217
+ 0
218
+ ];
219
+ continue;
220
+ case 7:
221
+ op = _.ops.pop();
222
+ _.trys.pop();
223
+ continue;
224
+ default:
225
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
226
+ _ = 0;
227
+ continue;
228
+ }
229
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
230
+ _.label = op[1];
231
+ break;
232
+ }
233
+ if (op[0] === 6 && _.label < t[1]) {
234
+ _.label = t[1];
235
+ t = op;
236
+ break;
237
+ }
238
+ if (t && _.label < t[2]) {
239
+ _.label = t[2];
240
+ _.ops.push(op);
241
+ break;
242
+ }
243
+ if (t[2]) _.ops.pop();
244
+ _.trys.pop();
245
+ continue;
246
+ }
247
+ op = body.call(thisArg, _);
248
+ } catch (e) {
249
+ op = [
250
+ 6,
251
+ e
252
+ ];
253
+ y = 0;
254
+ } finally{
255
+ f = t = 0;
256
+ }
257
+ if (op[0] & 5) throw op[1];
258
+ return {
259
+ value: op[0] ? op[1] : void 0,
260
+ done: true
261
+ };
262
+ }
263
+ }
264
+ /**
265
+ * Splits a model config into request parameters and execution controls.
266
+ *
267
+ * Forwarding one of ours is not harmless: OpenRouter validates the request body, so leaving `maxSteps` on
268
+ * it risks a 400 on the whole call. Which keys are ours is expressed by naming them in a rest-destructure
269
+ * rather than in a list of strings, so TypeScript checks the names against
270
+ * {@link OpenRouterModelConfig} and a rename cannot leave a stale entry behind.
271
+ *
272
+ * @param config - The merged model config.
273
+ * @returns The split config.
274
+ */ function splitOpenRouterModelConfig(config) {
275
+ var _ref = config !== null && config !== void 0 ? config : {}, maxSteps = _ref.maxSteps, requestTimeoutMs = _ref.requestTimeoutMs, rest = _object_without_properties$1(_ref, [
276
+ "maxSteps",
277
+ "requestTimeoutMs"
278
+ ]);
279
+ return {
280
+ requestConfig: filterUndefinedValues(rest),
281
+ maxSteps: maxSteps,
282
+ requestTimeoutMs: requestTimeoutMs
283
+ };
284
+ }
285
+ /**
286
+ * The hosted (server-executed) tool entries a config carries, e.g. `file_search`, `web_search`, `mcp`.
287
+ *
288
+ * These are NOT client tools and must never be handed to `callModel`: it destructures `tools` off the
289
+ * request and runs every entry through `convertToolsToAPIFormat`, which reads `tool.function.name` — so
290
+ * a hosted entry is dropped outright when no client tools are present and throws a
291
+ * `Cannot read properties of undefined` from inside the SDK when they are. They are dispatched instead
292
+ * by {@link sendOpenRouterResponsesRequest} or merged in after conversion by
293
+ * {@link openRouterModelResultForRequest}.
294
+ *
295
+ * @param config - The merged model config.
296
+ * @returns The hosted tool entries, or an empty array.
297
+ *
298
+ * @__NO_SIDE_EFFECTS__
299
+ */ function openRouterHostedTools(config) {
300
+ var tools = config === null || config === void 0 ? void 0 : config.tools;
301
+ return Array.isArray(tools) ? tools : [];
302
+ }
303
+ /**
304
+ * Converts a built request into the `/responses` request body.
305
+ *
306
+ * This is the whole wire body minus the SDK-only keys (`tools`/`state`/`stopWhen` on the `callModel`
307
+ * path), so both dispatch paths assemble the request the same way and cannot drift.
308
+ *
309
+ * @param request - The built request.
310
+ * @returns The request body, in the SDK's camelCase request surface.
311
+ */ function openRouterResponsesRequestBody(request) {
312
+ var requestConfig = splitOpenRouterModelConfig(request.config).requestConfig;
313
+ return filterUndefinedValues(_object_spread_props$1(_object_spread$2({}, requestConfig), {
314
+ input: request.input,
315
+ instructions: request.instructions || undefined,
316
+ trace: request.trace == null ? undefined : {
317
+ additionalProperties: _object_spread$2({}, request.trace)
318
+ }
319
+ }));
320
+ }
321
+ /**
322
+ * Converts a built request into the `callModel` input.
323
+ *
324
+ * Any hosted tools on the config are STRIPPED here rather than passed through: `callModel` owns the
325
+ * `tools` key and converts every entry as a client function tool. Hosted entries are re-attached after
326
+ * that conversion by {@link openRouterModelResultForRequest}.
327
+ *
328
+ * @param params - The request, tools, and state accessor.
329
+ * @returns The `callModel` input.
330
+ */ function openRouterCallModelInput(params) {
331
+ var request = params.request, tools = params.tools, state = params.state;
332
+ var maxSteps = splitOpenRouterModelConfig(request.config).maxSteps;
333
+ // dropped by name rather than by mutation, so TypeScript sees which keys leave the body: the hosted
334
+ // tools `callModel` cannot carry, and a config-set `stream` the non-streaming path must not inherit.
335
+ var _openRouterResponsesRequestBody = openRouterResponsesRequestBody(request); _openRouterResponsesRequestBody.tools; _openRouterResponsesRequestBody.stream; var body = _object_without_properties$1(_openRouterResponsesRequestBody, [
336
+ "tools",
337
+ "stream"
338
+ ]);
339
+ var input = filterUndefinedValues(_object_spread_props$1(_object_spread$2({}, body), {
340
+ tools: tools !== null && tools !== void 0 ? tools : undefined,
341
+ state: state !== null && state !== void 0 ? state : undefined,
342
+ stopWhen: maxSteps == null ? undefined : stepCountIs(maxSteps)
343
+ }));
344
+ return input;
345
+ }
346
+ /**
347
+ * Header `callModel` stamps on every request it dispatches, so OpenRouter can tell an agent-loop request
348
+ * apart from a plain one. Replicated on the merged hosted-tool path, which is a `callModel` request in
349
+ * everything but the entry point.
350
+ */ var OPENROUTER_CALL_MODEL_HEADER = 'x-openrouter-callmodel';
351
+ /**
352
+ * Builds the request options for a call, folding in the config's `requestTimeoutMs`.
353
+ *
354
+ * @param options - Caller-supplied options.
355
+ * @param requestTimeoutMs - The per-request timeout from the config, when it set one.
356
+ * @returns The merged options.
357
+ */ function openRouterRequestOptions(options, requestTimeoutMs) {
358
+ return _object_spread$2({}, options, requestTimeoutMs == null ? undefined : {
359
+ timeoutMs: requestTimeoutMs
360
+ });
361
+ }
362
+ /**
363
+ * Copies request options and stamps the `x-openrouter-callmodel` header onto them.
364
+ *
365
+ * Both header sources are read for the same reason `callModel` reads both: the SDK resolves
366
+ * `options.headers ?? options.fetchOptions.headers`, so setting `headers` alone would SHADOW a caller
367
+ * who passed theirs through the (deprecated) `fetchOptions` instead of losing nothing.
368
+ *
369
+ * @param options - The request options.
370
+ * @returns Options carrying the caller's headers plus the callModel marker.
371
+ */ function openRouterCallModelRequestOptions(options) {
372
+ var _ref, _options_headers;
373
+ var _options_fetchOptions;
374
+ // eslint-disable-next-line @typescript-eslint/no-deprecated
375
+ var headers = new Headers((_ref = (_options_headers = options.headers) !== null && _options_headers !== void 0 ? _options_headers : (_options_fetchOptions = options.fetchOptions) === null || _options_fetchOptions === void 0 ? void 0 : _options_fetchOptions.headers) !== null && _ref !== void 0 ? _ref : undefined);
376
+ headers.set(OPENROUTER_CALL_MODEL_HEADER, 'true');
377
+ return _object_spread_props$1(_object_spread$2({}, options), {
378
+ headers: headers
379
+ });
380
+ }
381
+ /**
382
+ * Sends a built request straight to `/responses`, bypassing `callModel` entirely.
383
+ *
384
+ * This is the path hosted (server-executed) tools take. `callModel` cannot carry them — it converts
385
+ * every `tools` entry as a client function tool — and there is nothing for its loop to do on a run whose
386
+ * tools are executed upstream anyway. Going direct also keeps the response VERBATIM: the request is
387
+ * non-streaming, so the returned `OpenResponsesResult` is the body OpenRouter sent rather than one
388
+ * reassembled from stream events, which is what preserves hosted-tool output items such as a
389
+ * `file_search_call` and the chunks `include: ['file_search_call.results']` asked for.
390
+ *
391
+ * @param params - The client, request, and options.
392
+ * @returns The response.
393
+ * @throws {Error} When the request fails, or when a streaming response comes back for a non-streaming request.
394
+ */ function sendOpenRouterResponsesRequest(params) {
395
+ return _async_to_generator$2(function() {
396
+ var client, request, options, requestTimeoutMs, responsesRequest, result;
397
+ return _ts_generator$2(this, function(_state) {
398
+ switch(_state.label){
399
+ case 0:
400
+ client = params.client, request = params.request, options = params.options;
401
+ requestTimeoutMs = splitOpenRouterModelConfig(request.config).requestTimeoutMs;
402
+ responsesRequest = _object_spread_props$1(_object_spread$2({}, openRouterResponsesRequestBody(request)), {
403
+ stream: false
404
+ });
405
+ return [
406
+ 4,
407
+ responsesSend(client, {
408
+ responsesRequest: responsesRequest
409
+ }, openRouterRequestOptions(options, requestTimeoutMs))
410
+ ];
411
+ case 1:
412
+ result = _state.sent();
413
+ if (!result.ok) {
414
+ throw result.error;
415
+ }
416
+ // `stream: false` narrows the SDK's response union by contract only, so the narrowing is asserted
417
+ // rather than assumed: an event stream read as a result yields a value whose every field is undefined,
418
+ // which a caller would store as a successful call that produced nothing.
419
+ if (typeof result.value[Symbol.asyncIterator] === 'function') {
420
+ throw new TypeError('OpenRouter returned a streaming response for a non-streaming `/responses` request.');
421
+ }
422
+ return [
423
+ 2,
424
+ result.value
425
+ ];
426
+ }
427
+ });
428
+ })();
429
+ }
430
+ /**
431
+ * Starts a call for a built request and returns the SDK's `ModelResult` without consuming it.
432
+ *
433
+ * Use this when the caller needs the streaming / tool-event surface. Most callers want
434
+ * {@link callModelForOpenRouterRequest}, which consumes the result into a normalized value.
435
+ *
436
+ * Hosted tools and client tools are NOT mutually exclusive here. When a config carries hosted tools this
437
+ * assembles the `ModelResult` itself — client tools converted to API format exactly as `callModel` would,
438
+ * with the hosted entries appended after that conversion — so a run can search a vector store AND drive
439
+ * the client-side tool loop. `callModel` cannot express that: it owns the `tools` key and there is no
440
+ * seam between its conversion and dispatch. Everything else about the run is unchanged, including the
441
+ * `x-openrouter-callmodel` header and the `stopWhen` step ceiling.
442
+ *
443
+ * @param params - The client, request, tools, state, and options.
444
+ * @returns The in-flight model result.
445
+ */ function openRouterModelResultForRequest(params) {
446
+ var client = params.client, request = params.request, tools = params.tools, state = params.state, options = params.options;
447
+ var _splitOpenRouterModelConfig = splitOpenRouterModelConfig(request.config), maxSteps = _splitOpenRouterModelConfig.maxSteps, requestTimeoutMs = _splitOpenRouterModelConfig.requestTimeoutMs;
448
+ var requestOptions = openRouterRequestOptions(options, requestTimeoutMs);
449
+ var hostedTools = openRouterHostedTools(request.config);
450
+ var result;
451
+ if (hostedTools.length === 0) {
452
+ result = callModel(client, openRouterCallModelInput(params), requestOptions);
453
+ } else {
454
+ // `stream` is dropped by name, exactly as the `callModel` path drops it, so neither path can inherit
455
+ // a config-set value.
456
+ var _openRouterResponsesRequestBody = openRouterResponsesRequestBody(request); _openRouterResponsesRequestBody.stream; var body = _object_without_properties$1(_openRouterResponsesRequestBody, [
457
+ "stream"
458
+ ]);
459
+ var apiRequest = _object_spread_props$1(_object_spread$2({}, body), {
460
+ tools: _to_consumable_array$1(tools == null ? [] : convertToolsToAPIFormat(tools)).concat(_to_consumable_array$1(hostedTools))
461
+ });
462
+ result = new ModelResult(_object_spread$2({
463
+ client: client,
464
+ request: apiRequest,
465
+ options: openRouterCallModelRequestOptions(requestOptions)
466
+ }, tools == null ? undefined : {
467
+ tools: tools
468
+ }, state == null ? undefined : {
469
+ state: state
470
+ }, maxSteps == null ? undefined : {
471
+ stopWhen: stepCountIs(maxSteps)
472
+ }));
473
+ }
474
+ return result;
475
+ }
476
+ /**
477
+ * Runs a built request to completion and normalizes the response.
478
+ *
479
+ * Routes to the direct `/responses` path for a hosted-tool run that needs no client-side tool loop, and
480
+ * to `ModelResult` otherwise. The caller does not choose: which transport a request needs is a property
481
+ * of the request, and making it a parameter would only create a way to get it wrong.
482
+ *
483
+ * @param params - The client, request, tools, state, and options.
484
+ * @returns The normalized call result.
485
+ */ function callModelForOpenRouterRequest(params) {
486
+ return _async_to_generator$2(function() {
487
+ var _ref, _params_tools, needsClientToolLoop, sendDirect, response, _tmp;
488
+ return _ts_generator$2(this, function(_state) {
489
+ switch(_state.label){
490
+ case 0:
491
+ // Client tools and a `StateAccessor` both live on `ModelResult`, so a run using either needs the loop
492
+ // that executes tools and round-trips conversation state — even when its hosted tools would otherwise
493
+ // qualify it for the direct path.
494
+ needsClientToolLoop = ((_ref = (_params_tools = params.tools) === null || _params_tools === void 0 ? void 0 : _params_tools.length) !== null && _ref !== void 0 ? _ref : 0) > 0 || params.state != null;
495
+ sendDirect = openRouterHostedTools(params.request.config).length > 0 && !needsClientToolLoop;
496
+ if (!sendDirect) return [
497
+ 3,
498
+ 2
499
+ ];
500
+ return [
501
+ 4,
502
+ sendOpenRouterResponsesRequest(params)
503
+ ];
504
+ case 1:
505
+ _tmp = _state.sent();
506
+ return [
507
+ 3,
508
+ 4
509
+ ];
510
+ case 2:
511
+ return [
512
+ 4,
513
+ openRouterModelResultForRequest(params).getResponse()
514
+ ];
515
+ case 3:
516
+ _tmp = _state.sent();
517
+ _state.label = 4;
518
+ case 4:
519
+ response = _tmp;
520
+ return [
521
+ 2,
522
+ openRouterCallResultFromResponse(response)
523
+ ];
524
+ }
525
+ });
526
+ })();
527
+ }
528
+ /**
529
+ * Normalizes an OpenRouter response into an {@link OpenRouterCallResult}.
530
+ *
531
+ * @param response - The response to normalize.
532
+ * @returns The normalized result.
533
+ */ function openRouterCallResultFromResponse(response) {
534
+ var outputText = openRouterOutputTextFromResponse(response);
535
+ var usage = response.usage;
536
+ return {
537
+ outputText: outputText,
538
+ outputJson: parseOpenRouterJsonOutput(outputText),
539
+ generationIds: response.id ? [
540
+ response.id
541
+ ] : [],
542
+ usage: usage == null ? undefined : openRouterRunUsageFromResponseUsage(usage),
543
+ model: response.model,
544
+ error: response.error == null ? undefined : openRouterRunErrorFromResponseError(response.error),
545
+ response: response
546
+ };
547
+ }
548
+ /**
549
+ * Reads the assistant text out of a response.
550
+ *
551
+ * The convenience `output_text` field is NOT populated by OpenRouter's `/responses` API — verified live,
552
+ * on both a streaming and a non-streaming request: the body carries `output` items (`reasoning`, then
553
+ * `message`) and no `output_text` at all. Reading that field alone therefore returns undefined for every
554
+ * real call, so a run task would store an empty `o` on a call that answered perfectly well and was
555
+ * charged for.
556
+ *
557
+ * Text is concatenated across ALL message items rather than just the first, since nothing guarantees a
558
+ * response is limited to one.
559
+ *
560
+ * @param response - The response.
561
+ * @returns The output text, or undefined when the response carried none.
562
+ */ function openRouterOutputTextFromResponse(response) {
563
+ var result = response.outputText;
564
+ if (!result) {
565
+ var _response_output;
566
+ var text = ((_response_output = response.output) !== null && _response_output !== void 0 ? _response_output : []).filter(function(item) {
567
+ return item.type === 'message';
568
+ }).flatMap(function(item) {
569
+ var _item_content;
570
+ return (_item_content = item.content) !== null && _item_content !== void 0 ? _item_content : [];
571
+ }).filter(function(part) {
572
+ return part.type === 'output_text';
573
+ }).map(function(part) {
574
+ var _part_text;
575
+ return (_part_text = part.text) !== null && _part_text !== void 0 ? _part_text : '';
576
+ }).join('');
577
+ result = text || undefined;
578
+ }
579
+ return result;
580
+ }
581
+ /**
582
+ * Flattens the SDK's nested usage object.
583
+ *
584
+ * A measurement the response did not report is OMITTED rather than carried as `undefined` or `null`.
585
+ *
586
+ * @param usage - The SDK usage object.
587
+ * @returns The flattened usage.
588
+ *
589
+ * @__NO_SIDE_EFFECTS__
590
+ */ function openRouterRunUsageFromResponseUsage(usage) {
591
+ var inputTokens = usage.inputTokens, outputTokens = usage.outputTokens, totalTokens = usage.totalTokens, cost = usage.cost, isByok = usage.isByok, inputTokensDetails = usage.inputTokensDetails, outputTokensDetails = usage.outputTokensDetails;
592
+ return filterUndefinedValues({
593
+ inputTokens: inputTokens,
594
+ outputTokens: outputTokens,
595
+ totalTokens: totalTokens,
596
+ reasoningTokens: outputTokensDetails === null || outputTokensDetails === void 0 ? void 0 : outputTokensDetails.reasoningTokens,
597
+ cachedTokens: inputTokensDetails === null || inputTokensDetails === void 0 ? void 0 : inputTokensDetails.cachedTokens,
598
+ cost: cost,
599
+ isByok: isByok
600
+ }, true);
601
+ }
602
+ /**
603
+ * Flattens the error an OpenRouter response reports in its body.
604
+ *
605
+ * Named rather than inlined at the one call site for the same reason
606
+ * {@link openRouterRunUsageFromResponseUsage} is: a library that exports `OpenRouterRunError` as a type
607
+ * should let a caller holding a raw `OpenResponsesResult` produce one without transcribing its shape.
608
+ *
609
+ * `code` goes through `String()` because OpenRouter reports a NUMERIC code here (the HTTP status), while
610
+ * `OpenRouterRunError.code` is a string — the same field an SDK-thrown error fills with `ECONNRESET`.
611
+ *
612
+ * @param error - The error reported on the response.
613
+ * @returns The flattened error.
614
+ *
615
+ * @__NO_SIDE_EFFECTS__
616
+ */ function openRouterRunErrorFromResponseError(error) {
617
+ var code = error.code, message = error.message;
618
+ return {
619
+ code: code == null ? undefined : String(code),
620
+ message: message
621
+ };
622
+ }
623
+ /**
624
+ * Parses model output as a JSON object.
625
+ *
626
+ * Returns undefined rather than throwing on anything that is not a JSON object: a model asked for
627
+ * text can and will return prose, and that is not an error.
628
+ *
629
+ * @param outputText - The output text.
630
+ * @returns The parsed object, or undefined when the output is not a JSON object.
631
+ */ function parseOpenRouterJsonOutput(outputText) {
632
+ var result;
633
+ if (outputText) {
634
+ try {
635
+ var parsed = JSON.parse(outputText);
636
+ if (parsed != null && (typeof parsed === "undefined" ? "undefined" : _type_of(parsed)) === 'object' && !Array.isArray(parsed)) {
637
+ result = parsed;
638
+ }
639
+ } catch (unused) {
640
+ // not JSON — leave undefined
641
+ }
642
+ }
643
+ return result;
644
+ }
645
+
646
+ function _define_property$1(obj, key, value) {
647
+ if (key in obj) {
648
+ Object.defineProperty(obj, key, {
649
+ value: value,
650
+ enumerable: true,
651
+ configurable: true,
652
+ writable: true
653
+ });
654
+ } else {
655
+ obj[key] = value;
656
+ }
657
+ return obj;
658
+ }
659
+ function _object_spread$1(target) {
660
+ for(var i = 1; i < arguments.length; i++){
661
+ var source = arguments[i] != null ? arguments[i] : {};
662
+ var ownKeys = Object.keys(source);
663
+ if (typeof Object.getOwnPropertySymbols === "function") {
664
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
665
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
666
+ }));
667
+ }
668
+ ownKeys.forEach(function(key) {
669
+ _define_property$1(target, key, source[key]);
670
+ });
671
+ }
672
+ return target;
673
+ }
674
+ /**
675
+ * Builds a hosted `file_search` tool entry with the field names the SDK actually forwards.
676
+ *
677
+ * @param vectorStoreIds - The `vs_…` ids to search.
678
+ * @param maxNumResults - Optional cap on returned chunks.
679
+ * @returns The hosted tool entry.
680
+ *
681
+ * @__NO_SIDE_EFFECTS__
682
+ */ function openRouterFileSearchTool(vectorStoreIds, maxNumResults) {
683
+ return _object_spread$1({
684
+ type: 'file_search',
685
+ vectorStoreIds: vectorStoreIds
686
+ }, maxNumResults == null ? undefined : {
687
+ maxNumResults: maxNumResults
688
+ });
689
+ }
690
+ /**
691
+ * The default PDF parser engine this package pins.
692
+ *
693
+ * Pinned because the alternative is silent: with no engine named, OpenRouter downgrades any model it
694
+ * believes lacks native file support to `mistral-ocr`, inheriting its 8-image cap and per-page billing with
695
+ * no error — which on a multi-page document quietly truncates content.
696
+ *
697
+ * `native` rather than the equally-free `pdf-text` because it fails LOUDLY. It requires a model with
698
+ * native file input and 400s on one without, where `pdf-text` would hand a scanned PDF to the model as
699
+ * empty text and let it answer ungrounded. A caller on a text-only model wants
700
+ * `openRouterFileParserPlugin('pdf-text')` — see {@link OpenRouterPdfParserEngine}.
701
+ */ var DEFAULT_OPENROUTER_PDF_PARSER_ENGINE = 'native';
702
+ /**
703
+ * The `file-parser` plugin entry with the PDF engine pinned.
704
+ *
705
+ * @param engine - Engine to pin. Defaults to {@link DEFAULT_OPENROUTER_PDF_PARSER_ENGINE}.
706
+ * @returns The plugin config entry.
707
+ *
708
+ * @__NO_SIDE_EFFECTS__
709
+ */ function openRouterFileParserPlugin() {
710
+ var engine = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : DEFAULT_OPENROUTER_PDF_PARSER_ENGINE;
711
+ return {
712
+ id: 'file-parser',
713
+ pdf: {
714
+ engine: engine
715
+ }
716
+ };
717
+ }
718
+ /**
719
+ * A provider config that pins routing to a single provider with fallbacks off and parameter support
720
+ * required — the configuration that makes a BYOK request actually reach the intended upstream with
721
+ * every parameter intact.
722
+ *
723
+ * @param provider - The provider slug to pin to (e.g. `openai`).
724
+ * @returns The provider routing config.
725
+ *
726
+ * @__NO_SIDE_EFFECTS__
727
+ */ function openRouterProviderPinnedTo(provider) {
728
+ return {
729
+ only: [
730
+ provider
731
+ ],
732
+ allowFallbacks: false,
733
+ requireParameters: true
734
+ };
735
+ }
736
+ /**
737
+ * Merges model configs left-to-right, so the last input wins.
738
+ *
739
+ * Merging is SHALLOW by key: an override that supplies `provider` replaces the whole provider object
740
+ * rather than merging into it. That is the behaviour a caller wants — a half-overridden `provider`
741
+ * (say, `only` from the override and `allowFallbacks` from the version) is a configuration nobody
742
+ * wrote down and nobody can reason about.
743
+ *
744
+ * `undefined` values do not overwrite; an explicit `null` does (it is how a caller clears a value
745
+ * the version set).
746
+ *
747
+ * @param configs - Configs to merge, lowest priority first.
748
+ * @returns The merged config.
749
+ */ function mergeOpenRouterModelConfig(configs) {
750
+ return mergeObjects(configs);
751
+ }
752
+ /**
753
+ * Validates a merged model config, catching the misconfigurations that fail silently at runtime
754
+ * rather than loudly.
755
+ *
756
+ * @param config - The merged config to check.
757
+ * @returns The validation result.
758
+ */ function validateOpenRouterModelConfig(config) {
759
+ var errors = [];
760
+ var warnings = [];
761
+ if (config == null) {
762
+ errors.push('No model config was provided.');
763
+ } else {
764
+ var _ref;
765
+ var _config_models, _config_text, _config_plugins, _fileParser_pdf, _config_tools, _config_tools1, _config_provider, _config_provider_only, _config_provider1;
766
+ if (!config.model && !((_config_models = config.models) === null || _config_models === void 0 ? void 0 : _config_models.length)) {
767
+ errors.push('No `model` (or `models` fallback chain) was specified.');
768
+ }
769
+ var format = (_config_text = config.text) === null || _config_text === void 0 ? void 0 : _config_text.format;
770
+ if ((format === null || format === void 0 ? void 0 : format.type) === 'json_schema') {
771
+ if (!format.name) {
772
+ errors.push('A `json_schema` text format requires a `name`.');
773
+ }
774
+ if (!format.schema) {
775
+ errors.push('A `json_schema` text format requires a `schema`.');
776
+ }
777
+ }
778
+ var fileParser = (_config_plugins = config.plugins) === null || _config_plugins === void 0 ? void 0 : _config_plugins.find(function(x) {
779
+ return x.id === 'file-parser';
780
+ });
781
+ if (fileParser != null && !((_fileParser_pdf = fileParser.pdf) === null || _fileParser_pdf === void 0 ? void 0 : _fileParser_pdf.engine)) {
782
+ warnings.push('The `file-parser` plugin has no pinned `pdf.engine`; OpenRouter will silently fall back to `mistral-ocr` (8-image cap, per-page billing) on any model it believes lacks native file support.');
783
+ }
784
+ var hasHostedTools = ((_ref = (_config_tools = config.tools) === null || _config_tools === void 0 ? void 0 : _config_tools.length) !== null && _ref !== void 0 ? _ref : 0) > 0;
785
+ var fileSearchWithoutStores = (_config_tools1 = config.tools) === null || _config_tools1 === void 0 ? void 0 : _config_tools1.some(function(x) {
786
+ return x.type === 'file_search' && !Array.isArray(x['vectorStoreIds']);
787
+ });
788
+ if (fileSearchWithoutStores) {
789
+ // The SDK drops an unrecognized field (a `vector_store_ids` authored in wire case, say) during
790
+ // outbound serialization, leaving a tool that searches nothing and a model that answers ungrounded
791
+ // with no error at all. That is exactly the failure worth refusing to publish.
792
+ errors.push('A `file_search` hosted tool requires a `vectorStoreIds` array. Note the CAMELCASE — the SDK drops the wire-cased `vector_store_ids`, leaving a tool that searches nothing.');
793
+ }
794
+ if (hasHostedTools && ((_config_provider = config.provider) === null || _config_provider === void 0 ? void 0 : _config_provider.requireParameters) !== true) {
795
+ warnings.push('Hosted tools were requested without `provider.requireParameters: true`; a provider that does not support them receives only the parameters it supports and ignores the rest, returning an ungrounded answer with no error.');
796
+ }
797
+ if (((_config_provider1 = config.provider) === null || _config_provider1 === void 0 ? void 0 : (_config_provider_only = _config_provider1.only) === null || _config_provider_only === void 0 ? void 0 : _config_provider_only.length) && config.provider.allowFallbacks !== false) {
798
+ warnings.push('`provider.only` was set without `provider.allowFallbacks: false`, so routing can still leave the pinned provider.');
799
+ }
800
+ }
801
+ return {
802
+ valid: errors.length === 0,
803
+ errors: errors,
804
+ warnings: warnings
805
+ };
806
+ }
807
+
808
+ function asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, key, arg) {
809
+ try {
810
+ var info = gen[key](arg);
811
+ var value = info.value;
812
+ } catch (error) {
813
+ reject(error);
814
+ return;
815
+ }
816
+ if (info.done) {
817
+ resolve(value);
818
+ } else {
819
+ Promise.resolve(value).then(_next, _throw);
820
+ }
821
+ }
822
+ function _async_to_generator$1(fn) {
823
+ return function() {
824
+ var self = this, args = arguments;
825
+ return new Promise(function(resolve, reject) {
826
+ var gen = fn.apply(self, args);
827
+ function _next(value) {
828
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "next", value);
829
+ }
830
+ function _throw(err) {
831
+ asyncGeneratorStep$1(gen, resolve, reject, _next, _throw, "throw", err);
832
+ }
833
+ _next(undefined);
834
+ });
835
+ };
836
+ }
837
+ function _ts_generator$1(thisArg, body) {
838
+ var f, y, t, _ = {
839
+ label: 0,
840
+ sent: function() {
841
+ if (t[0] & 1) throw t[1];
842
+ return t[1];
843
+ },
844
+ trys: [],
845
+ ops: []
846
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
847
+ return d(g, "next", {
848
+ value: verb(0)
849
+ }), d(g, "throw", {
850
+ value: verb(1)
851
+ }), d(g, "return", {
852
+ value: verb(2)
853
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
854
+ value: function() {
855
+ return this;
856
+ }
857
+ }), g;
858
+ function verb(n) {
859
+ return function(v) {
860
+ return step([
861
+ n,
862
+ v
863
+ ]);
864
+ };
865
+ }
866
+ function step(op) {
867
+ if (f) throw new TypeError("Generator is already executing.");
868
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
869
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
870
+ if (y = 0, t) op = [
871
+ op[0] & 2,
872
+ t.value
873
+ ];
874
+ switch(op[0]){
875
+ case 0:
876
+ case 1:
877
+ t = op;
878
+ break;
879
+ case 4:
880
+ _.label++;
881
+ return {
882
+ value: op[1],
883
+ done: false
884
+ };
885
+ case 5:
886
+ _.label++;
887
+ y = op[1];
888
+ op = [
889
+ 0
890
+ ];
891
+ continue;
892
+ case 7:
893
+ op = _.ops.pop();
894
+ _.trys.pop();
895
+ continue;
896
+ default:
897
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
898
+ _ = 0;
899
+ continue;
900
+ }
901
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
902
+ _.label = op[1];
903
+ break;
904
+ }
905
+ if (op[0] === 6 && _.label < t[1]) {
906
+ _.label = t[1];
907
+ t = op;
908
+ break;
909
+ }
910
+ if (t && _.label < t[2]) {
911
+ _.label = t[2];
912
+ _.ops.push(op);
913
+ break;
914
+ }
915
+ if (t[2]) _.ops.pop();
916
+ _.trys.pop();
917
+ continue;
918
+ }
919
+ op = body.call(thisArg, _);
920
+ } catch (e) {
921
+ op = [
922
+ 6,
923
+ e
924
+ ];
925
+ y = 0;
926
+ } finally{
927
+ f = t = 0;
928
+ }
929
+ if (op[0] & 5) throw op[1];
930
+ return {
931
+ value: op[0] ? op[1] : void 0,
932
+ done: true
933
+ };
934
+ }
935
+ }
936
+ /**
937
+ * Generates embeddings.
938
+ *
939
+ * Base64-encoded embeddings are decoded to numbers before being returned, so a caller never has to
940
+ * branch on the encoding the model happened to use.
941
+ *
942
+ * @param params - The client, model, input, and routing options.
943
+ * @returns The embeddings.
944
+ */ function openRouterEmbeddings(params) {
945
+ return _async_to_generator$1(function() {
946
+ var _response_usage, _response_usage1, client, model, input, dimensions, inputType, provider, options, requestBody, result, response, embeddings;
947
+ return _ts_generator$1(this, function(_state) {
948
+ switch(_state.label){
949
+ case 0:
950
+ client = params.client, model = params.model, input = params.input, dimensions = params.dimensions, inputType = params.inputType, provider = params.provider, options = params.options;
951
+ requestBody = {
952
+ model: model,
953
+ input: input,
954
+ dimensions: dimensions !== null && dimensions !== void 0 ? dimensions : undefined,
955
+ inputType: inputType !== null && inputType !== void 0 ? inputType : undefined,
956
+ provider: provider !== null && provider !== void 0 ? provider : undefined
957
+ };
958
+ return [
959
+ 4,
960
+ embeddingsGenerate(client, {
961
+ requestBody: requestBody
962
+ }, options !== null && options !== void 0 ? options : undefined)
963
+ ];
964
+ case 1:
965
+ result = _state.sent();
966
+ if (!result.ok) {
967
+ throw result.error;
968
+ }
969
+ response = result.value;
970
+ if (typeof response === 'string') {
971
+ throw new TypeError('OpenRouter returned a non-JSON embeddings response.');
972
+ }
973
+ embeddings = response.data.map(function(entry, index) {
974
+ var _entry_index;
975
+ return {
976
+ index: (_entry_index = entry.index) !== null && _entry_index !== void 0 ? _entry_index : index,
977
+ embedding: openRouterEmbeddingVector(entry.embedding)
978
+ };
979
+ });
980
+ return [
981
+ 2,
982
+ {
983
+ model: response.model,
984
+ embeddings: embeddings,
985
+ promptTokens: (_response_usage = response.usage) === null || _response_usage === void 0 ? void 0 : _response_usage.promptTokens,
986
+ totalTokens: (_response_usage1 = response.usage) === null || _response_usage1 === void 0 ? void 0 : _response_usage1.totalTokens
987
+ }
988
+ ];
989
+ }
990
+ });
991
+ })();
992
+ }
993
+ /**
994
+ * Decodes a base64 string to bytes.
995
+ *
996
+ * `atob` is a WHATWG global, present on Node ≥16 and in every browser, so no Node-only `Buffer` is assumed.
997
+ * Anything outside the base64 alphabet — padding, embedded newlines from a wrapped response — is stripped
998
+ * first, which is what makes the input tolerant rather than strict.
999
+ *
1000
+ * @param base64 - The base64 string. Padding is optional.
1001
+ * @returns The decoded bytes.
1002
+ */ function openRouterDecodeBase64(base64) {
1003
+ // `charCodeAt`, not `codePointAt`: `atob` returns a latin1 string, so every character is a single UTF-16
1004
+ // code unit below 256. The two agree here, and only `charCodeAt` is typed to return a plain `number`.
1005
+ // eslint-disable-next-line unicorn/prefer-code-point
1006
+ return Uint8Array.from(atob(base64.replaceAll(/[^A-Za-z0-9+/]/g, '')), function(c) {
1007
+ return c.charCodeAt(0);
1008
+ });
1009
+ }
1010
+ /**
1011
+ * Normalizes an embedding to a number array, decoding the base64 (little-endian float32) form.
1012
+ *
1013
+ * @param embedding - The embedding as returned.
1014
+ * @returns The vector.
1015
+ */ function openRouterEmbeddingVector(embedding) {
1016
+ var result;
1017
+ if (typeof embedding === 'string') {
1018
+ var bytes = openRouterDecodeBase64(embedding);
1019
+ var view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
1020
+ var length = Math.floor(bytes.byteLength / 4);
1021
+ result = [];
1022
+ for(var i = 0; i < length; i += 1){
1023
+ result.push(view.getFloat32(i * 4, true));
1024
+ }
1025
+ } else {
1026
+ result = embedding;
1027
+ }
1028
+ return result;
1029
+ }
1030
+
1031
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
1032
+ try {
1033
+ var info = gen[key](arg);
1034
+ var value = info.value;
1035
+ } catch (error) {
1036
+ reject(error);
1037
+ return;
1038
+ }
1039
+ if (info.done) {
1040
+ resolve(value);
1041
+ } else {
1042
+ Promise.resolve(value).then(_next, _throw);
1043
+ }
1044
+ }
1045
+ function _async_to_generator(fn) {
1046
+ return function() {
1047
+ var self = this, args = arguments;
1048
+ return new Promise(function(resolve, reject) {
1049
+ var gen = fn.apply(self, args);
1050
+ function _next(value) {
1051
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
1052
+ }
1053
+ function _throw(err) {
1054
+ asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
1055
+ }
1056
+ _next(undefined);
1057
+ });
1058
+ };
1059
+ }
1060
+ function _ts_generator(thisArg, body) {
1061
+ var f, y, t, _ = {
1062
+ label: 0,
1063
+ sent: function() {
1064
+ if (t[0] & 1) throw t[1];
1065
+ return t[1];
1066
+ },
1067
+ trys: [],
1068
+ ops: []
1069
+ }, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype), d = Object.defineProperty;
1070
+ return d(g, "next", {
1071
+ value: verb(0)
1072
+ }), d(g, "throw", {
1073
+ value: verb(1)
1074
+ }), d(g, "return", {
1075
+ value: verb(2)
1076
+ }), typeof Symbol === "function" && d(g, Symbol.iterator, {
1077
+ value: function() {
1078
+ return this;
1079
+ }
1080
+ }), g;
1081
+ function verb(n) {
1082
+ return function(v) {
1083
+ return step([
1084
+ n,
1085
+ v
1086
+ ]);
1087
+ };
1088
+ }
1089
+ function step(op) {
1090
+ if (f) throw new TypeError("Generator is already executing.");
1091
+ while(g && (g = 0, op[0] && (_ = 0)), _)try {
1092
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
1093
+ if (y = 0, t) op = [
1094
+ op[0] & 2,
1095
+ t.value
1096
+ ];
1097
+ switch(op[0]){
1098
+ case 0:
1099
+ case 1:
1100
+ t = op;
1101
+ break;
1102
+ case 4:
1103
+ _.label++;
1104
+ return {
1105
+ value: op[1],
1106
+ done: false
1107
+ };
1108
+ case 5:
1109
+ _.label++;
1110
+ y = op[1];
1111
+ op = [
1112
+ 0
1113
+ ];
1114
+ continue;
1115
+ case 7:
1116
+ op = _.ops.pop();
1117
+ _.trys.pop();
1118
+ continue;
1119
+ default:
1120
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
1121
+ _ = 0;
1122
+ continue;
1123
+ }
1124
+ if (op[0] === 3 && (!t || op[1] > t[0] && op[1] < t[3])) {
1125
+ _.label = op[1];
1126
+ break;
1127
+ }
1128
+ if (op[0] === 6 && _.label < t[1]) {
1129
+ _.label = t[1];
1130
+ t = op;
1131
+ break;
1132
+ }
1133
+ if (t && _.label < t[2]) {
1134
+ _.label = t[2];
1135
+ _.ops.push(op);
1136
+ break;
1137
+ }
1138
+ if (t[2]) _.ops.pop();
1139
+ _.trys.pop();
1140
+ continue;
1141
+ }
1142
+ op = body.call(thisArg, _);
1143
+ } catch (e) {
1144
+ op = [
1145
+ 6,
1146
+ e
1147
+ ];
1148
+ y = 0;
1149
+ } finally{
1150
+ f = t = 0;
1151
+ }
1152
+ if (op[0] & 5) throw op[1];
1153
+ return {
1154
+ value: op[0] ? op[1] : void 0,
1155
+ done: true
1156
+ };
1157
+ }
1158
+ }
1159
+ /**
1160
+ * Loads a generation's metadata — finish reason, cancellation, BYOK, latency, and the full token/cost
1161
+ * breakdown, which is finalised server-side and so can be more complete than the usage the response
1162
+ * carried.
1163
+ *
1164
+ * This is an AUDIT surface, never the system of record. What it returns is tied to account logging
1165
+ * settings (nothing is retained under ZDR / logging-disabled), its retention is undocumented, and it is
1166
+ * keyed per generation rather than per conversation — which is why a run task stores its own output and
1167
+ * keeps `gi (generationIds)` only for lookups like this one.
1168
+ *
1169
+ * @param params - The client and generation id.
1170
+ * @returns The generation metadata.
1171
+ * @throws {Error} When the lookup fails, including the 404 a generation that was never retained produces.
1172
+ */ function openRouterGeneration(params) {
1173
+ return _async_to_generator(function() {
1174
+ var client, id, options, result;
1175
+ return _ts_generator(this, function(_state) {
1176
+ switch(_state.label){
1177
+ case 0:
1178
+ client = params.client, id = params.id, options = params.options;
1179
+ return [
1180
+ 4,
1181
+ generationsGetGeneration(client, {
1182
+ id: id
1183
+ }, options !== null && options !== void 0 ? options : undefined)
1184
+ ];
1185
+ case 1:
1186
+ result = _state.sent();
1187
+ if (!result.ok) {
1188
+ throw result.error;
1189
+ }
1190
+ return [
1191
+ 2,
1192
+ result.value.data
1193
+ ];
1194
+ }
1195
+ });
1196
+ })();
1197
+ }
1198
+ /**
1199
+ * Loads a generation's stored content — prompt, completion, reasoning, and output.
1200
+ *
1201
+ * Subject to every caveat on {@link openRouterGeneration}: this reloads what OpenRouter happened to
1202
+ * retain, not what the run produced.
1203
+ *
1204
+ * @param params - The client and generation id.
1205
+ * @returns The stored content.
1206
+ * @throws {Error} When the lookup fails.
1207
+ */ function openRouterGenerationContent(params) {
1208
+ return _async_to_generator(function() {
1209
+ var client, id, options, result;
1210
+ return _ts_generator(this, function(_state) {
1211
+ switch(_state.label){
1212
+ case 0:
1213
+ client = params.client, id = params.id, options = params.options;
1214
+ return [
1215
+ 4,
1216
+ generationsListGenerationContent(client, {
1217
+ id: id
1218
+ }, options !== null && options !== void 0 ? options : undefined)
1219
+ ];
1220
+ case 1:
1221
+ result = _state.sent();
1222
+ if (!result.ok) {
1223
+ throw result.error;
1224
+ }
1225
+ return [
1226
+ 2,
1227
+ result.value.data
1228
+ ];
1229
+ }
1230
+ });
1231
+ })();
1232
+ }
1233
+
1234
+ function _define_property(obj, key, value) {
1235
+ if (key in obj) {
1236
+ Object.defineProperty(obj, key, {
1237
+ value: value,
1238
+ enumerable: true,
1239
+ configurable: true,
1240
+ writable: true
1241
+ });
1242
+ } else {
1243
+ obj[key] = value;
1244
+ }
1245
+ return obj;
1246
+ }
1247
+ function _object_spread(target) {
1248
+ for(var i = 1; i < arguments.length; i++){
1249
+ var source = arguments[i] != null ? arguments[i] : {};
1250
+ var ownKeys = Object.keys(source);
1251
+ if (typeof Object.getOwnPropertySymbols === "function") {
1252
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
1253
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
1254
+ }));
1255
+ }
1256
+ ownKeys.forEach(function(key) {
1257
+ _define_property(target, key, source[key]);
1258
+ });
1259
+ }
1260
+ return target;
1261
+ }
1262
+ function ownKeys(object, enumerableOnly) {
1263
+ var keys = Object.keys(object);
1264
+ if (Object.getOwnPropertySymbols) {
1265
+ var symbols = Object.getOwnPropertySymbols(object);
1266
+ keys.push.apply(keys, symbols);
1267
+ }
1268
+ return keys;
1269
+ }
1270
+ function _object_spread_props(target, source) {
1271
+ source = source != null ? source : {};
1272
+ if (Object.getOwnPropertyDescriptors) {
1273
+ Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
1274
+ } else {
1275
+ ownKeys(Object(source)).forEach(function(key) {
1276
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
1277
+ });
1278
+ }
1279
+ return target;
1280
+ }
1281
+ function _object_without_properties(source, excluded) {
1282
+ if (source == null) return {};
1283
+ var target = {}, sourceKeys, key, i;
1284
+ if (typeof Reflect !== "undefined" && Reflect.ownKeys) {
1285
+ sourceKeys = Reflect.ownKeys(Object(source));
1286
+ for(i = 0; i < sourceKeys.length; i++){
1287
+ key = sourceKeys[i];
1288
+ if (excluded.indexOf(key) >= 0) continue;
1289
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
1290
+ target[key] = source[key];
1291
+ }
1292
+ return target;
1293
+ }
1294
+ target = _object_without_properties_loose(source, excluded);
1295
+ if (Object.getOwnPropertySymbols) {
1296
+ sourceKeys = Object.getOwnPropertySymbols(source);
1297
+ for(i = 0; i < sourceKeys.length; i++){
1298
+ key = sourceKeys[i];
1299
+ if (excluded.indexOf(key) >= 0) continue;
1300
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
1301
+ target[key] = source[key];
1302
+ }
1303
+ }
1304
+ return target;
1305
+ }
1306
+ function _object_without_properties_loose(source, excluded) {
1307
+ if (source == null) return {};
1308
+ var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
1309
+ for(i = 0; i < sourceKeys.length; i++){
1310
+ key = sourceKeys[i];
1311
+ if (excluded.indexOf(key) >= 0) continue;
1312
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
1313
+ target[key] = source[key];
1314
+ }
1315
+ return target;
1316
+ }
1317
+ /**
1318
+ * Normalizes input to a message array.
1319
+ *
1320
+ * @param input - The input to normalize.
1321
+ * @returns The messages, empty when no input was given.
1322
+ */ function openRouterInputMessages(input) {
1323
+ var result;
1324
+ if (input == null) {
1325
+ result = [];
1326
+ } else if (typeof input === 'string') {
1327
+ result = [
1328
+ {
1329
+ role: 'user',
1330
+ content: [
1331
+ {
1332
+ type: 'input_text',
1333
+ text: input
1334
+ }
1335
+ ]
1336
+ }
1337
+ ];
1338
+ } else {
1339
+ result = input;
1340
+ }
1341
+ return result;
1342
+ }
1343
+ /**
1344
+ * Builds a text content part.
1345
+ *
1346
+ * @param text - The text.
1347
+ * @returns The content part.
1348
+ *
1349
+ * @__NO_SIDE_EFFECTS__
1350
+ */ function openRouterInputTextPart(text) {
1351
+ return {
1352
+ type: 'input_text',
1353
+ text: text
1354
+ };
1355
+ }
1356
+ /**
1357
+ * Builds an image content part.
1358
+ *
1359
+ * @param imageUrl - The image url (a signed url, a data url, or any publicly reachable url).
1360
+ * @param detail - Detail level. Defaults to `auto`.
1361
+ * @returns The content part.
1362
+ *
1363
+ * @__NO_SIDE_EFFECTS__
1364
+ */ function openRouterInputImagePart(imageUrl) {
1365
+ var detail = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 'auto';
1366
+ return {
1367
+ type: 'input_image',
1368
+ imageUrl: imageUrl,
1369
+ detail: detail
1370
+ };
1371
+ }
1372
+ /**
1373
+ * Builds a file content part from a url.
1374
+ *
1375
+ * @param fileUrl - The url the parser will dereference. Must be reachable from the public internet.
1376
+ * @param filename - Filename to present; its extension is what tells OpenRouter how to treat the file.
1377
+ * @returns The content part.
1378
+ *
1379
+ * @__NO_SIDE_EFFECTS__
1380
+ */ function openRouterInputFileUrlPart(fileUrl, filename) {
1381
+ return {
1382
+ type: 'input_file',
1383
+ fileUrl: fileUrl,
1384
+ filename: filename
1385
+ };
1386
+ }
1387
+ /**
1388
+ * Builds a file content part from base64 data.
1389
+ *
1390
+ * @param base64 - Base64 content, with or without a `data:` prefix.
1391
+ * @param filename - Filename to present.
1392
+ * @param contentType - Mime type used to build the `data:` prefix when the input lacks one. Defaults to `application/pdf`.
1393
+ * @returns The content part.
1394
+ *
1395
+ * @__NO_SIDE_EFFECTS__
1396
+ */ function openRouterInputFileDataPart(base64, filename) {
1397
+ var contentType = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : 'application/pdf';
1398
+ var fileData = base64.startsWith('data:') ? base64 : "data:".concat(contentType, ";base64,").concat(base64);
1399
+ return {
1400
+ type: 'input_file',
1401
+ fileData: fileData,
1402
+ filename: filename
1403
+ };
1404
+ }
1405
+ /**
1406
+ * Expands attached file references into file content parts.
1407
+ *
1408
+ * @param files - The attached file references.
1409
+ * @returns One content part per file.
1410
+ */ function openRouterInputFilePartsForAttachedFiles(files) {
1411
+ return (files !== null && files !== void 0 ? files : []).map(function(param) {
1412
+ var file = param.file, fileUrl = param.fileUrl, fileData = param.fileData;
1413
+ return fileData == null ? openRouterInputFileUrlPart(fileUrl, file.filename) : openRouterInputFileDataPart(fileData, file.filename);
1414
+ });
1415
+ }
1416
+ /**
1417
+ * Rewrites the `input_file` parts of an already-assembled conversation with the attachment resolved for
1418
+ * THIS attempt, matching on filename.
1419
+ *
1420
+ * A conversation persisted mid-run carries whatever the attempt that persisted it was carrying —
1421
+ * a url that has since expired, or (with inline attachments stripped on save) nothing at all. Replaying
1422
+ * it unchanged is the failure mode most likely to reach production unnoticed, because it only shows up
1423
+ * on a retry or a deferred resume. Resolving fresh per attempt is only half the fix; the other half is
1424
+ * making sure the stored history is re-pointed at the fresh attachment too.
1425
+ *
1426
+ * The field the attachment does NOT carry is REMOVED rather than left alone: a stored `fileUrl` sitting
1427
+ * next to a fresh `fileData` would send OpenRouter both, and it is not defined which one wins. Removed
1428
+ * rather than nulled, because this output goes on the wire — the SDK validates `input_file` against a
1429
+ * schema where an explicit `null` is not a legal absent value.
1430
+ *
1431
+ * A part whose filename matches nothing in `files` is left alone: it came from somewhere other than
1432
+ * this task's file list, and guessing at it would be worse than leaving it.
1433
+ *
1434
+ * @param messages - The assembled conversation.
1435
+ * @param files - The files attached for this attempt.
1436
+ * @returns The conversation with fresh attachments, or the input unchanged when there is nothing to rewrite.
1437
+ */ function openRouterMessagesWithFreshFileAttachments(messages, files) {
1438
+ var attachmentsByFilename = arrayToMap(files !== null && files !== void 0 ? files : [], function(attached) {
1439
+ return attached.file.filename;
1440
+ });
1441
+ var result = messages !== null && messages !== void 0 ? messages : [];
1442
+ if (attachmentsByFilename.size > 0 && result.length > 0) {
1443
+ result = result.map(function(message) {
1444
+ var updated = message;
1445
+ if (Array.isArray(message.content)) {
1446
+ var content = message.content.map(function(part) {
1447
+ var updatedPart = part;
1448
+ if (part.type === 'input_file' && part.filename != null) {
1449
+ var fresh = attachmentsByFilename.get(part.filename);
1450
+ if (fresh != null) {
1451
+ part.fileUrl; part.fileData; var rest = _object_without_properties(part, [
1452
+ "fileUrl",
1453
+ "fileData"
1454
+ ]);
1455
+ updatedPart = _object_spread({}, rest, fresh.fileData == null ? {
1456
+ fileUrl: fresh.fileUrl
1457
+ } : {
1458
+ fileData: fresh.fileData
1459
+ });
1460
+ }
1461
+ }
1462
+ return updatedPart;
1463
+ });
1464
+ updated = _object_spread_props(_object_spread({}, message), {
1465
+ content: content
1466
+ });
1467
+ }
1468
+ return updated;
1469
+ });
1470
+ }
1471
+ return result;
1472
+ }
1473
+ /**
1474
+ * Strips the attachment payload off every `input_file` part, keeping `filename` as the rejoin key.
1475
+ *
1476
+ * Applied on the way INTO Firestore. An attachment is resolved per attempt and is meaningless the
1477
+ * moment that attempt ends — a signed url has expired, and inline base64 is the whole file, on a
1478
+ * document with a 1 MiB ceiling and a `msg` field that already grows without bound. Nothing is lost:
1479
+ * {@link openRouterMessagesWithFreshFileAttachments} re-points the stored parts on the way back out.
1480
+ *
1481
+ * @param messages - The conversation about to be persisted.
1482
+ * @returns The conversation with attachment payloads removed.
1483
+ */ function openRouterMessagesWithoutFileAttachmentData(messages) {
1484
+ return (messages !== null && messages !== void 0 ? messages : []).map(function(message) {
1485
+ var updated = message;
1486
+ if (Array.isArray(message.content)) {
1487
+ var content = message.content.map(function(part) {
1488
+ return part.type === 'input_file' ? _object_spread_props(_object_spread({}, part), {
1489
+ fileUrl: null,
1490
+ fileData: null
1491
+ }) : part;
1492
+ });
1493
+ updated = _object_spread_props(_object_spread({}, message), {
1494
+ content: content
1495
+ });
1496
+ }
1497
+ return updated;
1498
+ });
1499
+ }
1500
+ /**
1501
+ * Renders one cached annotation as message text.
1502
+ *
1503
+ * @param annotation - The cached annotation.
1504
+ * @returns The text carrying the parse.
1505
+ *
1506
+ * @__NO_SIDE_EFFECTS__
1507
+ */ function openRouterFileAnnotationText(annotation) {
1508
+ var _annotation_content, _annotation_filename;
1509
+ var content = typeof annotation.content === 'string' ? annotation.content : JSON.stringify((_annotation_content = annotation.content) !== null && _annotation_content !== void 0 ? _annotation_content : null);
1510
+ return '<file name="'.concat((_annotation_filename = annotation.filename) !== null && _annotation_filename !== void 0 ? _annotation_filename : annotation.hash, '" hash="').concat(annotation.hash, '">\n').concat(content, "\n</file>");
1511
+ }
1512
+ /**
1513
+ * Builds the assistant message that carries cached `file-parser` output back, so an already-parsed file
1514
+ * is not parsed again.
1515
+ *
1516
+ * It carries the parse TWICE, deliberately, and for an empirical reason rather than a defensive one:
1517
+ *
1518
+ * - `annotations` is OpenRouter's own documented echo format, so the shape is kept and the mechanism
1519
+ * starts working the day the Responses API models it. Today it does not: the SDK validates the request
1520
+ * body against a closed union whose message variants have no `annotations` field, so the property is
1521
+ * STRIPPED during outbound serialization. Verified against the wire, not assumed.
1522
+ * - The parse is therefore ALSO rendered into `content`, as ordinary text, which does survive. Paired
1523
+ * with the request builder dropping the file part for an already-parsed file, that is what makes the
1524
+ * cache real today.
1525
+ *
1526
+ * @param annotations - The cached annotations.
1527
+ * @returns The message, or undefined when there is nothing cached to resubmit.
1528
+ */ function openRouterFileAnnotationMessage(annotations) {
1529
+ var result;
1530
+ if (annotations != null && annotations.length > 0) {
1531
+ result = {
1532
+ role: 'assistant',
1533
+ content: annotations.map(openRouterFileAnnotationText).join('\n'),
1534
+ annotations: annotations.map(function(annotation) {
1535
+ return {
1536
+ type: 'file',
1537
+ file: {
1538
+ hash: annotation.hash,
1539
+ name: annotation.filename,
1540
+ content: annotation.content
1541
+ }
1542
+ };
1543
+ })
1544
+ };
1545
+ }
1546
+ return result;
1547
+ }
1548
+ /**
1549
+ * Drops the files whose parse is already cached.
1550
+ *
1551
+ * Not re-sending the document is what actually prevents a re-parse. The annotation echo alone cannot:
1552
+ * the SDK strips it, and even where it survives it is a hint the provider is free to ignore, so a run
1553
+ * that relied on it would pay for the parse again with no error to show for it.
1554
+ *
1555
+ * A file is matched to its cached parse by filename, which is the only handle both sides share — the
1556
+ * annotation's `hash` is assigned by OpenRouter and the reference's `storagePath` is ours.
1557
+ *
1558
+ * @param files - The files attached for this attempt.
1559
+ * @param annotations - The cached annotations.
1560
+ * @returns The files that still need sending.
1561
+ *
1562
+ * @__NO_SIDE_EFFECTS__
1563
+ */ function openRouterUnparsedAttachedFiles(files, annotations) {
1564
+ var cachedFilenames = new Set((annotations !== null && annotations !== void 0 ? annotations : []).map(function(annotation) {
1565
+ return annotation.filename;
1566
+ }).filter(function(filename) {
1567
+ return filename != null;
1568
+ }));
1569
+ return (files !== null && files !== void 0 ? files : []).filter(function(param) {
1570
+ var file = param.file;
1571
+ return !cachedFilenames.has(file.filename);
1572
+ });
1573
+ }
1574
+
1575
+ function _array_like_to_array(arr, len) {
1576
+ if (len == null || len > arr.length) len = arr.length;
1577
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
1578
+ return arr2;
1579
+ }
1580
+ function _array_without_holes(arr) {
1581
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
1582
+ }
1583
+ function _iterable_to_array(iter) {
1584
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter);
1585
+ }
1586
+ function _non_iterable_spread() {
1587
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
1588
+ }
1589
+ function _to_consumable_array(arr) {
1590
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
1591
+ }
1592
+ function _unsupported_iterable_to_array(o, minLen) {
1593
+ if (!o) return;
1594
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
1595
+ var n = Object.prototype.toString.call(o).slice(8, -1);
1596
+ if (n === "Object" && o.constructor) n = o.constructor.name;
1597
+ if (n === "Map" || n === "Set") return Array.from(n);
1598
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
1599
+ }
1600
+ /**
1601
+ * Builds a request from a resolved prompt version plus a caller's dynamic input.
1602
+ *
1603
+ * Content is emitted STATIC FIRST — seed messages, then annotation echoes, then continued history,
1604
+ * then the caller's input, with attached files appended to the final user message. That ordering is
1605
+ * not cosmetic: a prompt cache only hits on a shared prefix, so putting the per-call content last is
1606
+ * what keeps the static prefix cacheable across runs of the same prompt.
1607
+ *
1608
+ * @param params - The prompt, input, overrides, files, history, and trace.
1609
+ * @returns The built request.
1610
+ */ function openRouterPromptRequest(params) {
1611
+ var _messages;
1612
+ var _prompt_messages;
1613
+ var prompt = params.prompt, input = params.input, overrides = params.overrides, files = params.files, fileAnnotations = params.fileAnnotations, history = params.history, trace = params.trace;
1614
+ var config = mergeOpenRouterModelConfig([
1615
+ prompt.config,
1616
+ overrides
1617
+ ]);
1618
+ var seedMessages = ((_prompt_messages = prompt.messages) !== null && _prompt_messages !== void 0 ? _prompt_messages : []).map(function(param) {
1619
+ var role = param.role, content = param.content;
1620
+ return {
1621
+ role: role,
1622
+ content: content
1623
+ };
1624
+ });
1625
+ var annotationMessage = openRouterFileAnnotationMessage(fileAnnotations);
1626
+ var inputMessages = openRouterInputMessages(input);
1627
+ // A file whose parse is already cached is NOT re-attached. Sending it again is what causes the
1628
+ // re-parse; the annotation echo alone cannot prevent one.
1629
+ var fileParts = openRouterInputFilePartsForAttachedFiles(openRouterUnparsedAttachedFiles(files, fileAnnotations));
1630
+ var messages = _to_consumable_array(seedMessages);
1631
+ if (annotationMessage != null) {
1632
+ messages.push(annotationMessage);
1633
+ }
1634
+ if (history != null && history.length > 0) {
1635
+ var _messages1;
1636
+ (_messages1 = messages).push.apply(_messages1, _to_consumable_array(history));
1637
+ }
1638
+ (_messages = messages).push.apply(_messages, _to_consumable_array(inputMessages));
1639
+ if (fileParts.length > 0) {
1640
+ // Files ride on the last user message so they sit alongside the text that refers to them. When
1641
+ // the caller passed no input at all (a file-only run) a user message is created to carry them.
1642
+ var lastUserIndex = messages.findLastIndex(function(x) {
1643
+ return x.role === 'user';
1644
+ });
1645
+ if (lastUserIndex >= 0) {
1646
+ var target = messages[lastUserIndex];
1647
+ var content = typeof target.content === 'string' ? [
1648
+ {
1649
+ type: 'input_text',
1650
+ text: target.content
1651
+ }
1652
+ ] : target.content;
1653
+ messages[lastUserIndex] = {
1654
+ role: target.role,
1655
+ content: _to_consumable_array(content).concat(_to_consumable_array(fileParts))
1656
+ };
1657
+ } else {
1658
+ messages.push({
1659
+ role: 'user',
1660
+ content: fileParts
1661
+ });
1662
+ }
1663
+ }
1664
+ return {
1665
+ config: config,
1666
+ instructions: prompt.instructions,
1667
+ input: messages,
1668
+ trace: trace
1669
+ };
1670
+ }
1671
+
1672
+ /**
1673
+ * Extracts the deferred (manual) tool calls from a conversation state.
1674
+ *
1675
+ * Only manual tools can be pending on resume: a tool with an `execute` function was run in-process
1676
+ * before the state was ever saved.
1677
+ *
1678
+ * @param state - The conversation state.
1679
+ * @param tools - The tool set the run was configured with, used to tell manual tools from executable ones.
1680
+ * @returns The pending deferred tool calls.
1681
+ */ function openRouterPendingDeferredToolCalls(state, tools) {
1682
+ var _ref;
1683
+ var manualToolNames = new Set((tools !== null && tools !== void 0 ? tools : []).filter(function(x) {
1684
+ return isManualTool(x);
1685
+ }).map(function(x) {
1686
+ return x.function.name;
1687
+ }));
1688
+ return ((_ref = state === null || state === void 0 ? void 0 : state.pendingToolCalls) !== null && _ref !== void 0 ? _ref : []).filter(function(call) {
1689
+ return manualToolNames.size === 0 || manualToolNames.has(call.name);
1690
+ }).map(function(call) {
1691
+ return openRouterPendingDeferredToolCallFromParsedCall(call);
1692
+ });
1693
+ }
1694
+ /**
1695
+ * Converts an SDK parsed tool call into a pending deferred tool call.
1696
+ *
1697
+ * @param call - The parsed tool call.
1698
+ * @param taskId - Optional task id to associate. Defaults to the call id.
1699
+ * @returns The pending deferred tool call.
1700
+ */ function openRouterPendingDeferredToolCallFromParsedCall(call, taskId) {
1701
+ return {
1702
+ callId: call.id,
1703
+ name: call.name,
1704
+ taskId: taskId !== null && taskId !== void 0 ? taskId : call.id,
1705
+ arguments: call.arguments
1706
+ };
1707
+ }
1708
+ /**
1709
+ * Turns resolutions into the `unsentToolResults` entries the SDK replays on the next call.
1710
+ *
1711
+ * A resolution whose `taskId` matches no pending call is DROPPED rather than throwing. Deferred
1712
+ * resolutions arrive from outside this process and may be replayed — an unmatched one means the task
1713
+ * was already settled, which must be a no-op, not a failure.
1714
+ *
1715
+ * @param pending - The currently pending deferred tool calls.
1716
+ * @param resolutions - The resolutions received.
1717
+ * @returns The unsent tool results, in the order the resolutions were given.
1718
+ */ function openRouterResolvedDeferredToolResults(pending, resolutions) {
1719
+ var byTaskId = arrayToMap(pending !== null && pending !== void 0 ? pending : [], function(call) {
1720
+ return call.taskId;
1721
+ });
1722
+ var results = [];
1723
+ (resolutions !== null && resolutions !== void 0 ? resolutions : []).forEach(function(resolution) {
1724
+ var call = byTaskId.get(resolution.taskId);
1725
+ if (call != null) {
1726
+ results.push({
1727
+ callId: call.callId,
1728
+ name: call.name,
1729
+ output: resolution.output,
1730
+ error: resolution.error
1731
+ });
1732
+ }
1733
+ });
1734
+ return results;
1735
+ }
1736
+ /**
1737
+ * Whether a conversation state is paused waiting on a deferred tool result.
1738
+ *
1739
+ * @param state - The conversation state.
1740
+ * @returns True when the state has pending tool calls it cannot resolve itself.
1741
+ */ function isOpenRouterStateAwaitingDeferredTools(state) {
1742
+ var _ref;
1743
+ var _state_pendingToolCalls;
1744
+ return ((_ref = state === null || state === void 0 ? void 0 : (_state_pendingToolCalls = state.pendingToolCalls) === null || _state_pendingToolCalls === void 0 ? void 0 : _state_pendingToolCalls.length) !== null && _ref !== void 0 ? _ref : 0) > 0;
1745
+ }
1746
+ /**
1747
+ * Converts recorded tool results into the `function_call_output` items that get appended to the
1748
+ * conversation before the run is resumed.
1749
+ *
1750
+ * This is how a deferred pause is un-paused, and it is done HERE rather than through the SDK on
1751
+ * purpose. `@openrouter/sdk@1.2.x` only knows how to resume a pause by re-running the tool locally
1752
+ * (`approveToolCalls` calls the tool's `execute`, and a manual tool has none) or by rejecting it — so
1753
+ * a result produced by another process has no route back in through the SDK's own API. Appending the
1754
+ * outputs to the persisted conversation and re-sending it does have one, and it is the same wire
1755
+ * format the SDK would have produced itself.
1756
+ *
1757
+ * @param results - The recorded results, in the persisted `callId` / `name` / `output` / `error` shape.
1758
+ * @returns The `function_call_output` items to append to the conversation.
1759
+ */ function openRouterFunctionCallOutputItems(results) {
1760
+ return unsentResultsToAPIFormat((results !== null && results !== void 0 ? results : []).map(function(result) {
1761
+ var _result_error;
1762
+ return {
1763
+ callId: result.callId,
1764
+ name: result.name,
1765
+ output: result.output,
1766
+ error: (_result_error = result.error) !== null && _result_error !== void 0 ? _result_error : undefined
1767
+ };
1768
+ }));
1769
+ }
1770
+
1771
+ export { DEFAULT_OPENROUTER_PDF_PARSER_ENGINE, OPENROUTER_CALL_MODEL_HEADER, callModelForOpenRouterRequest, isOpenRouterStateAwaitingDeferredTools, mergeOpenRouterModelConfig, openRouterCallModelInput, openRouterCallResultFromResponse, openRouterDecodeBase64, openRouterEmbeddingVector, openRouterEmbeddings, openRouterFileAnnotationMessage, openRouterFileAnnotationText, openRouterFileParserPlugin, openRouterFileSearchTool, openRouterFunctionCallOutputItems, openRouterGeneration, openRouterGenerationContent, openRouterHostedTools, openRouterInputFileDataPart, openRouterInputFilePartsForAttachedFiles, openRouterInputFileUrlPart, openRouterInputImagePart, openRouterInputMessages, openRouterInputTextPart, openRouterMessagesWithFreshFileAttachments, openRouterMessagesWithoutFileAttachmentData, openRouterModelResultForRequest, openRouterOutputTextFromResponse, openRouterPendingDeferredToolCallFromParsedCall, openRouterPendingDeferredToolCalls, openRouterPromptRequest, openRouterProviderPinnedTo, openRouterResolvedDeferredToolResults, openRouterResponsesRequestBody, openRouterRunErrorFromResponseError, openRouterRunUsageFromResponseUsage, openRouterUnparsedAttachedFiles, parseOpenRouterJsonOutput, sendOpenRouterResponsesRequest, splitOpenRouterModelConfig, validateOpenRouterModelConfig };