@node-llm/core 1.17.1 → 1.18.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.
Files changed (64) hide show
  1. package/README.md +1 -0
  2. package/dist/agent/Agent.d.ts +24 -11
  3. package/dist/agent/Agent.d.ts.map +1 -1
  4. package/dist/agent/Agent.js +1 -3
  5. package/dist/aliases.d.ts +341 -172
  6. package/dist/aliases.d.ts.map +1 -1
  7. package/dist/aliases.js +409 -240
  8. package/dist/chat/Chat.d.ts +13 -10
  9. package/dist/chat/Chat.d.ts.map +1 -1
  10. package/dist/chat/Chat.js +15 -4
  11. package/dist/chat/ChatOptions.d.ts +11 -11
  12. package/dist/chat/ChatOptions.d.ts.map +1 -1
  13. package/dist/chat/Tool.d.ts +26 -5
  14. package/dist/chat/Tool.d.ts.map +1 -1
  15. package/dist/chat/Tool.js +25 -3
  16. package/dist/chat/ToolCallOutcome.d.ts +6 -6
  17. package/dist/chat/ToolCallOutcome.d.ts.map +1 -1
  18. package/dist/chat/ToolHandler.d.ts +2 -2
  19. package/dist/chat/ToolHandler.d.ts.map +1 -1
  20. package/dist/config.d.ts +12 -2
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +18 -1
  23. package/dist/constants.d.ts +7 -0
  24. package/dist/constants.d.ts.map +1 -1
  25. package/dist/constants.js +3 -1
  26. package/dist/index.d.ts +9 -2
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +3 -0
  29. package/dist/judge/Judge.d.ts +107 -0
  30. package/dist/judge/Judge.d.ts.map +1 -0
  31. package/dist/judge/Judge.js +104 -0
  32. package/dist/judge/Judgment.d.ts +116 -0
  33. package/dist/judge/Judgment.d.ts.map +1 -0
  34. package/dist/judge/Judgment.js +159 -0
  35. package/dist/judge/Question.d.ts +91 -0
  36. package/dist/judge/Question.d.ts.map +1 -0
  37. package/dist/judge/Question.js +180 -0
  38. package/dist/llm.d.ts +46 -0
  39. package/dist/llm.d.ts.map +1 -1
  40. package/dist/llm.js +105 -5
  41. package/dist/models/ModelRegistry.d.ts +11 -18
  42. package/dist/models/ModelRegistry.d.ts.map +1 -1
  43. package/dist/models/ModelRegistry.js +6 -0
  44. package/dist/models/models.json +5181 -2145
  45. package/dist/providers/BaseProvider.d.ts +2 -1
  46. package/dist/providers/BaseProvider.d.ts.map +1 -1
  47. package/dist/providers/BaseProvider.js +3 -0
  48. package/dist/providers/Provider.d.ts +37 -0
  49. package/dist/providers/Provider.d.ts.map +1 -1
  50. package/dist/providers/registry.d.ts +2 -1
  51. package/dist/providers/registry.d.ts.map +1 -1
  52. package/dist/providers/registry.js +2 -1
  53. package/dist/providers/typesafe/SystemOne.d.ts +11 -0
  54. package/dist/providers/typesafe/SystemOne.d.ts.map +1 -0
  55. package/dist/providers/typesafe/SystemOne.js +171 -0
  56. package/dist/providers/typesafe/TypeSafeProvider.d.ts +27 -0
  57. package/dist/providers/typesafe/TypeSafeProvider.d.ts.map +1 -0
  58. package/dist/providers/typesafe/TypeSafeProvider.js +76 -0
  59. package/dist/providers/typesafe/index.d.ts +4 -0
  60. package/dist/providers/typesafe/index.d.ts.map +1 -0
  61. package/dist/providers/typesafe/index.js +19 -0
  62. package/dist/types/Middleware.d.ts +9 -0
  63. package/dist/types/Middleware.d.ts.map +1 -1
  64. package/package.json +13 -10
