@tangle-network/agent-eval 0.109.1 → 0.110.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/dist/analyst/index.d.ts +10 -12
  2. package/dist/analyst/index.js +8 -11
  3. package/dist/analyst/index.js.map +1 -1
  4. package/dist/{analyze-runs-DJYpep3L.d.ts → analyze-runs-Dmz6LA9e.d.ts} +4 -4
  5. package/dist/{baseline-Bbid3WoO.d.ts → baseline-DsNteOgR.d.ts} +32 -2
  6. package/dist/belief-state/index.d.ts +6 -6
  7. package/dist/benchmarks/index.d.ts +4 -4
  8. package/dist/benchmarks/index.js +7 -8
  9. package/dist/builder-eval/index.d.ts +4 -4
  10. package/dist/builder-eval/index.js +1 -2
  11. package/dist/builder-eval/index.js.map +1 -1
  12. package/dist/{calibration-BPmzuVPk.d.ts → calibration-Dz8TQV4y.d.ts} +2 -2
  13. package/dist/campaign/index.d.ts +16 -19
  14. package/dist/campaign/index.js +7 -8
  15. package/dist/{chunk-LOJ2QVCE.js → chunk-2IY4ILP4.js} +2 -2
  16. package/dist/{chunk-LIEJUH2I.js → chunk-6PL5MGDL.js} +9 -9
  17. package/dist/{chunk-2OGPXHOB.js → chunk-7NX6ZSBG.js} +36 -7
  18. package/dist/chunk-7NX6ZSBG.js.map +1 -0
  19. package/dist/{chunk-OVPVM4JC.js → chunk-GTERJI6Q.js} +4 -4
  20. package/dist/{chunk-YEHAEDUD.js → chunk-IMWDSFUM.js} +604 -2
  21. package/dist/chunk-IMWDSFUM.js.map +1 -0
  22. package/dist/{chunk-JZXGWLK5.js → chunk-MHNQWM4I.js} +62 -6
  23. package/dist/chunk-MHNQWM4I.js.map +1 -0
  24. package/dist/{chunk-QRVS7MX4.js → chunk-OW47B5WA.js} +3 -5
  25. package/dist/{chunk-QRVS7MX4.js.map → chunk-OW47B5WA.js.map} +1 -1
  26. package/dist/{chunk-DBDRR6GF.js → chunk-PLOMR3HP.js} +48 -2
  27. package/dist/chunk-PLOMR3HP.js.map +1 -0
  28. package/dist/{chunk-GDZAWO2I.js → chunk-QFGTU7MT.js} +2 -2
  29. package/dist/{chunk-R6D7NEYJ.js → chunk-RNB2NICW.js} +11 -11
  30. package/dist/{chunk-V7HNA47Z.js → chunk-RSVSSZKF.js} +5 -5
  31. package/dist/{chunk-5PK3626Q.js → chunk-XRGOKCMO.js} +88 -17
  32. package/dist/chunk-XRGOKCMO.js.map +1 -0
  33. package/dist/{code-agent-session-rnJKlqmT.d.ts → code-agent-session-yitf9I-F.d.ts} +1 -1
  34. package/dist/contract/index.d.ts +20 -23
  35. package/dist/contract/index.js +11 -13
  36. package/dist/contract/index.js.map +1 -1
  37. package/dist/{control-B8UthSBL.d.ts → control-U8LBKUES.d.ts} +5 -6
  38. package/dist/control.d.ts +8 -9
  39. package/dist/control.js +6 -8
  40. package/dist/{dataset-DS7ytHZU.d.ts → dataset-NENEzRgk.d.ts} +1 -1
  41. package/dist/{default-registry-BswHCXnU.d.ts → default-registry-Bcf1uKVI.d.ts} +1 -2
  42. package/dist/{emitter-C2rqGH_l.d.ts → emitter-BRchAAAx.d.ts} +2 -2
  43. package/dist/{failure-cluster-DH9Flgcf.d.ts → failure-cluster-C48PiReX.d.ts} +2 -2
  44. package/dist/feedback-trajectory-pDcz1lQ1.d.ts +348 -0
  45. package/dist/{gepa-B3x5Ulcv.d.ts → gepa-BUNP3606.d.ts} +143 -2
  46. package/dist/hosted/index.d.ts +7 -7
  47. package/dist/{index-pPtfoIJO.d.ts → index-Dc3VLGhp.d.ts} +2 -2
  48. package/dist/index.d.ts +645 -61
  49. package/dist/index.js +1282 -190
  50. package/dist/index.js.map +1 -1
  51. package/dist/{insight-report-B4xrdwEK.d.ts → insight-report-D4cXFsLt.d.ts} +1 -1
  52. package/dist/{integrity-DqGZg3st.d.ts → integrity-qemeBAyx.d.ts} +1 -1
  53. package/dist/{types-D1ytG0Yg.d.ts → kind-factory-20hcaYpf.d.ts} +169 -2
  54. package/dist/meta-eval/index.d.ts +5 -5
  55. package/dist/meta-eval/index.js +1 -2
  56. package/dist/meta-eval/index.js.map +1 -1
  57. package/dist/{multi-layer-verifier-CI4jdX-q.d.ts → multi-layer-verifier-BsqKuLyN.d.ts} +1 -1
  58. package/dist/multishot/index.d.ts +3 -3
  59. package/dist/openapi.json +1 -1
  60. package/dist/pipelines/index.d.ts +6 -7
  61. package/dist/pipelines/index.js +3 -6
  62. package/dist/pipelines/index.js.map +1 -1
  63. package/dist/{policy-edit-DQUXYMDm.d.ts → policy-edit-D2bBDZDf.d.ts} +2 -2
  64. package/dist/{pre-registration-BUhVPzE7.d.ts → pre-registration-BepVVa6P.d.ts} +3 -3
  65. package/dist/{provenance-DdDhf6cg.d.ts → provenance-DMvsfknv.d.ts} +3 -5
  66. package/dist/{query-0aTmbmQe.d.ts → query-Ck190MOd.d.ts} +2 -2
  67. package/dist/{release-report-DeJpsBiA.d.ts → release-report-oBfOz8ku.d.ts} +3 -3
  68. package/dist/reporting.d.ts +8 -8
  69. package/dist/{researcher-Wc7dx6GM.d.ts → researcher-CaH0CwFC.d.ts} +6 -6
  70. package/dist/rl.d.ts +568 -15
  71. package/dist/rl.js +4 -4
  72. package/dist/{rubric-predictive-validity-DPnyG-CE.d.ts → rubric-predictive-validity-C-fMteAW.d.ts} +1 -1
  73. package/dist/{run-record-I-Z3JNvO.d.ts → run-record-DksGsfgv.d.ts} +1 -1
  74. package/dist/{runtime-trajectory-iW9IhV3e.d.ts → runtime-trajectory-h5i0SZUj.d.ts} +1 -1
  75. package/dist/{schema-m0gsnbt3.d.ts → schema-SGWcK9wa.d.ts} +1 -1
  76. package/dist/{semantic-concept-judge-BmNZPB_j.d.ts → semantic-concept-judge-D7z6JCLZ.d.ts} +57 -4
  77. package/dist/{store-BcFXE6LG.d.ts → store-BsVi7ncX.d.ts} +1 -1
  78. package/dist/storyboard/index.d.ts +1 -1
  79. package/dist/{summary-report-QMZVe3P-.d.ts → summary-report-Bz-0-t8v.d.ts} +2 -2
  80. package/dist/{test-graded-scenario-DeODGLra.d.ts → test-graded-scenario-mzYBKspu.d.ts} +3 -3
  81. package/dist/traces.d.ts +54 -11
  82. package/dist/traces.js +25 -27
  83. package/dist/{types-BdIv5dvA.d.ts → types-v--ctu-b.d.ts} +2 -2
  84. package/dist/wire/index.d.ts +5 -6
  85. package/package.json +1 -71
  86. package/dist/adapters/http.d.ts +0 -142
  87. package/dist/adapters/http.js +0 -203
  88. package/dist/adapters/http.js.map +0 -1
  89. package/dist/adapters/langchain.d.ts +0 -95
  90. package/dist/adapters/langchain.js +0 -34
  91. package/dist/adapters/langchain.js.map +0 -1
  92. package/dist/adapters/otel.d.ts +0 -112
  93. package/dist/adapters/otel.js +0 -110
  94. package/dist/adapters/otel.js.map +0 -1
  95. package/dist/chunk-2OGPXHOB.js.map +0 -1
  96. package/dist/chunk-45EEMHTC.js +0 -35
  97. package/dist/chunk-45EEMHTC.js.map +0 -1
  98. package/dist/chunk-5BKGXME7.js +0 -65
  99. package/dist/chunk-5BKGXME7.js.map +0 -1
  100. package/dist/chunk-5PK3626Q.js.map +0 -1
  101. package/dist/chunk-6SK5VFYK.js +0 -100
  102. package/dist/chunk-6SK5VFYK.js.map +0 -1
  103. package/dist/chunk-DBDRR6GF.js.map +0 -1
  104. package/dist/chunk-DJWX3GVS.js +0 -81
  105. package/dist/chunk-DJWX3GVS.js.map +0 -1
  106. package/dist/chunk-FOUG2VVS.js +0 -855
  107. package/dist/chunk-FOUG2VVS.js.map +0 -1
  108. package/dist/chunk-JZXGWLK5.js.map +0 -1
  109. package/dist/chunk-K7QEIHHJ.js +0 -613
  110. package/dist/chunk-K7QEIHHJ.js.map +0 -1
  111. package/dist/chunk-KKHDIONI.js +0 -414
  112. package/dist/chunk-KKHDIONI.js.map +0 -1
  113. package/dist/chunk-KMPRBJK4.js +0 -74
  114. package/dist/chunk-KMPRBJK4.js.map +0 -1
  115. package/dist/chunk-Q2JRAWRI.js +0 -196
  116. package/dist/chunk-Q2JRAWRI.js.map +0 -1
  117. package/dist/chunk-RZTMDUO7.js +0 -49
  118. package/dist/chunk-RZTMDUO7.js.map +0 -1
  119. package/dist/chunk-STGVSCDH.js +0 -202
  120. package/dist/chunk-STGVSCDH.js.map +0 -1
  121. package/dist/chunk-YEHAEDUD.js.map +0 -1
  122. package/dist/control-runtime-Acf9CGhw.d.ts +0 -182
  123. package/dist/corpus-eBVwhCp1.d.ts +0 -560
  124. package/dist/counterfactual-DlOz8PBx.d.ts +0 -85
  125. package/dist/diagnose.d.ts +0 -252
  126. package/dist/diagnose.js +0 -382
  127. package/dist/diagnose.js.map +0 -1
  128. package/dist/feedback-trajectory-C9KCo8ag.d.ts +0 -169
  129. package/dist/governance/index.d.ts +0 -135
  130. package/dist/governance/index.js +0 -18
  131. package/dist/governance/index.js.map +0 -1
  132. package/dist/groundedness/index.d.ts +0 -112
  133. package/dist/groundedness/index.js +0 -77
  134. package/dist/groundedness/index.js.map +0 -1
  135. package/dist/harness-optimizer-mOl9XX_O.d.ts +0 -106
  136. package/dist/kind-factory-DvIGo_cP.d.ts +0 -171
  137. package/dist/knowledge/index.d.ts +0 -103
  138. package/dist/knowledge/index.js +0 -18
  139. package/dist/knowledge/index.js.map +0 -1
  140. package/dist/pareto-E-pembql.d.ts +0 -81
  141. package/dist/perf/index.d.ts +0 -123
  142. package/dist/perf/index.js +0 -18
  143. package/dist/perf/index.js.map +0 -1
  144. package/dist/prm/index.d.ts +0 -104
  145. package/dist/prm/index.js +0 -265
  146. package/dist/prm/index.js.map +0 -1
  147. package/dist/product-benchmark/index.d.ts +0 -247
  148. package/dist/product-benchmark/index.js +0 -37
  149. package/dist/product-benchmark/index.js.map +0 -1
  150. package/dist/red-team-KmmiqBlY.d.ts +0 -63
  151. package/dist/redact-B40YG2M_.d.ts +0 -45
  152. package/dist/rubric-Cc6UHvUb.d.ts +0 -73
  153. package/dist/run-critic-CmMf05uV.d.ts +0 -56
  154. package/dist/sink-fetch-B1Yg4Til.d.ts +0 -101
  155. package/dist/telemetry/file.d.ts +0 -19
  156. package/dist/telemetry/file.js +0 -45
  157. package/dist/telemetry/file.js.map +0 -1
  158. package/dist/telemetry/index.d.ts +0 -38
  159. package/dist/telemetry/index.js +0 -130
  160. package/dist/telemetry/index.js.map +0 -1
  161. package/dist/testing-C21CHsq2.d.ts +0 -20
  162. package/dist/testing.d.ts +0 -1
  163. package/dist/testing.js +0 -8
  164. package/dist/testing.js.map +0 -1
  165. package/dist/trajectory-2TkpSEVh.d.ts +0 -33
  166. package/dist/workflow/index.d.ts +0 -496
  167. package/dist/workflow/index.js +0 -2178
  168. package/dist/workflow/index.js.map +0 -1
  169. /package/dist/{chunk-LOJ2QVCE.js.map → chunk-2IY4ILP4.js.map} +0 -0
  170. /package/dist/{chunk-LIEJUH2I.js.map → chunk-6PL5MGDL.js.map} +0 -0
  171. /package/dist/{chunk-OVPVM4JC.js.map → chunk-GTERJI6Q.js.map} +0 -0
  172. /package/dist/{chunk-GDZAWO2I.js.map → chunk-QFGTU7MT.js.map} +0 -0
  173. /package/dist/{chunk-R6D7NEYJ.js.map → chunk-RNB2NICW.js.map} +0 -0
  174. /package/dist/{chunk-V7HNA47Z.js.map → chunk-RSVSSZKF.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/action-policy.ts","../src/detectors/index.ts","../src/control-runtime.ts","../src/run-evidence.ts","../src/propose-review.ts","../src/propose-review-control.ts"],"sourcesContent":["import type { FeedbackLabel, ProposedSideEffect } from './feedback-trajectory'\n\nexport interface ActionExecutionPolicy {\n allowedTypes?: string[]\n blockedTypes?: string[]\n alwaysRequireApprovalTypes?: string[]\n autoApproveTypes?: string[]\n requireApprovalForExternalSideEffects?: boolean\n requireApprovalAboveCostUsd?: number\n maxActionCostUsd?: number\n remainingBudgetUsd?: number\n expectedOutcomeRequired?: boolean\n killCriteriaRequired?: boolean\n}\n\nexport interface ActionPolicyDecision {\n allowed: boolean\n blocked: boolean\n requiresApproval: boolean\n reasons: string[]\n label?: FeedbackLabel\n}\n\nexport function evaluateActionPolicy(\n action: ProposedSideEffect,\n policy: ActionExecutionPolicy = {},\n options: { createdAt?: string } = {},\n): ActionPolicyDecision {\n const reasons: string[] = []\n let blocked = false\n let requiresApproval = Boolean(action.requiresApproval)\n\n if (policy.allowedTypes?.length && !policy.allowedTypes.includes(action.type)) {\n blocked = true\n reasons.push(`action type \"${action.type}\" is not allowed`)\n }\n if (policy.blockedTypes?.includes(action.type)) {\n blocked = true\n reasons.push(`action type \"${action.type}\" is blocked`)\n }\n if (policy.alwaysRequireApprovalTypes?.includes(action.type)) {\n requiresApproval = true\n reasons.push(`action type \"${action.type}\" requires approval`)\n }\n if (policy.requireApprovalForExternalSideEffects && action.externalSideEffect) {\n requiresApproval = true\n reasons.push('external side effect requires approval')\n }\n if (\n policy.requireApprovalAboveCostUsd !== undefined &&\n (action.costUsd ?? 0) > policy.requireApprovalAboveCostUsd\n ) {\n requiresApproval = true\n reasons.push(\n `cost ${action.costUsd} exceeds approval threshold ${policy.requireApprovalAboveCostUsd}`,\n )\n }\n if (policy.maxActionCostUsd !== undefined && (action.costUsd ?? 0) > policy.maxActionCostUsd) {\n blocked = true\n reasons.push(`cost ${action.costUsd} exceeds max action cost ${policy.maxActionCostUsd}`)\n }\n if (\n policy.remainingBudgetUsd !== undefined &&\n (action.costUsd ?? 0) > policy.remainingBudgetUsd\n ) {\n blocked = true\n reasons.push(`cost ${action.costUsd} exceeds remaining budget ${policy.remainingBudgetUsd}`)\n }\n if (policy.expectedOutcomeRequired && !action.metadata?.expectedOutcome) {\n blocked = true\n reasons.push('expected outcome is required')\n }\n if (policy.killCriteriaRequired && !action.metadata?.killCriteria) {\n blocked = true\n reasons.push('kill criteria are required')\n }\n if (policy.autoApproveTypes?.includes(action.type) && requiresApproval) {\n reasons.push(\n `action type \"${action.type}\" is auto-approved only when no approval policy applies`,\n )\n }\n\n if (!reasons.length) reasons.push(requiresApproval ? 'approval required' : 'action allowed')\n\n const label =\n blocked || requiresApproval\n ? {\n source: 'policy' as const,\n kind: blocked ? ('policy_block' as const) : ('comment' as const),\n value: { actionType: action.type, blocked, requiresApproval },\n reason: reasons.join('; '),\n severity: blocked ? ('critical' as const) : ('warning' as const),\n createdAt: options.createdAt ?? new Date().toISOString(),\n metadata: { action, policy },\n }\n : undefined\n\n return {\n allowed: !blocked,\n blocked,\n requiresApproval: !blocked && requiresApproval,\n reasons,\n label,\n }\n}\n","/**\n * Streaming detectors — the canonical, online failure-mode kernel.\n *\n * A `StreamingDetector` is a pure incremental reducer: fold one normalized step, get a signal the\n * moment a threshold trips (else null). The SAME kernel runs in two places, so the logic lives once:\n * - ONLINE, over a live agent pipe (a worker's tool-call stream) → raise a finding mid-run.\n * - INSIDE the control loop (`control-runtime`) → its `stopOn*` policies fold these detectors.\n *\n * Detectors are stateful but self-contained; `streak` is exposed for telemetry and `reset` clears it.\n * Fingerprinting is the CALLER's job — the control loop hashes state/action with `stableFingerprint`,\n * a tool-call pipe hashes args with `argHash` — so a detector stays agnostic to what it's watching.\n */\n\nimport type { FailureClass } from '../trace/schema'\n\nexport type DetectorSeverity = 'info' | 'warn' | 'critical'\n\n/** A normalized step a detector folds over. Fields are optional; each detector reads only what it\n * needs (repeated-action → `actionFingerprint`; no-progress → `stateFingerprint` + `score`;\n * error-streak → `status`). */\nexport interface DetectorEvent {\n /** Fingerprint of the action/tool-call this step took (caller pre-hashes). */\n readonly actionFingerprint?: string\n /** Fingerprint of observable state AFTER this step. */\n readonly stateFingerprint?: string\n /** Score after this step (the score-flat half of no-progress). */\n readonly score?: number\n /** Whether this step errored. */\n readonly status?: 'ok' | 'error'\n /** Free-form label carried into the signal evidence (e.g. the tool name). */\n readonly label?: string\n}\n\nexport interface DetectorSignal {\n readonly detector: string\n readonly severity: DetectorSeverity\n readonly failureClass?: FailureClass\n readonly reason: string\n /** Consecutive matching steps at the moment the signal fired. */\n readonly streak: number\n readonly evidence?: Record<string, unknown>\n}\n\nexport interface StreamingDetector {\n readonly id: string\n /** Current streak (consecutive matching steps) — for telemetry/introspection between observes. */\n readonly streak: number\n /** Fold one event; return a signal when the threshold trips, else null. */\n observe(event: DetectorEvent): DetectorSignal | null\n /** Clear all state. */\n reset(): void\n}\n\nexport interface RepeatedActionOptions {\n /** Signal once the same action fingerprint repeats this many CONSECUTIVE steps (default 3).\n * `<= 0` disables the signal (the streak is still tracked, for telemetry). */\n readonly maxRepeated?: number\n readonly severity?: DetectorSeverity\n /** Failure class to stamp on the signal (default `tool_recovery_failure`). */\n readonly failureClass?: FailureClass\n}\n\n/** Same action fingerprint N consecutive steps = a stuck loop (the #1 long-horizon failure mode). */\nexport function repeatedActionDetector(opts: RepeatedActionOptions = {}): StreamingDetector {\n const max = opts.maxRepeated ?? 3\n const severity = opts.severity ?? 'warn'\n const failureClass: FailureClass = opts.failureClass ?? 'tool_recovery_failure'\n let last: string | undefined\n let streak = 0\n return {\n id: 'repeated-action',\n get streak() {\n return streak\n },\n observe(event) {\n const fp = event.actionFingerprint\n if (fp === undefined) return null\n streak = fp === last ? streak + 1 : 1\n last = fp\n if (max <= 0 || streak < max) return null\n return {\n detector: 'repeated-action',\n severity,\n failureClass,\n reason: `stuck: repeated same action for ${streak} step(s)`,\n streak,\n ...(event.label ? { evidence: { action: event.label } } : {}),\n }\n },\n reset() {\n last = undefined\n streak = 0\n },\n }\n}\n\nexport interface NoProgressOptions {\n /** Signal once state is unchanged AND score is flat for this many CONSECUTIVE steps (default 3).\n * `<= 0` disables the signal. */\n readonly maxNoProgress?: number\n /** Minimum |score change| that counts as progress (default 0.001). */\n readonly minScoreDelta?: number\n readonly severity?: DetectorSeverity\n readonly failureClass?: FailureClass\n}\n\n/** State + score unchanged across N steps = spinning wheels. Compares each step to the previous one,\n * so prime with the initial state (observe it once before the first real step) to detect on step 1. */\nexport function noProgressDetector(opts: NoProgressOptions = {}): StreamingDetector {\n const max = opts.maxNoProgress ?? 3\n const minScoreDelta = opts.minScoreDelta ?? 0.001\n const severity = opts.severity ?? 'warn'\n const failureClass: FailureClass = opts.failureClass ?? 'tool_recovery_failure'\n let lastState: string | undefined\n let lastScore: number | undefined\n let streak = 0\n return {\n id: 'no-progress',\n get streak() {\n return streak\n },\n observe(event) {\n const stateUnchanged = lastState !== undefined && lastState === event.stateFingerprint\n const scoreFlat = Math.abs((event.score ?? 0) - (lastScore ?? 0)) < minScoreDelta\n streak = stateUnchanged && scoreFlat ? streak + 1 : 0\n lastState = event.stateFingerprint\n lastScore = event.score\n if (max <= 0 || streak < max) return null\n return {\n detector: 'no-progress',\n severity,\n failureClass,\n reason: `stuck: no state/score progress for ${streak} step(s)`,\n streak,\n ...(event.label ? { evidence: { state: event.label } } : {}),\n }\n },\n reset() {\n lastState = undefined\n lastScore = undefined\n streak = 0\n },\n }\n}\n\nexport interface ErrorStreakOptions {\n /** Signal once this many CONSECUTIVE steps errored (default 3). `<= 0` disables. */\n readonly maxErrors?: number\n readonly severity?: DetectorSeverity\n readonly failureClass?: FailureClass\n}\n\n/** N consecutive tool errors = the worker is hammering a broken approach. */\nexport function errorStreakDetector(opts: ErrorStreakOptions = {}): StreamingDetector {\n const max = opts.maxErrors ?? 3\n const severity = opts.severity ?? 'warn'\n const failureClass: FailureClass = opts.failureClass ?? 'tool_recovery_failure'\n let streak = 0\n return {\n id: 'error-streak',\n get streak() {\n return streak\n },\n observe(event) {\n if (event.status === undefined) return null\n streak = event.status === 'error' ? streak + 1 : 0\n if (max <= 0 || streak < max) return null\n return {\n detector: 'error-streak',\n severity,\n failureClass,\n reason: `stuck: ${streak} consecutive errored step(s)`,\n streak,\n ...(event.label ? { evidence: { lastError: event.label } } : {}),\n }\n },\n reset() {\n streak = 0\n },\n }\n}\n\n/** Fold one event through many detectors at once; returns every signal that fired this step. The\n * natural shape for an online pipe watching with a whole panel of detectors. */\nexport function observeAll(\n detectors: ReadonlyArray<StreamingDetector>,\n event: DetectorEvent,\n): DetectorSignal[] {\n const signals: DetectorSignal[] = []\n for (const d of detectors) {\n const s = d.observe(event)\n if (s) signals.push(s)\n }\n return signals\n}\n","/**\n * Policy-based agent control runtime.\n *\n * This is the minimal reusable loop behind driver-agent patterns:\n *\n * observe state -> validate -> decide next action -> act -> observe -> ...\n *\n * It deliberately does not model named \"topologies\". Direct execution,\n * critic/revise, driver intervention, specialist calls, and human escalation\n * are all just actions chosen by the control policy.\n */\n\nimport { noProgressDetector, repeatedActionDetector } from './detectors'\nimport { type SpanHandle, TraceEmitter } from './trace/emitter'\nimport type { FailureClass } from './trace/schema'\nimport type { TraceStore } from './trace/store'\n\nexport type ControlSeverity = 'info' | 'warning' | 'error' | 'critical'\nexport type ControlActionFailureMode = 'continue' | 'stop'\n\nexport interface ControlEvalResult {\n /** Stable validator or judge id. */\n id: string\n /** Whether this check passed. */\n passed: boolean\n /** Optional normalized score. 1 = best, 0 = worst. */\n score?: number\n /** Objective validators should usually be \"error\" or \"critical\" when failed. */\n severity?: ControlSeverity\n /** Human-readable result. */\n detail?: string\n /** Small evidence string or pointer. Avoid large payloads. */\n evidence?: string\n /** True when the result came from deterministic state, not LLM judgment. */\n objective?: boolean\n /** Structured details for downstream control policies and reports. */\n metadata?: Record<string, unknown>\n}\n\nexport interface ControlBudget {\n maxSteps: number\n maxWallMs?: number\n maxCostUsd?: number\n}\n\nexport interface ControlStopPolicies<TState, TAction> {\n /**\n * Stop after N consecutive steps with no state fingerprint change and\n * less than `minScoreDelta` score movement. Disabled when omitted.\n */\n maxNoProgressSteps?: number\n /**\n * Stop after the same action fingerprint is selected N consecutive\n * times. Disabled when omitted.\n */\n maxRepeatedActions?: number\n /** Minimum score movement that counts as progress. Default 0.001. */\n minScoreDelta?: number\n /** Override the default JSON/string fingerprint for state comparisons. */\n stateFingerprint?: (state: TState) => string\n /** Override the default JSON/string fingerprint for repeated-action checks. */\n actionFingerprint?: (action: TAction) => string\n}\n\nexport interface ControlContext<\n TState,\n TAction,\n TActionResult,\n TEval extends ControlEvalResult = ControlEvalResult,\n> {\n intent: string\n state: TState\n evals: TEval[]\n history: ControlStep<TState, TAction, TActionResult, TEval>[]\n budget: ControlBudget\n stepIndex: number\n wallMs: number\n spentCostUsd: number\n remainingCostUsd?: number\n abortSignal: AbortSignal\n emitter?: TraceEmitter\n}\n\nexport type ControlDecision<TAction> =\n | {\n type: 'continue'\n action: TAction\n reason?: string\n }\n | {\n type: 'stop'\n reason: string\n pass?: boolean\n score?: number\n }\n\nexport interface StopDecision {\n stop: boolean\n pass: boolean\n reason: string\n score?: number\n failureClass?: FailureClass\n}\n\nexport interface ControlActionOutcome<TActionResult> {\n ok: boolean\n result?: TActionResult\n error?: string\n costUsd?: number\n durationMs: number\n}\n\nexport interface ControlRuntimeError {\n phase: 'observe' | 'validate' | 'decide' | 'act' | 'stop-policy' | 'on-step' | 'trace'\n stepIndex: number\n message: string\n}\n\nexport interface ControlStep<\n TState,\n TAction,\n TActionResult,\n TEval extends ControlEvalResult = ControlEvalResult,\n> {\n index: number\n decision: ControlDecision<TAction>\n beforeState: TState\n afterState: TState\n evalsBefore: TEval[]\n evalsAfter: TEval[]\n actionOutcome?: ControlActionOutcome<TActionResult>\n startedAt: string\n endedAt: string\n}\n\nexport interface ControlRunResult<\n TState,\n TAction,\n TActionResult,\n TEval extends ControlEvalResult = ControlEvalResult,\n> {\n intent: string\n pass: boolean\n completed: boolean\n reason: string\n score?: number\n steps: ControlStep<TState, TAction, TActionResult, TEval>[]\n finalState: TState | undefined\n finalEvals: TEval[]\n wallMs: number\n spentCostUsd: number\n /** null when the run executed without a TraceEmitter wired (no run record was persisted). */\n runId: string | null\n failureClass?: FailureClass\n runtimeErrors: ControlRuntimeError[]\n stoppedBy: 'policy' | 'stop-policy' | 'budget' | 'abort' | 'runtime-error'\n}\n\nexport interface ControlRuntimeConfig<\n TState,\n TAction,\n TActionResult,\n TEval extends ControlEvalResult = ControlEvalResult,\n> {\n intent: string\n budget?: Partial<ControlBudget>\n signal?: AbortSignal\n /** Defaults to `continue`: action failures are recorded, then the policy gets another chance. */\n actionFailure?: ControlActionFailureMode\n /**\n * Extract cost from an action result. Used for `maxCostUsd` budget\n * enforcement and trace budget ledger emission.\n */\n getActionCostUsd?: (ctx: {\n action: TAction\n result: TActionResult\n state: TState\n evals: TEval[]\n history: ControlStep<TState, TAction, TActionResult, TEval>[]\n }) => number | undefined\n\n /** Read typed task/product state. Prefer structured state over transcript-only context. */\n observe: (ctx: {\n history: ControlStep<TState, TAction, TActionResult, TEval>[]\n abortSignal: AbortSignal\n }) => Promise<TState> | TState\n\n /** Objective validators first, subjective judges only where objective state is insufficient. */\n validate: (ctx: {\n intent: string\n state: TState\n history: ControlStep<TState, TAction, TActionResult, TEval>[]\n abortSignal: AbortSignal\n }) => Promise<TEval[]> | TEval[]\n\n /** Choose the next control action. Can call a worker, ask user, run critic, inspect state, or stop. */\n decide: (\n ctx: ControlContext<TState, TAction, TActionResult, TEval>,\n ) => Promise<ControlDecision<TAction>> | ControlDecision<TAction>\n\n /** Execute the action selected by the policy. */\n act: (\n action: TAction,\n ctx: ControlContext<TState, TAction, TActionResult, TEval>,\n ) => Promise<TActionResult> | TActionResult\n\n /** Final stopping policy. Called before decide and after each action. */\n shouldStop?: (\n ctx: ControlContext<TState, TAction, TActionResult, TEval>,\n ) => Promise<StopDecision> | StopDecision\n\n /** Optional hook for tracing or live progress updates. */\n onStep?: (step: ControlStep<TState, TAction, TActionResult, TEval>) => Promise<void> | void\n\n /** Optional generic stuck-loop policies. Custom `shouldStop` still runs first. */\n stopPolicies?: ControlStopPolicies<TState, TAction>\n\n /** Optional trace sink. Emits one run plus one span per control step. */\n store?: TraceStore\n scenarioId?: string\n projectId?: string\n variantId?: string\n}\n\nconst DEFAULT_BUDGET: ControlBudget = {\n maxSteps: 8,\n maxWallMs: 5 * 60 * 1000,\n}\n\nexport async function runAgentControlLoop<\n TState,\n TAction,\n TActionResult,\n TEval extends ControlEvalResult = ControlEvalResult,\n>(\n config: ControlRuntimeConfig<TState, TAction, TActionResult, TEval>,\n): Promise<ControlRunResult<TState, TAction, TActionResult, TEval>> {\n const budget = normalizeBudget(config.budget)\n const actionFailure = config.actionFailure ?? 'continue'\n const controller = new AbortController()\n const upstreamAbort = () => controller.abort(config.signal?.reason)\n if (config.signal) {\n if (config.signal.aborted) controller.abort(config.signal.reason)\n else config.signal.addEventListener('abort', upstreamAbort, { once: true })\n }\n\n const started = Date.now()\n const wallTimer = budget.maxWallMs\n ? setTimeout(\n () => controller.abort(new Error('control runtime wall timeout')),\n budget.maxWallMs,\n )\n : undefined\n const history: ControlStep<TState, TAction, TActionResult, TEval>[] = []\n const emitter = config.store ? new TraceEmitter(config.store) : undefined\n let spentCostUsd = 0\n const runtimeErrors: ControlRuntimeError[] = []\n // The stuck-detection kernels (shared with the online detectors). Thresholds 0 = disabled; the\n // streak is still tracked for telemetry. Both stops report `tool_recovery_failure`.\n const repeatedDetector = repeatedActionDetector({\n maxRepeated: config.stopPolicies?.maxRepeatedActions ?? 0,\n })\n const progressDetector = noProgressDetector({\n maxNoProgress: config.stopPolicies?.maxNoProgressSteps ?? 0,\n minScoreDelta: config.stopPolicies?.minScoreDelta ?? 0.001,\n })\n\n try {\n if (emitter) {\n await runTrace(runtimeErrors, 0, () =>\n emitter.startRun({\n scenarioId: config.scenarioId ?? 'agent-control-loop',\n projectId: config.projectId,\n variantId: config.variantId,\n layer: 'meta',\n tags: {\n intent: config.intent.slice(0, 120),\n maxSteps: String(budget.maxSteps),\n ...(budget.maxCostUsd !== undefined ? { maxCostUsd: String(budget.maxCostUsd) } : {}),\n },\n }),\n )\n }\n\n let state: TState\n let evals: TEval[]\n try {\n state = await config.observe({ history, abortSignal: controller.signal })\n } catch (err) {\n const error = runtimeError('observe', 0, err)\n runtimeErrors.push(error)\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: error.message,\n steps: history,\n finalState: undefined,\n finalEvals: [],\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'unknown',\n runtimeErrors,\n stoppedBy: 'runtime-error',\n })\n }\n try {\n evals = await config.validate({\n intent: config.intent,\n state,\n history,\n abortSignal: controller.signal,\n })\n await recordEvalSpans(emitter, evals, 'initial', runtimeErrors, 0)\n } catch (err) {\n const error = runtimeError('validate', 0, err)\n runtimeErrors.push(error)\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: error.message,\n steps: history,\n finalState: state,\n finalEvals: [],\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'unknown',\n runtimeErrors,\n stoppedBy: 'runtime-error',\n })\n }\n // Prime the no-progress detector with the initial state + score so step 0 can already detect a\n // no-op (mirrors the pre-loop fingerprint baseline). The priming observe never signals (streak 0).\n progressDetector.observe({\n stateFingerprint: fingerprintState(state, config.stopPolicies),\n score: averageScore(evals),\n })\n\n for (let stepIndex = 0; stepIndex < budget.maxSteps; stepIndex++) {\n if (controller.signal.aborted) {\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: abortReason(controller.signal),\n score: undefined,\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'timeout',\n runtimeErrors,\n stoppedBy: 'abort',\n })\n }\n\n const budgetStop = budgetStopDecision(budget, spentCostUsd)\n if (budgetStop.stop) {\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: budgetStop.reason,\n score: averageScore(evals),\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'budget_exceeded',\n runtimeErrors,\n stoppedBy: 'budget',\n })\n }\n\n const ctx = makeContext(\n config.intent,\n state,\n evals,\n history,\n budget,\n stepIndex,\n started,\n spentCostUsd,\n controller.signal,\n emitter,\n )\n let stop: StopDecision\n try {\n stop = config.shouldStop ? await config.shouldStop(ctx) : defaultStopDecision(evals)\n } catch (err) {\n runtimeErrors.push(runtimeError('stop-policy', stepIndex, err))\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: runtimeErrors[runtimeErrors.length - 1]!.message,\n score: averageScore(evals),\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'unknown',\n runtimeErrors,\n stoppedBy: 'runtime-error',\n })\n }\n if (stop.stop) {\n return finish(emitter, {\n intent: config.intent,\n pass: stop.pass,\n completed: true,\n reason: stop.reason,\n score: stop.score,\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: stop.failureClass,\n runtimeErrors,\n stoppedBy: 'stop-policy',\n })\n }\n\n let decision: ControlDecision<TAction>\n try {\n decision = await config.decide(ctx)\n } catch (err) {\n runtimeErrors.push(runtimeError('decide', stepIndex, err))\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: runtimeErrors[runtimeErrors.length - 1]!.message,\n score: averageScore(evals),\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'unknown',\n runtimeErrors,\n stoppedBy: 'runtime-error',\n })\n }\n if (decision.type === 'stop') {\n return finish(emitter, {\n intent: config.intent,\n pass: decision.pass ?? false,\n completed: true,\n reason: decision.reason,\n score: decision.score,\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: decision.pass === false ? 'unknown' : undefined,\n runtimeErrors,\n stoppedBy: 'policy',\n })\n }\n\n const actionFingerprint = fingerprintAction(decision.action, config.stopPolicies)\n const repeatedActionSignal = repeatedDetector.observe({ actionFingerprint })\n const repeatedActionStreak = repeatedDetector.streak\n if (repeatedActionSignal) {\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: true,\n reason: repeatedActionSignal.reason,\n score: averageScore(evals),\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'tool_recovery_failure',\n runtimeErrors,\n stoppedBy: 'stop-policy',\n })\n }\n\n const beforeState = state\n const evalsBefore = evals\n const scoreBefore = averageScore(evals)\n const actionStarted = Date.now()\n const stepHandle = emitter\n ? await runTrace(runtimeErrors, stepIndex, () =>\n emitter.tool({\n name: `control-step-${stepIndex}`,\n toolName: 'agent-control-action',\n args: decision.action,\n attributes: {\n decision: decision.reason ?? 'continue',\n repeatedActionStreak,\n },\n }),\n )\n : undefined\n let actionOutcome: ControlActionOutcome<TActionResult>\n try {\n const result = await config.act(decision.action, ctx)\n const rawCostUsd = config.getActionCostUsd?.({\n action: decision.action,\n result,\n state,\n evals,\n history,\n })\n const costUsd = normalizeActionCostUsd(rawCostUsd, runtimeErrors, stepIndex)\n if (costUsd !== undefined && Number.isFinite(costUsd) && costUsd > 0) {\n spentCostUsd += costUsd\n await recordCostBudget(\n emitter,\n budget,\n spentCostUsd,\n stepHandle,\n runtimeErrors,\n stepIndex,\n )\n }\n actionOutcome = {\n ok: true,\n result,\n ...(costUsd !== undefined ? { costUsd } : {}),\n durationMs: Date.now() - actionStarted,\n }\n } catch (err) {\n runtimeErrors.push(runtimeError('act', stepIndex, err))\n actionOutcome = {\n ok: false,\n error: runtimeErrors[runtimeErrors.length - 1]!.message,\n durationMs: Date.now() - actionStarted,\n }\n if (actionFailure === 'stop') {\n await runTrace(runtimeErrors, stepIndex, () =>\n stepHandle?.fail(actionOutcome.error ?? 'action failed'),\n )\n const step: ControlStep<TState, TAction, TActionResult, TEval> = {\n index: stepIndex,\n decision,\n beforeState,\n afterState: state,\n evalsBefore,\n evalsAfter: evals,\n actionOutcome,\n startedAt: new Date(actionStarted).toISOString(),\n endedAt: new Date().toISOString(),\n }\n history.push(step)\n await runOnStep(config.onStep, step, runtimeErrors)\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: actionOutcome.error ?? 'action failed',\n score: averageScore(evals),\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'unknown',\n runtimeErrors,\n stoppedBy: 'runtime-error',\n })\n }\n }\n\n try {\n state = await config.observe({ history, abortSignal: controller.signal })\n } catch (err) {\n runtimeErrors.push(runtimeError('observe', stepIndex, err))\n const step: ControlStep<TState, TAction, TActionResult, TEval> = {\n index: stepIndex,\n decision,\n beforeState,\n afterState: beforeState,\n evalsBefore,\n evalsAfter: evals,\n actionOutcome,\n startedAt: new Date(actionStarted).toISOString(),\n endedAt: new Date().toISOString(),\n }\n history.push(step)\n await runTrace(runtimeErrors, stepIndex, () =>\n stepHandle?.fail(runtimeErrors[runtimeErrors.length - 1]!.message),\n )\n await runOnStep(config.onStep, step, runtimeErrors)\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: runtimeErrors[runtimeErrors.length - 1]!.message,\n score: averageScore(evals),\n steps: history,\n finalState: beforeState,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'unknown',\n runtimeErrors,\n stoppedBy: 'runtime-error',\n })\n }\n try {\n evals = await config.validate({\n intent: config.intent,\n state,\n history,\n abortSignal: controller.signal,\n })\n await recordEvalSpans(\n emitter,\n evals,\n `step-${stepIndex}`,\n runtimeErrors,\n stepIndex,\n stepHandle?.span.spanId,\n )\n } catch (err) {\n runtimeErrors.push(runtimeError('validate', stepIndex, err))\n const step: ControlStep<TState, TAction, TActionResult, TEval> = {\n index: stepIndex,\n decision,\n beforeState,\n afterState: state,\n evalsBefore,\n evalsAfter: evals,\n actionOutcome,\n startedAt: new Date(actionStarted).toISOString(),\n endedAt: new Date().toISOString(),\n }\n history.push(step)\n await runTrace(runtimeErrors, stepIndex, () =>\n stepHandle?.fail(runtimeErrors[runtimeErrors.length - 1]!.message),\n )\n await runOnStep(config.onStep, step, runtimeErrors)\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: runtimeErrors[runtimeErrors.length - 1]!.message,\n score: averageScore(evals),\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'unknown',\n runtimeErrors,\n stoppedBy: 'runtime-error',\n })\n }\n const scoreAfter = averageScore(evals)\n const stateFingerprint = fingerprintState(state, config.stopPolicies)\n const noProgressSignal = progressDetector.observe({ stateFingerprint, score: scoreAfter })\n const noProgressStreak = progressDetector.streak\n\n const step: ControlStep<TState, TAction, TActionResult, TEval> = {\n index: stepIndex,\n decision,\n beforeState,\n afterState: state,\n evalsBefore,\n evalsAfter: evals,\n actionOutcome,\n startedAt: new Date(actionStarted).toISOString(),\n endedAt: new Date().toISOString(),\n }\n history.push(step)\n if (actionOutcome.ok) {\n await runTrace(runtimeErrors, stepIndex, () =>\n stepHandle?.end({\n attributes: {\n actionCostUsd: actionOutcome.costUsd ?? null,\n spentCostUsd,\n scoreBefore: scoreBefore ?? null,\n scoreAfter: scoreAfter ?? null,\n noProgressStreak,\n },\n }),\n )\n } else {\n await runTrace(runtimeErrors, stepIndex, () =>\n stepHandle?.fail(actionOutcome.error ?? 'action failed', {\n attributes: {\n spentCostUsd,\n noProgressStreak,\n },\n }),\n )\n }\n await runOnStep(config.onStep, step, runtimeErrors)\n\n if (noProgressSignal) {\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: true,\n reason: noProgressSignal.reason,\n score: scoreAfter,\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'tool_recovery_failure',\n runtimeErrors,\n stoppedBy: 'stop-policy',\n })\n }\n\n const postStepBudgetStop = budgetStopDecision(budget, spentCostUsd)\n if (postStepBudgetStop.stop) {\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: postStepBudgetStop.reason,\n score: scoreAfter,\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'budget_exceeded',\n runtimeErrors,\n stoppedBy: 'budget',\n })\n }\n\n const postStepCtx = makeContext(\n config.intent,\n state,\n evals,\n history,\n budget,\n stepIndex + 1,\n started,\n spentCostUsd,\n controller.signal,\n emitter,\n )\n let postStepStop: StopDecision\n try {\n postStepStop = config.shouldStop\n ? await config.shouldStop(postStepCtx)\n : defaultStopDecision(evals)\n } catch (err) {\n runtimeErrors.push(runtimeError('stop-policy', stepIndex + 1, err))\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: runtimeErrors[runtimeErrors.length - 1]!.message,\n score: averageScore(evals),\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'unknown',\n runtimeErrors,\n stoppedBy: 'runtime-error',\n })\n }\n if (postStepStop.stop) {\n return finish(emitter, {\n intent: config.intent,\n pass: postStepStop.pass,\n completed: true,\n reason: postStepStop.reason,\n score: postStepStop.score,\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: postStepStop.failureClass,\n runtimeErrors,\n stoppedBy: 'stop-policy',\n })\n }\n }\n\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: `budget exhausted: maxSteps=${budget.maxSteps}`,\n steps: history,\n finalState: state,\n finalEvals: evals,\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'budget_exceeded',\n runtimeErrors,\n stoppedBy: 'budget',\n })\n } catch (err) {\n runtimeErrors.push(runtimeError('act', history.length, err))\n return finish(emitter, {\n intent: config.intent,\n pass: false,\n completed: false,\n reason: runtimeErrors[runtimeErrors.length - 1]!.message,\n steps: history,\n finalState: undefined,\n finalEvals: [],\n wallMs: Date.now() - started,\n spentCostUsd,\n runId: emitter?.runId ?? null,\n failureClass: 'unknown',\n runtimeErrors,\n stoppedBy: 'runtime-error',\n })\n } finally {\n if (wallTimer) clearTimeout(wallTimer)\n if (config.signal) config.signal.removeEventListener('abort', upstreamAbort)\n }\n}\n\nexport function stopOnNoProgress<TState, TAction>(\n maxNoProgressSteps: number,\n options: Omit<ControlStopPolicies<TState, TAction>, 'maxNoProgressSteps'> = {},\n): ControlStopPolicies<TState, TAction> {\n return { ...options, maxNoProgressSteps }\n}\n\nexport function stopOnRepeatedAction<TState, TAction>(\n maxRepeatedActions: number,\n options: Omit<ControlStopPolicies<TState, TAction>, 'maxRepeatedActions'> = {},\n): ControlStopPolicies<TState, TAction> {\n return { ...options, maxRepeatedActions }\n}\n\nexport function objectiveEval(input: Omit<ControlEvalResult, 'objective'>): ControlEvalResult {\n return { ...input, objective: true }\n}\n\nexport function subjectiveEval(input: Omit<ControlEvalResult, 'objective'>): ControlEvalResult {\n return { ...input, objective: false }\n}\n\nfunction normalizeBudget(input: Partial<ControlBudget> | undefined): ControlBudget {\n const raw = { ...DEFAULT_BUDGET, ...input } as Record<string, unknown>\n if (!Number.isInteger(raw.maxSteps) || (raw.maxSteps as number) < 1) {\n throw new RangeError(\n `ControlRuntime budget.maxSteps must be an integer >= 1, got ${String(raw.maxSteps)}`,\n )\n }\n const budget: ControlBudget = { maxSteps: raw.maxSteps as number }\n if (raw.maxWallMs !== undefined) {\n if (\n typeof raw.maxWallMs !== 'number' ||\n !Number.isFinite(raw.maxWallMs) ||\n raw.maxWallMs <= 0\n ) {\n throw new RangeError(\n `ControlRuntime budget.maxWallMs must be a positive finite number, got ${String(raw.maxWallMs)}`,\n )\n }\n budget.maxWallMs = raw.maxWallMs\n }\n if (raw.maxCostUsd !== undefined) {\n if (\n typeof raw.maxCostUsd !== 'number' ||\n !Number.isFinite(raw.maxCostUsd) ||\n raw.maxCostUsd < 0\n ) {\n throw new RangeError(\n `ControlRuntime budget.maxCostUsd must be a nonnegative finite number, got ${String(raw.maxCostUsd)}`,\n )\n }\n budget.maxCostUsd = raw.maxCostUsd\n }\n return budget\n}\n\nfunction normalizeActionCostUsd(\n costUsd: number | undefined,\n runtimeErrors: ControlRuntimeError[],\n stepIndex: number,\n): number | undefined {\n if (costUsd === undefined) return undefined\n if (!Number.isFinite(costUsd) || costUsd < 0) {\n runtimeErrors.push(\n runtimeError('act', stepIndex, new Error(`invalid action costUsd: ${String(costUsd)}`)),\n )\n return undefined\n }\n return costUsd\n}\n\nexport function allCriticalPassed(evals: ControlEvalResult[]): boolean {\n return evals.every(\n (result) => result.passed || (result.severity !== 'critical' && result.severity !== 'error'),\n )\n}\n\nfunction makeContext<TState, TAction, TActionResult, TEval extends ControlEvalResult>(\n intent: string,\n state: TState,\n evals: TEval[],\n history: ControlStep<TState, TAction, TActionResult, TEval>[],\n budget: ControlBudget,\n stepIndex: number,\n started: number,\n spentCostUsd: number,\n abortSignal: AbortSignal,\n emitter?: TraceEmitter,\n): ControlContext<TState, TAction, TActionResult, TEval> {\n return {\n intent,\n state,\n evals,\n history,\n budget,\n stepIndex,\n wallMs: Date.now() - started,\n spentCostUsd,\n remainingCostUsd:\n budget.maxCostUsd === undefined ? undefined : Math.max(0, budget.maxCostUsd - spentCostUsd),\n abortSignal,\n emitter,\n }\n}\n\nfunction defaultStopDecision(evals: ControlEvalResult[]): StopDecision {\n if (!evals.length) return { stop: false, pass: false, reason: 'no evals yet' }\n const pass = allCriticalPassed(evals)\n return pass\n ? { stop: true, pass: true, reason: 'all critical evals passed', score: averageScore(evals) }\n : {\n stop: false,\n pass: false,\n reason: 'critical evals still failing',\n score: averageScore(evals),\n }\n}\n\nfunction averageScore(evals: ControlEvalResult[]): number | undefined {\n const scored = evals\n .map((result) => result.score)\n .filter((score): score is number => typeof score === 'number')\n if (!scored.length) return undefined\n return Math.round((scored.reduce((sum, score) => sum + score, 0) / scored.length) * 1000) / 1000\n}\n\nfunction budgetStopDecision(\n budget: ControlBudget,\n spentCostUsd: number,\n): { stop: boolean; reason: string } {\n if (budget.maxCostUsd !== undefined && spentCostUsd >= budget.maxCostUsd) {\n return {\n stop: true,\n reason: `budget exhausted: maxCostUsd=${budget.maxCostUsd}`,\n }\n }\n return { stop: false, reason: '' }\n}\n\nasync function recordCostBudget(\n emitter: TraceEmitter | undefined,\n budget: ControlBudget,\n spentCostUsd: number,\n handle: SpanHandle | undefined,\n runtimeErrors: ControlRuntimeError[],\n stepIndex: number,\n): Promise<void> {\n if (!emitter || budget.maxCostUsd === undefined) return\n const maxCostUsd = budget.maxCostUsd\n await runTrace(runtimeErrors, stepIndex, () =>\n emitter.recordBudget({\n dimension: 'usd',\n limit: maxCostUsd,\n consumed: spentCostUsd,\n remaining: Math.max(0, maxCostUsd - spentCostUsd),\n breached: spentCostUsd >= maxCostUsd,\n spanId: handle?.span.spanId,\n }),\n )\n}\n\nasync function recordEvalSpans(\n emitter: TraceEmitter | undefined,\n evals: ControlEvalResult[],\n phase: string,\n runtimeErrors: ControlRuntimeError[],\n stepIndex: number,\n targetSpanId?: string,\n): Promise<void> {\n if (!emitter) return\n for (const result of evals) {\n await runTrace(runtimeErrors, stepIndex, () =>\n emitter.recordJudge({\n judgeId: result.objective ? 'objective-validator' : 'subjective-judge',\n targetSpanId: targetSpanId ?? emitter.runId,\n name: `control-eval/${result.id}`,\n dimension: result.id,\n score: typeof result.score === 'number' ? result.score : result.passed ? 1 : 0,\n rationale: result.detail,\n evidence: result.evidence,\n attributes: {\n phase,\n passed: result.passed,\n severity: result.severity,\n objective: result.objective,\n },\n }),\n )\n }\n}\n\nasync function runOnStep<TState, TAction, TActionResult, TEval extends ControlEvalResult>(\n onStep: ControlRuntimeConfig<TState, TAction, TActionResult, TEval>['onStep'] | undefined,\n step: ControlStep<TState, TAction, TActionResult, TEval>,\n runtimeErrors: ControlRuntimeError[],\n): Promise<void> {\n if (!onStep) return\n try {\n await onStep(step)\n } catch (err) {\n runtimeErrors.push(runtimeError('on-step', step.index, err))\n }\n}\n\nasync function runTrace<T>(\n runtimeErrors: ControlRuntimeError[],\n stepIndex: number,\n write: () => Promise<T | undefined> | T | undefined,\n): Promise<T | undefined> {\n try {\n return await write()\n } catch (err) {\n runtimeErrors.push(runtimeError('trace', stepIndex, err))\n return undefined\n }\n}\n\nfunction fingerprintState<TState, TAction>(\n state: TState,\n policies?: ControlStopPolicies<TState, TAction>,\n): string {\n if (policies?.stateFingerprint) return policies.stateFingerprint(state)\n return stableFingerprint(state)\n}\n\nfunction fingerprintAction<TState, TAction>(\n action: TAction,\n policies?: ControlStopPolicies<TState, TAction>,\n): string {\n if (policies?.actionFingerprint) return policies.actionFingerprint(action)\n return stableFingerprint(action)\n}\n\nfunction stableFingerprint(value: unknown): string {\n if (typeof value === 'string') return value\n if (typeof value === 'number' || typeof value === 'boolean' || value == null) return String(value)\n try {\n return JSON.stringify(sortForFingerprint(value))\n } catch {\n return String(value)\n }\n}\n\nfunction sortForFingerprint(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortForFingerprint)\n if (!value || typeof value !== 'object') return value\n const record = value as Record<string, unknown>\n const sorted: Record<string, unknown> = {}\n for (const key of Object.keys(record).sort()) {\n sorted[key] = sortForFingerprint(record[key])\n }\n return sorted\n}\n\nfunction abortReason(signal: AbortSignal): string {\n const reason = signal.reason\n if (reason instanceof Error) return reason.message\n return reason ? String(reason) : 'aborted'\n}\n\nfunction runtimeError(\n phase: ControlRuntimeError['phase'],\n stepIndex: number,\n err: unknown,\n): ControlRuntimeError {\n const message = err instanceof Error ? err.message : String(err)\n return { phase, stepIndex, message }\n}\n\nasync function finish<TState, TAction, TActionResult, TEval extends ControlEvalResult>(\n emitter: TraceEmitter | undefined,\n result: ControlRunResult<TState, TAction, TActionResult, TEval>,\n): Promise<ControlRunResult<TState, TAction, TActionResult, TEval>> {\n await runTrace(result.runtimeErrors, result.steps.length, () =>\n emitter?.endRun({\n pass: result.pass,\n score: result.score ?? averageScore(result.finalEvals),\n failureClass: result.failureClass,\n notes: result.reason,\n }),\n )\n return result\n}\n","import type { ControlEvalResult, ControlRunResult } from './control-runtime'\nimport {\n type RunRecord,\n type RunSplitTag,\n type RunTokenUsage,\n validateRunRecord,\n} from './run-record'\nimport type { FailureClass } from './trace/schema'\n\nexport interface RunEvidenceMetadata {\n experimentId: string\n candidateId: string\n seed: number\n model: string\n promptHash: string\n configHash: string\n commitSha: string\n splitTag: RunSplitTag\n tokenUsage: RunTokenUsage\n queueMs?: number\n judgeMetadata?: RunRecord['judgeMetadata']\n raw?: Record<string, number>\n}\n\nexport interface ControlRunToRunRecordOptions extends RunEvidenceMetadata {\n runId?: string\n score?: number\n failureMode?: string\n}\n\n/**\n * Project a completed control-loop run into the strict RunRecord shape used by\n * release gates, optimizer tables, and research reports.\n *\n * The control loop owns live execution evidence. The caller still supplies the\n * experiment-cell metadata because prompt/config hashes, split assignment,\n * model snapshot, and commit SHA are product/harness concerns.\n */\nexport function controlRunToRunRecord<\n TState,\n TAction,\n TActionResult,\n TEval extends ControlEvalResult = ControlEvalResult,\n>(\n run: ControlRunResult<TState, TAction, TActionResult, TEval>,\n options: ControlRunToRunRecordOptions,\n): RunRecord {\n const score = clampScore(\n options.score ?? run.score ?? scoreFromEvals(run.finalEvals) ?? (run.pass ? 1 : 0),\n )\n const outcome =\n options.splitTag === 'holdout'\n ? { holdoutScore: score, raw: normalizeRawMetrics(options.raw, run, score) }\n : { searchScore: score, raw: normalizeRawMetrics(options.raw, run, score) }\n\n return validateRunRecord({\n runId:\n options.runId ??\n run.runId ??\n `control:${options.experimentId}:${options.candidateId}:${options.seed}:${options.splitTag}`,\n experimentId: options.experimentId,\n candidateId: options.candidateId,\n seed: options.seed,\n model: options.model,\n promptHash: options.promptHash,\n configHash: options.configHash,\n commitSha: options.commitSha,\n wallMs: run.wallMs,\n ...(options.queueMs !== undefined ? { queueMs: options.queueMs } : {}),\n costUsd: run.spentCostUsd,\n tokenUsage: options.tokenUsage,\n ...(options.judgeMetadata ? { judgeMetadata: options.judgeMetadata } : {}),\n outcome,\n failureMode: options.failureMode ?? failureModeFromRun(run),\n splitTag: options.splitTag,\n })\n}\n\nexport function scoreFromEvals(evals: readonly ControlEvalResult[]): number | undefined {\n const scores = evals\n .map((e) => e.score)\n .filter((score): score is number => typeof score === 'number' && Number.isFinite(score))\n if (scores.length === 0) return undefined\n return clampScore(scores.reduce((sum, score) => sum + score, 0) / scores.length)\n}\n\nfunction normalizeRawMetrics<TState, TAction, TActionResult, TEval extends ControlEvalResult>(\n raw: Record<string, number> | undefined,\n run: ControlRunResult<TState, TAction, TActionResult, TEval>,\n score: number,\n): Record<string, number> {\n return {\n ...finiteOnly(raw ?? {}),\n score,\n pass: run.pass ? 1 : 0,\n completed: run.completed ? 1 : 0,\n steps: run.steps.length,\n runtimeErrors: run.runtimeErrors.length,\n }\n}\n\nfunction finiteOnly(values: Record<string, number>): Record<string, number> {\n const out: Record<string, number> = {}\n for (const [key, value] of Object.entries(values)) {\n if (Number.isFinite(value)) out[key] = value\n }\n return out\n}\n\nfunction failureModeFromRun<TState, TAction, TActionResult, TEval extends ControlEvalResult>(\n run: ControlRunResult<TState, TAction, TActionResult, TEval>,\n): FailureClass | undefined {\n if (run.pass) return undefined\n return run.failureClass ?? 'unknown'\n}\n\nfunction clampScore(value: number): number {\n if (!Number.isFinite(value)) return 0\n return Math.max(0, Math.min(1, value))\n}\n","/**\n * Propose / Verify / Review — the core multi-shot primitive.\n *\n * shot N: propose(state, priorReview) → new state\n * verify(state) → pass/fail, optional layers\n * review(state, verification, memory) → observations + next-shot\n * instruction + shouldContinue\n * memory.append(entry)\n *\n * Roles are strictly separated:\n *\n * - The WORKER is whatever the caller wraps in `propose`. It is\n * stateful — caller owns its resume/session mechanism.\n * - The VERIFIER grades the state. It produces the ground truth.\n * The reviewer cannot overturn or downgrade a verification layer.\n * - The REVIEWER is stateless per call. Its continuity is the\n * `ReviewMemoryStore` — durable JSONL by default, or any store\n * implementing the interface. It reads memory + trace summary +\n * verification and directs the NEXT proposer shot.\n *\n * This shape is load-bearing. The reviewer never grades; the verifier\n * never directs. Two processes, two prompts, two concerns — which is\n * what keeps the loop from confirmation-biasing itself into \"all\n * passed\" when it didn't.\n *\n * Short-circuits and soft-fails are both first-class:\n * - verify.pass === true → reviewer LLM call is skipped, memory\n * records a success entry, loop exits.\n * - review throws → the shot still counts; the loop uses the\n * last-known instruction (or `fallbackInstruction`) for the next\n * propose call. A transient reviewer failure must NEVER abort a\n * valid arc.\n *\n * Composable: `propose` itself can be another `runProposeReview` call.\n * That's the dogfooding path — a harness built on this primitive is in\n * turn evaluable by it.\n */\n\nimport { appendFileSync, existsSync, mkdirSync, readFileSync } from 'node:fs'\nimport { dirname } from 'node:path'\nimport { type SpanHandle, TraceEmitter } from './trace/emitter'\nimport type { FailureClass } from './trace/schema'\nimport type { TraceStore } from './trace/store'\n\n// ── Types ────────────────────────────────────────────────────────────\n\nexport interface Verification {\n pass: boolean\n score?: number\n failingLayers?: string[]\n details?: unknown\n}\n\nexport interface Review {\n observations: string\n diagnosis: string\n nextShotInstruction: string\n shouldContinue: boolean\n confidence: number\n}\n\nexport interface ReviewMemoryEntry extends Review {\n shot: number\n timestamp: number\n verification: {\n pass: boolean\n score?: number\n failingLayers?: string[]\n }\n}\n\nexport interface ProposeInput<State> {\n shot: number\n goal: string\n state: State\n priorReview: Review | null\n abortSignal: AbortSignal\n emitter?: TraceEmitter\n}\n\nexport interface ProposeOutput<State, Summary = unknown> {\n state: State\n traceSummary?: Summary\n}\n\nexport interface ReviewInput<State, Summary = unknown> {\n shot: number\n goal: string\n state: State\n verification: Verification\n traceSummary: Summary | undefined\n memory: ReviewMemoryEntry[]\n}\n\nexport type ProposeFn<State, Summary = unknown> = (\n input: ProposeInput<State>,\n) => Promise<ProposeOutput<State, Summary>>\n\nexport type VerifyFn<State> = (state: State) => Promise<Verification>\n\nexport type ReviewFn<State, Summary = unknown> = (\n input: ReviewInput<State, Summary>,\n) => Promise<Review>\n\nexport interface ReviewMemoryStore {\n load(): Promise<ReviewMemoryEntry[]>\n append(entry: ReviewMemoryEntry): Promise<void>\n}\n\nexport interface ProposeReviewConfig<State, Summary = unknown> {\n goal: string\n initialState: State\n propose: ProposeFn<State, Summary>\n verify: VerifyFn<State>\n review: ReviewFn<State, Summary>\n /** Hard shot cap. Default 10. */\n maxShots?: number\n /** Wall-clock cap in ms. Default 10 min. */\n maxWallMs?: number\n /**\n * If the reviewer returns confidence ≤ floor on `confidenceFloorWindow`\n * consecutive shots, terminate early. Default floor 0.3, window 2.\n * Set window to 0 or floor to <0 to disable.\n */\n confidenceFloor?: number\n confidenceFloorWindow?: number\n /** Defaults to an in-memory store if omitted. */\n memory?: ReviewMemoryStore\n /** If provided, emit a Run + per-shot spans. */\n store?: TraceStore\n scenarioId?: string\n projectId?: string\n variantId?: string\n /**\n * Used when the reviewer soft-fails on shot 1 (no prior instruction to\n * fall back to). Default is a generic \"inspect failures and fix\".\n */\n fallbackInstruction?: string\n}\n\nexport interface ProposeReviewShot<State, Summary = unknown> {\n shot: number\n state: State\n verification: Verification\n traceSummary: Summary | undefined\n review: Review\n reviewAvailable: boolean\n reviewError?: string\n durationMs: number\n}\n\nexport interface ProposeReviewReport<State, Summary = unknown> {\n runId: string | null\n completed: boolean\n shots: ProposeReviewShot<State, Summary>[]\n finalState: State\n finalVerification: Verification\n failureClass?: FailureClass\n wallMs: number\n score: number\n}\n\n// ── Memory stores ────────────────────────────────────────────────────\n\nexport function inMemoryReviewStore(initial: ReviewMemoryEntry[] = []): ReviewMemoryStore {\n const entries: ReviewMemoryEntry[] = [...initial]\n return {\n async load() {\n return [...entries]\n },\n async append(entry) {\n entries.push(entry)\n },\n }\n}\n\nexport function jsonlReviewStore(path: string): ReviewMemoryStore {\n return {\n async load() {\n if (!existsSync(path)) return []\n const raw = readFileSync(path, 'utf8')\n const out: ReviewMemoryEntry[] = []\n for (const line of raw.split('\\n')) {\n const trimmed = line.trim()\n if (!trimmed) continue\n try {\n out.push(JSON.parse(trimmed) as ReviewMemoryEntry)\n } catch {\n // A corrupt line is an observability problem, not a correctness\n // one — skip it rather than aborting the loop.\n }\n }\n return out\n },\n async append(entry) {\n mkdirSync(dirname(path), { recursive: true })\n appendFileSync(path, `${JSON.stringify(entry)}\\n`)\n },\n }\n}\n\n// ── Core loop ────────────────────────────────────────────────────────\n\nconst DEFAULT_FALLBACK_INSTRUCTION =\n 'Inspect the verification failures above. Fix the critical issues first, then the major ones. Do not restate the failures — act on them.'\n\nexport async function runProposeReview<State, Summary = unknown>(\n config: ProposeReviewConfig<State, Summary>,\n): Promise<ProposeReviewReport<State, Summary>> {\n const maxShots = config.maxShots ?? 10\n const maxWallMs = config.maxWallMs ?? 10 * 60 * 1000\n const confidenceFloor = config.confidenceFloor ?? 0.3\n const confidenceFloorWindow = config.confidenceFloorWindow ?? 2\n const memory = config.memory ?? inMemoryReviewStore()\n const fallbackInstruction = config.fallbackInstruction ?? DEFAULT_FALLBACK_INSTRUCTION\n\n const emitter = config.store ? new TraceEmitter(config.store) : null\n if (emitter) {\n await emitter.startRun({\n scenarioId: config.scenarioId ?? 'propose-review',\n projectId: config.projectId,\n variantId: config.variantId,\n layer: 'meta',\n tags: {\n goal: config.goal.slice(0, 120),\n maxShots: String(maxShots),\n },\n })\n }\n\n const abort = new AbortController()\n const wallStart = Date.now()\n const wallTimer = setTimeout(\n () => abort.abort(new Error('propose-review wall timeout')),\n maxWallMs,\n )\n\n const shots: ProposeReviewShot<State, Summary>[] = []\n let state = config.initialState\n let priorReview: Review | null = null\n let lastVerification: Verification = { pass: false }\n let failureClass: FailureClass | undefined\n let completed = false\n let lowConfidenceStreak = 0\n\n try {\n for (let shot = 1; shot <= maxShots; shot++) {\n if (abort.signal.aborted) {\n failureClass = 'timeout'\n break\n }\n\n const shotStart = Date.now()\n const shotHandle = emitter ? await emitter.span({ kind: 'tool', name: `shot-${shot}` }) : null\n\n // 1. Propose.\n let proposeOut: ProposeOutput<State, Summary>\n try {\n proposeOut = await config.propose({\n shot,\n goal: config.goal,\n state,\n priorReview,\n abortSignal: abort.signal,\n emitter: emitter ?? undefined,\n })\n } catch (err) {\n await shotHandle?.fail(err instanceof Error ? err : String(err))\n failureClass = 'unknown'\n throw err\n }\n state = proposeOut.state\n const traceSummary = proposeOut.traceSummary\n\n // 2. Verify.\n let verification: Verification\n try {\n verification = await config.verify(state)\n } catch (err) {\n await shotHandle?.fail(err instanceof Error ? err : String(err))\n failureClass = 'unknown'\n throw err\n }\n lastVerification = verification\n\n // 3. Review — short-circuit on pass; soft-fail on throw.\n const memorySnapshot = await memory.load()\n const verificationDigest = {\n pass: verification.pass,\n score: verification.score,\n failingLayers: verification.failingLayers ?? [],\n }\n\n let review: Review\n let reviewAvailable = true\n let reviewError: string | undefined\n\n if (verification.pass) {\n review = {\n observations: 'verification passed — skipping reviewer LLM call',\n diagnosis: 'no failures to diagnose',\n nextShotInstruction: '(done)',\n shouldContinue: false,\n confidence: 1,\n }\n } else {\n try {\n review = await config.review({\n shot,\n goal: config.goal,\n state,\n verification,\n traceSummary,\n memory: memorySnapshot,\n })\n review = coerceReview(review)\n } catch (err) {\n reviewAvailable = false\n reviewError = err instanceof Error ? err.message : String(err)\n const lastInstruction =\n memorySnapshot.length > 0\n ? memorySnapshot[memorySnapshot.length - 1]!.nextShotInstruction\n : fallbackInstruction\n review = {\n observations: '(reviewer unavailable — using last-known instruction)',\n diagnosis: reviewError,\n nextShotInstruction: lastInstruction,\n shouldContinue: true,\n confidence: 0.3,\n }\n }\n }\n\n const entry: ReviewMemoryEntry = {\n shot,\n timestamp: Date.now(),\n ...review,\n verification: verificationDigest,\n }\n await memory.append(entry)\n\n const shotRecord: ProposeReviewShot<State, Summary> = {\n shot,\n state,\n verification,\n traceSummary,\n review,\n reviewAvailable,\n reviewError,\n durationMs: Date.now() - shotStart,\n }\n shots.push(shotRecord)\n\n await shotHandle?.end({\n attributes: {\n verificationPass: verification.pass,\n verificationScore: verification.score ?? null,\n reviewShouldContinue: review.shouldContinue,\n reviewConfidence: review.confidence,\n reviewAvailable,\n },\n } as Partial<SpanHandle['span']>)\n\n // 4. Exit rules.\n if (verification.pass) {\n completed = true\n break\n }\n if (!review.shouldContinue) {\n break\n }\n if (confidenceFloorWindow > 0 && review.confidence <= confidenceFloor) {\n lowConfidenceStreak += 1\n if (lowConfidenceStreak >= confidenceFloorWindow) break\n } else {\n lowConfidenceStreak = 0\n }\n\n priorReview = review\n }\n\n if (!completed && !failureClass) {\n failureClass = shots.length >= maxShots ? 'budget_exceeded' : 'unknown'\n }\n } finally {\n clearTimeout(wallTimer)\n }\n\n const score = lastVerification.pass\n ? 1\n : typeof lastVerification.score === 'number'\n ? lastVerification.score\n : 0\n\n if (emitter) {\n await emitter.endRun({\n pass: completed,\n score,\n failureClass,\n notes: `${shots.length} shot(s); final pass=${lastVerification.pass}`,\n })\n }\n\n return {\n runId: emitter?.runId ?? null,\n completed,\n shots,\n finalState: state,\n finalVerification: lastVerification,\n failureClass,\n wallMs: Date.now() - wallStart,\n score,\n }\n}\n\n// ── Reviewer helper (LLM-backed) ─────────────────────────────────────\n\nexport type LlmJsonCall = (req: { system: string; user: string }) => Promise<unknown>\n\nexport interface LlmReviewerConfig<State, Summary = unknown> {\n callJson: LlmJsonCall\n renderState?: (state: State) => string\n renderTraceSummary?: (summary: Summary | undefined) => string\n /** Appended to the default system prompt. */\n systemPromptAddendum?: string\n}\n\nconst REVIEWER_SYSTEM_PROMPT = `You are a senior reviewer directing a multi-shot build loop.\nYou do NOT grade — the verifier already did. Your job is to direct the worker's next shot.\nYou are blind to the worker's inner monologue. You see what it DID, not what it thought.\nReturn STRICT JSON matching the schema. No prose outside the JSON.`\n\nexport function createLlmReviewer<State, Summary = unknown>(\n cfg: LlmReviewerConfig<State, Summary>,\n): ReviewFn<State, Summary> {\n const renderState = cfg.renderState ?? ((s: State) => safeJson(s))\n const renderTraceSummary =\n cfg.renderTraceSummary ??\n ((s: Summary | undefined) => (s === undefined ? '(none)' : safeJson(s)))\n const system = cfg.systemPromptAddendum\n ? `${REVIEWER_SYSTEM_PROMPT}\\n\\n${cfg.systemPromptAddendum}`\n : REVIEWER_SYSTEM_PROMPT\n\n return async (input) => {\n const memoryBlock =\n input.memory.length === 0\n ? '(no prior shots — this is shot 1)'\n : input.memory\n .map((m) =>\n [\n `shot ${m.shot} — verification.pass=${m.verification.pass}` +\n (typeof m.verification.score === 'number'\n ? ` score=${m.verification.score.toFixed(2)}`\n : '') +\n ` confidence=${m.confidence.toFixed(2)} failing=[${(m.verification.failingLayers ?? []).join(',')}]`,\n ` observations: ${m.observations.slice(0, 400)}`,\n ` diagnosis: ${m.diagnosis.slice(0, 400)}`,\n ` instruction given: ${m.nextShotInstruction.slice(0, 400)}`,\n ].join('\\n'),\n )\n .join('\\n\\n')\n\n const user = [\n `=== GOAL ===`,\n input.goal,\n ``,\n `=== SHOT NUMBER ===`,\n String(input.shot),\n ``,\n `=== CURRENT STATE ===`,\n renderState(input.state),\n ``,\n `=== TRACE SUMMARY ===`,\n renderTraceSummary(input.traceSummary),\n ``,\n `=== VERIFICATION ===`,\n summarizeVerification(input.verification),\n ``,\n `=== REVIEWER MEMORY (prior shots) ===`,\n memoryBlock,\n ``,\n `=== YOUR TASK ===`,\n `Return STRICT JSON:`,\n `{`,\n ` \"observations\": string (20..2000 chars, first-person worker behavior — quote counts, errors, loops)`,\n ` \"diagnosis\": string (20..1500 chars, root cause, NOT a restatement of verification)`,\n ` \"nextShotInstruction\": string (40..3000 chars, concrete directive to the worker)`,\n ` \"shouldContinue\": boolean (false if verification.pass, or if thrashing, or unachievable)`,\n ` \"confidence\": number in [0,1]`,\n `}`,\n ].join('\\n')\n\n const raw = await cfg.callJson({ system, user })\n return coerceReview(raw as Partial<Review>)\n }\n}\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\nfunction coerceReview(raw: Partial<Review> | null | undefined): Review {\n if (!raw || typeof raw !== 'object') {\n throw new Error('reviewer returned non-object')\n }\n const observations = typeof raw.observations === 'string' ? raw.observations : ''\n const diagnosis = typeof raw.diagnosis === 'string' ? raw.diagnosis : ''\n const nextShotInstruction =\n typeof raw.nextShotInstruction === 'string' ? raw.nextShotInstruction : ''\n if (!observations || !diagnosis || !nextShotInstruction) {\n throw new Error('reviewer missing required string fields')\n }\n if (typeof raw.shouldContinue !== 'boolean') {\n throw new Error('reviewer missing shouldContinue boolean')\n }\n const confidenceRaw = Number(raw.confidence)\n if (!Number.isFinite(confidenceRaw)) {\n throw new Error('reviewer confidence not finite')\n }\n return {\n observations,\n diagnosis,\n nextShotInstruction,\n shouldContinue: raw.shouldContinue,\n confidence: Math.max(0, Math.min(1, confidenceRaw)),\n }\n}\n\nfunction summarizeVerification(v: Verification): string {\n const header =\n `pass=${v.pass}` +\n (typeof v.score === 'number' ? ` score=${v.score.toFixed(3)}` : '') +\n (v.failingLayers && v.failingLayers.length > 0\n ? ` failing=[${v.failingLayers.join(', ')}]`\n : '')\n const details = v.details === undefined ? '' : `\\n${safeJson(v.details).slice(0, 1500)}`\n return header + details\n}\n\nfunction safeJson(x: unknown): string {\n try {\n return JSON.stringify(x, null, 2)\n } catch {\n return String(x)\n }\n}\n","import {\n type ControlRunResult,\n type ControlRuntimeConfig,\n objectiveEval,\n runAgentControlLoop,\n} from './control-runtime'\nimport {\n inMemoryReviewStore,\n type ProposeFn,\n type ProposeOutput,\n type Review,\n type ReviewFn,\n type ReviewMemoryEntry,\n type ReviewMemoryStore,\n type Verification,\n type VerifyFn,\n} from './propose-review'\nimport type { FailureClass } from './trace/schema'\nimport type { TraceStore } from './trace/store'\n\nexport interface ProposeReviewControlState<State, Summary = unknown> {\n shot: number\n state: State\n priorReview: Review | null\n verification: Verification\n traceSummary?: Summary\n memory: ReviewMemoryEntry[]\n completed: boolean\n reviewAvailable: boolean\n reviewError?: string\n}\n\nexport interface ProposeReviewControlAction {\n type: 'propose-review-shot'\n shot: number\n}\n\nexport interface ProposeReviewControlResult<State, Summary = unknown> {\n state: State\n verification: Verification\n traceSummary?: Summary\n review: Review | null\n reviewAvailable: boolean\n reviewError?: string\n}\n\nexport interface ProposeReviewControlConfig<State, Summary = unknown> {\n goal: string\n initialState: State\n propose: ProposeFn<State, Summary>\n verify: VerifyFn<State>\n review: ReviewFn<State, Summary>\n maxShots?: number\n maxWallMs?: number\n memory?: ReviewMemoryStore\n store?: TraceStore\n scenarioId?: string\n projectId?: string\n variantId?: string\n fallbackInstruction?: string\n confidenceFloor?: number\n confidenceFloorWindow?: number\n failureClassFromVerification?: (verification: Verification) => FailureClass | undefined\n actionFailure?: ControlRuntimeConfig<\n ProposeReviewControlState<State, Summary>,\n ProposeReviewControlAction,\n ProposeReviewControlResult<State, Summary>\n >['actionFailure']\n}\n\nconst DEFAULT_FALLBACK_INSTRUCTION =\n 'Inspect the verification failures above. Fix the critical issues first, then the major ones. Do not restate the failures — act on them.'\n\nexport async function runProposeReviewAsControlLoop<State, Summary = unknown>(\n config: ProposeReviewControlConfig<State, Summary>,\n): Promise<\n ControlRunResult<\n ProposeReviewControlState<State, Summary>,\n ProposeReviewControlAction,\n ProposeReviewControlResult<State, Summary>\n >\n> {\n const maxShots = config.maxShots ?? 10\n const confidenceFloor = config.confidenceFloor ?? 0.3\n const confidenceFloorWindow = config.confidenceFloorWindow ?? 2\n const memory = config.memory ?? inMemoryReviewStore()\n const fallbackInstruction = config.fallbackInstruction ?? DEFAULT_FALLBACK_INSTRUCTION\n const failureClassFromVerification =\n config.failureClassFromVerification ?? controlFailureClassFromVerification\n let lowConfidenceStreak = 0\n\n let current: ProposeReviewControlState<State, Summary> = {\n shot: 0,\n state: config.initialState,\n priorReview: null,\n verification: { pass: false },\n memory: await memory.load(),\n completed: false,\n reviewAvailable: false,\n }\n\n return runAgentControlLoop({\n intent: config.goal,\n budget: { maxSteps: maxShots, maxWallMs: config.maxWallMs },\n store: config.store,\n scenarioId: config.scenarioId ?? 'propose-review-control',\n projectId: config.projectId,\n variantId: config.variantId,\n actionFailure: config.actionFailure ?? 'stop',\n observe: () => current,\n validate: ({ state }) => [\n objectiveEval({\n id: 'verification',\n passed: state.verification.pass,\n score: state.verification.score,\n severity: 'critical',\n detail: state.verification.pass\n ? 'verification passed'\n : `verification failed${state.verification.failingLayers?.length ? `: ${state.verification.failingLayers.join(', ')}` : ''}`,\n }),\n ],\n shouldStop: ({ state }) => {\n if (state.verification.pass) {\n return {\n stop: true,\n pass: true,\n reason: 'verification passed',\n score: state.verification.score,\n }\n }\n if (state.completed) {\n return {\n stop: true,\n pass: false,\n reason: 'reviewer stopped continuation',\n score: state.verification.score,\n failureClass: failureClassFromVerification(state.verification),\n }\n }\n return {\n stop: false,\n pass: false,\n reason: 'verification still failing',\n score: state.verification.score,\n }\n },\n decide: ({ state }) => ({\n type: 'continue',\n action: { type: 'propose-review-shot', shot: state.shot + 1 },\n reason: state.priorReview?.nextShotInstruction ?? fallbackInstruction,\n }),\n act: async (action, ctx) => {\n const shot = action.shot\n const proposeOut: ProposeOutput<State, Summary> = await config.propose({\n shot,\n goal: config.goal,\n state: current.state,\n priorReview: current.priorReview,\n abortSignal: ctx.abortSignal,\n emitter: ctx.emitter,\n })\n\n const nextState = proposeOut.state\n const verification = await config.verify(nextState)\n let review: Review | null = null\n let reviewAvailable = false\n let reviewError: string | undefined\n let shouldContinue = !verification.pass\n\n if (!verification.pass) {\n try {\n review = await config.review({\n shot,\n goal: config.goal,\n state: nextState,\n verification,\n traceSummary: proposeOut.traceSummary,\n memory: await memory.load(),\n })\n reviewAvailable = true\n shouldContinue = review.shouldContinue\n lowConfidenceStreak = review.confidence <= confidenceFloor ? lowConfidenceStreak + 1 : 0\n if (confidenceFloorWindow > 0 && lowConfidenceStreak >= confidenceFloorWindow)\n shouldContinue = false\n } catch (err) {\n reviewError = err instanceof Error ? err.message : String(err)\n review = current.priorReview ?? {\n observations: 'Reviewer unavailable.',\n diagnosis: reviewError,\n nextShotInstruction: fallbackInstruction,\n shouldContinue: true,\n confidence: 0,\n }\n shouldContinue = true\n }\n } else {\n review = {\n observations: 'Verification passed.',\n diagnosis: 'No further revision needed.',\n nextShotInstruction: '',\n shouldContinue: false,\n confidence: 1,\n }\n }\n\n const entry: ReviewMemoryEntry = {\n ...(review ?? {\n observations: 'No review.',\n diagnosis: '',\n nextShotInstruction: fallbackInstruction,\n shouldContinue,\n confidence: 0,\n }),\n shot,\n timestamp: Date.now(),\n verification: {\n pass: verification.pass,\n score: verification.score,\n failingLayers: verification.failingLayers,\n },\n }\n await memory.append(entry)\n\n current = {\n shot,\n state: nextState,\n priorReview: review,\n verification,\n traceSummary: proposeOut.traceSummary,\n memory: await memory.load(),\n completed: verification.pass || !shouldContinue,\n reviewAvailable,\n reviewError,\n }\n\n return {\n state: nextState,\n verification,\n traceSummary: proposeOut.traceSummary,\n review,\n reviewAvailable,\n reviewError,\n }\n },\n })\n}\n\nexport function controlFailureClassFromVerification(\n verification: Verification,\n): FailureClass | undefined {\n if (verification.pass) return undefined\n return verification.failingLayers?.length ? 'instruction_following' : 'unknown'\n}\n"],"mappings":"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","names":["step","DEFAULT_FALLBACK_INSTRUCTION"]}
@@ -1,8 +1,57 @@
1
- import {
2
- isJudgeSpan,
3
- isLlmSpan,
4
- isToolSpan
5
- } from "./chunk-5BKGXME7.js";
1
+ // src/trace/schema.ts
2
+ var TRACE_SCHEMA_VERSION = "1.0.0";
3
+ var FAILURE_CLASSES = [
4
+ "success",
5
+ "reasoning_error",
6
+ "tool_selection_error",
7
+ "tool_argument_error",
8
+ "tool_recovery_failure",
9
+ "hallucination",
10
+ "instruction_following",
11
+ "safety_refusal_miss",
12
+ "policy_violation",
13
+ "budget_exceeded",
14
+ "format_drift",
15
+ "permission_escalation",
16
+ "pii_leak",
17
+ "cost_overrun",
18
+ "timeout",
19
+ "sandbox_failure",
20
+ "missing_user_data",
21
+ "missing_domain_data",
22
+ "missing_codebase_context",
23
+ "missing_runtime_context",
24
+ "missing_credentials",
25
+ "missing_integration_connection",
26
+ "missing_integration_scope",
27
+ "integration_approval_required",
28
+ "integration_auth_expired",
29
+ "integration_provider_failure",
30
+ "bad_integration_manifest",
31
+ "unsafe_integration_write_denied",
32
+ "stale_external_data",
33
+ "bad_retrieval",
34
+ "insufficient_evidence",
35
+ "contradictory_evidence",
36
+ "ambiguous_user_intent",
37
+ "knowledge_readiness_blocked",
38
+ "unknown"
39
+ ];
40
+ function isLlmSpan(s) {
41
+ return s.kind === "llm";
42
+ }
43
+ function isToolSpan(s) {
44
+ return s.kind === "tool";
45
+ }
46
+ function isRetrievalSpan(s) {
47
+ return s.kind === "retrieval";
48
+ }
49
+ function isJudgeSpan(s) {
50
+ return s.kind === "judge";
51
+ }
52
+ function isSandboxSpan(s) {
53
+ return s.kind === "sandbox";
54
+ }
6
55
 
7
56
  // src/trace/query.ts
8
57
  async function runsForScenario(store, scenarioId) {
@@ -67,6 +116,13 @@ function runFailureClass(run) {
67
116
  }
68
117
 
69
118
  export {
119
+ TRACE_SCHEMA_VERSION,
120
+ FAILURE_CLASSES,
121
+ isLlmSpan,
122
+ isToolSpan,
123
+ isRetrievalSpan,
124
+ isJudgeSpan,
125
+ isSandboxSpan,
70
126
  runsForScenario,
71
127
  llmSpans,
72
128
  toolSpans,
@@ -76,4 +132,4 @@ export {
76
132
  aggregateLlm,
77
133
  runFailureClass
78
134
  };
79
- //# sourceMappingURL=chunk-JZXGWLK5.js.map
135
+ //# sourceMappingURL=chunk-MHNQWM4I.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/trace/schema.ts","../src/trace/query.ts"],"sourcesContent":["/**\n * TraceSchema v1 — the canonical data model for agent-eval.\n *\n * Every score, every failure class, every pipeline in the framework is\n * a view over this data. Shape it once, live with it.\n *\n * Wire-compatible with OpenTelemetry span semantics (see trace/otel.ts)\n * but extended with agent-specific span kinds (llm, tool, retrieval,\n * judge, sandbox) and first-class BudgetLedger / Artifact / JudgeVerdict\n * entities that OTEL leaves as free-form attributes.\n */\n\nexport const TRACE_SCHEMA_VERSION = '1.0.0'\n\n// ── Run ──────────────────────────────────────────────────────────────\n\nexport type RunStatus = 'running' | 'completed' | 'failed' | 'aborted'\n\nexport interface BudgetSpec {\n tokens?: number\n wallMs?: number\n calls?: number\n usd?: number\n}\n\nexport interface RunOutcome {\n score?: number\n pass?: boolean\n failureClass?: FailureClass\n notes?: string\n}\n\n/**\n * Layer — optional classification in a nested build workflow.\n * `builder`: the meta-agent editing a project (e.g. agent-builder Forge chat).\n * `app-build`: sandbox harness that compiled + tested the generated scaffold.\n * `app-runtime`: a run of the generated agent against a domain scenario.\n * `meta`: any meta-eval (judge replay, correlation analysis).\n */\nexport type RunLayer = 'builder' | 'app-build' | 'app-runtime' | 'meta' | 'custom'\n\nexport interface Run {\n runId: string\n /**\n * Stable identifier of the scenario being executed.\n *\n * Always populated on the persisted Run — but `TraceEmitter.startRun` accepts\n * input WITHOUT this field, substituting a sensible default\n * (`run.layer ?? run.tags?.['kind'] ?? 'runtime'`) when the caller has no\n * curated scenario to anchor to (runtime / operator / meta-eval runs). This\n * keeps the persisted shape unambiguous for downstream filters + aggregations\n * while removing the boilerplate of inventing placeholder ids at the call site.\n */\n scenarioId: string\n variantId?: string\n datasetVersion?: string\n /** Git SHA of agent code at run time. */\n codeSha?: string\n /** Hash of the prompt template + any system prompt. */\n promptSha?: string\n /** Model id + date + system-prompt hash, concatenated. */\n modelFingerprint?: string\n seed?: number\n /** Arbitrary environment markers (shell, docker version, tz). */\n envFingerprint?: Record<string, string>\n /** Version of the redaction rules applied to this run. */\n redactionVersion?: string\n /** Parent run in a nested build workflow. A builder run's children are\n * app-build runs; those children are app-runtime runs. */\n parentRunId?: string\n /** Stable project identifier — groups runs across chats + sessions. */\n projectId?: string\n /** Chat/conversation identifier within a project. */\n chatId?: string\n /** Layer classification — hint for aggregation; not enforced. */\n layer?: RunLayer\n startedAt: number\n endedAt?: number\n status: RunStatus\n outcome?: RunOutcome\n budget?: BudgetSpec\n /** Free-form labels for downstream grouping. */\n tags?: Record<string, string>\n}\n\n// ── Spans (hierarchical work units) ──────────────────────────────────\n\nexport type SpanKind = 'agent' | 'llm' | 'tool' | 'retrieval' | 'judge' | 'sandbox' | 'custom'\n\nexport type SpanStatus = 'ok' | 'error'\n\nexport interface SpanBase {\n spanId: string\n parentSpanId?: string\n runId: string\n kind: SpanKind\n name: string\n startedAt: number\n endedAt?: number\n status?: SpanStatus\n error?: string\n /** Anything not covered by typed fields. Kept deliberately free-form. */\n attributes?: Record<string, unknown>\n}\n\nexport interface Message {\n role: 'system' | 'user' | 'assistant' | 'tool'\n content: string\n tokens?: number\n /** Multi-modal content descriptors; blobs themselves live in Artifacts. */\n images?: Array<{ artifactId?: string; url?: string; mime?: string }>\n}\n\nexport interface LlmSpan extends SpanBase {\n kind: 'llm'\n model: string\n messages: Message[]\n output?: string\n inputTokens?: number\n outputTokens?: number\n cachedTokens?: number\n reasoningTokens?: number\n costUsd?: number\n finishReason?: string\n}\n\nexport interface ToolSpan extends SpanBase {\n kind: 'tool'\n toolName: string\n args: unknown\n result?: unknown\n latencyMs?: number\n}\n\nexport interface RetrievalSpan extends SpanBase {\n kind: 'retrieval'\n query: string\n hits: Array<{ docId: string; score: number; content?: string }>\n}\n\nexport interface JudgeSpan extends SpanBase {\n kind: 'judge'\n judgeId: string\n /** Span this judgment applies to. */\n targetSpanId: string\n dimension: string\n /** Numeric score (free-range; interpretation up to the judge). */\n score: number\n rationale?: string\n evidence?: string\n}\n\nexport interface SandboxSpan extends SpanBase {\n kind: 'sandbox'\n image?: string\n command?: string\n exitCode?: number\n testsTotal?: number\n testsPassed?: number\n stdoutHash?: string\n stderrHash?: string\n /** Duration in ms; the harness fills this explicitly (endedAt - startedAt may miss setup). */\n wallMs?: number\n}\n\nexport interface GenericSpan extends SpanBase {\n kind: 'agent' | 'custom'\n}\n\nexport type Span = LlmSpan | ToolSpan | RetrievalSpan | JudgeSpan | SandboxSpan | GenericSpan\n\n// ── Events (point-in-time occurrences within a span) ─────────────────\n\nexport type EventKind =\n | 'log'\n | 'error'\n | 'budget_decrement'\n | 'budget_breach'\n | 'state_mutation'\n | 'policy_violation'\n | 'redaction_applied'\n | 'custom'\n\nexport interface TraceEvent {\n eventId: string\n runId: string\n spanId?: string\n kind: EventKind\n timestamp: number\n payload: Record<string, unknown>\n}\n\n// ── Budget ledger (running token/wall/call/$ accounting) ─────────────\n\nexport interface BudgetLedgerEntry {\n runId: string\n dimension: keyof BudgetSpec\n limit: number\n consumed: number\n remaining: number\n timestamp: number\n breached: boolean\n /** Span that triggered this entry, if any. */\n spanId?: string\n}\n\n// ── Artifacts (blobs addressed by hash) ──────────────────────────────\n\nexport interface Artifact {\n artifactId: string\n runId: string\n spanId?: string\n contentType: string\n sizeBytes: number\n /** sha256 in hex. */\n hash: string\n /** External storage URL (R2, S3, filesystem path). */\n storageUrl?: string\n /** Inline content for small blobs — keep under ~64KB. */\n inlineContent?: string\n}\n\n// ── Failure taxonomy ─────────────────────────────────────────────────\n\nexport type FailureClass =\n | 'success'\n | 'reasoning_error'\n | 'tool_selection_error'\n | 'tool_argument_error'\n | 'tool_recovery_failure'\n | 'hallucination'\n | 'instruction_following'\n | 'safety_refusal_miss'\n | 'policy_violation'\n | 'budget_exceeded'\n | 'format_drift'\n | 'permission_escalation'\n | 'pii_leak'\n | 'cost_overrun'\n | 'timeout'\n | 'sandbox_failure'\n | 'missing_user_data'\n | 'missing_domain_data'\n | 'missing_codebase_context'\n | 'missing_runtime_context'\n | 'missing_credentials'\n | 'missing_integration_connection'\n | 'missing_integration_scope'\n | 'integration_approval_required'\n | 'integration_auth_expired'\n | 'integration_provider_failure'\n | 'bad_integration_manifest'\n | 'unsafe_integration_write_denied'\n | 'stale_external_data'\n | 'bad_retrieval'\n | 'insufficient_evidence'\n | 'contradictory_evidence'\n | 'ambiguous_user_intent'\n | 'knowledge_readiness_blocked'\n | 'unknown'\n\nexport const FAILURE_CLASSES: readonly FailureClass[] = [\n 'success',\n 'reasoning_error',\n 'tool_selection_error',\n 'tool_argument_error',\n 'tool_recovery_failure',\n 'hallucination',\n 'instruction_following',\n 'safety_refusal_miss',\n 'policy_violation',\n 'budget_exceeded',\n 'format_drift',\n 'permission_escalation',\n 'pii_leak',\n 'cost_overrun',\n 'timeout',\n 'sandbox_failure',\n 'missing_user_data',\n 'missing_domain_data',\n 'missing_codebase_context',\n 'missing_runtime_context',\n 'missing_credentials',\n 'missing_integration_connection',\n 'missing_integration_scope',\n 'integration_approval_required',\n 'integration_auth_expired',\n 'integration_provider_failure',\n 'bad_integration_manifest',\n 'unsafe_integration_write_denied',\n 'stale_external_data',\n 'bad_retrieval',\n 'insufficient_evidence',\n 'contradictory_evidence',\n 'ambiguous_user_intent',\n 'knowledge_readiness_blocked',\n 'unknown',\n] as const\n\n// ── Helpers ──────────────────────────────────────────────────────────\n\nexport function isLlmSpan(s: Span): s is LlmSpan {\n return s.kind === 'llm'\n}\nexport function isToolSpan(s: Span): s is ToolSpan {\n return s.kind === 'tool'\n}\nexport function isRetrievalSpan(s: Span): s is RetrievalSpan {\n return s.kind === 'retrieval'\n}\nexport function isJudgeSpan(s: Span): s is JudgeSpan {\n return s.kind === 'judge'\n}\nexport function isSandboxSpan(s: Span): s is SandboxSpan {\n return s.kind === 'sandbox'\n}\n","/**\n * Typed query helpers over TraceStore.\n *\n * Not a full SQL engine — a minimal, composable set of operators that\n * cover the canned-pipeline use cases. For ad-hoc analytics, persist to\n * NDJSON and point DuckDB at it; the schema is stable so external SQL\n * tooling works out of the box.\n */\n\nimport type { FailureClass, JudgeSpan, LlmSpan, Run, ToolSpan } from './schema'\nimport { isJudgeSpan, isLlmSpan, isToolSpan } from './schema'\nimport type { TraceStore } from './store'\n\nexport async function runsForScenario(store: TraceStore, scenarioId: string): Promise<Run[]> {\n return store.listRuns({ scenarioId })\n}\n\nexport async function llmSpans(store: TraceStore, runId?: string): Promise<LlmSpan[]> {\n const spans = await store.spans({ runId, kind: 'llm' })\n return spans.filter(isLlmSpan)\n}\n\nexport async function toolSpans(\n store: TraceStore,\n runId?: string,\n toolName?: string,\n): Promise<ToolSpan[]> {\n const spans = await store.spans({ runId, kind: 'tool', toolName })\n return spans.filter(isToolSpan)\n}\n\n/** Query judge-kind spans from the trace store, optionally scoped to a single run. */\nexport async function judgeSpans(store: TraceStore, runId?: string): Promise<JudgeSpan[]> {\n const spans = await store.spans({ runId, kind: 'judge' })\n return spans.filter(isJudgeSpan)\n}\n\n/** Group spans by any key selector. */\nexport function groupBy<T, K extends string | number>(items: T[], key: (t: T) => K): Map<K, T[]> {\n const map = new Map<K, T[]>()\n for (const item of items) {\n const k = key(item)\n let bucket = map.get(k)\n if (!bucket) {\n bucket = []\n map.set(k, bucket)\n }\n bucket.push(item)\n }\n return map\n}\n\n/** Hash tool arguments to an orderless-key-stable string for de-duplication. */\nexport function argHash(args: unknown): string {\n return stableStringify(args)\n}\n\nfunction stableStringify(value: unknown): string {\n // Must ALWAYS return a string: JSON.stringify(undefined) — and stringify of\n // functions/symbols — yields the JS value `undefined`, which would make\n // argHash return a non-string and silently break the de-dup keys behind\n // stuck-loop and failure-cluster.\n if (value === undefined) return 'undefined'\n if (value === null || typeof value !== 'object') return JSON.stringify(value) ?? 'undefined'\n if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`\n // Drop undefined-valued keys to match JSON.stringify semantics, so\n // `{a:1}` and `{a:1,b:undefined}` hash identically.\n const obj = value as Record<string, unknown>\n const keys = Object.keys(obj)\n .filter((k) => obj[k] !== undefined)\n .sort()\n const parts = keys.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`)\n return `{${parts.join(',')}}`\n}\n\n/** Sum an LLM-span array into aggregate token + cost. */\nexport function aggregateLlm(spans: LlmSpan[]): {\n inputTokens: number\n outputTokens: number\n cachedTokens: number\n reasoningTokens: number\n costUsd: number\n} {\n return spans.reduce(\n (acc, s) => ({\n inputTokens: acc.inputTokens + (s.inputTokens ?? 0),\n outputTokens: acc.outputTokens + (s.outputTokens ?? 0),\n cachedTokens: acc.cachedTokens + (s.cachedTokens ?? 0),\n // reasoningTokens is on LlmSpan but was omitted here — reasoning usage was\n // invisible to any cost/perf analysis reading this aggregate.\n reasoningTokens: acc.reasoningTokens + (s.reasoningTokens ?? 0),\n costUsd: acc.costUsd + (s.costUsd ?? 0),\n }),\n { inputTokens: 0, outputTokens: 0, cachedTokens: 0, reasoningTokens: 0, costUsd: 0 },\n )\n}\n\n/** Pick the outcome's failure class when present, else derive 'success' from run status. */\nexport function runFailureClass(run: Run): FailureClass {\n if (run.outcome?.failureClass) return run.outcome.failureClass\n if (run.status === 'completed' && run.outcome?.pass !== false) return 'success'\n if (run.status === 'aborted') return 'budget_exceeded'\n return 'unknown'\n}\n"],"mappings":"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","names":[]}
@@ -1,11 +1,9 @@
1
1
  import {
2
2
  AnalystRegistry,
3
3
  DEFAULT_TRACE_ANALYST_KINDS,
4
- createTraceAnalystKind
5
- } from "./chunk-2OGPXHOB.js";
6
- import {
4
+ createTraceAnalystKind,
7
5
  makeFinding
8
- } from "./chunk-45EEMHTC.js";
6
+ } from "./chunk-7NX6ZSBG.js";
9
7
  import {
10
8
  LLM_INPUT_TOKEN_ATTR_KEYS,
11
9
  LLM_OUTPUT_TOKEN_ATTR_KEYS,
@@ -204,4 +202,4 @@ export {
204
202
  behavioralAnalyst,
205
203
  buildDefaultAnalystRegistry
206
204
  };
207
- //# sourceMappingURL=chunk-QRVS7MX4.js.map
205
+ //# sourceMappingURL=chunk-OW47B5WA.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/trace-analyst/behavioral-metrics.ts","../src/analyst/behavioral-analyst.ts","../src/analyst/default-registry.ts"],"sourcesContent":["/**\n * Deterministic behavioral metrics over OTLP spans — pure arithmetic, no LLM.\n *\n * These are the model-independent multiplier: the four trace-quality signals a\n * tolerant analyzer (e.g. HALO) re-derives per run inside the model — token\n * growth, output decay, tool monoculture, missing self-verification — computed\n * here once, in TypeScript, with zero model judgment. A finding that falls out\n * of arithmetic is trivially model-agnostic and cannot hallucinate the trend.\n *\n * General, not trace-specific: the detectors key off token trajectories and\n * tool usage present in any agentic OTLP trace, not any one benchmark.\n */\n\nimport {\n LLM_INPUT_TOKEN_ATTR_KEYS,\n LLM_OUTPUT_TOKEN_ATTR_KEYS,\n TOOL_NAME_ATTR_KEYS,\n} from '../trace/otlp-attributes'\nimport type { TraceAnalystSpan } from './types'\n\nexport type SuboptimalCode =\n | 'monotonic-input-growth'\n | 'output-length-decay'\n | 'single-tool-dependency'\n | 'no-self-verification'\n\nexport interface SuboptimalSignal {\n code: SuboptimalCode\n severity: 'high' | 'medium' | 'low'\n /** Human-readable claim, with the backing numbers inlined. */\n detail: string\n /** The exact figures the detector fired on — auditable, no model in the loop. */\n evidence: Record<string, number | string | boolean>\n}\n\nexport interface BehavioralMetrics {\n llmCallCount: number\n inputTokenTrajectory: number[]\n outputTokenTrajectory: number[]\n toolHistogram: Record<string, number>\n totalToolCalls: number\n distinctTools: number\n /** distinct/total tool calls; 1.0 when there are no tool calls. */\n toolDiversityRatio: number\n hasSelfVerification: boolean\n signals: SuboptimalSignal[]\n}\n\n/** ≥ this input-token growth ratio across a run, with no compression, fires. */\nconst INPUT_GROWTH_FACTOR = 3\n/** Tool-usage signals need at least this many calls to be meaningful. */\nconst MIN_TOOL_CALLS = 3\n/** Tool names that read or check state count as self-verification, not mutation.\n * Covers the inspect verbs plus the read/search tools real harnesses use to\n * verify (Claude Code Read/Grep/Glob, codex read_file/ls/cat, git status/diff,\n * test/lint). A pure shell tool (Bash/exec_command) is intentionally NOT matched\n * — its name can't tell a `pytest` from an `rm`. */\nconst VERIFY_RE =\n /verif|eval|inspect|check|assert|validat|review|confirm|read|grep|glob|search|view|\\blist\\b|\\bls\\b|\\bcat\\b|\\bfind\\b|diff|status|\\btest|lint|typecheck/i\n\nfunction num(v: unknown): number | null {\n return typeof v === 'number' && Number.isFinite(v) ? v : null\n}\nfunction numAttr(attrs: Record<string, unknown>, keys: readonly string[]): number | null {\n for (const key of keys) {\n const value = num(attrs[key])\n if (value !== null) return value\n }\n return null\n}\nfunction inputTokensOf(s: TraceAnalystSpan): number | null {\n return (\n numAttr(s.attributes, LLM_INPUT_TOKEN_ATTR_KEYS) ?? num(s.attributes['llm.usage.input_tokens'])\n )\n}\nfunction outputTokensOf(s: TraceAnalystSpan): number | null {\n return (\n numAttr(s.attributes, LLM_OUTPUT_TOKEN_ATTR_KEYS) ??\n num(s.attributes['llm.usage.output_tokens'])\n )\n}\nfunction stepOf(s: TraceAnalystSpan): number | null {\n return num(s.attributes.step)\n}\nfunction toolNameOf(s: TraceAnalystSpan): string | null {\n if (s.tool_name) return s.tool_name\n for (const key of TOOL_NAME_ATTR_KEYS) {\n const t = s.attributes[key]\n if (typeof t === 'string' && t.length > 0) return t\n }\n return null\n}\n\n/**\n * Reduce a span list to behavioral metrics + fired suboptimality signals.\n * Pure + deterministic: same spans → same output, on any machine, no model.\n */\nexport function computeTraceMetrics(spans: readonly TraceAnalystSpan[]): BehavioralMetrics {\n // Order by step (when present) then start_time so trajectories reflect run order.\n const ordered = [...spans].sort((a, b) => {\n const sa = stepOf(a)\n const sb = stepOf(b)\n if (sa !== null && sb !== null && sa !== sb) return sa - sb\n return a.start_time.localeCompare(b.start_time)\n })\n\n const inputTokenTrajectory: number[] = []\n const outputTokenTrajectory: number[] = []\n const toolHistogram: Record<string, number> = {}\n let hasSelfVerification = false\n\n for (const s of ordered) {\n const inT = inputTokensOf(s)\n if (inT !== null) inputTokenTrajectory.push(inT)\n const outT = outputTokensOf(s)\n if (outT !== null) outputTokenTrajectory.push(outT)\n const tool = toolNameOf(s)\n if (tool) {\n toolHistogram[tool] = (toolHistogram[tool] ?? 0) + 1\n if (VERIFY_RE.test(tool)) hasSelfVerification = true\n }\n }\n\n const totalToolCalls = Object.values(toolHistogram).reduce((a, b) => a + b, 0)\n const distinctTools = Object.keys(toolHistogram).length\n const toolDiversityRatio = totalToolCalls === 0 ? 1 : distinctTools / totalToolCalls\n\n const signals: SuboptimalSignal[] = []\n\n if (inputTokenTrajectory.length >= 3) {\n const first = inputTokenTrajectory[0]!\n const last = inputTokenTrajectory[inputTokenTrajectory.length - 1]!\n // first === 0 with later growth is an unbounded ratio (0→huge context blowup);\n // treat it as infinite so the signal fires, and report it as such instead of\n // dividing by zero for the displayed factor.\n const growthFromZero = first === 0 && last > 0\n const growth = growthFromZero ? Infinity : first > 0 ? last / first : 0\n if (last > first && growth >= INPUT_GROWTH_FACTOR) {\n const growthLabel = growthFromZero ? '0→nonzero (unbounded)' : `${growth.toFixed(1)}x`\n signals.push({\n code: 'monotonic-input-growth',\n severity: 'high',\n detail: `LLM input tokens grew ${growthLabel} (${first}→${last}) across ${inputTokenTrajectory.length} calls — full history re-sent each step with no compression.`,\n evidence: {\n first,\n last,\n growth_x: growthFromZero ? 'unbounded' : Number(growth.toFixed(2)),\n calls: inputTokenTrajectory.length,\n },\n })\n }\n }\n\n if (outputTokenTrajectory.length >= 3) {\n const first = outputTokenTrajectory[0]!\n const last = outputTokenTrajectory[outputTokenTrajectory.length - 1]!\n if (last < first) {\n signals.push({\n code: 'output-length-decay',\n severity: 'medium',\n detail: `LLM output tokens shrank ${first}→${last} over ${outputTokenTrajectory.length} calls — less planning/reasoning per step as context grows.`,\n evidence: { first, last, calls: outputTokenTrajectory.length },\n })\n }\n }\n\n if (totalToolCalls >= MIN_TOOL_CALLS && distinctTools === 1) {\n const only = Object.keys(toolHistogram)[0]!\n signals.push({\n code: 'single-tool-dependency',\n severity: 'medium',\n detail: `All ${totalToolCalls} tool calls are \\`${only}\\` — no tool diversity and no fallback path.`,\n evidence: { tool: only, calls: totalToolCalls, distinct_tools: 1 },\n })\n }\n\n if (totalToolCalls >= MIN_TOOL_CALLS && !hasSelfVerification) {\n signals.push({\n code: 'no-self-verification',\n severity: 'medium',\n detail: `${totalToolCalls} tool calls and none verify/inspect/check state — the agent never validates its own actions.`,\n evidence: { tool_calls: totalToolCalls, verification_calls: 0 },\n })\n }\n\n return {\n llmCallCount: inputTokenTrajectory.length,\n inputTokenTrajectory,\n outputTokenTrajectory,\n toolHistogram,\n totalToolCalls,\n distinctTools,\n toolDiversityRatio,\n hasSelfVerification,\n signals,\n }\n}\n","/**\n * `behavioralAnalyst` — a DETERMINISTIC analyst (cost.kind = 'deterministic',\n * never calls the LLM). It produces the efficiency/behavioral findings a\n * tolerant agentic analyzer (HALO) re-derives per run inside the model —\n * context bloat, output decay, tool monoculture, missing self-verification —\n * directly from arithmetic over spans (`computeTraceMetrics`).\n *\n * Why it matters: these findings are model-agnostic BY CONSTRUCTION (no model\n * in the loop), so they cannot return 0 on a weak model the way the Ax-RLM\n * does — and they are strictly more reliable than HALO, which spends tokens\n * re-deriving the same numbers and can hallucinate the trend. The agentic\n * RLM kinds remain for SEMANTIC findings that genuinely need a model; this\n * analyst owns the behavioral class.\n */\n\nimport {\n type BehavioralMetrics,\n computeTraceMetrics,\n type SuboptimalCode,\n} from '../trace-analyst/behavioral-metrics'\nimport type { TraceAnalysisStore } from '../trace-analyst/store'\nimport type { TraceAnalystSpan } from '../trace-analyst/types'\nimport { type Analyst, type AnalystFinding, makeFinding } from './types'\n\nconst RECOMMENDED_ACTION: Record<SuboptimalCode, string> = {\n 'monotonic-input-growth':\n 'Add a context-budget instruction: once prior context exceeds a threshold, summarize earlier steps into a short status line instead of re-sending full history.',\n 'output-length-decay':\n 'Require a minimum planning/reasoning budget per step so late steps do not degrade into terse, error-prone commands.',\n 'single-tool-dependency':\n 'Direct the agent to use the full toolset (verify / inspect / alternate actions), not a single execute call, and to plan a fallback when a call returns an unexpected result.',\n 'no-self-verification':\n 'After every state-mutating action, verify the result (eval / inspect / assert) before proceeding.',\n}\n\nconst ANALYST_ID = 'efficiency-behavioral'\n\n/**\n * Map computed signals → structured AnalystFindings. Pure: no LLM, no clock\n * dependence beyond `produced_at` (overridable for deterministic tests).\n */\nexport function deriveEfficiencyFindings(\n metrics: BehavioralMetrics,\n opts: { analystId?: string; producedAt?: string } = {},\n): AnalystFinding[] {\n const analystId = opts.analystId ?? ANALYST_ID\n return metrics.signals.map((sig) =>\n makeFinding({\n analyst_id: analystId,\n area: 'efficiency',\n subject: sig.code, // kebab — passes the cluster grammar; stable key for diffFindings\n claim: sig.detail,\n severity: sig.severity,\n // Deterministic arithmetic over spans, not a model judgment → certain.\n confidence: 1,\n evidence_refs: [\n {\n kind: 'metric',\n uri: `metric://efficiency/${sig.code}`,\n excerpt: JSON.stringify(sig.evidence),\n },\n ],\n recommended_action: RECOMMENDED_ACTION[sig.code],\n metadata: { deterministic: true, evidence: sig.evidence },\n ...(opts.producedAt ? { produced_at: opts.producedAt } : {}),\n }),\n )\n}\n\n/** The deterministic behavioral/efficiency analyst (no LLM, any-model). */\nexport function behavioralAnalyst(): Analyst<TraceAnalysisStore> {\n return {\n id: ANALYST_ID,\n description:\n 'Deterministic behavioral/efficiency findings over OTLP spans — token-growth, output-decay, tool-monoculture, missing self-verification. Zero LLM; model-agnostic by construction.',\n inputKind: 'trace-store',\n cost: { kind: 'deterministic' },\n version: '1.0.0',\n async analyze(store) {\n const overview = await store.getOverview()\n const spans: TraceAnalystSpan[] = []\n for (const traceId of overview.sample_trace_ids) {\n const viewed = await store.viewTrace({ trace_id: traceId })\n if (viewed.spans) spans.push(...viewed.spans)\n }\n return deriveEfficiencyFindings(computeTraceMetrics(spans))\n },\n }\n}\n","/**\n * `buildDefaultAnalystRegistry` — the canonical analyst suite, so consumers\n * stop hand-wiring `new AnalystRegistry()` + per-kind `createTraceAnalystKind`.\n *\n * The deterministic `behavioralAnalyst` is ALWAYS registered (it needs no\n * model and is model-agnostic by construction). The agentic RLM kinds are\n * registered only when an `ai` service is supplied — so a caller with no LLM\n * still gets the full behavioral/efficiency diagnosis, and the substrate's\n * \"any model (including no model)\" guarantee holds at the suite level.\n */\n\nimport type { AxAIService } from '@ax-llm/ax'\nimport { behavioralAnalyst } from './behavioral-analyst'\nimport { createTraceAnalystKind, type TraceAnalystKindSpec } from './kind-factory'\nimport { DEFAULT_TRACE_ANALYST_KINDS } from './kinds'\nimport { AnalystRegistry, type AnalystRegistryOptions } from './registry'\n\nexport interface DefaultAnalystRegistryOptions {\n /** Ax service for the agentic RLM kinds. Omit → only the deterministic analyst. */\n ai?: AxAIService\n /** Model for the agentic kinds (falls back to the ai service default). */\n model?: string\n /** Which agentic kinds to register when `ai` is present. Default = the shipped suite. */\n kinds?: readonly TraceAnalystKindSpec[]\n /** Set false to omit the deterministic behavioral analyst (default: include). */\n includeBehavioral?: boolean\n /** Forwarded to the AnalystRegistry constructor (signal, tags, priorFindings). */\n registry?: AnalystRegistryOptions\n}\n\nexport function buildDefaultAnalystRegistry(\n opts: DefaultAnalystRegistryOptions = {},\n): AnalystRegistry {\n const registry = new AnalystRegistry(opts.registry)\n if (opts.includeBehavioral !== false) {\n registry.register(behavioralAnalyst())\n }\n if (opts.ai) {\n const kinds = opts.kinds ?? DEFAULT_TRACE_ANALYST_KINDS\n for (const spec of kinds) {\n registry.register(createTraceAnalystKind(spec, { ai: opts.ai, model: opts.model }))\n }\n }\n return registry\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/trace-analyst/behavioral-metrics.ts","../src/analyst/behavioral-analyst.ts","../src/analyst/default-registry.ts"],"sourcesContent":["/**\n * Deterministic behavioral metrics over OTLP spans — pure arithmetic, no LLM.\n *\n * These are the model-independent multiplier: the four trace-quality signals a\n * tolerant analyzer (e.g. HALO) re-derives per run inside the model — token\n * growth, output decay, tool monoculture, missing self-verification — computed\n * here once, in TypeScript, with zero model judgment. A finding that falls out\n * of arithmetic is trivially model-agnostic and cannot hallucinate the trend.\n *\n * General, not trace-specific: the detectors key off token trajectories and\n * tool usage present in any agentic OTLP trace, not any one benchmark.\n */\n\nimport {\n LLM_INPUT_TOKEN_ATTR_KEYS,\n LLM_OUTPUT_TOKEN_ATTR_KEYS,\n TOOL_NAME_ATTR_KEYS,\n} from '../trace/otlp-attributes'\nimport type { TraceAnalystSpan } from './types'\n\nexport type SuboptimalCode =\n | 'monotonic-input-growth'\n | 'output-length-decay'\n | 'single-tool-dependency'\n | 'no-self-verification'\n\nexport interface SuboptimalSignal {\n code: SuboptimalCode\n severity: 'high' | 'medium' | 'low'\n /** Human-readable claim, with the backing numbers inlined. */\n detail: string\n /** The exact figures the detector fired on — auditable, no model in the loop. */\n evidence: Record<string, number | string | boolean>\n}\n\nexport interface BehavioralMetrics {\n llmCallCount: number\n inputTokenTrajectory: number[]\n outputTokenTrajectory: number[]\n toolHistogram: Record<string, number>\n totalToolCalls: number\n distinctTools: number\n /** distinct/total tool calls; 1.0 when there are no tool calls. */\n toolDiversityRatio: number\n hasSelfVerification: boolean\n signals: SuboptimalSignal[]\n}\n\n/** ≥ this input-token growth ratio across a run, with no compression, fires. */\nconst INPUT_GROWTH_FACTOR = 3\n/** Tool-usage signals need at least this many calls to be meaningful. */\nconst MIN_TOOL_CALLS = 3\n/** Tool names that read or check state count as self-verification, not mutation.\n * Covers the inspect verbs plus the read/search tools real harnesses use to\n * verify (Claude Code Read/Grep/Glob, codex read_file/ls/cat, git status/diff,\n * test/lint). A pure shell tool (Bash/exec_command) is intentionally NOT matched\n * — its name can't tell a `pytest` from an `rm`. */\nconst VERIFY_RE =\n /verif|eval|inspect|check|assert|validat|review|confirm|read|grep|glob|search|view|\\blist\\b|\\bls\\b|\\bcat\\b|\\bfind\\b|diff|status|\\btest|lint|typecheck/i\n\nfunction num(v: unknown): number | null {\n return typeof v === 'number' && Number.isFinite(v) ? v : null\n}\nfunction numAttr(attrs: Record<string, unknown>, keys: readonly string[]): number | null {\n for (const key of keys) {\n const value = num(attrs[key])\n if (value !== null) return value\n }\n return null\n}\nfunction inputTokensOf(s: TraceAnalystSpan): number | null {\n return (\n numAttr(s.attributes, LLM_INPUT_TOKEN_ATTR_KEYS) ?? num(s.attributes['llm.usage.input_tokens'])\n )\n}\nfunction outputTokensOf(s: TraceAnalystSpan): number | null {\n return (\n numAttr(s.attributes, LLM_OUTPUT_TOKEN_ATTR_KEYS) ??\n num(s.attributes['llm.usage.output_tokens'])\n )\n}\nfunction stepOf(s: TraceAnalystSpan): number | null {\n return num(s.attributes.step)\n}\nfunction toolNameOf(s: TraceAnalystSpan): string | null {\n if (s.tool_name) return s.tool_name\n for (const key of TOOL_NAME_ATTR_KEYS) {\n const t = s.attributes[key]\n if (typeof t === 'string' && t.length > 0) return t\n }\n return null\n}\n\n/**\n * Reduce a span list to behavioral metrics + fired suboptimality signals.\n * Pure + deterministic: same spans → same output, on any machine, no model.\n */\nexport function computeTraceMetrics(spans: readonly TraceAnalystSpan[]): BehavioralMetrics {\n // Order by step (when present) then start_time so trajectories reflect run order.\n const ordered = [...spans].sort((a, b) => {\n const sa = stepOf(a)\n const sb = stepOf(b)\n if (sa !== null && sb !== null && sa !== sb) return sa - sb\n return a.start_time.localeCompare(b.start_time)\n })\n\n const inputTokenTrajectory: number[] = []\n const outputTokenTrajectory: number[] = []\n const toolHistogram: Record<string, number> = {}\n let hasSelfVerification = false\n\n for (const s of ordered) {\n const inT = inputTokensOf(s)\n if (inT !== null) inputTokenTrajectory.push(inT)\n const outT = outputTokensOf(s)\n if (outT !== null) outputTokenTrajectory.push(outT)\n const tool = toolNameOf(s)\n if (tool) {\n toolHistogram[tool] = (toolHistogram[tool] ?? 0) + 1\n if (VERIFY_RE.test(tool)) hasSelfVerification = true\n }\n }\n\n const totalToolCalls = Object.values(toolHistogram).reduce((a, b) => a + b, 0)\n const distinctTools = Object.keys(toolHistogram).length\n const toolDiversityRatio = totalToolCalls === 0 ? 1 : distinctTools / totalToolCalls\n\n const signals: SuboptimalSignal[] = []\n\n if (inputTokenTrajectory.length >= 3) {\n const first = inputTokenTrajectory[0]!\n const last = inputTokenTrajectory[inputTokenTrajectory.length - 1]!\n // first === 0 with later growth is an unbounded ratio (0→huge context blowup);\n // treat it as infinite so the signal fires, and report it as such instead of\n // dividing by zero for the displayed factor.\n const growthFromZero = first === 0 && last > 0\n const growth = growthFromZero ? Infinity : first > 0 ? last / first : 0\n if (last > first && growth >= INPUT_GROWTH_FACTOR) {\n const growthLabel = growthFromZero ? '0→nonzero (unbounded)' : `${growth.toFixed(1)}x`\n signals.push({\n code: 'monotonic-input-growth',\n severity: 'high',\n detail: `LLM input tokens grew ${growthLabel} (${first}→${last}) across ${inputTokenTrajectory.length} calls — full history re-sent each step with no compression.`,\n evidence: {\n first,\n last,\n growth_x: growthFromZero ? 'unbounded' : Number(growth.toFixed(2)),\n calls: inputTokenTrajectory.length,\n },\n })\n }\n }\n\n if (outputTokenTrajectory.length >= 3) {\n const first = outputTokenTrajectory[0]!\n const last = outputTokenTrajectory[outputTokenTrajectory.length - 1]!\n if (last < first) {\n signals.push({\n code: 'output-length-decay',\n severity: 'medium',\n detail: `LLM output tokens shrank ${first}→${last} over ${outputTokenTrajectory.length} calls — less planning/reasoning per step as context grows.`,\n evidence: { first, last, calls: outputTokenTrajectory.length },\n })\n }\n }\n\n if (totalToolCalls >= MIN_TOOL_CALLS && distinctTools === 1) {\n const only = Object.keys(toolHistogram)[0]!\n signals.push({\n code: 'single-tool-dependency',\n severity: 'medium',\n detail: `All ${totalToolCalls} tool calls are \\`${only}\\` — no tool diversity and no fallback path.`,\n evidence: { tool: only, calls: totalToolCalls, distinct_tools: 1 },\n })\n }\n\n if (totalToolCalls >= MIN_TOOL_CALLS && !hasSelfVerification) {\n signals.push({\n code: 'no-self-verification',\n severity: 'medium',\n detail: `${totalToolCalls} tool calls and none verify/inspect/check state — the agent never validates its own actions.`,\n evidence: { tool_calls: totalToolCalls, verification_calls: 0 },\n })\n }\n\n return {\n llmCallCount: inputTokenTrajectory.length,\n inputTokenTrajectory,\n outputTokenTrajectory,\n toolHistogram,\n totalToolCalls,\n distinctTools,\n toolDiversityRatio,\n hasSelfVerification,\n signals,\n }\n}\n","/**\n * `behavioralAnalyst` — a DETERMINISTIC analyst (cost.kind = 'deterministic',\n * never calls the LLM). It produces the efficiency/behavioral findings a\n * tolerant agentic analyzer (HALO) re-derives per run inside the model —\n * context bloat, output decay, tool monoculture, missing self-verification —\n * directly from arithmetic over spans (`computeTraceMetrics`).\n *\n * Why it matters: these findings are model-agnostic BY CONSTRUCTION (no model\n * in the loop), so they cannot return 0 on a weak model the way the Ax-RLM\n * does — and they are strictly more reliable than HALO, which spends tokens\n * re-deriving the same numbers and can hallucinate the trend. The agentic\n * RLM kinds remain for SEMANTIC findings that genuinely need a model; this\n * analyst owns the behavioral class.\n */\n\nimport {\n type BehavioralMetrics,\n computeTraceMetrics,\n type SuboptimalCode,\n} from '../trace-analyst/behavioral-metrics'\nimport type { TraceAnalysisStore } from '../trace-analyst/store'\nimport type { TraceAnalystSpan } from '../trace-analyst/types'\nimport { type Analyst, type AnalystFinding, makeFinding } from './types'\n\nconst RECOMMENDED_ACTION: Record<SuboptimalCode, string> = {\n 'monotonic-input-growth':\n 'Add a context-budget instruction: once prior context exceeds a threshold, summarize earlier steps into a short status line instead of re-sending full history.',\n 'output-length-decay':\n 'Require a minimum planning/reasoning budget per step so late steps do not degrade into terse, error-prone commands.',\n 'single-tool-dependency':\n 'Direct the agent to use the full toolset (verify / inspect / alternate actions), not a single execute call, and to plan a fallback when a call returns an unexpected result.',\n 'no-self-verification':\n 'After every state-mutating action, verify the result (eval / inspect / assert) before proceeding.',\n}\n\nconst ANALYST_ID = 'efficiency-behavioral'\n\n/**\n * Map computed signals → structured AnalystFindings. Pure: no LLM, no clock\n * dependence beyond `produced_at` (overridable for deterministic tests).\n */\nexport function deriveEfficiencyFindings(\n metrics: BehavioralMetrics,\n opts: { analystId?: string; producedAt?: string } = {},\n): AnalystFinding[] {\n const analystId = opts.analystId ?? ANALYST_ID\n return metrics.signals.map((sig) =>\n makeFinding({\n analyst_id: analystId,\n area: 'efficiency',\n subject: sig.code, // kebab — passes the cluster grammar; stable key for diffFindings\n claim: sig.detail,\n severity: sig.severity,\n // Deterministic arithmetic over spans, not a model judgment → certain.\n confidence: 1,\n evidence_refs: [\n {\n kind: 'metric',\n uri: `metric://efficiency/${sig.code}`,\n excerpt: JSON.stringify(sig.evidence),\n },\n ],\n recommended_action: RECOMMENDED_ACTION[sig.code],\n metadata: { deterministic: true, evidence: sig.evidence },\n ...(opts.producedAt ? { produced_at: opts.producedAt } : {}),\n }),\n )\n}\n\n/** The deterministic behavioral/efficiency analyst (no LLM, any-model). */\nexport function behavioralAnalyst(): Analyst<TraceAnalysisStore> {\n return {\n id: ANALYST_ID,\n description:\n 'Deterministic behavioral/efficiency findings over OTLP spans — token-growth, output-decay, tool-monoculture, missing self-verification. Zero LLM; model-agnostic by construction.',\n inputKind: 'trace-store',\n cost: { kind: 'deterministic' },\n version: '1.0.0',\n async analyze(store) {\n const overview = await store.getOverview()\n const spans: TraceAnalystSpan[] = []\n for (const traceId of overview.sample_trace_ids) {\n const viewed = await store.viewTrace({ trace_id: traceId })\n if (viewed.spans) spans.push(...viewed.spans)\n }\n return deriveEfficiencyFindings(computeTraceMetrics(spans))\n },\n }\n}\n","/**\n * `buildDefaultAnalystRegistry` — the canonical analyst suite, so consumers\n * stop hand-wiring `new AnalystRegistry()` + per-kind `createTraceAnalystKind`.\n *\n * The deterministic `behavioralAnalyst` is ALWAYS registered (it needs no\n * model and is model-agnostic by construction). The agentic RLM kinds are\n * registered only when an `ai` service is supplied — so a caller with no LLM\n * still gets the full behavioral/efficiency diagnosis, and the substrate's\n * \"any model (including no model)\" guarantee holds at the suite level.\n */\n\nimport type { AxAIService } from '@ax-llm/ax'\nimport { behavioralAnalyst } from './behavioral-analyst'\nimport { createTraceAnalystKind, type TraceAnalystKindSpec } from './kind-factory'\nimport { DEFAULT_TRACE_ANALYST_KINDS } from './kinds'\nimport { AnalystRegistry, type AnalystRegistryOptions } from './registry'\n\nexport interface DefaultAnalystRegistryOptions {\n /** Ax service for the agentic RLM kinds. Omit → only the deterministic analyst. */\n ai?: AxAIService\n /** Model for the agentic kinds (falls back to the ai service default). */\n model?: string\n /** Which agentic kinds to register when `ai` is present. Default = the shipped suite. */\n kinds?: readonly TraceAnalystKindSpec[]\n /** Set false to omit the deterministic behavioral analyst (default: include). */\n includeBehavioral?: boolean\n /** Forwarded to the AnalystRegistry constructor (signal, tags, priorFindings). */\n registry?: AnalystRegistryOptions\n}\n\nexport function buildDefaultAnalystRegistry(\n opts: DefaultAnalystRegistryOptions = {},\n): AnalystRegistry {\n const registry = new AnalystRegistry(opts.registry)\n if (opts.includeBehavioral !== false) {\n registry.register(behavioralAnalyst())\n }\n if (opts.ai) {\n const kinds = opts.kinds ?? DEFAULT_TRACE_ANALYST_KINDS\n for (const spec of kinds) {\n registry.register(createTraceAnalystKind(spec, { ai: opts.ai, model: opts.model }))\n }\n }\n return registry\n}\n"],"mappings":"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","names":[]}
@@ -5,7 +5,7 @@ import {
5
5
  argHash,
6
6
  groupBy,
7
7
  toolSpans
8
- } from "./chunk-JZXGWLK5.js";
8
+ } from "./chunk-MHNQWM4I.js";
9
9
 
10
10
  // src/failure-taxonomy.ts
11
11
  var DEFAULT_RULES = [
@@ -394,6 +394,51 @@ async function computeToolUseMetrics(store, runId, options = {}) {
394
394
  };
395
395
  }
396
396
 
397
+ // src/trajectory.ts
398
+ async function buildTrajectory(store, runId) {
399
+ const spans = await store.spans({ runId });
400
+ const events = await store.events({ runId });
401
+ const childrenOf = /* @__PURE__ */ new Map();
402
+ for (const s of spans) {
403
+ const arr = childrenOf.get(s.parentSpanId) ?? [];
404
+ arr.push(s);
405
+ childrenOf.set(s.parentSpanId, arr);
406
+ }
407
+ for (const arr of childrenOf.values()) arr.sort((a, b) => a.startedAt - b.startedAt);
408
+ const eventsBySpan = /* @__PURE__ */ new Map();
409
+ for (const e of events) {
410
+ if (!e.spanId) continue;
411
+ const arr = eventsBySpan.get(e.spanId) ?? [];
412
+ arr.push(e);
413
+ eventsBySpan.set(e.spanId, arr);
414
+ }
415
+ const steps = [];
416
+ const walk = (spanId, depth) => {
417
+ const kids = childrenOf.get(spanId) ?? [];
418
+ for (const child of kids) {
419
+ steps.push({
420
+ index: steps.length,
421
+ span: child,
422
+ depth,
423
+ events: eventsBySpan.get(child.spanId) ?? []
424
+ });
425
+ walk(child.spanId, depth + 1);
426
+ }
427
+ };
428
+ walk(void 0, 0);
429
+ const llmTurns = steps.filter((s) => s.span.kind === "llm").length;
430
+ const toolCalls = steps.filter((s) => s.span.kind === "tool").length;
431
+ const judgeVerdicts = steps.filter((s) => s.span.kind === "judge").length;
432
+ const retrievals = steps.filter((s) => s.span.kind === "retrieval").length;
433
+ let totalDurationMs = 0;
434
+ if (steps.length > 0) {
435
+ const starts = spans.map((s) => s.startedAt);
436
+ const ends = spans.map((s) => s.endedAt ?? s.startedAt);
437
+ totalDurationMs = Math.max(...ends) - Math.min(...starts);
438
+ }
439
+ return { runId, steps, llmTurns, toolCalls, judgeVerdicts, retrievals, totalDurationMs };
440
+ }
441
+
397
442
  // src/baseline.ts
398
443
  function compareToBaseline(samples, options = {}) {
399
444
  const effectThreshold = options.effectThreshold ?? 0.5;
@@ -548,8 +593,9 @@ export {
548
593
  DEFAULT_RULES,
549
594
  classifyFailure,
550
595
  computeToolUseMetrics,
596
+ buildTrajectory,
551
597
  compareToBaseline,
552
598
  iqr,
553
599
  welchsTTest
554
600
  };
555
- //# sourceMappingURL=chunk-DBDRR6GF.js.map
601
+ //# sourceMappingURL=chunk-PLOMR3HP.js.map