@dereekb/openrouter 14.8.0 → 14.10.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dereekb/openrouter",
3
- "version": "14.8.0",
3
+ "version": "14.10.0",
4
4
  "sideEffects": false,
5
5
  "type": "module",
6
6
  "exports": {
@@ -19,19 +19,24 @@
19
19
  "types": "./index.d.ts",
20
20
  "import": "./index.esm.js",
21
21
  "default": "./index.esm.js"
22
+ },
23
+ "./decision": {
24
+ "types": "./decision.d.ts",
25
+ "import": "./decision.esm.js",
26
+ "default": "./decision.esm.js"
22
27
  }
23
28
  },
24
29
  "peerDependencies": {
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",
30
+ "@dereekb/firebase": "14.10.0",
31
+ "@dereekb/firebase-server": "14.10.0",
32
+ "@dereekb/model": "14.10.0",
33
+ "@dereekb/util": "14.10.0",
29
34
  "@nestjs/common": "^12.0.1",
30
35
  "@openrouter/sdk": "^1.3.8",
31
36
  "arktype": "^2.2.0"
32
37
  },
33
38
  "devDependencies": {
34
- "@dereekb/nestjs": "14.8.0"
39
+ "@dereekb/nestjs": "14.10.0"
35
40
  },
36
41
  "module": "./index.esm.js",
37
42
  "main": "./index.esm.js",
@@ -0,0 +1,26 @@
1
+ /**
2
+ * `@dereekb/openrouter/decision` — the System One (Jev) decision layer, loadable WITHOUT evaluating
3
+ * `@openrouter/sdk`.
4
+ *
5
+ * The root `@dereekb/openrouter` entry re-exports SDK values (`callModel`, `responsesSend`,
6
+ * `systemOneCreate`, …), so importing any value from it evaluates the SDK — a measurable cold-start cost
7
+ * that a test runner isolating each spec file pays once per file. This entry carries everything a decision
8
+ * is BUILT from and READ with, and nothing that sends one:
9
+ *
10
+ * - the declaration vocabulary — Choice / Score / Noul questions, answers, confidence bands, validation;
11
+ * - the request, the wire mapping (`openRouterDecisionRequestBody`), the reply reader
12
+ * (`readOpenRouterDecisionAnswers`) and its faults, and the usage flattening;
13
+ * - the model config and the model ids, including the System One routing guard
14
+ * (`isOpenRouterSystemOneModelId`).
15
+ *
16
+ * The transport, `openRouterDecision`, stays on the root entry because it is the one `systemOneCreate`
17
+ * caller. A consumer that owns its own transport pairs this entry with its own lazily-loaded client.
18
+ *
19
+ * Everything here is ALSO exported from the root entry, from the same modules — the two entries share one
20
+ * chunk, so a class such as `OpenRouterDecisionAnswerFaultError` has one identity whichever entry a value
21
+ * was imported through.
22
+ */
23
+ export * from './lib/openrouter.config';
24
+ export * from './lib/openrouter.decision';
25
+ export * from './lib/openrouter.decision.question';
26
+ export * from './lib/openrouter.type';
@@ -1,6 +1,7 @@
1
1
  export * from './openrouter.call';
2
2
  export * from './openrouter.config';
3
3
  export * from './openrouter.decision';
4
+ export * from './openrouter.decision.call';
4
5
  export * from './openrouter.decision.question';
5
6
  export * from './openrouter.embedding';
6
7
  export * from './openrouter.generation';