@@ -0,0 +1,180 @@
1
+ /**
2
+ * Typed questions for judgments.
3
+ *
4
+ * A judgment asks a set of named questions about one input and returns a typed
5
+ * answer for each: the probability that a statement holds, a choice among named
6
+ * options, or a score on an ordered scale. Questions are plain data, so they
7
+ * can be declared on a Judge class, passed to NodeLLM.judge, or built at
8
+ * runtime from application data.
9
+ */
10
+ /**
11
+ * Declares a yes/no question whose answer is the probability of yes. A value
12
+ * near 0.5 means yes and no are about equally likely, not "medium"; use a
13
+ * score to measure degree.
14
+ *
15
+ * @example
16
+ * probability("Does this need attention today?", {
17
+ * yes: "An explicit deadline today or an ongoing outage",
18
+ * no: "A general question with no time pressure"
19
+ * })
20
+ */
21
+ export function probability(instructions, criteria) {
22
+ return { type: "probability", instructions, ...(criteria ? { criteria } : {}) };
23
+ }
24
+ /**
25
+ * Declares a question that selects one named option and returns a probability
26
+ * for every option. Include a catch-all such as `other` when none of the
27
+ * specific options may fit. Use null for an option that needs no description.
28
+ *
29
+ * @example
30
+ * choice("Which team should handle this?", {
31
+ * billing: "Payments and refunds",
32
+ * technical: "Bugs and integrations",
33
+ * other: null
34
+ * })
35
+ */
36
+ export function choice(instructions, options) {
37
+ return { type: "choice", instructions, options };
38
+ }
39
+ /**
40
+ * Declares a question scored against ordered levels. The first level is 0, the
41
+ * second 1, and so on; the answer is probability-weighted and can fall between
42
+ * levels. Describe each level concretely.
43
+ *
44
+ * @example
45
+ * score("How frustrated is the customer?", ["Calm", "Frustrated", "Angry"])
46
+ */
47
+ export function score(instructions, levels) {
48
+ return { type: "score", instructions, levels };
49
+ }
50
+ function isDescription(value) {
51
+ if (value === null || typeof value === "string")
52
+ return true;
53
+ if (Array.isArray(value))
54
+ return value.every(isJson);
55
+ if (typeof value === "object")
56
+ return isJson(value);
57
+ return false;
58
+ }
59
+ function isJson(value) {
60
+ if (value === null)
61
+ return true;
62
+ switch (typeof value) {
63
+ case "string":
64
+ case "boolean":
65
+ return true;
66
+ case "number":
67
+ return Number.isFinite(value);
68
+ case "object":
69
+ if (Array.isArray(value))
70
+ return value.every(isJson);
71
+ if (Object.getPrototypeOf(value) !== Object.prototype &&
72
+ Object.getPrototypeOf(value) !== null) {
73
+ return false;
74
+ }
75
+ return Object.values(value).every(isJson);
76
+ default:
77
+ return false;
78
+ }
79
+ }
80
+ function invalid(name, message) {
81
+ throw new Error(`Invalid judgment question '${name}': ${message}`);
82
+ }
83
+ function validateDescriptions(name, values) {
84
+ if (!values.every(isDescription)) {
85
+ invalid(name, "descriptions must be text, an object, an array, or null");
86
+ }
87
+ }
88
+ /**
89
+ * Validates every question and returns them in declaration order with their
90
+ * names attached. Rejects the problems a provider would otherwise report as an
91
+ * opaque 400: unknown types, empty choices or scales, and probability criteria
92
+ * that describe anything other than yes and no.
93
+ */
94
+ export function normalizeQuestions(questions) {
95
+ if (!questions || typeof questions !== "object" || Array.isArray(questions)) {
96
+ throw new Error("Judgment questions must be an object keyed by question name");
97
+ }
98
+ const entries = Object.entries(questions);
99
+ if (entries.length === 0) {
100
+ throw new Error("A judgment needs at least one question");
101
+ }
102
+ return entries.map(([name, question]) => {
103
+ if (name.length === 0)
104
+ invalid(name, "a question name cannot be empty");
105
+ if (!question || typeof question !== "object")
106
+ invalid(name, "the definition must be an object");
107
+ if (question.instructions !== undefined && !isDescription(question.instructions)) {
108
+ invalid(name, "instructions must be text, an object, an array, or null");
109
+ }
110
+ switch (question.type) {
111
+ case "probability":
112
+ validateProbability(name, question);
113
+ break;
114
+ case "choice":
115
+ validateChoice(name, question);
116
+ break;
117
+ case "score":
118
+ validateScore(name, question);
119
+ break;
120
+ default:
121
+ invalid(name, `unknown type '${String(question.type)}'`);
122
+ }
123
+ return { ...question, name };
124
+ });
125
+ }
126
+ function validateProbability(name, question) {
127
+ const extra = Object.keys(question).filter((k) => !["type", "instructions", "criteria"].includes(k));
128
+ if (extra.length > 0)
129
+ invalid(name, `unknown fields ${extra.join(", ")}`);
130
+ if (question.criteria === undefined)
131
+ return;
132
+ const criteria = question.criteria;
133
+ if (!criteria || typeof criteria !== "object" || Array.isArray(criteria)) {
134
+ invalid(name, "probability criteria must describe yes and no");
135
+ }
136
+ const keys = Object.keys(criteria);
137
+ const unknown = keys.filter((k) => !["yes", "no", "true", "false"].includes(k));
138
+ if (unknown.length > 0)
139
+ invalid(name, "probability criteria must describe yes and no");
140
+ // yes/true and no/false are the same outcome; describing one twice is ambiguous.
141
+ const positives = keys.filter((k) => k === "yes" || k === "true").length;
142
+ const negatives = keys.filter((k) => k === "no" || k === "false").length;
143
+ if (positives > 1 || negatives > 1)
144
+ invalid(name, "probability criteria contain duplicate outcomes");
145
+ validateDescriptions(name, Object.values(criteria));
146
+ }
147
+ function validateChoice(name, question) {
148
+ const extra = Object.keys(question).filter((k) => !["type", "instructions", "options"].includes(k));
149
+ if (extra.length > 0)
150
+ invalid(name, `unknown fields ${extra.join(", ")}`);
151
+ const options = question.options;
152
+ if (!options || typeof options !== "object" || Array.isArray(options)) {
153
+ invalid(name, "a choice needs a non-empty object of options");
154
+ }
155
+ const keys = Object.keys(options);
156
+ if (keys.length === 0)
157
+ invalid(name, "a choice needs a non-empty object of options");
158
+ if (keys.some((k) => k.length === 0))
159
+ invalid(name, "choice options must have non-empty names");
160
+ validateDescriptions(name, Object.values(options));
161
+ }
162
+ function validateScore(name, question) {
163
+ const extra = Object.keys(question).filter((k) => !["type", "instructions", "levels"].includes(k));
164
+ if (extra.length > 0)
165
+ invalid(name, `unknown fields ${extra.join(", ")}`);
166
+ if (!Array.isArray(question.levels) || question.levels.length === 0) {
167
+ invalid(name, "a score needs a non-empty array of levels");
168
+ }
169
+ validateDescriptions(name, question.levels);
170
+ }
171
+ /** True when the value can be sent as judgment input. */
172
+ export function isJudgmentInput(value) {
173
+ if (typeof value === "string")
174
+ return true;
175
+ if (Array.isArray(value))
176
+ return isJson(value);
177
+ if (value !== null && typeof value === "object")
178
+ return isJson(value);
179
+ return false;
180
+ }
package/dist/llm.d.ts CHANGED
@@ -9,6 +9,9 @@ import { Moderation } from "./moderation/Moderation.js";
9
9
  import { Embedding } from "./embedding/Embedding.js";
