@dereekb/openrouter 14.7.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.
- package/README.md +164 -1
- package/decision.d.ts +1 -0
- package/decision.esm.js +2 -0
- package/firebase/index.esm.js +14 -5
- package/firebase/package.json +7 -7
- package/firebase/src/lib/openrouter.api.d.ts +21 -0
- package/firebase/src/lib/openrouter.model.d.ts +74 -2
- package/firebase-server/index.esm.js +417 -49
- package/firebase-server/package.json +12 -12
- package/firebase-server/src/lib/openrouter.call.inline.d.ts +58 -1
- package/firebase-server/src/lib/openrouter.runtask.handle.d.ts +26 -0
- package/firebase-server/src/lib/openrouter.runtask.service.d.ts +37 -1
- package/firebase-server/src/test/openrouter.fake.d.ts +45 -0
- package/index.esm.js +335 -136
- package/openrouter.decision.esm.js +1185 -0
- package/package.json +12 -7
- package/src/decision.d.ts +26 -0
- package/src/lib/index.d.ts +3 -0
- package/src/lib/openrouter.call.d.ts +18 -1
- package/src/lib/openrouter.config.d.ts +18 -1
- package/src/lib/openrouter.decision.call.d.ts +81 -0
- package/src/lib/openrouter.decision.d.ts +286 -0
- package/src/lib/openrouter.decision.question.d.ts +399 -0
- package/src/lib/openrouter.prompt.d.ts +25 -0
- package/src/lib/openrouter.sdk.d.ts +10 -2
- package/src/lib/openrouter.type.d.ts +51 -0
|
@@ -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 };
|