@opensearch-project/agent-health 0.5.2 → 0.7.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 (230) hide show
  1. package/README.md +1 -0
  2. package/cli/dist/index.js +2325 -961
  3. package/dist/assets/index-D-Np_l_T.js +246 -0
  4. package/dist/assets/index-vZt9QZKf.css +1 -0
  5. package/dist/index.html +2 -2
  6. package/docs/CLI.md +183 -3
  7. package/docs/CONFIGURATION.md +1 -1
  8. package/docs/CONNECTORS.md +1 -1
  9. package/docs/INSTRUMENT_WITH_OTEL.md +7 -0
  10. package/docs/SDK.md +178 -5
  11. package/docs/STORAGE_INDEX_FIELD_LIMITS.md +216 -0
  12. package/docs/skills/AGENT_HEALTH.md +55 -1
  13. package/docs/skills/add-connector/SKILL.md +5 -1
  14. package/examples/eval-files/demo.eval.js +1 -1
  15. package/examples/eval-files/ops-rca-classification.eval.js +71 -0
  16. package/examples/eval-files/ops-rca-evaluator.json +15 -0
  17. package/examples/eval-files/sdk-demo.eval.js +72 -0
  18. package/examples/eval-files/sdk-describe-demo.eval.js +50 -0
  19. package/examples/eval-files/sdk-hooks-demo.eval.js +1 -1
  20. package/lib/dist/lib/agentTrends.d.ts +210 -0
  21. package/lib/dist/lib/agentTrends.d.ts.map +1 -0
  22. package/lib/dist/lib/agentTrends.js +360 -0
  23. package/lib/dist/lib/agentTrends.js.map +1 -0
  24. package/lib/dist/lib/bedrockCompat.d.ts +27 -0
  25. package/lib/dist/lib/bedrockCompat.d.ts.map +1 -0
  26. package/lib/dist/lib/bedrockCompat.js +83 -0
  27. package/lib/dist/lib/bedrockCompat.js.map +1 -0
  28. package/lib/dist/lib/benchmarkCaseReview.d.ts +114 -0
  29. package/lib/dist/lib/benchmarkCaseReview.d.ts.map +1 -0
  30. package/lib/dist/lib/benchmarkCaseReview.js +177 -0
  31. package/lib/dist/lib/benchmarkCaseReview.js.map +1 -0
  32. package/lib/dist/lib/benchmarkImage.d.ts +52 -0
  33. package/lib/dist/lib/benchmarkImage.d.ts.map +1 -0
  34. package/lib/dist/lib/benchmarkImage.js +113 -0
  35. package/lib/dist/lib/benchmarkImage.js.map +1 -0
  36. package/lib/dist/lib/benchmarkRunsTable.d.ts +109 -0
  37. package/lib/dist/lib/benchmarkRunsTable.d.ts.map +1 -0
  38. package/lib/dist/lib/benchmarkRunsTable.js +212 -0
  39. package/lib/dist/lib/benchmarkRunsTable.js.map +1 -0
  40. package/lib/dist/lib/benchmarkVersionUtils.d.ts +13 -0
  41. package/lib/dist/lib/benchmarkVersionUtils.d.ts.map +1 -1
  42. package/lib/dist/lib/benchmarkVersionUtils.js +21 -0
  43. package/lib/dist/lib/benchmarkVersionUtils.js.map +1 -1
  44. package/lib/dist/lib/chunkedFetch.d.ts +18 -0
  45. package/lib/dist/lib/chunkedFetch.d.ts.map +1 -0
  46. package/lib/dist/lib/chunkedFetch.js +40 -0
  47. package/lib/dist/lib/chunkedFetch.js.map +1 -0
  48. package/lib/dist/lib/comparisonInsights.d.ts +151 -0
  49. package/lib/dist/lib/comparisonInsights.d.ts.map +1 -0
  50. package/lib/dist/lib/comparisonInsights.js +270 -0
  51. package/lib/dist/lib/comparisonInsights.js.map +1 -0
  52. package/lib/dist/lib/config/loader.d.ts.map +1 -1
  53. package/lib/dist/lib/config/loader.js +16 -1
  54. package/lib/dist/lib/config/loader.js.map +1 -1
  55. package/lib/dist/lib/config/types.d.ts +14 -0
  56. package/lib/dist/lib/config/types.d.ts.map +1 -1
  57. package/lib/dist/lib/constants.d.ts +11 -0
  58. package/lib/dist/lib/constants.d.ts.map +1 -1
  59. package/lib/dist/lib/constants.js +10 -1
  60. package/lib/dist/lib/constants.js.map +1 -1
  61. package/lib/dist/lib/contextFormat.d.ts +26 -0
  62. package/lib/dist/lib/contextFormat.d.ts.map +1 -0
  63. package/lib/dist/lib/contextFormat.js +28 -0
  64. package/lib/dist/lib/contextFormat.js.map +1 -0
  65. package/lib/dist/lib/dashboardMetrics.d.ts +11 -2
  66. package/lib/dist/lib/dashboardMetrics.d.ts.map +1 -1
  67. package/lib/dist/lib/dashboardMetrics.js +38 -3
  68. package/lib/dist/lib/dashboardMetrics.js.map +1 -1
  69. package/lib/dist/lib/envCompat.d.ts.map +1 -1
  70. package/lib/dist/lib/envCompat.js +14 -5
  71. package/lib/dist/lib/envCompat.js.map +1 -1
  72. package/lib/dist/lib/evaluationRerun.d.ts +102 -0
  73. package/lib/dist/lib/evaluationRerun.d.ts.map +1 -0
  74. package/lib/dist/lib/evaluationRerun.js +134 -0
  75. package/lib/dist/lib/evaluationRerun.js.map +1 -0
  76. package/lib/dist/lib/judgeFailureSummary.d.ts +66 -0
  77. package/lib/dist/lib/judgeFailureSummary.d.ts.map +1 -0
  78. package/lib/dist/lib/judgeFailureSummary.js +68 -0
  79. package/lib/dist/lib/judgeFailureSummary.js.map +1 -0
  80. package/lib/dist/lib/judgeStrategies.d.ts +108 -0
  81. package/lib/dist/lib/judgeStrategies.d.ts.map +1 -0
  82. package/lib/dist/lib/judgeStrategies.js +135 -0
  83. package/lib/dist/lib/judgeStrategies.js.map +1 -0
  84. package/lib/dist/lib/matchers/expect.d.ts +21 -1
  85. package/lib/dist/lib/matchers/expect.d.ts.map +1 -1
  86. package/lib/dist/lib/matchers/expect.js +51 -0
  87. package/lib/dist/lib/matchers/expect.js.map +1 -1
  88. package/lib/dist/lib/matchers/judgeAccessor.d.ts +4 -0
  89. package/lib/dist/lib/matchers/judgeAccessor.d.ts.map +1 -1
  90. package/lib/dist/lib/matchers/judgeAccessor.js +13 -2
  91. package/lib/dist/lib/matchers/judgeAccessor.js.map +1 -1
  92. package/lib/dist/lib/matchers/judgeReasoningParse.d.ts +49 -0
  93. package/lib/dist/lib/matchers/judgeReasoningParse.d.ts.map +1 -0
  94. package/lib/dist/lib/matchers/judgeReasoningParse.js +128 -0
  95. package/lib/dist/lib/matchers/judgeReasoningParse.js.map +1 -0
  96. package/lib/dist/lib/matchers/traces.d.ts +17 -2
  97. package/lib/dist/lib/matchers/traces.d.ts.map +1 -1
  98. package/lib/dist/lib/matchers/traces.js +136 -16
  99. package/lib/dist/lib/matchers/traces.js.map +1 -1
  100. package/lib/dist/lib/matchers/tracesPricing.d.ts +38 -0
  101. package/lib/dist/lib/matchers/tracesPricing.d.ts.map +1 -0
  102. package/lib/dist/lib/matchers/tracesPricing.js +64 -0
  103. package/lib/dist/lib/matchers/tracesPricing.js.map +1 -0
  104. package/lib/dist/lib/matchers/types.d.ts +25 -0
  105. package/lib/dist/lib/matchers/types.d.ts.map +1 -1
  106. package/lib/dist/lib/resolveCanonicalRun.d.ts +23 -0
  107. package/lib/dist/lib/resolveCanonicalRun.d.ts.map +1 -0
  108. package/lib/dist/lib/resolveCanonicalRun.js +26 -0
  109. package/lib/dist/lib/resolveCanonicalRun.js.map +1 -0
  110. package/lib/dist/lib/runActions.d.ts +120 -0
  111. package/lib/dist/lib/runActions.d.ts.map +1 -0
  112. package/lib/dist/lib/runActions.js +130 -0
  113. package/lib/dist/lib/runActions.js.map +1 -0
  114. package/lib/dist/lib/runInsights.d.ts +86 -0
  115. package/lib/dist/lib/runInsights.d.ts.map +1 -0
  116. package/lib/dist/lib/runInsights.js +185 -0
  117. package/lib/dist/lib/runInsights.js.map +1 -0
  118. package/lib/dist/lib/runName.d.ts +29 -0
  119. package/lib/dist/lib/runName.d.ts.map +1 -0
  120. package/lib/dist/lib/runName.js +38 -0
  121. package/lib/dist/lib/runName.js.map +1 -0
  122. package/lib/dist/lib/runReportPath.d.ts +16 -0
  123. package/lib/dist/lib/runReportPath.d.ts.map +1 -0
  124. package/lib/dist/lib/runReportPath.js +22 -0
  125. package/lib/dist/lib/runReportPath.js.map +1 -0
  126. package/lib/dist/lib/runSort.d.ts +27 -0
  127. package/lib/dist/lib/runSort.d.ts.map +1 -0
  128. package/lib/dist/lib/runSort.js +31 -0
  129. package/lib/dist/lib/runSort.js.map +1 -0
  130. package/lib/dist/lib/runStats.d.ts +109 -5
  131. package/lib/dist/lib/runStats.d.ts.map +1 -1
  132. package/lib/dist/lib/runStats.js +193 -10
  133. package/lib/dist/lib/runStats.js.map +1 -1
  134. package/lib/dist/lib/testCases/define.d.ts.map +1 -1
  135. package/lib/dist/lib/testCases/define.js +93 -46
  136. package/lib/dist/lib/testCases/define.js.map +1 -1
  137. package/lib/dist/lib/testCases/judge.d.ts.map +1 -1
  138. package/lib/dist/lib/testCases/judge.js +22 -4
  139. package/lib/dist/lib/testCases/judge.js.map +1 -1
  140. package/lib/dist/lib/testCases/loader.d.ts +35 -1
  141. package/lib/dist/lib/testCases/loader.d.ts.map +1 -1
  142. package/lib/dist/lib/testCases/loader.js +278 -31
  143. package/lib/dist/lib/testCases/loader.js.map +1 -1
  144. package/lib/dist/lib/trajectoryStepDisplay.d.ts +25 -0
  145. package/lib/dist/lib/trajectoryStepDisplay.d.ts.map +1 -0
  146. package/lib/dist/lib/trajectoryStepDisplay.js +42 -0
  147. package/lib/dist/lib/trajectoryStepDisplay.js.map +1 -0
  148. package/lib/dist/lib/utils.d.ts +34 -0
  149. package/lib/dist/lib/utils.d.ts.map +1 -1
  150. package/lib/dist/lib/utils.js +49 -0
  151. package/lib/dist/lib/utils.js.map +1 -1
  152. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts +68 -22
  153. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.d.ts.map +1 -1
  154. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js +148 -111
  155. package/lib/dist/services/connectors/claude-code/ClaudeCodeConnector.js.map +1 -1
  156. package/lib/dist/services/connectors/kiro/KiroConnector.d.ts +21 -13
  157. package/lib/dist/services/connectors/kiro/KiroConnector.d.ts.map +1 -1
  158. package/lib/dist/services/connectors/kiro/KiroConnector.js +22 -25
  159. package/lib/dist/services/connectors/kiro/KiroConnector.js.map +1 -1
  160. package/lib/dist/services/connectors/pi/PiConnector.d.ts +49 -10
  161. package/lib/dist/services/connectors/pi/PiConnector.d.ts.map +1 -1
  162. package/lib/dist/services/connectors/pi/PiConnector.js +102 -86
  163. package/lib/dist/services/connectors/pi/PiConnector.js.map +1 -1
  164. package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts +59 -14
  165. package/lib/dist/services/connectors/subprocess/SubprocessConnector.d.ts.map +1 -1
  166. package/lib/dist/services/connectors/subprocess/SubprocessConnector.js +95 -61
  167. package/lib/dist/services/connectors/subprocess/SubprocessConnector.js.map +1 -1
  168. package/lib/dist/services/evaluation/bedrockJudge.d.ts +18 -0
  169. package/lib/dist/services/evaluation/bedrockJudge.d.ts.map +1 -1
  170. package/lib/dist/services/evaluation/bedrockJudge.js +4 -0
  171. package/lib/dist/services/evaluation/bedrockJudge.js.map +1 -1
  172. package/lib/dist/services/evaluation/index.d.ts +18 -1
  173. package/lib/dist/services/evaluation/index.d.ts.map +1 -1
  174. package/lib/dist/services/evaluation/index.js +156 -19
  175. package/lib/dist/services/evaluation/index.js.map +1 -1
  176. package/lib/dist/services/metrics.d.ts +55 -0
  177. package/lib/dist/services/metrics.d.ts.map +1 -0
  178. package/lib/dist/services/metrics.js +89 -0
  179. package/lib/dist/services/metrics.js.map +1 -0
  180. package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts +1 -1
  181. package/lib/dist/services/storage/asyncBenchmarkStorage.d.ts.map +1 -1
  182. package/lib/dist/services/storage/asyncBenchmarkStorage.js +30 -3
  183. package/lib/dist/services/storage/asyncBenchmarkStorage.js.map +1 -1
  184. package/lib/dist/services/storage/asyncRunStorage.d.ts +20 -1
  185. package/lib/dist/services/storage/asyncRunStorage.d.ts.map +1 -1
  186. package/lib/dist/services/storage/asyncRunStorage.js +125 -2
  187. package/lib/dist/services/storage/asyncRunStorage.js.map +1 -1
  188. package/lib/dist/services/storage/asyncTestCaseStorage.d.ts +18 -4
  189. package/lib/dist/services/storage/asyncTestCaseStorage.d.ts.map +1 -1
  190. package/lib/dist/services/storage/asyncTestCaseStorage.js +21 -4
  191. package/lib/dist/services/storage/asyncTestCaseStorage.js.map +1 -1
  192. package/lib/dist/services/storage/opensearchClient.d.ts +47 -12
  193. package/lib/dist/services/storage/opensearchClient.d.ts.map +1 -1
  194. package/lib/dist/services/storage/opensearchClient.js +12 -5
  195. package/lib/dist/services/storage/opensearchClient.js.map +1 -1
  196. package/lib/dist/services/traces/browserRecovery.d.ts +12 -1
  197. package/lib/dist/services/traces/browserRecovery.d.ts.map +1 -1
  198. package/lib/dist/services/traces/browserRecovery.js +35 -5
  199. package/lib/dist/services/traces/browserRecovery.js.map +1 -1
  200. package/lib/dist/services/traces/index.d.ts +8 -1
  201. package/lib/dist/services/traces/index.d.ts.map +1 -1
  202. package/lib/dist/services/traces/index.js +33 -12
  203. package/lib/dist/services/traces/index.js.map +1 -1
  204. package/lib/dist/services/traces/judgeAgentsHints.d.ts +98 -3
  205. package/lib/dist/services/traces/judgeAgentsHints.d.ts.map +1 -1
  206. package/lib/dist/services/traces/judgeAgentsHints.js +144 -3
  207. package/lib/dist/services/traces/judgeAgentsHints.js.map +1 -1
  208. package/lib/dist/services/traces/messageExtraction.d.ts.map +1 -1
  209. package/lib/dist/services/traces/messageExtraction.js +95 -33
  210. package/lib/dist/services/traces/messageExtraction.js.map +1 -1
  211. package/lib/dist/services/traces/spansToTrajectory.d.ts.map +1 -1
  212. package/lib/dist/services/traces/spansToTrajectory.js +51 -13
  213. package/lib/dist/services/traces/spansToTrajectory.js.map +1 -1
  214. package/lib/dist/services/traces/tracePoller.d.ts +27 -3
  215. package/lib/dist/services/traces/tracePoller.d.ts.map +1 -1
  216. package/lib/dist/services/traces/tracePoller.js +196 -33
  217. package/lib/dist/services/traces/tracePoller.js.map +1 -1
  218. package/lib/dist/services/traces/trajectoryMerge.d.ts +79 -0
  219. package/lib/dist/services/traces/trajectoryMerge.d.ts.map +1 -0
  220. package/lib/dist/services/traces/trajectoryMerge.js +109 -0
  221. package/lib/dist/services/traces/trajectoryMerge.js.map +1 -0
  222. package/lib/dist/types/index.d.ts +250 -3
  223. package/lib/dist/types/index.d.ts.map +1 -1
  224. package/lib/dist/types/index.js +24 -0
  225. package/lib/dist/types/index.js.map +1 -1
  226. package/package.json +8 -5
  227. package/server/dist/app.js +5490 -1557
  228. package/server/dist/index.js +5490 -1557
  229. package/dist/assets/index-CCQRDlO0.js +0 -243
  230. package/dist/assets/index-CNHQVbcj.css +0 -1
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Pure helpers for the benchmark Runs tab (table + pass-rate-over-time chart).
3
+ *
4
+ * Kept free of React/DOM so the click-to-filter semantics and the chart
5
+ * series derivation can be unit-tested directly. The component
6
+ * (components/evals3/BenchmarkRunsPage.tsx) is a thin renderer over these.
7
+ */
8
+ import type { BenchmarkRun } from '../types/index.js';
9
+ import { getEffectiveRunStatus } from '../lib/runStats.js';
10
+ /** The dimensions a user can click on in the table to filter by. */
11
+ export type RunFilterField = 'agent' | 'model' | 'judge' | 'evaluator' | 'status';
12
+ export interface RunFilter {
13
+ field: RunFilterField;
14
+ /** Raw value (id/key), NOT the display label — labels can collide. */
15
+ value: string;
16
+ /** Human label for the pill. */
17
+ label: string;
18
+ }
19
+ export interface RunTableRow {
20
+ run: BenchmarkRun;
21
+ agentKey: string;
22
+ agentName: string;
23
+ modelId: string;
24
+ modelName: string;
25
+ judgeModelId: string;
26
+ judgeLabel: string;
27
+ evaluatorId: string;
28
+ evaluatorLabel: string;
29
+ status: ReturnType<typeof getEffectiveRunStatus>;
30
+ passed: number;
31
+ failed: number;
32
+ errored: number;
33
+ /** Still to come — only ever non-zero while the run is live. */
34
+ pending: number;
35
+ /** Per-case entries currently executing — only ever non-zero while the run is live. */
36
+ running: number;
37
+ /**
38
+ * Planned test cases that never executed because the run reached a
39
+ * TERMINAL status first (cancelled mid-way, or the executor died). Neither
40
+ * a pass, a fail nor "pending": nothing will ever happen to them, so they
41
+ * must never render with an in-progress spinner.
42
+ */
43
+ notRun: number;
44
+ total: number;
45
+ /**
46
+ * Pass rate over the *evaluable* set (total − errored − pending − running),
47
+ * or null when nothing has been evaluated yet. Percent 0–100.
48
+ */
49
+ passRate: number | null;
50
+ /** Number of test cases in the run (snapshotted size, falling back to results). */
51
+ size: number;
52
+ }
53
+ export interface RowLabelResolvers {
54
+ agentName: (agentKey: string) => string;
55
+ modelName: (modelId: string) => string;
56
+ judgeLabel: (judgeModelId?: string | null) => string;
57
+ evaluatorLabel: (evaluatorId?: string | null) => string;
58
+ }
59
+ export declare function computePassRate(passed: number, failed: number): number | null;
60
+ export declare function buildRunTableRow(run: BenchmarkRun, resolve: RowLabelResolvers): RunTableRow;
61
+ export declare function rowFieldValue(row: RunTableRow, field: RunFilterField): string;
62
+ export declare function rowFieldLabel(row: RunTableRow, field: RunFilterField): string;
63
+ export declare function isSameFilter(a: RunFilter, b: RunFilter): boolean;
64
+ /**
65
+ * Click semantics: clicking a value that is already an active filter removes
66
+ * it (toggle); otherwise it is added. Multiple values on the same field are
67
+ * OR-ed; different fields are AND-ed (see {@link applyRunFilters}).
68
+ */
69
+ export declare function toggleRunFilter(filters: RunFilter[], next: RunFilter): RunFilter[];
70
+ export declare function removeRunFilter(filters: RunFilter[], target: RunFilter): RunFilter[];
71
+ export declare function applyRunFilters(rows: RunTableRow[], filters: RunFilter[]): RunTableRow[];
72
+ export type RunSortField = 'name' | 'agent' | 'model' | 'size' | 'passRate' | 'judge' | 'evaluator' | 'date';
73
+ export interface RunSort {
74
+ field: RunSortField;
75
+ dir: 'asc' | 'desc';
76
+ }
77
+ export declare const DEFAULT_RUN_SORT: RunSort;
78
+ export declare function toggleRunSort(current: RunSort, field: RunSortField): RunSort;
79
+ export declare function sortRunRows(rows: RunTableRow[], sort: RunSort): RunTableRow[];
80
+ export interface PassRatePoint {
81
+ /** Epoch ms of run.createdAt — numeric so the X axis is a real time axis. */
82
+ t: number;
83
+ runId: string;
84
+ runName: string;
85
+ passRate: number;
86
+ passed: number;
87
+ failed: number;
88
+ total: number;
89
+ }
90
+ export interface PassRateSeries {
91
+ /** Series key = agentKey (the sketch groups lines by agent, e.g. CC vs AIS). */
92
+ key: string;
93
+ label: string;
94
+ points: PassRatePoint[];
95
+ }
96
+ /**
97
+ * One line per agent, points ordered by time. Runs without an evaluable
98
+ * result (pass rate null — e.g. still running with nothing judged, or fully
99
+ * errored) are excluded: plotting them as 0% would read as a regression.
100
+ */
101
+ export declare function buildPassRateSeries(rows: RunTableRow[]): PassRateSeries[];
102
+ /** Latest run = max createdAt over the given runs (not "first in the array" —
103
+ * the merged list appends standalone eval-run docs after embedded runs, so
104
+ * array order is not chronological). */
105
+ export declare function latestRunId(runs: Array<Pick<BenchmarkRun, 'id' | 'createdAt'>>): string | null;
106
+ /** Deterministic, distinguishable palette for agent lines (index-based). */
107
+ export declare const SERIES_COLORS: string[];
108
+ export declare function seriesColor(index: number): string;
109
+ //# sourceMappingURL=benchmarkRunsTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benchmarkRunsTable.d.ts","sourceRoot":"","sources":["../../benchmarkRunsTable.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,212 @@
1
+ /*
2
+ * Copyright OpenSearch Contributors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { computeRunStats, getEffectiveRunStatus } from '../lib/runStats.js';
6
+ export function computePassRate(passed, failed) {
7
+ const evaluable = passed + failed;
8
+ if (evaluable <= 0)
9
+ return null;
10
+ return Math.round((passed / evaluable) * 1000) / 10;
11
+ }
12
+ /**
13
+ * Run statuses after which no further per-case progress can happen. Only the
14
+ * EXPLICIT persisted status counts: the results-derived fallback in
15
+ * getEffectiveRunStatus reports 'completed' for any status-less legacy run
16
+ * whose observed results all happen to be settled — exactly what an in-flight
17
+ * legacy run looks like between two cases — so it must not gate bucketing
18
+ * (a status-less run therefore keeps the pre-existing pending rendering).
19
+ * Mirrors `TERMINAL_RUN_STATUSES` in the terminal-aware `lib/runStats`
20
+ * (#486); collapse onto `isTerminalRunStatus` from there once it lands.
21
+ */
22
+ function isTerminalStatus(status) {
23
+ return status === 'completed' || status === 'failed' || status === 'cancelled';
24
+ }
25
+ export function buildRunTableRow(run, resolve) {
26
+ const status = getEffectiveRunStatus(run);
27
+ const terminal = isTerminalStatus(run.status);
28
+ const { passed, failed, errored, total } = computeRunStats(run);
29
+ const settled = passed + failed + errored;
30
+ // Bug (owner report, 2026-09-08): a run cancelled at 43/62 rendered
31
+ // "11/32 /19 ⟳" — the never-started remainder (planned − observed) was
32
+ // re-derived as `pending` here regardless of the run's TERMINAL status, so
33
+ // every cancelled/failed run on the benchmark page looked in progress
34
+ // forever. Once the run is terminal nothing can start those cases (nor
35
+ // finish a per-case entry an executor left `running` when it died), so
36
+ // the remainder is `notRun`, and pending/running are zero by definition.
37
+ let running = 0;
38
+ if (!terminal) {
39
+ Object.values(run.results || {}).forEach(r => { if (r.status === 'running')
40
+ running++; });
41
+ }
42
+ const notRun = terminal ? Math.max(0, total - settled) : 0;
43
+ const pending = terminal ? 0 : Math.max(0, total - settled - running);
44
+ const size = run.testCaseSnapshots?.length || total;
45
+ const agentKey = run.agentKey || '';
46
+ const modelId = run.modelId || '';
47
+ const judgeModelId = run.judgeModelId || '';
48
+ const evaluatorId = run.evaluatorId || '';
49
+ return {
50
+ run,
51
+ agentKey,
52
+ agentName: resolve.agentName(agentKey),
53
+ modelId,
54
+ modelName: resolve.modelName(modelId),
55
+ judgeModelId,
56
+ judgeLabel: resolve.judgeLabel(judgeModelId || undefined),
57
+ evaluatorId,
58
+ evaluatorLabel: resolve.evaluatorLabel(evaluatorId || undefined),
59
+ status,
60
+ passed, failed, errored, pending, running, notRun, total,
61
+ passRate: computePassRate(passed, failed),
62
+ size,
63
+ };
64
+ }
65
+ // ─── Filters ─────────────────────────────────────────────────────────────────
66
+ export function rowFieldValue(row, field) {
67
+ switch (field) {
68
+ case 'agent': return row.agentKey;
69
+ case 'model': return row.modelId;
70
+ case 'judge': return row.judgeModelId;
71
+ case 'evaluator': return row.evaluatorId;
72
+ case 'status': return row.status;
73
+ }
74
+ }
75
+ export function rowFieldLabel(row, field) {
76
+ switch (field) {
77
+ case 'agent': return row.agentName;
78
+ case 'model': return row.modelName;
79
+ case 'judge': return row.judgeLabel;
80
+ case 'evaluator': return row.evaluatorLabel;
81
+ case 'status': return row.status;
82
+ }
83
+ }
84
+ export function isSameFilter(a, b) {
85
+ return a.field === b.field && a.value === b.value;
86
+ }
87
+ /**
88
+ * Click semantics: clicking a value that is already an active filter removes
89
+ * it (toggle); otherwise it is added. Multiple values on the same field are
90
+ * OR-ed; different fields are AND-ed (see {@link applyRunFilters}).
91
+ */
92
+ export function toggleRunFilter(filters, next) {
93
+ const exists = filters.some(f => isSameFilter(f, next));
94
+ return exists ? filters.filter(f => !isSameFilter(f, next)) : [...filters, next];
95
+ }
96
+ export function removeRunFilter(filters, target) {
97
+ return filters.filter(f => !isSameFilter(f, target));
98
+ }
99
+ export function applyRunFilters(rows, filters) {
100
+ if (filters.length === 0)
101
+ return rows;
102
+ const byField = new Map();
103
+ for (const f of filters) {
104
+ if (!byField.has(f.field))
105
+ byField.set(f.field, new Set());
106
+ byField.get(f.field).add(f.value);
107
+ }
108
+ return rows.filter(row => {
109
+ for (const [field, values] of byField) {
110
+ if (!values.has(rowFieldValue(row, field)))
111
+ return false;
112
+ }
113
+ return true;
114
+ });
115
+ }
116
+ export const DEFAULT_RUN_SORT = { field: 'date', dir: 'desc' };
117
+ export function toggleRunSort(current, field) {
118
+ if (current.field === field)
119
+ return { field, dir: current.dir === 'asc' ? 'desc' : 'asc' };
120
+ // Numeric/date columns default to descending (biggest/newest first);
121
+ // text columns to ascending.
122
+ const numeric = ['size', 'passRate', 'date'];
123
+ return { field, dir: numeric.includes(field) ? 'desc' : 'asc' };
124
+ }
125
+ export function sortRunRows(rows, sort) {
126
+ const dir = sort.dir === 'asc' ? 1 : -1;
127
+ const cmpNum = (a, b) => {
128
+ // nulls always sink to the bottom regardless of direction
129
+ if (a === null && b === null)
130
+ return 0;
131
+ if (a === null)
132
+ return 1;
133
+ if (b === null)
134
+ return -1;
135
+ return dir * (a - b);
136
+ };
137
+ return [...rows].sort((a, b) => {
138
+ switch (sort.field) {
139
+ case 'name': return dir * a.run.name.localeCompare(b.run.name);
140
+ case 'agent': return dir * a.agentName.localeCompare(b.agentName);
141
+ case 'model': return dir * a.modelName.localeCompare(b.modelName);
142
+ case 'judge': return dir * a.judgeLabel.localeCompare(b.judgeLabel);
143
+ case 'evaluator': return dir * a.evaluatorLabel.localeCompare(b.evaluatorLabel);
144
+ case 'size': return cmpNum(a.size, b.size);
145
+ case 'passRate': return cmpNum(a.passRate, b.passRate);
146
+ case 'date':
147
+ default:
148
+ return dir * (new Date(a.run.createdAt).getTime() - new Date(b.run.createdAt).getTime());
149
+ }
150
+ });
151
+ }
152
+ /**
153
+ * One line per agent, points ordered by time. Runs without an evaluable
154
+ * result (pass rate null — e.g. still running with nothing judged, or fully
155
+ * errored) are excluded: plotting them as 0% would read as a regression.
156
+ */
157
+ export function buildPassRateSeries(rows) {
158
+ const byAgent = new Map();
159
+ for (const row of rows) {
160
+ if (row.passRate === null)
161
+ continue;
162
+ const t = new Date(row.run.createdAt).getTime();
163
+ if (Number.isNaN(t))
164
+ continue;
165
+ let series = byAgent.get(row.agentKey);
166
+ if (!series) {
167
+ series = { key: row.agentKey, label: row.agentName, points: [] };
168
+ byAgent.set(row.agentKey, series);
169
+ }
170
+ series.points.push({
171
+ t, runId: row.run.id, runName: row.run.name,
172
+ passRate: row.passRate, passed: row.passed, failed: row.failed, total: row.total,
173
+ });
174
+ }
175
+ const out = [...byAgent.values()];
176
+ for (const s of out)
177
+ s.points.sort((a, b) => a.t - b.t);
178
+ // Order by label (then key) — NOT by point count. Series index drives the
179
+ // line colour, so the order must be stable while the page polls every few
180
+ // seconds and new runs land; "busiest first" would recolour agents mid-run.
181
+ out.sort((a, b) => a.label.localeCompare(b.label) || a.key.localeCompare(b.key));
182
+ return out;
183
+ }
184
+ /** Latest run = max createdAt over the given runs (not "first in the array" —
185
+ * the merged list appends standalone eval-run docs after embedded runs, so
186
+ * array order is not chronological). */
187
+ export function latestRunId(runs) {
188
+ let best = null;
189
+ for (const r of runs) {
190
+ const t = new Date(r.createdAt).getTime();
191
+ if (Number.isNaN(t))
192
+ continue;
193
+ if (!best || t > best.t)
194
+ best = { id: r.id, t };
195
+ }
196
+ return best?.id ?? null;
197
+ }
198
+ /** Deterministic, distinguishable palette for agent lines (index-based). */
199
+ export const SERIES_COLORS = [
200
+ '#3b82f6', // blue-500
201
+ '#f59e0b', // amber-500
202
+ '#10b981', // emerald-500
203
+ '#8b5cf6', // violet-500
204
+ '#ef4444', // red-500
205
+ '#06b6d4', // cyan-500
206
+ '#ec4899', // pink-500
207
+ '#84cc16', // lime-500
208
+ ];
209
+ export function seriesColor(index) {
210
+ return SERIES_COLORS[index % SERIES_COLORS.length];
211
+ }
212
+ //# sourceMappingURL=benchmarkRunsTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"benchmarkRunsTable.js","sourceRoot":"","sources":["../../benchmarkRunsTable.ts"],"names":[],"mappings":"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"}
@@ -34,4 +34,17 @@ export declare function getVersionTestCases(testCases: TestCase[], selectedVersi
34
34
  * @param versionFilter - Version number to filter by, or 'all' for all runs
35
35
  */
36
36
  export declare function filterRunsByVersion(runs: BenchmarkRun[] | undefined, versionFilter: number | 'all'): BenchmarkRun[];
37
+ /**
38
+ * Resolve the effective run-version filter from a persisted (possibly stale)
39
+ * value. A persisted version the benchmark doesn't actually have — e.g. a
40
+ * filter set while viewing a different benchmark under the old global
41
+ * localStorage key, a deleted version, or corrupted storage — must behave as
42
+ * 'all' rather than filtering every run out and rendering a bogus
43
+ * "No runs for vN" empty state that looks like data loss.
44
+ *
45
+ * @param raw - persisted filter value
46
+ * @param availableVersions - the benchmark's actual version numbers
47
+ * (undefined while the benchmark is still loading — value passes through)
48
+ */
49
+ export declare function effectiveRunVersionFilter(raw: number | 'all', availableVersions: number[] | undefined): number | 'all';
37
50
  //# sourceMappingURL=benchmarkVersionUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"benchmarkVersionUtils.d.ts","sourceRoot":"","sources":["../../benchmarkVersionUtils.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAoB,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,WAAW,EAAE,CA0B7E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EAAE,EAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,GAC7B,WAAW,GAAG,IAAI,CAIpB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,QAAQ,EAAE,EACrB,mBAAmB,EAAE,WAAW,GAAG,IAAI,GACtC,QAAQ,EAAE,CAKZ;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAAE,GAAG,SAAS,EAChC,aAAa,EAAE,MAAM,GAAG,KAAK,GAC5B,YAAY,EAAE,CAShB"}
1
+ {"version":3,"file":"benchmarkVersionUtils.d.ts","sourceRoot":"","sources":["../../benchmarkVersionUtils.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAoB,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnF;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,IAAI,GAAG,WAAW,EAAE,CA0B7E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,WAAW,EAAE,EAC1B,eAAe,EAAE,MAAM,GAAG,IAAI,GAC7B,WAAW,GAAG,IAAI,CAIpB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,QAAQ,EAAE,EACrB,mBAAmB,EAAE,WAAW,GAAG,IAAI,GACtC,QAAQ,EAAE,CAKZ;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,YAAY,EAAE,GAAG,SAAS,EAChC,aAAa,EAAE,MAAM,GAAG,KAAK,GAC5B,YAAY,EAAE,CAShB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,MAAM,GAAG,KAAK,EACnB,iBAAiB,EAAE,MAAM,EAAE,GAAG,SAAS,GACtC,MAAM,GAAG,KAAK,CAKhB"}
@@ -65,4 +65,25 @@ export function filterRunsByVersion(runs, versionFilter) {
65
65
  return sorted;
66
66
  return sorted.filter(run => (run.benchmarkVersion || 1) === versionFilter);
67
67
  }
68
+ /**
69
+ * Resolve the effective run-version filter from a persisted (possibly stale)
70
+ * value. A persisted version the benchmark doesn't actually have — e.g. a
71
+ * filter set while viewing a different benchmark under the old global
72
+ * localStorage key, a deleted version, or corrupted storage — must behave as
73
+ * 'all' rather than filtering every run out and rendering a bogus
74
+ * "No runs for vN" empty state that looks like data loss.
75
+ *
76
+ * @param raw - persisted filter value
77
+ * @param availableVersions - the benchmark's actual version numbers
78
+ * (undefined while the benchmark is still loading — value passes through)
79
+ */
80
+ export function effectiveRunVersionFilter(raw, availableVersions) {
81
+ if (raw === 'all')
82
+ return 'all';
83
+ if (!Number.isInteger(raw) || raw < 1)
84
+ return 'all';
85
+ if (availableVersions !== undefined && !availableVersions.includes(raw))
86
+ return 'all';
87
+ return raw;
88
+ }
68
89
  //# sourceMappingURL=benchmarkVersionUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"benchmarkVersionUtils.js","sourceRoot":"","sources":["../../benchmarkVersionUtils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"benchmarkVersionUtils.js","sourceRoot":"","sources":["../../benchmarkVersionUtils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Shared "fetch a big id list without blowing up the request" policy.
3
+ *
4
+ * A comparison over a large multi-run pool can need results for hundreds of
5
+ * ids (report ids, test-case ids, …) in one go. Two failure modes to avoid:
6
+ * - one unbounded `?ids=<all>` GET can blow past practical URL/header size
7
+ * limits (HTTP 431 — see asyncRunStorage.getReportsByIds's history);
8
+ * - firing one request per chunk with no cap can stampede the backend.
9
+ *
10
+ * `fetchChunked` splits `ids` into bounded chunks and fans them out with a
11
+ * capped worker pool — never one unbounded request, never an unbounded burst
12
+ * of parallel ones either. Used by asyncRunStorage (report ids) and
13
+ * asyncTestCaseStorage (test-case ids).
14
+ */
15
+ export declare const DEFAULT_CHUNK_SIZE = 100;
16
+ export declare const DEFAULT_MAX_CONCURRENT_CHUNKS = 8;
17
+ export declare function fetchChunked<T>(ids: string[], chunkSize: number, fetchChunk: (chunk: string[]) => Promise<T[]>, maxConcurrentChunks?: number): Promise<T[]>;
18
+ //# sourceMappingURL=chunkedFetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunkedFetch.d.ts","sourceRoot":"","sources":["../../chunkedFetch.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,MAAM,CAAC;AACtC,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,wBAAsB,YAAY,CAAC,CAAC,EAClC,GAAG,EAAE,MAAM,EAAE,EACb,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,CAAC,EAAE,CAAC,EAC7C,mBAAmB,GAAE,MAAsC,GAC1D,OAAO,CAAC,CAAC,EAAE,CAAC,CAiBd"}
@@ -0,0 +1,40 @@
1
+ /*
2
+ * Copyright OpenSearch Contributors
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ /**
6
+ * Shared "fetch a big id list without blowing up the request" policy.
7
+ *
8
+ * A comparison over a large multi-run pool can need results for hundreds of
9
+ * ids (report ids, test-case ids, …) in one go. Two failure modes to avoid:
10
+ * - one unbounded `?ids=<all>` GET can blow past practical URL/header size
11
+ * limits (HTTP 431 — see asyncRunStorage.getReportsByIds's history);
12
+ * - firing one request per chunk with no cap can stampede the backend.
13
+ *
14
+ * `fetchChunked` splits `ids` into bounded chunks and fans them out with a
15
+ * capped worker pool — never one unbounded request, never an unbounded burst
16
+ * of parallel ones either. Used by asyncRunStorage (report ids) and
17
+ * asyncTestCaseStorage (test-case ids).
18
+ */
19
+ export const DEFAULT_CHUNK_SIZE = 100;
20
+ export const DEFAULT_MAX_CONCURRENT_CHUNKS = 8;
21
+ export async function fetchChunked(ids, chunkSize, fetchChunk, maxConcurrentChunks = DEFAULT_MAX_CONCURRENT_CHUNKS) {
22
+ const chunks = [];
23
+ for (let i = 0; i < ids.length; i += chunkSize) {
24
+ chunks.push(ids.slice(i, i + chunkSize));
25
+ }
26
+ const results = new Array(chunks.length);
27
+ let nextChunk = 0;
28
+ async function worker() {
29
+ while (true) {
30
+ const i = nextChunk++;
31
+ if (i >= chunks.length)
32
+ return;
33
+ results[i] = await fetchChunk(chunks[i]);
34
+ }
35
+ }
36
+ const workerCount = Math.min(maxConcurrentChunks, chunks.length);
37
+ await Promise.all(Array.from({ length: workerCount }, () => worker()));
38
+ return results.flat();
39
+ }
40
+ //# sourceMappingURL=chunkedFetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunkedFetch.js","sourceRoot":"","sources":["../../chunkedFetch.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AACtC,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAa,EACb,SAAiB,EACjB,UAA6C,EAC7C,sBAA8B,6BAA6B;IAE3D,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAE,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAC3C,CAAC;IACD,MAAM,OAAO,GAAU,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAChD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,UAAU,MAAM;QACnB,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,CAAC,GAAG,SAAS,EAAE,CAAC;YACtB,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM;gBAAE,OAAO;YAC/B,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACjE,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;IACvE,OAAO,OAAO,CAAC,IAAI,EAAE,CAAC;AACxB,CAAC"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Comparison insights — deterministic agreement + category math for the
3
+ * comparison page's insights band (and, later, as grounding context for the
4
+ * "What's actually different" LLM deep-dive).
5
+ *
6
+ * Everything here is pure arithmetic over the already-loaded comparison rows:
7
+ * no API calls, no LLM. The band renders the *what* (which runs agree where,
8
+ * which categories are weak); the deep-dive explains the *why*.
9
+ *
10
+ * Generalized to N runs from the start:
11
+ * - 2 runs → "Both pass / Both fail / Split"
12
+ * - 3+ runs → "All pass / All fail / Split"
13
+ */
14
+ import type { TestCaseComparisonRow } from '../types/index.js';
15
+ /** Agreement bucket for a row across the selected runs. */
16
+ export type AgreementBucket = 'allPass' | 'allFail' | 'split';
17
+ export interface AgreementPartition {
18
+ allPass: TestCaseComparisonRow[];
19
+ allFail: TestCaseComparisonRow[];
20
+ split: TestCaseComparisonRow[];
21
+ /** Rows where at least one run has no verdict (missing report / not run). */
22
+ uncovered: TestCaseComparisonRow[];
23
+ }
24
+ /**
25
+ * Partition rows into agreement buckets across the given runs.
26
+ * A row only participates when EVERY selected run has a verdict for it —
27
+ * partially-covered rows go to `uncovered` (they can't agree or disagree).
28
+ */
29
+ export declare function partitionByAgreement(rows: TestCaseComparisonRow[], runIds: string[]): AgreementPartition;
30
+ /** Bucket a single row (same semantics as {@link partitionByAgreement}); null = uncovered. */
31
+ export declare function bucketRow(row: TestCaseComparisonRow, runIds: string[]): AgreementBucket | null;
32
+ /**
33
+ * Synthetic bucket names. Parentheses are deliberately outside the
34
+ * name-tag charset (`[\w-]`), so a real benchmark category can never
35
+ * collide with these rollup buckets.
36
+ */
37
+ export declare const UNCATEGORIZED = "(uncategorized)";
38
+ /** Rollup bucket for categories with too few cases to be meaningful. */
39
+ export declare const OTHER_CATEGORY = "(other)";
40
+ /**
41
+ * Extract a row's category.
42
+ * Priority:
43
+ * 1. The `subcategory:<x>` label — the proper, purpose-built tag for this
44
+ * (set via the SDK's `test(name, { labels: ['subcategory:basic'] })`,
45
+ * the JSON/CLI import's `subcategory` field, or the Test Case editor).
46
+ * Prefer this over anything scraped from free text: it's validated,
47
+ * exported/round-tripped, and shown elsewhere in the UI (EvalsPage,
48
+ * BenchmarkEditor) — a real column, not a regex guess.
49
+ * 2. A bracketed tag embedded in the test-case name — a convention older
50
+ * imported benchmarks used before `subcategory` existed (e.g.
51
+ * "qst_0011 [basic] How long is …"). Kept only for benchmarks that
52
+ * predate the `subcategory` field; new imports should set it instead.
53
+ * 3. A `topic:<x>` label (the generic labels system, pre-dates
54
+ * `subcategory` as a dedicated concept).
55
+ * 4. {@link UNCATEGORIZED}.
56
+ * (`category:<x>` labels are intentionally NOT used here: imported benchmarks
57
+ * commonly stamp a single `category:RAG` on every case, which would collapse
58
+ * the breakdown into one column — that's the coarse domain, not this facet.
59
+ * {@link categoryLabelIsUsableFallback} + {@link extractRowCategoryEffective}
60
+ * add `category:` back in, but ONLY for the comparisons where it's actually
61
+ * informative — see their docs.)
62
+ */
63
+ export declare function extractRowCategory(row: Pick<TestCaseComparisonRow, 'testCaseName' | 'labels'>): string;
64
+ /**
65
+ * Whether `category:` should be used as a LAST-RESORT fallback facet for
66
+ * this set of rows. True only when, among the rows {@link extractRowCategory}
67
+ * leaves as {@link UNCATEGORIZED} (rows with a real `[bracket]`/`topic:`
68
+ * facet keep using that, whether or not `category:` also varies — one
69
+ * differently-tagged row must not disable the fallback for every OTHER row
70
+ * that has nothing better):
71
+ * 1. There's at least one such row.
72
+ * 2. The `category:` label, normalized the same way {@link
73
+ * extractRowCategoryEffective} returns it (lowercased, so
74
+ * `category:RAG` and `category:rag` count as ONE value, not two —
75
+ * inconsistent casing must not look like variance), has ≥2 distinct
76
+ * values that EACH appear on ≥2 rows. The 2-per-value floor keeps a
77
+ * single stray/typo'd label from flipping this on for what is really a
78
+ * uniform category with one dirty row — that must still resolve to
79
+ * "nothing to facet by", not a real-facet-plus-a-noise-column matrix.
80
+ * A uniformly-stamped `category:RAG` (the case the original "intentionally
81
+ * NOT used" heuristic was written for) stays excluded — falling back to it
82
+ * would add a redundant single-value column to every such comparison,
83
+ * exactly the noise that heuristic was trying to avoid. WixQA-400's
84
+ * `category:expertwritten|simulated` (200/200) is the motivating case where
85
+ * it DOES vary (both values well above the floor) and is genuinely useful.
86
+ * Callers that resolve a per-row category for a set of rows should compute
87
+ * this ONCE for the whole set and pass it to every {@link
88
+ * extractRowCategoryEffective} call, so the matrix, its shared-weakness
89
+ * callout, and the table's click-to-filter all agree on the same facet.
90
+ */
91
+ export declare function categoryLabelIsUsableFallback(rows: Pick<TestCaseComparisonRow, 'testCaseName' | 'labels'>[]): boolean;
92
+ /**
93
+ * {@link extractRowCategory}, extended with the `category:` fallback when
94
+ * {@link categoryLabelIsUsableFallback} (computed once per row-set, passed
95
+ * in as `useCategoryFallback`) says it's actually informative for this
96
+ * comparison. Only reached when the base extraction is {@link
97
+ * UNCATEGORIZED} — a real bracket/topic facet always wins.
98
+ */
99
+ export declare function extractRowCategoryEffective(row: Pick<TestCaseComparisonRow, 'testCaseName' | 'labels'>, useCategoryFallback: boolean): string;
100
+ export interface CategoryCell {
101
+ passed: number;
102
+ total: number;
103
+ }
104
+ export interface CategoryBreakdown {
105
+ /** Display order: by case count desc; `other` (if present) always last. */
106
+ categories: string[];
107
+ /** runId → category → {passed,total}. Totals may differ per run (missing results are skipped). */
108
+ perRun: Record<string, Record<string, CategoryCell>>;
109
+ /** Overall case count per category (across rows, not per run). */
110
+ totals: Record<string, number>;
111
+ /**
112
+ * Raw categories each displayed column represents. Identity for real
113
+ * categories; the union of rolled-up raw categories for `(other)`.
114
+ * Filtering MUST use this mapping so clicking `(other)` matches exactly
115
+ * the rows its cell counted.
116
+ */
117
+ members: Record<string, string[]>;
118
+ /**
119
+ * Whether this breakdown fell back to the `category:` label (see {@link
120
+ * categoryLabelIsUsableFallback}). Callers that need to resolve a row's
121
+ * category OUTSIDE this function (e.g. {@link detectSharedWeakness}, or
122
+ * the compare page's click-to-filter) must pass this to {@link
123
+ * extractRowCategoryEffective} to stay consistent with what's displayed.
124
+ */
125
+ usesCategoryFallback: boolean;
126
+ }
127
+ /**
128
+ * Default minimum case count for a category to get its own column; smaller
129
+ * ones roll up into `other`. Callers with small datasets may lower this —
130
+ * a cell needs enough cases that a single verdict flip doesn't swing it
131
+ * by tens of percentage points.
132
+ */
133
+ export declare const MIN_CATEGORY_CASES = 5;
134
+ /** Per-category pass rates per run, with small categories rolled into `other`. */
135
+ export declare function buildCategoryBreakdown(rows: TestCaseComparisonRow[], runIds: string[], minCases?: number): CategoryBreakdown;
136
+ export interface SharedWeakness {
137
+ category: string;
138
+ /** runId → pass-rate percent (0-100) in this category. */
139
+ rates: Record<string, number>;
140
+ /** Fraction (0-1) of all-fail cases that belong to this category. */
141
+ allFailShare: number;
142
+ }
143
+ /**
144
+ * Detect a category that is the weakest (within {@link WEAKEST_TOLERANCE_PP})
145
+ * for EVERY selected run — the "shared floor". When present, it usually
146
+ * indicates a benchmark/corpus-level problem rather than an agent choice.
147
+ * Returns null when runs disagree about their weakest category or nothing is
148
+ * genuinely weak. `other`/`uncategorized` rollups are never flagged.
149
+ */
150
+ export declare function detectSharedWeakness(breakdown: CategoryBreakdown, partition: AgreementPartition, runIds: string[]): SharedWeakness | null;
151
+ //# sourceMappingURL=comparisonInsights.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comparisonInsights.d.ts","sourceRoot":"","sources":["../../comparisonInsights.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAGrD,2DAA2D;AAC3D,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;AAE9D,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,KAAK,EAAE,qBAAqB,EAAE,CAAC;IAC/B,6EAA6E;IAC7E,SAAS,EAAE,qBAAqB,EAAE,CAAC;CACpC;AAyBD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,qBAAqB,EAAE,EAC7B,MAAM,EAAE,MAAM,EAAE,GACf,kBAAkB,CAgBpB;AAED,8FAA8F;AAC9F,wBAAgB,SAAS,CAAC,GAAG,EAAE,qBAAqB,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,eAAe,GAAG,IAAI,CAO9F;AAED;;;;GAIG;AACH,eAAO,MAAM,aAAa,oBAAoB,CAAC;AAC/C,wEAAwE;AACxE,eAAO,MAAM,cAAc,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,IAAI,CAAC,qBAAqB,EAAE,cAAc,GAAG,QAAQ,CAAC,GAAG,MAAM,CAQtG;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,IAAI,CAAC,qBAAqB,EAAE,cAAc,GAAG,QAAQ,CAAC,EAAE,GAC7D,OAAO,CAUT;AAED;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CACzC,GAAG,EAAE,IAAI,CAAC,qBAAqB,EAAE,cAAc,GAAG,QAAQ,CAAC,EAC3D,mBAAmB,EAAE,OAAO,GAC3B,MAAM,CAKR;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,2EAA2E;IAC3E,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,kGAAkG;IAClG,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IACrD,kEAAkE;IAClE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClC;;;;;;OAMG;IACH,oBAAoB,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,IAAI,CAAC;AAEpC,kFAAkF;AAClF,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,qBAAqB,EAAE,EAC7B,MAAM,EAAE,MAAM,EAAE,EAChB,QAAQ,GAAE,MAA2B,GACpC,iBAAiB,CAwCnB;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,qEAAqE;IACrE,YAAY,EAAE,MAAM,CAAC;CACtB;AAYD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,iBAAiB,EAC5B,SAAS,EAAE,kBAAkB,EAC7B,MAAM,EAAE,MAAM,EAAE,GACf,cAAc,GAAG,IAAI,CAuCvB"}