10
10
  import { NodeLLMConfig } from "./config.js";
11
11
  import { Middleware } from "./types/Middleware.js";
12
+ import { JudgmentInput } from "./providers/Provider.js";
13
+ import { QuestionMap } from "./judge/Question.js";
14
+ import { JudgmentResult } from "./judge/Judgment.js";
12
15
  export interface RetryOptions {
13
16
  attempts?: number;
14
17
  delayMs?: number;
@@ -21,6 +24,7 @@ type LLMConfig = {
21
24
  defaultTranscriptionModel?: string;
22
25
  defaultModerationModel?: string;
23
26
  defaultEmbeddingModel?: string;
27
+ defaultJudgmentModel?: string;
24
28
  } & Omit<Partial<NodeLLMConfig>, "provider">;
25
29
  export declare class NodeLLMCore {
26
30
  readonly config: NodeLLMConfig;
@@ -35,11 +39,13 @@ export declare class NodeLLMCore {
35
39
  transcription?: string;
36
40
  moderation?: string;
37
41
  embedding?: string;
42
+ judgment?: string;
38
43
  });
39
44
  get defaultChatModel(): string | undefined;
40
45
  get defaultTranscriptionModel(): string | undefined;
41
46
  get defaultModerationModel(): string | undefined;
42
47
  get defaultEmbeddingModel(): string | undefined;
48
+ get defaultJudgmentModel(): string | undefined;
43
49
  /**
44
50
  * Returns a scoped LLM instance configured for a specific provider.
45
51
  * This returns a NEW immutable instance.
@@ -72,6 +78,8 @@ export declare class NodeLLMCore {
72
78
  language?: string;
73
79
  speakerNames?: string[];
74
80
  speakerReferences?: string[];
81
+ /** Word and/or segment timestamps, where the provider supports them. */
82
+ timestamp_granularities?: ("word" | "segment")[];
75
83
  assumeModelExists?: boolean;
76
84
  requestTimeout?: number;
77
85
  middlewares?: Middleware[];
@@ -89,6 +97,44 @@ export declare class NodeLLMCore {
89
97
  requestTimeout?: number;
90
98
  middlewares?: Middleware[];
91
99
  }): Promise<Embedding>;
