@dereekb/openrouter 14.6.0 → 14.8.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 +144 -1
- 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 +1402 -52
- package/package.json +7 -7
- package/src/lib/index.d.ts +2 -0
- package/src/lib/openrouter.call.d.ts +18 -1
- package/src/lib/openrouter.config.d.ts +18 -1
- package/src/lib/openrouter.decision.d.ts +352 -0
- package/src/lib/openrouter.decision.question.d.ts +392 -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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dereekb/openrouter",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.8.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -22,16 +22,16 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"peerDependencies": {
|
|
25
|
-
"@dereekb/firebase": "14.
|
|
26
|
-
"@dereekb/firebase-server": "14.
|
|
27
|
-
"@dereekb/model": "14.
|
|
28
|
-
"@dereekb/util": "14.
|
|
25
|
+
"@dereekb/firebase": "14.8.0",
|
|
26
|
+
"@dereekb/firebase-server": "14.8.0",
|
|
27
|
+
"@dereekb/model": "14.8.0",
|
|
28
|
+
"@dereekb/util": "14.8.0",
|
|
29
29
|
"@nestjs/common": "^12.0.1",
|
|
30
|
-
"@openrouter/sdk": "^1.
|
|
30
|
+
"@openrouter/sdk": "^1.3.8",
|
|
31
31
|
"arktype": "^2.2.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@dereekb/nestjs": "14.
|
|
34
|
+
"@dereekb/nestjs": "14.8.0"
|
|
35
35
|
},
|
|
36
36
|
"module": "./index.esm.js",
|
|
37
37
|
"main": "./index.esm.js",
|
package/src/lib/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export * from './openrouter.call';
|
|
2
2
|
export * from './openrouter.config';
|
|
3
|
+
export * from './openrouter.decision';
|
|
4
|
+
export * from './openrouter.decision.question';
|
|
3
5
|
export * from './openrouter.embedding';
|
|
4
6
|
export * from './openrouter.generation';
|
|
5
7
|
export * from './openrouter.input';
|
|
@@ -2,7 +2,7 @@ import { type Maybe } from '@dereekb/util';
|
|
|
2
2
|
import { type CallModelInput, type OpenResponsesResult, type OpenRouterCore, type RequestOptions, type StateAccessor, type Tool, ModelResult } from './openrouter.sdk';
|
|
3
3
|
import { type OpenRouterHostedToolConfig, type OpenRouterModelConfig } from './openrouter.config';
|
|
4
4
|
import { type OpenRouterPromptRequest } from './openrouter.request';
|
|
5
|
-
import { type OpenRouterGenerationId, type OpenRouterRunError, type OpenRouterRunUsage } from './openrouter.type';
|
|
5
|
+
import { type OpenRouterGenerationId, type OpenRouterModelId, type OpenRouterRunError, type OpenRouterRunUsage } from './openrouter.type';
|
|
6
6
|
/**
|
|
7
7
|
* A model config split into the part that goes on the request and the part that controls how the
|
|
8
8
|
* request is executed.
|
|
@@ -106,14 +106,31 @@ export interface OpenRouterCallModelInputParams<TTools extends readonly Tool[] =
|
|
|
106
106
|
*/
|
|
107
107
|
readonly state?: Maybe<StateAccessor<TTools>>;
|
|
108
108
|
}
|
|
109
|
+
/**
|
|
110
|
+
* Raised when a request naming a System One model is sent down the completion arm.
|
|
111
|
+
*
|
|
112
|
+
* Its own error type rather than a generic one because the fix is specific and mechanical — the call
|
|
113
|
+
* goes to `openRouterDecision` — and an error a reader can act on without opening the source is worth
|
|
114
|
+
* a named class.
|
|
115
|
+
*/
|
|
116
|
+
export declare class OpenRouterSystemOneModelOnCompletionArmError extends Error {
|
|
117
|
+
readonly model: OpenRouterModelId;
|
|
118
|
+
constructor(model: OpenRouterModelId);
|
|
119
|
+
}
|
|
109
120
|
/**
|
|
110
121
|
* Converts a built request into the `/responses` request body.
|
|
111
122
|
*
|
|
112
123
|
* This is the whole wire body minus the SDK-only keys (`tools`/`state`/`stopWhen` on the `callModel`
|
|
113
124
|
* path), so both dispatch paths assemble the request the same way and cannot drift.
|
|
114
125
|
*
|
|
126
|
+
* It is also where a System One model is refused, because it is the ONE point every dispatch path
|
|
127
|
+
* converges on — `openRouterCallModelInput`, `sendOpenRouterResponsesRequest` and
|
|
128
|
+
* `openRouterModelResultForRequest` all build their body here — so no route to the completion arm can
|
|
129
|
+
* be added later that quietly skips the check.
|
|
130
|
+
*
|
|
115
131
|
* @param request - The built request.
|
|
116
132
|
* @returns The request body, in the SDK's camelCase request surface.
|
|
133
|
+
* @throws {OpenRouterSystemOneModelOnCompletionArmError} When the config names a System One model.
|
|
117
134
|
*/
|
|
118
135
|
export declare function openRouterResponsesRequestBody(request: OpenRouterPromptRequest): Record<string, unknown>;
|
|
119
136
|
/**
|
|
@@ -289,6 +289,10 @@ export interface OpenRouterModelConfig {
|
|
|
289
289
|
export declare function mergeOpenRouterModelConfig(configs: Maybe<OpenRouterModelConfig>[]): OpenRouterModelConfig;
|
|
290
290
|
/**
|
|
291
291
|
* Result of validating an {@link OpenRouterModelConfig}.
|
|
292
|
+
*
|
|
293
|
+
* Also the package's general validation shape — `validateOpenRouterDecisionQuestions` and
|
|
294
|
+
* `validateOpenRouterDecisionRequest` report through it too, so a caller publishing a prompt can gather
|
|
295
|
+
* config problems and question problems into one surface rather than branching on which produced them.
|
|
292
296
|
*/
|
|
293
297
|
export interface OpenRouterModelConfigValidation {
|
|
294
298
|
/**
|
|
@@ -304,11 +308,24 @@ export interface OpenRouterModelConfigValidation {
|
|
|
304
308
|
*/
|
|
305
309
|
readonly warnings: string[];
|
|
306
310
|
}
|
|
311
|
+
/**
|
|
312
|
+
* Options for {@link validateOpenRouterModelConfig}.
|
|
313
|
+
*/
|
|
314
|
+
export interface ValidateOpenRouterModelConfigOptions {
|
|
315
|
+
/**
|
|
316
|
+
* Whether the config belongs to a DECISION rather than a completion.
|
|
317
|
+
*
|
|
318
|
+
* Only the model check differs, and it inverts: a decision requires a System One model and a
|
|
319
|
+
* completion refuses one. Defaults to false.
|
|
320
|
+
*/
|
|
321
|
+
readonly decision?: Maybe<boolean>;
|
|
322
|
+
}
|
|
307
323
|
/**
|
|
308
324
|
* Validates a merged model config, catching the misconfigurations that fail silently at runtime
|
|
309
325
|
* rather than loudly.
|
|
310
326
|
*
|
|
311
327
|
* @param config - The merged config to check.
|
|
328
|
+
* @param options - Which arm the config is for.
|
|
312
329
|
* @returns The validation result.
|
|
313
330
|
*/
|
|
314
|
-
export declare function validateOpenRouterModelConfig(config: Maybe<OpenRouterModelConfig>): OpenRouterModelConfigValidation;
|
|
331
|
+
export declare function validateOpenRouterModelConfig(config: Maybe<OpenRouterModelConfig>, options?: Maybe<ValidateOpenRouterModelConfigOptions>): OpenRouterModelConfigValidation;
|
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type OpenRouterModelConfig, type OpenRouterModelConfigValidation } from './openrouter.config';
|
|
3
|
+
import { type OpenRouterDecisionAnswer, type OpenRouterDecisionAnswers, type OpenRouterDecisionEntry, type OpenRouterDecisionQuestion, type OpenRouterDecisionQuestionId, type OpenRouterDecisionQuestions, type OpenRouterDecisionState } from './openrouter.decision.question';
|
|
4
|
+
import { type OpenRouterResolvedPrompt } from './openrouter.prompt';
|
|
5
|
+
import { type OpenRouterRequestTrace } from './openrouter.request';
|
|
6
|
+
import { type DecisionsRequest, type DecisionsResponse, type OpenRouterCore, type RequestOptions } from './openrouter.sdk';
|
|
7
|
+
import { type OpenRouterGenerationId, type OpenRouterModelId, type OpenRouterRunUsage } from './openrouter.type';
|
|
8
|
+
/**
|
|
9
|
+
* How far a distribution's probabilities may sum from 1 before the reply is read as malformed.
|
|
10
|
+
*
|
|
11
|
+
* Wide enough to absorb the float rounding a JSON round-trip introduces, narrow enough that a
|
|
12
|
+
* distribution missing an option does not pass.
|
|
13
|
+
*/
|
|
14
|
+
export declare const OPENROUTER_DECISION_DISTRIBUTION_SUM_TOLERANCE = 0.05;
|
|
15
|
+
/**
|
|
16
|
+
* A caller-chosen id grouping related decisions for observability.
|
|
17
|
+
*
|
|
18
|
+
* Never sent to the provider — it exists for broadcast grouping and private logging only.
|
|
19
|
+
*/
|
|
20
|
+
export type OpenRouterDecisionSessionId = string;
|
|
21
|
+
/**
|
|
22
|
+
* A decision request: the config naming the model, the state to judge, and the questions to ask of it.
|
|
23
|
+
*
|
|
24
|
+
* The decisions analogue of `OpenRouterPromptRequest`, and deliberately a separate type rather than a
|
|
25
|
+
* mode on it. The two share no content at all — one carries messages and an output contract, the other
|
|
26
|
+
* carries a state and an answer space — so folding them together would produce a type where half the
|
|
27
|
+
* fields are meaningless on any given request.
|
|
28
|
+
*/
|
|
29
|
+
export interface OpenRouterDecisionRequest<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions> {
|
|
30
|
+
/**
|
|
31
|
+
* The merged model config. Only `model`, `provider` and `user` reach the wire — see
|
|
32
|
+
* {@link splitOpenRouterDecisionModelConfig}.
|
|
33
|
+
*/
|
|
34
|
+
readonly config: OpenRouterModelConfig;
|
|
35
|
+
/**
|
|
36
|
+
* The content to judge.
|
|
37
|
+
*/
|
|
38
|
+
readonly state: OpenRouterDecisionState;
|
|
39
|
+
/**
|
|
40
|
+
* The declared questions.
|
|
41
|
+
*/
|
|
42
|
+
readonly questions: Q;
|
|
43
|
+
/**
|
|
44
|
+
* Observability grouping id.
|
|
45
|
+
*/
|
|
46
|
+
readonly sessionId?: Maybe<OpenRouterDecisionSessionId>;
|
|
47
|
+
/**
|
|
48
|
+
* Trace metadata, carried exactly as it is on a completion request.
|
|
49
|
+
*/
|
|
50
|
+
readonly trace?: Maybe<OpenRouterRequestTrace>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Params for {@link openRouterDecisionRequest}.
|
|
54
|
+
*/
|
|
55
|
+
export interface OpenRouterDecisionRequestParams<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions> {
|
|
56
|
+
/**
|
|
57
|
+
* The resolved prompt version supplying the base config and any STORED questions.
|
|
58
|
+
*/
|
|
59
|
+
readonly prompt?: Maybe<OpenRouterResolvedPrompt>;
|
|
60
|
+
/**
|
|
61
|
+
* The content to judge.
|
|
62
|
+
*/
|
|
63
|
+
readonly state: OpenRouterDecisionState;
|
|
64
|
+
/**
|
|
65
|
+
* Questions declared by the caller for THIS call, merged over the prompt's stored questions by id.
|
|
66
|
+
*
|
|
67
|
+
* Dynamic questions are the normal case for a decision whose answer space is derived from data the
|
|
68
|
+
* caller holds — a shortlist of rows, a set of candidates — which cannot be written down in advance.
|
|
69
|
+
*/
|
|
70
|
+
readonly questions?: Maybe<Q>;
|
|
71
|
+
/**
|
|
72
|
+
* Per-call config overrides, applied on top of the prompt's config.
|
|
73
|
+
*/
|
|
74
|
+
readonly overrides?: Maybe<OpenRouterModelConfig>;
|
|
75
|
+
/**
|
|
76
|
+
* Observability grouping id.
|
|
77
|
+
*/
|
|
78
|
+
readonly sessionId?: Maybe<OpenRouterDecisionSessionId>;
|
|
79
|
+
/**
|
|
80
|
+
* Trace metadata.
|
|
81
|
+
*/
|
|
82
|
+
readonly trace?: Maybe<OpenRouterRequestTrace>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Raised when a decision cannot be asked as declared.
|
|
86
|
+
*
|
|
87
|
+
* Every declaration problem fails HERE — before a request is built, naming the question — rather than as
|
|
88
|
+
* a 4xx about a request body. The distinction matters because the fixes are different: a malformed
|
|
89
|
+
* declaration is a code or authoring bug, while a 4xx is an operational one.
|
|
90
|
+
*/
|
|
91
|
+
export declare class OpenRouterDecisionDeclarationError extends Error {
|
|
92
|
+
readonly errors: string[];
|
|
93
|
+
constructor(errors: string[]);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Builds a decision request from an optional resolved prompt plus the caller's state and questions.
|
|
97
|
+
*
|
|
98
|
+
* Stored questions and caller questions are merged BY ID with the caller winning, the same composition
|
|
99
|
+
* a prompt's static seed messages and dynamic `input` already use. What differs is the reason: there is
|
|
100
|
+
* no prompt cache on this route, so the merge is about where a question is authored — a fixed taxonomy
|
|
101
|
+
* belongs in a version an operator can edit, a per-call candidate set can only come from code.
|
|
102
|
+
*
|
|
103
|
+
* @param params - The prompt, state, questions, overrides, session id, and trace.
|
|
104
|
+
* @returns The built request.
|
|
105
|
+
* @throws {OpenRouterDecisionDeclarationError} When the merged question map cannot be asked.
|
|
106
|
+
*/
|
|
107
|
+
export declare function openRouterDecisionRequest<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions>(params: OpenRouterDecisionRequestParams<Q>): OpenRouterDecisionRequest<Q>;
|
|
108
|
+
/**
|
|
109
|
+
* The parts of an {@link OpenRouterModelConfig} that reach a decisions request, and the parts that
|
|
110
|
+
* cannot.
|
|
111
|
+
*/
|
|
112
|
+
export interface OpenRouterSplitDecisionModelConfig {
|
|
113
|
+
/**
|
|
114
|
+
* The parameters the decisions route accepts.
|
|
115
|
+
*/
|
|
116
|
+
readonly requestConfig: Pick<OpenRouterModelConfig, 'model' | 'provider' | 'user'>;
|
|
117
|
+
/**
|
|
118
|
+
* Per-request wall-clock timeout, when the config set one.
|
|
119
|
+
*/
|
|
120
|
+
readonly requestTimeoutMs?: Maybe<number>;
|
|
121
|
+
/**
|
|
122
|
+
* Names of the config keys the decisions route has no equivalent for, in the order declared.
|
|
123
|
+
*/
|
|
124
|
+
readonly dropped: string[];
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Splits a model config into the parameters a decisions request accepts and the ones it does not.
|
|
128
|
+
*
|
|
129
|
+
* The decisions route takes only `model`, `provider` and `user`. Everything else on
|
|
130
|
+
* {@link OpenRouterModelConfig} describes a completion — an output format, a reasoning budget, a tool
|
|
131
|
+
* set, a temperature — and none of it has a meaning here: a decision has no free-form output to shape
|
|
132
|
+
* and no tools to call. Those keys are reported in `dropped` rather than quietly discarded, because a
|
|
133
|
+
* `temperature` a caller believes is in effect is exactly the kind of thing that is only noticed when
|
|
134
|
+
* an answer is already wrong.
|
|
135
|
+
*
|
|
136
|
+
* `models` (the fallback chain) is dropped for a sharper reason: the decisions route takes a single
|
|
137
|
+
* `model`, so a chain authored here does not degrade to its first entry — it simply does not exist.
|
|
138
|
+
*
|
|
139
|
+
* @param config - The merged model config.
|
|
140
|
+
* @returns The split config.
|
|
141
|
+
*/
|
|
142
|
+
export declare function splitOpenRouterDecisionModelConfig(config: Maybe<OpenRouterModelConfig>): OpenRouterSplitDecisionModelConfig;
|
|
143
|
+
/**
|
|
144
|
+
* Validates a decision request before it is sent.
|
|
145
|
+
*
|
|
146
|
+
* The mirror of `validateOpenRouterModelConfig` for this arm, and the reason both exist: the model slug
|
|
147
|
+
* is the ONLY thing that says which of OpenRouter's two inference surfaces a request belongs to, so it
|
|
148
|
+
* is checked on both, and neither arm can be entered with a model the other one owns.
|
|
149
|
+
*
|
|
150
|
+
* @param request - The request to check.
|
|
151
|
+
* @returns The validation result.
|
|
152
|
+
*/
|
|
153
|
+
export declare function validateOpenRouterDecisionRequest(request: Maybe<OpenRouterDecisionRequest>): OpenRouterModelConfigValidation;
|
|
154
|
+
/**
|
|
155
|
+
* One declared question in the shape the wire carries it.
|
|
156
|
+
*
|
|
157
|
+
* All three primitives collapse onto a single `criteria` key, which is why this mapping exists at all:
|
|
158
|
+
* the declaration types name what each primitive's criteria MEAN (`options`, `levels`, `means`), and the
|
|
159
|
+
* wire does not.
|
|
160
|
+
*/
|
|
161
|
+
export type OpenRouterDecisionWireQuestion = {
|
|
162
|
+
readonly type: 'choice';
|
|
163
|
+
readonly instructions: OpenRouterDecisionEntry;
|
|
164
|
+
readonly criteria: Readonly<Record<string, Maybe<OpenRouterDecisionEntry>>>;
|
|
165
|
+
} | {
|
|
166
|
+
readonly type: 'score';
|
|
167
|
+
readonly instructions: OpenRouterDecisionEntry;
|
|
168
|
+
readonly criteria: readonly OpenRouterDecisionEntry[];
|
|
169
|
+
} | {
|
|
170
|
+
readonly type: 'noul';
|
|
171
|
+
readonly instructions: OpenRouterDecisionEntry;
|
|
172
|
+
readonly criteria?: {
|
|
173
|
+
readonly true: OpenRouterDecisionEntry;
|
|
174
|
+
readonly false: OpenRouterDecisionEntry;
|
|
175
|
+
};
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Converts one declared question to its wire shape.
|
|
179
|
+
*
|
|
180
|
+
* A pure rename. Three details carry meaning and are not incidental:
|
|
181
|
+
*
|
|
182
|
+
* - an option with no description becomes an explicit `null`, which is how the wire spells "undescribed
|
|
183
|
+
* option" — omitting the key would instead remove the option from the answer space;
|
|
184
|
+
* - a Noul with no `means` omits `criteria` ENTIRELY rather than sending an empty object;
|
|
185
|
+
* - a structured entry is passed through by IDENTITY, never copied or re-serialized, because the wire
|
|
186
|
+
* carries declaration guidance verbatim and a normalising round-trip is exactly the kind of silent
|
|
187
|
+
* edit this mapping must not make.
|
|
188
|
+
*
|
|
189
|
+
* @param question - The declared question.
|
|
190
|
+
* @returns The wire question.
|
|
191
|
+
*/
|
|
192
|
+
export declare function openRouterDecisionWireQuestion(question: OpenRouterDecisionQuestion): OpenRouterDecisionWireQuestion;
|
|
193
|
+
/**
|
|
194
|
+
* Converts a built request into the `/systemone` request body.
|
|
195
|
+
*
|
|
196
|
+
* @param request - The built request.
|
|
197
|
+
* @returns The request body, in the SDK's request surface.
|
|
198
|
+
*/
|
|
199
|
+
export declare function openRouterDecisionRequestBody(request: OpenRouterDecisionRequest): DecisionsRequest;
|
|
200
|
+
/**
|
|
201
|
+
* What is wrong with one answer in a reply.
|
|
202
|
+
*/
|
|
203
|
+
export type OpenRouterDecisionFaultKind = 'answer-missing' | 'answer-mistyped' | 'choice-off-option' | 'value-out-of-range';
|
|
204
|
+
/**
|
|
205
|
+
* One thing wrong with a reply.
|
|
206
|
+
*/
|
|
207
|
+
export interface OpenRouterDecisionFault {
|
|
208
|
+
readonly kind: OpenRouterDecisionFaultKind;
|
|
209
|
+
readonly question: OpenRouterDecisionQuestionId;
|
|
210
|
+
readonly detail: string;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Raised when a reply did not answer the questions that were declared.
|
|
214
|
+
*
|
|
215
|
+
* This is always a defect in the RESPONSE and never a judgement the model made. "None of these fits" is
|
|
216
|
+
* not a fault — it is said through a Noul the caller declared for it, and arrives as an ANSWER. A caller
|
|
217
|
+
* that catches this is handling a malformed reply, not a negative one.
|
|
218
|
+
*/
|
|
219
|
+
export declare class OpenRouterDecisionAnswerFaultError extends Error {
|
|
220
|
+
readonly faults: OpenRouterDecisionFault[];
|
|
221
|
+
constructor(faults: OpenRouterDecisionFault[]);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Config for {@link readOpenRouterDecisionAnswers}.
|
|
225
|
+
*/
|
|
226
|
+
export interface ReadOpenRouterDecisionAnswersConfig<Q extends OpenRouterDecisionQuestions> {
|
|
227
|
+
/**
|
|
228
|
+
* The questions that were declared.
|
|
229
|
+
*/
|
|
230
|
+
readonly questions: Q;
|
|
231
|
+
/**
|
|
232
|
+
* The answers as returned.
|
|
233
|
+
*/
|
|
234
|
+
readonly raw: Readonly<Record<string, Maybe<OpenRouterDecisionAnswer>>>;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Either the answers, or everything wrong with them.
|
|
238
|
+
*/
|
|
239
|
+
export type OpenRouterDecisionAnswersRead<Q extends OpenRouterDecisionQuestions> = {
|
|
240
|
+
readonly answers: OpenRouterDecisionAnswers<Q>;
|
|
241
|
+
readonly faults?: undefined;
|
|
242
|
+
} | {
|
|
243
|
+
readonly answers?: undefined;
|
|
244
|
+
readonly faults: OpenRouterDecisionFault[];
|
|
245
|
+
};
|
|
246
|
+
/**
|
|
247
|
+
* Membership-checks a reply against the questions that were declared.
|
|
248
|
+
*
|
|
249
|
+
* This is the transport's GUARANTEE, and the reason no consumer re-checks: past this point a `choice` is
|
|
250
|
+
* one of the declared options, a `score` is inside the declared range, and a `noul` is a probability. It
|
|
251
|
+
* is what a decision has instead of the parse-and-salvage a completion needs — the answer space was
|
|
252
|
+
* declared, so an answer either sits inside it or the reply is broken.
|
|
253
|
+
*
|
|
254
|
+
* Every fault is collected rather than the first, because a reply that lost one answer has usually lost
|
|
255
|
+
* more than one and reporting them one round-trip at a time is no way to debug a declaration.
|
|
256
|
+
*
|
|
257
|
+
* An ABSENT distribution or confidence is checked for nothing: only `choice` / `score` / `noul` are
|
|
258
|
+
* guaranteed on the wire, so their absence is a real reply.
|
|
259
|
+
*
|
|
260
|
+
* @param config - The declared questions and the raw answers.
|
|
261
|
+
* @returns The answers, or the faults.
|
|
262
|
+
*/
|
|
263
|
+
export declare function readOpenRouterDecisionAnswers<Q extends OpenRouterDecisionQuestions>(config: ReadOpenRouterDecisionAnswersConfig<Q>): OpenRouterDecisionAnswersRead<Q>;
|
|
264
|
+
/**
|
|
265
|
+
* Flattens a decisions reply's usage into the package's usage shape.
|
|
266
|
+
*
|
|
267
|
+
* Reported through the SAME {@link OpenRouterRunUsage} a completion reports, so the cost ledger needs no
|
|
268
|
+
* second counting site and a run's spend is readable without knowing which arm served it.
|
|
269
|
+
*
|
|
270
|
+
* Two things about this route's numbers, both measured rather than assumed:
|
|
271
|
+
*
|
|
272
|
+
* - `outputTokens` is REPORTED and non-zero, but it is not billed. `cost` is input alone at the model's
|
|
273
|
+
* input rate — verified live at 350 input tokens and $0.042/Mtok giving exactly $0.0000147, with 34
|
|
274
|
+
* output tokens on the same reply. So a cost-per-token derived from `totalTokens` here is wrong.
|
|
275
|
+
* - `cost` is FINAL when it arrives. A completion's is settled server-side afterwards and refined by the
|
|
276
|
+
* broadcast webhook; a decision's is synchronous, which is why a decision run needs no reconciliation.
|
|
277
|
+
*
|
|
278
|
+
* A measurement the reply did not report is OMITTED rather than carried as `undefined`, because a spread
|
|
279
|
+
* `cost: undefined` reads downstream as "cost zero" rather than "cost unknown".
|
|
280
|
+
*
|
|
281
|
+
* @param usage - The usage as returned.
|
|
282
|
+
* @returns The flattened usage.
|
|
283
|
+
*
|
|
284
|
+
* @__NO_SIDE_EFFECTS__
|
|
285
|
+
*/
|
|
286
|
+
export declare function openRouterRunUsageFromDecisionsUsage(usage: Maybe<DecisionsResponse['usage']>): Maybe<OpenRouterRunUsage>;
|
|
287
|
+
/**
|
|
288
|
+
* A normalized result of one decision.
|
|
289
|
+
*
|
|
290
|
+
* Field names deliberately match `OpenRouterCallResult` wherever the two have the same meaning, so a
|
|
291
|
+
* caller reading `model` / `generationIds` / `usage` does not have to learn a second vocabulary for the
|
|
292
|
+
* second arm. There is no `outputText` or `error`: a decision has no prose output, and the route reports
|
|
293
|
+
* a failure as a thrown transport error rather than as a field on a 200.
|
|
294
|
+
*/
|
|
295
|
+
export interface OpenRouterDecisionResult<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions> {
|
|
296
|
+
/**
|
|
297
|
+
* The answers, membership-checked against the declared questions.
|
|
298
|
+
*/
|
|
299
|
+
readonly answers: OpenRouterDecisionAnswers<Q>;
|
|
300
|
+
/**
|
|
301
|
+
* The model that actually served the decision — a VERSIONED slug even when an alias was asked for,
|
|
302
|
+
* which is what makes an answer reproducible.
|
|
303
|
+
*/
|
|
304
|
+
readonly model?: Maybe<OpenRouterModelId>;
|
|
305
|
+
/**
|
|
306
|
+
* The provider that served it.
|
|
307
|
+
*/
|
|
308
|
+
readonly provider?: Maybe<string>;
|
|
309
|
+
/**
|
|
310
|
+
* Generation ids produced, for auditing. At most one on this route.
|
|
311
|
+
*/
|
|
312
|
+
readonly generationIds: OpenRouterGenerationId[];
|
|
313
|
+
/**
|
|
314
|
+
* Token/cost usage.
|
|
315
|
+
*/
|
|
316
|
+
readonly usage?: Maybe<OpenRouterRunUsage>;
|
|
317
|
+
/**
|
|
318
|
+
* The raw response, for anything the normalized shape drops.
|
|
319
|
+
*/
|
|
320
|
+
readonly response: DecisionsResponse;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Params for {@link openRouterDecision}.
|
|
324
|
+
*/
|
|
325
|
+
export interface OpenRouterDecisionParams<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions> {
|
|
326
|
+
/**
|
|
327
|
+
* The OpenRouter client.
|
|
328
|
+
*/
|
|
329
|
+
readonly client: OpenRouterCore;
|
|
330
|
+
/**
|
|
331
|
+
* The built request.
|
|
332
|
+
*/
|
|
333
|
+
readonly request: OpenRouterDecisionRequest<Q>;
|
|
334
|
+
/**
|
|
335
|
+
* Additional request options, merged under the config's `requestTimeoutMs`.
|
|
336
|
+
*/
|
|
337
|
+
readonly options?: Maybe<RequestOptions>;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Asks a decision and returns its answers.
|
|
341
|
+
*
|
|
342
|
+
* The request is validated first, so a model that cannot serve a decision is refused HERE rather than by
|
|
343
|
+
* the route — the mirror of the refusal `callModelForOpenRouterRequest` makes for a System One model on
|
|
344
|
+
* the completion arm. Which surface a request belongs to is a property of the request, not a choice the
|
|
345
|
+
* caller makes at the call site.
|
|
346
|
+
*
|
|
347
|
+
* @param params - The client, request, and options.
|
|
348
|
+
* @returns The normalized decision result.
|
|
349
|
+
* @throws {OpenRouterDecisionDeclarationError} When the request cannot be asked as declared.
|
|
350
|
+
* @throws {OpenRouterDecisionAnswerFaultError} When the reply did not answer the declared questions.
|
|
351
|
+
*/
|
|
352
|
+
export declare function openRouterDecision<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions>(params: OpenRouterDecisionParams<Q>): Promise<OpenRouterDecisionResult<Q>>;
|