@tangle-network/agent-eval 0.189.0 → 0.190.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/CHANGELOG.md +94 -0
  2. package/README.md +3 -2
  3. package/dist/adapters/http.d.ts +10 -1
  4. package/dist/adapters/http.d.ts.map +1 -1
  5. package/dist/adapters/http.js +75 -7
  6. package/dist/adapters/http.js.map +1 -1
  7. package/dist/analyst/index.d.ts +66 -3
  8. package/dist/analyst/index.d.ts.map +1 -1
  9. package/dist/analyst/index.js +212 -7
  10. package/dist/analyst/index.js.map +1 -1
  11. package/dist/{benchmark-command-BhhAYstU.js → benchmark-command-BXIr_k8D.js} +12 -11
  12. package/dist/benchmark-command-BXIr_k8D.js.map +1 -0
  13. package/dist/benchmarks/index.d.ts +1 -1
  14. package/dist/benchmarks/index.js +3 -3
  15. package/dist/campaign/index.d.ts +4 -4
  16. package/dist/campaign/index.js +7 -7
  17. package/dist/{campaign-BWoSQPSU.js → campaign-B7q74uIh.js} +256 -11
  18. package/dist/campaign-B7q74uIh.js.map +1 -0
  19. package/dist/{campaign-evidence-CBlGJ3kC.js → campaign-evidence-D40-LHIL.js} +6 -5
  20. package/dist/campaign-evidence-D40-LHIL.js.map +1 -0
  21. package/dist/{chat-client-C4dg7Ng_.js → chat-client-B_ItsSBw.js} +2 -2
  22. package/dist/{chat-client-C4dg7Ng_.js.map → chat-client-B_ItsSBw.js.map} +1 -1
  23. package/dist/{chat-json-call-JVGbfx95.js → chat-json-call-CXHBvUz8.js} +2 -2
  24. package/dist/{chat-json-call-JVGbfx95.js.map → chat-json-call-CXHBvUz8.js.map} +1 -1
  25. package/dist/claim-BGOUqoMq.d.ts +38 -0
  26. package/dist/claim-BGOUqoMq.d.ts.map +1 -0
  27. package/dist/cli.js +3 -3
  28. package/dist/contract/index.d.ts +4 -4
  29. package/dist/contract/index.js +8 -8
  30. package/dist/{default-registry-m2jhbG6Q.js → default-registry-16I-Bxlf.js} +2 -2
  31. package/dist/{default-registry-m2jhbG6Q.js.map → default-registry-16I-Bxlf.js.map} +1 -1
  32. package/dist/{define-agent-eval-98sgUaC1.js → define-agent-eval-DPizhHfy.js} +4 -4
  33. package/dist/{define-agent-eval-98sgUaC1.js.map → define-agent-eval-DPizhHfy.js.map} +1 -1
  34. package/dist/{define-agent-eval-q6890HU4.d.ts → define-agent-eval-DblGedQk.d.ts} +4 -3
  35. package/dist/define-agent-eval-DblGedQk.d.ts.map +1 -0
  36. package/dist/diagnosis/index.d.ts +14 -2
  37. package/dist/diagnosis/index.d.ts.map +1 -1
  38. package/dist/diagnosis/index.js +11 -4
  39. package/dist/diagnosis/index.js.map +1 -1
  40. package/dist/{dspy-rlm-engine-DLYttKBm.js → dspy-rlm-engine-Cs5LzJ-f.js} +3 -3
  41. package/dist/{dspy-rlm-engine-DLYttKBm.js.map → dspy-rlm-engine-Cs5LzJ-f.js.map} +1 -1
  42. package/dist/{eval-campaign-C0Q1Eeo_.js → eval-campaign-CwsBn0Gm.js} +2 -2
  43. package/dist/{eval-campaign-C0Q1Eeo_.js.map → eval-campaign-CwsBn0Gm.js.map} +1 -1
  44. package/dist/experiment/index.d.ts +2 -1
  45. package/dist/experiment/index.d.ts.map +1 -1
  46. package/dist/experiment/index.js +1 -1
  47. package/dist/exporters-XMCYJlqT.d.ts +161 -0
  48. package/dist/exporters-XMCYJlqT.d.ts.map +1 -0
  49. package/dist/{external-optimizer-process-C3quNeKV.js → external-optimizer-process-BnSmrkgL.js} +3 -3
  50. package/dist/{external-optimizer-process-C3quNeKV.js.map → external-optimizer-process-BnSmrkgL.js.map} +1 -1
  51. package/dist/{external-optimizer-subprocess-BDwgKLO1.js → external-optimizer-subprocess-kbcPu5po.js} +3 -3
  52. package/dist/{external-optimizer-subprocess-BDwgKLO1.js.map → external-optimizer-subprocess-kbcPu5po.js.map} +1 -1
  53. package/dist/{feedback-trajectory-B3ZSkfAq.d.ts → feedback-trajectory-BYjh7NEM.d.ts} +2 -2
  54. package/dist/{feedback-trajectory-B3ZSkfAq.d.ts.map → feedback-trajectory-BYjh7NEM.d.ts.map} +1 -1
  55. package/dist/{index-CnJOPR_E.d.ts → index-CJv56rhX.d.ts} +673 -244
  56. package/dist/index-CJv56rhX.d.ts.map +1 -0
  57. package/dist/{index-Dk1dOUfm.d.ts → index-CWoIJHmy.d.ts} +4 -4
  58. package/dist/{index-Dk1dOUfm.d.ts.map → index-CWoIJHmy.d.ts.map} +1 -1
  59. package/dist/{index-Bcc9PkOz.d.ts → index-D4pC7Tvd.d.ts} +3 -2
  60. package/dist/index-D4pC7Tvd.d.ts.map +1 -0
  61. package/dist/{index-BqDJ6fUK.d.ts → index-I4UJGRno.d.ts} +74 -2
  62. package/dist/index-I4UJGRno.d.ts.map +1 -0
  63. package/dist/index.d.ts +66 -17
  64. package/dist/index.d.ts.map +1 -1
  65. package/dist/index.js +375 -31
  66. package/dist/index.js.map +1 -1
  67. package/dist/{journal-CDP0Vhx_.js → journal-c3qY0SDP.js} +246 -5
  68. package/dist/journal-c3qY0SDP.js.map +1 -0
  69. package/dist/{kind-factory-BGwN0nE6.js → kind-factory-ByZeXDqF.js} +2 -2
  70. package/dist/{kind-factory-BGwN0nE6.js.map → kind-factory-ByZeXDqF.js.map} +1 -1
  71. package/dist/ledger-core/index.d.ts +2 -2
  72. package/dist/ledger-core/index.js +2 -2
  73. package/dist/{llm-client-DF9bPNYA.js → llm-client-KYQBh9C8.js} +2 -2
  74. package/dist/{llm-client-DF9bPNYA.js.map → llm-client-KYQBh9C8.js.map} +1 -1
  75. package/dist/{llm-judge-M_l_WXw2.js → llm-judge-BnxAv7ed.js} +1892 -1378
  76. package/dist/llm-judge-BnxAv7ed.js.map +1 -0
  77. package/dist/mint-C9Lojt1V.d.ts +147 -0
  78. package/dist/mint-C9Lojt1V.d.ts.map +1 -0
  79. package/dist/openapi.json +1 -1
  80. package/dist/pipelines/index.d.ts +1 -1
  81. package/dist/pipelines/index.js +1 -1
  82. package/dist/pipelines/index.js.map +1 -1
  83. package/dist/{produced-state-BOY98IJO.js → produced-state-BXjXJHJT.js} +4 -4
  84. package/dist/{produced-state-BOY98IJO.js.map → produced-state-BXjXJHJT.js.map} +1 -1
  85. package/dist/{raw-provider-sink-C96CcqeG.js → raw-provider-sink-DYh4Bszw.js} +2 -2
  86. package/dist/{raw-provider-sink-C96CcqeG.js.map → raw-provider-sink-DYh4Bszw.js.map} +1 -1
  87. package/dist/{redact-DxwlUAvh.js → redact-B7rt9Zot.js} +130 -10
  88. package/dist/redact-B7rt9Zot.js.map +1 -0
  89. package/dist/{redact-DPoH1-OW.d.ts → redact-CopuMxll.d.ts} +7 -5
  90. package/dist/redact-CopuMxll.d.ts.map +1 -0
  91. package/dist/rl.d.ts +3 -2
  92. package/dist/rl.d.ts.map +1 -1
  93. package/dist/rl.js +1 -1
  94. package/dist/rollout/index.d.ts +3 -2
  95. package/dist/search-ledger-types-C9anU2DX.d.ts +489 -0
  96. package/dist/search-ledger-types-C9anU2DX.d.ts.map +1 -0
  97. package/dist/{semantic-concept-judge-Cm2K2wAo.js → semantic-concept-judge-ClB73cei.js} +6 -6
  98. package/dist/{semantic-concept-judge-Cm2K2wAo.js.map → semantic-concept-judge-ClB73cei.js.map} +1 -1
  99. package/dist/{server-C8XvqCg8.js → server-DtetGGoA.js} +2 -2
  100. package/dist/{server-C8XvqCg8.js.map → server-DtetGGoA.js.map} +1 -1
  101. package/dist/{skillopt-optimization-method-BVSB676o.js → skillopt-optimization-method-l2vDBtKp.js} +363 -18
  102. package/dist/skillopt-optimization-method-l2vDBtKp.js.map +1 -0
  103. package/dist/{spans-W0o8pbEg.d.ts → spans-BWtjk_9c.d.ts} +2 -2
  104. package/dist/{spans-W0o8pbEg.d.ts.map → spans-BWtjk_9c.d.ts.map} +1 -1
  105. package/dist/{statistical-heldout-plAHG82H.d.ts → statistical-heldout-CLpjYffJ.d.ts} +2 -36
  106. package/dist/statistical-heldout-CLpjYffJ.d.ts.map +1 -0
  107. package/dist/{store-otlp-D0AV4cvB.js → store-otlp-84DH0OEH.js} +2 -2
  108. package/dist/{store-otlp-D0AV4cvB.js.map → store-otlp-84DH0OEH.js.map} +1 -1
  109. package/dist/{store-tool-spans-8PAyhRqb.d.ts → store-tool-spans-BBXs8hDP.d.ts} +2 -2
  110. package/dist/{store-tool-spans-8PAyhRqb.d.ts.map → store-tool-spans-BBXs8hDP.d.ts.map} +1 -1
  111. package/dist/{store-tool-spans-B_0mXvYl.js → store-tool-spans-DUiqyHvR.js} +5 -5
  112. package/dist/{store-tool-spans-B_0mXvYl.js.map → store-tool-spans-DUiqyHvR.js.map} +1 -1
  113. package/dist/traces.d.ts +3 -63
  114. package/dist/traces.d.ts.map +1 -1
  115. package/dist/traces.js +6 -195
  116. package/dist/traces.js.map +1 -1
  117. package/dist/wire/index.d.ts +1 -1
  118. package/dist/wire/index.js +1 -1
  119. package/docs/adapters-observability.md +31 -27
  120. package/docs/charter.md +1 -1
  121. package/docs/design/mlbenchmarks-book-review.md +1 -1
  122. package/docs/distributed-driver.md +1 -5
  123. package/docs/experiment.md +15 -0
  124. package/docs/public-api.md +181 -71
  125. package/docs/redaction.md +7 -1
  126. package/docs/search-ledger.md +174 -0
  127. package/docs/trace-contracts.md +48 -3
  128. package/package.json +1 -1
  129. package/dist/benchmark-command-BhhAYstU.js.map +0 -1
  130. package/dist/campaign-BWoSQPSU.js.map +0 -1
  131. package/dist/campaign-evidence-CBlGJ3kC.js.map +0 -1
  132. package/dist/define-agent-eval-q6890HU4.d.ts.map +0 -1
  133. package/dist/index-Bcc9PkOz.d.ts.map +0 -1
  134. package/dist/index-BqDJ6fUK.d.ts.map +0 -1
  135. package/dist/index-CnJOPR_E.d.ts.map +0 -1
  136. package/dist/journal-CDP0Vhx_.js.map +0 -1
  137. package/dist/llm-judge-M_l_WXw2.js.map +0 -1
  138. package/dist/mint-DsS38v5c.d.ts +0 -305
  139. package/dist/mint-DsS38v5c.d.ts.map +0 -1
  140. package/dist/redact-DPoH1-OW.d.ts.map +0 -1
  141. package/dist/redact-DxwlUAvh.js.map +0 -1
  142. package/dist/search-ledger-types-D7KDVg-o.d.ts +0 -302
  143. package/dist/search-ledger-types-D7KDVg-o.d.ts.map +0 -1
  144. package/dist/skillopt-optimization-method-BVSB676o.js.map +0 -1
  145. package/dist/statistical-heldout-plAHG82H.d.ts.map +0 -1
  146. package/docs/search-history-receipts.md +0 -233