100
+ /**
101
+ * Asks typed questions about one input and returns a typed answer for each:
102
+ * a probability, a choice among named options, or a score on a scale.
103
+ *
104
+ * The provider follows the model: `jev-latest` (the default) is answered by
105
+ * TypeSafe whichever provider this instance is scoped to. Pass `provider` to
106
+ * route explicitly, for example to a Jev-compatible local server configured
107
+ * through `typesafeApiBase`.
108
+ *
109
+ * Each call judges only the input given; it keeps no conversation history.
110
+ *
111
+ * @example
112
+ * const judgment = await NodeLLM.judge("Please refund the duplicate charge today.", {
113
+ * questions: {
114
+ * urgent: probability("Does this need attention today?"),
115
+ * team: choice("Which team should handle this?", { billing: "Payments", other: null })
116
+ * }
117
+ * });
118
+ * judgment.urgent.probability; // 0.91
119
+ * judgment.team.choice; // "billing"
120
+ */
121
+ judge<const Q extends QuestionMap>(input: JudgmentInput, options: {
122
+ questions: Q;
123
+ model?: string;
124
+ provider?: string;
125
+ /** Provider-specific fields merged into the request body. */
126
+ providerOptions?: Record<string, unknown>;
127
+ requestTimeout?: number;
128
+ middlewares?: Middleware[];
129
+ }): Promise<JudgmentResult<Q>>;
130
+ /**
131
+ * Picks the provider that answers judgments for a model: an explicit choice
132
+ * first, then the registry's owner of a known judgment model, then this
133
+ * instance's own provider - which is how a model the registry does not know,
134
+ * such as one on a local Jev-compatible server, reaches the provider it was
135
+ * scoped to.
136
+ */
137
+ private judgmentProvider;
92
138
  }
93
139
  export { Transcription, Moderation, Embedding, ModelRegistry, PricingRegistry };