@@ -0,0 +1,81 @@
1
+ /**
2
+ * The TRANSPORT half of the decision layer: {@link openRouterDecision}, the one caller of the SDK's
3
+ * `systemOneCreate`.
4
+ *
5
+ * Kept apart from `openrouter.decision.ts` (declaring, validating, the wire mapping, reading a reply) so
6
+ * that everything a decision is built from can be loaded without evaluating `@openrouter/sdk` — see the
7
+ * `@dereekb/openrouter/decision` entry. A caller that owns its own transport (its own timeout, retry
8
+ * policy or error shape) builds the body with `openRouterDecisionRequestBody` and reads the reply with
9
+ * `readOpenRouterDecisionAnswers`, and never needs this file.
10
+ */
11
+ import { type Maybe } from '@dereekb/util';
12
+ import { type OpenRouterDecisionRequest } from './openrouter.decision';
13
+ import { type OpenRouterDecisionAnswers, type OpenRouterDecisionQuestions } from './openrouter.decision.question';
14
+ import { type DecisionsResponse, type OpenRouterCore, type RequestOptions } from './openrouter.sdk';
15
+ import { type OpenRouterGenerationId, type OpenRouterModelId, type OpenRouterRunUsage } from './openrouter.type';
16
+ /**
17
+ * A normalized result of one decision.
18
+ *
19
+ * Field names deliberately match `OpenRouterCallResult` wherever the two have the same meaning, so a
20
+ * caller reading `model` / `generationIds` / `usage` does not have to learn a second vocabulary for the
21
+ * second arm. There is no `outputText` or `error`: a decision has no prose output, and the route reports
22
+ * a failure as a thrown transport error rather than as a field on a 200.
23
+ */
24
+ export interface OpenRouterDecisionResult<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions> {
25
+ /**
26
+ * The answers, membership-checked against the declared questions.
27
+ */
28
+ readonly answers: OpenRouterDecisionAnswers<Q>;
29
+ /**
30
+ * The model that actually served the decision — a VERSIONED slug even when an alias was asked for,
31
+ * which is what makes an answer reproducible.
32
+ */
33
+ readonly model?: Maybe<OpenRouterModelId>;
34
+ /**
35
+ * The provider that served it.
36
+ */
37
+ readonly provider?: Maybe<string>;
38
+ /**
39
+ * Generation ids produced, for auditing. At most one on this route.
40
+ */
41
+ readonly generationIds: OpenRouterGenerationId[];
42
+ /**
43
+ * Token/cost usage.
44
+ */
45
+ readonly usage?: Maybe<OpenRouterRunUsage>;
46
+ /**
47
+ * The raw response, for anything the normalized shape drops.
48
+ */
49
+ readonly response: DecisionsResponse;
50
+ }
51
+ /**
52
+ * Params for {@link openRouterDecision}.
53
+ */
54
+ export interface OpenRouterDecisionParams<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions> {
55
+ /**
56
+ * The OpenRouter client.
57
+ */
58
+ readonly client: OpenRouterCore;
59
+ /**
60
+ * The built request.
61
+ */
62
+ readonly request: OpenRouterDecisionRequest<Q>;
63
+ /**
64
+ * Additional request options, merged under the config's `requestTimeoutMs`.
65
+ */
66
+ readonly options?: Maybe<RequestOptions>;
67
+ }
68
+ /**
69
+ * Asks a decision and returns its answers.
70
+ *
71
+ * The request is validated first, so a model that cannot serve a decision is refused HERE rather than by
72
+ * the route — the mirror of the refusal `callModelForOpenRouterRequest` makes for a System One model on
73
+ * the completion arm. Which surface a request belongs to is a property of the request, not a choice the
74
+ * caller makes at the call site.
75
+ *
76
+ * @param params - The client, request, and options.
77
+ * @returns The normalized decision result.
78
+ * @throws {OpenRouterDecisionDeclarationError} When the request cannot be asked as declared.
79
+ * @throws {OpenRouterDecisionAnswerFaultError} When the reply did not answer the declared questions.
80
+ */
81
+ export declare function openRouterDecision<Q extends OpenRouterDecisionQuestions = OpenRouterDecisionQuestions>(params: OpenRouterDecisionParams<Q>): Promise<OpenRouterDecisionResult<Q>>;
@@ -3,8 +3,8 @@ import { type OpenRouterModelConfig, type OpenRouterModelConfigValidation } from
3
3
  import { type OpenRouterDecisionAnswer, type OpenRouterDecisionAnswers, type OpenRouterDecisionEntry, type OpenRouterDecisionQuestion, type OpenRouterDecisionQuestionId, type OpenRouterDecisionQuestions, type OpenRouterDecisionState } from './openrouter.decision.question';
4
4
  import { type OpenRouterResolvedPrompt } from './openrouter.prompt';
5
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';
6
+ import type { DecisionsRequest, DecisionsResponse } from './openrouter.sdk';
7
+ import { type OpenRouterRunUsage } from './openrouter.type';
8
8
  /**
9
9
  * How far a distribution's probabilities may sum from 1 before the reply is read as malformed.
10
10
  *
@@ -284,69 +284,3 @@ export declare function readOpenRouterDecisionAnswers<Q extends OpenRouterDecisi
284
284
  * @__NO_SIDE_EFFECTS__
285
285
  */
286
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>>;
@@ -26,24 +26,29 @@ export type OpenRouterDecisionEntry = string | Readonly<Record<string, unknown>>
26
26
  *
27
27
  * `inspect` and `compare` name parts of the state, in the same backticked dot-path convention prose
28
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.
29
34
  */
30
- export interface OpenRouterDecisionStructuredInstructions {
35
+ export type OpenRouterDecisionStructuredInstructions = {
31
36
  readonly question: string;
32
37
  readonly focus?: Maybe<string>;
33
38
  readonly inspect?: Maybe<string | ReadonlyArray<string>>;
34
39
  readonly compare?: Maybe<ReadonlyArray<string>>;
35
- }
40
+ };
36
41
  /**
37
42
  * A structured Choice option.
38
43
  *
39
44
  * CONTRASTIVE by design: use the SAME keys on every option of a question so the model compares like
40
45
  * with like. `not_for` is where an option's boundary against its neighbours goes.
41
46
  */
42
- export interface OpenRouterDecisionStructuredCriterion {
47
+ export type OpenRouterDecisionStructuredCriterion = {
43
48
  readonly what: string;
44
49
  readonly not_for?: Maybe<string>;
45
50
  readonly examples?: Maybe<ReadonlyArray<string>>;
46
- }
51
+ };
47
52
  /**
48
53
  * A structured Score level.
49
54
  *
@@ -51,11 +56,11 @@ export interface OpenRouterDecisionStructuredCriterion {
51
56
  * model something to match the state against, where "moderately severe" does not. Use the same keys on
52
57
  * every level of a question.
53
58
  */
54
- export interface OpenRouterDecisionStructuredLevel {
59
+ export type OpenRouterDecisionStructuredLevel = {
55
60
  readonly what: string;
56
61
  readonly signals?: Maybe<ReadonlyArray<string>>;
57
62
  readonly examples?: Maybe<ReadonlyArray<string>>;
58
- }
63
+ };
59
64
  /**
60
65
  * The declared options of a Choice, keyed by the option name the answer will quote.
61
66
  *
@@ -260,7 +265,9 @@ export declare function openRouterDecisionChoiceOptionNames<O extends string = s
260
265
  * Reads a confidence as a band.
261
266
  *
262
267
  * 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".
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`.
264
271
  *
265
272
  * @param confidence - The reported confidence, if any.
266
273
  * @returns The band.