@@ -0,0 +1,147 @@
1
+ import { a as RunRecord, s as RunSearchCoordinates } from "./run-record-DF-fuu31.js";
2
+ import { s as TraceStore } from "./store-C4avFjIi.js";
3
+ import { a as MintedRolloutLine, t as ChatMessage, v as RolloutRole } from "./schema-B5LtYvn9.js";
4
+ //#region src/rollout/reward.d.ts
5
+ /**
6
+ * Which split's score wins when a record carries both. `'holdout'` is the
7
+ * canonical "real signal" default; `'search'` exists because some callers
8
+ * deliberately score on the search split when both are present.
9
+ */
10
+ type ScorePreference = 'holdout' | 'search';
11
+ /** Only the outcome is read, so every accessor here accepts anything carrying one. */
12
+ type Scored = Pick<RunRecord, 'outcome'>;
13
+ /** True when the authenticity gate flagged the run as gamed (`realness.gated`). */
14
+ declare function isRealnessGated(record: Scored): boolean;
15
+ /**
16
+ * The RAW score recorded on ONE split, with no cross-split fallback and no
17
+ * anti-Goodhart gate.
18
+ *
19
+ * The narrowest of the three raw readers, and the one every split-scoped
20
+ * consumer wants: a per-split report, a promotion gate, or a paired comparison
21
+ * asks "what did this run score on the split I am summarising", and answering
22
+ * it with the other split's number silently mixes populations. `undefined` =
23
+ * that split was never scored.
24
+ *
25
+ * Same warning as `observedScore`: this INCLUDES runs flagged as gamed. Never
26
+ * feed it into training data.
27
+ */
28
+ declare function observedSplitScore(record: Scored, split: ScorePreference): number | undefined;
29
+ /**
30
+ * The RAW split score the run carries, with NO anti-Goodhart gate applied.
31
+ *
32
+ * INCLUDES RUNS FLAGGED AS GAMED (`outcome.realness.gated === true`); NEVER
33
+ * feed this into training data — a fine-tune that sees it learns from gamed
34
+ * successes. It is exported anyway because analysis, reporting, and
35
+ * reward-hacking detection legitimately need the ungated number: forcing a
36
+ * gamed run to 0 collapses the proxy signal toward ground truth and makes a
37
+ * detector report "clean" on exactly the population that is being gamed.
38
+ *
39
+ * Returns `undefined` when the record carries neither score — an unscored run
40
+ * is a labeled gap, not a measured zero, and each caller picks its own
41
+ * sentinel (`?? 0`, `?? null`, skip, throw). Non-finite values are returned
42
+ * as-is; callers that care keep their own `Number.isFinite` guard.
43
+ */
44
+ declare function observedScore(record: Scored, prefer?: ScorePreference): number | undefined;
45
+ /** Which split actually carried the score, or that none did. */
46
+ type ScoreOrigin = 'holdout' | 'search' | 'unscored';
47
+ /**
48
+ * Where `observedScore` / `trainingScore` read their number from — the
49
+ * provenance label a rollout line's `reward_source` is built from, and the
50
+ * only supported way to ask "was this run scored at all" without respelling
51
+ * the field access.
52
+ */
53
+ declare function scoreOrigin(record: Scored, prefer?: ScorePreference): ScoreOrigin;
54
+ /**
55
+ * The GATED score — the only derivation allowed to reach training data.
56
+ *
57
+ * A realness-gated run scores 0 no matter what it claims, so a fine-tune
58
+ * cannot learn from a gamed success. An unscored run stays `undefined` (a
59
+ * labeled gap), keeping "we never measured this" distinct from "we measured
60
+ * zero"; callers that need a number apply their own sentinel.
61
+ */
62
+ declare function trainingScore(record: Scored, prefer?: ScorePreference): number | undefined;
63
+ /**
64
+ * `{reward, gated}` as written onto a minted `RolloutLine` — `trainingScore`
65
+ * plus the flag itself, so the gate travels into the exported row and a
66
+ * downstream filter can drop or down-weight the line.
67
+ *
68
+ * An unscored record yields `reward: null`, matching the schema's "no verdict
69
+ * exists — a labeled gap, never 0" rule. It previously collapsed to 0, which
70
+ * made a run nobody graded indistinguishable from one graded as a total
71
+ * failure, and taught any trainer reading the row that the trajectory was bad.
72
+ * A gated run still yields 0, because that IS a verdict: the gate decided.
73
+ */
74
+ declare function trainingReward(record: Scored): {
75
+ reward: number | null;
76
+ gated: boolean;
77
+ };
78
+ //#endregion
79
+ //#region src/rollout/mint.d.ts
80
+ /** Redactor for transcript/step payload text (secrets, PII), not opaque identity. */
81
+ type RolloutScrubber = (text: string) => string;
82
+ /** A search cell's place in its search tree, read from the search ledger. */
83
+ interface RolloutSearchLineage {
84
+ /** Edges between the cell's node and the search root; the root is 0. */
85
+ depth: number;
86
+ /** Order in which the node registered in its search; the root is 0. */
87
+ ordinal: number;
88
+ /** Repeat index of the cell on its task, from 0. */
89
+ rep: number;
90
+ /** Run id of the cell whose execution contains this search; null for a
91
+ * top-level search. */
92
+ containingRunId: string | null;
93
+ }
94
+ interface MintRolloutOptions {
95
+ scrub?: RolloutScrubber;
96
+ /**
97
+ * Full canonical capture, including turns no longer in the model's context.
98
+ * When supplied, missing/empty capture is refused, never replaced with a
99
+ * span summary. Use the execution owner's capture or the existing harness
100
+ * readers; reviewer traces and compacted histories are not full capture.
101
+ */
102
+ messagesOf?: (runId: string) => readonly ChatMessage[] | undefined | Promise<readonly ChatMessage[] | undefined>;
103
+ /** Cap steps per line (longest runs first drop middle steps). Default: no cap. */
104
+ maxSteps?: number;
105
+ /** Role recorded on every minted line. Default 'agent' (a solo eval run). */
106
+ role?: RolloutRole;
107
+ /** Task suite label. Default: the record's `experimentId`. */
108
+ suite?: string;
109
+ /** Injected clock for deterministic output. */
110
+ now?: () => Date;
111
+ /**
112
+ * Lineage of a search run, read from its search ledger. It fills the line's
113
+ * `generation` (node depth), `candidate_index` (node order), `task.rep` and
114
+ * `parent_rollout_id` (the containing cell's run). Mint refuses a record
115
+ * that carries `search` when this is absent, because a null `generation`
116
+ * states that the run is not part of a search.
117
+ */
118
+ searchLineage?: (search: RunSearchCoordinates) => RolloutSearchLineage | Promise<RolloutSearchLineage>;
119
+ }
120
+ interface MintRolloutResult {
121
+ rows: MintedRolloutLine[];
122
+ /** runIds that had a RunRecord but no spans — emitted as gap lines AND listed here. */
123
+ missingTraces: string[];
124
+ }
125
+ /**
126
+ * Why a record cannot be minted, one entry per missing field, empty when it can.
127
+ *
128
+ * Exported so a caller can partition a whole ledger — "which of my 2742 records
129
+ * predate 0.126" — without catching an exception per record, and without
130
+ * re-deriving the field list on their side. A re-derived list is a list that
131
+ * drifts from the door it is supposed to predict.
132
+ *
133
+ * Takes a `RunRecord` because that is what the caller holds and what the
134
+ * compiler agrees they hold. The type is precisely the thing that is wrong, so
135
+ * the checks read the record as the untyped bag it actually is on disk.
136
+ */
137
+ declare function unmintableReasons(record: RunRecord): string[];
138
+ /**
139
+ * Join RunRecords with their traces into canonical rollout lines. Records
140
+ * without spans or an explicit capture are emitted as labeled gap lines and reported in
141
+ * `missingTraces`. Execution-only records without a task score are rejected
142
+ * because a missing training label is not a zero reward.
143
+ */
144
+ declare function mintRolloutRows(records: RunRecord[], store: TraceStore, options?: MintRolloutOptions): Promise<MintRolloutResult>;
145
+ //#endregion
146
+ export { mintRolloutRows as a, ScorePreference as c, observedSplitScore as d, scoreOrigin as f, RolloutSearchLineage as i, isRealnessGated as l, trainingScore as m, MintRolloutResult as n, unmintableReasons as o, trainingReward as p, RolloutScrubber as r, ScoreOrigin as s, MintRolloutOptions as t, observedScore as u };
147
+ //# sourceMappingURL=mint-C9Lojt1V.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mint-C9Lojt1V.d.ts","names":[],"sources":["../src/rollout/reward.ts","../src/rollout/mint.ts"],"mappings":";;;;;;;;;KA2BY;;KAGP,SAAS,KAAK;;iBAGH,gBAAgB,QAAQ;;;;;;;;;;;;;;iBAiBxB,mBAAmB,QAAQ,QAAQ,OAAO;;;;;;;;;;;;;;;;iBAmB1C,cACd,QAAQ,QACR,SAAQ;;KAOE;;;;;;;iBAQI,YAAY,QAAQ,QAAQ,SAAQ,kBAA8B;;;;;;;;;iBAelE,cACd,QAAQ,QACR,SAAQ;;;;;;;;;;;;iBAiBM,eAAe,QAAQ;EAAW;EAAuB;;;;;KCtE7D,mBAAmB;;UAGd;;EAEf;;EAEA;;EAEA;;;EAGA;;UAGe;EACf,QAAQ;;;;;;;EAOR,cACE,2BACY,4BAA4B,iBAAiB;;EAE3D;;EAEA,OAAO;;EAEP;;EAEA,YAAY;;;;;;;;EAQZ,iBACE,QAAQ,yBACL,uBAAuB,QAAQ;;UAGrB;EACf,MAAM;;EAEN;;;;;;;;;;;;;;iBA4Pc,kBAAkB,QAAQ;;;;;;;iBAiMpB,gBACpB,SAAS,aACT,OAAO,YACP,UAAS,qBACR,QAAQ"}
package/dist/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "@tangle-network/agent-eval — wire protocol",
5
- "version": "0.189.0",
5
+ "version": "0.190.1",
6
6
  "description": "HTTP and stdio RPC interface to agent-eval. The TypeScript runtime is the source of truth; this spec is the contract that cross-language clients (Python, Rust, Go) generate from.\n\nWire-protocol version: 1.1.0. Bumps on breaking changes to request/response schemas.",