94
140
  /**
package/dist/llm.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llm.d.ts","sourceRoot":"","sources":["../src/llm.ts"],"names":[],"mappings":"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"}
package/dist/llm.js CHANGED
@@ -1,16 +1,19 @@
1
1
  import { Chat } from "./chat/Chat.js";
2
- import { providerRegistry, ensureOpenAIRegistered, registerAnthropicProvider, registerGeminiProvider, registerDeepSeekProvider, registerOllamaProvider, registerOpenRouterProvider, registerBedrockProvider, registerXAIProvider, registerMistralProvider } from "./providers/registry.js";
2
+ import { providerRegistry, ensureOpenAIRegistered, registerAnthropicProvider, registerGeminiProvider, registerDeepSeekProvider, registerOllamaProvider, registerOpenRouterProvider, registerBedrockProvider, registerXAIProvider, registerMistralProvider, registerTypeSafeProvider } from "./providers/registry.js";
3
3
  import { GeneratedImage } from "./image/GeneratedImage.js";
4
4
  import { ModelRegistry } from "./models/ModelRegistry.js";
5
5
  import { PricingRegistry } from "./models/PricingRegistry.js";
6
6
  import { Transcription } from "./transcription/Transcription.js";
7
7
  import { Moderation } from "./moderation/Moderation.js";
8
8
  import { Embedding } from "./embedding/Embedding.js";
9
- import { ProviderNotConfiguredError, UnsupportedFeatureError, ModelCapabilityError } from "./errors/index.js";
9
+ import { ProviderNotConfiguredError, UnsupportedFeatureError, ModelCapabilityError, ConfigurationError } from "./errors/index.js";
10
10
  import { resolveModelAlias } from "./model_aliases.js";
11
11
  import { logger } from "./utils/logger.js";
12
12
  import { config, Configuration } from "./config.js";
13
13
  import { runMiddleware } from "./utils/middleware-runner.js";
14
+ import { normalizeQuestions, isJudgmentInput } from "./judge/Question.js";
15
+ import { buildJudgment } from "./judge/Judgment.js";
16
+ import { DEFAULT_MODELS } from "./constants.js";
14
17
  import { randomUUID } from "node:crypto";
15
18
  // Provider registration map
16
19
  const PROVIDER_REGISTRARS = {
@@ -22,7 +25,8 @@ const PROVIDER_REGISTRARS = {
22
25
  openrouter: registerOpenRouterProvider,
23
26
  bedrock: registerBedrockProvider,
24
27
  xai: registerXAIProvider,
25
- mistral: registerMistralProvider
28
+ mistral: registerMistralProvider,
29
+ typesafe: registerTypeSafeProvider
26
30
  };
27
31
  export class NodeLLMCore {
28
32
  config;
@@ -54,6 +58,9 @@ export class NodeLLMCore {
54
58
  get defaultEmbeddingModel() {
55
59
  return this.defaults.embedding;
56
60
  }
61
+ get defaultJudgmentModel() {
62
+ return this.defaults.judgment;
63
+ }
57
64
  /**
58
65
  * Returns a scoped LLM instance configured for a specific provider.
59
66
  * This returns a NEW immutable instance.
@@ -70,7 +77,8 @@ export class NodeLLMCore {
70
77
  defaultChatModel: this.defaults.chat,
71
78
  defaultTranscriptionModel: this.defaults.transcription,
72
79
  defaultModerationModel: this.defaults.moderation,
73
- defaultEmbeddingModel: this.defaults.embedding
80
+ defaultEmbeddingModel: this.defaults.embedding,
81
+ defaultJudgmentModel: this.defaults.judgment
74
82
  });
75
83
  }
76
84
  /**
@@ -281,6 +289,97 @@ export class NodeLLMCore {
281
289
  throw error;
282
290
  }
283
291
  }
292
+ /**
293
+ * Asks typed questions about one input and returns a typed answer for each:
294
+ * a probability, a choice among named options, or a score on a scale.
295
+ *
296
+ * The provider follows the model: `jev-latest` (the default) is answered by
297
+ * TypeSafe whichever provider this instance is scoped to. Pass `provider` to
298
+ * route explicitly, for example to a Jev-compatible local server configured
299
+ * through `typesafeApiBase`.
300
+ *
301
+ * Each call judges only the input given; it keeps no conversation history.
302
+ *
303
+ * @example
304
+ * const judgment = await NodeLLM.judge("Please refund the duplicate charge today.", {
305
+ * questions: {
306
+ * urgent: probability("Does this need attention today?"),
307
+ * team: choice("Which team should handle this?", { billing: "Payments", other: null })
308
+ * }
309
+ * });
310
+ * judgment.urgent.probability; // 0.91
311
+ * judgment.team.choice; // "billing"
312
+ */
313
+ async judge(input, options) {
314
+ if (!isJudgmentInput(input)) {
315
+ throw new Error("Judgment input must be text, an object, or an array of JSON-compatible values");
316
+ }
317
+ const questions = normalizeQuestions(options.questions);
318
+ const model = options.model || this.defaults.judgment || DEFAULT_MODELS.JUDGMENT;
319
+ const provider = this.judgmentProvider(model, options.provider);
320
+ if (!provider.judge) {
321
+ throw new UnsupportedFeatureError(provider.id, "judge");
322
+ }
323
+ const context = {
324
+ requestId: randomUUID(),
325
+ provider: provider.id,
326
+ model,
327
+ judgmentInput: input,
328
+ judgmentOptions: options,
329
+ state: {}
330
+ };
331
+ const middlewares = [...this.middlewares, ...(options.middlewares || [])];
332
+ try {
333
+ await runMiddleware(middlewares, "onRequest", context);
334
+ const response = await provider.judge({
335
+ model,
336
+ input: context.judgmentInput ?? input,
337
+ questions,
338
+ providerOptions: options.providerOptions,
339
+ requestTimeout: options.requestTimeout ?? this.config.requestTimeout
340
+ });
341
+ // Priced by the requested model, which is what the registry knows; the
342
+ // response names the exact build that answered (jev-latest comes back as
343
+ // e.g. jev-1.13.0). An unpriced model leaves cost undefined rather than a
344
+ // guessed number.
345
+ const usage = ModelRegistry.calculateCost(response.usage, model, provider.id);
346
+ const judgment = buildJudgment({ ...response, usage }, questions);
347
+ await runMiddleware(middlewares, "onResponse", context, judgment);
348
+ return judgment;
349
+ }
350
+ catch (error) {
351
+ await runMiddleware(middlewares, "onError", context, error);
352
+ throw error;
353
+ }
354
+ }
355
+ /**
356
+ * Picks the provider that answers judgments for a model: an explicit choice
357
+ * first, then the registry's owner of a known judgment model, then this
358
+ * instance's own provider - which is how a model the registry does not know,
359
+ * such as one on a local Jev-compatible server, reaches the provider it was
360
+ * scoped to.
361
+ */
362
+ judgmentProvider(model, explicit) {
363
+ const known = ModelRegistry.find(model);
364
+ const owner = explicit ??
365
+ (known &&
366
+ known.id.toLowerCase() === model.toLowerCase() &&
367
+ known.capabilities?.includes("judgment")
368
+ ? known.provider
369
+ : undefined);
370
+ if (!owner || owner === this.provider?.id) {
371
+ if (!this.provider) {
372
+ // Guessing a provider for an unknown model would send the request (and
373
+ // the credentials) somewhere the caller did not choose.
374
+ throw new ConfigurationError(`Unknown judgment model '${model}': no provider is known to serve it. ` +
375
+ `Pass \`provider\` (for example "typesafe"), or call judge on ` +
376
+ `NodeLLM.withProvider("typesafe").`);
377
+ }
378
+ return this.provider;
379
+ }
380
+ PROVIDER_REGISTRARS[owner]?.();
381
+ return providerRegistry.resolve(owner, this.config);
382
+ }
284
383
  }
