@aid-framework/runtime 0.0.0 → 0.1.39

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 (188) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +53 -0
  3. package/dist/.tsbuildinfo +1 -0
  4. package/dist/agents/deep_agents.d.ts +78 -0
  5. package/dist/agents/deep_agents.d.ts.map +1 -0
  6. package/dist/agents/deep_agents.js +477 -0
  7. package/dist/agents/deep_agents.js.map +1 -0
  8. package/dist/agents/engine.d.ts +85 -0
  9. package/dist/agents/engine.d.ts.map +1 -0
  10. package/dist/agents/engine.js +129 -0
  11. package/dist/agents/engine.js.map +1 -0
  12. package/dist/agents/gateway_chat_model.d.ts +151 -0
  13. package/dist/agents/gateway_chat_model.d.ts.map +1 -0
  14. package/dist/agents/gateway_chat_model.js +350 -0
  15. package/dist/agents/gateway_chat_model.js.map +1 -0
  16. package/dist/agents/guardrail_middleware.d.ts +57 -0
  17. package/dist/agents/guardrail_middleware.d.ts.map +1 -0
  18. package/dist/agents/guardrail_middleware.js +85 -0
  19. package/dist/agents/guardrail_middleware.js.map +1 -0
  20. package/dist/agents/guardrails.d.ts +124 -0
  21. package/dist/agents/guardrails.d.ts.map +1 -0
  22. package/dist/agents/guardrails.js +336 -0
  23. package/dist/agents/guardrails.js.map +1 -0
  24. package/dist/agents/index.d.ts +15 -0
  25. package/dist/agents/index.d.ts.map +1 -0
  26. package/dist/agents/index.js +15 -0
  27. package/dist/agents/index.js.map +1 -0
  28. package/dist/agents/ir.d.ts +144 -0
  29. package/dist/agents/ir.d.ts.map +1 -0
  30. package/dist/agents/ir.js +513 -0
  31. package/dist/agents/ir.js.map +1 -0
  32. package/dist/agents/loop.d.ts +145 -0
  33. package/dist/agents/loop.d.ts.map +1 -0
  34. package/dist/agents/loop.js +1025 -0
  35. package/dist/agents/loop.js.map +1 -0
  36. package/dist/agents/memory.d.ts +115 -0
  37. package/dist/agents/memory.d.ts.map +1 -0
  38. package/dist/agents/memory.js +258 -0
  39. package/dist/agents/memory.js.map +1 -0
  40. package/dist/agents/state.d.ts +137 -0
  41. package/dist/agents/state.d.ts.map +1 -0
  42. package/dist/agents/state.js +255 -0
  43. package/dist/agents/state.js.map +1 -0
  44. package/dist/concurrency.d.ts +36 -0
  45. package/dist/concurrency.d.ts.map +1 -0
  46. package/dist/concurrency.js +86 -0
  47. package/dist/concurrency.js.map +1 -0
  48. package/dist/control.d.ts +116 -0
  49. package/dist/control.d.ts.map +1 -0
  50. package/dist/control.js +281 -0
  51. package/dist/control.js.map +1 -0
  52. package/dist/cost.d.ts +95 -0
  53. package/dist/cost.d.ts.map +1 -0
  54. package/dist/cost.js +161 -0
  55. package/dist/cost.js.map +1 -0
  56. package/dist/errors.d.ts +213 -0
  57. package/dist/errors.d.ts.map +1 -0
  58. package/dist/errors.js +316 -0
  59. package/dist/errors.js.map +1 -0
  60. package/dist/evals/dataset.d.ts +45 -0
  61. package/dist/evals/dataset.d.ts.map +1 -0
  62. package/dist/evals/dataset.js +147 -0
  63. package/dist/evals/dataset.js.map +1 -0
  64. package/dist/evals/gate.d.ts +236 -0
  65. package/dist/evals/gate.d.ts.map +1 -0
  66. package/dist/evals/gate.js +572 -0
  67. package/dist/evals/gate.js.map +1 -0
  68. package/dist/evals/metrics.d.ts +141 -0
  69. package/dist/evals/metrics.d.ts.map +1 -0
  70. package/dist/evals/metrics.js +364 -0
  71. package/dist/evals/metrics.js.map +1 -0
  72. package/dist/evals/predicate.d.ts +79 -0
  73. package/dist/evals/predicate.d.ts.map +1 -0
  74. package/dist/evals/predicate.js +178 -0
  75. package/dist/evals/predicate.js.map +1 -0
  76. package/dist/evals/runner.d.ts +94 -0
  77. package/dist/evals/runner.d.ts.map +1 -0
  78. package/dist/evals/runner.js +202 -0
  79. package/dist/evals/runner.js.map +1 -0
  80. package/dist/gateway.d.ts +118 -0
  81. package/dist/gateway.d.ts.map +1 -0
  82. package/dist/gateway.js +250 -0
  83. package/dist/gateway.js.map +1 -0
  84. package/dist/index.d.ts +83 -0
  85. package/dist/index.d.ts.map +1 -0
  86. package/dist/index.js +59 -0
  87. package/dist/index.js.map +1 -0
  88. package/dist/internal/json.d.ts +44 -0
  89. package/dist/internal/json.d.ts.map +1 -0
  90. package/dist/internal/json.js +90 -0
  91. package/dist/internal/json.js.map +1 -0
  92. package/dist/internal/text.d.ts +17 -0
  93. package/dist/internal/text.d.ts.map +1 -0
  94. package/dist/internal/text.js +22 -0
  95. package/dist/internal/text.js.map +1 -0
  96. package/dist/pipeline.d.ts +80 -0
  97. package/dist/pipeline.d.ts.map +1 -0
  98. package/dist/pipeline.js +159 -0
  99. package/dist/pipeline.js.map +1 -0
  100. package/dist/policy.d.ts +52 -0
  101. package/dist/policy.d.ts.map +1 -0
  102. package/dist/policy.js +199 -0
  103. package/dist/policy.js.map +1 -0
  104. package/dist/prompts.d.ts +86 -0
  105. package/dist/prompts.d.ts.map +1 -0
  106. package/dist/prompts.js +337 -0
  107. package/dist/prompts.js.map +1 -0
  108. package/dist/providers/base.d.ts +19 -0
  109. package/dist/providers/base.d.ts.map +1 -0
  110. package/dist/providers/base.js +13 -0
  111. package/dist/providers/base.js.map +1 -0
  112. package/dist/providers/fake.d.ts +98 -0
  113. package/dist/providers/fake.d.ts.map +1 -0
  114. package/dist/providers/fake.js +181 -0
  115. package/dist/providers/fake.js.map +1 -0
  116. package/dist/providers/http.d.ts +62 -0
  117. package/dist/providers/http.d.ts.map +1 -0
  118. package/dist/providers/http.js +245 -0
  119. package/dist/providers/http.js.map +1 -0
  120. package/dist/retrieval/chunking.d.ts +88 -0
  121. package/dist/retrieval/chunking.d.ts.map +1 -0
  122. package/dist/retrieval/chunking.js +188 -0
  123. package/dist/retrieval/chunking.js.map +1 -0
  124. package/dist/retrieval/citations.d.ts +98 -0
  125. package/dist/retrieval/citations.d.ts.map +1 -0
  126. package/dist/retrieval/citations.js +134 -0
  127. package/dist/retrieval/citations.js.map +1 -0
  128. package/dist/retrieval/connectors.d.ts +74 -0
  129. package/dist/retrieval/connectors.d.ts.map +1 -0
  130. package/dist/retrieval/connectors.js +218 -0
  131. package/dist/retrieval/connectors.js.map +1 -0
  132. package/dist/retrieval/embedding.d.ts +116 -0
  133. package/dist/retrieval/embedding.d.ts.map +1 -0
  134. package/dist/retrieval/embedding.js +282 -0
  135. package/dist/retrieval/embedding.js.map +1 -0
  136. package/dist/retrieval/gate.d.ts +52 -0
  137. package/dist/retrieval/gate.d.ts.map +1 -0
  138. package/dist/retrieval/gate.js +91 -0
  139. package/dist/retrieval/gate.js.map +1 -0
  140. package/dist/retrieval/hybrid.d.ts +76 -0
  141. package/dist/retrieval/hybrid.d.ts.map +1 -0
  142. package/dist/retrieval/hybrid.js +150 -0
  143. package/dist/retrieval/hybrid.js.map +1 -0
  144. package/dist/retrieval/metrics.d.ts +126 -0
  145. package/dist/retrieval/metrics.d.ts.map +1 -0
  146. package/dist/retrieval/metrics.js +200 -0
  147. package/dist/retrieval/metrics.js.map +1 -0
  148. package/dist/retrieval/pgvector.d.ts +62 -0
  149. package/dist/retrieval/pgvector.d.ts.map +1 -0
  150. package/dist/retrieval/pgvector.js +262 -0
  151. package/dist/retrieval/pgvector.js.map +1 -0
  152. package/dist/retrieval/rerank.d.ts +61 -0
  153. package/dist/retrieval/rerank.d.ts.map +1 -0
  154. package/dist/retrieval/rerank.js +105 -0
  155. package/dist/retrieval/rerank.js.map +1 -0
  156. package/dist/retrieval/retriever.d.ts +125 -0
  157. package/dist/retrieval/retriever.d.ts.map +1 -0
  158. package/dist/retrieval/retriever.js +281 -0
  159. package/dist/retrieval/retriever.js.map +1 -0
  160. package/dist/retrieval/stores.d.ts +106 -0
  161. package/dist/retrieval/stores.d.ts.map +1 -0
  162. package/dist/retrieval/stores.js +142 -0
  163. package/dist/retrieval/stores.js.map +1 -0
  164. package/dist/retrieval/types.d.ts +314 -0
  165. package/dist/retrieval/types.d.ts.map +1 -0
  166. package/dist/retrieval/types.js +388 -0
  167. package/dist/retrieval/types.js.map +1 -0
  168. package/dist/steps.d.ts +156 -0
  169. package/dist/steps.d.ts.map +1 -0
  170. package/dist/steps.js +199 -0
  171. package/dist/steps.js.map +1 -0
  172. package/dist/structured.d.ts +91 -0
  173. package/dist/structured.d.ts.map +1 -0
  174. package/dist/structured.js +155 -0
  175. package/dist/structured.js.map +1 -0
  176. package/dist/tools.d.ts +100 -0
  177. package/dist/tools.d.ts.map +1 -0
  178. package/dist/tools.js +201 -0
  179. package/dist/tools.js.map +1 -0
  180. package/dist/tracing.d.ts +104 -0
  181. package/dist/tracing.d.ts.map +1 -0
  182. package/dist/tracing.js +155 -0
  183. package/dist/tracing.js.map +1 -0
  184. package/dist/types.d.ts +240 -0
  185. package/dist/types.d.ts.map +1 -0
  186. package/dist/types.js +357 -0
  187. package/dist/types.js.map +1 -0
  188. package/package.json +80 -14
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Eval metrics.
3
+ *
4
+ * A metric turns `(case, prediction)` into a score in `[0, 1]`. Each metric declares
5
+ * whether it is *deterministic*, and the gate uses that flag to refuse to be built on
6
+ * a metric that calls a model. This is the enforcement point for a Phase 0 decision:
7
+ * implement `llm-judge`, never make CI depend on it.
8
+ */
9
+ import type { EvalCase } from './dataset.js';
10
+ import { type PredicateNode } from './predicate.js';
11
+ /** One metric's verdict on one prediction. */
12
+ export declare class MetricResult {
13
+ readonly metric: string;
14
+ readonly score: number;
15
+ readonly passed: boolean;
16
+ readonly detail: string;
17
+ constructor(init: {
18
+ readonly metric: string;
19
+ readonly score: number;
20
+ readonly passed: boolean;
21
+ readonly detail?: string;
22
+ });
23
+ }
24
+ /** Scores a single prediction. */
25
+ export interface Metric {
26
+ /** Stable identifier used in baselines and thresholds. */
27
+ readonly name: string;
28
+ /**
29
+ * Whether the same prediction always yields the same score.
30
+ *
31
+ * A model-backed metric is not deterministic, and the gate refuses to threshold on
32
+ * one: a CI signal that itself varies run to run cannot distinguish a regression
33
+ * from its own noise.
34
+ */
35
+ readonly deterministic: boolean;
36
+ score(entry: EvalCase, prediction: string): Promise<MetricResult>;
37
+ }
38
+ /**
39
+ * Casefold and collapse whitespace, then strip surrounding punctuation.
40
+ *
41
+ * None of this is written with a regex, and that is deliberate: a prediction is
42
+ * model output and therefore arbitrary-length input, while every spelling with a
43
+ * quantifier (`/\s+/g`, `/^[ .!?'"]+/`, `/[ .!?'"]+$/`) costs steps proportional to
44
+ * the run it consumes. A forward pass and a scan from each end are linear whatever
45
+ * arrives, and they produce exactly the strings the collapsed regexes did.
46
+ */
47
+ export declare function normalize(text: string): string;
48
+ /** Normalized string equality against `case.expected`. */
49
+ export declare class ExactMatch implements Metric {
50
+ private readonly _name;
51
+ constructor(options?: {
52
+ readonly name?: string;
53
+ });
54
+ get name(): string;
55
+ get deterministic(): boolean;
56
+ score(entry: EvalCase, prediction: string): Promise<MetricResult>;
57
+ }
58
+ /** Whether the normalized prediction contains the normalized expectation. */
59
+ export declare class NormalizedContains implements Metric {
60
+ private readonly _name;
61
+ constructor(options?: {
62
+ readonly name?: string;
63
+ });
64
+ get name(): string;
65
+ get deterministic(): boolean;
66
+ score(entry: EvalCase, prediction: string): Promise<MetricResult>;
67
+ }
68
+ /**
69
+ * Whether the prediction parses as JSON and satisfies the case's schema.
70
+ *
71
+ * The schema lives in the case's metadata under `json_schema` as a JSON string, which
72
+ * keeps datasets in a single file format.
73
+ */
74
+ export declare class JsonSchemaValid implements Metric {
75
+ private readonly _name;
76
+ constructor(options?: {
77
+ readonly name?: string;
78
+ });
79
+ get name(): string;
80
+ get deterministic(): boolean;
81
+ score(entry: EvalCase, prediction: string): Promise<MetricResult>;
82
+ }
83
+ /**
84
+ * Whether a declared predicate holds for the case and its prediction.
85
+ *
86
+ * The condition arrives as the IR's predicate AST -- the very tree the spec layer
87
+ * parsed and checked -- so this metric needs no parser and cannot disagree with the
88
+ * one that accepted the spec. A prediction that makes the predicate false scores 0.0
89
+ * and reports the spec's own `message` verbatim, because the point of letting the
90
+ * author write the message is that a failure quotes them.
91
+ *
92
+ * A predicate that cannot be decided throws instead of scoring. See `predicate.ts`
93
+ * for why that distinction is load-bearing.
94
+ */
95
+ export declare class AssertMetric implements Metric {
96
+ readonly name: string;
97
+ readonly deterministic = true;
98
+ readonly expr: PredicateNode;
99
+ readonly message: string;
100
+ constructor(init: {
101
+ readonly expr: PredicateNode;
102
+ readonly message: string;
103
+ readonly name?: string;
104
+ });
105
+ score(entry: EvalCase, prediction: string): Promise<MetricResult>;
106
+ }
107
+ /** The structured output an LLM judge must return. */
108
+ export declare const JudgeVerdict: import("../structured.js").StructuredOutput<{
109
+ score: number;
110
+ reason: string;
111
+ }>;
112
+ /** A judge call: one prompt in, one model answer out. */
113
+ export type JudgeCall = (prompt: string) => Promise<string>;
114
+ /**
115
+ * Scores a prediction with a model, as a *metric only*.
116
+ *
117
+ * `deterministic` is `false` and must stay that way. Using this metric for a CI
118
+ * threshold would make the gate's own verdict probabilistic; the gate raises rather
119
+ * than allow it. It is implemented because a judge is the right way to explore quality
120
+ * locally and to produce a second opinion next to a deterministic gate -- not because
121
+ * it can be trusted as the gate.
122
+ */
123
+ export declare class LlmJudge implements Metric {
124
+ private readonly _call;
125
+ private readonly _rubric;
126
+ private readonly _name;
127
+ private readonly _retries;
128
+ constructor(call: JudgeCall, options: {
129
+ readonly rubric: string;
130
+ readonly name?: string;
131
+ readonly retries?: number;
132
+ });
133
+ get name(): string;
134
+ get deterministic(): boolean;
135
+ score(entry: EvalCase, prediction: string): Promise<MetricResult>;
136
+ private buildPrompt;
137
+ }
138
+ /** The deterministic gate metrics: everything that needs no model call. */
139
+ export declare function defaultMetrics(): Metric[];
140
+ export declare function metricNames(metrics: readonly Metric[]): string[];
141
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/evals/metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,364 @@
1
+ /**
2
+ * Eval metrics.
3
+ *
4
+ * A metric turns `(case, prediction)` into a score in `[0, 1]`. Each metric declares
5
+ * whether it is *deterministic*, and the gate uses that flag to refuse to be built on
6
+ * a metric that calls a model. This is the enforcement point for a Phase 0 decision:
7
+ * implement `llm-judge`, never make CI depend on it.
8
+ */
9
+ import { z } from 'zod';
10
+ // biome-ignore lint/suspicious/noShadowRestrictedNames: the framework's own error name, matching the Python runtime's public surface
11
+ import { EvalError } from '../errors.js';
12
+ import { repr } from '../internal/json.js';
13
+ import { runStructured, structuredOutput } from '../structured.js';
14
+ import { evaluatePredicate } from './predicate.js';
15
+ /** One metric's verdict on one prediction. */
16
+ export class MetricResult {
17
+ metric;
18
+ score;
19
+ passed;
20
+ detail;
21
+ constructor(init) {
22
+ if (!(init.score >= 0.0 && init.score <= 1.0)) {
23
+ throw new RangeError('score must be between 0 and 1');
24
+ }
25
+ this.metric = init.metric;
26
+ this.score = init.score;
27
+ this.passed = init.passed;
28
+ this.detail = init.detail ?? '';
29
+ }
30
+ }
31
+ /**
32
+ * Casefold and collapse whitespace, then strip surrounding punctuation.
33
+ *
34
+ * None of this is written with a regex, and that is deliberate: a prediction is
35
+ * model output and therefore arbitrary-length input, while every spelling with a
36
+ * quantifier (`/\s+/g`, `/^[ .!?'"]+/`, `/[ .!?'"]+$/`) costs steps proportional to
37
+ * the run it consumes. A forward pass and a scan from each end are linear whatever
38
+ * arrives, and they produce exactly the strings the collapsed regexes did.
39
+ */
40
+ export function normalize(text) {
41
+ // Upper-then-lower approximates Python's `str.casefold()`, which folds further than
42
+ // `toLowerCase()` alone: 'ß' folds to 'ss', 'ſ' to 's', 'Σ' to 'σ'.
43
+ const folded = collapseWhitespace(text.trim()).toUpperCase().toLowerCase();
44
+ let start = 0;
45
+ let end = folded.length;
46
+ while (start < end && PUNCTUATION.has(folded[start]))
47
+ start += 1;
48
+ while (end > start && PUNCTUATION.has(folded[end - 1]))
49
+ end -= 1;
50
+ return folded.slice(start, end);
51
+ }
52
+ /** The characters stripped from either end after folding. */
53
+ const PUNCTUATION = new Set([' ', '.', '!', '?', "'", '"']);
54
+ /**
55
+ * The code points JavaScript's `\s` matches, as inclusive ranges.
56
+ *
57
+ * Spelled out rather than delegated to a regex so that {@link collapseWhitespace} is
58
+ * a single pass: the set is fixed, so a table lookup is all a collapse needs.
59
+ */
60
+ const WHITESPACE_RANGES = [
61
+ [0x09, 0x0d],
62
+ [0x20, 0x20],
63
+ [0xa0, 0xa0],
64
+ [0x1680, 0x1680],
65
+ [0x2000, 0x200a],
66
+ [0x2028, 0x2029],
67
+ [0x202f, 0x202f],
68
+ [0x205f, 0x205f],
69
+ [0x3000, 0x3000],
70
+ [0xfeff, 0xfeff],
71
+ ];
72
+ function isWhitespace(codePoint) {
73
+ for (const [low, high] of WHITESPACE_RANGES) {
74
+ if (codePoint >= low && codePoint <= high)
75
+ return true;
76
+ }
77
+ return false;
78
+ }
79
+ /** Collapse every internal run of whitespace to one space, in a single pass. */
80
+ function collapseWhitespace(text) {
81
+ let out = '';
82
+ let pending = false;
83
+ for (const char of text) {
84
+ if (isWhitespace(char.codePointAt(0))) {
85
+ pending = true;
86
+ continue;
87
+ }
88
+ if (pending && out.length > 0)
89
+ out += ' ';
90
+ pending = false;
91
+ out += char;
92
+ }
93
+ return out;
94
+ }
95
+ /** Normalized string equality against `case.expected`. */
96
+ export class ExactMatch {
97
+ _name;
98
+ constructor(options = {}) {
99
+ this._name = options.name ?? 'exact-match';
100
+ }
101
+ get name() {
102
+ return this._name;
103
+ }
104
+ get deterministic() {
105
+ return true;
106
+ }
107
+ async score(entry, prediction) {
108
+ if (entry.expected === null) {
109
+ throw new EvalError(`case ${repr(entry.id)} has no expected value for ${this.name}`);
110
+ }
111
+ const ok = normalize(prediction) === normalize(entry.expected);
112
+ return new MetricResult({
113
+ metric: this.name,
114
+ score: ok ? 1.0 : 0.0,
115
+ passed: ok,
116
+ detail: ok ? '' : `expected ${repr(entry.expected)}`,
117
+ });
118
+ }
119
+ }
120
+ /** Whether the normalized prediction contains the normalized expectation. */
121
+ export class NormalizedContains {
122
+ _name;
123
+ constructor(options = {}) {
124
+ this._name = options.name ?? 'contains';
125
+ }
126
+ get name() {
127
+ return this._name;
128
+ }
129
+ get deterministic() {
130
+ return true;
131
+ }
132
+ async score(entry, prediction) {
133
+ if (entry.expected === null) {
134
+ throw new EvalError(`case ${repr(entry.id)} has no expected value for ${this.name}`);
135
+ }
136
+ const ok = normalize(prediction).includes(normalize(entry.expected));
137
+ return new MetricResult({
138
+ metric: this.name,
139
+ score: ok ? 1.0 : 0.0,
140
+ passed: ok,
141
+ detail: ok ? '' : `missing ${repr(entry.expected)}`,
142
+ });
143
+ }
144
+ }
145
+ /** The Python `type(value).__name__` for a JSON value. */
146
+ function typeName(value) {
147
+ if (value === null)
148
+ return 'NoneType';
149
+ if (Array.isArray(value))
150
+ return 'list';
151
+ if (typeof value === 'object')
152
+ return 'dict';
153
+ if (typeof value === 'string')
154
+ return 'str';
155
+ if (typeof value === 'boolean')
156
+ return 'bool';
157
+ if (typeof value === 'number')
158
+ return Number.isInteger(value) ? 'int' : 'float';
159
+ return typeof value;
160
+ }
161
+ function typeOk(value, declared) {
162
+ switch (declared) {
163
+ case 'object':
164
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
165
+ case 'array':
166
+ return Array.isArray(value);
167
+ case 'string':
168
+ return typeof value === 'string';
169
+ case 'integer':
170
+ return typeof value === 'number' && Number.isInteger(value);
171
+ case 'number':
172
+ return typeof value === 'number';
173
+ case 'boolean':
174
+ return typeof value === 'boolean';
175
+ case 'null':
176
+ return value === null;
177
+ default:
178
+ return true;
179
+ }
180
+ }
181
+ function isObject(value) {
182
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
183
+ }
184
+ /** Check the JSON Schema subset a dataset realistically uses. */
185
+ function schemaProblems(schema, value, path) {
186
+ const problems = [];
187
+ if (!isObject(schema))
188
+ return problems;
189
+ const declared = schema.type;
190
+ if (typeof declared === 'string' && !typeOk(value, declared)) {
191
+ problems.push(`${path}: expected ${declared}, got ${typeName(value)}`);
192
+ }
193
+ if (isObject(value)) {
194
+ const required = schema.required;
195
+ if (Array.isArray(required)) {
196
+ for (const name of required) {
197
+ if (typeof name === 'string' && !Object.hasOwn(value, name)) {
198
+ problems.push(`${path}: missing required property ${repr(name)}`);
199
+ }
200
+ }
201
+ }
202
+ const properties = schema.properties;
203
+ if (isObject(properties)) {
204
+ for (const [name, subschema] of Object.entries(properties)) {
205
+ if (Object.hasOwn(value, name)) {
206
+ problems.push(...schemaProblems(subschema, value[name], `${path}.${name}`));
207
+ }
208
+ }
209
+ }
210
+ }
211
+ if (Array.isArray(value) && isObject(schema.items)) {
212
+ for (const [index, item] of value.entries()) {
213
+ problems.push(...schemaProblems(schema.items, item, `${path}[${index}]`));
214
+ }
215
+ }
216
+ return problems;
217
+ }
218
+ /**
219
+ * Whether the prediction parses as JSON and satisfies the case's schema.
220
+ *
221
+ * The schema lives in the case's metadata under `json_schema` as a JSON string, which
222
+ * keeps datasets in a single file format.
223
+ */
224
+ export class JsonSchemaValid {
225
+ _name;
226
+ constructor(options = {}) {
227
+ this._name = options.name ?? 'json-valid';
228
+ }
229
+ get name() {
230
+ return this._name;
231
+ }
232
+ get deterministic() {
233
+ return true;
234
+ }
235
+ async score(entry, prediction) {
236
+ const schema = entry.metadata.json_schema;
237
+ let parsed;
238
+ try {
239
+ parsed = JSON.parse(prediction);
240
+ }
241
+ catch (error) {
242
+ const message = error instanceof Error ? error.message : String(error);
243
+ return new MetricResult({
244
+ metric: this.name,
245
+ score: 0.0,
246
+ passed: false,
247
+ detail: `invalid JSON: ${message}`,
248
+ });
249
+ }
250
+ if (schema === undefined) {
251
+ return new MetricResult({ metric: this.name, score: 1.0, passed: true, detail: 'parsed' });
252
+ }
253
+ const problems = schemaProblems(JSON.parse(schema), parsed, '$');
254
+ return new MetricResult({
255
+ metric: this.name,
256
+ score: problems.length === 0 ? 1.0 : 0.0,
257
+ passed: problems.length === 0,
258
+ detail: problems.join('; '),
259
+ });
260
+ }
261
+ }
262
+ /**
263
+ * Whether a declared predicate holds for the case and its prediction.
264
+ *
265
+ * The condition arrives as the IR's predicate AST -- the very tree the spec layer
266
+ * parsed and checked -- so this metric needs no parser and cannot disagree with the
267
+ * one that accepted the spec. A prediction that makes the predicate false scores 0.0
268
+ * and reports the spec's own `message` verbatim, because the point of letting the
269
+ * author write the message is that a failure quotes them.
270
+ *
271
+ * A predicate that cannot be decided throws instead of scoring. See `predicate.ts`
272
+ * for why that distinction is load-bearing.
273
+ */
274
+ export class AssertMetric {
275
+ name;
276
+ deterministic = true;
277
+ expr;
278
+ message;
279
+ constructor(init) {
280
+ this.name = init.name ?? 'assert';
281
+ this.expr = init.expr;
282
+ this.message = init.message;
283
+ }
284
+ async score(entry, prediction) {
285
+ const ok = evaluatePredicate(this.expr, { entry, prediction });
286
+ return new MetricResult({
287
+ metric: this.name,
288
+ score: ok ? 1.0 : 0.0,
289
+ passed: ok,
290
+ detail: ok ? '' : this.message,
291
+ });
292
+ }
293
+ }
294
+ /** The structured output an LLM judge must return. */
295
+ export const JudgeVerdict = structuredOutput('JudgeVerdict', z.object({
296
+ score: z.number().min(0.0).max(1.0),
297
+ reason: z.string().default(''),
298
+ }));
299
+ /**
300
+ * Scores a prediction with a model, as a *metric only*.
301
+ *
302
+ * `deterministic` is `false` and must stay that way. Using this metric for a CI
303
+ * threshold would make the gate's own verdict probabilistic; the gate raises rather
304
+ * than allow it. It is implemented because a judge is the right way to explore quality
305
+ * locally and to produce a second opinion next to a deterministic gate -- not because
306
+ * it can be trusted as the gate.
307
+ */
308
+ export class LlmJudge {
309
+ _call;
310
+ _rubric;
311
+ _name;
312
+ _retries;
313
+ constructor(call, options) {
314
+ this._call = call;
315
+ this._rubric = options.rubric;
316
+ this._name = options.name ?? 'llm-judge';
317
+ this._retries = options.retries ?? 2;
318
+ }
319
+ get name() {
320
+ return this._name;
321
+ }
322
+ get deterministic() {
323
+ return false;
324
+ }
325
+ async score(entry, prediction) {
326
+ const prompt = this.buildPrompt(entry, prediction);
327
+ try {
328
+ const verdict = await runStructured(this._call, JudgeVerdict, prompt, {
329
+ retries: this._retries,
330
+ });
331
+ return new MetricResult({
332
+ metric: this.name,
333
+ score: verdict.score,
334
+ passed: verdict.score >= 0.5,
335
+ detail: verdict.reason,
336
+ });
337
+ }
338
+ catch (error) {
339
+ const message = error instanceof Error ? error.message : String(error);
340
+ return new MetricResult({
341
+ metric: this.name,
342
+ score: 0.0,
343
+ passed: false,
344
+ detail: `judge failed: ${message}`,
345
+ });
346
+ }
347
+ }
348
+ buildPrompt(entry, prediction) {
349
+ const expected = entry.expected ?? '<not provided>';
350
+ return (`${this._rubric}\n\n` +
351
+ `Input: ${entry.input}\n` +
352
+ `Reference: ${expected}\n` +
353
+ `Candidate: ${prediction}\n\n` +
354
+ 'Reply with JSON: {"score": <0.0-1.0>, "reason": "<short>"}');
355
+ }
356
+ }
357
+ /** The deterministic gate metrics: everything that needs no model call. */
358
+ export function defaultMetrics() {
359
+ return [new ExactMatch(), new NormalizedContains(), new JsonSchemaValid()];
360
+ }
361
+ export function metricNames(metrics) {
362
+ return metrics.map((metric) => metric.name);
363
+ }
364
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/evals/metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * The PredicateExpr evaluator an `assert` metric runs.
3
+ *
4
+ * The AST is data, not code: the IR parses and validates it, the generator emits it
5
+ * as a plain object literal, and this module walks it. There is no `eval` and no
6
+ * `new Function` anywhere on that path, so a predicate can only ever do what this
7
+ * file implements -- read the prediction, the case id and one metadata key, call
8
+ * four total string builtins, and compare. Anything else is a node kind this walker
9
+ * does not know, and an unknown node throws rather than passing.
10
+ *
11
+ * Throwing matters more than it looks. A false assertion and an *undecidable* one
12
+ * are different outcomes: `false` is a legitimate result the gate must see, while a
13
+ * missing metadata key or a string where a number belongs means the eval itself is
14
+ * misconfigured. Returning `false` for either would report a broken eval as a
15
+ * failing candidate, and returning `true` would hide it, so both throw `EvalError`.
16
+ *
17
+ * Both sides of `and`/`or` are always evaluated. Short-circuiting would let
18
+ * `case.metadata.missing == "x" or true` pass silently, which is the one failure
19
+ * mode this whole design exists to prevent.
20
+ */
21
+ import type { EvalCase } from './dataset.js';
22
+ /**
23
+ * A value a predicate can carry.
24
+ *
25
+ * Numbers are a single `number` here; Python normalizes its `int` and `float` to
26
+ * `float` so a JSON literal `3` and `length(...)` compare equal in both. Booleans
27
+ * are kept apart from numbers on purpose, because `1 == true` is false here and a
28
+ * grammar that answered differently in each language would be worse than no grammar.
29
+ */
30
+ export type PredicateValue = boolean | number | string;
31
+ /** The node shapes the IR emits. Structural, because the runtime owns no IR types. */
32
+ export type PredicateNode = {
33
+ readonly kind: 'boolean';
34
+ readonly value: boolean;
35
+ } | {
36
+ readonly kind: 'number';
37
+ readonly value: number;
38
+ } | {
39
+ readonly kind: 'string';
40
+ readonly value: string;
41
+ } | {
42
+ readonly kind: 'invalid';
43
+ readonly reason: string;
44
+ } | {
45
+ readonly kind: 'path';
46
+ readonly path: string;
47
+ readonly name?: string;
48
+ } | {
49
+ readonly kind: 'call';
50
+ readonly name: string;
51
+ readonly args: readonly PredicateNode[];
52
+ } | {
53
+ readonly kind: 'comparison';
54
+ readonly op: string;
55
+ readonly left: PredicateNode;
56
+ readonly right: PredicateNode;
57
+ } | {
58
+ readonly kind: 'not';
59
+ readonly operand: PredicateNode;
60
+ } | {
61
+ readonly kind: 'and' | 'or';
62
+ readonly left: PredicateNode;
63
+ readonly right: PredicateNode;
64
+ };
65
+ /** The name a diagnostic uses for a value's type. */
66
+ export declare function typeName(value: PredicateValue): string;
67
+ /**
68
+ * Evaluate `node` against one case and prediction, or throw if it cannot be.
69
+ *
70
+ * A non-boolean result is an error rather than a truthiness test: the expression's
71
+ * type is fixed at build time, so a non-boolean here means the AST and the walker
72
+ * disagree, and guessing which one is right is exactly the kind of guess that makes
73
+ * a gate untrustworthy.
74
+ */
75
+ export declare function evaluatePredicate(node: PredicateNode | undefined, context: {
76
+ readonly entry: EvalCase;
77
+ readonly prediction: string;
78
+ }): boolean;
79
+ //# sourceMappingURL=predicate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"predicate.d.ts","sourceRoot":"","sources":["../../src/evals/predicate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAE7C;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEvD,sFAAsF;AACtF,MAAM,MAAM,aAAa,GACrB;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACrD;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACxE;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,aAAa,EAAE,CAAA;CAAE,GACzF;IACE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;CAC/B,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAA;CAAE,GACzD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAA;CAAE,CAAC;AAIjG,qDAAqD;AACrD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAItD;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,aAAa,GAAG,SAAS,EAC/B,OAAO,EAAE;IAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACjE,OAAO,CAMT"}