@dereekb/openrouter 14.8.0 → 14.9.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.
@@ -0,0 +1,1185 @@
1
+ import { mergeObjects, filterUndefinedValues, mapObjectMap } from '@dereekb/util';
2
+
3
+ /**
4
+ * The namespace every System One model slug lives under.
5
+ */ var OPENROUTER_SYSTEM_ONE_MODEL_NAMESPACE = 'typesafe';
6
+ /**
7
+ * Jev 1.13, the System One model this package pins by default.
8
+ *
9
+ * A VERSIONED slug rather than one of the moving aliases (`jev-latest`, `jev-preview`), for the same
10
+ * reason {@link OpenRouterPromptVersionNumber} exists: a decision's answer is only reproducible against
11
+ * the exact model that produced it, and an alias silently moves out from under a stored prompt. Point a
12
+ * prompt at an alias deliberately, never by default.
13
+ */ var OPENROUTER_JEV_1_13_MODEL_ID = 'typesafe/jev-1.13';
14
+ /**
15
+ * The newest STABLE Jev. A moving alias — see {@link OPENROUTER_JEV_1_13_MODEL_ID}.
16
+ */ var OPENROUTER_JEV_LATEST_MODEL_ID = 'typesafe/jev-latest';
17
+ /**
18
+ * The newest Jev, stable or not. A moving alias — see {@link OPENROUTER_JEV_1_13_MODEL_ID}.
19
+ */ var OPENROUTER_JEV_PREVIEW_MODEL_ID = 'typesafe/jev-preview';
20
+ /**
21
+ * The System One model a decision uses when its config names none.
22
+ */ var DEFAULT_OPENROUTER_SYSTEM_ONE_MODEL_ID = OPENROUTER_JEV_1_13_MODEL_ID;
23
+ /**
24
+ * Matches the bare System One slugs OpenRouter maps into the `typesafe/` namespace.
25
+ */ var OPENROUTER_BARE_SYSTEM_ONE_MODEL_REGEX = /^jev(-|$)/;
26
+ /**
27
+ * Whether a model slug names a System One model.
28
+ *
29
+ * This is the ONLY discriminator available, and it is the reason this function exists rather than a
30
+ * lookup: System One models are NOT listed by `GET /models`, so nothing can be learned about one from
31
+ * the catalog. A caller that guessed wrong does not get an error it can read — a Jev slug sent to
32
+ * `/responses` fails at the provider, and a chat slug sent to `/systemone` is refused by the route.
33
+ *
34
+ * Both forms are recognised: the namespaced slug (`typesafe/jev-1.13`) and the bare one (`jev-1.13`,
35
+ * `jev-latest`), which the SDK documents itself as mapping onto the `typesafe/` namespace.
36
+ *
37
+ * @param model - The model slug to test.
38
+ * @returns True when the slug names a System One model.
39
+ *
40
+ * @__NO_SIDE_EFFECTS__
41
+ */ function isOpenRouterSystemOneModelId(model) {
42
+ var slug = model === null || model === void 0 ? void 0 : model.trim().toLowerCase();
43
+ return slug == null || slug === '' ? false : slug.startsWith("".concat(OPENROUTER_SYSTEM_ONE_MODEL_NAMESPACE, "/")) || OPENROUTER_BARE_SYSTEM_ONE_MODEL_REGEX.test(slug);
44
+ }
45
+
46
+ function _array_like_to_array$2(arr, len) {
47
+ if (len == null || len > arr.length) len = arr.length;
48
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
49
+ return arr2;
50
+ }
51
+ function _array_without_holes$2(arr) {
52
+ if (Array.isArray(arr)) return _array_like_to_array$2(arr);
53
+ }
54
+ function _define_property$2(obj, key, value) {
55
+ if (key in obj) {
56
+ Object.defineProperty(obj, key, {
57
+ value: value,
58
+ enumerable: true,
59
+ configurable: true,
60
+ writable: true
61
+ });
62
+ } else obj[key] = value;
63
+ return obj;
64
+ }
65
+ function _iterable_to_array$2(iter) {
66
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
67
+ return Array.from(iter);
68
+ }
69
+ }
70
+ function _non_iterable_spread$2() {
71
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
72
+ }
73
+ function _object_spread$2(target) {
74
+ for(var i = 1; i < arguments.length; i++){
75
+ var source = arguments[i] != null ? arguments[i] : {};
76
+ var ownKeys = Object.keys(source);
77
+ if (typeof Object.getOwnPropertySymbols === "function") {
78
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
79
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
80
+ }));
81
+ }
82
+ ownKeys.forEach(function(key) {
83
+ _define_property$2(target, key, source[key]);
84
+ });
85
+ }
86
+ return target;
87
+ }
88
+ function _to_consumable_array$2(arr) {
89
+ return _array_without_holes$2(arr) || _iterable_to_array$2(arr) || _unsupported_iterable_to_array$2(arr) || _non_iterable_spread$2();
90
+ }
91
+ function _unsupported_iterable_to_array$2(o, minLen) {
92
+ if (!o) return;
93
+ if (typeof o === "string") return _array_like_to_array$2(o, minLen);
94
+ var n = Object.prototype.toString.call(o).slice(8, -1);
95
+ if (n === "Object" && o.constructor) n = o.constructor.name;
96
+ if (n === "Map" || n === "Set") return Array.from(n);
97
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$2(o, minLen);
98
+ }
99
+ /**
100
+ * Builds a hosted `file_search` tool entry with the field names the SDK actually forwards.
101
+ *
102
+ * @param vectorStoreIds - The `vs_…` ids to search.
103
+ * @param maxNumResults - Optional cap on returned chunks.
104
+ * @returns The hosted tool entry.
105
+ *
106
+ * @__NO_SIDE_EFFECTS__
107
+ */ function openRouterFileSearchTool(vectorStoreIds, maxNumResults) {
108
+ return _object_spread$2({
109
+ type: 'file_search',
110
+ vectorStoreIds: vectorStoreIds
111
+ }, maxNumResults == null ? undefined : {
112
+ maxNumResults: maxNumResults
113
+ });
114
+ }
115
+ /**
116
+ * The default PDF parser engine this package pins.
117
+ *
118
+ * Pinned because the alternative is silent: with no engine named, OpenRouter downgrades any model it
119
+ * believes lacks native file support to `mistral-ocr`, inheriting its 8-image cap and per-page billing with
120
+ * no error — which on a multi-page document quietly truncates content.
121
+ *
122
+ * `native` rather than the equally-free `pdf-text` because it fails LOUDLY. It requires a model with
123
+ * native file input and 400s on one without, where `pdf-text` would hand a scanned PDF to the model as
124
+ * empty text and let it answer ungrounded. A caller on a text-only model wants
125
+ * `openRouterFileParserPlugin('pdf-text')` — see {@link OpenRouterPdfParserEngine}.
126
+ */ var DEFAULT_OPENROUTER_PDF_PARSER_ENGINE = 'native';
127
+ /**
128
+ * The `file-parser` plugin entry with the PDF engine pinned.
129
+ *
130
+ * @param engine - Engine to pin. Defaults to {@link DEFAULT_OPENROUTER_PDF_PARSER_ENGINE}.
131
+ * @returns The plugin config entry.
132
+ *
133
+ * @__NO_SIDE_EFFECTS__
134
+ */ function openRouterFileParserPlugin() {
135
+ var engine = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : DEFAULT_OPENROUTER_PDF_PARSER_ENGINE;
136
+ return {
137
+ id: 'file-parser',
138
+ pdf: {
139
+ engine: engine
140
+ }
141
+ };
142
+ }
143
+ /**
144
+ * A provider config that pins routing to a single provider with fallbacks off and parameter support
145
+ * required — the configuration that makes a BYOK request actually reach the intended upstream with
146
+ * every parameter intact.
147
+ *
148
+ * @param provider - The provider slug to pin to (e.g. `openai`).
149
+ * @returns The provider routing config.
150
+ *
151
+ * @__NO_SIDE_EFFECTS__
152
+ */ function openRouterProviderPinnedTo(provider) {
153
+ return {
154
+ only: [
155
+ provider
156
+ ],
157
+ allowFallbacks: false,
158
+ requireParameters: true
159
+ };
160
+ }
161
+ /**
162
+ * Merges model configs left-to-right, so the last input wins.
163
+ *
164
+ * Merging is SHALLOW by key: an override that supplies `provider` replaces the whole provider object
165
+ * rather than merging into it. That is the behaviour a caller wants — a half-overridden `provider`
166
+ * (say, `only` from the override and `allowFallbacks` from the version) is a configuration nobody
167
+ * wrote down and nobody can reason about.
168
+ *
169
+ * `undefined` values do not overwrite; an explicit `null` does (it is how a caller clears a value
170
+ * the version set).
171
+ *
172
+ * @param configs - Configs to merge, lowest priority first.
173
+ * @returns The merged config.
174
+ */ function mergeOpenRouterModelConfig(configs) {
175
+ return mergeObjects(configs);
176
+ }
177
+ /**
178
+ * Validates a merged model config, catching the misconfigurations that fail silently at runtime
179
+ * rather than loudly.
180
+ *
181
+ * @param config - The merged config to check.
182
+ * @param options - Which arm the config is for.
183
+ * @returns The validation result.
184
+ */ function validateOpenRouterModelConfig(config, options) {
185
+ var errors = [];
186
+ var warnings = [];
187
+ var decision = (options === null || options === void 0 ? void 0 : options.decision) === true;
188
+ if (config == null) {
189
+ errors.push('No model config was provided.');
190
+ } else {
191
+ var _config_models, _ref;
192
+ var _config_models1, _config_text, _config_plugins, _fileParser_pdf, _config_tools, _config_tools1, _config_provider, _config_provider_only, _config_provider1;
193
+ if (!config.model && !((_config_models1 = config.models) === null || _config_models1 === void 0 ? void 0 : _config_models1.length)) {
194
+ errors.push('No `model` (or `models` fallback chain) was specified.');
195
+ }
196
+ // OpenRouter has TWO inference surfaces and the model slug is the only thing that says which one a
197
+ // request belongs to — System One models are absent from `GET /models`, so nothing can be learned
198
+ // about one from the catalog. Checked here because this runs at publish time: a Jev slug typed into
199
+ // a stored prompt version is refused when it is written, rather than failing in a sweep days later
200
+ // with an error that names neither the prompt nor the reason.
201
+ var declaredModels = [
202
+ config.model
203
+ ].concat(_to_consumable_array$2((_config_models = config.models) !== null && _config_models !== void 0 ? _config_models : [])).filter(Boolean);
204
+ var systemOneModels = declaredModels.filter(function(x) {
205
+ return isOpenRouterSystemOneModelId(x);
206
+ });
207
+ if (decision) {
208
+ var _config_models2;
209
+ declaredModels.filter(function(x) {
210
+ return !isOpenRouterSystemOneModelId(x);
211
+ }).forEach(function(model) {
212
+ errors.push("`".concat(model, "` is not a System One model, and only a System One model answers a decision. Name a `typesafe/…` model (see DEFAULT_OPENROUTER_SYSTEM_ONE_MODEL_ID)."));
213
+ });
214
+ if ((_config_models2 = config.models) === null || _config_models2 === void 0 ? void 0 : _config_models2.length) {
215
+ warnings.push('`models` has no meaning on a decision: the decisions route takes a single `model` and no fallback chain, so every entry here is dropped.');
216
+ }
217
+ } else {
218
+ systemOneModels.forEach(function(model) {
219
+ errors.push("`".concat(model, "` is a System One model, which answers only `POST /systemone` and cannot serve a completion. Ask it through `openRouterDecision` rather than `callModelForOpenRouterRequest`, or name a chat model here."));
220
+ });
221
+ }
222
+ var format = (_config_text = config.text) === null || _config_text === void 0 ? void 0 : _config_text.format;
223
+ if ((format === null || format === void 0 ? void 0 : format.type) === 'json_schema') {
224
+ if (!format.name) {
225
+ errors.push('A `json_schema` text format requires a `name`.');
226
+ }
227
+ if (!format.schema) {
228
+ errors.push('A `json_schema` text format requires a `schema`.');
229
+ }
230
+ }
231
+ var fileParser = (_config_plugins = config.plugins) === null || _config_plugins === void 0 ? void 0 : _config_plugins.find(function(x) {
232
+ return x.id === 'file-parser';
233
+ });
234
+ if (fileParser != null && !((_fileParser_pdf = fileParser.pdf) === null || _fileParser_pdf === void 0 ? void 0 : _fileParser_pdf.engine)) {
235
+ 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.');
236
+ }
237
+ var hasHostedTools = ((_ref = (_config_tools = config.tools) === null || _config_tools === void 0 ? void 0 : _config_tools.length) !== null && _ref !== void 0 ? _ref : 0) > 0;
238
+ var fileSearchWithoutStores = (_config_tools1 = config.tools) === null || _config_tools1 === void 0 ? void 0 : _config_tools1.some(function(x) {
239
+ return x.type === 'file_search' && !Array.isArray(x['vectorStoreIds']);
240
+ });
241
+ if (fileSearchWithoutStores) {
242
+ // The SDK drops an unrecognized field (a `vector_store_ids` authored in wire case, say) during
243
+ // outbound serialization, leaving a tool that searches nothing and a model that answers ungrounded
244
+ // with no error at all. That is exactly the failure worth refusing to publish.
245
+ 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.');
246
+ }
247
+ if (hasHostedTools && ((_config_provider = config.provider) === null || _config_provider === void 0 ? void 0 : _config_provider.requireParameters) !== true) {
248
+ 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.');
249
+ }
250
+ 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) {
251
+ warnings.push('`provider.only` was set without `provider.allowFallbacks: false`, so routing can still leave the pinned provider.');
252
+ }
253
+ }
254
+ return {
255
+ valid: errors.length === 0,
256
+ errors: errors,
257
+ warnings: warnings
258
+ };
259
+ }
260
+
261
+ function _array_like_to_array$1(arr, len) {
262
+ if (len == null || len > arr.length) len = arr.length;
263
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
264
+ return arr2;
265
+ }
266
+ function _array_without_holes$1(arr) {
267
+ if (Array.isArray(arr)) return _array_like_to_array$1(arr);
268
+ }
269
+ function _define_property$1(obj, key, value) {
270
+ if (key in obj) {
271
+ Object.defineProperty(obj, key, {
272
+ value: value,
273
+ enumerable: true,
274
+ configurable: true,
275
+ writable: true
276
+ });
277
+ } else obj[key] = value;
278
+ return obj;
279
+ }
280
+ function _iterable_to_array$1(iter) {
281
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
282
+ return Array.from(iter);
283
+ }
284
+ }
285
+ function _non_iterable_spread$1() {
286
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
287
+ }
288
+ function _object_spread$1(target) {
289
+ for(var i = 1; i < arguments.length; i++){
290
+ var source = arguments[i] != null ? arguments[i] : {};
291
+ var ownKeys = Object.keys(source);
292
+ if (typeof Object.getOwnPropertySymbols === "function") {
293
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
294
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
295
+ }));
296
+ }
297
+ ownKeys.forEach(function(key) {
298
+ _define_property$1(target, key, source[key]);
299
+ });
300
+ }
301
+ return target;
302
+ }
303
+ function _to_consumable_array$1(arr) {
304
+ return _array_without_holes$1(arr) || _iterable_to_array$1(arr) || _unsupported_iterable_to_array$1(arr) || _non_iterable_spread$1();
305
+ }
306
+ function _type_of$1(obj) {
307
+ "@swc/helpers - typeof";
308
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
309
+ }
310
+ function _unsupported_iterable_to_array$1(o, minLen) {
311
+ if (!o) return;
312
+ if (typeof o === "string") return _array_like_to_array$1(o, minLen);
313
+ var n = Object.prototype.toString.call(o).slice(8, -1);
314
+ if (n === "Object" && o.constructor) n = o.constructor.name;
315
+ if (n === "Map" || n === "Set") return Array.from(n);
316
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array$1(o, minLen);
317
+ }
318
+ /**
319
+ * Confidence at or above which {@link asOpenRouterDecisionConfidenceBand} reads `high`.
320
+ *
321
+ * A documented STARTING POINT, not a tuned threshold. Note also that a Noul probability and a Choice
322
+ * confidence answer different questions and are not comparable, so a threshold calibrated for one may
323
+ * not be carried over to the other.
324
+ */ var OPENROUTER_DECISION_CONFIDENCE_HIGH = 0.75;
325
+ /**
326
+ * Confidence at or above which {@link asOpenRouterDecisionConfidenceBand} reads `medium`.
327
+ *
328
+ * See the note on {@link OPENROUTER_DECISION_CONFIDENCE_HIGH}.
329
+ */ var OPENROUTER_DECISION_CONFIDENCE_MEDIUM = 0.5;
330
+ /**
331
+ * Most options a single Choice may declare.
332
+ *
333
+ * A hard transport limit, not a guideline. Past it, narrow in two stages — ask a first Choice that picks
334
+ * the branch, then a second over that branch's members — rather than truncating the set, because an
335
+ * option that was truncated away is one the model can never pick and nothing reports that it was missing.
336
+ */ var OPENROUTER_DECISION_CHOICE_OPTIONS_MAX = 255;
337
+ /**
338
+ * Fewest levels a Score may declare.
339
+ */ var OPENROUTER_DECISION_SCORE_LEVELS_MIN = 2;
340
+ /**
341
+ * Most levels a Score may declare.
342
+ *
343
+ * The trap this guards: a 0..8 band is NINE levels and legal, while a 0..10 scale is eleven and is
344
+ * rejected at the wire. Past the ceiling, MERGE the levels that cannot be told apart — never truncate
345
+ * the top, which silently removes the extreme the threshold usually cares about.
346
+ */ var OPENROUTER_DECISION_SCORE_LEVELS_MAX = 10;
347
+ /**
348
+ * Whether a declaration entry says nothing at all.
349
+ *
350
+ * A blank string, an empty array, and a keyless object all ask nothing, and all three reach the wire as
351
+ * a question the model cannot answer.
352
+ *
353
+ * @param entry - The entry to test.
354
+ * @returns True when the entry carries no guidance.
355
+ *
356
+ * @__NO_SIDE_EFFECTS__
357
+ */ function isBlankOpenRouterDecisionEntry(entry) {
358
+ var result;
359
+ if (entry == null) {
360
+ result = true;
361
+ } else if (typeof entry === 'string') {
362
+ result = entry.trim() === '';
363
+ } else if (Array.isArray(entry)) {
364
+ result = entry.length === 0;
365
+ } else {
366
+ result = Object.keys(entry).length === 0;
367
+ }
368
+ return result;
369
+ }
370
+ /**
371
+ * The option names a Choice declared — what the model was SHOWN.
372
+ *
373
+ * @param question - The choice question.
374
+ * @returns The declared option names, in declaration order.
375
+ *
376
+ * @__NO_SIDE_EFFECTS__
377
+ */ function openRouterDecisionChoiceOptionNames(question) {
378
+ return Object.keys(question.options);
379
+ }
380
+ /**
381
+ * Reads a confidence as a band.
382
+ *
383
+ * An ABSENT confidence reads `low` rather than throwing: the model is not required to report one, and a
384
+ * caller that branches on the band should treat "did not say" the same as "not sure". A non-finite one
385
+ * (`NaN`, `Infinity`) reads `low` for the same reason — a garbled number is not a report of certainty,
386
+ * and without the guard `NaN` fails every comparison below and falls through to `medium`.
387
+ *
388
+ * @param confidence - The reported confidence, if any.
389
+ * @returns The band.
390
+ *
391
+ * @__NO_SIDE_EFFECTS__
392
+ */ function asOpenRouterDecisionConfidenceBand(confidence) {
393
+ var result;
394
+ if (confidence == null || !Number.isFinite(confidence) || confidence < OPENROUTER_DECISION_CONFIDENCE_MEDIUM) {
395
+ result = 'low';
396
+ } else if (confidence >= OPENROUTER_DECISION_CONFIDENCE_HIGH) {
397
+ result = 'high';
398
+ } else {
399
+ result = 'medium';
400
+ }
401
+ return result;
402
+ }
403
+ /**
404
+ * Reads a Choice's distribution as a ranking, most probable first.
405
+ *
406
+ * The distribution is a FREE full ranking — the model reports every option, not just the winner — so a
407
+ * caller wanting a shortlist should read this rather than paying for a second question.
408
+ *
409
+ * Returns an empty array when the answer carried no distribution, which is a real reply rather than an
410
+ * error. The sort is stable, so tied options keep declaration order.
411
+ *
412
+ * @param answer - The choice answer.
413
+ * @returns The ranking rows.
414
+ *
415
+ * @__NO_SIDE_EFFECTS__
416
+ */ function openRouterDecisionChoiceRanking(answer) {
417
+ var probabilities = answer.probabilities;
418
+ return probabilities == null ? [] : Object.keys(probabilities).map(function(option) {
419
+ return {
420
+ option: option,
421
+ probability: probabilities[option]
422
+ };
423
+ }).sort(function(a, b) {
424
+ return b.probability - a.probability;
425
+ });
426
+ }
427
+ /**
428
+ * Reads a Choice's distribution back as the caller's OWN rows, most probable first.
429
+ *
430
+ * The seam exists because a Choice's options are usually derived from rows the caller already holds, and
431
+ * walking the distribution back to them by hand at every call site is where the option-name convention
432
+ * quietly drifts.
433
+ *
434
+ * @param config - The answers, the question to read, and how to resolve an option to a row.
435
+ * @returns The resolved rows, most probable first. Options that resolve to nothing are dropped.
436
+ */ function mapOpenRouterDecisionChoiceRows(config) {
437
+ var answers = config.answers, question = config.question, rowOf = config.rowOf;
438
+ var answer = answers[question];
439
+ return answer.type === 'choice' ? openRouterDecisionChoiceRanking(answer).map(function(param) {
440
+ var option = param.option, probability = param.probability;
441
+ return {
442
+ row: rowOf(option),
443
+ probability: probability
444
+ };
445
+ }).filter(function(x) {
446
+ return x.row != null;
447
+ }) : [];
448
+ }
449
+ /**
450
+ * Matches a backticked dot-and-index path, the convention for naming a part of the state from inside
451
+ * `instructions`.
452
+ */ var OPENROUTER_DECISION_STATE_PATH_REGEX = /`([A-Za-z_$][\w$]*((\.[A-Za-z_$][\w$]*)|(\[\d+\]))*)`/g;
453
+ /**
454
+ * Reads back the state paths a declaration entry names.
455
+ *
456
+ * The convention is to name a part of the state as a dot-and-index path IN BACKTICKS — `` `phrase` ``,
457
+ * `` `ticket.sender.email` ``, `` `messages[0].text` `` — so a question points at something the state
458
+ * actually carries rather than describing it again in prose.
459
+ *
460
+ * Documented and inspectable, deliberately NOT enforced: backticks also legitimately quote an option key
461
+ * or a literal, so a spec may pin that a declaration points at keys its state has, while the transport
462
+ * never refuses one that does not.
463
+ *
464
+ * @param entry - The entry to read. Objects and arrays are walked.
465
+ * @returns The paths, deduplicated, in the order they first appear.
466
+ */ function openRouterDecisionStatePaths(entry) {
467
+ var found = new Set();
468
+ function read(value) {
469
+ if (typeof value === 'string') {
470
+ var _iteratorNormalCompletion = true, _didIteratorError = false, _iteratorError = undefined;
471
+ try {
472
+ for(var _iterator = value.matchAll(OPENROUTER_DECISION_STATE_PATH_REGEX)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true){
473
+ var match = _step.value;
474
+ found.add(match[1]);
475
+ }
476
+ } catch (err) {
477
+ _didIteratorError = true;
478
+ _iteratorError = err;
479
+ } finally{
480
+ try {
481
+ if (!_iteratorNormalCompletion && _iterator.return != null) {
482
+ _iterator.return();
483
+ }
484
+ } finally{
485
+ if (_didIteratorError) {
486
+ throw _iteratorError;
487
+ }
488
+ }
489
+ }
490
+ } else if (Array.isArray(value)) {
491
+ value.forEach(read);
492
+ } else if (value != null && (typeof value === "undefined" ? "undefined" : _type_of$1(value)) === 'object') {
493
+ Object.values(value).forEach(read);
494
+ }
495
+ }
496
+ read(entry);
497
+ return Array.from(found);
498
+ }
499
+ /**
500
+ * Declares a Choice question.
501
+ *
502
+ * Supply the FULL option set, plus an explicit `other` / `none of the above` when the set may not cover
503
+ * the input — the distribution is normalised over what was supplied, so a Choice always names a winner
504
+ * whether or not one fits.
505
+ *
506
+ * @param instructions - The complete question, as the model will read it.
507
+ * @param options - The options, keyed by the name the answer will quote.
508
+ * @returns The declared question.
509
+ *
510
+ * @__NO_SIDE_EFFECTS__
511
+ */ function openRouterChoiceQuestion(instructions, options) {
512
+ return {
513
+ type: 'choice',
514
+ instructions: instructions,
515
+ options: options
516
+ };
517
+ }
518
+ /**
519
+ * Declares a Score question.
520
+ *
521
+ * Use as many levels as can be described DISTINCTLY, lowest to highest — three is fine, and a rare
522
+ * extreme deserves its own level. One dimension per question.
523
+ *
524
+ * @param instructions - The complete question, as the model will read it.
525
+ * @param levels - The levels, lowest first. At least two.
526
+ * @returns The declared question.
527
+ *
528
+ * @__NO_SIDE_EFFECTS__
529
+ */ function openRouterScoreQuestion(instructions, levels) {
530
+ return {
531
+ type: 'score',
532
+ instructions: instructions,
533
+ levels: _to_consumable_array$1(levels)
534
+ };
535
+ }
536
+ /**
537
+ * Declares a Noul question.
538
+ *
539
+ * @param instructions - The complete question, as the model will read it.
540
+ * @param means - Optional explicit definitions of the true and false sides.
541
+ * @returns The declared question.
542
+ *
543
+ * @__NO_SIDE_EFFECTS__
544
+ */ function openRouterNoulQuestion(instructions, means) {
545
+ return _object_spread$1({
546
+ type: 'noul',
547
+ instructions: instructions
548
+ }, means == null ? undefined : {
549
+ means: means
550
+ });
551
+ }
552
+ /**
553
+ * Describes what is wrong with one declared question, or undefined when nothing is.
554
+ *
555
+ * @param question - The question to check.
556
+ * @returns The problem, or undefined.
557
+ */ function openRouterDecisionQuestionDeclarationDetail(question) {
558
+ var result;
559
+ if (isBlankOpenRouterDecisionEntry(question.instructions)) {
560
+ result = 'a question with no instructions asks nothing';
561
+ } else {
562
+ switch(question.type){
563
+ case 'choice':
564
+ {
565
+ var options = openRouterDecisionChoiceOptionNames(question).length;
566
+ if (options === 0) {
567
+ result = 'a Choice declaring no options asks nothing';
568
+ } else if (options > OPENROUTER_DECISION_CHOICE_OPTIONS_MAX) {
569
+ result = "a Choice may declare at most ".concat(OPENROUTER_DECISION_CHOICE_OPTIONS_MAX, " options and this one declares ").concat(options, "; narrow in two stages rather than truncating");
570
+ }
571
+ break;
572
+ }
573
+ case 'score':
574
+ {
575
+ var levels = question.levels.length;
576
+ if (levels < OPENROUTER_DECISION_SCORE_LEVELS_MIN) {
577
+ result = "a Score needs at least ".concat(OPENROUTER_DECISION_SCORE_LEVELS_MIN, " ordered levels and this one declares ").concat(levels);
578
+ } else if (levels > OPENROUTER_DECISION_SCORE_LEVELS_MAX) {
579
+ result = "a Score may declare at most ".concat(OPENROUTER_DECISION_SCORE_LEVELS_MAX, " levels and this one declares ").concat(levels, "; merge the levels that cannot be described distinctly rather than truncating the top");
580
+ }
581
+ break;
582
+ }
583
+ }
584
+ }
585
+ return result;
586
+ }
587
+ /**
588
+ * Validates a declared question map.
589
+ *
590
+ * Every problem here fails AT THE DECLARATION, naming the question, rather than as a 4xx about a request
591
+ * body — which is the difference between a publish that is refused and a run that dies in a sweep at 2am.
592
+ *
593
+ * Returns the package's standard validation result so a caller can report question problems and config
594
+ * problems through one surface.
595
+ *
596
+ * @param questions - The declared questions.
597
+ * @returns The validation result.
598
+ */ function validateOpenRouterDecisionQuestions(questions) {
599
+ var errors = [];
600
+ var warnings = [];
601
+ var ids = questions == null ? [] : Object.keys(questions);
602
+ if (ids.length === 0) {
603
+ errors.push('No questions were declared. A decision asks the model to pick a position inside an answer space, so there is nothing to ask without one.');
604
+ }
605
+ ids.forEach(function(id) {
606
+ var detail = openRouterDecisionQuestionDeclarationDetail(questions[id]);
607
+ if (detail != null) {
608
+ errors.push("Question `".concat(id, "` cannot be asked: ").concat(detail, "."));
609
+ }
610
+ });
611
+ return {
612
+ valid: errors.length === 0,
613
+ errors: errors,
614
+ warnings: warnings
615
+ };
616
+ }
617
+
618
+ function _array_like_to_array(arr, len) {
619
+ if (len == null || len > arr.length) len = arr.length;
620
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
621
+ return arr2;
622
+ }
623
+ function _array_without_holes(arr) {
624
+ if (Array.isArray(arr)) return _array_like_to_array(arr);
625
+ }
626
+ function _assert_this_initialized(self) {
627
+ if (self === void 0) throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
628
+ return self;
629
+ }
630
+ function _call_super(_this, derived, args) {
631
+ derived = _get_prototype_of(derived);
632
+ return _possible_constructor_return(_this, _is_native_reflect_construct() ? Reflect.construct(derived, args || [], _get_prototype_of(_this).constructor) : derived.apply(_this, args));
633
+ }
634
+ function _class_call_check(instance, Constructor) {
635
+ if (!(instance instanceof Constructor)) throw new TypeError("Cannot call a class as a function");
636
+ }
637
+ function _construct(Parent, args, Class) {
638
+ if (_is_native_reflect_construct()) _construct = Reflect.construct;
639
+ else {
640
+ _construct = function construct(Parent, args, Class) {
641
+ var a = [
642
+ null
643
+ ];
644
+ a.push.apply(a, args);
645
+ var Constructor = Function.bind.apply(Parent, a);
646
+ var instance = new Constructor();
647
+ if (Class) _set_prototype_of(instance, Class.prototype);
648
+ return instance;
649
+ };
650
+ }
651
+ return _construct.apply(null, arguments);
652
+ }
653
+ function _define_property(obj, key, value) {
654
+ if (key in obj) {
655
+ Object.defineProperty(obj, key, {
656
+ value: value,
657
+ enumerable: true,
658
+ configurable: true,
659
+ writable: true
660
+ });
661
+ } else obj[key] = value;
662
+ return obj;
663
+ }
664
+ function _get_prototype_of(o) {
665
+ _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
666
+ return o.__proto__ || Object.getPrototypeOf(o);
667
+ };
668
+ return _get_prototype_of(o);
669
+ }
670
+ function _inherits(subClass, superClass) {
671
+ if (typeof superClass !== "function" && superClass !== null) {
672
+ throw new TypeError("Super expression must either be null or a function");
673
+ }
674
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
675
+ constructor: {
676
+ value: subClass,
677
+ writable: true,
678
+ configurable: true
679
+ }
680
+ });
681
+ if (superClass) _set_prototype_of(subClass, superClass);
682
+ }
683
+ function _is_native_function(fn) {
684
+ return Function.toString.call(fn).indexOf("[native code]") !== -1;
685
+ }
686
+ function _is_native_reflect_construct() {
687
+ try {
688
+ var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
689
+ } catch (_) {}
690
+ return (_is_native_reflect_construct = function() {
691
+ return !!result;
692
+ })();
693
+ }
694
+ function _iterable_to_array(iter) {
695
+ if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) {
696
+ return Array.from(iter);
697
+ }
698
+ }
699
+ function _non_iterable_spread() {
700
+ throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
701
+ }
702
+ function _object_spread(target) {
703
+ for(var i = 1; i < arguments.length; i++){
704
+ var source = arguments[i] != null ? arguments[i] : {};
705
+ var ownKeys = Object.keys(source);
706
+ if (typeof Object.getOwnPropertySymbols === "function") {
707
+ ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
708
+ return Object.getOwnPropertyDescriptor(source, sym).enumerable;
709
+ }));
710
+ }
711
+ ownKeys.forEach(function(key) {
712
+ _define_property(target, key, source[key]);
713
+ });
714
+ }
715
+ return target;
716
+ }
717
+ function ownKeys(object, enumerableOnly) {
718
+ var keys = Object.keys(object);
719
+ if (Object.getOwnPropertySymbols) {
720
+ var symbols = Object.getOwnPropertySymbols(object);
721
+ keys.push.apply(keys, symbols);
722
+ }
723
+ return keys;
724
+ }
725
+ function _object_spread_props(target, source) {
726
+ source = source != null ? source : {};
727
+ if (Object.getOwnPropertyDescriptors) Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
728
+ else {
729
+ ownKeys(Object(source)).forEach(function(key) {
730
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
731
+ });
732
+ }
733
+ return target;
734
+ }
735
+ function _object_without_properties(source, excluded) {
736
+ if (source == null) return {};
737
+ var target = {}, sourceKeys, key, i;
738
+ if (typeof Reflect !== "undefined" && Reflect.ownKeys) {
739
+ sourceKeys = Reflect.ownKeys(Object(source));
740
+ for(i = 0; i < sourceKeys.length; i++){
741
+ key = sourceKeys[i];
742
+ if (excluded.indexOf(key) >= 0) continue;
743
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
744
+ target[key] = source[key];
745
+ }
746
+ return target;
747
+ }
748
+ target = _object_without_properties_loose(source, excluded);
749
+ if (Object.getOwnPropertySymbols) {
750
+ sourceKeys = Object.getOwnPropertySymbols(source);
751
+ for(i = 0; i < sourceKeys.length; i++){
752
+ key = sourceKeys[i];
753
+ if (excluded.indexOf(key) >= 0) continue;
754
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
755
+ target[key] = source[key];
756
+ }
757
+ }
758
+ return target;
759
+ }
760
+ function _object_without_properties_loose(source, excluded) {
761
+ if (source == null) return {};
762
+ var target = {}, sourceKeys = Object.getOwnPropertyNames(source), key, i;
763
+ for(i = 0; i < sourceKeys.length; i++){
764
+ key = sourceKeys[i];
765
+ if (excluded.indexOf(key) >= 0) continue;
766
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
767
+ target[key] = source[key];
768
+ }
769
+ return target;
770
+ }
771
+ function _possible_constructor_return(self, call) {
772
+ if (call && (_type_of(call) === "object" || typeof call === "function")) return call;
773
+ return _assert_this_initialized(self);
774
+ }
775
+ function _set_prototype_of(o, p) {
776
+ _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
777
+ o.__proto__ = p;
778
+ return o;
779
+ };
780
+ return _set_prototype_of(o, p);
781
+ }
782
+ function _to_consumable_array(arr) {
783
+ return _array_without_holes(arr) || _iterable_to_array(arr) || _unsupported_iterable_to_array(arr) || _non_iterable_spread();
784
+ }
785
+ function _type_of(obj) {
786
+ "@swc/helpers - typeof";
787
+ return obj && typeof Symbol !== "undefined" && obj.constructor === Symbol ? "symbol" : typeof obj;
788
+ }
789
+ function _unsupported_iterable_to_array(o, minLen) {
790
+ if (!o) return;
791
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
792
+ var n = Object.prototype.toString.call(o).slice(8, -1);
793
+ if (n === "Object" && o.constructor) n = o.constructor.name;
794
+ if (n === "Map" || n === "Set") return Array.from(n);
795
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
796
+ }
797
+ function _wrap_native_super(Class) {
798
+ var _cache = typeof Map === "function" ? new Map() : undefined;
799
+ _wrap_native_super = function(Class) {
800
+ if (Class === null || !_is_native_function(Class)) return Class;
801
+ if (typeof Class !== "function") throw new TypeError("Super expression must either be null or a function");
802
+ if (typeof _cache !== "undefined") {
803
+ if (_cache.has(Class)) return _cache.get(Class);
804
+ _cache.set(Class, Wrapper);
805
+ }
806
+ function Wrapper() {
807
+ return _construct(Class, arguments, _get_prototype_of(this).constructor);
808
+ }
809
+ Wrapper.prototype = Object.create(Class.prototype, {
810
+ constructor: {
811
+ value: Wrapper,
812
+ enumerable: false,
813
+ writable: true,
814
+ configurable: true
815
+ }
816
+ });
817
+ return _set_prototype_of(Wrapper, Class);
818
+ };
819
+ return _wrap_native_super(Class);
820
+ }
821
+ /**
822
+ * How far a distribution's probabilities may sum from 1 before the reply is read as malformed.
823
+ *
824
+ * Wide enough to absorb the float rounding a JSON round-trip introduces, narrow enough that a
825
+ * distribution missing an option does not pass.
826
+ */ var OPENROUTER_DECISION_DISTRIBUTION_SUM_TOLERANCE = 0.05;
827
+ /**
828
+ * Raised when a decision cannot be asked as declared.
829
+ *
830
+ * Every declaration problem fails HERE — before a request is built, naming the question — rather than as
831
+ * a 4xx about a request body. The distinction matters because the fixes are different: a malformed
832
+ * declaration is a code or authoring bug, while a 4xx is an operational one.
833
+ */ var OpenRouterDecisionDeclarationError = /*#__PURE__*/ function(Error1) {
834
+ _inherits(OpenRouterDecisionDeclarationError, Error1);
835
+ function OpenRouterDecisionDeclarationError(errors) {
836
+ _class_call_check(this, OpenRouterDecisionDeclarationError);
837
+ var _this;
838
+ _this = _call_super(this, OpenRouterDecisionDeclarationError, [
839
+ "This decision cannot be asked as declared: ".concat(errors.join(' '))
840
+ ]), _define_property(_this, "errors", void 0);
841
+ _this.name = 'OpenRouterDecisionDeclarationError';
842
+ _this.errors = errors;
843
+ return _this;
844
+ }
845
+ return OpenRouterDecisionDeclarationError;
846
+ }(_wrap_native_super(Error));
847
+ /**
848
+ * Builds a decision request from an optional resolved prompt plus the caller's state and questions.
849
+ *
850
+ * Stored questions and caller questions are merged BY ID with the caller winning, the same composition
851
+ * a prompt's static seed messages and dynamic `input` already use. What differs is the reason: there is
852
+ * no prompt cache on this route, so the merge is about where a question is authored — a fixed taxonomy
853
+ * belongs in a version an operator can edit, a per-call candidate set can only come from code.
854
+ *
855
+ * @param params - The prompt, state, questions, overrides, session id, and trace.
856
+ * @returns The built request.
857
+ * @throws {OpenRouterDecisionDeclarationError} When the merged question map cannot be asked.
858
+ */ function openRouterDecisionRequest(params) {
859
+ var _ref;
860
+ var prompt = params.prompt, state = params.state, questions = params.questions, overrides = params.overrides, sessionId = params.sessionId, trace = params.trace;
861
+ var config = mergeOpenRouterModelConfig([
862
+ prompt === null || prompt === void 0 ? void 0 : prompt.config,
863
+ overrides
864
+ ]);
865
+ var merged = _object_spread({}, (_ref = prompt === null || prompt === void 0 ? void 0 : prompt.questions) !== null && _ref !== void 0 ? _ref : undefined, questions !== null && questions !== void 0 ? questions : undefined);
866
+ var validation = validateOpenRouterDecisionQuestions(merged);
867
+ if (!validation.valid) {
868
+ throw new OpenRouterDecisionDeclarationError(validation.errors);
869
+ }
870
+ return {
871
+ config: config,
872
+ state: state,
873
+ questions: merged,
874
+ sessionId: sessionId,
875
+ trace: trace
876
+ };
877
+ }
878
+ /**
879
+ * Splits a model config into the parameters a decisions request accepts and the ones it does not.
880
+ *
881
+ * The decisions route takes only `model`, `provider` and `user`. Everything else on
882
+ * {@link OpenRouterModelConfig} describes a completion — an output format, a reasoning budget, a tool
883
+ * set, a temperature — and none of it has a meaning here: a decision has no free-form output to shape
884
+ * and no tools to call. Those keys are reported in `dropped` rather than quietly discarded, because a
885
+ * `temperature` a caller believes is in effect is exactly the kind of thing that is only noticed when
886
+ * an answer is already wrong.
887
+ *
888
+ * `models` (the fallback chain) is dropped for a sharper reason: the decisions route takes a single
889
+ * `model`, so a chain authored here does not degrade to its first entry — it simply does not exist.
890
+ *
891
+ * @param config - The merged model config.
892
+ * @returns The split config.
893
+ */ function splitOpenRouterDecisionModelConfig(config) {
894
+ // Named in a destructure rather than a list of strings, exactly as `splitOpenRouterModelConfig` does,
895
+ // so TypeScript checks the names against the config interface and a rename cannot leave a stale entry.
896
+ var _ref = config !== null && config !== void 0 ? config : {}, model = _ref.model, provider = _ref.provider, user = _ref.user, requestTimeoutMs = _ref.requestTimeoutMs, rest = _object_without_properties(_ref, [
897
+ "model",
898
+ "provider",
899
+ "user",
900
+ "requestTimeoutMs"
901
+ ]);
902
+ var dropped = Object.keys(filterUndefinedValues(rest));
903
+ return {
904
+ requestConfig: filterUndefinedValues({
905
+ model: model,
906
+ provider: provider,
907
+ user: user
908
+ }),
909
+ requestTimeoutMs: requestTimeoutMs,
910
+ dropped: dropped
911
+ };
912
+ }
913
+ /**
914
+ * Validates a decision request before it is sent.
915
+ *
916
+ * The mirror of `validateOpenRouterModelConfig` for this arm, and the reason both exist: the model slug
917
+ * is the ONLY thing that says which of OpenRouter's two inference surfaces a request belongs to, so it
918
+ * is checked on both, and neither arm can be entered with a model the other one owns.
919
+ *
920
+ * @param request - The request to check.
921
+ * @returns The validation result.
922
+ */ function validateOpenRouterDecisionRequest(request) {
923
+ var errors = [];
924
+ var warnings = [];
925
+ if (request == null) {
926
+ errors.push('No decision request was provided.');
927
+ } else {
928
+ var _splitOpenRouterDecisionModelConfig = splitOpenRouterDecisionModelConfig(request.config), requestConfig = _splitOpenRouterDecisionModelConfig.requestConfig, dropped = _splitOpenRouterDecisionModelConfig.dropped;
929
+ var model = requestConfig.model;
930
+ if (!model) {
931
+ errors.push('No `model` was specified.');
932
+ } else if (!isOpenRouterSystemOneModelId(model)) {
933
+ errors.push("`".concat(model, "` is not a System One model, and only a System One model answers a decision. Name a `typesafe/…` model (see DEFAULT_OPENROUTER_SYSTEM_ONE_MODEL_ID), or call `callModelForOpenRouterRequest` instead."));
934
+ }
935
+ var questionValidation = validateOpenRouterDecisionQuestions(request.questions);
936
+ questionValidation.errors.forEach(function(x) {
937
+ return errors.push(x);
938
+ });
939
+ questionValidation.warnings.forEach(function(x) {
940
+ return warnings.push(x);
941
+ });
942
+ if (dropped.length > 0) {
943
+ var names = dropped.map(function(x) {
944
+ return '`' + x + '`';
945
+ }).join(', ');
946
+ warnings.push("The decisions route accepts only `model`, `provider` and `user`; ".concat(names, " ").concat(dropped.length === 1 ? 'was' : 'were', " dropped from the request."));
947
+ }
948
+ }
949
+ return {
950
+ valid: errors.length === 0,
951
+ errors: errors,
952
+ warnings: warnings
953
+ };
954
+ }
955
+ /**
956
+ * Converts one declared question to its wire shape.
957
+ *
958
+ * A pure rename. Three details carry meaning and are not incidental:
959
+ *
960
+ * - an option with no description becomes an explicit `null`, which is how the wire spells "undescribed
961
+ * option" — omitting the key would instead remove the option from the answer space;
962
+ * - a Noul with no `means` omits `criteria` ENTIRELY rather than sending an empty object;
963
+ * - a structured entry is passed through by IDENTITY, never copied or re-serialized, because the wire
964
+ * carries declaration guidance verbatim and a normalising round-trip is exactly the kind of silent
965
+ * edit this mapping must not make.
966
+ *
967
+ * @param question - The declared question.
968
+ * @returns The wire question.
969
+ */ function openRouterDecisionWireQuestion(question) {
970
+ var result;
971
+ switch(question.type){
972
+ case 'choice':
973
+ result = {
974
+ type: 'choice',
975
+ instructions: question.instructions,
976
+ criteria: openRouterDecisionChoiceOptionNames(question).reduce(function(all, option) {
977
+ var _question_options_option;
978
+ all[option] = (_question_options_option = question.options[option]) !== null && _question_options_option !== void 0 ? _question_options_option : null;
979
+ return all;
980
+ }, {})
981
+ };
982
+ break;
983
+ case 'score':
984
+ result = {
985
+ type: 'score',
986
+ instructions: question.instructions,
987
+ criteria: _to_consumable_array(question.levels)
988
+ };
989
+ break;
990
+ case 'noul':
991
+ result = _object_spread({
992
+ type: 'noul',
993
+ instructions: question.instructions
994
+ }, question.means == null ? undefined : {
995
+ criteria: {
996
+ true: question.means.true,
997
+ false: question.means.false
998
+ }
999
+ });
1000
+ break;
1001
+ }
1002
+ return result;
1003
+ }
1004
+ /**
1005
+ * Converts a built request into the `/systemone` request body.
1006
+ *
1007
+ * @param request - The built request.
1008
+ * @returns The request body, in the SDK's request surface.
1009
+ */ function openRouterDecisionRequestBody(request) {
1010
+ var _requestConfig_model, _request_sessionId;
1011
+ var requestConfig = splitOpenRouterDecisionModelConfig(request.config).requestConfig;
1012
+ return filterUndefinedValues(_object_spread_props(_object_spread({}, requestConfig), {
1013
+ model: (_requestConfig_model = requestConfig.model) !== null && _requestConfig_model !== void 0 ? _requestConfig_model : '',
1014
+ state: request.state,
1015
+ questions: mapObjectMap(request.questions, function(question) {
1016
+ return openRouterDecisionWireQuestion(question);
1017
+ }),
1018
+ sessionId: (_request_sessionId = request.sessionId) !== null && _request_sessionId !== void 0 ? _request_sessionId : undefined,
1019
+ trace: request.trace == null ? undefined : {
1020
+ additionalProperties: _object_spread({}, request.trace)
1021
+ }
1022
+ }));
1023
+ }
1024
+ /**
1025
+ * Raised when a reply did not answer the questions that were declared.
1026
+ *
1027
+ * This is always a defect in the RESPONSE and never a judgement the model made. "None of these fits" is
1028
+ * not a fault — it is said through a Noul the caller declared for it, and arrives as an ANSWER. A caller
1029
+ * that catches this is handling a malformed reply, not a negative one.
1030
+ */ var OpenRouterDecisionAnswerFaultError = /*#__PURE__*/ function(Error1) {
1031
+ _inherits(OpenRouterDecisionAnswerFaultError, Error1);
1032
+ function OpenRouterDecisionAnswerFaultError(faults) {
1033
+ _class_call_check(this, OpenRouterDecisionAnswerFaultError);
1034
+ var _this;
1035
+ var described = faults.map(function(x) {
1036
+ return x.question + ' (' + x.kind + '): ' + x.detail;
1037
+ }).join('; ');
1038
+ _this = _call_super(this, OpenRouterDecisionAnswerFaultError, [
1039
+ "The decision reply did not answer its declared questions: ".concat(described)
1040
+ ]), _define_property(_this, "faults", void 0);
1041
+ _this.name = 'OpenRouterDecisionAnswerFaultError';
1042
+ _this.faults = faults;
1043
+ return _this;
1044
+ }
1045
+ return OpenRouterDecisionAnswerFaultError;
1046
+ }(_wrap_native_super(Error));
1047
+ /**
1048
+ * Collects everything wrong with one answer against the question that asked it.
1049
+ *
1050
+ * @param question - The declared question.
1051
+ * @param id - The question's id, for reporting.
1052
+ * @param answer - The answer as returned, if any.
1053
+ * @returns The faults found. Empty when the answer is well formed.
1054
+ */ function openRouterDecisionAnswerFaults(question, id, answer) {
1055
+ var faults = [];
1056
+ if (answer == null) {
1057
+ faults.push({
1058
+ kind: 'answer-missing',
1059
+ question: id,
1060
+ detail: 'no answer was returned'
1061
+ });
1062
+ } else if (answer.type !== question.type) {
1063
+ faults.push({
1064
+ kind: 'answer-mistyped',
1065
+ question: id,
1066
+ detail: "a ".concat(question.type, " question was answered with a ").concat(answer.type)
1067
+ });
1068
+ } else if (answer.type === 'choice' && question.type === 'choice') {
1069
+ var declared = new Set(openRouterDecisionChoiceOptionNames(question));
1070
+ if (!declared.has(answer.choice)) {
1071
+ faults.push({
1072
+ kind: 'choice-off-option',
1073
+ question: id,
1074
+ detail: "`".concat(answer.choice, "` was not one of the declared options")
1075
+ });
1076
+ }
1077
+ var probabilities = answer.probabilities;
1078
+ if (probabilities != null) {
1079
+ var options = Object.keys(probabilities);
1080
+ var undeclared = options.filter(function(x) {
1081
+ return !declared.has(x);
1082
+ });
1083
+ if (undeclared.length > 0) {
1084
+ var names = undeclared.map(function(x) {
1085
+ return '`' + x + '`';
1086
+ }).join(', ');
1087
+ faults.push({
1088
+ kind: 'choice-off-option',
1089
+ question: id,
1090
+ detail: "the distribution covers undeclared options ".concat(names)
1091
+ });
1092
+ }
1093
+ var sum = options.reduce(function(total, option) {
1094
+ return total + probabilities[option];
1095
+ }, 0);
1096
+ if (Math.abs(sum - 1) > OPENROUTER_DECISION_DISTRIBUTION_SUM_TOLERANCE) {
1097
+ faults.push({
1098
+ kind: 'value-out-of-range',
1099
+ question: id,
1100
+ detail: "the distribution sums to ".concat(sum, " rather than 1")
1101
+ });
1102
+ }
1103
+ }
1104
+ } else if (answer.type === 'score' && question.type === 'score') {
1105
+ var max = question.levels.length - 1;
1106
+ if (!(answer.score >= 0 && answer.score <= max)) {
1107
+ faults.push({
1108
+ kind: 'value-out-of-range',
1109
+ question: id,
1110
+ detail: "the score ".concat(answer.score, " is outside the declared 0..").concat(max)
1111
+ });
1112
+ }
1113
+ } else if (answer.type === 'noul' && !(answer.noul >= 0 && answer.noul <= 1)) {
1114
+ faults.push({
1115
+ kind: 'value-out-of-range',
1116
+ question: id,
1117
+ detail: "the noul ".concat(answer.noul, " is outside 0..1")
1118
+ });
1119
+ }
1120
+ return faults;
1121
+ }
1122
+ /**
1123
+ * Membership-checks a reply against the questions that were declared.
1124
+ *
1125
+ * This is the transport's GUARANTEE, and the reason no consumer re-checks: past this point a `choice` is
1126
+ * one of the declared options, a `score` is inside the declared range, and a `noul` is a probability. It
1127
+ * is what a decision has instead of the parse-and-salvage a completion needs — the answer space was
1128
+ * declared, so an answer either sits inside it or the reply is broken.
1129
+ *
1130
+ * Every fault is collected rather than the first, because a reply that lost one answer has usually lost
1131
+ * more than one and reporting them one round-trip at a time is no way to debug a declaration.
1132
+ *
1133
+ * An ABSENT distribution or confidence is checked for nothing: only `choice` / `score` / `noul` are
1134
+ * guaranteed on the wire, so their absence is a real reply.
1135
+ *
1136
+ * @param config - The declared questions and the raw answers.
1137
+ * @returns The answers, or the faults.
1138
+ */ function readOpenRouterDecisionAnswers(config) {
1139
+ var questions = config.questions, raw = config.raw;
1140
+ var faults = Object.keys(questions).flatMap(function(id) {
1141
+ return openRouterDecisionAnswerFaults(questions[id], id, raw[id]);
1142
+ });
1143
+ return faults.length > 0 ? {
1144
+ faults: faults
1145
+ } : {
1146
+ answers: raw
1147
+ };
1148
+ }
1149
+ /**
1150
+ * Flattens a decisions reply's usage into the package's usage shape.
1151
+ *
1152
+ * Reported through the SAME {@link OpenRouterRunUsage} a completion reports, so the cost ledger needs no
1153
+ * second counting site and a run's spend is readable without knowing which arm served it.
1154
+ *
1155
+ * Two things about this route's numbers, both measured rather than assumed:
1156
+ *
1157
+ * - `outputTokens` is REPORTED and non-zero, but it is not billed. `cost` is input alone at the model's
1158
+ * input rate — verified live at 350 input tokens and $0.042/Mtok giving exactly $0.0000147, with 34
1159
+ * output tokens on the same reply. So a cost-per-token derived from `totalTokens` here is wrong.
1160
+ * - `cost` is FINAL when it arrives. A completion's is settled server-side afterwards and refined by the
1161
+ * broadcast webhook; a decision's is synchronous, which is why a decision run needs no reconciliation.
1162
+ *
1163
+ * A measurement the reply did not report is OMITTED rather than carried as `undefined`, because a spread
1164
+ * `cost: undefined` reads downstream as "cost zero" rather than "cost unknown".
1165
+ *
1166
+ * @param usage - The usage as returned.
1167
+ * @returns The flattened usage.
1168
+ *
1169
+ * @__NO_SIDE_EFFECTS__
1170
+ */ function openRouterRunUsageFromDecisionsUsage(usage) {
1171
+ var result;
1172
+ if (usage != null) {
1173
+ var inputTokens = usage.inputTokens, outputTokens = usage.outputTokens, cost = usage.cost;
1174
+ var totalTokens = inputTokens == null && outputTokens == null ? undefined : (inputTokens !== null && inputTokens !== void 0 ? inputTokens : 0) + (outputTokens !== null && outputTokens !== void 0 ? outputTokens : 0);
1175
+ result = filterUndefinedValues({
1176
+ inputTokens: inputTokens,
1177
+ outputTokens: outputTokens,
1178
+ totalTokens: totalTokens,
1179
+ cost: cost
1180
+ }, true);
1181
+ }
1182
+ return result;
1183
+ }
1184
+
1185
+ export { openRouterNoulQuestion as A, openRouterProviderPinnedTo as B, openRouterRunUsageFromDecisionsUsage as C, DEFAULT_OPENROUTER_PDF_PARSER_ENGINE as D, openRouterScoreQuestion as E, readOpenRouterDecisionAnswers as F, splitOpenRouterDecisionModelConfig as G, validateOpenRouterDecisionQuestions as H, validateOpenRouterDecisionRequest as I, validateOpenRouterModelConfig as J, OPENROUTER_DECISION_CHOICE_OPTIONS_MAX as O, DEFAULT_OPENROUTER_SYSTEM_ONE_MODEL_ID as a, OPENROUTER_DECISION_CONFIDENCE_HIGH as b, OPENROUTER_DECISION_CONFIDENCE_MEDIUM as c, OPENROUTER_DECISION_DISTRIBUTION_SUM_TOLERANCE as d, OPENROUTER_DECISION_SCORE_LEVELS_MAX as e, OPENROUTER_DECISION_SCORE_LEVELS_MIN as f, OPENROUTER_JEV_1_13_MODEL_ID as g, OPENROUTER_JEV_LATEST_MODEL_ID as h, OPENROUTER_JEV_PREVIEW_MODEL_ID as i, OPENROUTER_SYSTEM_ONE_MODEL_NAMESPACE as j, OpenRouterDecisionAnswerFaultError as k, OpenRouterDecisionDeclarationError as l, asOpenRouterDecisionConfidenceBand as m, isBlankOpenRouterDecisionEntry as n, isOpenRouterSystemOneModelId as o, mapOpenRouterDecisionChoiceRows as p, mergeOpenRouterModelConfig as q, openRouterChoiceQuestion as r, openRouterDecisionChoiceOptionNames as s, openRouterDecisionChoiceRanking as t, openRouterDecisionRequest as u, openRouterDecisionRequestBody as v, openRouterDecisionStatePaths as w, openRouterDecisionWireQuestion as x, openRouterFileParserPlugin as y, openRouterFileSearchTool as z };