@dereekb/openrouter 14.7.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.
@@ -0,0 +1,392 @@
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
+ export interface OpenRouterDecisionStructuredInstructions {
31
+ readonly question: string;
32
+ readonly focus?: Maybe<string>;
33
+ readonly inspect?: Maybe<string | ReadonlyArray<string>>;
34
+ readonly compare?: Maybe<ReadonlyArray<string>>;
35
+ }
36
+ /**
37
+ * A structured Choice option.
38
+ *
39
+ * CONTRASTIVE by design: use the SAME keys on every option of a question so the model compares like
40
+ * with like. `not_for` is where an option's boundary against its neighbours goes.
41
+ */
42
+ export interface OpenRouterDecisionStructuredCriterion {
43
+ readonly what: string;
44
+ readonly not_for?: Maybe<string>;
45
+ readonly examples?: Maybe<ReadonlyArray<string>>;
46
+ }
47
+ /**
48
+ * A structured Score level.
49
+ *
50
+ * `what` is a SITUATION, not a degree — "broken or degraded feature, but a workaround exists" gives the
51
+ * model something to match the state against, where "moderately severe" does not. Use the same keys on
52
+ * every level of a question.
53
+ */
54
+ export interface OpenRouterDecisionStructuredLevel {
55
+ readonly what: string;
56
+ readonly signals?: Maybe<ReadonlyArray<string>>;
57
+ readonly examples?: Maybe<ReadonlyArray<string>>;
58
+ }
59
+ /**
60
+ * The declared options of a Choice, keyed by the option name the answer will quote.
61
+ *
62
+ * A `null` / absent description declares an UNDESCRIBED option, which is the right thing when the state
63
+ * already carries the option's own text.
64
+ */
65
+ export type OpenRouterDecisionChoiceOptions<O extends string = string> = Readonly<Record<O, Maybe<OpenRouterDecisionEntry>>>;
66
+ /**
67
+ * The two sides of a Noul, for a condition whose boundary is worth stating explicitly.
68
+ *
69
+ * Both sides or neither — a one-sided definition is not expressible, because a `true` with no matching
70
+ * `false` measurably degrades the answer.
71
+ */
72
+ export interface OpenRouterDecisionNoulMeans {
73
+ readonly true: OpenRouterDecisionEntry;
74
+ readonly false: OpenRouterDecisionEntry;
75
+ }
76
+ /**
77
+ * "Which of these options?"
78
+ *
79
+ * A Choice is only ever RELATIVE: the probabilities are normalised over the options supplied, so
80
+ * something always wins even when nothing fits. When "nothing fits" is an outcome the caller acts on, a
81
+ * Noul rides beside the Choice — it is absolute, and may be low for every option.
82
+ */
83
+ export interface OpenRouterDecisionChoiceQuestion<O extends string = string> {
84
+ readonly type: 'choice';
85
+ readonly instructions: OpenRouterDecisionEntry;
86
+ readonly options: OpenRouterDecisionChoiceOptions<O>;
87
+ }
88
+ /**
89
+ * The levels of a Score, lowest to highest, as accepted by {@link openRouterScoreQuestion}.
90
+ *
91
+ * A tuple rather than an array so the two-level minimum is a COMPILE error for a question written in
92
+ * code. The question interface itself holds a plain array, because a question read back out of storage
93
+ * is one.
94
+ */
95
+ export type OpenRouterDecisionScoreLevels = readonly [OpenRouterDecisionEntry, OpenRouterDecisionEntry, ...OpenRouterDecisionEntry[]];
96
+ /**
97
+ * "Which level on this rubric?"
98
+ *
99
+ * The answer may land BETWEEN two levels, so cross a THRESHOLD with a score and never try to recover a
100
+ * magnitude from one. Every level is evaluated separately and the model never sees a level's number or
101
+ * its neighbours, which is why numbers in the level descriptions do not help and situations do.
102
+ */
103
+ export interface OpenRouterDecisionScoreQuestion {
104
+ readonly type: 'score';
105
+ readonly instructions: OpenRouterDecisionEntry;
106
+ readonly levels: ReadonlyArray<OpenRouterDecisionEntry>;
107
+ }
108
+ /**
109
+ * "Is this true?"
110
+ *
111
+ * The returned probability IS the uncertainty, so a Noul carries no separate confidence. Define the
112
+ * CONDITION: "states they used Python at work" is a Noul, while "strong in Python" is a Score.
113
+ */
114
+ export interface OpenRouterDecisionNoulQuestion {
115
+ readonly type: 'noul';
116
+ readonly instructions: OpenRouterDecisionEntry;
117
+ readonly means?: Maybe<OpenRouterDecisionNoulMeans>;
118
+ }
119
+ /**
120
+ * Any one declared question.
121
+ */
122
+ export type OpenRouterDecisionQuestion<O extends string = string> = OpenRouterDecisionChoiceQuestion<O> | OpenRouterDecisionScoreQuestion | OpenRouterDecisionNoulQuestion;
123
+ /**
124
+ * The questions one decision declares, keyed by {@link OpenRouterDecisionQuestionId}.
125
+ *
126
+ * Declare every question one state could need in ONE call: each is evaluated independently against the
127
+ * same state, so the map is both the batching unit and the cost unit. The state is sent (and billed)
128
+ * once, and a speculative question the caller may discard costs only its own tokens.
129
+ */
130
+ export type OpenRouterDecisionQuestions = Readonly<Record<OpenRouterDecisionQuestionId, OpenRouterDecisionQuestion>>;
131
+ /**
132
+ * The content to judge.
133
+ *
134
+ * Prefer an object so each part has a NAME a question can point at. Filtering belongs in code first:
135
+ * accuracy falls as a state grows with material unrelated to the decision, so a wide state is not a
136
+ * free hedge.
137
+ */
138
+ export type OpenRouterDecisionState = string | Readonly<Record<string, unknown>> | ReadonlyArray<unknown>;
139
+ /**
140
+ * A decision state in the form durable storage can hold: an object or an array, never a bare string.
141
+ *
142
+ * The narrowing is not a storage workaround dressed up as doctrine — it IS the doctrine. A state should
143
+ * be an object anyway, so each part has a name a question can point at with the backticked dot-path
144
+ * convention; a bare string leaves every question describing the state again in prose. A caller whose
145
+ * state really is one value names it (`{ phrase: '…' }`) and gets a question that can say `` `phrase` ``.
146
+ *
147
+ * (It also happens to be what a JSON-string Firestore field can carry, which is why the queued arm of
148
+ * the execution system takes this rather than {@link OpenRouterDecisionState}.)
149
+ */
150
+ export type OpenRouterStorableDecisionState = Exclude<OpenRouterDecisionState, string>;
151
+ /**
152
+ * The answer to a Choice.
153
+ *
154
+ * `choice` is GUARANTEED to be one of the declared options — that is the transport's contract, checked
155
+ * by `readOpenRouterDecisionAnswers` — and `probabilities` covers every declared option, summing to 1.
156
+ * Both `probabilities` and `confidence` are optional: an absent one is a real reply, not a fault.
157
+ */
158
+ export interface OpenRouterDecisionChoiceAnswer<O extends string = string> {
159
+ readonly type: 'choice';
160
+ readonly choice: O;
161
+ readonly probabilities?: Maybe<Readonly<Record<O, number>>>;
162
+ readonly confidence?: Maybe<number>;
163
+ }
164
+ /**
165
+ * The answer to a Score.
166
+ *
167
+ * `legend` echoes the declared levels back, keyed by their index as a string.
168
+ */
169
+ export interface OpenRouterDecisionScoreAnswer {
170
+ readonly type: 'score';
171
+ readonly score: number;
172
+ readonly legend?: Maybe<Readonly<Record<string, OpenRouterDecisionEntry>>>;
173
+ readonly probabilities?: Maybe<Readonly<Record<string, number>>>;
174
+ readonly confidence?: Maybe<number>;
175
+ }
176
+ /**
177
+ * The answer to a Noul: the probability the condition holds, 0..1.
178
+ */
179
+ export interface OpenRouterDecisionNoulAnswer {
180
+ readonly type: 'noul';
181
+ readonly noul: number;
182
+ }
183
+ /**
184
+ * Any one answer.
185
+ */
186
+ export type OpenRouterDecisionAnswer<O extends string = string> = OpenRouterDecisionChoiceAnswer<O> | OpenRouterDecisionScoreAnswer | OpenRouterDecisionNoulAnswer;
187
+ /**
188
+ * The answer type a given declared question produces.
189
+ */
190
+ export type OpenRouterDecisionAnswerFor<Q extends OpenRouterDecisionQuestion> = Q extends OpenRouterDecisionNoulQuestion ? OpenRouterDecisionNoulAnswer : Q extends OpenRouterDecisionScoreQuestion ? OpenRouterDecisionScoreAnswer : Q extends OpenRouterDecisionChoiceQuestion<infer O> ? OpenRouterDecisionChoiceAnswer<O> : never;
191
+ /**
192
+ * The answers a declared question map produces.
193
+ *
194
+ * DERIVED from the questions rather than declared beside them, so a caller reads `answers.urgency.score`
195
+ * with no cast and a renamed question is a compile error at every reader.
196
+ */
197
+ export type OpenRouterDecisionAnswers<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions> = {
198
+ readonly [K in keyof Q]: OpenRouterDecisionAnswerFor<Q[K]>;
199
+ };
200
+ /**
201
+ * A coarse reading of a Choice or Score `confidence`.
202
+ */
203
+ export type OpenRouterDecisionConfidenceBand = 'high' | 'medium' | 'low';
204
+ /**
205
+ * Confidence at or above which {@link asOpenRouterDecisionConfidenceBand} reads `high`.
206
+ *
207
+ * A documented STARTING POINT, not a tuned threshold. Note also that a Noul probability and a Choice
208
+ * confidence answer different questions and are not comparable, so a threshold calibrated for one may
209
+ * not be carried over to the other.
210
+ */
211
+ export declare const OPENROUTER_DECISION_CONFIDENCE_HIGH = 0.75;
212
+ /**
213
+ * Confidence at or above which {@link asOpenRouterDecisionConfidenceBand} reads `medium`.
214
+ *
215
+ * See the note on {@link OPENROUTER_DECISION_CONFIDENCE_HIGH}.
216
+ */
217
+ export declare const OPENROUTER_DECISION_CONFIDENCE_MEDIUM = 0.5;
218
+ /**
219
+ * Most options a single Choice may declare.
220
+ *
221
+ * A hard transport limit, not a guideline. Past it, narrow in two stages — ask a first Choice that picks
222
+ * the branch, then a second over that branch's members — rather than truncating the set, because an
223
+ * option that was truncated away is one the model can never pick and nothing reports that it was missing.
224
+ */
225
+ export declare const OPENROUTER_DECISION_CHOICE_OPTIONS_MAX = 255;
226
+ /**
227
+ * Fewest levels a Score may declare.
228
+ */
229
+ export declare const OPENROUTER_DECISION_SCORE_LEVELS_MIN = 2;
230
+ /**
231
+ * Most levels a Score may declare.
232
+ *
233
+ * The trap this guards: a 0..8 band is NINE levels and legal, while a 0..10 scale is eleven and is
234
+ * rejected at the wire. Past the ceiling, MERGE the levels that cannot be told apart — never truncate
235
+ * the top, which silently removes the extreme the threshold usually cares about.
236
+ */
237
+ export declare const OPENROUTER_DECISION_SCORE_LEVELS_MAX = 10;
238
+ /**
239
+ * Whether a declaration entry says nothing at all.
240
+ *
241
+ * A blank string, an empty array, and a keyless object all ask nothing, and all three reach the wire as
242
+ * a question the model cannot answer.
243
+ *
244
+ * @param entry - The entry to test.
245
+ * @returns True when the entry carries no guidance.
246
+ *
247
+ * @__NO_SIDE_EFFECTS__
248
+ */
249
+ export declare function isBlankOpenRouterDecisionEntry(entry: Maybe<OpenRouterDecisionEntry>): boolean;
250
+ /**
251
+ * The option names a Choice declared — what the model was SHOWN.
252
+ *
253
+ * @param question - The choice question.
254
+ * @returns The declared option names, in declaration order.
255
+ *
256
+ * @__NO_SIDE_EFFECTS__
257
+ */
258
+ export declare function openRouterDecisionChoiceOptionNames<O extends string = string>(question: OpenRouterDecisionChoiceQuestion<O>): O[];
259
+ /**
260
+ * Reads a confidence as a band.
261
+ *
262
+ * An ABSENT confidence reads `low` rather than throwing: the model is not required to report one, and a
263
+ * caller that branches on the band should treat "did not say" the same as "not sure".
264
+ *
265
+ * @param confidence - The reported confidence, if any.
266
+ * @returns The band.
267
+ *
268
+ * @__NO_SIDE_EFFECTS__
269
+ */
270
+ export declare function asOpenRouterDecisionConfidenceBand(confidence: Maybe<number>): OpenRouterDecisionConfidenceBand;
271
+ /**
272
+ * One row of a Choice's distribution.
273
+ */
274
+ export interface OpenRouterDecisionChoiceRankingRow<O extends string = string> {
275
+ readonly option: O;
276
+ readonly probability: number;
277
+ }
278
+ /**
279
+ * Reads a Choice's distribution as a ranking, most probable first.
280
+ *
281
+ * The distribution is a FREE full ranking — the model reports every option, not just the winner — so a
282
+ * caller wanting a shortlist should read this rather than paying for a second question.
283
+ *
284
+ * Returns an empty array when the answer carried no distribution, which is a real reply rather than an
285
+ * error. The sort is stable, so tied options keep declaration order.
286
+ *
287
+ * @param answer - The choice answer.
288
+ * @returns The ranking rows.
289
+ *
290
+ * @__NO_SIDE_EFFECTS__
291
+ */
292
+ export declare function openRouterDecisionChoiceRanking<O extends string = string>(answer: OpenRouterDecisionChoiceAnswer<O>): OpenRouterDecisionChoiceRankingRow<O>[];
293
+ /**
294
+ * Config for {@link mapOpenRouterDecisionChoiceRows}.
295
+ */
296
+ export interface MapOpenRouterDecisionChoiceRowsConfig<Q extends OpenRouterDecisionQuestions, K extends keyof Q & string, R> {
297
+ /**
298
+ * The answers the decision returned.
299
+ */
300
+ readonly answers: OpenRouterDecisionAnswers<Q>;
301
+ /**
302
+ * Which question's distribution to read.
303
+ */
304
+ readonly question: K;
305
+ /**
306
+ * Resolves one declared option name back to the caller's own row. Return null to drop it.
307
+ */
308
+ readonly rowOf: (option: string) => Maybe<R>;
309
+ }
310
+ /**
311
+ * One of the caller's own rows, with the probability the model gave it.
312
+ */
313
+ export interface OpenRouterDecisionChoiceRow<R> {
314
+ readonly row: R;
315
+ readonly probability: number;
316
+ }
317
+ /**
318
+ * Reads a Choice's distribution back as the caller's OWN rows, most probable first.
319
+ *
320
+ * The seam exists because a Choice's options are usually derived from rows the caller already holds, and
321
+ * walking the distribution back to them by hand at every call site is where the option-name convention
322
+ * quietly drifts.
323
+ *
324
+ * @param config - The answers, the question to read, and how to resolve an option to a row.
325
+ * @returns The resolved rows, most probable first. Options that resolve to nothing are dropped.
326
+ */
327
+ export declare function mapOpenRouterDecisionChoiceRows<Q extends OpenRouterDecisionQuestions, K extends keyof Q & string, R>(config: MapOpenRouterDecisionChoiceRowsConfig<Q, K, R>): OpenRouterDecisionChoiceRow<R>[];
328
+ /**
329
+ * Reads back the state paths a declaration entry names.
330
+ *
331
+ * The convention is to name a part of the state as a dot-and-index path IN BACKTICKS — `` `phrase` ``,
332
+ * `` `ticket.sender.email` ``, `` `messages[0].text` `` — so a question points at something the state
333
+ * actually carries rather than describing it again in prose.
334
+ *
335
+ * Documented and inspectable, deliberately NOT enforced: backticks also legitimately quote an option key
336
+ * or a literal, so a spec may pin that a declaration points at keys its state has, while the transport
337
+ * never refuses one that does not.
338
+ *
339
+ * @param entry - The entry to read. Objects and arrays are walked.
340
+ * @returns The paths, deduplicated, in the order they first appear.
341
+ */
342
+ export declare function openRouterDecisionStatePaths(entry: Maybe<OpenRouterDecisionEntry>): string[];
343
+ /**
344
+ * Declares a Choice question.
345
+ *
346
+ * Supply the FULL option set, plus an explicit `other` / `none of the above` when the set may not cover
347
+ * the input — the distribution is normalised over what was supplied, so a Choice always names a winner
348
+ * whether or not one fits.
349
+ *
350
+ * @param instructions - The complete question, as the model will read it.
351
+ * @param options - The options, keyed by the name the answer will quote.
352
+ * @returns The declared question.
353
+ *
354
+ * @__NO_SIDE_EFFECTS__
355
+ */
356
+ export declare function openRouterChoiceQuestion<O extends string = string>(instructions: OpenRouterDecisionEntry, options: OpenRouterDecisionChoiceOptions<O>): OpenRouterDecisionChoiceQuestion<O>;
357
+ /**
358
+ * Declares a Score question.
359
+ *
360
+ * Use as many levels as can be described DISTINCTLY, lowest to highest — three is fine, and a rare
361
+ * extreme deserves its own level. One dimension per question.
362
+ *
363
+ * @param instructions - The complete question, as the model will read it.
364
+ * @param levels - The levels, lowest first. At least two.
365
+ * @returns The declared question.
366
+ *
367
+ * @__NO_SIDE_EFFECTS__
368
+ */
369
+ export declare function openRouterScoreQuestion(instructions: OpenRouterDecisionEntry, levels: OpenRouterDecisionScoreLevels): OpenRouterDecisionScoreQuestion;
370
+ /**
371
+ * Declares a Noul question.
372
+ *
373
+ * @param instructions - The complete question, as the model will read it.
374
+ * @param means - Optional explicit definitions of the true and false sides.
375
+ * @returns The declared question.
376
+ *
377
+ * @__NO_SIDE_EFFECTS__
378
+ */
379
+ export declare function openRouterNoulQuestion(instructions: OpenRouterDecisionEntry, means?: Maybe<OpenRouterDecisionNoulMeans>): OpenRouterDecisionNoulQuestion;
380
+ /**
381
+ * Validates a declared question map.
382
+ *
383
+ * Every problem here fails AT THE DECLARATION, naming the question, rather than as a 4xx about a request
384
+ * body — which is the difference between a publish that is refused and a run that dies in a sweep at 2am.
385
+ *
386
+ * Returns the package's standard validation result so a caller can report question problems and config
387
+ * problems through one surface.
388
+ *
389
+ * @param questions - The declared questions.
390
+ * @returns The validation result.
391
+ */
392
+ 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
  *