@tangle-network/agent-eval 0.23.1 → 0.25.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.
- package/CHANGELOG.md +145 -0
- package/README.md +212 -79
- package/dist/baseline-4R5deP0N.d.ts +108 -0
- package/dist/benchmarks/index.d.ts +3 -2
- package/dist/benchmarks/index.js +1 -1
- package/dist/builder-eval/index.d.ts +249 -0
- package/dist/builder-eval/index.js +391 -0
- package/dist/builder-eval/index.js.map +1 -0
- package/dist/{chunk-IOXMGMHQ.js → chunk-2A5XJB43.js} +142 -318
- package/dist/chunk-2A5XJB43.js.map +1 -0
- package/dist/chunk-47X6LRCE.js +76 -0
- package/dist/chunk-47X6LRCE.js.map +1 -0
- package/dist/{chunk-6M774GY6.js → chunk-4F5DQN55.js} +1 -1
- package/dist/chunk-4F5DQN55.js.map +1 -0
- package/dist/{chunk-KAO3Q65R.js → chunk-4S4BM3QQ.js} +15 -13
- package/dist/chunk-4S4BM3QQ.js.map +1 -0
- package/dist/chunk-5BKGXME7.js +65 -0
- package/dist/chunk-5BKGXME7.js.map +1 -0
- package/dist/{chunk-6KQG5HAH.js → chunk-5LBB5B3Z.js} +376 -72
- package/dist/chunk-5LBB5B3Z.js.map +1 -0
- package/dist/{chunk-42I2QC2L.js → chunk-6QDKWHLS.js} +18 -14
- package/dist/chunk-6QDKWHLS.js.map +1 -0
- package/dist/{chunk-VQQSPGSM.js → chunk-EDUKQ5AM.js} +247 -189
- package/dist/chunk-EDUKQ5AM.js.map +1 -0
- package/dist/chunk-I4MBDTY5.js +272 -0
- package/dist/chunk-I4MBDTY5.js.map +1 -0
- package/dist/chunk-JLZQWFV3.js +618 -0
- package/dist/chunk-JLZQWFV3.js.map +1 -0
- package/dist/chunk-K2TPS5LB.js +569 -0
- package/dist/chunk-K2TPS5LB.js.map +1 -0
- package/dist/chunk-KKHDIONI.js +414 -0
- package/dist/chunk-KKHDIONI.js.map +1 -0
- package/dist/chunk-KMPRBJK4.js +74 -0
- package/dist/chunk-KMPRBJK4.js.map +1 -0
- package/dist/{chunk-QUKKGHTZ.js → chunk-KTGTIOFD.js} +6 -3
- package/dist/chunk-KTGTIOFD.js.map +1 -0
- package/dist/chunk-LSH4MMOZ.js +838 -0
- package/dist/chunk-LSH4MMOZ.js.map +1 -0
- package/dist/chunk-NG236HPC.js +57 -0
- package/dist/chunk-NG236HPC.js.map +1 -0
- package/dist/{chunk-QBW3YBTR.js → chunk-NLMNWKVM.js} +14 -6
- package/dist/chunk-NLMNWKVM.js.map +1 -0
- package/dist/chunk-NU65VQ7M.js +99 -0
- package/dist/chunk-NU65VQ7M.js.map +1 -0
- package/dist/chunk-OWLAAMME.js +250 -0
- package/dist/chunk-OWLAAMME.js.map +1 -0
- package/dist/{chunk-SQQLHODJ.js → chunk-PC4UYEBM.js} +7 -4
- package/dist/chunk-PC4UYEBM.js.map +1 -0
- package/dist/{chunk-7EAUOUQS.js → chunk-RAF443UI.js} +213 -115
- package/dist/chunk-RAF443UI.js.map +1 -0
- package/dist/chunk-RZTMDUO7.js +49 -0
- package/dist/chunk-RZTMDUO7.js.map +1 -0
- package/dist/{chunk-EXGR4XEM.js → chunk-SESZDQPX.js} +23 -19
- package/dist/chunk-SESZDQPX.js.map +1 -0
- package/dist/{chunk-5IIQKMD5.js → chunk-TVVP3ZZQ.js} +14 -4
- package/dist/chunk-TVVP3ZZQ.js.map +1 -0
- package/dist/chunk-WWYCWKUM.js +196 -0
- package/dist/chunk-WWYCWKUM.js.map +1 -0
- package/dist/{chunk-AXHNWLIX.js → chunk-YRZ4M5GS.js} +2 -90
- package/dist/chunk-YRZ4M5GS.js.map +1 -0
- package/dist/chunk-ZN274SWR.js +613 -0
- package/dist/chunk-ZN274SWR.js.map +1 -0
- package/dist/cli.js +10 -6
- package/dist/cli.js.map +1 -1
- package/dist/{control-DvkH87qJ.d.ts → control-CBShYYA6.d.ts} +32 -33
- package/dist/control-runtime-BuJHoLg0.d.ts +180 -0
- package/dist/control.d.ts +8 -6
- package/dist/control.js +10 -7
- package/dist/{dataset-B9qvlm_o.d.ts → dataset-CiK_3LDr.d.ts} +5 -2
- package/dist/{emitter-B2XqDKFU.d.ts → emitter-DP_cSSiw.d.ts} +1 -1
- package/dist/errors-BZ9sTdz7.d.ts +70 -0
- package/dist/failure-cluster-C2EGSDiT.d.ts +76 -0
- package/dist/feedback-trajectory-DfFdrraJ.d.ts +169 -0
- package/dist/governance/index.d.ts +5 -0
- package/dist/governance/index.js +18 -0
- package/dist/governance/index.js.map +1 -0
- package/dist/{index-DDTlbHEK.d.ts → index--fVrWDiR.d.ts} +1 -1
- package/dist/index-Oj9fAPPN.d.ts +270 -0
- package/dist/index.d.ts +2018 -3003
- package/dist/index.js +7443 -9102
- package/dist/index.js.map +1 -1
- package/dist/{integrity-Cr5YodSY.d.ts → integrity-DK2EBVZC.d.ts} +4 -3
- package/dist/knowledge/index.d.ts +102 -0
- package/dist/knowledge/index.js +18 -0
- package/dist/knowledge/index.js.map +1 -0
- package/dist/meta-eval/index.d.ts +99 -0
- package/dist/meta-eval/index.js +324 -0
- package/dist/meta-eval/index.js.map +1 -0
- package/dist/multi-layer-verifier-LkP3LVKj.d.ts +141 -0
- package/dist/openapi.json +491 -1
- package/dist/optimization.d.ts +11 -8
- package/dist/optimization.js +11 -9
- package/dist/outcome-store-D6KWmYvj.d.ts +63 -0
- package/dist/pipelines/index.d.ts +172 -0
- package/dist/pipelines/index.js +345 -0
- package/dist/pipelines/index.js.map +1 -0
- package/dist/prm/index.d.ts +99 -0
- package/dist/prm/index.js +222 -0
- package/dist/prm/index.js.map +1 -0
- package/dist/query-DODUYdPg.d.ts +30 -0
- package/dist/release-report-BNgMdqPF.d.ts +292 -0
- package/dist/replay-BL96gCEP.d.ts +226 -0
- package/dist/reporting.d.ts +10 -295
- package/dist/reporting.js +10 -6
- package/dist/{eval-campaign-Ds5QljIh.d.ts → researcher-BPT8x_NT.d.ts} +148 -146
- package/dist/rl.d.ts +1762 -8
- package/dist/rl.js +2035 -58
- package/dist/rl.js.map +1 -1
- package/dist/rubric-D5tjHNJQ.d.ts +72 -0
- package/dist/rubric-predictive-validity-C0uDYwG6.d.ts +105 -0
- package/dist/{run-record-DNiOMBrZ.d.ts → run-record-CqzahIbx.d.ts} +4 -1
- package/dist/sequential-Dgz1n51-.d.ts +139 -0
- package/dist/{store-u47QaJ9G.d.ts → store-Db2Bv8Cf.d.ts} +1 -1
- package/dist/{summary-report-Ce1r4EYo.d.ts → summary-report-C7VPYEj2.d.ts} +3 -76
- package/dist/telemetry/file.js +4 -1
- package/dist/telemetry/file.js.map +1 -1
- package/dist/telemetry/index.js +57 -57
- package/dist/telemetry/index.js.map +1 -1
- package/dist/test-graded-scenario-B2kWEdh9.d.ts +146 -0
- package/dist/traces.d.ts +142 -387
- package/dist/traces.js +1302 -40
- package/dist/traces.js.map +1 -1
- package/dist/trajectory-CnoBo-JY.d.ts +32 -0
- package/dist/wire/index.d.ts +369 -25
- package/dist/wire/index.js +22 -3
- package/package.json +44 -18
- package/dist/chunk-42I2QC2L.js.map +0 -1
- package/dist/chunk-5IIQKMD5.js.map +0 -1
- package/dist/chunk-6KQG5HAH.js.map +0 -1
- package/dist/chunk-6M774GY6.js.map +0 -1
- package/dist/chunk-7EAUOUQS.js.map +0 -1
- package/dist/chunk-AXHNWLIX.js.map +0 -1
- package/dist/chunk-EXGR4XEM.js.map +0 -1
- package/dist/chunk-IOXMGMHQ.js.map +0 -1
- package/dist/chunk-KAO3Q65R.js.map +0 -1
- package/dist/chunk-LZKIOBG2.js +0 -2026
- package/dist/chunk-LZKIOBG2.js.map +0 -1
- package/dist/chunk-QBW3YBTR.js.map +0 -1
- package/dist/chunk-QUKKGHTZ.js.map +0 -1
- package/dist/chunk-SQQLHODJ.js.map +0 -1
- package/dist/chunk-V5QSWN7L.js +0 -1310
- package/dist/chunk-V5QSWN7L.js.map +0 -1
- package/dist/chunk-VQQSPGSM.js.map +0 -1
- package/dist/chunk-XPHOZPOM.js +0 -1947
- package/dist/chunk-XPHOZPOM.js.map +0 -1
- package/dist/feedback-trajectory-c43WGtTX.d.ts +0 -346
- package/dist/index-ekBXweiQ.d.ts +0 -1894
- package/dist/sequential-DgU2mFsE.d.ts +0 -304
package/dist/optimization.js
CHANGED
|
@@ -25,17 +25,19 @@ import {
|
|
|
25
25
|
summarizePreferenceMemory,
|
|
26
26
|
trialTraceFromMultiShotTrial,
|
|
27
27
|
withAssignedFeedbackSplit
|
|
28
|
-
} from "./chunk-
|
|
29
|
-
import "./chunk-
|
|
28
|
+
} from "./chunk-EDUKQ5AM.js";
|
|
29
|
+
import "./chunk-NLMNWKVM.js";
|
|
30
30
|
import {
|
|
31
31
|
runEvalCampaign
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
34
|
-
import "./chunk-
|
|
35
|
-
import "./chunk-
|
|
36
|
-
import "./chunk-
|
|
37
|
-
import "./chunk-
|
|
38
|
-
import "./chunk-
|
|
32
|
+
} from "./chunk-SESZDQPX.js";
|
|
33
|
+
import "./chunk-4S4BM3QQ.js";
|
|
34
|
+
import "./chunk-2A5XJB43.js";
|
|
35
|
+
import "./chunk-I4MBDTY5.js";
|
|
36
|
+
import "./chunk-KTGTIOFD.js";
|
|
37
|
+
import "./chunk-PC4UYEBM.js";
|
|
38
|
+
import "./chunk-TVVP3ZZQ.js";
|
|
39
|
+
import "./chunk-4F5DQN55.js";
|
|
40
|
+
import "./chunk-NG236HPC.js";
|
|
39
41
|
import "./chunk-PZ5AY32C.js";
|
|
40
42
|
export {
|
|
41
43
|
CallbackResearcher,
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OutcomeStore — deployment outcomes attached to Run IDs.
|
|
3
|
+
*
|
|
4
|
+
* Outcomes arrive asynchronously from production telemetry after the
|
|
5
|
+
* eval run completed: user ratings, retention flags, conversion events,
|
|
6
|
+
* revenue, support-ticket rate, anything a product team can measure.
|
|
7
|
+
* The store is a peer to TraceStore — separate lifecycle, same runId
|
|
8
|
+
* foreign key.
|
|
9
|
+
*
|
|
10
|
+
* The whole point of this module is to make the meta-eval correlation
|
|
11
|
+
* question computable: `correlate(evalMetric, outcomeMetric) → r, ρ, n, CI`.
|
|
12
|
+
*/
|
|
13
|
+
interface DeploymentOutcome {
|
|
14
|
+
runId: string;
|
|
15
|
+
capturedAt: number;
|
|
16
|
+
/** Numeric outcomes keyed by name — retention_7d, csat, revenue_usd, etc. */
|
|
17
|
+
metrics: Record<string, number>;
|
|
18
|
+
/** Dimensions for stratified analysis — cohort, region, user_segment. */
|
|
19
|
+
labels?: Record<string, string>;
|
|
20
|
+
/** Free-form provenance (source system, pipeline version). */
|
|
21
|
+
source?: string;
|
|
22
|
+
}
|
|
23
|
+
interface OutcomeFilter {
|
|
24
|
+
runIds?: string[];
|
|
25
|
+
since?: number;
|
|
26
|
+
until?: number;
|
|
27
|
+
label?: {
|
|
28
|
+
key: string;
|
|
29
|
+
value: string;
|
|
30
|
+
};
|
|
31
|
+
source?: string;
|
|
32
|
+
}
|
|
33
|
+
interface OutcomeStore {
|
|
34
|
+
append(outcome: DeploymentOutcome): Promise<void>;
|
|
35
|
+
/** All outcomes attached to this run (a single run can have many — multiple
|
|
36
|
+
* capture windows over deployment time). */
|
|
37
|
+
forRun(runId: string): Promise<DeploymentOutcome[]>;
|
|
38
|
+
list(filter?: OutcomeFilter): Promise<DeploymentOutcome[]>;
|
|
39
|
+
}
|
|
40
|
+
declare class InMemoryOutcomeStore implements OutcomeStore {
|
|
41
|
+
private items;
|
|
42
|
+
append(outcome: DeploymentOutcome): Promise<void>;
|
|
43
|
+
forRun(runId: string): Promise<DeploymentOutcome[]>;
|
|
44
|
+
list(filter?: OutcomeFilter): Promise<DeploymentOutcome[]>;
|
|
45
|
+
}
|
|
46
|
+
interface FileSystemOutcomeStoreOptions {
|
|
47
|
+
dir: string;
|
|
48
|
+
maxBytes?: number;
|
|
49
|
+
}
|
|
50
|
+
declare class FileSystemOutcomeStore implements OutcomeStore {
|
|
51
|
+
private dir;
|
|
52
|
+
private maxBytes;
|
|
53
|
+
private memo?;
|
|
54
|
+
private loaded;
|
|
55
|
+
constructor(options: FileSystemOutcomeStoreOptions);
|
|
56
|
+
private ensureDir;
|
|
57
|
+
append(outcome: DeploymentOutcome): Promise<void>;
|
|
58
|
+
private load;
|
|
59
|
+
forRun(runId: string): Promise<DeploymentOutcome[]>;
|
|
60
|
+
list(filter?: OutcomeFilter): Promise<DeploymentOutcome[]>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { type DeploymentOutcome as D, FileSystemOutcomeStore as F, InMemoryOutcomeStore as I, type OutcomeStore as O, type OutcomeFilter as a, type FileSystemOutcomeStoreOptions as b };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { g as BudgetSpec, T as TraceStore, h as RunFilter, R as Run, a as ToolSpan } from '../store-Db2Bv8Cf.js';
|
|
2
|
+
export { a as FailureCluster, F as FailureClusterReport, f as failureClusterView } from '../failure-cluster-C2EGSDiT.js';
|
|
3
|
+
import { a as TrajectoryStep } from '../trajectory-CnoBo-JY.js';
|
|
4
|
+
import { B as BaselineOptions, a as BaselineReport } from '../baseline-4R5deP0N.js';
|
|
5
|
+
export { c as computeToolUseMetrics } from '../baseline-4R5deP0N.js';
|
|
6
|
+
import { l as llmSpans } from '../query-DODUYdPg.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* BudgetBreachView — aggregates breach events across the corpus.
|
|
10
|
+
*
|
|
11
|
+
* Answers: which dimensions get hit most often? Which scenarios are
|
|
12
|
+
* underbudgeted? Which variants trigger the most breaches?
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface BudgetBreachFinding {
|
|
16
|
+
runId: string;
|
|
17
|
+
scenarioId: string;
|
|
18
|
+
variantId?: string;
|
|
19
|
+
dimension: keyof BudgetSpec;
|
|
20
|
+
limit: number;
|
|
21
|
+
consumed: number;
|
|
22
|
+
excessRatio: number;
|
|
23
|
+
timestamp: number;
|
|
24
|
+
}
|
|
25
|
+
interface BudgetBreachReport {
|
|
26
|
+
findings: BudgetBreachFinding[];
|
|
27
|
+
byDimension: Record<string, number>;
|
|
28
|
+
byScenario: Record<string, number>;
|
|
29
|
+
byVariant: Record<string, number>;
|
|
30
|
+
totalRuns: number;
|
|
31
|
+
breachedRunRatio: number;
|
|
32
|
+
}
|
|
33
|
+
declare function budgetBreachView(store: TraceStore, options?: {
|
|
34
|
+
scenarioId?: string;
|
|
35
|
+
variantId?: string;
|
|
36
|
+
}): Promise<BudgetBreachReport>;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* FirstDivergenceView — aligns two trajectories by step index, reports
|
|
40
|
+
* the first step where they differ.
|
|
41
|
+
*
|
|
42
|
+
* "Differ" is configurable — default is (kind, toolName if tool, model
|
|
43
|
+
* if llm). Use this view to attribute "why is variant B better?" to a
|
|
44
|
+
* specific step rather than an aggregate mean delta.
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
interface DivergenceReport {
|
|
48
|
+
runA: string;
|
|
49
|
+
runB: string;
|
|
50
|
+
firstDivergenceIndex: number | null;
|
|
51
|
+
aStep?: TrajectoryStep;
|
|
52
|
+
bStep?: TrajectoryStep;
|
|
53
|
+
reason?: string;
|
|
54
|
+
/** Common prefix length (steps that matched). */
|
|
55
|
+
commonPrefixLen: number;
|
|
56
|
+
}
|
|
57
|
+
interface DivergenceOptions {
|
|
58
|
+
/** Returns true if two steps are considered equal. Default: kind + tool/model match. */
|
|
59
|
+
stepEquals?: (a: TrajectoryStep, b: TrajectoryStep) => boolean;
|
|
60
|
+
}
|
|
61
|
+
declare function firstDivergenceView(store: TraceStore, runA: string, runB: string, options?: DivergenceOptions): Promise<DivergenceReport>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* JudgeAgreementView — pairwise agreement between judges across the
|
|
65
|
+
* corpus, grouped by dimension.
|
|
66
|
+
*
|
|
67
|
+
* Output drives two workflows:
|
|
68
|
+
* - Judge robustness audit: "does Claude agree with GPT at κ ≥ 0.6?"
|
|
69
|
+
* - Calibration tracking: κ vs golden human labels over time (by
|
|
70
|
+
* providing a `humanGoldenJudgeId`).
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
interface JudgePair {
|
|
74
|
+
judgeA: string;
|
|
75
|
+
judgeB: string;
|
|
76
|
+
dimension: string;
|
|
77
|
+
/** Number of (targetSpanId, dimension) tuples both judges scored. */
|
|
78
|
+
commonItems: number;
|
|
79
|
+
pearson: number;
|
|
80
|
+
krippendorff: number;
|
|
81
|
+
}
|
|
82
|
+
interface JudgeAgreementReport {
|
|
83
|
+
pairs: JudgePair[];
|
|
84
|
+
dimensions: string[];
|
|
85
|
+
judgeIds: string[];
|
|
86
|
+
}
|
|
87
|
+
declare function judgeAgreementView(store: TraceStore): Promise<JudgeAgreementReport>;
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* RegressionView — compares a candidate slice to a baseline slice on a
|
|
91
|
+
* named metric. Delegates the statistics (Welch's t-test, Cohen's d,
|
|
92
|
+
* IQR stability) to `baseline.ts`.
|
|
93
|
+
*
|
|
94
|
+
* This is the entry point for CI regression gates: "given runs tagged
|
|
95
|
+
* release=A and release=B, did any metric regress?"
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
interface RegressionSpec {
|
|
99
|
+
metric: string;
|
|
100
|
+
higherIsBetter: boolean;
|
|
101
|
+
/** Extract a scalar from a run. Default extractors handle common metrics. */
|
|
102
|
+
extract?: (run: Run, store: TraceStore) => Promise<number | null>;
|
|
103
|
+
}
|
|
104
|
+
interface RegressionOptions extends BaselineOptions {
|
|
105
|
+
baseline: RunFilter;
|
|
106
|
+
candidate: RunFilter;
|
|
107
|
+
}
|
|
108
|
+
declare function regressionView(store: TraceStore, metrics: RegressionSpec[], options: RegressionOptions): Promise<BaselineReport>;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* StuckLoopView — detects when an agent calls the same tool with the
|
|
112
|
+
* same (or structurally similar) arguments ≥ N times in a short window.
|
|
113
|
+
*
|
|
114
|
+
* Rationale: agents that loop are the number-one production failure
|
|
115
|
+
* mode on long-horizon flows. The view returns (runId, toolName,
|
|
116
|
+
* argHash, occurrences, windowMs) for each detected loop plus a
|
|
117
|
+
* fraction of runs affected.
|
|
118
|
+
*/
|
|
119
|
+
|
|
120
|
+
interface StuckLoopFinding {
|
|
121
|
+
runId: string;
|
|
122
|
+
toolName: string;
|
|
123
|
+
argHash: string;
|
|
124
|
+
occurrences: number;
|
|
125
|
+
spanIds: string[];
|
|
126
|
+
/** Milliseconds between first and last call in the loop. */
|
|
127
|
+
windowMs: number;
|
|
128
|
+
}
|
|
129
|
+
interface StuckLoopReport {
|
|
130
|
+
findings: StuckLoopFinding[];
|
|
131
|
+
affectedRunRatio: number;
|
|
132
|
+
totalRuns: number;
|
|
133
|
+
}
|
|
134
|
+
interface StuckLoopOptions {
|
|
135
|
+
/** Minimum call count to flag a loop (default 3). */
|
|
136
|
+
minOccurrences?: number;
|
|
137
|
+
/** Filter to a specific runId; omit to scan the entire corpus. */
|
|
138
|
+
runId?: string;
|
|
139
|
+
}
|
|
140
|
+
declare function stuckLoopView(store: TraceStore, options?: StuckLoopOptions): Promise<StuckLoopReport>;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* ToolWasteView — fraction of tool calls whose results weren't used
|
|
144
|
+
* downstream. Without a "used" signal we fall back to structural
|
|
145
|
+
* proxies: error calls, duplicate calls, and tool calls followed by
|
|
146
|
+
* zero subsequent LLM spans are all considered waste.
|
|
147
|
+
*
|
|
148
|
+
* Consumers can pass a `usageOracle` that inspects a tool span and
|
|
149
|
+
* returns true iff the tool's result appears in a later LLM message,
|
|
150
|
+
* artifact, or state mutation — that's the canonical definition; the
|
|
151
|
+
* default heuristic is a reasonable fallback.
|
|
152
|
+
*/
|
|
153
|
+
|
|
154
|
+
interface ToolWasteFinding {
|
|
155
|
+
runId: string;
|
|
156
|
+
wastedCalls: number;
|
|
157
|
+
totalCalls: number;
|
|
158
|
+
wasteRate: number;
|
|
159
|
+
}
|
|
160
|
+
interface ToolWasteReport {
|
|
161
|
+
byRun: ToolWasteFinding[];
|
|
162
|
+
overallWasteRate: number;
|
|
163
|
+
}
|
|
164
|
+
interface ToolWasteOptions {
|
|
165
|
+
runId?: string;
|
|
166
|
+
usageOracle?: (tool: ToolSpan, later: {
|
|
167
|
+
llm: Awaited<ReturnType<typeof llmSpans>>;
|
|
168
|
+
}) => boolean;
|
|
169
|
+
}
|
|
170
|
+
declare function toolWasteView(store: TraceStore, options?: ToolWasteOptions): Promise<ToolWasteReport>;
|
|
171
|
+
|
|
172
|
+
export { type BudgetBreachFinding, type BudgetBreachReport, type DivergenceOptions, type DivergenceReport, type JudgeAgreementReport, type JudgePair, type RegressionOptions, type RegressionSpec, type StuckLoopFinding, type StuckLoopOptions, type StuckLoopReport, type ToolWasteFinding, type ToolWasteOptions, type ToolWasteReport, budgetBreachView, firstDivergenceView, judgeAgreementView, regressionView, stuckLoopView, toolWasteView };
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import {
|
|
2
|
+
compareToBaseline,
|
|
3
|
+
computeToolUseMetrics,
|
|
4
|
+
failureClusterView
|
|
5
|
+
} from "../chunk-JLZQWFV3.js";
|
|
6
|
+
import {
|
|
7
|
+
buildTrajectory
|
|
8
|
+
} from "../chunk-RZTMDUO7.js";
|
|
9
|
+
import {
|
|
10
|
+
interRaterReliability
|
|
11
|
+
} from "../chunk-I4MBDTY5.js";
|
|
12
|
+
import {
|
|
13
|
+
aggregateLlm,
|
|
14
|
+
argHash,
|
|
15
|
+
llmSpans,
|
|
16
|
+
runFailureClass,
|
|
17
|
+
toolSpans
|
|
18
|
+
} from "../chunk-47X6LRCE.js";
|
|
19
|
+
import "../chunk-5BKGXME7.js";
|
|
20
|
+
import "../chunk-NG236HPC.js";
|
|
21
|
+
import "../chunk-PZ5AY32C.js";
|
|
22
|
+
|
|
23
|
+
// src/pipelines/budget-breach.ts
|
|
24
|
+
async function budgetBreachView(store, options = {}) {
|
|
25
|
+
const runs = await store.listRuns({
|
|
26
|
+
scenarioId: options.scenarioId,
|
|
27
|
+
variantId: options.variantId
|
|
28
|
+
});
|
|
29
|
+
const findings = [];
|
|
30
|
+
const byDimension = {};
|
|
31
|
+
const byScenario = {};
|
|
32
|
+
const byVariant = {};
|
|
33
|
+
for (const run of runs) {
|
|
34
|
+
const entries = await store.budget(run.runId);
|
|
35
|
+
for (const e of entries) {
|
|
36
|
+
if (!e.breached) continue;
|
|
37
|
+
const excessRatio = e.limit > 0 ? e.consumed / e.limit : Infinity;
|
|
38
|
+
findings.push({
|
|
39
|
+
runId: run.runId,
|
|
40
|
+
scenarioId: run.scenarioId,
|
|
41
|
+
variantId: run.variantId,
|
|
42
|
+
dimension: e.dimension,
|
|
43
|
+
limit: e.limit,
|
|
44
|
+
consumed: e.consumed,
|
|
45
|
+
excessRatio,
|
|
46
|
+
timestamp: e.timestamp
|
|
47
|
+
});
|
|
48
|
+
byDimension[e.dimension] = (byDimension[e.dimension] ?? 0) + 1;
|
|
49
|
+
byScenario[run.scenarioId] = (byScenario[run.scenarioId] ?? 0) + 1;
|
|
50
|
+
if (run.variantId) byVariant[run.variantId] = (byVariant[run.variantId] ?? 0) + 1;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
const breachedRuns = new Set(findings.map((f) => f.runId));
|
|
54
|
+
return {
|
|
55
|
+
findings,
|
|
56
|
+
byDimension,
|
|
57
|
+
byScenario,
|
|
58
|
+
byVariant,
|
|
59
|
+
totalRuns: runs.length,
|
|
60
|
+
breachedRunRatio: runs.length > 0 ? breachedRuns.size / runs.length : 0
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/pipelines/first-divergence.ts
|
|
65
|
+
async function firstDivergenceView(store, runA, runB, options = {}) {
|
|
66
|
+
const [a, b] = await Promise.all([buildTrajectory(store, runA), buildTrajectory(store, runB)]);
|
|
67
|
+
const eq = options.stepEquals ?? defaultStepEquals;
|
|
68
|
+
const minLen = Math.min(a.steps.length, b.steps.length);
|
|
69
|
+
for (let i = 0; i < minLen; i++) {
|
|
70
|
+
const aStep = a.steps[i];
|
|
71
|
+
const bStep = b.steps[i];
|
|
72
|
+
if (!eq(aStep, bStep)) {
|
|
73
|
+
return {
|
|
74
|
+
runA,
|
|
75
|
+
runB,
|
|
76
|
+
firstDivergenceIndex: i,
|
|
77
|
+
aStep,
|
|
78
|
+
bStep,
|
|
79
|
+
reason: describeDifference(aStep, bStep),
|
|
80
|
+
commonPrefixLen: i
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
if (a.steps.length === b.steps.length) {
|
|
85
|
+
return { runA, runB, firstDivergenceIndex: null, commonPrefixLen: minLen };
|
|
86
|
+
}
|
|
87
|
+
const longer = a.steps.length > b.steps.length ? a : b;
|
|
88
|
+
return {
|
|
89
|
+
runA,
|
|
90
|
+
runB,
|
|
91
|
+
firstDivergenceIndex: minLen,
|
|
92
|
+
aStep: a.steps[minLen],
|
|
93
|
+
bStep: b.steps[minLen],
|
|
94
|
+
reason: `one trajectory has ${longer.steps.length - minLen} more step(s) after index ${minLen - 1}`,
|
|
95
|
+
commonPrefixLen: minLen
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function defaultStepEquals(a, b) {
|
|
99
|
+
if (a.span.kind !== b.span.kind) return false;
|
|
100
|
+
if (a.span.kind === "tool" && b.span.kind === "tool") return a.span.toolName === b.span.toolName;
|
|
101
|
+
if (a.span.kind === "llm" && b.span.kind === "llm") return a.span.model === b.span.model;
|
|
102
|
+
if (a.span.kind === "judge" && b.span.kind === "judge")
|
|
103
|
+
return a.span.dimension === b.span.dimension;
|
|
104
|
+
return a.span.name === b.span.name;
|
|
105
|
+
}
|
|
106
|
+
function describeDifference(a, b) {
|
|
107
|
+
if (a.span.kind !== b.span.kind) return `kind ${a.span.kind} vs ${b.span.kind}`;
|
|
108
|
+
if (a.span.kind === "tool" && b.span.kind === "tool" && a.span.toolName !== b.span.toolName) {
|
|
109
|
+
return `tool ${a.span.toolName} vs ${b.span.toolName}`;
|
|
110
|
+
}
|
|
111
|
+
if (a.span.kind === "llm" && b.span.kind === "llm" && a.span.model !== b.span.model) {
|
|
112
|
+
return `model ${a.span.model} vs ${b.span.model}`;
|
|
113
|
+
}
|
|
114
|
+
return `name "${a.span.name}" vs "${b.span.name}"`;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// src/pipelines/judge-agreement.ts
|
|
118
|
+
async function judgeAgreementView(store) {
|
|
119
|
+
const all = (await store.spans({ kind: "judge" })).filter(
|
|
120
|
+
(s) => s.kind === "judge"
|
|
121
|
+
);
|
|
122
|
+
if (all.length === 0) return { pairs: [], dimensions: [], judgeIds: [] };
|
|
123
|
+
const byDimension = /* @__PURE__ */ new Map();
|
|
124
|
+
for (const s of all) {
|
|
125
|
+
const arr = byDimension.get(s.dimension) ?? [];
|
|
126
|
+
arr.push(s);
|
|
127
|
+
byDimension.set(s.dimension, arr);
|
|
128
|
+
}
|
|
129
|
+
const judgeIds = [...new Set(all.map((s) => s.judgeId))].sort();
|
|
130
|
+
const pairs = [];
|
|
131
|
+
for (const [dim, spans] of byDimension) {
|
|
132
|
+
const byJudge = /* @__PURE__ */ new Map();
|
|
133
|
+
for (const s of spans) {
|
|
134
|
+
const m = byJudge.get(s.judgeId) ?? /* @__PURE__ */ new Map();
|
|
135
|
+
m.set(s.targetSpanId, s.score);
|
|
136
|
+
byJudge.set(s.judgeId, m);
|
|
137
|
+
}
|
|
138
|
+
const judgesHere = [...byJudge.keys()];
|
|
139
|
+
for (let i = 0; i < judgesHere.length; i++) {
|
|
140
|
+
for (let j = i + 1; j < judgesHere.length; j++) {
|
|
141
|
+
const judgeI = judgesHere[i];
|
|
142
|
+
const judgeJ = judgesHere[j];
|
|
143
|
+
const a = byJudge.get(judgeI);
|
|
144
|
+
const b = byJudge.get(judgeJ);
|
|
145
|
+
const common = [];
|
|
146
|
+
for (const [target, scoreA] of a) {
|
|
147
|
+
const scoreB = b.get(target);
|
|
148
|
+
if (scoreB !== void 0) common.push([scoreA, scoreB]);
|
|
149
|
+
}
|
|
150
|
+
if (common.length < 2) continue;
|
|
151
|
+
const judgeScores = common.map(
|
|
152
|
+
([scoreA, scoreB]) => [
|
|
153
|
+
{ judgeName: judgeI, dimension: dim, score: scoreA, reasoning: "" },
|
|
154
|
+
{ judgeName: judgeJ, dimension: dim, score: scoreB, reasoning: "" }
|
|
155
|
+
]
|
|
156
|
+
);
|
|
157
|
+
const k = interRaterReliability(
|
|
158
|
+
judgeScores[0].map((_, k2) => judgeScores.map((pair) => pair[k2]))
|
|
159
|
+
);
|
|
160
|
+
pairs.push({
|
|
161
|
+
judgeA: judgeI,
|
|
162
|
+
judgeB: judgeJ,
|
|
163
|
+
dimension: dim,
|
|
164
|
+
commonItems: common.length,
|
|
165
|
+
pearson: pearson(
|
|
166
|
+
common.map((c) => c[0]),
|
|
167
|
+
common.map((c) => c[1])
|
|
168
|
+
),
|
|
169
|
+
krippendorff: k
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
pairs: pairs.sort((a, b) => b.commonItems - a.commonItems),
|
|
176
|
+
dimensions: [...byDimension.keys()].sort(),
|
|
177
|
+
judgeIds
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
function pearson(a, b) {
|
|
181
|
+
if (a.length !== b.length || a.length < 2) return NaN;
|
|
182
|
+
const mA = a.reduce((s, v) => s + v, 0) / a.length;
|
|
183
|
+
const mB = b.reduce((s, v) => s + v, 0) / b.length;
|
|
184
|
+
let num = 0, denA = 0, denB = 0;
|
|
185
|
+
for (let i = 0; i < a.length; i++) {
|
|
186
|
+
const dA = a[i] - mA;
|
|
187
|
+
const dB = b[i] - mB;
|
|
188
|
+
num += dA * dB;
|
|
189
|
+
denA += dA * dA;
|
|
190
|
+
denB += dB * dB;
|
|
191
|
+
}
|
|
192
|
+
if (denA === 0 || denB === 0) return denA === 0 && denB === 0 ? 1 : 0;
|
|
193
|
+
return num / Math.sqrt(denA * denB);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// src/pipelines/regression.ts
|
|
197
|
+
async function regressionView(store, metrics, options) {
|
|
198
|
+
const baselineRuns = await store.listRuns(options.baseline);
|
|
199
|
+
const candidateRuns = await store.listRuns(options.candidate);
|
|
200
|
+
const samples = await Promise.all(
|
|
201
|
+
metrics.map(async (m) => {
|
|
202
|
+
const extract = m.extract ?? defaultExtract(m.metric);
|
|
203
|
+
const baseline = await extractAll(baselineRuns, extract, store);
|
|
204
|
+
const candidate = await extractAll(candidateRuns, extract, store);
|
|
205
|
+
return { metric: m.metric, higherIsBetter: m.higherIsBetter, baseline, candidate };
|
|
206
|
+
})
|
|
207
|
+
);
|
|
208
|
+
return compareToBaseline(samples, options);
|
|
209
|
+
}
|
|
210
|
+
async function extractAll(runs, extract, store) {
|
|
211
|
+
const out = [];
|
|
212
|
+
for (const r of runs) {
|
|
213
|
+
const v = await extract(r, store);
|
|
214
|
+
if (v !== null && Number.isFinite(v)) out.push(v);
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
function defaultExtract(metric) {
|
|
219
|
+
return async (run, store) => {
|
|
220
|
+
switch (metric) {
|
|
221
|
+
case "score":
|
|
222
|
+
case "overallScore":
|
|
223
|
+
return run.outcome?.score ?? null;
|
|
224
|
+
case "pass":
|
|
225
|
+
return run.outcome?.pass === true ? 1 : 0;
|
|
226
|
+
case "durationMs":
|
|
227
|
+
return run.endedAt && run.startedAt ? run.endedAt - run.startedAt : null;
|
|
228
|
+
case "costUsd": {
|
|
229
|
+
const llm = await llmSpans(store, run.runId);
|
|
230
|
+
return aggregateLlm(llm).costUsd;
|
|
231
|
+
}
|
|
232
|
+
case "inputTokens": {
|
|
233
|
+
const llm = await llmSpans(store, run.runId);
|
|
234
|
+
return aggregateLlm(llm).inputTokens;
|
|
235
|
+
}
|
|
236
|
+
case "outputTokens": {
|
|
237
|
+
const llm = await llmSpans(store, run.runId);
|
|
238
|
+
return aggregateLlm(llm).outputTokens;
|
|
239
|
+
}
|
|
240
|
+
case "failureClass": {
|
|
241
|
+
return runFailureClass(run) === "success" ? 1 : 0;
|
|
242
|
+
}
|
|
243
|
+
default:
|
|
244
|
+
return null;
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// src/pipelines/stuck-loop.ts
|
|
250
|
+
async function stuckLoopView(store, options = {}) {
|
|
251
|
+
const minOccurrences = options.minOccurrences ?? 3;
|
|
252
|
+
const runs = options.runId ? [{ runId: options.runId }] : (await store.listRuns()).map((r) => ({ runId: r.runId }));
|
|
253
|
+
const findings = [];
|
|
254
|
+
for (const { runId } of runs) {
|
|
255
|
+
const tools = await toolSpans(store, runId);
|
|
256
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
257
|
+
for (const t of tools) {
|
|
258
|
+
const h = argHash(t.args);
|
|
259
|
+
const key = `${t.toolName}|${h}`;
|
|
260
|
+
const bucket = byKey.get(key) ?? { spans: [], argHash: h };
|
|
261
|
+
bucket.spans.push(t);
|
|
262
|
+
byKey.set(key, bucket);
|
|
263
|
+
}
|
|
264
|
+
for (const [key, { spans, argHash: h }] of byKey) {
|
|
265
|
+
if (spans.length < minOccurrences) continue;
|
|
266
|
+
const sorted = [...spans].sort((a, b) => a.startedAt - b.startedAt);
|
|
267
|
+
const first = sorted[0].startedAt;
|
|
268
|
+
const last = sorted[sorted.length - 1].startedAt;
|
|
269
|
+
findings.push({
|
|
270
|
+
runId,
|
|
271
|
+
toolName: key.split("|")[0],
|
|
272
|
+
argHash: h,
|
|
273
|
+
occurrences: sorted.length,
|
|
274
|
+
spanIds: sorted.map((s) => s.spanId),
|
|
275
|
+
windowMs: last - first
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const affectedRuns = new Set(findings.map((f) => f.runId));
|
|
280
|
+
return {
|
|
281
|
+
findings,
|
|
282
|
+
affectedRunRatio: runs.length > 0 ? affectedRuns.size / runs.length : 0,
|
|
283
|
+
totalRuns: runs.length
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// src/pipelines/tool-waste.ts
|
|
288
|
+
async function toolWasteView(store, options = {}) {
|
|
289
|
+
const runs = options.runId ? [options.runId] : (await store.listRuns()).map((r) => r.runId);
|
|
290
|
+
const byRun = [];
|
|
291
|
+
let totalCalls = 0;
|
|
292
|
+
let totalWasted = 0;
|
|
293
|
+
for (const runId of runs) {
|
|
294
|
+
const tools = await toolSpans(store, runId);
|
|
295
|
+
if (tools.length === 0) {
|
|
296
|
+
byRun.push({ runId, wastedCalls: 0, totalCalls: 0, wasteRate: 0 });
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
const llms = await llmSpans(store, runId);
|
|
300
|
+
let wasted = 0;
|
|
301
|
+
for (const t of tools) {
|
|
302
|
+
if (t.status === "error") {
|
|
303
|
+
wasted++;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
const laterLlm = llms.filter((l) => l.startedAt > t.startedAt);
|
|
307
|
+
if (options.usageOracle) {
|
|
308
|
+
if (!options.usageOracle(t, { llm: laterLlm })) wasted++;
|
|
309
|
+
} else {
|
|
310
|
+
const resultStr = stringify(t.result);
|
|
311
|
+
const used = laterLlm.some(
|
|
312
|
+
(l) => l.messages.some(
|
|
313
|
+
(m) => typeof m.content === "string" && resultStr && m.content.includes(resultStr.slice(0, 120))
|
|
314
|
+
)
|
|
315
|
+
);
|
|
316
|
+
if (!used) wasted++;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const wasteRate = wasted / tools.length;
|
|
320
|
+
byRun.push({ runId, wastedCalls: wasted, totalCalls: tools.length, wasteRate });
|
|
321
|
+
totalCalls += tools.length;
|
|
322
|
+
totalWasted += wasted;
|
|
323
|
+
}
|
|
324
|
+
return { byRun, overallWasteRate: totalCalls > 0 ? totalWasted / totalCalls : 0 };
|
|
325
|
+
}
|
|
326
|
+
function stringify(v) {
|
|
327
|
+
if (v === null || v === void 0) return "";
|
|
328
|
+
if (typeof v === "string") return v;
|
|
329
|
+
try {
|
|
330
|
+
return JSON.stringify(v);
|
|
331
|
+
} catch {
|
|
332
|
+
return String(v);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
export {
|
|
336
|
+
budgetBreachView,
|
|
337
|
+
computeToolUseMetrics,
|
|
338
|
+
failureClusterView,
|
|
339
|
+
firstDivergenceView,
|
|
340
|
+
judgeAgreementView,
|
|
341
|
+
regressionView,
|
|
342
|
+
stuckLoopView,
|
|
343
|
+
toolWasteView
|
|
344
|
+
};
|
|
345
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/pipelines/budget-breach.ts","../../src/pipelines/first-divergence.ts","../../src/pipelines/judge-agreement.ts","../../src/pipelines/regression.ts","../../src/pipelines/stuck-loop.ts","../../src/pipelines/tool-waste.ts"],"sourcesContent":["/**\n * BudgetBreachView — aggregates breach events across the corpus.\n *\n * Answers: which dimensions get hit most often? Which scenarios are\n * underbudgeted? Which variants trigger the most breaches?\n */\n\nimport type { BudgetSpec } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nexport interface BudgetBreachFinding {\n runId: string\n scenarioId: string\n variantId?: string\n dimension: keyof BudgetSpec\n limit: number\n consumed: number\n excessRatio: number\n timestamp: number\n}\n\nexport interface BudgetBreachReport {\n findings: BudgetBreachFinding[]\n byDimension: Record<string, number>\n byScenario: Record<string, number>\n byVariant: Record<string, number>\n totalRuns: number\n breachedRunRatio: number\n}\n\nexport async function budgetBreachView(\n store: TraceStore,\n options: { scenarioId?: string; variantId?: string } = {},\n): Promise<BudgetBreachReport> {\n const runs = await store.listRuns({\n scenarioId: options.scenarioId,\n variantId: options.variantId,\n })\n const findings: BudgetBreachFinding[] = []\n const byDimension: Record<string, number> = {}\n const byScenario: Record<string, number> = {}\n const byVariant: Record<string, number> = {}\n\n for (const run of runs) {\n const entries = await store.budget(run.runId)\n for (const e of entries) {\n if (!e.breached) continue\n const excessRatio = e.limit > 0 ? e.consumed / e.limit : Infinity\n findings.push({\n runId: run.runId,\n scenarioId: run.scenarioId,\n variantId: run.variantId,\n dimension: e.dimension,\n limit: e.limit,\n consumed: e.consumed,\n excessRatio,\n timestamp: e.timestamp,\n })\n byDimension[e.dimension] = (byDimension[e.dimension] ?? 0) + 1\n byScenario[run.scenarioId] = (byScenario[run.scenarioId] ?? 0) + 1\n if (run.variantId) byVariant[run.variantId] = (byVariant[run.variantId] ?? 0) + 1\n }\n }\n\n const breachedRuns = new Set(findings.map((f) => f.runId))\n return {\n findings,\n byDimension,\n byScenario,\n byVariant,\n totalRuns: runs.length,\n breachedRunRatio: runs.length > 0 ? breachedRuns.size / runs.length : 0,\n }\n}\n","/**\n * FirstDivergenceView — aligns two trajectories by step index, reports\n * the first step where they differ.\n *\n * \"Differ\" is configurable — default is (kind, toolName if tool, model\n * if llm). Use this view to attribute \"why is variant B better?\" to a\n * specific step rather than an aggregate mean delta.\n */\n\nimport type { TraceStore } from '../trace/store'\nimport { buildTrajectory, type Trajectory, type TrajectoryStep } from '../trajectory'\n\nexport interface DivergenceReport {\n runA: string\n runB: string\n firstDivergenceIndex: number | null\n aStep?: TrajectoryStep\n bStep?: TrajectoryStep\n reason?: string\n /** Common prefix length (steps that matched). */\n commonPrefixLen: number\n}\n\nexport interface DivergenceOptions {\n /** Returns true if two steps are considered equal. Default: kind + tool/model match. */\n stepEquals?: (a: TrajectoryStep, b: TrajectoryStep) => boolean\n}\n\nexport async function firstDivergenceView(\n store: TraceStore,\n runA: string,\n runB: string,\n options: DivergenceOptions = {},\n): Promise<DivergenceReport> {\n const [a, b] = await Promise.all([buildTrajectory(store, runA), buildTrajectory(store, runB)])\n const eq = options.stepEquals ?? defaultStepEquals\n const minLen = Math.min(a.steps.length, b.steps.length)\n for (let i = 0; i < minLen; i++) {\n const aStep = a.steps[i]!\n const bStep = b.steps[i]!\n if (!eq(aStep, bStep)) {\n return {\n runA,\n runB,\n firstDivergenceIndex: i,\n aStep,\n bStep,\n reason: describeDifference(aStep, bStep),\n commonPrefixLen: i,\n }\n }\n }\n if (a.steps.length === b.steps.length) {\n return { runA, runB, firstDivergenceIndex: null, commonPrefixLen: minLen }\n }\n const longer: Trajectory = a.steps.length > b.steps.length ? a : b\n return {\n runA,\n runB,\n firstDivergenceIndex: minLen,\n aStep: a.steps[minLen],\n bStep: b.steps[minLen],\n reason: `one trajectory has ${longer.steps.length - minLen} more step(s) after index ${minLen - 1}`,\n commonPrefixLen: minLen,\n }\n}\n\nfunction defaultStepEquals(a: TrajectoryStep, b: TrajectoryStep): boolean {\n if (a.span.kind !== b.span.kind) return false\n if (a.span.kind === 'tool' && b.span.kind === 'tool') return a.span.toolName === b.span.toolName\n if (a.span.kind === 'llm' && b.span.kind === 'llm') return a.span.model === b.span.model\n if (a.span.kind === 'judge' && b.span.kind === 'judge')\n return a.span.dimension === b.span.dimension\n return a.span.name === b.span.name\n}\n\nfunction describeDifference(a: TrajectoryStep, b: TrajectoryStep): string {\n if (a.span.kind !== b.span.kind) return `kind ${a.span.kind} vs ${b.span.kind}`\n if (a.span.kind === 'tool' && b.span.kind === 'tool' && a.span.toolName !== b.span.toolName) {\n return `tool ${a.span.toolName} vs ${b.span.toolName}`\n }\n if (a.span.kind === 'llm' && b.span.kind === 'llm' && a.span.model !== b.span.model) {\n return `model ${a.span.model} vs ${b.span.model}`\n }\n return `name \"${a.span.name}\" vs \"${b.span.name}\"`\n}\n","/**\n * JudgeAgreementView — pairwise agreement between judges across the\n * corpus, grouped by dimension.\n *\n * Output drives two workflows:\n * - Judge robustness audit: \"does Claude agree with GPT at κ ≥ 0.6?\"\n * - Calibration tracking: κ vs golden human labels over time (by\n * providing a `humanGoldenJudgeId`).\n */\n\nimport { interRaterReliability } from '../statistics'\nimport type { JudgeSpan } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nexport interface JudgePair {\n judgeA: string\n judgeB: string\n dimension: string\n /** Number of (targetSpanId, dimension) tuples both judges scored. */\n commonItems: number\n pearson: number\n krippendorff: number\n}\n\nexport interface JudgeAgreementReport {\n pairs: JudgePair[]\n dimensions: string[]\n judgeIds: string[]\n}\n\nexport async function judgeAgreementView(store: TraceStore): Promise<JudgeAgreementReport> {\n const all = (await store.spans({ kind: 'judge' })).filter(\n (s): s is JudgeSpan => s.kind === 'judge',\n )\n if (all.length === 0) return { pairs: [], dimensions: [], judgeIds: [] }\n\n const byDimension = new Map<string, JudgeSpan[]>()\n for (const s of all) {\n const arr = byDimension.get(s.dimension) ?? []\n arr.push(s)\n byDimension.set(s.dimension, arr)\n }\n\n const judgeIds = [...new Set(all.map((s) => s.judgeId))].sort()\n const pairs: JudgePair[] = []\n for (const [dim, spans] of byDimension) {\n const byJudge = new Map<string, Map<string, number>>()\n for (const s of spans) {\n const m = byJudge.get(s.judgeId) ?? new Map<string, number>()\n m.set(s.targetSpanId, s.score)\n byJudge.set(s.judgeId, m)\n }\n const judgesHere = [...byJudge.keys()]\n for (let i = 0; i < judgesHere.length; i++) {\n for (let j = i + 1; j < judgesHere.length; j++) {\n const judgeI = judgesHere[i]!\n const judgeJ = judgesHere[j]!\n const a = byJudge.get(judgeI)!\n const b = byJudge.get(judgeJ)!\n const common: Array<[number, number]> = []\n for (const [target, scoreA] of a) {\n const scoreB = b.get(target)\n if (scoreB !== undefined) common.push([scoreA, scoreB])\n }\n if (common.length < 2) continue\n const judgeScores = common.map(\n ([scoreA, scoreB]) =>\n [\n { judgeName: judgeI, dimension: dim, score: scoreA, reasoning: '' },\n { judgeName: judgeJ, dimension: dim, score: scoreB, reasoning: '' },\n ] as const,\n )\n const k = interRaterReliability(\n judgeScores[0]!.map((_, k2) => judgeScores.map((pair) => pair[k2]!)),\n )\n pairs.push({\n judgeA: judgeI,\n judgeB: judgeJ,\n dimension: dim,\n commonItems: common.length,\n pearson: pearson(\n common.map((c) => c[0]),\n common.map((c) => c[1]),\n ),\n krippendorff: k,\n })\n }\n }\n }\n\n return {\n pairs: pairs.sort((a, b) => b.commonItems - a.commonItems),\n dimensions: [...byDimension.keys()].sort(),\n judgeIds,\n }\n}\n\nfunction pearson(a: number[], b: number[]): number {\n if (a.length !== b.length || a.length < 2) return NaN\n const mA = a.reduce((s, v) => s + v, 0) / a.length\n const mB = b.reduce((s, v) => s + v, 0) / b.length\n let num = 0,\n denA = 0,\n denB = 0\n for (let i = 0; i < a.length; i++) {\n const dA = a[i]! - mA\n const dB = b[i]! - mB\n num += dA * dB\n denA += dA * dA\n denB += dB * dB\n }\n if (denA === 0 || denB === 0) return denA === 0 && denB === 0 ? 1 : 0\n return num / Math.sqrt(denA * denB)\n}\n","/**\n * RegressionView — compares a candidate slice to a baseline slice on a\n * named metric. Delegates the statistics (Welch's t-test, Cohen's d,\n * IQR stability) to `baseline.ts`.\n *\n * This is the entry point for CI regression gates: \"given runs tagged\n * release=A and release=B, did any metric regress?\"\n */\n\nimport { type BaselineOptions, type BaselineReport, compareToBaseline } from '../baseline'\nimport { aggregateLlm, llmSpans, runFailureClass } from '../trace/query'\nimport type { Run } from '../trace/schema'\nimport type { RunFilter, TraceStore } from '../trace/store'\n\nexport interface RegressionSpec {\n metric: string\n higherIsBetter: boolean\n /** Extract a scalar from a run. Default extractors handle common metrics. */\n extract?: (run: Run, store: TraceStore) => Promise<number | null>\n}\n\nexport interface RegressionOptions extends BaselineOptions {\n baseline: RunFilter\n candidate: RunFilter\n}\n\nexport async function regressionView(\n store: TraceStore,\n metrics: RegressionSpec[],\n options: RegressionOptions,\n): Promise<BaselineReport> {\n const baselineRuns = await store.listRuns(options.baseline)\n const candidateRuns = await store.listRuns(options.candidate)\n const samples = await Promise.all(\n metrics.map(async (m) => {\n const extract = m.extract ?? defaultExtract(m.metric)\n const baseline = await extractAll(baselineRuns, extract, store)\n const candidate = await extractAll(candidateRuns, extract, store)\n return { metric: m.metric, higherIsBetter: m.higherIsBetter, baseline, candidate }\n }),\n )\n return compareToBaseline(samples, options)\n}\n\nasync function extractAll(\n runs: Run[],\n extract: (r: Run, s: TraceStore) => Promise<number | null>,\n store: TraceStore,\n): Promise<number[]> {\n const out: number[] = []\n for (const r of runs) {\n const v = await extract(r, store)\n if (v !== null && Number.isFinite(v)) out.push(v)\n }\n return out\n}\n\nfunction defaultExtract(metric: string): (run: Run, store: TraceStore) => Promise<number | null> {\n return async (run, store) => {\n switch (metric) {\n case 'score':\n case 'overallScore':\n return run.outcome?.score ?? null\n case 'pass':\n return run.outcome?.pass === true ? 1 : 0\n case 'durationMs':\n return run.endedAt && run.startedAt ? run.endedAt - run.startedAt : null\n case 'costUsd': {\n const llm = await llmSpans(store, run.runId)\n return aggregateLlm(llm).costUsd\n }\n case 'inputTokens': {\n const llm = await llmSpans(store, run.runId)\n return aggregateLlm(llm).inputTokens\n }\n case 'outputTokens': {\n const llm = await llmSpans(store, run.runId)\n return aggregateLlm(llm).outputTokens\n }\n case 'failureClass': {\n return runFailureClass(run) === 'success' ? 1 : 0\n }\n default:\n return null\n }\n }\n}\n","/**\n * StuckLoopView — detects when an agent calls the same tool with the\n * same (or structurally similar) arguments ≥ N times in a short window.\n *\n * Rationale: agents that loop are the number-one production failure\n * mode on long-horizon flows. The view returns (runId, toolName,\n * argHash, occurrences, windowMs) for each detected loop plus a\n * fraction of runs affected.\n */\n\nimport { argHash, toolSpans } from '../trace/query'\nimport type { TraceStore } from '../trace/store'\n\nexport interface StuckLoopFinding {\n runId: string\n toolName: string\n argHash: string\n occurrences: number\n spanIds: string[]\n /** Milliseconds between first and last call in the loop. */\n windowMs: number\n}\n\nexport interface StuckLoopReport {\n findings: StuckLoopFinding[]\n affectedRunRatio: number\n totalRuns: number\n}\n\nexport interface StuckLoopOptions {\n /** Minimum call count to flag a loop (default 3). */\n minOccurrences?: number\n /** Filter to a specific runId; omit to scan the entire corpus. */\n runId?: string\n}\n\nexport async function stuckLoopView(\n store: TraceStore,\n options: StuckLoopOptions = {},\n): Promise<StuckLoopReport> {\n const minOccurrences = options.minOccurrences ?? 3\n const runs = options.runId\n ? [{ runId: options.runId }]\n : (await store.listRuns()).map((r) => ({ runId: r.runId }))\n\n const findings: StuckLoopFinding[] = []\n for (const { runId } of runs) {\n const tools = await toolSpans(store, runId)\n const byKey = new Map<string, { spans: typeof tools; argHash: string }>()\n for (const t of tools) {\n const h = argHash(t.args)\n const key = `${t.toolName}|${h}`\n const bucket = byKey.get(key) ?? { spans: [], argHash: h }\n bucket.spans.push(t)\n byKey.set(key, bucket)\n }\n for (const [key, { spans, argHash: h }] of byKey) {\n if (spans.length < minOccurrences) continue\n const sorted = [...spans].sort((a, b) => a.startedAt - b.startedAt)\n const first = sorted[0]!.startedAt\n const last = sorted[sorted.length - 1]!.startedAt\n findings.push({\n runId,\n toolName: key.split('|')[0]!,\n argHash: h,\n occurrences: sorted.length,\n spanIds: sorted.map((s) => s.spanId),\n windowMs: last - first,\n })\n }\n }\n\n const affectedRuns = new Set(findings.map((f) => f.runId))\n return {\n findings,\n affectedRunRatio: runs.length > 0 ? affectedRuns.size / runs.length : 0,\n totalRuns: runs.length,\n }\n}\n","/**\n * ToolWasteView — fraction of tool calls whose results weren't used\n * downstream. Without a \"used\" signal we fall back to structural\n * proxies: error calls, duplicate calls, and tool calls followed by\n * zero subsequent LLM spans are all considered waste.\n *\n * Consumers can pass a `usageOracle` that inspects a tool span and\n * returns true iff the tool's result appears in a later LLM message,\n * artifact, or state mutation — that's the canonical definition; the\n * default heuristic is a reasonable fallback.\n */\n\nimport { computeToolUseMetrics } from '../tool-use-metrics'\nimport { llmSpans, toolSpans } from '../trace/query'\nimport type { ToolSpan } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nexport interface ToolWasteFinding {\n runId: string\n wastedCalls: number\n totalCalls: number\n wasteRate: number\n}\n\nexport interface ToolWasteReport {\n byRun: ToolWasteFinding[]\n overallWasteRate: number\n}\n\nexport interface ToolWasteOptions {\n runId?: string\n usageOracle?: (tool: ToolSpan, later: { llm: Awaited<ReturnType<typeof llmSpans>> }) => boolean\n}\n\nexport async function toolWasteView(\n store: TraceStore,\n options: ToolWasteOptions = {},\n): Promise<ToolWasteReport> {\n const runs = options.runId ? [options.runId] : (await store.listRuns()).map((r) => r.runId)\n\n const byRun: ToolWasteFinding[] = []\n let totalCalls = 0\n let totalWasted = 0\n for (const runId of runs) {\n const tools = await toolSpans(store, runId)\n if (tools.length === 0) {\n byRun.push({ runId, wastedCalls: 0, totalCalls: 0, wasteRate: 0 })\n continue\n }\n const llms = await llmSpans(store, runId)\n let wasted = 0\n for (const t of tools) {\n if (t.status === 'error') {\n wasted++\n continue\n }\n const laterLlm = llms.filter((l) => l.startedAt > t.startedAt)\n if (options.usageOracle) {\n if (!options.usageOracle(t, { llm: laterLlm })) wasted++\n } else {\n // Default heuristic: a tool whose result is NOT mentioned in any\n // later LLM input message is likely wasted.\n const resultStr = stringify(t.result)\n const used = laterLlm.some((l) =>\n l.messages.some(\n (m) =>\n typeof m.content === 'string' &&\n resultStr &&\n m.content.includes(resultStr.slice(0, 120)),\n ),\n )\n if (!used) wasted++\n }\n }\n const wasteRate = wasted / tools.length\n byRun.push({ runId, wastedCalls: wasted, totalCalls: tools.length, wasteRate })\n totalCalls += tools.length\n totalWasted += wasted\n }\n return { byRun, overallWasteRate: totalCalls > 0 ? totalWasted / totalCalls : 0 }\n}\n\nfunction stringify(v: unknown): string {\n if (v === null || v === undefined) return ''\n if (typeof v === 'string') return v\n try {\n return JSON.stringify(v)\n } catch {\n return String(v)\n }\n}\n\n// Re-export for convenience in consumers that want both descriptive and usage metrics.\nexport { computeToolUseMetrics }\n"],"mappings":"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","names":[]}
|