@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,107 @@
1
+ import { NodeLLMCore } from "../llm.js";
2
+ import { JudgmentInput } from "../providers/Provider.js";
3
+ import { LazyValue } from "../agent/Agent.js";
4
+ import { QuestionMap } from "./Question.js";
5
+ import { JudgmentResult } from "./Judgment.js";
6
+ /** The questions a Judge class declares, once resolved. */
7
+ export type QuestionsOf<T> = T extends {
8
+ questions: infer Q;
9
+ } ? Q extends (...args: never[]) => infer R ? R extends QuestionMap ? R : never : Q extends QuestionMap ? Q : never : never;
10
+ export interface JudgeCallOptions<I = Record<string, unknown>> {
11
+ /** Values for the inputs the judge declares; available to lazy settings. */
12
+ inputs?: I;
13
+ /** Overrides the judge's model for this call. */
14
+ model?: string;
15
+ /** Overrides the judge's provider for this call. */
16
+ provider?: string;
17
+ /** Merged over the judge's own providerOptions. */
18
+ providerOptions?: Record<string, unknown>;
19
+ requestTimeout?: number;
20
+ /** The NodeLLM instance to judge with. Defaults to the global NodeLLM. */
21
+ llm?: NodeLLMCore;
22
+ }
23
+ /**
24
+ * A reusable set of typed questions about your application data.
25
+ *
26
+ * Subclass it and declare `questions`; call `judge` with the input. Answers are
27
+ * typed from the declaration, so a choice's answer is a union of its options.
28
+ *
29
+ * @example
30
+ * class TicketTriage extends Judge {
31
+ * static questions = {
32
+ * urgent: probability("Does this need attention today?"),
33
+ * department: choice("Which team should handle this?", {
34
+ * billing: "Payments and refunds",
35
+ * technical: "Bugs and integrations",
36
+ * other: null
37
+ * }),
38
+ * frustration: score("How frustrated is the customer?", ["Calm", "Frustrated", "Angry"])
39
+ * };
40
+ * }
41
+ *
42
+ * const judgment = await TicketTriage.judge("Please refund the duplicate charge today.");
43
+ * judgment.urgent.probability; // number
44
+ * judgment.department.choice; // "billing" | "technical" | "other"
45
+ *
46
+ * Settings can depend on runtime data. Declare the inputs a judge needs and
47
+ * pass them to `judge`; `questions`, `model` and `providerOptions` may be
48
+ * functions of those inputs, resolved once per judgment.
49
+ *
50
+ * @example
51
+ * class TeamRouter extends Judge {
52
+ * static inputs = ["teams"] as const;
53
+ * static questions = ({ teams }: { teams: Team[] }) => ({
54
+ * team: choice("Which team should handle this?",
55
+ * Object.fromEntries(teams.map((t) => [t.slug, t.description])))
56
+ * });
57
+ * }
58
+ * await TeamRouter.judge(ticket.body, { inputs: { teams } });
59
+ */
60
+ export declare abstract class Judge {
61
+ /** The judgment model. Defaults to the instance default, then `jev-latest`. */
62
+ static model?: LazyValue<string, never>;
63
+ /** Routes to a specific provider; normally inferred from the model. */
64
+ static provider?: string;
65
+ /** Names of the inputs `judge` must be given. */
66
+ static inputs?: readonly string[];
67
+ /** The questions, or a function of the declared inputs returning them. */
68
+ static questions: LazyValue<QuestionMap, never>;
69
+ /** Provider-specific request fields, or a function of the inputs. */
70
+ static providerOptions?: LazyValue<Record<string, unknown>, never>;
71
+ /**
72
+ * Judges the input and returns typed answers. The input is text, an object,
73
+ * or an array of JSON-compatible values - or a function of the inputs that
74
+ * returns one.
75
+ */
76
+ static judge<T extends typeof Judge, I extends Record<string, unknown> = Record<string, unknown>>(this: T, input: LazyValue<JudgmentInput, I>, options?: JudgeCallOptions<I>): Promise<JudgmentResult<QuestionsOf<T>>>;
77
+ }
78
+ /**
79
+ * Defines a judge without a class, mirroring `defineAgent`.
80
+ *
81
+ * @example
82
+ * const Urgency = defineJudge({
83
+ * questions: { urgent: probability("Does this need attention today?") }
84
+ * });
85
+ * (await Urgency.judge("The site is down")).urgent.probability;
86
+ */
87
+ export declare function defineJudge<const Q extends QuestionMap>(definition: {
88
+ questions: LazyValue<Q, never>;
89
+ model?: LazyValue<string, never>;
90
+ provider?: string;
91
+ inputs?: readonly string[];
92
+ providerOptions?: LazyValue<Record<string, unknown>, never>;
93
+ }): {
94
+ new (): {};
95
+ questions: LazyValue<Q, never>;
96
+ model: LazyValue<string, never> | undefined;
97
+ provider: string | undefined;
98
+ inputs: readonly string[] | undefined;
99
+ providerOptions: LazyValue<Record<string, unknown>, never> | undefined;
100
+ /**
101
+ * Judges the input and returns typed answers. The input is text, an object,
102
+ * or an array of JSON-compatible values - or a function of the inputs that
103
+ * returns one.
104
+ */
105
+ judge<T extends typeof Judge, I extends Record<string, unknown> = Record<string, unknown>>(this: T, input: LazyValue<JudgmentInput, I>, options?: JudgeCallOptions<I>): Promise<JudgmentResult<QuestionsOf<T>>>;
106
+ };
107
+ //# sourceMappingURL=Judge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Judge.d.ts","sourceRoot":"","sources":["../../src/judge/Judge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ import { NodeLLM } from "../llm.js";
2
+ /**
3
+ * A reusable set of typed questions about your application data.
4
+ *
5
+ * Subclass it and declare `questions`; call `judge` with the input. Answers are
6
+ * typed from the declaration, so a choice's answer is a union of its options.
7
+ *
8
+ * @example
9
+ * class TicketTriage extends Judge {
10
+ * static questions = {
11
+ * urgent: probability("Does this need attention today?"),
12
+ * department: choice("Which team should handle this?", {
13
+ * billing: "Payments and refunds",
14
+ * technical: "Bugs and integrations",
15
+ * other: null
16
+ * }),
17
+ * frustration: score("How frustrated is the customer?", ["Calm", "Frustrated", "Angry"])
18
+ * };
19
+ * }
20
+ *
21
+ * const judgment = await TicketTriage.judge("Please refund the duplicate charge today.");
22
+ * judgment.urgent.probability; // number
23
+ * judgment.department.choice; // "billing" | "technical" | "other"
24
+ *
25
+ * Settings can depend on runtime data. Declare the inputs a judge needs and
26
+ * pass them to `judge`; `questions`, `model` and `providerOptions` may be
27
+ * functions of those inputs, resolved once per judgment.
28
+ *
29
+ * @example
30
+ * class TeamRouter extends Judge {
31
+ * static inputs = ["teams"] as const;
32
+ * static questions = ({ teams }: { teams: Team[] }) => ({
33
+ * team: choice("Which team should handle this?",
34
+ * Object.fromEntries(teams.map((t) => [t.slug, t.description])))
35
+ * });
36
+ * }
37
+ * await TeamRouter.judge(ticket.body, { inputs: { teams } });
38
+ */
39
+ export class Judge {
40
+ /** The judgment model. Defaults to the instance default, then `jev-latest`. */
41
+ static model;
42
+ /** Routes to a specific provider; normally inferred from the model. */
43
+ static provider;
44
+ /** Names of the inputs `judge` must be given. */
45
+ static inputs;
46
+ /** The questions, or a function of the declared inputs returning them. */
47
+ static questions;
48
+ /** Provider-specific request fields, or a function of the inputs. */
49
+ static providerOptions;
50
+ /**
51
+ * Judges the input and returns typed answers. The input is text, an object,
52
+ * or an array of JSON-compatible values - or a function of the inputs that
53
+ * returns one.
54
+ */
55
+ static async judge(input, options = {}) {
56
+ const inputs = (options.inputs ?? {});
57
+ checkInputs(this, inputs);
58
+ const resolve = (value) => typeof value === "function" ? value(inputs) : value;
59
+ const questions = resolve(this.questions);
60
+ if (!questions) {
61
+ throw new Error(`${this.name} declares no questions`);
62
+ }
63
+ const declaredOptions = resolve(this.providerOptions);
64
+ const providerOptions = declaredOptions || options.providerOptions
65
+ ? { ...declaredOptions, ...options.providerOptions }
66
+ : undefined;
67
+ const llm = options.llm ?? NodeLLM;
68
+ return llm.judge(resolve(input), {
69
+ questions: questions,
70
+ model: options.model ?? resolve(this.model),
71
+ provider: options.provider ?? this.provider,
72
+ providerOptions,
73
+ requestTimeout: options.requestTimeout
74
+ });
75
+ }
76
+ }
77
+ function checkInputs(judge, inputs) {
78
+ const declared = judge.inputs ?? [];
79
+ const given = Object.keys(inputs);
80
+ const missing = declared.filter((name) => !(name in inputs));
81
+ const unknown = given.filter((name) => !declared.includes(name));
82
+ if (missing.length > 0)
83
+ throw new Error(`${judge.name} is missing inputs: ${missing.join(", ")}`);
84
+ if (unknown.length > 0)
85
+ throw new Error(`${judge.name} does not declare inputs: ${unknown.join(", ")}`);
86
+ }
87
+ /**
88
+ * Defines a judge without a class, mirroring `defineAgent`.
89
+ *
90
+ * @example
91
+ * const Urgency = defineJudge({
92
+ * questions: { urgent: probability("Does this need attention today?") }
93
+ * });
94
+ * (await Urgency.judge("The site is down")).urgent.probability;
95
+ */
96
+ export function defineJudge(definition) {
97
+ return class extends Judge {
98
+ static questions = definition.questions;
99
+ static model = definition.model;
100
+ static provider = definition.provider;
101
+ static inputs = definition.inputs;
102
+ static providerOptions = definition.providerOptions;
103
+ };
104
+ }
@@ -0,0 +1,116 @@
1
+ import { JudgmentResponse, Usage } from "../providers/Provider.js";
2
+ import { ChoiceQuestion, Description, ProbabilityQuestion, NamedQuestion, QuestionDefinition, QuestionMap, ScoreQuestion } from "./Question.js";
3
+ /** The probability that a yes/no statement holds, between 0 and 1. */
4
+ export declare class ProbabilityAnswer {
5
+ readonly probability: number;
6
+ readonly type: "probability";
7
+ constructor(probability: number);
8
+ toJSON(): {
9
+ type: "probability";
10
+ probability: number;
11
+ };
12
+ }
13
+ /**
14
+ * The selected option, with a probability for every option. `confidence`
15
+ * describes how concentrated the distribution is; it is not a guarantee that
16
+ * the choice is correct.
17
+ */
18
+ export declare class ChoiceAnswer<K extends string = string> {
19
+ readonly choice: K;
20
+ readonly probabilities: Readonly<Record<K, number>>;
21
+ readonly confidence: number;
22
+ readonly type: "choice";
23
+ constructor(choice: K, probabilities: Readonly<Record<K, number>>, confidence: number);
24
+ toJSON(): {
25
+ type: "choice";
26
+ choice: K;
27
+ probabilities: Readonly<Record<K, number>>;
28
+ confidence: number;
29
+ };
30
+ }
31
+ /**
32
+ * A probability-weighted position on an ordered scale. Level 0 is the first
33
+ * level, so with three levels the score runs from 0 to 2 and can fall between
34
+ * them. `probabilities` is keyed by level index.
35
+ */
36
+ export declare class ScoreAnswer {
37
+ readonly score: number;
38
+ readonly levels: readonly Description[];
39
+ readonly probabilities: Readonly<Record<number, number>>;
40
+ readonly confidence: number;
41
+ readonly type: "score";
42
+ constructor(score: number, levels: readonly Description[], probabilities: Readonly<Record<number, number>>, confidence: number);
43
+ toJSON(): {
44
+ type: "score";
45
+ score: number;
46
+ levels: readonly Description[];
47
+ probabilities: Readonly<Record<number, number>>;
48
+ confidence: number;
49
+ };
50
+ }
51
+ export type Answer = ProbabilityAnswer | ChoiceAnswer | ScoreAnswer;
52
+ /** The answer type a question produces. */
53
+ export type AnswerFor<D extends QuestionDefinition> = D extends ProbabilityQuestion ? ProbabilityAnswer : D extends ChoiceQuestion<infer K> ? ChoiceAnswer<K> : D extends ScoreQuestion ? ScoreAnswer : never;
54
+ /** Answers keyed by question name, typed from the questions asked. */
55
+ export type AnswersOf<Q extends QuestionMap> = {
56
+ readonly [N in keyof Q]: AnswerFor<Q[N]>;
57
+ };
58
+ /**
59
+ * The typed answers to a set of questions, with the model that answered them
60
+ * and the tokens it used.
61
+ *
62
+ * Answers are available by name - `judgment.urgent.probability` - and through
63
+ * `judgment.answers`. A question named like one of Judgment's own members
64
+ * (`model`, `usage`, `get`, ...) is only reachable through `answers` or `get`.
65
+ */
66
+ export declare class Judgment<Q extends QuestionMap = QuestionMap> {
67
+ readonly answers: AnswersOf<Q>;
68
+ /** The model that answered, as reported by the provider. */
69
+ readonly model: string;
70
+ /** Token usage. `cost` is present only when the model has known pricing. */
71
+ readonly usage: Usage;
72
+ /** The provider's raw response. */
73
+ readonly raw?: unknown | undefined;
74
+ constructor(answers: AnswersOf<Q>,
75
+ /** The model that answered, as reported by the provider. */
76
+ model: string,
77
+ /** Token usage. `cost` is present only when the model has known pricing. */
78
+ usage: Usage,
79
+ /** The provider's raw response. */
80
+ raw?: unknown | undefined);
81
+ /** Returns the named answer, or undefined when there is none. */
82
+ get<N extends keyof Q & string>(name: N): AnswersOf<Q>[N] | undefined;
83
+ /** Returns the named answer, throwing when there is none. */
84
+ fetch<N extends keyof Q & string>(name: N): AnswersOf<Q>[N];
85
+ [Symbol.iterator](): IterableIterator<[keyof Q & string, Answer]>;
86
+ toJSON(): {
87
+ model: string;
88
+ answers: {
89
+ [k: string]: {
90
+ type: "probability";
91
+ probability: number;
92
+ } | {
93
+ type: "score";
94
+ score: number;
95
+ levels: readonly Description[];
96
+ probabilities: Readonly<Record<number, number>>;
97
+ confidence: number;
98
+ } | {
99
+ type: "choice";
100
+ choice: string;
101
+ probabilities: Readonly<Record<string, number>>;
102
+ confidence: number;
103
+ };
104
+ };
105
+ usage: Usage;
106
+ };
107
+ }
108
+ /** A Judgment whose answers can also be read directly by question name. */
109
+ export type JudgmentResult<Q extends QuestionMap = QuestionMap> = Judgment<Q> & Omit<AnswersOf<Q>, keyof Judgment<Q>>;
110
+ /**
111
+ * Wraps a provider's answers in typed, frozen answer objects. Every question
112
+ * must come back answered with the type it was asked as; anything else means
113
+ * the provider and the request disagree, and is reported rather than guessed.
114
+ */
115
+ export declare function buildJudgment<Q extends QuestionMap>(response: JudgmentResponse, questions: NamedQuestion[]): JudgmentResult<Q>;
116
+ //# sourceMappingURL=Judgment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Judgment.d.ts","sourceRoot":"","sources":["../../src/judge/Judgment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ /** The probability that a yes/no statement holds, between 0 and 1. */
2
+ export class ProbabilityAnswer {
3
+ probability;
4
+ type = "probability";
5
+ constructor(probability) {
6
+ this.probability = probability;
7
+ Object.freeze(this);
8
+ }
9
+ toJSON() {
10
+ return { type: this.type, probability: this.probability };
11
+ }
12
+ }
13
+ /**
14
+ * The selected option, with a probability for every option. `confidence`
15
+ * describes how concentrated the distribution is; it is not a guarantee that
16
+ * the choice is correct.
17
+ */
18
+ export class ChoiceAnswer {
19
+ choice;
20
+ probabilities;
21
+ confidence;
22
+ type = "choice";
23
+ constructor(choice, probabilities, confidence) {
24
+ this.choice = choice;
25
+ this.probabilities = probabilities;
26
+ this.confidence = confidence;
27
+ Object.freeze(this.probabilities);
28
+ Object.freeze(this);
29
+ }
30
+ toJSON() {
31
+ return {
32
+ type: this.type,
33
+ choice: this.choice,
34
+ probabilities: this.probabilities,
35
+ confidence: this.confidence
36
+ };
37
+ }
38
+ }
39
+ /**
40
+ * A probability-weighted position on an ordered scale. Level 0 is the first
41
+ * level, so with three levels the score runs from 0 to 2 and can fall between
42
+ * them. `probabilities` is keyed by level index.
43
+ */
44
+ export class ScoreAnswer {
45
+ score;
46
+ levels;
47
+ probabilities;
48
+ confidence;
49
+ type = "score";
50
+ constructor(score, levels, probabilities, confidence) {
51
+ this.score = score;
52
+ this.levels = levels;
53
+ this.probabilities = probabilities;
54
+ this.confidence = confidence;
55
+ Object.freeze(this.levels);
56
+ Object.freeze(this.probabilities);
57
+ Object.freeze(this);
58
+ }
59
+ toJSON() {
60
+ return {
61
+ type: this.type,
62
+ score: this.score,
63
+ levels: this.levels,
64
+ probabilities: this.probabilities,
65
+ confidence: this.confidence
66
+ };
67
+ }
68
+ }
69
+ /**
70
+ * The typed answers to a set of questions, with the model that answered them
71
+ * and the tokens it used.
72
+ *
73
+ * Answers are available by name - `judgment.urgent.probability` - and through
74
+ * `judgment.answers`. A question named like one of Judgment's own members
75
+ * (`model`, `usage`, `get`, ...) is only reachable through `answers` or `get`.
76
+ */
77
+ export class Judgment {
78
+ answers;
79
+ model;
80
+ usage;
81
+ raw;
82
+ constructor(answers,
83
+ /** The model that answered, as reported by the provider. */
84
+ model,
85
+ /** Token usage. `cost` is present only when the model has known pricing. */
86
+ usage,
87
+ /** The provider's raw response. */
88
+ raw) {
89
+ this.answers = answers;
90
+ this.model = model;
91
+ this.usage = usage;
92
+ this.raw = raw;
93
+ Object.freeze(this.answers);
94
+ for (const name of Object.keys(answers)) {
95
+ if (name in this)
96
+ continue;
97
+ Object.defineProperty(this, name, {
98
+ value: answers[name],
99
+ enumerable: false
100
+ });
101
+ }
102
+ Object.freeze(this);
103
+ }
104
+ /** Returns the named answer, or undefined when there is none. */
105
+ get(name) {
106
+ return Object.prototype.hasOwnProperty.call(this.answers, name)
107
+ ? this.answers[name]
108
+ : undefined;
109
+ }
110
+ /** Returns the named answer, throwing when there is none. */
111
+ fetch(name) {
112
+ const answer = this.get(name);
113
+ if (answer === undefined)
114
+ throw new Error(`No answer named '${name}' in this judgment`);
115
+ return answer;
116
+ }
117
+ *[Symbol.iterator]() {
118
+ for (const [name, answer] of Object.entries(this.answers)) {
119
+ yield [name, answer];
120
+ }
121
+ }
122
+ toJSON() {
123
+ return {
124
+ model: this.model,
125
+ answers: Object.fromEntries(Object.entries(this.answers).map(([name, answer]) => [name, answer.toJSON()])),
126
+ usage: this.usage
127
+ };
128
+ }
129
+ }
130
+ /**
131
+ * Wraps a provider's answers in typed, frozen answer objects. Every question
132
+ * must come back answered with the type it was asked as; anything else means
133
+ * the provider and the request disagree, and is reported rather than guessed.
134
+ */
135
+ export function buildJudgment(response, questions) {
136
+ const answers = {};
137
+ for (const question of questions) {
138
+ const data = response.answers[question.name];
139
+ if (!data)
140
+ throw new Error(`The provider returned no answer for '${question.name}'`);
141
+ if (data.type !== question.type) {
142
+ throw new Error(`The provider answered '${question.name}' as a ${data.type}, but it was asked as a ${question.type}`);
143
+ }
144
+ switch (data.type) {
145
+ case "probability":
146
+ answers[question.name] = new ProbabilityAnswer(data.probability);
147
+ break;
148
+ case "choice":
149
+ answers[question.name] = new ChoiceAnswer(data.choice, { ...data.probabilities }, data.confidence);
150
+ break;
151
+ case "score":
152
+ // Copy the levels: the answer is frozen, and freezing the caller's own
153
+ // question definition would be a surprising side effect.
154
+ answers[question.name] = new ScoreAnswer(data.score, structuredClone(question.levels), { ...data.probabilities }, data.confidence);
155
+ break;
156
+ }
157
+ }
158
+ return new Judgment(answers, response.model, response.usage, response.raw);
159
+ }
@@ -0,0 +1,91 @@
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
+ /** A JSON-compatible value, used for descriptions and structured input. */
11
+ export type JsonValue = string | number | boolean | null | JsonValue[] | {
12
+ [key: string]: JsonValue;
13
+ };
14
+ /**
15
+ * Describes a question, an option, or a level. Text is usual; an object or
16
+ * array carries structured instructions, and null means "no description".
17
+ */
18
+ export type Description = string | null | JsonValue[] | {
19
+ [key: string]: JsonValue;
20
+ };
21
+ /** The yes/no boundary of a probability question. Either side is optional. */
22
+ export interface ProbabilityCriteria {
23
+ yes?: Description;
24
+ no?: Description;
25
+ }
26
+ export interface ProbabilityQuestion {
27
+ type: "probability";
28
+ instructions?: Description;
29
+ criteria?: ProbabilityCriteria;
30
+ }
31
+ export interface ChoiceQuestion<K extends string = string> {
32
+ type: "choice";
33
+ instructions?: Description;
34
+ options: Record<K, Description>;
35
+ }
36
+ export interface ScoreQuestion {
37
+ type: "score";
38
+ instructions?: Description;
39
+ levels: Description[];
40
+ }
41
+ export type QuestionDefinition = ProbabilityQuestion | ChoiceQuestion | ScoreQuestion;
42
+ /** Questions keyed by the name your code reads the answer from. */
43
+ export type QuestionMap = Record<string, QuestionDefinition>;
44
+ /** A question after validation, carrying its name for the provider. */
45
+ export type NamedQuestion = QuestionDefinition & {
46
+ name: string;
47
+ };
48
+ /**
49
+ * Declares a yes/no question whose answer is the probability of yes. A value
50
+ * near 0.5 means yes and no are about equally likely, not "medium"; use a
51
+ * score to measure degree.
52
+ *
53
+ * @example
54
+ * probability("Does this need attention today?", {
55
+ * yes: "An explicit deadline today or an ongoing outage",
56
+ * no: "A general question with no time pressure"
57
+ * })
58
+ */
59
+ export declare function probability(instructions?: Description, criteria?: ProbabilityCriteria): ProbabilityQuestion;
60
+ /**
61
+ * Declares a question that selects one named option and returns a probability
62
+ * for every option. Include a catch-all such as `other` when none of the
63
+ * specific options may fit. Use null for an option that needs no description.
64
+ *
65
+ * @example
66
+ * choice("Which team should handle this?", {
67
+ * billing: "Payments and refunds",
68
+ * technical: "Bugs and integrations",
69
+ * other: null
70
+ * })
71
+ */
72
+ export declare function choice<const O extends Record<string, Description>>(instructions: Description | undefined, options: O): ChoiceQuestion<Extract<keyof O, string>>;
73
+ /**
74
+ * Declares a question scored against ordered levels. The first level is 0, the
75
+ * second 1, and so on; the answer is probability-weighted and can fall between
76
+ * levels. Describe each level concretely.
77
+ *
78
+ * @example
79
+ * score("How frustrated is the customer?", ["Calm", "Frustrated", "Angry"])
80
+ */
81
+ export declare function score(instructions: Description | undefined, levels: Description[]): ScoreQuestion;
82
+ /**
83
+ * Validates every question and returns them in declaration order with their
84
+ * names attached. Rejects the problems a provider would otherwise report as an
85
+ * opaque 400: unknown types, empty choices or scales, and probability criteria
86
+ * that describe anything other than yes and no.
87
+ */
88
+ export declare function normalizeQuestions(questions: QuestionMap): NamedQuestion[];
89
+ /** True when the value can be sent as judgment input. */
90
+ export declare function isJudgmentInput(value: unknown): boolean;
91
+ //# sourceMappingURL=Question.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Question.d.ts","sourceRoot":"","sources":["../../src/judge/Question.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,2EAA2E;AAC3E,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEjC;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAErF,8EAA8E;AAC9E,MAAM,WAAW,mBAAmB;IAClC,GAAG,CAAC,EAAE,WAAW,CAAC;IAClB,EAAE,CAAC,EAAE,WAAW,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,aAAa,CAAC;IACpB,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,EAAE,mBAAmB,CAAC;CAChC;AAED,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM;IACvD,IAAI,EAAE,QAAQ,CAAC;IACf,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,MAAM,MAAM,kBAAkB,GAAG,mBAAmB,GAAG,cAAc,GAAG,aAAa,CAAC;AAEtF,mEAAmE;AACnE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;AAE7D,uEAAuE;AACvE,MAAM,MAAM,aAAa,GAAG,kBAAkB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CACzB,YAAY,CAAC,EAAE,WAAW,EAC1B,QAAQ,CAAC,EAAE,mBAAmB,GAC7B,mBAAmB,CAErB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,EAChE,YAAY,EAAE,WAAW,GAAG,SAAS,EACrC,OAAO,EAAE,CAAC,GACT,cAAc,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAE1C;AAED;;;;;;;GAOG;AACH,wBAAgB,KAAK,CAAC,YAAY,EAAE,WAAW,GAAG,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,aAAa,CAEjG;AAyCD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,WAAW,GAAG,aAAa,EAAE,CAmC1E;AAuDD,yDAAyD;AACzD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAKvD"}