@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
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { R as RunRecord } from './run-record-CqzahIbx.js';
|
|
2
|
+
import { O as OutcomeStore } from './outcome-store-D6KWmYvj.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Rubric predictive validity — does our eval rubric predict deployment
|
|
6
|
+
* outcomes?
|
|
7
|
+
*
|
|
8
|
+
* `correlationStudy` (already in this package) joins a `TraceStore` to an
|
|
9
|
+
* `OutcomeStore` and computes Pearson + Spearman + bootstrap CI for each
|
|
10
|
+
* (eval-metric, outcome-metric) pair. That answers "does X correlate with
|
|
11
|
+
* Y at all." `rubricPredictiveValidity` is the campaign-shaped wrapper
|
|
12
|
+
* around it: take a sequence of `RunRecord`s (the canonical campaign
|
|
13
|
+
* artifact) and a `DeploymentOutcomeStore`, join on `runId`, return a
|
|
14
|
+
* ranked verdict on every rubric whose dimension scores were captured in
|
|
15
|
+
* `outcome.raw`.
|
|
16
|
+
*
|
|
17
|
+
* The point — quoting the methodology doc — is that **without this loop
|
|
18
|
+
* every rubric is faith-based**. Once it's wired, you know which rubrics
|
|
19
|
+
* have earned their promotion power and which ones are decoration.
|
|
20
|
+
*
|
|
21
|
+
* const validity = await rubricPredictiveValidity({
|
|
22
|
+
* runs: lastQuarter,
|
|
23
|
+
* outcomes: shipFlagOutcomeStore,
|
|
24
|
+
* outcomeMetrics: ['revenue_lift', 'retention_30d', 'csat'],
|
|
25
|
+
* rubrics: ['anti_slop', 'semantic_concept', 'tool_recovery'],
|
|
26
|
+
* })
|
|
27
|
+
* for (const r of validity.ranked) {
|
|
28
|
+
* console.log(`${r.rubric} → ${r.bestOutcome}: ρ=${r.spearman.toFixed(2)}`)
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* The function is intentionally read-only. Use the verdict to deprecate
|
|
32
|
+
* decorative rubrics, re-weight composite scores, or trigger a
|
|
33
|
+
* recalibration sweep when predictive validity drops below a threshold.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
interface RubricPredictiveValidityInput {
|
|
37
|
+
/**
|
|
38
|
+
* Canonical campaign output. Each record's `outcome.raw[<rubricId>]`
|
|
39
|
+
* provides the eval score; missing keys are silently skipped per pair.
|
|
40
|
+
*/
|
|
41
|
+
runs: RunRecord[];
|
|
42
|
+
outcomes: OutcomeStore;
|
|
43
|
+
/**
|
|
44
|
+
* Outcome metric names to evaluate against. Each must appear in at
|
|
45
|
+
* least one `DeploymentOutcome.metrics` keyspace; pairs with too few
|
|
46
|
+
* joined samples are excluded from the result.
|
|
47
|
+
*/
|
|
48
|
+
outcomeMetrics: string[];
|
|
49
|
+
/**
|
|
50
|
+
* Rubric ids to evaluate. Must appear as keys in `RunRecord.outcome.raw`.
|
|
51
|
+
* If omitted, every numeric key in `outcome.raw` across the run set is
|
|
52
|
+
* treated as a rubric.
|
|
53
|
+
*/
|
|
54
|
+
rubrics?: string[];
|
|
55
|
+
/** Minimum joined-sample count before a pair is reported. Default 8. */
|
|
56
|
+
minSamples?: number;
|
|
57
|
+
/** Bootstrap resamples for CI. Default 500. */
|
|
58
|
+
bootstrapResamples?: number;
|
|
59
|
+
/** Random seed for the bootstrap (mulberry32). Default unset (Math.random). */
|
|
60
|
+
seed?: number;
|
|
61
|
+
/**
|
|
62
|
+
* Reduction when multiple outcomes attach to one runId. Default `'latest'`
|
|
63
|
+
* (most recently captured).
|
|
64
|
+
*/
|
|
65
|
+
reduction?: 'latest' | 'mean' | 'max';
|
|
66
|
+
}
|
|
67
|
+
interface RubricOutcomePair {
|
|
68
|
+
rubric: string;
|
|
69
|
+
outcome: string;
|
|
70
|
+
n: number;
|
|
71
|
+
pearson: number;
|
|
72
|
+
spearman: number;
|
|
73
|
+
ci95: {
|
|
74
|
+
low: number;
|
|
75
|
+
high: number;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Verdict bucket. `load_bearing` ≥ 0.7, `informative` ≥ 0.4,
|
|
79
|
+
* `decorative` < 0.4 in absolute correlation. A negative correlation
|
|
80
|
+
* with a desired outcome is also `decorative` — actively misleading
|
|
81
|
+
* is worse than uninformative.
|
|
82
|
+
*/
|
|
83
|
+
verdict: 'load_bearing' | 'informative' | 'decorative';
|
|
84
|
+
}
|
|
85
|
+
interface RubricRanking {
|
|
86
|
+
rubric: string;
|
|
87
|
+
/** Outcome metric this rubric correlated best with. */
|
|
88
|
+
bestOutcome: string;
|
|
89
|
+
spearman: number;
|
|
90
|
+
pearson: number;
|
|
91
|
+
n: number;
|
|
92
|
+
verdict: RubricOutcomePair['verdict'];
|
|
93
|
+
}
|
|
94
|
+
interface RubricPredictiveValidityReport {
|
|
95
|
+
pairs: RubricOutcomePair[];
|
|
96
|
+
/** Per-rubric best pair, sorted descending by |spearman|. */
|
|
97
|
+
ranked: RubricRanking[];
|
|
98
|
+
joinedSamples: number;
|
|
99
|
+
skippedRuns: number;
|
|
100
|
+
/** Rubrics that were declared but never produced a usable score. */
|
|
101
|
+
rubricsWithoutData: string[];
|
|
102
|
+
}
|
|
103
|
+
declare function rubricPredictiveValidity(input: RubricPredictiveValidityInput): Promise<RubricPredictiveValidityReport>;
|
|
104
|
+
|
|
105
|
+
export { type RubricOutcomePair as R, type RubricPredictiveValidityInput as a, type RubricPredictiveValidityReport as b, type RubricRanking as c, rubricPredictiveValidity as r };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { V as ValidationError } from './errors-BZ9sTdz7.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Paper-grade RunRecord schema + runtime validator.
|
|
3
5
|
*
|
|
@@ -117,7 +119,8 @@ interface RunRecord {
|
|
|
117
119
|
*/
|
|
118
120
|
scenarioId?: string;
|
|
119
121
|
}
|
|
120
|
-
|
|
122
|
+
|
|
123
|
+
declare class RunRecordValidationError extends ValidationError {
|
|
121
124
|
readonly path: string;
|
|
122
125
|
constructor(message: string, path?: string);
|
|
123
126
|
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Always-valid sequential evaluation.
|
|
3
|
+
*
|
|
4
|
+
* `researchReport` (0.21+) assumes a single pre-specified analysis. Real
|
|
5
|
+
* consumers run campaigns weekly / nightly / per-PR; each new run silently
|
|
6
|
+
* inflates the false-discovery rate, because the BH-FDR guarantee was for
|
|
7
|
+
* the *first* look, not the 47th. Without time-uniform inference,
|
|
8
|
+
* launch-decision teams either (a) don't peek, which forfeits the cost
|
|
9
|
+
* advantage of stop-when-decisive, or (b) peek and pretend they didn't,
|
|
10
|
+
* which forfeits scientific validity.
|
|
11
|
+
*
|
|
12
|
+
* This module ships **e-value-based confidence sequences** for paired
|
|
13
|
+
* bounded outcomes. The methodology is the predictable plug-in betting
|
|
14
|
+
* martingale of Waudby-Smith & Ramdas (2024) — provably valid at *any*
|
|
15
|
+
* stopping time. Concretely:
|
|
16
|
+
*
|
|
17
|
+
* For paired deltas D_1, D_2, … ∈ [-c, c] with the null H_0: E[D] ≤ 0,
|
|
18
|
+
* a betting fraction λ_i is chosen using only D_{1..i-1} (predictable
|
|
19
|
+
* plug-in), and the running e-value is
|
|
20
|
+
*
|
|
21
|
+
* E_t = ∏_{i=1}^{t} (1 + λ_i · D_i)
|
|
22
|
+
*
|
|
23
|
+
* E_t is a non-negative martingale under H_0 with E[E_t] ≤ 1, so by
|
|
24
|
+
* Ville's inequality, P(∃ t : E_t ≥ 1/α) ≤ α — we can reject the null
|
|
25
|
+
* at any time without inflating the type-I error.
|
|
26
|
+
*
|
|
27
|
+
* Combined with `runEvalCampaign`, every consumer running rolling
|
|
28
|
+
* campaigns gains the ability to ship the moment evidence is decisive,
|
|
29
|
+
* stop-early on dead-on-arrival variants, and accumulate evidence across
|
|
30
|
+
* partial runs without spending the FDR budget. No new sweep is wasted.
|
|
31
|
+
*
|
|
32
|
+
* References:
|
|
33
|
+
* - Howard, S. R., Ramdas, A., McAuliffe, J., Sekhon, J. (2021).
|
|
34
|
+
* Time-uniform, nonparametric, nonasymptotic confidence sequences.
|
|
35
|
+
* Annals of Statistics, 49(2), 1055–1080.
|
|
36
|
+
* - Waudby-Smith, I., Ramdas, A. (2024). Estimating means of bounded
|
|
37
|
+
* random variables by betting. JRSS B, 86(1), 1–27.
|
|
38
|
+
*/
|
|
39
|
+
type SequentialDecision = 'promote_now' | 'continue' | 'reject_now' | 'equivalent';
|
|
40
|
+
interface PairedEvalueOptions {
|
|
41
|
+
/**
|
|
42
|
+
* Bound on |delta|. Default 1 (matching most score scales). Must satisfy
|
|
43
|
+
* c > 0; deltas outside [-c, c] are clipped with a warning attached to
|
|
44
|
+
* the return value.
|
|
45
|
+
*/
|
|
46
|
+
bound?: number;
|
|
47
|
+
/** Target Type-I error. Default 0.05. */
|
|
48
|
+
alpha?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Region of Practical Equivalence on the *mean* paired delta. When
|
|
51
|
+
* supplied, the verdict can return `'equivalent'` once the running
|
|
52
|
+
* confidence sequence on the mean is fully contained in [low, high].
|
|
53
|
+
*/
|
|
54
|
+
rope?: {
|
|
55
|
+
low: number;
|
|
56
|
+
high: number;
|
|
57
|
+
};
|
|
58
|
+
/** Initial bet shrinkage (0 < scale ≤ 1). Default 0.5 — empirically robust. */
|
|
59
|
+
initialBetShrinkage?: number;
|
|
60
|
+
}
|
|
61
|
+
interface PairedEvalueStep {
|
|
62
|
+
/** 1-indexed observation count. */
|
|
63
|
+
t: number;
|
|
64
|
+
delta: number;
|
|
65
|
+
/** Running e-value E_t = ∏ (1 + λ_i · D_i). */
|
|
66
|
+
evalue: number;
|
|
67
|
+
/** Time-uniform p-value at stopping time t. */
|
|
68
|
+
pValue: number;
|
|
69
|
+
/** Lower bound of the empirical Bernstein confidence sequence at level 1-α. */
|
|
70
|
+
csLow: number;
|
|
71
|
+
csHigh: number;
|
|
72
|
+
/** Verdict at this stopping time. */
|
|
73
|
+
decision: SequentialDecision;
|
|
74
|
+
}
|
|
75
|
+
interface PairedEvalueSequence {
|
|
76
|
+
steps: PairedEvalueStep[];
|
|
77
|
+
/** The decision at the final step. */
|
|
78
|
+
finalDecision: SequentialDecision;
|
|
79
|
+
/** Index (1-based) at which a non-`continue` decision first fired, or null. */
|
|
80
|
+
decisionFiredAt: number | null;
|
|
81
|
+
/** True if any deltas were clipped to [-bound, bound]. */
|
|
82
|
+
clipped: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Run the paired e-value sequence over an in-order delta stream.
|
|
86
|
+
*
|
|
87
|
+
* Use for *streaming* / interim analyses: pass the deltas you have so
|
|
88
|
+
* far, get the verdict at every prefix length. The decision is
|
|
89
|
+
* monotone-stable in the sense that once `'reject_now'` or `'promote_now'`
|
|
90
|
+
* fires, the verdict at later steps remains decisive (the e-value is a
|
|
91
|
+
* non-negative martingale; once it crosses the threshold, it's crossed).
|
|
92
|
+
*/
|
|
93
|
+
declare function pairedEvalueSequence(deltas: number[], opts?: PairedEvalueOptions): PairedEvalueSequence;
|
|
94
|
+
interface InterimReleaseConfidenceInput {
|
|
95
|
+
/**
|
|
96
|
+
* One delta series per candidate (paired deltas vs comparator). Order
|
|
97
|
+
* within a series is the order the campaigns were run.
|
|
98
|
+
*/
|
|
99
|
+
deltaSeries: Array<{
|
|
100
|
+
candidateId: string;
|
|
101
|
+
deltas: number[];
|
|
102
|
+
}>;
|
|
103
|
+
alpha?: number;
|
|
104
|
+
bound?: number;
|
|
105
|
+
rope?: {
|
|
106
|
+
low: number;
|
|
107
|
+
high: number;
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
interface InterimReleaseConfidence {
|
|
111
|
+
candidates: Array<{
|
|
112
|
+
candidateId: string;
|
|
113
|
+
decision: SequentialDecision;
|
|
114
|
+
decisionFiredAt: number | null;
|
|
115
|
+
finalEvalue: number;
|
|
116
|
+
finalPValue: number;
|
|
117
|
+
pairs: number;
|
|
118
|
+
csLow: number;
|
|
119
|
+
csHigh: number;
|
|
120
|
+
}>;
|
|
121
|
+
/**
|
|
122
|
+
* Campaign-level recommendation: pick the strongest 'promote_now', else
|
|
123
|
+
* 'continue' if any candidate is still live, else 'reject_now' if every
|
|
124
|
+
* candidate is dead, else 'equivalent'.
|
|
125
|
+
*/
|
|
126
|
+
recommendation: {
|
|
127
|
+
decision: SequentialDecision;
|
|
128
|
+
candidateId: string | null;
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Run interim sequential analyses across many candidates at once,
|
|
133
|
+
* preserving the time-uniform α guarantee for each candidate's series and
|
|
134
|
+
* synthesising a campaign-level recommendation. Designed to be called on
|
|
135
|
+
* every campaign tick — the recommendation is anytime-valid.
|
|
136
|
+
*/
|
|
137
|
+
declare function evaluateInterimReleaseConfidence(input: InterimReleaseConfidenceInput): InterimReleaseConfidence;
|
|
138
|
+
|
|
139
|
+
export { type InterimReleaseConfidence as I, type PairedEvalueOptions as P, type SequentialDecision as S, type InterimReleaseConfidenceInput as a, type PairedEvalueSequence as b, type PairedEvalueStep as c, evaluateInterimReleaseConfidence as e, pairedEvalueSequence as p };
|
|
@@ -294,4 +294,4 @@ declare class FileSystemTraceStore implements TraceStore {
|
|
|
294
294
|
artifacts(runId: string): Promise<Artifact[]>;
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
export { type Artifact as A, type BudgetLedgerEntry as B, type EventKind as E, type FailureClass as F, type GenericSpan as G, InMemoryTraceStore as I, type JudgeSpan as J, type LlmSpan as L, type Message as M, type
|
|
297
|
+
export { type Artifact as A, type BudgetLedgerEntry as B, type EventKind as E, type FailureClass as F, type GenericSpan as G, InMemoryTraceStore as I, type JudgeSpan as J, type LlmSpan as L, type Message as M, type Run as R, type Span as S, type TraceStore as T, type ToolSpan as a, type TraceEvent as b, type RunOutcome as c, type SpanKind as d, type RetrievalSpan as e, type SandboxSpan as f, type BudgetSpec as g, type RunFilter as h, type EventFilter as i, FAILURE_CLASSES as j, FileSystemTraceStore as k, type FileSystemTraceStoreOptions as l, type RunLayer as m, type RunStatus as n, type SpanBase as o, type SpanFilter as p, type SpanStatus as q, TRACE_SCHEMA_VERSION as r, isJudgeSpan as s, isLlmSpan as t, isRetrievalSpan as u, isSandboxSpan as v, isToolSpan as w };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { R as RunRecord, a as RunSplitTag } from './run-record-
|
|
2
|
-
import {
|
|
1
|
+
import { R as RunRecord, a as RunSplitTag } from './run-record-CqzahIbx.js';
|
|
2
|
+
import { F as FailureClusterReport } from './failure-cluster-C2EGSDiT.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* HeldOutGate — first-class held-out paired-delta promotion gate.
|
|
@@ -596,79 +596,6 @@ declare function runMultiShotOptimization<P>(config: MultiShotOptimizationConfig
|
|
|
596
596
|
declare function defaultMultiShotObjectives(): Objective<VariantAggregate>[];
|
|
597
597
|
declare function trialTraceFromMultiShotTrial(trial: MultiShotTrialResult): TrialTrace;
|
|
598
598
|
|
|
599
|
-
/**
|
|
600
|
-
* Failure taxonomy — canonical classes + a default classifier.
|
|
601
|
-
*
|
|
602
|
-
* Every failed run should end up in a named class. The classifier here
|
|
603
|
-
* is rule-based (fast, deterministic); an LLM fallback can be added by
|
|
604
|
-
* the consumer for novel cases and trained into the rule base over time.
|
|
605
|
-
*
|
|
606
|
-
* Consumers call `classifyFailure(run, spans, events)` and persist the
|
|
607
|
-
* returned class as `Run.outcome.failureClass`.
|
|
608
|
-
*/
|
|
609
|
-
|
|
610
|
-
interface FailureContext {
|
|
611
|
-
run: Run;
|
|
612
|
-
spans: Span[];
|
|
613
|
-
events: TraceEvent[];
|
|
614
|
-
}
|
|
615
|
-
interface FailureClassification {
|
|
616
|
-
failureClass: FailureClass;
|
|
617
|
-
reason: string;
|
|
618
|
-
triggerSpanId?: string;
|
|
619
|
-
triggerEventId?: string;
|
|
620
|
-
}
|
|
621
|
-
/** Ordered rules — first match wins. */
|
|
622
|
-
interface FailureRule {
|
|
623
|
-
id: string;
|
|
624
|
-
match: (ctx: FailureContext) => {
|
|
625
|
-
failureClass: FailureClass;
|
|
626
|
-
reason: string;
|
|
627
|
-
triggerSpanId?: string;
|
|
628
|
-
triggerEventId?: string;
|
|
629
|
-
} | null;
|
|
630
|
-
}
|
|
631
|
-
declare const DEFAULT_RULES: FailureRule[];
|
|
632
|
-
/** Classify the failure mode of a run using an ordered rule list. */
|
|
633
|
-
declare function classifyFailure(ctx: FailureContext, rules?: FailureRule[]): FailureClassification;
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* FailureClusterView — groups failed runs by (failureClass, triggerTool,
|
|
637
|
-
* argHash-prefix) so weekly reviews can prioritize the top-N clusters.
|
|
638
|
-
*
|
|
639
|
-
* Each cluster includes: N runs, scenarios affected, representative
|
|
640
|
-
* error message, a proposed mitigation hint (rule → action table).
|
|
641
|
-
*/
|
|
642
|
-
|
|
643
|
-
interface FailureCluster {
|
|
644
|
-
failureClass: FailureClass;
|
|
645
|
-
/** Tool name when the trigger was a tool span, else undefined. */
|
|
646
|
-
toolName?: string;
|
|
647
|
-
/** First 16 chars of argHash — clusters similar args. */
|
|
648
|
-
argPrefix?: string;
|
|
649
|
-
/**
|
|
650
|
-
* Source dimension when the trigger was a judge span (e.g. `'format'`,
|
|
651
|
-
* `'safety'`, `'correctness'`). Lets cross-template aggregators
|
|
652
|
-
* group failures by the dimension that fired without overloading
|
|
653
|
-
* `argPrefix`. Optional — legacy clusters without this field
|
|
654
|
-
* deserialize cleanly.
|
|
655
|
-
*/
|
|
656
|
-
dimension?: string;
|
|
657
|
-
runCount: number;
|
|
658
|
-
scenarioIds: string[];
|
|
659
|
-
exampleError?: string;
|
|
660
|
-
exampleRunId: string;
|
|
661
|
-
}
|
|
662
|
-
interface FailureClusterReport {
|
|
663
|
-
clusters: FailureCluster[];
|
|
664
|
-
totalFailures: number;
|
|
665
|
-
totalRuns: number;
|
|
666
|
-
}
|
|
667
|
-
declare function failureClusterView(store: TraceStore, options?: {
|
|
668
|
-
rules?: FailureRule[];
|
|
669
|
-
minClusterSize?: number;
|
|
670
|
-
}): Promise<FailureClusterReport>;
|
|
671
|
-
|
|
672
599
|
/**
|
|
673
600
|
* Reporting helpers — production summaries and paper-quality figures — sit alongside `reporter.ts` rather
|
|
674
601
|
* than replacing it.
|
|
@@ -975,4 +902,4 @@ interface ResearchReport {
|
|
|
975
902
|
*/
|
|
976
903
|
declare function researchReport(runs: RunRecord[], opts?: ResearchReportOptions): Promise<ResearchReport>;
|
|
977
904
|
|
|
978
|
-
export {
|
|
905
|
+
export { gainHistogram as $, type ActionableSideInfo as A, trialTraceFromMultiShotTrial as B, type GainDistributionBin as C, DEFAULT_MUTATION_PRIMITIVES as D, type EvolvableVariant as E, type GainDistributionFigureSpec as F, type GenerationReport as G, type GainDistributionOptions as H, InMemoryTrialCache as I, type ParetoFigureSpec as J, type ParetoPoint as K, RESEARCH_REPORT_HARD_PAIR_FLOOR as L, type MultiShotGateConfig as M, type ResearchReport as N, type ResearchReportCandidate as O, type PromptEvolutionConfig as P, type ResearchReportDecision as Q, type ReflectionContext as R, type ScenarioAggregate as S, type TrialCache as T, type ResearchReportMethodology as U, type VariantAggregate as V, type ResearchReportOptions as W, type ResearchReportRecommendation as X, type SummaryTable as Y, type SummaryTableOptions as Z, type SummaryTableRow as _, type AsiSeverity as a, paretoChart as a0, researchReport as a1, summaryTable as a2, type GateDecision as a3, type HeldOutGateConfig as a4, type Objective as a5, type ParetoResult as a6, type Direction as a7, type GateEvidence as a8, HeldOutGate as a9, type HeldOutGateRejectionCode as aa, crowdingDistance as ab, dominates as ac, paretoFrontier as ad, paretoFrontierWithCrowding as ae, scalarScore as af, type MultiShotGateResult as b, type MultiShotMutateAdapter as c, type MultiShotOptimizationConfig as d, type MultiShotOptimizationResult as e, type MultiShotRun as f, type MultiShotRunInput as g, type MultiShotRunner as h, type MultiShotScore as i, type MultiShotScorer as j, type MultiShotSplit as k, type MultiShotTrace as l, type MultiShotTrialResult as m, type MultiShotVariant as n, type MutateAdapter as o, type PromptEvolutionEvent as p, type PromptEvolutionResult as q, type ReflectionProposal as r, type ScoreAdapter as s, type TrialResult as t, type TrialTrace as u, buildReflectionPrompt as v, defaultMultiShotObjectives as w, parseReflectionResponse as x, runMultiShotOptimization as y, runPromptEvolution as z };
|
package/dist/telemetry/file.js
CHANGED
|
@@ -18,7 +18,10 @@ var FileTelemetrySink = class {
|
|
|
18
18
|
if (!stream) {
|
|
19
19
|
const dir = path.join(this.baseDir, repo);
|
|
20
20
|
fs.mkdirSync(dir, { recursive: true });
|
|
21
|
-
stream = fs.createWriteStream(path.join(dir, `${date}.jsonl`), {
|
|
21
|
+
stream = fs.createWriteStream(path.join(dir, `${date}.jsonl`), {
|
|
22
|
+
flags: "a",
|
|
23
|
+
encoding: "utf-8"
|
|
24
|
+
});
|
|
22
25
|
this.streams.set(key, stream);
|
|
23
26
|
}
|
|
24
27
|
stream.write(`${JSON.stringify(envelope)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/telemetry/sink-file.ts"],"sourcesContent":["/**\n * Node-only file sink. Imports `node:fs` — DO NOT import this from a Worker\n * or edge runtime; use `./sink-fetch` instead.\n */\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { TelemetryEnvelope } from './schema'\nimport type { TelemetrySink } from './sink-fetch'\n\n/** Append envelopes to a JSONL file, partitioned by repo + date. */\nexport class FileTelemetrySink implements TelemetrySink {\n private streams = new Map<string, fs.WriteStream>()\n\n constructor(private readonly baseDir: string) {\n fs.mkdirSync(baseDir, { recursive: true })\n }\n\n emit(envelope: TelemetryEnvelope): void {\n const date = envelope.timestamp.slice(0, 10) // YYYY-MM-DD\n const repo = envelope.source.repo || 'unknown'\n const key = `${repo}/${date}`\n let stream = this.streams.get(key)\n if (!stream) {\n const dir = path.join(this.baseDir, repo)\n fs.mkdirSync(dir, { recursive: true })\n stream = fs.createWriteStream(path.join(dir, `${date}.jsonl`), {
|
|
1
|
+
{"version":3,"sources":["../../src/telemetry/sink-file.ts"],"sourcesContent":["/**\n * Node-only file sink. Imports `node:fs` — DO NOT import this from a Worker\n * or edge runtime; use `./sink-fetch` instead.\n */\n\nimport * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport type { TelemetryEnvelope } from './schema'\nimport type { TelemetrySink } from './sink-fetch'\n\n/** Append envelopes to a JSONL file, partitioned by repo + date. */\nexport class FileTelemetrySink implements TelemetrySink {\n private streams = new Map<string, fs.WriteStream>()\n\n constructor(private readonly baseDir: string) {\n fs.mkdirSync(baseDir, { recursive: true })\n }\n\n emit(envelope: TelemetryEnvelope): void {\n const date = envelope.timestamp.slice(0, 10) // YYYY-MM-DD\n const repo = envelope.source.repo || 'unknown'\n const key = `${repo}/${date}`\n let stream = this.streams.get(key)\n if (!stream) {\n const dir = path.join(this.baseDir, repo)\n fs.mkdirSync(dir, { recursive: true })\n stream = fs.createWriteStream(path.join(dir, `${date}.jsonl`), {\n flags: 'a',\n encoding: 'utf-8',\n })\n this.streams.set(key, stream)\n }\n stream.write(`${JSON.stringify(envelope)}\\n`)\n }\n\n async close(): Promise<void> {\n const closes = Array.from(this.streams.values()).map(\n (s) => new Promise<void>((resolve) => s.end(() => resolve())),\n )\n this.streams.clear()\n await Promise.all(closes)\n }\n}\n\n/** Default location for local telemetry, mirroring bad CLI's convention. */\nexport function defaultTelemetryDir(homeDir: string, override?: string): string {\n return override || path.join(homeDir, '.agent-eval', 'telemetry')\n}\n"],"mappings":";;;AAKA,YAAY,QAAQ;AACpB,YAAY,UAAU;AAKf,IAAM,oBAAN,MAAiD;AAAA,EAGtD,YAA6B,SAAiB;AAAjB;AAC3B,IAAG,aAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EAC3C;AAAA,EAF6B;AAAA,EAFrB,UAAU,oBAAI,IAA4B;AAAA,EAMlD,KAAK,UAAmC;AACtC,UAAM,OAAO,SAAS,UAAU,MAAM,GAAG,EAAE;AAC3C,UAAM,OAAO,SAAS,OAAO,QAAQ;AACrC,UAAM,MAAM,GAAG,IAAI,IAAI,IAAI;AAC3B,QAAI,SAAS,KAAK,QAAQ,IAAI,GAAG;AACjC,QAAI,CAAC,QAAQ;AACX,YAAM,MAAW,UAAK,KAAK,SAAS,IAAI;AACxC,MAAG,aAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AACrC,eAAY,qBAAuB,UAAK,KAAK,GAAG,IAAI,QAAQ,GAAG;AAAA,QAC7D,OAAO;AAAA,QACP,UAAU;AAAA,MACZ,CAAC;AACD,WAAK,QAAQ,IAAI,KAAK,MAAM;AAAA,IAC9B;AACA,WAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,CAAC;AAAA,CAAI;AAAA,EAC9C;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,SAAS,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,EAAE;AAAA,MAC/C,CAAC,MAAM,IAAI,QAAc,CAAC,YAAY,EAAE,IAAI,MAAM,QAAQ,CAAC,CAAC;AAAA,IAC9D;AACA,SAAK,QAAQ,MAAM;AACnB,UAAM,QAAQ,IAAI,MAAM;AAAA,EAC1B;AACF;AAGO,SAAS,oBAAoB,SAAiB,UAA2B;AAC9E,SAAO,YAAiB,UAAK,SAAS,eAAe,WAAW;AAClE;","names":[]}
|
package/dist/telemetry/index.js
CHANGED
|
@@ -3,62 +3,6 @@ import "../chunk-PZ5AY32C.js";
|
|
|
3
3
|
// src/telemetry/schema.ts
|
|
4
4
|
var TELEMETRY_SCHEMA_VERSION = 1;
|
|
5
5
|
|
|
6
|
-
// src/telemetry/sink-fetch.ts
|
|
7
|
-
var HttpTelemetrySink = class {
|
|
8
|
-
constructor(endpoint, bearer) {
|
|
9
|
-
this.endpoint = endpoint;
|
|
10
|
-
this.bearer = bearer;
|
|
11
|
-
}
|
|
12
|
-
endpoint;
|
|
13
|
-
bearer;
|
|
14
|
-
inflight = /* @__PURE__ */ new Set();
|
|
15
|
-
emit(envelope) {
|
|
16
|
-
const body = JSON.stringify(envelope);
|
|
17
|
-
const headers = { "content-type": "application/json" };
|
|
18
|
-
if (this.bearer) headers.authorization = `Bearer ${this.bearer}`;
|
|
19
|
-
const promise = fetch(this.endpoint, { method: "POST", headers, body }).then(() => void 0).catch(() => void 0);
|
|
20
|
-
this.inflight.add(promise);
|
|
21
|
-
promise.finally(() => this.inflight.delete(promise));
|
|
22
|
-
}
|
|
23
|
-
async close() {
|
|
24
|
-
await Promise.allSettled(Array.from(this.inflight));
|
|
25
|
-
}
|
|
26
|
-
};
|
|
27
|
-
var FanoutTelemetrySink = class {
|
|
28
|
-
constructor(sinks) {
|
|
29
|
-
this.sinks = sinks;
|
|
30
|
-
}
|
|
31
|
-
sinks;
|
|
32
|
-
emit(envelope) {
|
|
33
|
-
for (const sink of this.sinks) {
|
|
34
|
-
try {
|
|
35
|
-
const result = sink.emit(envelope);
|
|
36
|
-
if (result && typeof result.catch === "function") {
|
|
37
|
-
;
|
|
38
|
-
result.catch(() => void 0);
|
|
39
|
-
}
|
|
40
|
-
} catch {
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
async close() {
|
|
45
|
-
await Promise.allSettled(this.sinks.map((s) => Promise.resolve(s.close?.())));
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
var NullTelemetrySink = class {
|
|
49
|
-
emit() {
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
var InMemoryTelemetrySink = class {
|
|
53
|
-
envelopes = [];
|
|
54
|
-
emit(envelope) {
|
|
55
|
-
this.envelopes.push(envelope);
|
|
56
|
-
}
|
|
57
|
-
clear() {
|
|
58
|
-
this.envelopes.length = 0;
|
|
59
|
-
}
|
|
60
|
-
};
|
|
61
|
-
|
|
62
6
|
// src/telemetry/client.ts
|
|
63
7
|
var TelemetryClient = class {
|
|
64
8
|
constructor(sink, defaultSource) {
|
|
@@ -97,7 +41,7 @@ function makeEnvelopeId() {
|
|
|
97
41
|
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
98
42
|
return crypto.randomUUID();
|
|
99
43
|
}
|
|
100
|
-
return
|
|
44
|
+
return `env-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
101
45
|
}
|
|
102
46
|
var SECRET_FLAGS = /* @__PURE__ */ new Set(["--api-key", "--bearer", "--token", "--password"]);
|
|
103
47
|
function sanitiseArgv(argv) {
|
|
@@ -117,6 +61,62 @@ function sanitiseArgv(argv) {
|
|
|
117
61
|
}
|
|
118
62
|
return out;
|
|
119
63
|
}
|
|
64
|
+
|
|
65
|
+
// src/telemetry/sink-fetch.ts
|
|
66
|
+
var HttpTelemetrySink = class {
|
|
67
|
+
constructor(endpoint, bearer) {
|
|
68
|
+
this.endpoint = endpoint;
|
|
69
|
+
this.bearer = bearer;
|
|
70
|
+
}
|
|
71
|
+
endpoint;
|
|
72
|
+
bearer;
|
|
73
|
+
inflight = /* @__PURE__ */ new Set();
|
|
74
|
+
emit(envelope) {
|
|
75
|
+
const body = JSON.stringify(envelope);
|
|
76
|
+
const headers = { "content-type": "application/json" };
|
|
77
|
+
if (this.bearer) headers.authorization = `Bearer ${this.bearer}`;
|
|
78
|
+
const promise = fetch(this.endpoint, { method: "POST", headers, body }).then(() => void 0).catch(() => void 0);
|
|
79
|
+
this.inflight.add(promise);
|
|
80
|
+
promise.finally(() => this.inflight.delete(promise));
|
|
81
|
+
}
|
|
82
|
+
async close() {
|
|
83
|
+
await Promise.allSettled(Array.from(this.inflight));
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
var FanoutTelemetrySink = class {
|
|
87
|
+
constructor(sinks) {
|
|
88
|
+
this.sinks = sinks;
|
|
89
|
+
}
|
|
90
|
+
sinks;
|
|
91
|
+
emit(envelope) {
|
|
92
|
+
for (const sink of this.sinks) {
|
|
93
|
+
try {
|
|
94
|
+
const result = sink.emit(envelope);
|
|
95
|
+
if (result && typeof result.catch === "function") {
|
|
96
|
+
;
|
|
97
|
+
result.catch(() => void 0);
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
async close() {
|
|
104
|
+
await Promise.allSettled(this.sinks.map((s) => Promise.resolve(s.close?.())));
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
var NullTelemetrySink = class {
|
|
108
|
+
emit() {
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
var InMemoryTelemetrySink = class {
|
|
112
|
+
envelopes = [];
|
|
113
|
+
emit(envelope) {
|
|
114
|
+
this.envelopes.push(envelope);
|
|
115
|
+
}
|
|
116
|
+
clear() {
|
|
117
|
+
this.envelopes.length = 0;
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
120
|
export {
|
|
121
121
|
FanoutTelemetrySink,
|
|
122
122
|
HttpTelemetrySink,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/telemetry/schema.ts","../../src/telemetry/sink-fetch.ts","../../src/telemetry/client.ts"],"sourcesContent":["/**\n * Fleet telemetry envelope — agent-eval's portable observability shape.\n *\n * Designed so any consumer (Node CLI, Cloudflare Worker, Lambda, browser\n * extension) can emit structured rows describing one unit of work — a page\n * audit, a tool call, an evolve round, a full agent run — to a central sink.\n *\n * The schema is intentionally a strict superset of agent-eval's `Run` shape\n * so a future TraceStore adapter can promote envelopes into traces without\n * translation.\n */\n\nexport const TELEMETRY_SCHEMA_VERSION = 1\n\n/** Discriminator for the unit of work this envelope describes. */\nexport type TelemetryKind =\n | 'agent-run'\n | 'design-audit-page'\n | 'design-audit-run'\n | 'design-evolve-round'\n | 'design-evolve-run'\n | 'gepa-trial'\n | 'gepa-generation'\n | 'tool-call'\n | 'judge-verdict'\n | 'custom'\n\nexport interface TelemetryEnvelope {\n schemaVersion: typeof TELEMETRY_SCHEMA_VERSION\n envelopeId: string\n runId: string\n timestamp: string\n parentRunId?: string\n\n source: TelemetrySource\n model?: TelemetryModel\n kind: TelemetryKind\n ok: boolean\n durationMs: number\n\n data: Record<string, unknown>\n metrics: Record<string, number>\n tags?: Record<string, string>\n\n error?: string\n}\n\nexport interface TelemetrySource {\n /** Repo identity — basename of cwd plus git remote if discoverable. */\n repo: string\n cwd: string\n gitSha?: string\n gitBranch?: string\n cliVersion: string\n /** What was invoked, e.g. `design-audit`, `bad run`, `gepa --target`. */\n invocation: string\n /** Sanitised argv minus secrets. */\n argv?: string[]\n /**\n * Multi-tenant identity. Set when the consumer runs inside a hosted\n * product so a fleet rollup can group by tenant without leaking customer\n * URLs or PII.\n */\n tenantId?: string\n /** Optional sub-tenant identity (project, suite, walkthrough, customer). */\n customerId?: string\n /** SHA-256 (12 hex) of the API key used to authenticate this run, when applicable. */\n apiKeyHash?: string\n}\n\nexport interface TelemetryModel {\n provider: string\n name: string\n /** SHA-256 (12 hex chars) of the prompt(s) used. */\n promptHash?: string\n /** SHA-256 (12 hex chars) of the composed rubric body, if applicable. */\n rubricHash?: string\n}\n","/**\n * Workers-safe telemetry sinks — only `fetch` and pure JS. No `fs`, no\n * `child_process`. Safe to import from a Cloudflare Worker, Lambda, edge\n * function, or browser extension.\n *\n * For Node-only file persistence, import from '@tangle-network/agent-eval/telemetry/file'.\n */\n\nimport type { TelemetryEnvelope } from './schema'\n\nexport interface TelemetrySink {\n emit(envelope: TelemetryEnvelope): Promise<void> | void\n close?(): Promise<void> | void\n}\n\n/** Best-effort POST to a remote collector. Fire-and-forget; never throws. */\nexport class HttpTelemetrySink implements TelemetrySink {\n private inflight = new Set<Promise<void>>()\n\n constructor(\n private readonly endpoint: string,\n private readonly bearer?: string,\n ) {}\n\n emit(envelope: TelemetryEnvelope): void {\n const body = JSON.stringify(envelope)\n const headers: Record<string, string> = { 'content-type': 'application/json' }\n if (this.bearer) headers.authorization = `Bearer ${this.bearer}`\n const promise = fetch(this.endpoint, { method: 'POST', headers, body })\n .then(() => undefined)\n .catch(() => undefined)\n this.inflight.add(promise)\n promise.finally(() => this.inflight.delete(promise))\n }\n\n async close(): Promise<void> {\n await Promise.allSettled(Array.from(this.inflight))\n }\n}\n\n/** Fanout to multiple sinks — failures in one do not affect others. */\nexport class FanoutTelemetrySink implements TelemetrySink {\n constructor(private readonly sinks: TelemetrySink[]) {}\n\n emit(envelope: TelemetryEnvelope): void {\n for (const sink of this.sinks) {\n try {\n const result = sink.emit(envelope)\n if (result && typeof (result as Promise<unknown>).catch === 'function') {\n ;(result as Promise<unknown>).catch(() => undefined)\n }\n } catch {\n // swallow — telemetry must never break a run\n }\n }\n }\n\n async close(): Promise<void> {\n await Promise.allSettled(this.sinks.map((s) => Promise.resolve(s.close?.())))\n }\n}\n\n/** No-op sink — used when telemetry is explicitly disabled. */\nexport class NullTelemetrySink implements TelemetrySink {\n emit(): void {}\n}\n\n/** In-memory sink — useful for tests + downstream adapters. */\nexport class InMemoryTelemetrySink implements TelemetrySink {\n readonly envelopes: TelemetryEnvelope[] = []\n emit(envelope: TelemetryEnvelope): void {\n this.envelopes.push(envelope)\n }\n clear(): void { this.envelopes.length = 0 }\n}\n","/**\n * Telemetry client — thin wrapper that builds envelopes from `EmitArgs` and\n * delegates to a `TelemetrySink`. Pure logic; no I/O. Use this from any\n * runtime — Workers, Node, browser — and choose the sink accordingly.\n *\n * For an opinionated singleton with env-var-driven sink wiring (the bad CLI\n * pattern), see `./node-client.ts`.\n */\n\nimport type { TelemetryEnvelope, TelemetryKind, TelemetryModel, TelemetrySource } from './schema'\nimport { TELEMETRY_SCHEMA_VERSION } from './schema'\nimport type { TelemetrySink } from './sink-fetch'\n\nexport interface EmitArgs {\n kind: TelemetryKind\n runId: string\n parentRunId?: string\n ok: boolean\n durationMs: number\n data?: Record<string, unknown>\n metrics?: Record<string, number>\n tags?: Record<string, string>\n model?: TelemetryModel\n error?: string\n /** Override the source for this envelope. Falls back to `defaultSource`. */\n source?: TelemetrySource\n}\n\nexport class TelemetryClient {\n constructor(\n private readonly sink: TelemetrySink,\n private readonly defaultSource: TelemetrySource,\n ) {}\n\n emit(args: EmitArgs): void {\n const envelope: TelemetryEnvelope = {\n schemaVersion: TELEMETRY_SCHEMA_VERSION,\n envelopeId: makeEnvelopeId(),\n runId: args.runId,\n timestamp: new Date().toISOString(),\n source: args.source ?? this.defaultSource,\n kind: args.kind,\n ok: args.ok,\n durationMs: args.durationMs,\n data: args.data ?? {},\n metrics: args.metrics ?? {},\n ...(args.parentRunId ? { parentRunId: args.parentRunId } : {}),\n ...(args.model ? { model: args.model } : {}),\n ...(args.tags ? { tags: args.tags } : {}),\n ...(args.error ? { error: args.error } : {}),\n }\n try {\n this.sink.emit(envelope)\n } catch {\n // swallow — telemetry never breaks the calling code path\n }\n }\n\n async close(): Promise<void> {\n await this.sink.close?.()\n }\n}\n\n/** Generate a UUIDv4 with whatever crypto is available (Node, Workers, browsers). */\nfunction makeEnvelopeId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n // Last-resort fallback. Lower entropy but never throws.\n return 'env-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 10)\n}\n\nexport const SECRET_FLAGS = new Set(['--api-key', '--bearer', '--token', '--password'])\n\n/** Strip likely-secret values from argv, preserving structure. */\nexport function sanitiseArgv(argv: string[]): string[] {\n const out: string[] = []\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!\n if (SECRET_FLAGS.has(a)) {\n out.push(a, '<redacted>')\n i++\n continue\n }\n if (/^(?:--api-key|--bearer|--token|--password)=/.test(a)) {\n out.push(a.replace(/=.*$/, '=<redacted>'))\n continue\n }\n out.push(a)\n }\n return out\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/telemetry/schema.ts","../../src/telemetry/client.ts","../../src/telemetry/sink-fetch.ts"],"sourcesContent":["/**\n * Fleet telemetry envelope — agent-eval's portable observability shape.\n *\n * Designed so any consumer (Node CLI, Cloudflare Worker, Lambda, browser\n * extension) can emit structured rows describing one unit of work — a page\n * audit, a tool call, an evolve round, a full agent run — to a central sink.\n *\n * The schema is intentionally a strict superset of agent-eval's `Run` shape\n * so a future TraceStore adapter can promote envelopes into traces without\n * translation.\n */\n\nexport const TELEMETRY_SCHEMA_VERSION = 1\n\n/** Discriminator for the unit of work this envelope describes. */\nexport type TelemetryKind =\n | 'agent-run'\n | 'design-audit-page'\n | 'design-audit-run'\n | 'design-evolve-round'\n | 'design-evolve-run'\n | 'gepa-trial'\n | 'gepa-generation'\n | 'tool-call'\n | 'judge-verdict'\n | 'custom'\n\nexport interface TelemetryEnvelope {\n schemaVersion: typeof TELEMETRY_SCHEMA_VERSION\n envelopeId: string\n runId: string\n timestamp: string\n parentRunId?: string\n\n source: TelemetrySource\n model?: TelemetryModel\n kind: TelemetryKind\n ok: boolean\n durationMs: number\n\n data: Record<string, unknown>\n metrics: Record<string, number>\n tags?: Record<string, string>\n\n error?: string\n}\n\nexport interface TelemetrySource {\n /** Repo identity — basename of cwd plus git remote if discoverable. */\n repo: string\n cwd: string\n gitSha?: string\n gitBranch?: string\n cliVersion: string\n /** What was invoked, e.g. `design-audit`, `bad run`, `gepa --target`. */\n invocation: string\n /** Sanitised argv minus secrets. */\n argv?: string[]\n /**\n * Multi-tenant identity. Set when the consumer runs inside a hosted\n * product so a fleet rollup can group by tenant without leaking customer\n * URLs or PII.\n */\n tenantId?: string\n /** Optional sub-tenant identity (project, suite, walkthrough, customer). */\n customerId?: string\n /** SHA-256 (12 hex) of the API key used to authenticate this run, when applicable. */\n apiKeyHash?: string\n}\n\nexport interface TelemetryModel {\n provider: string\n name: string\n /** SHA-256 (12 hex chars) of the prompt(s) used. */\n promptHash?: string\n /** SHA-256 (12 hex chars) of the composed rubric body, if applicable. */\n rubricHash?: string\n}\n","/**\n * Telemetry client — thin wrapper that builds envelopes from `EmitArgs` and\n * delegates to a `TelemetrySink`. Pure logic; no I/O. Use this from any\n * runtime — Workers, Node, browser — and choose the sink accordingly.\n *\n * For an opinionated singleton with env-var-driven sink wiring (the bad CLI\n * pattern), see `./node-client.ts`.\n */\n\nimport type { TelemetryEnvelope, TelemetryKind, TelemetryModel, TelemetrySource } from './schema'\nimport { TELEMETRY_SCHEMA_VERSION } from './schema'\nimport type { TelemetrySink } from './sink-fetch'\n\nexport interface EmitArgs {\n kind: TelemetryKind\n runId: string\n parentRunId?: string\n ok: boolean\n durationMs: number\n data?: Record<string, unknown>\n metrics?: Record<string, number>\n tags?: Record<string, string>\n model?: TelemetryModel\n error?: string\n /** Override the source for this envelope. Falls back to `defaultSource`. */\n source?: TelemetrySource\n}\n\nexport class TelemetryClient {\n constructor(\n private readonly sink: TelemetrySink,\n private readonly defaultSource: TelemetrySource,\n ) {}\n\n emit(args: EmitArgs): void {\n const envelope: TelemetryEnvelope = {\n schemaVersion: TELEMETRY_SCHEMA_VERSION,\n envelopeId: makeEnvelopeId(),\n runId: args.runId,\n timestamp: new Date().toISOString(),\n source: args.source ?? this.defaultSource,\n kind: args.kind,\n ok: args.ok,\n durationMs: args.durationMs,\n data: args.data ?? {},\n metrics: args.metrics ?? {},\n ...(args.parentRunId ? { parentRunId: args.parentRunId } : {}),\n ...(args.model ? { model: args.model } : {}),\n ...(args.tags ? { tags: args.tags } : {}),\n ...(args.error ? { error: args.error } : {}),\n }\n try {\n this.sink.emit(envelope)\n } catch {\n // swallow — telemetry never breaks the calling code path\n }\n }\n\n async close(): Promise<void> {\n await this.sink.close?.()\n }\n}\n\n/** Generate a UUIDv4 with whatever crypto is available (Node, Workers, browsers). */\nfunction makeEnvelopeId(): string {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID()\n }\n // Last-resort fallback. Lower entropy but never throws.\n return `env-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`\n}\n\nexport const SECRET_FLAGS = new Set(['--api-key', '--bearer', '--token', '--password'])\n\n/** Strip likely-secret values from argv, preserving structure. */\nexport function sanitiseArgv(argv: string[]): string[] {\n const out: string[] = []\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i]!\n if (SECRET_FLAGS.has(a)) {\n out.push(a, '<redacted>')\n i++\n continue\n }\n if (/^(?:--api-key|--bearer|--token|--password)=/.test(a)) {\n out.push(a.replace(/=.*$/, '=<redacted>'))\n continue\n }\n out.push(a)\n }\n return out\n}\n","/**\n * Workers-safe telemetry sinks — only `fetch` and pure JS. No `fs`, no\n * `child_process`. Safe to import from a Cloudflare Worker, Lambda, edge\n * function, or browser extension.\n *\n * For Node-only file persistence, import from '@tangle-network/agent-eval/telemetry/file'.\n */\n\nimport type { TelemetryEnvelope } from './schema'\n\nexport interface TelemetrySink {\n emit(envelope: TelemetryEnvelope): Promise<void> | void\n close?(): Promise<void> | void\n}\n\n/** Best-effort POST to a remote collector. Fire-and-forget; never throws. */\nexport class HttpTelemetrySink implements TelemetrySink {\n private inflight = new Set<Promise<void>>()\n\n constructor(\n private readonly endpoint: string,\n private readonly bearer?: string,\n ) {}\n\n emit(envelope: TelemetryEnvelope): void {\n const body = JSON.stringify(envelope)\n const headers: Record<string, string> = { 'content-type': 'application/json' }\n if (this.bearer) headers.authorization = `Bearer ${this.bearer}`\n const promise = fetch(this.endpoint, { method: 'POST', headers, body })\n .then(() => undefined)\n .catch(() => undefined)\n this.inflight.add(promise)\n promise.finally(() => this.inflight.delete(promise))\n }\n\n async close(): Promise<void> {\n await Promise.allSettled(Array.from(this.inflight))\n }\n}\n\n/** Fanout to multiple sinks — failures in one do not affect others. */\nexport class FanoutTelemetrySink implements TelemetrySink {\n constructor(private readonly sinks: TelemetrySink[]) {}\n\n emit(envelope: TelemetryEnvelope): void {\n for (const sink of this.sinks) {\n try {\n const result = sink.emit(envelope)\n if (result && typeof (result as Promise<unknown>).catch === 'function') {\n ;(result as Promise<unknown>).catch(() => undefined)\n }\n } catch {\n // swallow — telemetry must never break a run\n }\n }\n }\n\n async close(): Promise<void> {\n await Promise.allSettled(this.sinks.map((s) => Promise.resolve(s.close?.())))\n }\n}\n\n/** No-op sink — used when telemetry is explicitly disabled. */\nexport class NullTelemetrySink implements TelemetrySink {\n emit(): void {}\n}\n\n/** In-memory sink — useful for tests + downstream adapters. */\nexport class InMemoryTelemetrySink implements TelemetrySink {\n readonly envelopes: TelemetryEnvelope[] = []\n emit(envelope: TelemetryEnvelope): void {\n this.envelopes.push(envelope)\n }\n clear(): void {\n this.envelopes.length = 0\n }\n}\n"],"mappings":"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","names":[]}
|