@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,399 @@
|
|
|
1
|
+
import { type Maybe } from '@dereekb/util';
|
|
2
|
+
import { type OpenRouterModelConfigValidation } from './openrouter.config';
|
|
3
|
+
/**
|
|
4
|
+
* Identifier a caller gives one question inside a decision.
|
|
5
|
+
*
|
|
6
|
+
* The id is NEVER sent to the model — it is only how the caller addresses the matching answer — so a
|
|
7
|
+
* self-explanatory key is no substitute for writing the complete question in `instructions`.
|
|
8
|
+
*/
|
|
9
|
+
export type OpenRouterDecisionQuestionId = string;
|
|
10
|
+
/**
|
|
11
|
+
* Discriminator of the three System One question primitives.
|
|
12
|
+
*/
|
|
13
|
+
export type OpenRouterDecisionQuestionType = 'choice' | 'score' | 'noul';
|
|
14
|
+
/**
|
|
15
|
+
* One piece of declaration guidance: a question's `instructions`, a Choice option, a Score level, or a
|
|
16
|
+
* side of a Noul.
|
|
17
|
+
*
|
|
18
|
+
* Every declaration surface accepts a string, an object, or an array, and the wire carries whichever was
|
|
19
|
+
* supplied VERBATIM. Start with strings — a short unambiguous criterion stays one. Structure is for
|
|
20
|
+
* guidance prose would blur, and for data that is already JSON (a taxonomy branch, a database row):
|
|
21
|
+
* serializing a row into a sentence so the model can read it back out is work the model does not need.
|
|
22
|
+
*/
|
|
23
|
+
export type OpenRouterDecisionEntry = string | Readonly<Record<string, unknown>> | ReadonlyArray<unknown>;
|
|
24
|
+
/**
|
|
25
|
+
* Structured `instructions`, for a question with several parts.
|
|
26
|
+
*
|
|
27
|
+
* `inspect` and `compare` name parts of the state, in the same backticked dot-path convention prose
|
|
28
|
+
* instructions use.
|
|
29
|
+
*
|
|
30
|
+
* A `type` alias, not an `interface`, and deliberately so for all three structured shapes: an interface
|
|
31
|
+
* has no implicit index signature, so a value typed as one is NOT assignable to the
|
|
32
|
+
* `Readonly<Record<string, unknown>>` arm of {@link OpenRouterDecisionEntry} — a structured entry
|
|
33
|
+
* declared through its own name would then be refused by the very builders it exists to feed.
|
|
34
|
+
*/
|
|
35
|
+
export type OpenRouterDecisionStructuredInstructions = {
|
|
36
|
+
readonly question: string;
|
|
37
|
+
readonly focus?: Maybe<string>;
|
|
38
|
+
readonly inspect?: Maybe<string | ReadonlyArray<string>>;
|
|
39
|
+
readonly compare?: Maybe<ReadonlyArray<string>>;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* A structured Choice option.
|
|
43
|
+
*
|
|
44
|
+
* CONTRASTIVE by design: use the SAME keys on every option of a question so the model compares like
|
|
45
|
+
* with like. `not_for` is where an option's boundary against its neighbours goes.
|
|
46
|
+
*/
|
|
47
|
+
export type OpenRouterDecisionStructuredCriterion = {
|
|
48
|
+
readonly what: string;
|
|
49
|
+
readonly not_for?: Maybe<string>;
|
|
50
|
+
readonly examples?: Maybe<ReadonlyArray<string>>;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* A structured Score level.
|
|
54
|
+
*
|
|
55
|
+
* `what` is a SITUATION, not a degree — "broken or degraded feature, but a workaround exists" gives the
|
|
56
|
+
* model something to match the state against, where "moderately severe" does not. Use the same keys on
|
|
57
|
+
* every level of a question.
|
|
58
|
+
*/
|
|
59
|
+
export type OpenRouterDecisionStructuredLevel = {
|
|
60
|
+
readonly what: string;
|
|
61
|
+
readonly signals?: Maybe<ReadonlyArray<string>>;
|
|
62
|
+
readonly examples?: Maybe<ReadonlyArray<string>>;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* The declared options of a Choice, keyed by the option name the answer will quote.
|
|
66
|
+
*
|
|
67
|
+
* A `null` / absent description declares an UNDESCRIBED option, which is the right thing when the state
|
|
68
|
+
* already carries the option's own text.
|
|
69
|
+
*/
|
|
70
|
+
export type OpenRouterDecisionChoiceOptions<O extends string = string> = Readonly<Record<O, Maybe<OpenRouterDecisionEntry>>>;
|
|
71
|
+
/**
|
|
72
|
+
* The two sides of a Noul, for a condition whose boundary is worth stating explicitly.
|
|
73
|
+
*
|
|
74
|
+
* Both sides or neither — a one-sided definition is not expressible, because a `true` with no matching
|
|
75
|
+
* `false` measurably degrades the answer.
|
|
76
|
+
*/
|
|
77
|
+
export interface OpenRouterDecisionNoulMeans {
|
|
78
|
+
readonly true: OpenRouterDecisionEntry;
|
|
79
|
+
readonly false: OpenRouterDecisionEntry;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* "Which of these options?"
|
|
83
|
+
*
|
|
84
|
+
* A Choice is only ever RELATIVE: the probabilities are normalised over the options supplied, so
|
|
85
|
+
* something always wins even when nothing fits. When "nothing fits" is an outcome the caller acts on, a
|
|
86
|
+
* Noul rides beside the Choice — it is absolute, and may be low for every option.
|
|
87
|
+
*/
|
|
88
|
+
export interface OpenRouterDecisionChoiceQuestion<O extends string = string> {
|
|
89
|
+
readonly type: 'choice';
|
|
90
|
+
readonly instructions: OpenRouterDecisionEntry;
|
|
91
|
+
readonly options: OpenRouterDecisionChoiceOptions<O>;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The levels of a Score, lowest to highest, as accepted by {@link openRouterScoreQuestion}.
|
|
95
|
+
*
|
|
96
|
+
* A tuple rather than an array so the two-level minimum is a COMPILE error for a question written in
|
|
97
|
+
* code. The question interface itself holds a plain array, because a question read back out of storage
|
|
98
|
+
* is one.
|
|
99
|
+
*/
|
|
100
|
+
export type OpenRouterDecisionScoreLevels = readonly [OpenRouterDecisionEntry, OpenRouterDecisionEntry, ...OpenRouterDecisionEntry[]];
|
|
101
|
+
/**
|
|
102
|
+
* "Which level on this rubric?"
|
|
103
|
+
*
|
|
104
|
+
* The answer may land BETWEEN two levels, so cross a THRESHOLD with a score and never try to recover a
|
|
105
|
+
* magnitude from one. Every level is evaluated separately and the model never sees a level's number or
|
|
106
|
+
* its neighbours, which is why numbers in the level descriptions do not help and situations do.
|
|
107
|
+
*/
|
|
108
|
+
export interface OpenRouterDecisionScoreQuestion {
|
|
109
|
+
readonly type: 'score';
|
|
110
|
+
readonly instructions: OpenRouterDecisionEntry;
|
|
111
|
+
readonly levels: ReadonlyArray<OpenRouterDecisionEntry>;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* "Is this true?"
|
|
115
|
+
*
|
|
116
|
+
* The returned probability IS the uncertainty, so a Noul carries no separate confidence. Define the
|
|
117
|
+
* CONDITION: "states they used Python at work" is a Noul, while "strong in Python" is a Score.
|
|
118
|
+
*/
|
|
119
|
+
export interface OpenRouterDecisionNoulQuestion {
|
|
120
|
+
readonly type: 'noul';
|
|
121
|
+
readonly instructions: OpenRouterDecisionEntry;
|
|
122
|
+
readonly means?: Maybe<OpenRouterDecisionNoulMeans>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Any one declared question.
|
|
126
|
+
*/
|
|
127
|
+
export type OpenRouterDecisionQuestion<O extends string = string> = OpenRouterDecisionChoiceQuestion<O> | OpenRouterDecisionScoreQuestion | OpenRouterDecisionNoulQuestion;
|
|
128
|
+
/**
|
|
129
|
+
* The questions one decision declares, keyed by {@link OpenRouterDecisionQuestionId}.
|
|
130
|
+
*
|
|
131
|
+
* Declare every question one state could need in ONE call: each is evaluated independently against the
|
|
132
|
+
* same state, so the map is both the batching unit and the cost unit. The state is sent (and billed)
|
|
133
|
+
* once, and a speculative question the caller may discard costs only its own tokens.
|
|
134
|
+
*/
|
|
135
|
+
export type OpenRouterDecisionQuestions = Readonly<Record<OpenRouterDecisionQuestionId, OpenRouterDecisionQuestion>>;
|
|
136
|
+
/**
|
|
137
|
+
* The content to judge.
|
|
138
|
+
*
|
|
139
|
+
* Prefer an object so each part has a NAME a question can point at. Filtering belongs in code first:
|
|
140
|
+
* accuracy falls as a state grows with material unrelated to the decision, so a wide state is not a
|
|
141
|
+
* free hedge.
|
|
142
|
+
*/
|
|
143
|
+
export type OpenRouterDecisionState = string | Readonly<Record<string, unknown>> | ReadonlyArray<unknown>;
|
|
144
|
+
/**
|
|
145
|
+
* A decision state in the form durable storage can hold: an object or an array, never a bare string.
|
|
146
|
+
*
|
|
147
|
+
* The narrowing is not a storage workaround dressed up as doctrine — it IS the doctrine. A state should
|
|
148
|
+
* be an object anyway, so each part has a name a question can point at with the backticked dot-path
|
|
149
|
+
* convention; a bare string leaves every question describing the state again in prose. A caller whose
|
|
150
|
+
* state really is one value names it (`{ phrase: '…' }`) and gets a question that can say `` `phrase` ``.
|
|
151
|
+
*
|
|
152
|
+
* (It also happens to be what a JSON-string Firestore field can carry, which is why the queued arm of
|
|
153
|
+
* the execution system takes this rather than {@link OpenRouterDecisionState}.)
|
|
154
|
+
*/
|
|
155
|
+
export type OpenRouterStorableDecisionState = Exclude<OpenRouterDecisionState, string>;
|
|
156
|
+
/**
|
|
157
|
+
* The answer to a Choice.
|
|
158
|
+
*
|
|
159
|
+
* `choice` is GUARANTEED to be one of the declared options — that is the transport's contract, checked
|
|
160
|
+
* by `readOpenRouterDecisionAnswers` — and `probabilities` covers every declared option, summing to 1.
|
|
161
|
+
* Both `probabilities` and `confidence` are optional: an absent one is a real reply, not a fault.
|
|
162
|
+
*/
|
|
163
|
+
export interface OpenRouterDecisionChoiceAnswer<O extends string = string> {
|
|
164
|
+
readonly type: 'choice';
|
|
165
|
+
readonly choice: O;
|
|
166
|
+
readonly probabilities?: Maybe<Readonly<Record<O, number>>>;
|
|
167
|
+
readonly confidence?: Maybe<number>;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* The answer to a Score.
|
|
171
|
+
*
|
|
172
|
+
* `legend` echoes the declared levels back, keyed by their index as a string.
|
|
173
|
+
*/
|
|
174
|
+
export interface OpenRouterDecisionScoreAnswer {
|
|
175
|
+
readonly type: 'score';
|
|
176
|
+
readonly score: number;
|
|
177
|
+
readonly legend?: Maybe<Readonly<Record<string, OpenRouterDecisionEntry>>>;
|
|
178
|
+
readonly probabilities?: Maybe<Readonly<Record<string, number>>>;
|
|
179
|
+
readonly confidence?: Maybe<number>;
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* The answer to a Noul: the probability the condition holds, 0..1.
|
|
183
|
+
*/
|
|
184
|
+
export interface OpenRouterDecisionNoulAnswer {
|
|
185
|
+
readonly type: 'noul';
|
|
186
|
+
readonly noul: number;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Any one answer.
|
|
190
|
+
*/
|
|
191
|
+
export type OpenRouterDecisionAnswer<O extends string = string> = OpenRouterDecisionChoiceAnswer<O> | OpenRouterDecisionScoreAnswer | OpenRouterDecisionNoulAnswer;
|
|
192
|
+
/**
|
|
193
|
+
* The answer type a given declared question produces.
|
|
194
|
+
*/
|
|
195
|
+
export type OpenRouterDecisionAnswerFor<Q extends OpenRouterDecisionQuestion> = Q extends OpenRouterDecisionNoulQuestion ? OpenRouterDecisionNoulAnswer : Q extends OpenRouterDecisionScoreQuestion ? OpenRouterDecisionScoreAnswer : Q extends OpenRouterDecisionChoiceQuestion<infer O> ? OpenRouterDecisionChoiceAnswer<O> : never;
|
|
196
|
+
/**
|
|
197
|
+
* The answers a declared question map produces.
|
|
198
|
+
*
|
|
199
|
+
* DERIVED from the questions rather than declared beside them, so a caller reads `answers.urgency.score`
|
|
200
|
+
* with no cast and a renamed question is a compile error at every reader.
|
|
201
|
+
*/
|
|
202
|
+
export type OpenRouterDecisionAnswers<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions> = {
|
|
203
|
+
readonly [K in keyof Q]: OpenRouterDecisionAnswerFor<Q[K]>;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* A coarse reading of a Choice or Score `confidence`.
|
|
207
|
+
*/
|
|
208
|
+
export type OpenRouterDecisionConfidenceBand = 'high' | 'medium' | 'low';
|
|
209
|
+
/**
|
|
210
|
+
* Confidence at or above which {@link asOpenRouterDecisionConfidenceBand} reads `high`.
|
|
211
|
+
*
|
|
212
|
+
* A documented STARTING POINT, not a tuned threshold. Note also that a Noul probability and a Choice
|
|
213
|
+
* confidence answer different questions and are not comparable, so a threshold calibrated for one may
|
|
214
|
+
* not be carried over to the other.
|
|
215
|
+
*/
|
|
216
|
+
export declare const OPENROUTER_DECISION_CONFIDENCE_HIGH = 0.75;
|
|
217
|
+
/**
|
|
218
|
+
* Confidence at or above which {@link asOpenRouterDecisionConfidenceBand} reads `medium`.
|
|
219
|
+
*
|
|
220
|
+
* See the note on {@link OPENROUTER_DECISION_CONFIDENCE_HIGH}.
|
|
221
|
+
*/
|
|
222
|
+
export declare const OPENROUTER_DECISION_CONFIDENCE_MEDIUM = 0.5;
|
|
223
|
+
/**
|
|
224
|
+
* Most options a single Choice may declare.
|
|
225
|
+
*
|
|
226
|
+
* A hard transport limit, not a guideline. Past it, narrow in two stages — ask a first Choice that picks
|
|
227
|
+
* the branch, then a second over that branch's members — rather than truncating the set, because an
|
|
228
|
+
* option that was truncated away is one the model can never pick and nothing reports that it was missing.
|
|
229
|
+
*/
|
|
230
|
+
export declare const OPENROUTER_DECISION_CHOICE_OPTIONS_MAX = 255;
|
|
231
|
+
/**
|
|
232
|
+
* Fewest levels a Score may declare.
|
|
233
|
+
*/
|
|
234
|
+
export declare const OPENROUTER_DECISION_SCORE_LEVELS_MIN = 2;
|
|
235
|
+
/**
|
|
236
|
+
* Most levels a Score may declare.
|
|
237
|
+
*
|
|
238
|
+
* The trap this guards: a 0..8 band is NINE levels and legal, while a 0..10 scale is eleven and is
|
|
239
|
+
* rejected at the wire. Past the ceiling, MERGE the levels that cannot be told apart — never truncate
|
|
240
|
+
* the top, which silently removes the extreme the threshold usually cares about.
|
|
241
|
+
*/
|
|
242
|
+
export declare const OPENROUTER_DECISION_SCORE_LEVELS_MAX = 10;
|
|
243
|
+
/**
|
|
244
|
+
* Whether a declaration entry says nothing at all.
|
|
245
|
+
*
|
|
246
|
+
* A blank string, an empty array, and a keyless object all ask nothing, and all three reach the wire as
|
|
247
|
+
* a question the model cannot answer.
|
|
248
|
+
*
|
|
249
|
+
* @param entry - The entry to test.
|
|
250
|
+
* @returns True when the entry carries no guidance.
|
|
251
|
+
*
|
|
252
|
+
* @__NO_SIDE_EFFECTS__
|
|
253
|
+
*/
|
|
254
|
+
export declare function isBlankOpenRouterDecisionEntry(entry: Maybe<OpenRouterDecisionEntry>): boolean;
|
|
255
|
+
/**
|
|
256
|
+
* The option names a Choice declared — what the model was SHOWN.
|
|
257
|
+
*
|
|
258
|
+
* @param question - The choice question.
|
|
259
|
+
* @returns The declared option names, in declaration order.
|
|
260
|
+
*
|
|
261
|
+
* @__NO_SIDE_EFFECTS__
|
|
262
|
+
*/
|
|
263
|
+
export declare function openRouterDecisionChoiceOptionNames<O extends string = string>(question: OpenRouterDecisionChoiceQuestion<O>): O[];
|
|
264
|
+
/**
|
|
265
|
+
* Reads a confidence as a band.
|
|
266
|
+
*
|
|
267
|
+
* An ABSENT confidence reads `low` rather than throwing: the model is not required to report one, and a
|
|
268
|
+
* caller that branches on the band should treat "did not say" the same as "not sure". A non-finite one
|
|
269
|
+
* (`NaN`, `Infinity`) reads `low` for the same reason — a garbled number is not a report of certainty,
|
|
270
|
+
* and without the guard `NaN` fails every comparison below and falls through to `medium`.
|
|
271
|
+
*
|
|
272
|
+
* @param confidence - The reported confidence, if any.
|
|
273
|
+
* @returns The band.
|
|
274
|
+
*
|
|
275
|
+
* @__NO_SIDE_EFFECTS__
|
|
276
|
+
*/
|
|
277
|
+
export declare function asOpenRouterDecisionConfidenceBand(confidence: Maybe<number>): OpenRouterDecisionConfidenceBand;
|
|
278
|
+
/**
|
|
279
|
+
* One row of a Choice's distribution.
|
|
280
|
+
*/
|
|
281
|
+
export interface OpenRouterDecisionChoiceRankingRow<O extends string = string> {
|
|
282
|
+
readonly option: O;
|
|
283
|
+
readonly probability: number;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Reads a Choice's distribution as a ranking, most probable first.
|
|
287
|
+
*
|
|
288
|
+
* The distribution is a FREE full ranking — the model reports every option, not just the winner — so a
|
|
289
|
+
* caller wanting a shortlist should read this rather than paying for a second question.
|
|
290
|
+
*
|
|
291
|
+
* Returns an empty array when the answer carried no distribution, which is a real reply rather than an
|
|
292
|
+
* error. The sort is stable, so tied options keep declaration order.
|
|
293
|
+
*
|
|
294
|
+
* @param answer - The choice answer.
|
|
295
|
+
* @returns The ranking rows.
|
|
296
|
+
*
|
|
297
|
+
* @__NO_SIDE_EFFECTS__
|
|
298
|
+
*/
|
|
299
|
+
export declare function openRouterDecisionChoiceRanking<O extends string = string>(answer: OpenRouterDecisionChoiceAnswer<O>): OpenRouterDecisionChoiceRankingRow<O>[];
|
|
300
|
+
/**
|
|
301
|
+
* Config for {@link mapOpenRouterDecisionChoiceRows}.
|
|
302
|
+
*/
|
|
303
|
+
export interface MapOpenRouterDecisionChoiceRowsConfig<Q extends OpenRouterDecisionQuestions, K extends keyof Q & string, R> {
|
|
304
|
+
/**
|
|
305
|
+
* The answers the decision returned.
|
|
306
|
+
*/
|
|
307
|
+
readonly answers: OpenRouterDecisionAnswers<Q>;
|
|
308
|
+
/**
|
|
309
|
+
* Which question's distribution to read.
|
|
310
|
+
*/
|
|
311
|
+
readonly question: K;
|
|
312
|
+
/**
|
|
313
|
+
* Resolves one declared option name back to the caller's own row. Return null to drop it.
|
|
314
|
+
*/
|
|
315
|
+
readonly rowOf: (option: string) => Maybe<R>;
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* One of the caller's own rows, with the probability the model gave it.
|
|
319
|
+
*/
|
|
320
|
+
export interface OpenRouterDecisionChoiceRow<R> {
|
|
321
|
+
readonly row: R;
|
|
322
|
+
readonly probability: number;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Reads a Choice's distribution back as the caller's OWN rows, most probable first.
|
|
326
|
+
*
|
|
327
|
+
* The seam exists because a Choice's options are usually derived from rows the caller already holds, and
|
|
328
|
+
* walking the distribution back to them by hand at every call site is where the option-name convention
|
|
329
|
+
* quietly drifts.
|
|
330
|
+
*
|
|
331
|
+
* @param config - The answers, the question to read, and how to resolve an option to a row.
|
|
332
|
+
* @returns The resolved rows, most probable first. Options that resolve to nothing are dropped.
|
|
333
|
+
*/
|
|
334
|
+
export declare function mapOpenRouterDecisionChoiceRows<Q extends OpenRouterDecisionQuestions, K extends keyof Q & string, R>(config: MapOpenRouterDecisionChoiceRowsConfig<Q, K, R>): OpenRouterDecisionChoiceRow<R>[];
|
|
335
|
+
/**
|
|
336
|
+
* Reads back the state paths a declaration entry names.
|
|
337
|
+
*
|
|
338
|
+
* The convention is to name a part of the state as a dot-and-index path IN BACKTICKS — `` `phrase` ``,
|
|
339
|
+
* `` `ticket.sender.email` ``, `` `messages[0].text` `` — so a question points at something the state
|
|
340
|
+
* actually carries rather than describing it again in prose.
|
|
341
|
+
*
|
|
342
|
+
* Documented and inspectable, deliberately NOT enforced: backticks also legitimately quote an option key
|
|
343
|
+
* or a literal, so a spec may pin that a declaration points at keys its state has, while the transport
|
|
344
|
+
* never refuses one that does not.
|
|
345
|
+
*
|
|
346
|
+
* @param entry - The entry to read. Objects and arrays are walked.
|
|
347
|
+
* @returns The paths, deduplicated, in the order they first appear.
|
|
348
|
+
*/
|
|
349
|
+
export declare function openRouterDecisionStatePaths(entry: Maybe<OpenRouterDecisionEntry>): string[];
|
|
350
|
+
/**
|
|
351
|
+
* Declares a Choice question.
|
|
352
|
+
*
|
|
353
|
+
* Supply the FULL option set, plus an explicit `other` / `none of the above` when the set may not cover
|
|
354
|
+
* the input — the distribution is normalised over what was supplied, so a Choice always names a winner
|
|
355
|
+
* whether or not one fits.
|
|
356
|
+
*
|
|
357
|
+
* @param instructions - The complete question, as the model will read it.
|
|
358
|
+
* @param options - The options, keyed by the name the answer will quote.
|
|
359
|
+
* @returns The declared question.
|
|
360
|
+
*
|
|
361
|
+
* @__NO_SIDE_EFFECTS__
|
|
362
|
+
*/
|
|
363
|
+
export declare function openRouterChoiceQuestion<O extends string = string>(instructions: OpenRouterDecisionEntry, options: OpenRouterDecisionChoiceOptions<O>): OpenRouterDecisionChoiceQuestion<O>;
|
|
364
|
+
/**
|
|
365
|
+
* Declares a Score question.
|
|
366
|
+
*
|
|
367
|
+
* Use as many levels as can be described DISTINCTLY, lowest to highest — three is fine, and a rare
|
|
368
|
+
* extreme deserves its own level. One dimension per question.
|
|
369
|
+
*
|
|
370
|
+
* @param instructions - The complete question, as the model will read it.
|
|
371
|
+
* @param levels - The levels, lowest first. At least two.
|
|
372
|
+
* @returns The declared question.
|
|
373
|
+
*
|
|
374
|
+
* @__NO_SIDE_EFFECTS__
|
|
375
|
+
*/
|
|
376
|
+
export declare function openRouterScoreQuestion(instructions: OpenRouterDecisionEntry, levels: OpenRouterDecisionScoreLevels): OpenRouterDecisionScoreQuestion;
|
|
377
|
+
/**
|
|
378
|
+
* Declares a Noul question.
|
|
379
|
+
*
|
|
380
|
+
* @param instructions - The complete question, as the model will read it.
|
|
381
|
+
* @param means - Optional explicit definitions of the true and false sides.
|
|
382
|
+
* @returns The declared question.
|
|
383
|
+
*
|
|
384
|
+
* @__NO_SIDE_EFFECTS__
|
|
385
|
+
*/
|
|
386
|
+
export declare function openRouterNoulQuestion(instructions: OpenRouterDecisionEntry, means?: Maybe<OpenRouterDecisionNoulMeans>): OpenRouterDecisionNoulQuestion;
|
|
387
|
+
/**
|
|
388
|
+
* Validates a declared question map.
|
|
389
|
+
*
|
|
390
|
+
* Every problem here fails AT THE DECLARATION, naming the question, rather than as a 4xx about a request
|
|
391
|
+
* body — which is the difference between a publish that is refused and a run that dies in a sweep at 2am.
|
|
392
|
+
*
|
|
393
|
+
* Returns the package's standard validation result so a caller can report question problems and config
|
|
394
|
+
* problems through one surface.
|
|
395
|
+
*
|
|
396
|
+
* @param questions - The declared questions.
|
|
397
|
+
* @returns The validation result.
|
|
398
|
+
*/
|
|
399
|
+
export declare function validateOpenRouterDecisionQuestions(questions: Maybe<OpenRouterDecisionQuestions>): OpenRouterModelConfigValidation;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type Maybe } from '@dereekb/util';
|
|
2
2
|
import { type OpenRouterModelConfig } from './openrouter.config';
|
|
3
|
+
import { type OpenRouterDecisionQuestions } from './openrouter.decision.question';
|
|
3
4
|
import { type OpenRouterInputRole } from './openrouter.input';
|
|
4
5
|
import { type OpenRouterPromptKey, type OpenRouterPromptVersionNumber } from './openrouter.type';
|
|
5
6
|
/**
|
|
@@ -46,6 +47,18 @@ export interface OpenRouterResolvedPrompt {
|
|
|
46
47
|
* The version's model config.
|
|
47
48
|
*/
|
|
48
49
|
readonly config: OpenRouterModelConfig;
|
|
50
|
+
/**
|
|
51
|
+
* The questions this prompt declares, when it is a DECISION prompt.
|
|
52
|
+
*
|
|
53
|
+
* Present makes a prompt a decision: a version carrying questions is asked through
|
|
54
|
+
* `openRouterDecision` rather than `callModelForOpenRouterRequest`, and its config names a System One
|
|
55
|
+
* model rather than a chat one. The two are mutually exclusive by construction — a decision has no
|
|
56
|
+
* prose output for `instructions` and `messages` to shape.
|
|
57
|
+
*
|
|
58
|
+
* These are the STATIC half of a decision's answer space, the counterpart of `messages`. A caller may
|
|
59
|
+
* declare further questions per call; they merge over these by id. See `openRouterDecisionRequest`.
|
|
60
|
+
*/
|
|
61
|
+
readonly questions?: Maybe<OpenRouterDecisionQuestions>;
|
|
49
62
|
}
|
|
50
63
|
/**
|
|
51
64
|
* Which half of a prompt resolution served it: the stored version, or the code definition standing in
|
|
@@ -87,4 +100,16 @@ export interface OpenRouterPromptDefinition extends OpenRouterResolvedPrompt {
|
|
|
87
100
|
* What this prompt is for, used when this definition is published to Firestore.
|
|
88
101
|
*/
|
|
89
102
|
readonly description?: Maybe<string>;
|
|
103
|
+
/**
|
|
104
|
+
* Whether the prompt this definition creates is locked to the store from the moment it exists.
|
|
105
|
+
*
|
|
106
|
+
* Takes effect ONLY on create — it is the initial value of the prompt's own `storeLocked` flag, not a
|
|
107
|
+
* standing instruction. A definition cannot lock a prompt it did not create, because doing so would
|
|
108
|
+
* let code silently seize a prompt an operator is already maintaining.
|
|
109
|
+
*
|
|
110
|
+
* Declare it for a prompt whose content is EXPECTED to be tuned at runtime — a decision's questions
|
|
111
|
+
* being the motivating case — so a fresh environment is seeded once and then left alone, with no
|
|
112
|
+
* per-environment manual step to remember.
|
|
113
|
+
*/
|
|
114
|
+
readonly storeLocked?: Maybe<boolean>;
|
|
90
115
|
}
|
|
@@ -13,6 +13,13 @@
|
|
|
13
13
|
* (`execute: false`) plus `ConversationState.pendingToolCalls` / `unsentToolResults` already provide that
|
|
14
14
|
* mechanism. See `openrouter.tool.ts`.
|
|
15
15
|
*
|
|
16
|
+
* `systemOneCreate` is the System One (decisions) operation, and is the ONE place that route is reached.
|
|
17
|
+
* Its path is resolved under the client root (`pathToFunc('/systemone')`), so the same `serverURL` that
|
|
18
|
+
* governs `/responses` governs it — there is no second base-url concept to configure or get wrong. It
|
|
19
|
+
* requires `@openrouter/sdk@^1.3.8`: the operation does not exist below that, and the alpha route it
|
|
20
|
+
* replaced (`/api/alpha/decisions`) was a SIBLING of `/api/v1` that older SDKs resolved relative to the
|
|
21
|
+
* client's own server, producing `…/api/v1/api/alpha/decisions` and a 404 on every call.
|
|
22
|
+
*
|
|
16
23
|
* `responsesSend` / `ModelResult` / `convertToolsToAPIFormat` are what make hosted (server-executed) tools
|
|
17
24
|
* deliverable: `callModel` owns the `tools` key and converts every entry as a client function tool, so
|
|
18
25
|
* taking its transport and its tool loop directly is what lets `openrouter.call.ts` put an
|
|
@@ -22,6 +29,7 @@ export { callModel } from '@openrouter/sdk/funcs/call-model';
|
|
|
22
29
|
export { responsesSend } from '@openrouter/sdk/funcs/responsesSend';
|
|
23
30
|
export { unsentResultsToAPIFormat } from '@openrouter/sdk/lib/conversation-state';
|
|
24
31
|
export { embeddingsGenerate } from '@openrouter/sdk/funcs/embeddingsGenerate';
|
|
32
|
+
export { systemOneCreate } from '@openrouter/sdk/funcs/systemOneCreate';
|
|
25
33
|
export { generationsGetGeneration } from '@openrouter/sdk/funcs/generationsGetGeneration';
|
|
26
34
|
export { generationsListGenerationContent } from '@openrouter/sdk/funcs/generationsListGenerationContent';
|
|
27
35
|
export { ModelResult } from '@openrouter/sdk/lib/model-result';
|
|
@@ -33,5 +41,5 @@ export type { OpenRouterCore } from '@openrouter/sdk/core';
|
|
|
33
41
|
export type { CallModelInput } from '@openrouter/sdk/lib/async-params';
|
|
34
42
|
export type { RequestOptions } from '@openrouter/sdk/lib/sdks';
|
|
35
43
|
export type { ConversationState, ConversationStatus, ParsedToolCall, StateAccessor, StopWhen, Tool, UnsentToolResult } from '@openrouter/sdk/lib/tool-types';
|
|
36
|
-
export type { FunctionCallOutputItem, GenerationContentData, GenerationResponseData, InputsUnion, OpenResponsesResult, ResponsesRequest, Usage } from '@openrouter/sdk/models';
|
|
37
|
-
export type { CreateEmbeddingsRequest, CreateEmbeddingsResponseBody, CreateResponsesResponse } from '@openrouter/sdk/models/operations';
|
|
44
|
+
export type { DecisionsChoiceAnswer, DecisionsChoiceQuestion, DecisionsNoulAnswer, DecisionsNoulQuestion, DecisionsRequest, DecisionsResponse, DecisionsScoreAnswer, DecisionsScoreQuestion, FunctionCallOutputItem, GenerationContentData, GenerationResponseData, InputsUnion, OpenResponsesResult, ResponsesRequest, Usage } from '@openrouter/sdk/models';
|
|
45
|
+
export type { CreateEmbeddingsRequest, CreateEmbeddingsResponseBody, CreateResponsesResponse, CreateSystemoneRequest } from '@openrouter/sdk/models/operations';
|
|
@@ -8,6 +8,57 @@ import { type Maybe } from '@dereekb/util';
|
|
|
8
8
|
* `@dereekb/nestjs/openrouter`. They are plain string aliases, so values cross the boundary freely.
|
|
9
9
|
*/
|
|
10
10
|
export type OpenRouterModelId = string;
|
|
11
|
+
/**
|
|
12
|
+
* A model slug naming a SYSTEM ONE model — OpenRouter's second inference surface, served by
|
|
13
|
+
* `POST /systemone` rather than `/responses`.
|
|
14
|
+
*
|
|
15
|
+
* A System One model does not take messages and does not answer with prose. The caller declares the
|
|
16
|
+
* answer space up front as typed questions and the model returns a position inside it plus a calibrated
|
|
17
|
+
* distribution. See `openrouter.decision.ts`.
|
|
18
|
+
*/
|
|
19
|
+
export type OpenRouterSystemOneModelId = OpenRouterModelId;
|
|
20
|
+
/**
|
|
21
|
+
* The namespace every System One model slug lives under.
|
|
22
|
+
*/
|
|
23
|
+
export declare const OPENROUTER_SYSTEM_ONE_MODEL_NAMESPACE = "typesafe";
|
|
24
|
+
/**
|
|
25
|
+
* Jev 1.13, the System One model this package pins by default.
|
|
26
|
+
*
|
|
27
|
+
* A VERSIONED slug rather than one of the moving aliases (`jev-latest`, `jev-preview`), for the same
|
|
28
|
+
* reason {@link OpenRouterPromptVersionNumber} exists: a decision's answer is only reproducible against
|
|
29
|
+
* the exact model that produced it, and an alias silently moves out from under a stored prompt. Point a
|
|
30
|
+
* prompt at an alias deliberately, never by default.
|
|
31
|
+
*/
|
|
32
|
+
export declare const OPENROUTER_JEV_1_13_MODEL_ID: OpenRouterSystemOneModelId;
|
|
33
|
+
/**
|
|
34
|
+
* The newest STABLE Jev. A moving alias — see {@link OPENROUTER_JEV_1_13_MODEL_ID}.
|
|
35
|
+
*/
|
|
36
|
+
export declare const OPENROUTER_JEV_LATEST_MODEL_ID: OpenRouterSystemOneModelId;
|
|
37
|
+
/**
|
|
38
|
+
* The newest Jev, stable or not. A moving alias — see {@link OPENROUTER_JEV_1_13_MODEL_ID}.
|
|
39
|
+
*/
|
|
40
|
+
export declare const OPENROUTER_JEV_PREVIEW_MODEL_ID: OpenRouterSystemOneModelId;
|
|
41
|
+
/**
|
|
42
|
+
* The System One model a decision uses when its config names none.
|
|
43
|
+
*/
|
|
44
|
+
export declare const DEFAULT_OPENROUTER_SYSTEM_ONE_MODEL_ID: OpenRouterSystemOneModelId;
|
|
45
|
+
/**
|
|
46
|
+
* Whether a model slug names a System One model.
|
|
47
|
+
*
|
|
48
|
+
* This is the ONLY discriminator available, and it is the reason this function exists rather than a
|
|
49
|
+
* lookup: System One models are NOT listed by `GET /models`, so nothing can be learned about one from
|
|
50
|
+
* the catalog. A caller that guessed wrong does not get an error it can read — a Jev slug sent to
|
|
51
|
+
* `/responses` fails at the provider, and a chat slug sent to `/systemone` is refused by the route.
|
|
52
|
+
*
|
|
53
|
+
* Both forms are recognised: the namespaced slug (`typesafe/jev-1.13`) and the bare one (`jev-1.13`,
|
|
54
|
+
* `jev-latest`), which the SDK documents itself as mapping onto the `typesafe/` namespace.
|
|
55
|
+
*
|
|
56
|
+
* @param model - The model slug to test.
|
|
57
|
+
* @returns True when the slug names a System One model.
|
|
58
|
+
*
|
|
59
|
+
* @__NO_SIDE_EFFECTS__
|
|
60
|
+
*/
|
|
61
|
+
export declare function isOpenRouterSystemOneModelId(model: Maybe<OpenRouterModelId>): boolean;
|
|
11
62
|
/**
|
|
12
63
|
* A generation id returned by OpenRouter for a completed request.
|
|
13
64
|
*
|