285
384
  export { Transcription, Moderation, Embedding, ModelRegistry, PricingRegistry };
286
385
  /**
@@ -330,7 +429,8 @@ export function createLLM(options = {}) {
330
429
  chat: options.defaultChatModel,
331
430
  transcription: options.defaultTranscriptionModel,
332
431
  moderation: options.defaultModerationModel,
333
- embedding: options.defaultEmbeddingModel
432
+ embedding: options.defaultEmbeddingModel,
433
+ judgment: options.defaultJudgmentModel
334
434
  };
335
435
  return new NodeLLMCore(baseConfig, providerInstance, retry, options.middlewares || [], defaults);
336
436
  }
@@ -25,30 +25,23 @@ export declare class ModelRegistry {
25
25
  /**
26
26
  * Calculate cost for usage.
27
27
  */
28
- static calculateCost(usage: {
29
- input_tokens: number;
30
- output_tokens: number;
31
- total_tokens: number;
32
- cached_tokens?: number;
33
- reasoning_tokens?: number;
34
- image_tokens?: number;
35
- }, modelId: string, provider: string): {
36
- input_tokens: number;
37
- output_tokens: number;
38
- total_tokens: number;
39
- cached_tokens?: number;
40
- reasoning_tokens?: number;
41
- image_tokens?: number;
42
- } | {
43
- input_cost: number;
44
- output_cost: number;
45
- cost: number;
28
+ /**
29
+ * Returns the usage with `input_cost`, `output_cost` and `cost` added when the
30
+ * model has known pricing. Without pricing the usage comes back unchanged and
31
+ * the cost fields are undefined - declared on the return type either way, so
32
+ * callers can read `.cost` without a cast.
33
+ */
34
+ static calculateCost<U extends {
46
35
  input_tokens: number;
47
36
  output_tokens: number;
48
37
  total_tokens: number;
49
38
  cached_tokens?: number;
50
39
  reasoning_tokens?: number;
51
40
  image_tokens?: number;
41
+ }>(usage: U, modelId: string, provider: string): U & {
42
+ input_cost?: number;
43
+ output_cost?: number;
44
+ cost?: number;
52
45
  };
53
46
  }