7
7
  "contact": {
8
8
  "name": "Tangle Network",
@@ -1,7 +1,7 @@
1
1
  import { f as Run } from "../schema-2g7trUwH.js";
2
2
  import { a as RunFilter, s as TraceStore } from "../store-C4avFjIi.js";
3
3
  import { n as FailureClusterReport, r as failureClusterView, t as FailureCluster } from "../failure-cluster-CbgEDcFJ.js";
4
- import { t as DiagnosisSpan } from "../spans-W0o8pbEg.js";
4
+ import { t as DiagnosisSpan } from "../spans-BWtjk_9c.js";
5
5
  import { n as TrajectoryStep } from "../trajectory-Y1fmdlw7.js";
6
6
  import { c as computeToolUseMetrics, d as judgeAgreementView, f as BudgetBreachFinding, g as BaselineReport, h as BaselineOptions, i as toolWasteView, l as JudgeAgreementReport, m as budgetBreachView, n as ToolWasteOptions, p as BudgetBreachReport, r as ToolWasteReport, t as ToolWasteFinding, u as JudgePair } from "../tool-waste-CP5DO383.js";
7
7
  //#region src/pipelines/first-divergence.d.ts
@@ -167,7 +167,7 @@ function diffStepsFromSpans(spans) {
167
167
  if (list) list.push(span);
168
168
  else children.set(parent, [span]);
169
169
  }
170
- const byStart = (x, y) => (x.startMs ?? 0) - (y.startMs ?? 0) || x.spanId.localeCompare(y.spanId);
170
+ const byStart = (x, y) => (x.startMs ?? 0) - (y.startMs ?? 0) || (x.endMs ?? 0) - (y.endMs ?? 0) || x.kind.localeCompare(y.kind) || x.name.localeCompare(y.name) || x.spanId.localeCompare(y.spanId);
171
171
  for (const list of children.values()) list.sort(byStart);
172
172
  const ordered = [];
173
173
  const visited = /* @__PURE__ */ new Set();
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/pipelines/first-divergence.ts","../../src/pipelines/regression.ts","../../src/pipelines/stuck-loop.ts"],"sourcesContent":["/**\n * Step diff between two runs, with the first divergence marked.\n *\n * Steps pair in three passes, each over the steps still unpaired:\n * 1. `id`: the same step id in both runs, e.g. a forked run that kept its\n * parent's span ids.\n * 2. `position`: the same index with the same name and kind.\n * 3. `name`: the same name and kind anywhere, first unpaired step in order.\n * A step left unpaired exists in only one run. The first divergence is the\n * first index at which the two runs stop agreeing step for step, and it says\n * how: a paired step changed, one run replaced, added or removed a step, or the\n * runs ran the same steps in a different order.\n *\n * `diffSteps` reads plain `DiffStep` lists, so the same diff serves agent-eval\n * trace stores (`firstDivergenceView`) and flat OTLP spans\n * (`diffStepsFromSpans`). Use it to attribute \"why is variant B better?\" to a\n * step, and to compare sibling or parent and child runs of a search tree.\n */\n\nimport type { DiagnosisSpan } from '../diagnosis/spans'\nimport type { Span } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\nimport { buildTrajectory, type TrajectoryStep } from '../trajectory'\n\n/** One step of a run, as the diff reads it. */\nexport interface DiffStep {\n /** The step's id within its run. */\n id: string\n name: string\n kind: string\n /** Fields compared once two steps pair, such as status, tool or model. */\n fields: Readonly<Record<string, string | number | boolean | null>>\n}\n\nexport type StepPairing = 'id' | 'position' | 'name'\n\nexport interface FieldDifference {\n field: string\n a: string | number | boolean | null\n b: string | number | boolean | null\n}\n\nexport interface StepPair {\n /** Index in run A. */\n a: number\n /** Index in run B. */\n b: number\n pairedBy: StepPairing\n /** Empty when the paired steps agree on name, kind and every field. */\n differences: FieldDifference[]\n}\n\nexport type StepDivergenceKind = 'changed' | 'replaced' | 'only-in-a' | 'only-in-b' | 'reordered'\n\nexport interface StepDivergence {\n /** The first index at which the runs stop agreeing; equals `commonPrefixLen`. */\n index: number\n kind: StepDivergenceKind\n /** Index of the step at `index` in each run, or null when that run has ended. */\n a: number | null\n b: number | null\n /** Set when `kind` is `changed`. */\n differences: FieldDifference[]\n reason: string\n}\n\nexport interface StepDiff {\n /** Paired steps in run A order. */\n pairs: StepPair[]\n /** Indexes of run A steps with no partner in run B. */\n onlyInA: number[]\n /** Indexes of run B steps with no partner in run A. */\n onlyInB: number[]\n /** Leading steps paired index for index with no difference. */\n commonPrefixLen: number\n /** Null when the runs agree step for step. */\n firstDivergence: StepDivergence | null\n}\n\nexport function diffSteps(a: readonly DiffStep[], b: readonly DiffStep[]): StepDiff {\n const partnerOfA = new Map<number, { b: number; pairedBy: StepPairing }>()\n const pairedB = new Set<number>()\n const pair = (i: number, j: number, pairedBy: StepPairing) => {\n partnerOfA.set(i, { b: j, pairedBy })\n pairedB.add(j)\n }\n\n const bById = new Map<string, number[]>()\n b.forEach((step, j) => {\n const list = bById.get(step.id)\n if (list) list.push(j)\n else bById.set(step.id, [j])\n })\n a.forEach((step, i) => {\n const j = bById.get(step.id)?.find((candidate) => !pairedB.has(candidate))\n if (j !== undefined) pair(i, j, 'id')\n })\n a.forEach((step, i) => {\n if (partnerOfA.has(i) || i >= b.length || pairedB.has(i)) return\n if (sameShape(step, b[i]!)) pair(i, i, 'position')\n })\n a.forEach((step, i) => {\n if (partnerOfA.has(i)) return\n const j = b.findIndex((candidate, index) => !pairedB.has(index) && sameShape(step, candidate))\n if (j >= 0) pair(i, j, 'name')\n })\n\n const pairs: StepPair[] = [...partnerOfA.entries()]\n .sort(([x], [y]) => x - y)\n .map(([i, partner]) => ({\n a: i,\n b: partner.b,\n pairedBy: partner.pairedBy,\n differences: differencesBetween(a[i]!, b[partner.b]!),\n }))\n const pairByA = new Map(pairs.map((entry) => [entry.a, entry]))\n const partnerOfB = new Map(pairs.map((entry) => [entry.b, entry.a]))\n\n let prefix = 0\n while (prefix < a.length && prefix < b.length) {\n const entry = pairByA.get(prefix)\n if (!entry || entry.b !== prefix || entry.differences.length > 0) break\n prefix += 1\n }\n\n return {\n pairs,\n onlyInA: a.map((_, i) => i).filter((i) => !partnerOfA.has(i)),\n onlyInB: b.map((_, j) => j).filter((j) => !pairedB.has(j)),\n commonPrefixLen: prefix,\n firstDivergence:\n prefix === a.length && prefix === b.length\n ? null\n : divergenceAt(prefix, a, b, pairByA.get(prefix), partnerOfB),\n }\n}\n\nfunction divergenceAt(\n index: number,\n a: readonly DiffStep[],\n b: readonly DiffStep[],\n pairOfA: StepPair | undefined,\n partnerOfB: ReadonlyMap<number, number>,\n): StepDivergence {\n const stepA = a[index]\n const stepB = b[index]\n const base = {\n index,\n a: stepA ? index : null,\n b: stepB ? index : null,\n differences: [] as FieldDifference[],\n }\n if (stepA && stepB && pairOfA?.b === index) {\n return {\n ...base,\n kind: 'changed',\n differences: pairOfA.differences,\n reason: `at index ${index}, ${describe(stepA)} changed: ${pairOfA.differences\n .map((d) => `${d.field} ${String(d.a)} vs ${String(d.b)}`)\n .join('; ')}`,\n }\n }\n const aUnpaired = stepA !== undefined && pairOfA === undefined\n const bUnpaired = stepB !== undefined && !partnerOfB.has(index)\n if (stepA && stepB && aUnpaired && bUnpaired) {\n return {\n ...base,\n kind: 'replaced',\n reason: `at index ${index}, A ran ${describe(stepA)} and B ran ${describe(stepB)}`,\n }\n }\n if (stepA && aUnpaired) {\n return {\n ...base,\n kind: 'only-in-a',\n reason: `at index ${index}, only A has ${describe(stepA)}`,\n }\n }\n if (stepB && bUnpaired) {\n return {\n ...base,\n kind: 'only-in-b',\n reason: `at index ${index}, only B has ${describe(stepB)}`,\n }\n }\n return {\n ...base,\n kind: 'reordered',\n reason: `at index ${index}, A ran ${describe(stepA!)} and B ran ${describe(stepB!)}; both steps occur in the other run at a different position`,\n }\n}\n\nfunction sameShape(x: DiffStep, y: DiffStep): boolean {\n return x.name === y.name && x.kind === y.kind\n}\n\nfunction differencesBetween(x: DiffStep, y: DiffStep): FieldDifference[] {\n const differences: FieldDifference[] = []\n if (x.kind !== y.kind) differences.push({ field: 'kind', a: x.kind, b: y.kind })\n if (x.name !== y.name) differences.push({ field: 'name', a: x.name, b: y.name })\n const fields = [...new Set([...Object.keys(x.fields), ...Object.keys(y.fields)])].sort()\n for (const field of fields) {\n const left = x.fields[field] ?? null\n const right = y.fields[field] ?? null\n if (left !== right) differences.push({ field, a: left, b: right })\n }\n return differences\n}\n\nfunction describe(step: DiffStep): string {\n return `${step.kind} \"${step.name}\"`\n}\n\n// ── agent-eval trace store ────────────────────────────────────────────\n\nexport interface DivergenceReport {\n runA: string\n runB: string\n /** Null when the runs agree step for step. */\n firstDivergenceIndex: number | null\n aStep?: TrajectoryStep\n bStep?: TrajectoryStep\n reason?: string\n commonPrefixLen: number\n /** The step diff behind the first divergence, over trajectory step indexes. */\n diff: StepDiff\n}\n\nexport async function firstDivergenceView(\n store: TraceStore,\n runA: string,\n runB: string,\n): Promise<DivergenceReport> {\n const [a, b] = await Promise.all([buildTrajectory(store, runA), buildTrajectory(store, runB)])\n const diff = diffSteps(a.steps.map(trajectoryDiffStep), b.steps.map(trajectoryDiffStep))\n const divergence = diff.firstDivergence\n return {\n runA,\n runB,\n firstDivergenceIndex: divergence?.index ?? null,\n ...(divergence?.a != null ? { aStep: a.steps[divergence.a] } : {}),\n ...(divergence?.b != null ? { bStep: b.steps[divergence.b] } : {}),\n ...(divergence ? { reason: divergence.reason } : {}),\n commonPrefixLen: diff.commonPrefixLen,\n diff,\n }\n}\n\nfunction trajectoryDiffStep(step: TrajectoryStep): DiffStep {\n const span: Span = step.span\n const fields: Record<string, string | number | boolean | null> = {\n status: span.status ?? null,\n }\n if (span.kind === 'tool') fields.tool = span.toolName\n if (span.kind === 'llm') fields.model = span.model\n if (span.kind === 'judge') fields.dimension = span.dimension\n return { id: span.spanId, name: span.name, kind: span.kind, fields }\n}\n\n// ── flat OTLP spans ───────────────────────────────────────────────────\n\n/**\n * One run's spans as diff steps, in containment order: depth first, siblings\n * by start time, the same order `buildTrajectory` gives a trace store run.\n * Spans whose parent is absent, or whose parents form a cycle, start their own\n * subtree, so every span appears exactly once.\n */\nexport function diffStepsFromSpans(spans: readonly DiagnosisSpan[]): DiffStep[] {\n const ids = new Set(spans.map((span) => span.spanId))\n const children = new Map<string | null, DiagnosisSpan[]>()\n for (const span of spans) {\n const parent =\n span.parentSpanId !== null && ids.has(span.parentSpanId) ? span.parentSpanId : null\n const list = children.get(parent)\n if (list) list.push(span)\n else children.set(parent, [span])\n }\n const byStart = (x: DiagnosisSpan, y: DiagnosisSpan) =>\n (x.startMs ?? 0) - (y.startMs ?? 0) || x.spanId.localeCompare(y.spanId)\n for (const list of children.values()) list.sort(byStart)\n const ordered: DiffStep[] = []\n const visited = new Set<string>()\n const visit = (span: DiagnosisSpan) => {\n if (visited.has(span.spanId)) return\n visited.add(span.spanId)\n ordered.push({\n id: span.spanId,\n name: span.name,\n kind: span.kind,\n fields: { status: span.status, tool: span.toolName, model: span.model },\n })\n for (const child of children.get(span.spanId) ?? []) visit(child)\n }\n for (const root of children.get(null) ?? []) visit(root)\n for (const span of [...spans].sort(byStart)) visit(span)\n return ordered\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 { runMetricExtractor } 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. Omit it and `metric` must name one of\n * `RUN_METRICS`; any other name is refused. */\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 ?? runMetricExtractor(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","/**\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 { executionTrackByLane } from '../trace/execution-tracks'\nimport { argHash, hasCapturedToolArgs } from '../trace/query'\nimport { isToolSpan, type Span, type ToolSpan } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nconst DEFAULT_MAX_WINDOW_MS = 60_000\nconst DEFAULT_MAX_INTERVENING_TOOL_CALLS = 0\n\ninterface ScopedToolCall {\n span: ToolSpan\n scopeSpanId: string | null\n laneSpanId: string | null\n}\n\ninterface IndexedToolCall extends ScopedToolCall {\n toolCallIndex: number\n trackId: string\n}\n\nexport interface StuckLoopFinding {\n runId: string\n toolName: string\n argHash: string\n /** Calls in this episode's densest qualifying interval, not the whole-run total. */\n occurrences: number\n spanIds: string[]\n /** Nearest agent ancestor, or the direct parent when ancestry is incomplete. */\n scopeSpanId?: 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 /** Maximum time between the first and last repeated call (default 60 seconds). */\n maxWindowMs?: number\n /**\n * Maximum other tool calls allowed between adjacent repeats (default 0).\n * Set to 1 to detect alternating patterns such as A,B,A,B,A.\n */\n maxInterveningToolCalls?: 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 maxWindowMs = options.maxWindowMs ?? DEFAULT_MAX_WINDOW_MS\n const maxInterveningToolCalls =\n options.maxInterveningToolCalls ?? DEFAULT_MAX_INTERVENING_TOOL_CALLS\n if (!Number.isInteger(minOccurrences) || minOccurrences < 1) {\n throw new RangeError('minOccurrences must be a positive integer')\n }\n if (!Number.isFinite(maxWindowMs) || maxWindowMs < 0) {\n throw new RangeError('maxWindowMs must be a finite non-negative number')\n }\n if (!Number.isInteger(maxInterveningToolCalls) || maxInterveningToolCalls < 0) {\n throw new RangeError('maxInterveningToolCalls must be a non-negative integer')\n }\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 spans = await store.spans({ runId })\n const spansById = new Map(spans.map((span) => [span.spanId, span]))\n const scopedTools: ScopedToolCall[] = spans\n .filter(isToolSpan)\n .map((span, sourceIndex) => ({ span, sourceIndex }))\n .sort((a, b) => a.span.startedAt - b.span.startedAt || a.sourceIndex - b.sourceIndex)\n .map(({ span }) => ({ span, ...executionScope(span, spansById) }))\n const trackByLane = executionTrackByLane(\n scopedTools.map((call) => {\n const direct = call.laneSpanId === null || call.laneSpanId === call.scopeSpanId\n const timed = direct\n ? call.span\n : call.laneSpanId\n ? spansById.get(call.laneSpanId)\n : undefined\n return {\n key: executionKey(call),\n scopeKey: JSON.stringify(call.scopeSpanId),\n start: timed?.startedAt ?? null,\n end: timed?.endedAt ?? null,\n }\n }),\n )\n const nextToolIndexByTrack = new Map<string, number>()\n const orderedTools: IndexedToolCall[] = scopedTools.map((call) => {\n const trackId = trackByLane.get(executionKey(call))!\n const toolCallIndex = nextToolIndexByTrack.get(trackId) ?? 0\n nextToolIndexByTrack.set(trackId, toolCallIndex + 1)\n return { ...call, toolCallIndex, trackId }\n })\n const byKey = new Map<\n string,\n {\n calls: IndexedToolCall[]\n argHash: string\n toolName: string\n scopeSpanId: string | null\n }\n >()\n for (const call of orderedTools) {\n if (!hasCapturedToolArgs(call.span)) continue\n const h = argHash(call.span.args)\n const key = JSON.stringify([call.trackId, call.span.toolName, h])\n const bucket = byKey.get(key) ?? {\n calls: [],\n argHash: h,\n toolName: call.span.toolName,\n scopeSpanId: call.scopeSpanId,\n }\n bucket.calls.push(call)\n byKey.set(key, bucket)\n }\n for (const { calls, argHash: h, toolName, scopeSpanId } of byKey.values()) {\n if (calls.length < minOccurrences) continue\n let episodeStart = 0\n for (let episodeEnd = 1; episodeEnd <= calls.length; episodeEnd += 1) {\n const previous = calls[episodeEnd - 1]!\n const next = calls[episodeEnd]\n const episodeEnded =\n next === undefined ||\n next.span.startedAt - previous.span.startedAt > maxWindowMs ||\n next.toolCallIndex - previous.toolCallIndex - 1 > maxInterveningToolCalls ||\n !callsAreSerial(previous, next)\n if (!episodeEnded) continue\n\n const episode = calls.slice(episodeStart, episodeEnd)\n let left = 0\n let bestStart = 0\n let bestEnd = -1\n for (let right = 0; right < episode.length; right += 1) {\n while (episode[right]!.span.startedAt - episode[left]!.span.startedAt > maxWindowMs) {\n left += 1\n }\n if (right - left > bestEnd - bestStart) {\n bestStart = left\n bestEnd = right\n }\n }\n if (bestEnd - bestStart + 1 >= minOccurrences) {\n const loop = episode.slice(bestStart, bestEnd + 1)\n const first = loop[0]!.span.startedAt\n const last = loop[loop.length - 1]!.span.startedAt\n findings.push({\n runId,\n toolName,\n argHash: h,\n occurrences: loop.length,\n spanIds: loop.map((call) => call.span.spanId),\n ...(scopeSpanId ? { scopeSpanId } : {}),\n windowMs: last - first,\n })\n }\n episodeStart = episodeEnd\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\nfunction laneKey(call: Pick<ScopedToolCall, 'scopeSpanId' | 'laneSpanId'>): string {\n return JSON.stringify([call.scopeSpanId, call.laneSpanId])\n}\n\nfunction executionKey(call: ScopedToolCall): string {\n return call.laneSpanId === null || call.laneSpanId === call.scopeSpanId\n ? JSON.stringify([call.scopeSpanId, call.span.spanId])\n : laneKey(call)\n}\n\nfunction executionScope(\n span: ToolSpan,\n spansById: ReadonlyMap<string, Span>,\n): { scopeSpanId: string | null; laneSpanId: string | null } {\n const directParent = span.parentSpanId\n if (!directParent) return { scopeSpanId: null, laneSpanId: null }\n\n let currentId: string | undefined = directParent\n let laneSpanId: string | null = null\n const seen = new Set<string>()\n while (currentId && !seen.has(currentId)) {\n seen.add(currentId)\n const current = spansById.get(currentId)\n if (!current) return { scopeSpanId: directParent, laneSpanId: directParent }\n if (current.kind === 'agent') {\n return { scopeSpanId: current.spanId, laneSpanId: laneSpanId ?? current.spanId }\n }\n laneSpanId = current.spanId\n currentId = current.parentSpanId\n }\n return { scopeSpanId: directParent, laneSpanId: directParent }\n}\n\nfunction callsAreSerial(previous: IndexedToolCall, next: IndexedToolCall): boolean {\n return previous.span.endedAt !== undefined && previous.span.endedAt <= next.span.startedAt\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/pipelines/first-divergence.ts","../../src/pipelines/regression.ts","../../src/pipelines/stuck-loop.ts"],"sourcesContent":["/**\n * Step diff between two runs, with the first divergence marked.\n *\n * Steps pair in three passes, each over the steps still unpaired:\n * 1. `id`: the same step id in both runs, e.g. a forked run that kept its\n * parent's span ids.\n * 2. `position`: the same index with the same name and kind.\n * 3. `name`: the same name and kind anywhere, first unpaired step in order.\n * A step left unpaired exists in only one run. The first divergence is the\n * first index at which the two runs stop agreeing step for step, and it says\n * how: a paired step changed, one run replaced, added or removed a step, or the\n * runs ran the same steps in a different order.\n *\n * `diffSteps` reads plain `DiffStep` lists, so the same diff serves agent-eval\n * trace stores (`firstDivergenceView`) and flat OTLP spans\n * (`diffStepsFromSpans`). Use it to attribute \"why is variant B better?\" to a\n * step, and to compare sibling or parent and child runs of a search tree.\n */\n\nimport type { DiagnosisSpan } from '../diagnosis/spans'\nimport type { Span } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\nimport { buildTrajectory, type TrajectoryStep } from '../trajectory'\n\n/** One step of a run, as the diff reads it. */\nexport interface DiffStep {\n /** The step's id within its run. */\n id: string\n name: string\n kind: string\n /** Fields compared once two steps pair, such as status, tool or model. */\n fields: Readonly<Record<string, string | number | boolean | null>>\n}\n\nexport type StepPairing = 'id' | 'position' | 'name'\n\nexport interface FieldDifference {\n field: string\n a: string | number | boolean | null\n b: string | number | boolean | null\n}\n\nexport interface StepPair {\n /** Index in run A. */\n a: number\n /** Index in run B. */\n b: number\n pairedBy: StepPairing\n /** Empty when the paired steps agree on name, kind and every field. */\n differences: FieldDifference[]\n}\n\nexport type StepDivergenceKind = 'changed' | 'replaced' | 'only-in-a' | 'only-in-b' | 'reordered'\n\nexport interface StepDivergence {\n /** The first index at which the runs stop agreeing; equals `commonPrefixLen`. */\n index: number\n kind: StepDivergenceKind\n /** Index of the step at `index` in each run, or null when that run has ended. */\n a: number | null\n b: number | null\n /** Set when `kind` is `changed`. */\n differences: FieldDifference[]\n reason: string\n}\n\nexport interface StepDiff {\n /** Paired steps in run A order. */\n pairs: StepPair[]\n /** Indexes of run A steps with no partner in run B. */\n onlyInA: number[]\n /** Indexes of run B steps with no partner in run A. */\n onlyInB: number[]\n /** Leading steps paired index for index with no difference. */\n commonPrefixLen: number\n /** Null when the runs agree step for step. */\n firstDivergence: StepDivergence | null\n}\n\nexport function diffSteps(a: readonly DiffStep[], b: readonly DiffStep[]): StepDiff {\n const partnerOfA = new Map<number, { b: number; pairedBy: StepPairing }>()\n const pairedB = new Set<number>()\n const pair = (i: number, j: number, pairedBy: StepPairing) => {\n partnerOfA.set(i, { b: j, pairedBy })\n pairedB.add(j)\n }\n\n const bById = new Map<string, number[]>()\n b.forEach((step, j) => {\n const list = bById.get(step.id)\n if (list) list.push(j)\n else bById.set(step.id, [j])\n })\n a.forEach((step, i) => {\n const j = bById.get(step.id)?.find((candidate) => !pairedB.has(candidate))\n if (j !== undefined) pair(i, j, 'id')\n })\n a.forEach((step, i) => {\n if (partnerOfA.has(i) || i >= b.length || pairedB.has(i)) return\n if (sameShape(step, b[i]!)) pair(i, i, 'position')\n })\n a.forEach((step, i) => {\n if (partnerOfA.has(i)) return\n const j = b.findIndex((candidate, index) => !pairedB.has(index) && sameShape(step, candidate))\n if (j >= 0) pair(i, j, 'name')\n })\n\n const pairs: StepPair[] = [...partnerOfA.entries()]\n .sort(([x], [y]) => x - y)\n .map(([i, partner]) => ({\n a: i,\n b: partner.b,\n pairedBy: partner.pairedBy,\n differences: differencesBetween(a[i]!, b[partner.b]!),\n }))\n const pairByA = new Map(pairs.map((entry) => [entry.a, entry]))\n const partnerOfB = new Map(pairs.map((entry) => [entry.b, entry.a]))\n\n let prefix = 0\n while (prefix < a.length && prefix < b.length) {\n const entry = pairByA.get(prefix)\n if (!entry || entry.b !== prefix || entry.differences.length > 0) break\n prefix += 1\n }\n\n return {\n pairs,\n onlyInA: a.map((_, i) => i).filter((i) => !partnerOfA.has(i)),\n onlyInB: b.map((_, j) => j).filter((j) => !pairedB.has(j)),\n commonPrefixLen: prefix,\n firstDivergence:\n prefix === a.length && prefix === b.length\n ? null\n : divergenceAt(prefix, a, b, pairByA.get(prefix), partnerOfB),\n }\n}\n\nfunction divergenceAt(\n index: number,\n a: readonly DiffStep[],\n b: readonly DiffStep[],\n pairOfA: StepPair | undefined,\n partnerOfB: ReadonlyMap<number, number>,\n): StepDivergence {\n const stepA = a[index]\n const stepB = b[index]\n const base = {\n index,\n a: stepA ? index : null,\n b: stepB ? index : null,\n differences: [] as FieldDifference[],\n }\n if (stepA && stepB && pairOfA?.b === index) {\n return {\n ...base,\n kind: 'changed',\n differences: pairOfA.differences,\n reason: `at index ${index}, ${describe(stepA)} changed: ${pairOfA.differences\n .map((d) => `${d.field} ${String(d.a)} vs ${String(d.b)}`)\n .join('; ')}`,\n }\n }\n const aUnpaired = stepA !== undefined && pairOfA === undefined\n const bUnpaired = stepB !== undefined && !partnerOfB.has(index)\n if (stepA && stepB && aUnpaired && bUnpaired) {\n return {\n ...base,\n kind: 'replaced',\n reason: `at index ${index}, A ran ${describe(stepA)} and B ran ${describe(stepB)}`,\n }\n }\n if (stepA && aUnpaired) {\n return {\n ...base,\n kind: 'only-in-a',\n reason: `at index ${index}, only A has ${describe(stepA)}`,\n }\n }\n if (stepB && bUnpaired) {\n return {\n ...base,\n kind: 'only-in-b',\n reason: `at index ${index}, only B has ${describe(stepB)}`,\n }\n }\n return {\n ...base,\n kind: 'reordered',\n reason: `at index ${index}, A ran ${describe(stepA!)} and B ran ${describe(stepB!)}; both steps occur in the other run at a different position`,\n }\n}\n\nfunction sameShape(x: DiffStep, y: DiffStep): boolean {\n return x.name === y.name && x.kind === y.kind\n}\n\nfunction differencesBetween(x: DiffStep, y: DiffStep): FieldDifference[] {\n const differences: FieldDifference[] = []\n if (x.kind !== y.kind) differences.push({ field: 'kind', a: x.kind, b: y.kind })\n if (x.name !== y.name) differences.push({ field: 'name', a: x.name, b: y.name })\n const fields = [...new Set([...Object.keys(x.fields), ...Object.keys(y.fields)])].sort()\n for (const field of fields) {\n const left = x.fields[field] ?? null\n const right = y.fields[field] ?? null\n if (left !== right) differences.push({ field, a: left, b: right })\n }\n return differences\n}\n\nfunction describe(step: DiffStep): string {\n return `${step.kind} \"${step.name}\"`\n}\n\n// ── agent-eval trace store ────────────────────────────────────────────\n\nexport interface DivergenceReport {\n runA: string\n runB: string\n /** Null when the runs agree step for step. */\n firstDivergenceIndex: number | null\n aStep?: TrajectoryStep\n bStep?: TrajectoryStep\n reason?: string\n commonPrefixLen: number\n /** The step diff behind the first divergence, over trajectory step indexes. */\n diff: StepDiff\n}\n\nexport async function firstDivergenceView(\n store: TraceStore,\n runA: string,\n runB: string,\n): Promise<DivergenceReport> {\n const [a, b] = await Promise.all([buildTrajectory(store, runA), buildTrajectory(store, runB)])\n const diff = diffSteps(a.steps.map(trajectoryDiffStep), b.steps.map(trajectoryDiffStep))\n const divergence = diff.firstDivergence\n return {\n runA,\n runB,\n firstDivergenceIndex: divergence?.index ?? null,\n ...(divergence?.a != null ? { aStep: a.steps[divergence.a] } : {}),\n ...(divergence?.b != null ? { bStep: b.steps[divergence.b] } : {}),\n ...(divergence ? { reason: divergence.reason } : {}),\n commonPrefixLen: diff.commonPrefixLen,\n diff,\n }\n}\n\nfunction trajectoryDiffStep(step: TrajectoryStep): DiffStep {\n const span: Span = step.span\n const fields: Record<string, string | number | boolean | null> = {\n status: span.status ?? null,\n }\n if (span.kind === 'tool') fields.tool = span.toolName\n if (span.kind === 'llm') fields.model = span.model\n if (span.kind === 'judge') fields.dimension = span.dimension\n return { id: span.spanId, name: span.name, kind: span.kind, fields }\n}\n\n// ── flat OTLP spans ───────────────────────────────────────────────────\n\n/**\n * One run's spans as diff steps, in containment order: depth first, siblings\n * by start time, the same order `buildTrajectory` gives a trace store run.\n * Spans whose parent is absent, or whose parents form a cycle, start their own\n * subtree, so every span appears exactly once.\n */\nexport function diffStepsFromSpans(spans: readonly DiagnosisSpan[]): DiffStep[] {\n const ids = new Set(spans.map((span) => span.spanId))\n const children = new Map<string | null, DiagnosisSpan[]>()\n for (const span of spans) {\n const parent =\n span.parentSpanId !== null && ids.has(span.parentSpanId) ? span.parentSpanId : null\n const list = children.get(parent)\n if (list) list.push(span)\n else children.set(parent, [span])\n }\n // Span ids are random per run, so two runs of the same logical trace can carry\n // different ids for \"the same\" span. Siblings that share a start time (a common\n // case: parallel steps a driver starts together) must still sort the same way\n // in both runs, or the diff below reports a false `reordered` divergence purely\n // from spanId noise. End time, kind and name are content, not per-run identity,\n // so they break the tie before spanId, which is the last resort.\n const byStart = (x: DiagnosisSpan, y: DiagnosisSpan) =>\n (x.startMs ?? 0) - (y.startMs ?? 0) ||\n (x.endMs ?? 0) - (y.endMs ?? 0) ||\n x.kind.localeCompare(y.kind) ||\n x.name.localeCompare(y.name) ||\n x.spanId.localeCompare(y.spanId)\n for (const list of children.values()) list.sort(byStart)\n const ordered: DiffStep[] = []\n const visited = new Set<string>()\n const visit = (span: DiagnosisSpan) => {\n if (visited.has(span.spanId)) return\n visited.add(span.spanId)\n ordered.push({\n id: span.spanId,\n name: span.name,\n kind: span.kind,\n fields: { status: span.status, tool: span.toolName, model: span.model },\n })\n for (const child of children.get(span.spanId) ?? []) visit(child)\n }\n for (const root of children.get(null) ?? []) visit(root)\n for (const span of [...spans].sort(byStart)) visit(span)\n return ordered\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 { runMetricExtractor } 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. Omit it and `metric` must name one of\n * `RUN_METRICS`; any other name is refused. */\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 ?? runMetricExtractor(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","/**\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 { executionTrackByLane } from '../trace/execution-tracks'\nimport { argHash, hasCapturedToolArgs } from '../trace/query'\nimport { isToolSpan, type Span, type ToolSpan } from '../trace/schema'\nimport type { TraceStore } from '../trace/store'\n\nconst DEFAULT_MAX_WINDOW_MS = 60_000\nconst DEFAULT_MAX_INTERVENING_TOOL_CALLS = 0\n\ninterface ScopedToolCall {\n span: ToolSpan\n scopeSpanId: string | null\n laneSpanId: string | null\n}\n\ninterface IndexedToolCall extends ScopedToolCall {\n toolCallIndex: number\n trackId: string\n}\n\nexport interface StuckLoopFinding {\n runId: string\n toolName: string\n argHash: string\n /** Calls in this episode's densest qualifying interval, not the whole-run total. */\n occurrences: number\n spanIds: string[]\n /** Nearest agent ancestor, or the direct parent when ancestry is incomplete. */\n scopeSpanId?: 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 /** Maximum time between the first and last repeated call (default 60 seconds). */\n maxWindowMs?: number\n /**\n * Maximum other tool calls allowed between adjacent repeats (default 0).\n * Set to 1 to detect alternating patterns such as A,B,A,B,A.\n */\n maxInterveningToolCalls?: 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 maxWindowMs = options.maxWindowMs ?? DEFAULT_MAX_WINDOW_MS\n const maxInterveningToolCalls =\n options.maxInterveningToolCalls ?? DEFAULT_MAX_INTERVENING_TOOL_CALLS\n if (!Number.isInteger(minOccurrences) || minOccurrences < 1) {\n throw new RangeError('minOccurrences must be a positive integer')\n }\n if (!Number.isFinite(maxWindowMs) || maxWindowMs < 0) {\n throw new RangeError('maxWindowMs must be a finite non-negative number')\n }\n if (!Number.isInteger(maxInterveningToolCalls) || maxInterveningToolCalls < 0) {\n throw new RangeError('maxInterveningToolCalls must be a non-negative integer')\n }\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 spans = await store.spans({ runId })\n const spansById = new Map(spans.map((span) => [span.spanId, span]))\n const scopedTools: ScopedToolCall[] = spans\n .filter(isToolSpan)\n .map((span, sourceIndex) => ({ span, sourceIndex }))\n .sort((a, b) => a.span.startedAt - b.span.startedAt || a.sourceIndex - b.sourceIndex)\n .map(({ span }) => ({ span, ...executionScope(span, spansById) }))\n const trackByLane = executionTrackByLane(\n scopedTools.map((call) => {\n const direct = call.laneSpanId === null || call.laneSpanId === call.scopeSpanId\n const timed = direct\n ? call.span\n : call.laneSpanId\n ? spansById.get(call.laneSpanId)\n : undefined\n return {\n key: executionKey(call),\n scopeKey: JSON.stringify(call.scopeSpanId),\n start: timed?.startedAt ?? null,\n end: timed?.endedAt ?? null,\n }\n }),\n )\n const nextToolIndexByTrack = new Map<string, number>()\n const orderedTools: IndexedToolCall[] = scopedTools.map((call) => {\n const trackId = trackByLane.get(executionKey(call))!\n const toolCallIndex = nextToolIndexByTrack.get(trackId) ?? 0\n nextToolIndexByTrack.set(trackId, toolCallIndex + 1)\n return { ...call, toolCallIndex, trackId }\n })\n const byKey = new Map<\n string,\n {\n calls: IndexedToolCall[]\n argHash: string\n toolName: string\n scopeSpanId: string | null\n }\n >()\n for (const call of orderedTools) {\n if (!hasCapturedToolArgs(call.span)) continue\n const h = argHash(call.span.args)\n const key = JSON.stringify([call.trackId, call.span.toolName, h])\n const bucket = byKey.get(key) ?? {\n calls: [],\n argHash: h,\n toolName: call.span.toolName,\n scopeSpanId: call.scopeSpanId,\n }\n bucket.calls.push(call)\n byKey.set(key, bucket)\n }\n for (const { calls, argHash: h, toolName, scopeSpanId } of byKey.values()) {\n if (calls.length < minOccurrences) continue\n let episodeStart = 0\n for (let episodeEnd = 1; episodeEnd <= calls.length; episodeEnd += 1) {\n const previous = calls[episodeEnd - 1]!\n const next = calls[episodeEnd]\n const episodeEnded =\n next === undefined ||\n next.span.startedAt - previous.span.startedAt > maxWindowMs ||\n next.toolCallIndex - previous.toolCallIndex - 1 > maxInterveningToolCalls ||\n !callsAreSerial(previous, next)\n if (!episodeEnded) continue\n\n const episode = calls.slice(episodeStart, episodeEnd)\n let left = 0\n let bestStart = 0\n let bestEnd = -1\n for (let right = 0; right < episode.length; right += 1) {\n while (episode[right]!.span.startedAt - episode[left]!.span.startedAt > maxWindowMs) {\n left += 1\n }\n if (right - left > bestEnd - bestStart) {\n bestStart = left\n bestEnd = right\n }\n }\n if (bestEnd - bestStart + 1 >= minOccurrences) {\n const loop = episode.slice(bestStart, bestEnd + 1)\n const first = loop[0]!.span.startedAt\n const last = loop[loop.length - 1]!.span.startedAt\n findings.push({\n runId,\n toolName,\n argHash: h,\n occurrences: loop.length,\n spanIds: loop.map((call) => call.span.spanId),\n ...(scopeSpanId ? { scopeSpanId } : {}),\n windowMs: last - first,\n })\n }\n episodeStart = episodeEnd\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\nfunction laneKey(call: Pick<ScopedToolCall, 'scopeSpanId' | 'laneSpanId'>): string {\n return JSON.stringify([call.scopeSpanId, call.laneSpanId])\n}\n\nfunction executionKey(call: ScopedToolCall): string {\n return call.laneSpanId === null || call.laneSpanId === call.scopeSpanId\n ? JSON.stringify([call.scopeSpanId, call.span.spanId])\n : laneKey(call)\n}\n\nfunction executionScope(\n span: ToolSpan,\n spansById: ReadonlyMap<string, Span>,\n): { scopeSpanId: string | null; laneSpanId: string | null } {\n const directParent = span.parentSpanId\n if (!directParent) return { scopeSpanId: null, laneSpanId: null }\n\n let currentId: string | undefined = directParent\n let laneSpanId: string | null = null\n const seen = new Set<string>()\n while (currentId && !seen.has(currentId)) {\n seen.add(currentId)\n const current = spansById.get(currentId)\n if (!current) return { scopeSpanId: directParent, laneSpanId: directParent }\n if (current.kind === 'agent') {\n return { scopeSpanId: current.spanId, laneSpanId: laneSpanId ?? current.spanId }\n }\n laneSpanId = current.spanId\n currentId = current.parentSpanId\n }\n return { scopeSpanId: directParent, laneSpanId: directParent }\n}\n\nfunction callsAreSerial(previous: IndexedToolCall, next: IndexedToolCall): boolean {\n return previous.span.endedAt !== undefined && previous.span.endedAt <= next.span.startedAt\n}\n"],"mappings":"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"}
@@ -1,10 +1,10 @@
1
1
  import { s as ValidationError } from "./errors-Dngq5h35.js";
2
2
  import { r as canonicalString } from "./canonical-BsZVgBhW.js";
3
- import { n as JudgeParseError } from "./llm-judge-M_l_WXw2.js";
3
+ import { n as JudgeParseError } from "./llm-judge-BnxAv7ed.js";
4
4
  import { i as CostLedger } from "./cost-ledger-_IbkejCF.js";
5
- import { O as recoverTruncatedJson } from "./campaign-evidence-CBlGJ3kC.js";
5
+ import { O as recoverTruncatedJson } from "./campaign-evidence-D40-LHIL.js";
6
6
  import { t as certificationEvidenceDigest } from "./verdict-DhPoXApk.js";
7
- import { f as ModelSubstitutionError, h as assertServedModel, o as costReceiptFromLlm, s as costReceiptFromLlmError, u as maximumChargeForLlmRequest } from "./llm-client-DF9bPNYA.js";
7
+ import { f as ModelSubstitutionError, h as assertServedModel, o as costReceiptFromLlm, s as costReceiptFromLlmError, u as maximumChargeForLlmRequest } from "./llm-client-KYQBh9C8.js";
8
8
  import { createHash, randomUUID } from "node:crypto";
9
9
  import { harnessSupportsModel } from "@tangle-network/agent-interface";
10
10
  //#region src/agent-profile.ts
@@ -588,4 +588,4 @@ function extractProducedState(events) {
588
588
  //#endregion
589
589
  export { CODING_HARNESSES as a, agentProfileId as c, harnessAxisOf as d, verifyCompletion as i, agentProfileModelId as l, completionVerdict as n, HARNESS_NATIVE_MODEL as o, createLlmCorrectnessChecker as r, agentProfileHash as s, extractProducedState as t, expandProfileAxes as u };
590
590
 
591
- //# sourceMappingURL=produced-state-BOY98IJO.js.map
591
+ //# sourceMappingURL=produced-state-BXjXJHJT.js.map