@axlsdk/studio 0.23.3 → 0.24.1

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/dist/cli.cjs CHANGED
@@ -131,42 +131,177 @@ function sanitizeRichInputFailure(event) {
131
131
  }
132
132
  return event;
133
133
  }
134
+ var MEASURED_METADATA_KEYS = /* @__PURE__ */ new Set([
135
+ "models",
136
+ "modelCallCounts",
137
+ "workflows",
138
+ "workflowCallCounts",
139
+ "tokens",
140
+ "agentCalls"
141
+ ]);
142
+ function redactItemMetadata(metadata) {
143
+ if (!metadata) return metadata;
144
+ const out = {};
145
+ for (const [key, value] of Object.entries(metadata)) {
146
+ out[key] = MEASURED_METADATA_KEYS.has(key) ? value : REDACTED;
147
+ }
148
+ return out;
149
+ }
150
+ function projectItemFailure(failure) {
151
+ if (!failure || typeof failure !== "object") return void 0;
152
+ const f = failure;
153
+ if (typeof f.name !== "string") return void 0;
154
+ return {
155
+ name: f.name,
156
+ ...typeof f.provider === "string" ? { provider: f.provider } : {},
157
+ ...typeof f.status === "number" && Number.isFinite(f.status) ? { status: f.status } : {},
158
+ ...typeof f.retryable === "boolean" ? { retryable: f.retryable } : {},
159
+ ...typeof f.requestId === "string" ? { requestId: f.requestId } : {}
160
+ };
161
+ }
162
+ function isPlainObject(value) {
163
+ return typeof value === "object" && value !== null && !Array.isArray(value);
164
+ }
165
+ function redactScorerDetail(detail) {
166
+ if (!isPlainObject(detail)) return REDACTED;
167
+ const d = detail;
168
+ return {
169
+ score: d.score,
170
+ ...d.duration !== void 0 ? { duration: d.duration } : {},
171
+ ...d.cost !== void 0 ? { cost: d.cost } : {},
172
+ // `skipped` is a structural boolean (the `applies` predicate verdict),
173
+ // not user/LLM content — preserve it so the client's N/A chip renders.
174
+ ...d.skipped !== void 0 ? { skipped: d.skipped } : {},
175
+ // `outcome` and `accounting` are structural (a classification and a set
176
+ // of counts), so they survive redaction the way `skipped` does — without
177
+ // them a compliance-mode reader cannot tell a judge that was stopped on
178
+ // budget from one that scored 0.
179
+ ...d.outcome !== void 0 ? { outcome: d.outcome } : {},
180
+ ...d.accounting !== void 0 ? { accounting: d.accounting } : {},
181
+ // `diagnostics` survives for the same reason `accounting` does: it is a
182
+ // list of operation ids and statuses, not content.
183
+ ...d.diagnostics !== void 0 ? { diagnostics: d.diagnostics } : {}
184
+ // metadata deliberately omitted — may contain LLM scorer reasoning
185
+ };
186
+ }
134
187
  function redactEvalItem(item) {
188
+ if (!isPlainObject(item)) return REDACTED;
189
+ const { failure, ...rest } = item;
190
+ const typed = item;
191
+ const projectedFailure = failure !== void 0 ? projectItemFailure(failure) : void 0;
135
192
  const scrubbed = {
136
- ...item,
193
+ ...rest,
194
+ ...projectedFailure ? { failure: projectedFailure } : {},
137
195
  input: REDACTED,
138
196
  output: REDACTED,
139
- ...item.annotations !== void 0 ? { annotations: REDACTED } : {},
140
- ...item.error !== void 0 ? { error: REDACTED } : {},
141
- ...item.scorerErrors !== void 0 ? { scorerErrors: item.scorerErrors.map(() => REDACTED) } : {}
142
- };
143
- if (item.scoreDetails) {
144
- const detailsOut = {};
145
- for (const [name, detail] of Object.entries(item.scoreDetails)) {
146
- detailsOut[name] = {
147
- score: detail.score,
148
- ...detail.duration !== void 0 ? { duration: detail.duration } : {},
149
- ...detail.cost !== void 0 ? { cost: detail.cost } : {},
150
- // `skipped` is a structural boolean (the `applies` predicate verdict),
151
- // not user/LLM content — preserve it so the client's N/A chip renders.
152
- ...detail.skipped !== void 0 ? { skipped: detail.skipped } : {}
153
- // metadata deliberately omitted — may contain LLM scorer reasoning
154
- };
197
+ // `diagnostics` is spread through untouched on purpose: it holds operation
198
+ // IDs, kinds, turn/attempt indexes and a status — pointers into an artifact,
199
+ // never content. The records themselves are redacted by the core rule at
200
+ // both write time and delivery time (`redactRecordLine`).
201
+ ...typed.metadata !== void 0 ? {
202
+ metadata: isPlainObject(typed.metadata) ? redactItemMetadata(typed.metadata) : REDACTED
203
+ } : {},
204
+ ...typed.annotations !== void 0 ? { annotations: REDACTED } : {},
205
+ ...typed.error !== void 0 ? { error: REDACTED } : {},
206
+ ...typed.scorerErrors !== void 0 ? {
207
+ scorerErrors: Array.isArray(typed.scorerErrors) ? typed.scorerErrors.map(() => REDACTED) : REDACTED
208
+ } : {},
209
+ // `callerReport.metadata` is whatever the workflow callback returned — free-
210
+ // form user content, exactly like `output`, so it is dropped rather than
211
+ // masked (same treatment as scorer metadata below). Its sibling `cost` is a
212
+ // plain number and stays. (`outcome` and `accounting` are spread through
213
+ // untouched: both are structural counts and classifications, no content.)
214
+ ...typed.callerReport !== void 0 ? {
215
+ callerReport: isPlainObject(typed.callerReport) ? typeof typed.callerReport.cost === "number" ? { cost: typed.callerReport.cost } : {} : REDACTED
216
+ } : {}
217
+ };
218
+ if (typed.scoreDetails !== void 0) {
219
+ if (isPlainObject(typed.scoreDetails)) {
220
+ const detailsOut = {};
221
+ for (const [name, detail] of Object.entries(typed.scoreDetails)) {
222
+ detailsOut[name] = redactScorerDetail(detail);
223
+ }
224
+ scrubbed.scoreDetails = detailsOut;
225
+ } else {
226
+ scrubbed.scoreDetails = REDACTED;
155
227
  }
156
- scrubbed.scoreDetails = detailsOut;
157
228
  }
158
229
  return scrubbed;
159
230
  }
160
231
  function redactEvalResult(result, redact) {
161
232
  if (!redact) return result;
162
- const meta3 = result.metadata;
163
- const scrubbedMetadata = meta3 && typeof meta3.batchFailure === "string" ? { ...meta3, batchFailure: REDACTED } : result.metadata;
233
+ return redactResultShape(result);
234
+ }
235
+ function redactResultShape(result) {
236
+ const scrubbedMetadata = redactResultMetadata(result.metadata);
237
+ const hasMultiRun = "_multiRun" in result;
238
+ const multiRun = result._multiRun;
164
239
  return {
165
240
  ...result,
166
241
  metadata: scrubbedMetadata,
167
- items: result.items.map(redactEvalItem)
242
+ items: Array.isArray(result.items) ? result.items.map(redactEvalItem) : REDACTED,
243
+ ...hasMultiRun && multiRun !== void 0 ? {
244
+ _multiRun: isPlainObject(multiRun) ? redactMultiRun(multiRun) : REDACTED
245
+ } : {}
168
246
  };
169
247
  }
248
+ function redactResultMetadata(metadata) {
249
+ const meta3 = metadata;
250
+ return isPlainObject(meta3) && typeof meta3.batchFailure === "string" ? { ...meta3, batchFailure: REDACTED } : metadata;
251
+ }
252
+ function redactMultiRun(multiRun) {
253
+ const { allRuns } = multiRun;
254
+ return {
255
+ ...multiRun,
256
+ ...allRuns !== void 0 ? {
257
+ allRuns: Array.isArray(allRuns) ? allRuns.map(
258
+ (run) => isPlainObject(run) && Array.isArray(run.items) ? redactResultShape(run) : REDACTED
259
+ ) : REDACTED
260
+ } : {},
261
+ ...typeof multiRun.batchFailure === "string" ? { batchFailure: REDACTED } : {}
262
+ };
263
+ }
264
+ function redactEvalComparison(comparison, redact) {
265
+ if (!redact) return comparison;
266
+ const maskInput = (r) => ({ ...r, input: REDACTED });
267
+ const side = (s) => ({
268
+ ...s,
269
+ metadata: redactResultMetadata(s.metadata)
270
+ });
271
+ return {
272
+ ...comparison,
273
+ baseline: side(comparison.baseline),
274
+ candidate: side(comparison.candidate),
275
+ regressions: comparison.regressions.map(maskInput),
276
+ improvements: comparison.improvements.map(maskInput)
277
+ };
278
+ }
279
+ function redactRecordLine(line, redact) {
280
+ if (!redact) return line;
281
+ let parsed;
282
+ try {
283
+ parsed = JSON.parse(line);
284
+ } catch {
285
+ const stub = {
286
+ v: 1,
287
+ phase: "end",
288
+ operationId: "unknown",
289
+ kind: "chat",
290
+ transportAttempts: 1,
291
+ provider: "unknown",
292
+ model: "unknown",
293
+ termination: "the stored record could not be parsed",
294
+ captured: {
295
+ fidelity: "runtime_request",
296
+ redacted: true,
297
+ truncated: true,
298
+ omitted: ["record"]
299
+ }
300
+ };
301
+ return JSON.stringify(stub);
302
+ }
303
+ return JSON.stringify((0, import_axl.redactCapturedRequest)(parsed));
304
+ }
170
305
  function redactEvalHistoryEntry(entry, redact) {
171
306
  if (!redact) return entry;
172
307
  return {
@@ -943,7 +1078,50 @@ function reduceCost(acc, event) {
943
1078
  };
944
1079
  }
945
1080
  function emptyEvalTrendData() {
946
- return { byEval: {}, totalRuns: 0, totalCost: 0 };
1081
+ return { byEval: {}, totalRuns: 0, totalCost: 0, totalCostCompleteness: "complete" };
1082
+ }
1083
+ function worse(a, b) {
1084
+ if (a === "unverified" || b === "unverified") return "unverified";
1085
+ if (a === "incomplete" || b === "incomplete") return "incomplete";
1086
+ return "complete";
1087
+ }
1088
+ function extractAccounting(data) {
1089
+ const result = data ?? {};
1090
+ const accounting = result.accounting;
1091
+ if (!accounting || typeof accounting !== "object") {
1092
+ return { cost: usable(extractCost(data)), completeness: "unverified", budgetStopped: false };
1093
+ }
1094
+ const completeness = accounting.completeness === "complete" || accounting.completeness === "incomplete" ? accounting.completeness : "unverified";
1095
+ const knownCost = usable(accounting.knownCost);
1096
+ const summary = result.summary;
1097
+ return {
1098
+ cost: knownCost,
1099
+ completeness,
1100
+ budgetStopped: isBudgetStopped(accounting.budget?.status, summary?.coverage)
1101
+ };
1102
+ }
1103
+ function usable(value) {
1104
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
1105
+ }
1106
+ function refusedWork(coverage) {
1107
+ if (!coverage || typeof coverage !== "object") return 0;
1108
+ const { items, scorers } = coverage;
1109
+ let refused = count(items, "budget_skipped") + count(items, "budget_interrupted");
1110
+ if (scorers && typeof scorers === "object") {
1111
+ for (const s of Object.values(scorers)) {
1112
+ refused += count(s, "budget_skipped") + count(s, "budget_interrupted");
1113
+ }
1114
+ }
1115
+ return refused;
1116
+ }
1117
+ function count(block, key) {
1118
+ if (!block || typeof block !== "object") return 0;
1119
+ const value = block[key];
1120
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : 0;
1121
+ }
1122
+ function isBudgetStopped(status, coverage) {
1123
+ if (status !== "closed") return false;
1124
+ return refusedWork(coverage) > 0;
947
1125
  }
948
1126
  function extractScores(data) {
949
1127
  if (!data || typeof data !== "object") return {};
@@ -1010,7 +1188,7 @@ function computeScoreStats(runs) {
1010
1188
  }
1011
1189
  function reduceEvalTrends(acc, entry) {
1012
1190
  const scores = extractScores(entry.data);
1013
- const cost = extractCost(entry.data);
1191
+ const { cost, completeness, budgetStopped } = extractAccounting(entry.data);
1014
1192
  const model = extractModel(entry.data);
1015
1193
  const duration3 = extractDuration(entry.data);
1016
1194
  const metadata = entry.data?.metadata;
@@ -1021,6 +1199,8 @@ function reduceEvalTrends(acc, entry) {
1021
1199
  id: entry.id,
1022
1200
  scores,
1023
1201
  cost,
1202
+ completeness,
1203
+ ...budgetStopped ? { budgetStopped: true } : {},
1024
1204
  ...model !== void 0 ? { model } : {},
1025
1205
  ...duration3 !== void 0 ? { duration: duration3 } : {},
1026
1206
  ...runGroupId !== void 0 ? { runGroupId } : {},
@@ -1039,12 +1219,15 @@ function reduceEvalTrends(acc, entry) {
1039
1219
  scoreMean: mean,
1040
1220
  scoreStd: std,
1041
1221
  costTotal: (prev?.costTotal ?? 0) + cost,
1222
+ costCompleteness: worse(prev?.costCompleteness ?? "complete", completeness),
1223
+ budgetStoppedRuns: (prev?.budgetStoppedRuns ?? 0) + (budgetStopped ? 1 : 0),
1042
1224
  runCount: (prev?.runCount ?? 0) + 1
1043
1225
  };
1044
1226
  return {
1045
1227
  byEval,
1046
1228
  totalRuns: acc.totalRuns + 1,
1047
- totalCost: acc.totalCost + cost
1229
+ totalCost: acc.totalCost + cost,
1230
+ totalCostCompleteness: worse(acc.totalCostCompleteness ?? "complete", completeness)
1048
1231
  };
1049
1232
  }
1050
1233
  var MAX_DURATIONS = 200;
@@ -1745,6 +1928,184 @@ function createCostRoutes(costAggregator) {
1745
1928
  // src/server/routes/evals.ts
1746
1929
  var import_node_crypto = require("crypto");
1747
1930
  var import_hono10 = require("hono");
1931
+
1932
+ // src/server/eval-import.ts
1933
+ var ITEM_OUTCOMES = [
1934
+ "completed",
1935
+ "failed",
1936
+ "cancelled",
1937
+ "budget_skipped",
1938
+ "budget_interrupted"
1939
+ ];
1940
+ var SCORER_OUTCOMES = [
1941
+ "scored",
1942
+ "failed",
1943
+ "skipped",
1944
+ "cancelled",
1945
+ "budget_skipped",
1946
+ "budget_interrupted"
1947
+ ];
1948
+ var EPSILON = 1e-9;
1949
+ function isFiniteNonNegative(value) {
1950
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
1951
+ }
1952
+ function isCount(value) {
1953
+ return isFiniteNonNegative(value) && Number.isInteger(value);
1954
+ }
1955
+ function isValidImportedBudget(value) {
1956
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1957
+ const b = value;
1958
+ if (!isFiniteNonNegative(b.limit)) return false;
1959
+ if (!isFiniteNonNegative(b.knownSpend)) return false;
1960
+ if (!isFiniteNonNegative(b.knownOvershoot)) return false;
1961
+ if (b.status !== "open" && b.status !== "closed") return false;
1962
+ if (b.closedBy !== void 0 && b.closedBy !== "case" && b.closedBy !== "scorer" && b.closedBy !== "operation") {
1963
+ return false;
1964
+ }
1965
+ if (b.knownSpend >= b.limit !== (b.status === "closed")) return false;
1966
+ const expected = Math.max(0, b.knownSpend - b.limit);
1967
+ return Math.abs(b.knownOvershoot - expected) <= EPSILON;
1968
+ }
1969
+ function isValidImportedCoverage(value) {
1970
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1971
+ const c = value;
1972
+ if (!c.items || typeof c.items !== "object" || Array.isArray(c.items)) return false;
1973
+ const items = c.items;
1974
+ for (const key of ITEM_OUTCOMES) {
1975
+ if (!isCount(items[key])) return false;
1976
+ }
1977
+ if (!c.scorers || typeof c.scorers !== "object" || Array.isArray(c.scorers)) return false;
1978
+ for (const bucket of Object.values(c.scorers)) {
1979
+ if (!bucket || typeof bucket !== "object" || Array.isArray(bucket)) return false;
1980
+ const counts = bucket;
1981
+ for (const key of SCORER_OUTCOMES) {
1982
+ if (!isCount(counts[key])) return false;
1983
+ }
1984
+ }
1985
+ return true;
1986
+ }
1987
+ function isValidImportedItemErrorRate(value) {
1988
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
1989
+ const r = value;
1990
+ const { failed, attempted, rate, limit, exceeded } = r;
1991
+ if (!isCount(failed) || !isCount(attempted) || failed > attempted) return false;
1992
+ if (!isFiniteNonNegative(limit) || limit > 1) return false;
1993
+ if (typeof rate !== "number" || typeof exceeded !== "boolean") return false;
1994
+ const expectedRate = attempted > 0 ? failed / attempted : 0;
1995
+ if (Math.abs(rate - expectedRate) > EPSILON) return false;
1996
+ return exceeded === (attempted > 0 && rate > limit);
1997
+ }
1998
+ function isValidImportedMultiRun(value) {
1999
+ if (!isPlainRecord(value)) return false;
2000
+ const { allRuns } = value;
2001
+ if (allRuns === void 0) return true;
2002
+ if (!Array.isArray(allRuns)) return false;
2003
+ return allRuns.every(
2004
+ (run) => isPlainRecord(run) && Array.isArray(run.items) && run.items.every(isPlainRecord)
2005
+ );
2006
+ }
2007
+ function isPlainRecord(value) {
2008
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2009
+ }
2010
+ function sumOf(record2) {
2011
+ if (record2 === void 0) return 0;
2012
+ if (record2 === null || typeof record2 !== "object" || Array.isArray(record2)) return void 0;
2013
+ let total = 0;
2014
+ for (const value of Object.values(record2)) {
2015
+ if (!isFiniteNonNegative(value)) return void 0;
2016
+ total += value;
2017
+ }
2018
+ return total;
2019
+ }
2020
+ function allNumeric(record2) {
2021
+ if (record2 === void 0) return true;
2022
+ if (record2 === null || typeof record2 !== "object" || Array.isArray(record2)) return false;
2023
+ return Object.values(record2).every(
2024
+ (value) => typeof value === "number" && Number.isFinite(value)
2025
+ );
2026
+ }
2027
+ function isValidImportedAccounting(value) {
2028
+ if (!value || typeof value !== "object" || Array.isArray(value)) return false;
2029
+ const a = value;
2030
+ if (a.version !== 1) return false;
2031
+ if (a.currency !== "USD") return false;
2032
+ if (!isFiniteNonNegative(a.knownCost)) return false;
2033
+ if (a.completeness !== "complete" && a.completeness !== "incomplete" && a.completeness !== "unverified") {
2034
+ return false;
2035
+ }
2036
+ if (!allNumeric(a.reasons)) return false;
2037
+ if (!allNumeric(a.usage)) return false;
2038
+ const ops = a.operations;
2039
+ if (!ops || typeof ops !== "object") return false;
2040
+ for (const key of ["total", "settled", "unknown", "denied"]) {
2041
+ if (!isFiniteNonNegative(ops[key])) return false;
2042
+ }
2043
+ if (!allNumeric(ops.byKind)) return false;
2044
+ if (ops.total !== ops.settled + ops.unknown) return false;
2045
+ if (a.completeness === "unverified") return true;
2046
+ const provenanceTotal = sumOf(a.provenance);
2047
+ if (provenanceTotal === void 0) return false;
2048
+ if (Math.abs(provenanceTotal - a.knownCost) > EPSILON) return false;
2049
+ const breakdown = a.breakdown;
2050
+ if (!breakdown || typeof breakdown !== "object") return false;
2051
+ const breakdownTotal = sumOf({
2052
+ generation: breakdown.generation,
2053
+ judging: breakdown.judging,
2054
+ external: breakdown.external
2055
+ });
2056
+ if (breakdownTotal === void 0) return false;
2057
+ if (Math.abs(breakdownTotal - a.knownCost) > EPSILON) return false;
2058
+ return true;
2059
+ }
2060
+ function importedAccountingIsTrustworthy(result) {
2061
+ if (!result || typeof result !== "object") return false;
2062
+ const r = result;
2063
+ if (r.accounting !== void 0 && !isValidImportedAccounting(r.accounting)) return false;
2064
+ const budget = r.accounting?.budget;
2065
+ if (budget !== void 0 && !isValidImportedBudget(budget)) return false;
2066
+ const coverage = r.summary?.coverage;
2067
+ if (coverage !== void 0 && !isValidImportedCoverage(coverage)) return false;
2068
+ if (!Array.isArray(r.items)) return true;
2069
+ for (const item of r.items) {
2070
+ if (!item || typeof item !== "object") continue;
2071
+ const i = item;
2072
+ if (i.accounting !== void 0 && !isValidImportedAccounting(i.accounting)) return false;
2073
+ if (i.scoreDetails && typeof i.scoreDetails === "object") {
2074
+ for (const detail of Object.values(i.scoreDetails)) {
2075
+ const d = detail;
2076
+ if (d?.accounting !== void 0 && !isValidImportedAccounting(d.accounting)) return false;
2077
+ }
2078
+ }
2079
+ }
2080
+ return true;
2081
+ }
2082
+ function stripAccounting(result) {
2083
+ const copy = structuredClone(result);
2084
+ delete copy.accounting;
2085
+ const summary = copy.summary;
2086
+ if (summary && typeof summary === "object") {
2087
+ delete summary.coverage;
2088
+ }
2089
+ const items = copy.items;
2090
+ if (Array.isArray(items)) {
2091
+ for (const item of items) {
2092
+ if (!item || typeof item !== "object") continue;
2093
+ const i = item;
2094
+ delete i.accounting;
2095
+ const details = i.scoreDetails;
2096
+ if (details && typeof details === "object") {
2097
+ for (const detail of Object.values(details)) {
2098
+ if (detail && typeof detail === "object") {
2099
+ delete detail.accounting;
2100
+ }
2101
+ }
2102
+ }
2103
+ }
2104
+ }
2105
+ return copy;
2106
+ }
2107
+
2108
+ // src/server/routes/evals.ts
1748
2109
  function createEvalRoutes(connMgr, evalLoader) {
1749
2110
  const app5 = new import_hono10.Hono();
1750
2111
  const activeRuns = /* @__PURE__ */ new Map();
@@ -1792,6 +2153,7 @@ function createEvalRoutes(connMgr, evalLoader) {
1792
2153
  let runs = 1;
1793
2154
  let stream = false;
1794
2155
  let captureTraces = false;
2156
+ let captureRequests = false;
1795
2157
  try {
1796
2158
  const body = await c.req.json().catch(() => ({}));
1797
2159
  if (typeof body.runs === "number" && Number.isFinite(body.runs) && body.runs > 1) {
@@ -1803,6 +2165,9 @@ function createEvalRoutes(connMgr, evalLoader) {
1803
2165
  if (body.captureTraces === true) {
1804
2166
  captureTraces = true;
1805
2167
  }
2168
+ if (body.captureRequests === true) {
2169
+ captureRequests = true;
2170
+ }
1806
2171
  } catch {
1807
2172
  }
1808
2173
  if (stream) {
@@ -1826,6 +2191,7 @@ function createEvalRoutes(connMgr, evalLoader) {
1826
2191
  metadata: { runGroupId, runIndex: r, batchAttempted: runs },
1827
2192
  signal: ac.signal,
1828
2193
  captureTraces,
2194
+ captureRequests,
1829
2195
  onProgress: (event) => {
1830
2196
  if (event.type === "run_done") return;
1831
2197
  connMgr.broadcastWithWildcard(`eval:${evalRunId}`, {
@@ -1898,6 +2264,7 @@ function createEvalRoutes(connMgr, evalLoader) {
1898
2264
  const result = await runtime.runRegisteredEval(name, {
1899
2265
  signal: ac.signal,
1900
2266
  captureTraces,
2267
+ captureRequests,
1901
2268
  onProgress: (event) => {
1902
2269
  if (event.type === "run_done") return;
1903
2270
  connMgr.broadcastWithWildcard(`eval:${evalRunId}`, event);
@@ -1929,7 +2296,8 @@ function createEvalRoutes(connMgr, evalLoader) {
1929
2296
  try {
1930
2297
  const result2 = await runtime.runRegisteredEval(name, {
1931
2298
  metadata: { runGroupId, runIndex: r, batchAttempted: runs },
1932
- captureTraces
2299
+ captureTraces,
2300
+ captureRequests
1933
2301
  });
1934
2302
  results.push(result2);
1935
2303
  } catch (err) {
@@ -1945,11 +2313,14 @@ function createEvalRoutes(connMgr, evalLoader) {
1945
2313
  const partial2 = results.length < runs;
1946
2314
  const failureMsg = runFailure ? redactErrorMessage(runFailure, redactOn) || String(runFailure) || void 0 : void 0;
1947
2315
  const aggDegraded = unionDegradedScorers(results);
2316
+ const worstItemRate = worstItemErrorRate(results);
2317
+ const { modelTiming: _runOneModelTiming, ...firstSummary } = first.summary;
1948
2318
  const result = {
1949
2319
  ...first,
1950
2320
  summary: {
1951
- ...first.summary,
1952
- ...aggDegraded.length > 0 ? { degraded: aggDegraded } : {}
2321
+ ...firstSummary,
2322
+ ...aggDegraded.length > 0 ? { degraded: aggDegraded } : {},
2323
+ ...worstItemRate ? { itemErrorRate: worstItemRate } : {}
1953
2324
  },
1954
2325
  _multiRun: {
1955
2326
  aggregate,
@@ -1967,7 +2338,10 @@ function createEvalRoutes(connMgr, evalLoader) {
1967
2338
  data: redactEvalResult(result, redactOn)
1968
2339
  });
1969
2340
  } else {
1970
- const result = await runtime.runRegisteredEval(name, { captureTraces });
2341
+ const result = await runtime.runRegisteredEval(name, {
2342
+ captureTraces,
2343
+ captureRequests
2344
+ });
1971
2345
  return c.json({
1972
2346
  ok: true,
1973
2347
  data: redactEvalResult(result, redactOn)
@@ -1980,6 +2354,106 @@ function createEvalRoutes(connMgr, evalLoader) {
1980
2354
  );
1981
2355
  }
1982
2356
  });
2357
+ async function resolveDiagnostics(runtime, id) {
2358
+ const entry = await runtime.getEvalResult(id);
2359
+ const artifactId = entry?.data?.diagnostics?.artifactId;
2360
+ return typeof artifactId === "string" && artifactId !== "" ? { artifactId } : void 0;
2361
+ }
2362
+ app5.get("/evals/:id/diagnostics", async (c) => {
2363
+ const runtime = c.get("runtime");
2364
+ const id = c.req.param("id");
2365
+ const resolved = await resolveDiagnostics(runtime, id);
2366
+ if (!resolved) {
2367
+ return c.json(
2368
+ {
2369
+ ok: false,
2370
+ error: {
2371
+ code: "NOT_FOUND",
2372
+ message: `Eval result "${id}" has no captured requests`
2373
+ }
2374
+ },
2375
+ 404
2376
+ );
2377
+ }
2378
+ const opened = await runtime.openDiagnosticArtifact(resolved.artifactId);
2379
+ if (!opened) {
2380
+ return c.json(
2381
+ {
2382
+ ok: false,
2383
+ error: {
2384
+ code: "NOT_FOUND",
2385
+ message: `Captured requests for eval result "${id}" are no longer available`
2386
+ }
2387
+ },
2388
+ 404
2389
+ );
2390
+ }
2391
+ return c.json({
2392
+ ok: true,
2393
+ data: {
2394
+ artifactId: opened.manifest.artifactId,
2395
+ status: opened.manifest.status,
2396
+ ...opened.manifest.reason !== void 0 ? { reason: opened.manifest.reason } : {},
2397
+ records: opened.manifest.records,
2398
+ bytes: opened.manifest.bytes,
2399
+ fidelity: opened.manifest.fidelity,
2400
+ redaction: opened.manifest.redaction,
2401
+ ...opened.manifest.expiresAt !== void 0 ? { expiresAt: opened.manifest.expiresAt } : {},
2402
+ ...opened.manifest.copiedFrom !== void 0 ? { copiedFrom: opened.manifest.copiedFrom } : {}
2403
+ }
2404
+ });
2405
+ });
2406
+ app5.get("/evals/:id/diagnostics/records", async (c) => {
2407
+ const runtime = c.get("runtime");
2408
+ const redactOn = runtime.isRedactEnabled();
2409
+ const id = c.req.param("id");
2410
+ const resolved = await resolveDiagnostics(runtime, id);
2411
+ const opened = resolved ? await runtime.openDiagnosticArtifact(resolved.artifactId) : void 0;
2412
+ if (!opened) {
2413
+ return c.json(
2414
+ {
2415
+ ok: false,
2416
+ error: {
2417
+ code: "NOT_FOUND",
2418
+ message: `Captured requests for eval result "${id}" are not available`
2419
+ }
2420
+ },
2421
+ 404
2422
+ );
2423
+ }
2424
+ let cancelled = false;
2425
+ const lines = opened.lines[Symbol.asyncIterator]();
2426
+ return new Response(
2427
+ new ReadableStream({
2428
+ async start(controller) {
2429
+ const encoder = new TextEncoder();
2430
+ try {
2431
+ for (; ; ) {
2432
+ const next = await lines.next();
2433
+ if (next.done || cancelled) break;
2434
+ controller.enqueue(encoder.encode(`${redactRecordLine(next.value, redactOn)}
2435
+ `));
2436
+ }
2437
+ if (!cancelled) controller.close();
2438
+ } catch (error48) {
2439
+ if (!cancelled) controller.error(error48);
2440
+ } finally {
2441
+ await lines.return?.().catch(() => void 0);
2442
+ }
2443
+ },
2444
+ cancel() {
2445
+ cancelled = true;
2446
+ }
2447
+ }),
2448
+ {
2449
+ status: 200,
2450
+ headers: {
2451
+ "Content-Type": "application/x-ndjson; charset=utf-8",
2452
+ "Cache-Control": "no-store"
2453
+ }
2454
+ }
2455
+ );
2456
+ });
1983
2457
  app5.post("/evals/runs/:evalRunId/cancel", (c) => {
1984
2458
  const evalRunId = c.req.param("evalRunId");
1985
2459
  const ac = activeRuns.get(evalRunId);
@@ -1999,6 +2473,7 @@ function createEvalRoutes(connMgr, evalLoader) {
1999
2473
  const redactOn = runtime.isRedactEnabled();
2000
2474
  const name = c.req.param("name");
2001
2475
  const body = await c.req.json();
2476
+ const captureRequests = body.captureRequests === true;
2002
2477
  if (!body.resultId || typeof body.resultId !== "string") {
2003
2478
  return c.json(
2004
2479
  { ok: false, error: { code: "BAD_REQUEST", message: "resultId is required" } },
@@ -2012,8 +2487,7 @@ function createEvalRoutes(connMgr, evalLoader) {
2012
2487
  404
2013
2488
  );
2014
2489
  }
2015
- const history = await runtime.getEvalHistory();
2016
- const historyEntry = history.find((h) => h.id === body.resultId);
2490
+ const historyEntry = await runtime.getEvalResult(body.resultId);
2017
2491
  if (!historyEntry) {
2018
2492
  return c.json(
2019
2493
  { ok: false, error: { code: "NOT_FOUND", message: `Result "${body.resultId}" not found` } },
@@ -2026,7 +2500,8 @@ function createEvalRoutes(connMgr, evalLoader) {
2026
2500
  const result = await rescore(
2027
2501
  historyEntry.data,
2028
2502
  config2.scorers,
2029
- runtime
2503
+ runtime,
2504
+ captureRequests ? { captureRequests: true } : void 0
2030
2505
  );
2031
2506
  await runtime.saveEvalResult({
2032
2507
  id: result.id,
@@ -2080,8 +2555,13 @@ function createEvalRoutes(connMgr, evalLoader) {
2080
2555
  400
2081
2556
  );
2082
2557
  }
2083
- const history = await runtime.getEvalHistory();
2084
- const byId = new Map(history.map((h) => [h.id, h.data]));
2558
+ const idsOf = (v) => Array.isArray(v) ? v : [v];
2559
+ const requested = /* @__PURE__ */ new Set([...idsOf(body.baselineId), ...idsOf(body.candidateId)]);
2560
+ const byId = /* @__PURE__ */ new Map();
2561
+ for (const id of requested) {
2562
+ const entry = await runtime.getEvalResult(id);
2563
+ if (entry) byId.set(id, entry.data);
2564
+ }
2085
2565
  const missing = [];
2086
2566
  const resolveOne = (id) => {
2087
2567
  const data = byId.get(id);
@@ -2117,7 +2597,10 @@ function createEvalRoutes(connMgr, evalLoader) {
2117
2597
  }
2118
2598
  try {
2119
2599
  const result = await runtime.evalCompare(baseline, candidate, body.options);
2120
- return c.json({ ok: true, data: result });
2600
+ return c.json({
2601
+ ok: true,
2602
+ data: redactEvalComparison(result, redactOn)
2603
+ });
2121
2604
  } catch (err) {
2122
2605
  return c.json(
2123
2606
  {
@@ -2185,6 +2668,26 @@ function createEvalRoutes(connMgr, evalLoader) {
2185
2668
  const workflowsFromMeta = Array.isArray(metadataObj.workflows) ? metadataObj.workflows : [];
2186
2669
  const primaryWorkflow = workflowsFromMeta.find((w) => typeof w === "string");
2187
2670
  const evalName = trim(body.eval) ?? trim(primaryWorkflow) ?? trim(firstResult.workflow) ?? "imported";
2671
+ let readAccounting;
2672
+ let validateRequestSidecar;
2673
+ try {
2674
+ ({ readAccounting, validateRequestSidecar } = await import("@axlsdk/eval"));
2675
+ } catch {
2676
+ readAccounting = void 0;
2677
+ validateRequestSidecar = void 0;
2678
+ }
2679
+ let sidecarLines;
2680
+ if (body.requests !== void 0 && body.requests !== null) {
2681
+ if (!validateRequestSidecar) {
2682
+ return bad("importing captured requests requires @axlsdk/eval to be installed");
2683
+ }
2684
+ const validation = validateRequestSidecar(body.requests);
2685
+ if (!validation.ok) return bad(validation.reason);
2686
+ sidecarLines = validation.lines;
2687
+ }
2688
+ if (sidecarLines && validatedResults.length > 1) {
2689
+ return bad("a requests sidecar can only accompany a single result");
2690
+ }
2188
2691
  const timestamp = Date.now();
2189
2692
  const imported = [];
2190
2693
  for (const r of validatedResults) {
@@ -2194,6 +2697,42 @@ function createEvalRoutes(connMgr, evalLoader) {
2194
2697
  id,
2195
2698
  metadata: typeof r.metadata === "object" && r.metadata != null ? r.metadata : {}
2196
2699
  };
2700
+ if (entry.accounting === void 0) {
2701
+ if (entry.summary?.coverage !== void 0 && !isValidImportedCoverage(entry.summary.coverage)) {
2702
+ delete entry.summary.coverage;
2703
+ entry.metadata.importedAccounting = "invalid";
2704
+ }
2705
+ if (readAccounting) {
2706
+ entry.accounting = readAccounting(entry);
2707
+ }
2708
+ } else if (importedAccountingIsTrustworthy(entry)) {
2709
+ entry.metadata.importedAccounting = "declared";
2710
+ } else {
2711
+ const stripped = stripAccounting(entry);
2712
+ entry.accounting = readAccounting ? readAccounting(stripped) : void 0;
2713
+ entry.items = stripped.items;
2714
+ entry.summary = stripped.summary;
2715
+ entry.metadata.importedAccounting = "invalid";
2716
+ }
2717
+ if (entry.summary?.itemErrorRate !== void 0 && !isValidImportedItemErrorRate(entry.summary.itemErrorRate)) {
2718
+ delete entry.summary.itemErrorRate;
2719
+ entry.metadata.importedItemErrorRate = "invalid";
2720
+ }
2721
+ const multiRun = entry._multiRun;
2722
+ if (multiRun !== void 0 && !isValidImportedMultiRun(multiRun)) {
2723
+ delete entry._multiRun;
2724
+ entry.metadata.importedMultiRun = "invalid";
2725
+ }
2726
+ if (sidecarLines) {
2727
+ entry.diagnostics = await restageImportedRequests(runtime, id, sidecarLines);
2728
+ } else if (entry.diagnostics) {
2729
+ entry.diagnostics = {
2730
+ ...entry.diagnostics,
2731
+ artifactId: "",
2732
+ status: "unavailable",
2733
+ reason: "imported without its captured-request sidecar"
2734
+ };
2735
+ }
2197
2736
  await runtime.saveEvalResult({ id, eval: evalName, timestamp, data: entry });
2198
2737
  imported.push({ id, eval: evalName, timestamp });
2199
2738
  }
@@ -2202,12 +2741,72 @@ function createEvalRoutes(connMgr, evalLoader) {
2202
2741
  }
2203
2742
  return c.json({ ok: true, data: { imported } });
2204
2743
  });
2744
+ async function restageImportedRequests(runtime, ownerId, lines) {
2745
+ let stagedId;
2746
+ try {
2747
+ const staged = await runtime.stageDiagnosticArtifact({ kind: "eval", id: ownerId });
2748
+ stagedId = staged.artifactId;
2749
+ let bytes = 0;
2750
+ let allRedacted = lines.length > 0;
2751
+ for (const line of lines) {
2752
+ await staged.sink.append(line);
2753
+ bytes += Buffer.byteLength(line, "utf-8");
2754
+ if (allRedacted) {
2755
+ try {
2756
+ allRedacted = JSON.parse(line).captured?.redacted === true;
2757
+ } catch {
2758
+ allRedacted = false;
2759
+ }
2760
+ }
2761
+ }
2762
+ const manifest = await runtime.finalizeDiagnosticArtifact(
2763
+ staged.artifactId,
2764
+ "complete",
2765
+ void 0,
2766
+ allRedacted ? "applied" : "none"
2767
+ );
2768
+ return {
2769
+ version: 1,
2770
+ artifactId: manifest.artifactId,
2771
+ fidelity: "runtime_request",
2772
+ status: manifest.status,
2773
+ records: lines.length,
2774
+ bytes,
2775
+ redaction: manifest.redaction
2776
+ };
2777
+ } catch (error48) {
2778
+ if (stagedId !== void 0) {
2779
+ await runtime.rollbackDiagnosticArtifact(stagedId).catch(() => void 0);
2780
+ }
2781
+ return {
2782
+ version: 1,
2783
+ artifactId: "",
2784
+ fidelity: "runtime_request",
2785
+ status: "unavailable",
2786
+ reason: `captured requests could not be stored: ${error48 instanceof Error ? error48.message : String(error48)}`,
2787
+ records: 0,
2788
+ bytes: 0,
2789
+ redaction: "none"
2790
+ };
2791
+ }
2792
+ }
2205
2793
  function closeActiveRuns() {
2206
2794
  for (const ac of activeRuns.values()) ac.abort();
2207
2795
  activeRuns.clear();
2208
2796
  }
2209
2797
  return { app: app5, closeActiveRuns };
2210
2798
  }
2799
+ function worstItemErrorRate(results) {
2800
+ let worst;
2801
+ let runsExceeded = 0;
2802
+ for (const run of results) {
2803
+ const r = run.summary?.itemErrorRate;
2804
+ if (!r) continue;
2805
+ if (r.exceeded) runsExceeded++;
2806
+ if (!worst || r.rate > worst.rate) worst = r;
2807
+ }
2808
+ return worst ? { ...worst, runsExceeded } : void 0;
2809
+ }
2211
2810
  function unionDegradedScorers(results) {
2212
2811
  const byScorer = /* @__PURE__ */ new Map();
2213
2812
  for (const run of results) {
@@ -2218,8 +2817,8 @@ function unionDegradedScorers(results) {
2218
2817
  if (!existing) {
2219
2818
  byScorer.set(d.scorer, { ...d, runsAffected: 1 });
2220
2819
  } else {
2221
- const worse = d.rate > existing.rate ? d : existing;
2222
- byScorer.set(d.scorer, { ...worse, runsAffected: existing.runsAffected + 1 });
2820
+ const worse2 = d.rate > existing.rate ? d : existing;
2821
+ byScorer.set(d.scorer, { ...worse2, runsAffected: existing.runsAffected + 1 });
2223
2822
  }
2224
2823
  }
2225
2824
  }
@@ -2859,7 +3458,7 @@ __export(util_exports, {
2859
3458
  getSizableOrigin: () => getSizableOrigin,
2860
3459
  hexToUint8Array: () => hexToUint8Array,
2861
3460
  isObject: () => isObject,
2862
- isPlainObject: () => isPlainObject,
3461
+ isPlainObject: () => isPlainObject2,
2863
3462
  issue: () => issue,
2864
3463
  joinValues: () => joinValues,
2865
3464
  jsonStringifyReplacer: () => jsonStringifyReplacer,
@@ -3043,7 +3642,7 @@ var allowsEval = cached(() => {
3043
3642
  return false;
3044
3643
  }
3045
3644
  });
3046
- function isPlainObject(o) {
3645
+ function isPlainObject2(o) {
3047
3646
  if (isObject(o) === false)
3048
3647
  return false;
3049
3648
  const ctor = o.constructor;
@@ -3060,7 +3659,7 @@ function isPlainObject(o) {
3060
3659
  return true;
3061
3660
  }
3062
3661
  function shallowClone(o) {
3063
- if (isPlainObject(o))
3662
+ if (isPlainObject2(o))
3064
3663
  return { ...o };
3065
3664
  if (Array.isArray(o))
3066
3665
  return [...o];
@@ -3253,7 +3852,7 @@ function omit(schema, mask) {
3253
3852
  return clone(schema, def);
3254
3853
  }
3255
3854
  function extend(schema, shape) {
3256
- if (!isPlainObject(shape)) {
3855
+ if (!isPlainObject2(shape)) {
3257
3856
  throw new Error("Invalid input to extend: expected a plain object");
3258
3857
  }
3259
3858
  const checks = schema._zod.def.checks;
@@ -3276,7 +3875,7 @@ function extend(schema, shape) {
3276
3875
  return clone(schema, def);
3277
3876
  }
3278
3877
  function safeExtend(schema, shape) {
3279
- if (!isPlainObject(shape)) {
3878
+ if (!isPlainObject2(shape)) {
3280
3879
  throw new Error("Invalid input to safeExtend: expected a plain object");
3281
3880
  }
3282
3881
  const def = mergeDefs(schema._zod.def, {
@@ -5551,7 +6150,7 @@ function mergeValues(a, b) {
5551
6150
  if (a instanceof Date && b instanceof Date && +a === +b) {
5552
6151
  return { valid: true, data: a };
5553
6152
  }
5554
- if (isPlainObject(a) && isPlainObject(b)) {
6153
+ if (isPlainObject2(a) && isPlainObject2(b)) {
5555
6154
  const bKeys = Object.keys(b);
5556
6155
  const sharedKeys = Object.keys(a).filter((key) => bKeys.indexOf(key) !== -1);
5557
6156
  const newObj = { ...a, ...b };
@@ -5705,7 +6304,7 @@ var $ZodRecord = /* @__PURE__ */ $constructor("$ZodRecord", (inst, def) => {
5705
6304
  $ZodType.init(inst, def);
5706
6305
  inst._zod.parse = (payload, ctx) => {
5707
6306
  const input = payload.value;
5708
- if (!isPlainObject(input)) {
6307
+ if (!isPlainObject2(input)) {
5709
6308
  payload.issues.push({
5710
6309
  expected: "record",
5711
6310
  code: "invalid_type",
@@ -6713,8 +7312,8 @@ function az_default() {
6713
7312
  }
6714
7313
 
6715
7314
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/be.js
6716
- function getBelarusianPlural(count, one, few, many) {
6717
- const absCount = Math.abs(count);
7315
+ function getBelarusianPlural(count2, one, few, many) {
7316
+ const absCount = Math.abs(count2);
6718
7317
  const lastDigit = absCount % 10;
6719
7318
  const lastTwoDigits = absCount % 100;
6720
7319
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {
@@ -8538,8 +9137,8 @@ function hu_default() {
8538
9137
  }
8539
9138
 
8540
9139
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/hy.js
8541
- function getArmenianPlural(count, one, many) {
8542
- return Math.abs(count) === 1 ? one : many;
9140
+ function getArmenianPlural(count2, one, many) {
9141
+ return Math.abs(count2) === 1 ? one : many;
8543
9142
  }
8544
9143
  function withDefiniteArticle(word) {
8545
9144
  if (!word)
@@ -10547,8 +11146,8 @@ function pt_default() {
10547
11146
  }
10548
11147
 
10549
11148
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ru.js
10550
- function getRussianPlural(count, one, few, many) {
10551
- const absCount = Math.abs(count);
11149
+ function getRussianPlural(count2, one, few, many) {
11150
+ const absCount = Math.abs(count2);
10552
11151
  const lastDigit = absCount % 10;
10553
11152
  const lastTwoDigits = absCount % 100;
10554
11153
  if (lastTwoDigits >= 11 && lastTwoDigits <= 19) {