54
47
  //# sourceMappingURL=ModelRegistry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ModelRegistry.d.ts","sourceRoot":"","sources":["../../src/models/ModelRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAInC,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,MAAM,CAA6C;IAElE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAmBlE;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,IAAI;IAe1C;;OAEG;IACH,MAAM,CAAC,GAAG,IAAI,KAAK,EAAE;IAIrB;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKhF;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAwB/E;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK9E;;OAEG;IACH,MAAM,CAAC,aAAa,CAClB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,EACD,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM;sBARA,MAAM;uBACL,MAAM;sBACP,MAAM;wBACJ,MAAM;2BACH,MAAM;uBACV,MAAM;;;;;sBALP,MAAM;uBACL,MAAM;sBACP,MAAM;wBACJ,MAAM;2BACH,MAAM;uBACV,MAAM;;CAoD1B"}
1
+ {"version":3,"file":"ModelRegistry.d.ts","sourceRoot":"","sources":["../../src/models/ModelRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAInC,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAC,MAAM,CAA6C;IAElE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAmBlE;;OAEG;IACH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,GAAG,KAAK,EAAE,GAAG,IAAI;IAe1C;;OAEG;IACH,MAAM,CAAC,GAAG,IAAI,KAAK,EAAE;IAIrB;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAKhF;;OAEG;IACH,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAwB/E;;OAEG;IACH,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK9E;;OAEG;IACH;;;;;OAKG;IACH,MAAM,CAAC,aAAa,CAClB,CAAC,SAAS;QACR,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,EAAE,MAAM,CAAC;QACtB,YAAY,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,EAED,KAAK,EAAE,CAAC,EACR,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,CAAC,GAAG;QAAE,UAAU,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;CAgDpE"}
@@ -77,6 +77,12 @@ export class ModelRegistry {
77
77
  /**
78
78
  * Calculate cost for usage.
79
79
  */
80
+ /**
81
+ * Returns the usage with `input_cost`, `output_cost` and `cost` added when the
82
+ * model has known pricing. Without pricing the usage comes back unchanged and
83
+ * the cost fields are undefined - declared on the return type either way, so
84
+ * callers can read `.cost` without a cast.
85
+ */
80
86
  static calculateCost(usage, modelId, provider) {
81
87
  const pricing = PricingRegistry.getPricing(modelId, provider);
82
88
  if (!pricing) {