@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.
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/firebase/index.cjs.default.js +1 -0
- package/firebase/index.cjs.js +666 -0
- package/firebase/index.cjs.mjs +2 -0
- package/firebase/index.d.ts +1 -0
- package/firebase/index.esm.js +626 -0
- package/firebase/package.json +25 -0
- package/firebase/src/index.d.ts +1 -0
- package/firebase/src/lib/index.d.ts +4 -0
- package/firebase/src/lib/openrouter.api.d.ts +226 -0
- package/firebase/src/lib/openrouter.id.d.ts +56 -0
- package/firebase/src/lib/openrouter.model.d.ts +609 -0
- package/firebase/src/lib/openrouter.query.d.ts +121 -0
- package/firebase-server/index.cjs.default.js +1 -0
- package/firebase-server/index.cjs.js +4520 -0
- package/firebase-server/index.cjs.mjs +2 -0
- package/firebase-server/index.d.ts +1 -0
- package/firebase-server/index.esm.js +4466 -0
- package/firebase-server/package.json +38 -0
- package/firebase-server/src/index.d.ts +1 -0
- package/firebase-server/src/lib/index.d.ts +10 -0
- package/firebase-server/src/lib/openrouter.action.server.d.ts +196 -0
- package/firebase-server/src/lib/openrouter.broadcast.d.ts +93 -0
- package/firebase-server/src/lib/openrouter.call.inline.d.ts +57 -0
- package/firebase-server/src/lib/openrouter.file.attachment.d.ts +97 -0
- package/firebase-server/src/lib/openrouter.module.d.ts +65 -0
- package/firebase-server/src/lib/openrouter.prompt.service.d.ts +109 -0
- package/firebase-server/src/lib/openrouter.runtask.handle.d.ts +56 -0
- package/firebase-server/src/lib/openrouter.runtask.service.d.ts +380 -0
- package/firebase-server/src/lib/openrouter.runtask.sweep.d.ts +170 -0
- package/firebase-server/src/lib/openrouter.state.accessor.d.ts +106 -0
- package/firebase-server/src/test/openrouter.fake.d.ts +134 -0
- package/index.cjs.default.js +1 -0
- package/index.cjs.js +1867 -0
- package/index.cjs.mjs +2 -0
- package/index.d.ts +1 -0
- package/index.esm.js +1771 -0
- package/package.json +32 -0
- package/src/index.d.ts +1 -0
- package/src/lib/index.d.ts +10 -0
- package/src/lib/openrouter.call.d.ts +268 -0
- package/src/lib/openrouter.config.d.ts +314 -0
- package/src/lib/openrouter.embedding.d.ts +87 -0
- package/src/lib/openrouter.generation.d.ts +46 -0
- package/src/lib/openrouter.input.d.ts +238 -0
- package/src/lib/openrouter.prompt.d.ts +79 -0
- package/src/lib/openrouter.request.d.ts +91 -0
- package/src/lib/openrouter.sdk.d.ts +37 -0
- package/src/lib/openrouter.tool.d.ts +99 -0
- 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 };
|