@tangle-network/agent-eval 0.126.6 → 0.127.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 (129) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +2 -2
  3. package/dist/analyst/index.d.ts +52 -40
  4. package/dist/analyst/index.js +4 -4
  5. package/dist/belief-state/index.d.ts +34 -36
  6. package/dist/belief-state/index.js +2 -2
  7. package/dist/benchmarks/index.d.ts +30 -12
  8. package/dist/benchmarks/index.js +12 -10
  9. package/dist/builder-eval/index.js +1 -1
  10. package/dist/campaign/index.d.ts +432 -146
  11. package/dist/campaign/index.js +11 -9
  12. package/dist/{chunk-ARU2PZFM.js → chunk-424XHVKV.js} +43 -23
  13. package/dist/chunk-424XHVKV.js.map +1 -0
  14. package/dist/{chunk-NUKSVU3W.js → chunk-5DTSBUL2.js} +2 -2
  15. package/dist/{chunk-BTACVO2W.js → chunk-65QETEKG.js} +542 -258
  16. package/dist/chunk-65QETEKG.js.map +1 -0
  17. package/dist/{chunk-CGG5SLH3.js → chunk-ARCFIY7U.js} +2 -2
  18. package/dist/{chunk-P22LJ3Y2.js → chunk-CLELFRQG.js} +6 -4
  19. package/dist/chunk-CLELFRQG.js.map +1 -0
  20. package/dist/{chunk-LUNF2SEL.js → chunk-DJKY2TSY.js} +3 -3
  21. package/dist/chunk-DPUHNQLN.js +232 -0
  22. package/dist/chunk-DPUHNQLN.js.map +1 -0
  23. package/dist/{chunk-IPYXE555.js → chunk-EJGRPCO3.js} +36 -13
  24. package/dist/chunk-EJGRPCO3.js.map +1 -0
  25. package/dist/{chunk-K6IAZZ6L.js → chunk-FA3MFYNA.js} +132 -110
  26. package/dist/chunk-FA3MFYNA.js.map +1 -0
  27. package/dist/chunk-IG35YDN3.js +614 -0
  28. package/dist/chunk-IG35YDN3.js.map +1 -0
  29. package/dist/{chunk-DPZAEKA6.js → chunk-IMGJZBFG.js} +84 -56
  30. package/dist/chunk-IMGJZBFG.js.map +1 -0
  31. package/dist/{chunk-H5UD2323.js → chunk-IN455XKS.js} +53 -1
  32. package/dist/chunk-IN455XKS.js.map +1 -0
  33. package/dist/{chunk-PJQFMIOX.js → chunk-MHELPNRP.js} +31 -1
  34. package/dist/chunk-MHELPNRP.js.map +1 -0
  35. package/dist/{chunk-IILEIWGW.js → chunk-NL33OXEP.js} +41 -36
  36. package/dist/chunk-NL33OXEP.js.map +1 -0
  37. package/dist/{chunk-474LBSOX.js → chunk-OD5NQ2CS.js} +41 -16
  38. package/dist/chunk-OD5NQ2CS.js.map +1 -0
  39. package/dist/{chunk-QOTFXW5L.js → chunk-P5W7RQKK.js} +2 -2
  40. package/dist/{chunk-IR3KBHOY.js → chunk-P6FYH6K4.js} +39 -3
  41. package/dist/chunk-P6FYH6K4.js.map +1 -0
  42. package/dist/{chunk-J5SQWP6Y.js → chunk-PBE2LOSS.js} +18 -2
  43. package/dist/chunk-PBE2LOSS.js.map +1 -0
  44. package/dist/{chunk-E3IADPLG.js → chunk-PRB53E3J.js} +50 -224
  45. package/dist/chunk-PRB53E3J.js.map +1 -0
  46. package/dist/{chunk-X4UCIOTZ.js → chunk-S5YLIBFX.js} +2 -2
  47. package/dist/{chunk-7VYEGHWF.js → chunk-SZLVEKMJ.js} +41 -20
  48. package/dist/chunk-SZLVEKMJ.js.map +1 -0
  49. package/dist/{chunk-LKKT3IVV.js → chunk-TSN7JT6D.js} +6 -4
  50. package/dist/{chunk-LKKT3IVV.js.map → chunk-TSN7JT6D.js.map} +1 -1
  51. package/dist/{chunk-M7AH34KV.js → chunk-UTA2TGC4.js} +32 -16
  52. package/dist/chunk-UTA2TGC4.js.map +1 -0
  53. package/dist/{chunk-MAX3TN3C.js → chunk-UWZZKKU7.js} +7 -19
  54. package/dist/chunk-UWZZKKU7.js.map +1 -0
  55. package/dist/{chunk-ZVCHKKOP.js → chunk-WED5KLZQ.js} +39 -15
  56. package/dist/chunk-WED5KLZQ.js.map +1 -0
  57. package/dist/{chunk-OCFJACJU.js → chunk-X6VOPMLD.js} +74 -14
  58. package/dist/chunk-X6VOPMLD.js.map +1 -0
  59. package/dist/{chunk-MOXWMGPC.js → chunk-Y5CYOL42.js} +159 -70
  60. package/dist/chunk-Y5CYOL42.js.map +1 -0
  61. package/dist/{chunk-FO7HEH76.js → chunk-YJBNWCAA.js} +2 -2
  62. package/dist/chunk-ZPUEEM5U.js +179 -0
  63. package/dist/chunk-ZPUEEM5U.js.map +1 -0
  64. package/dist/{chunk-KE2VWPZX.js → chunk-ZUUWPZCV.js} +3 -3
  65. package/dist/cli.js +4 -4
  66. package/dist/contract/index.d.ts +464 -126
  67. package/dist/contract/index.js +425 -211
  68. package/dist/contract/index.js.map +1 -1
  69. package/dist/control.d.ts +34 -32
  70. package/dist/control.js +2 -2
  71. package/dist/hosted/index.d.ts +142 -41
  72. package/dist/hosted/index.js +23 -1
  73. package/dist/index.d.ts +365 -256
  74. package/dist/index.js +315 -226
  75. package/dist/index.js.map +1 -1
  76. package/dist/meta-eval/index.d.ts +32 -32
  77. package/dist/meta-eval/index.js +2 -2
  78. package/dist/multishot/index.d.ts +1 -0
  79. package/dist/openapi.json +1 -1
  80. package/dist/pipelines/index.js +2 -2
  81. package/dist/reporting.d.ts +97 -74
  82. package/dist/reporting.js +5 -4
  83. package/dist/rl.d.ts +177 -131
  84. package/dist/rl.js +232 -126
  85. package/dist/rl.js.map +1 -1
  86. package/dist/rollout/index.d.ts +53 -63
  87. package/dist/rollout/index.js +7 -5
  88. package/dist/{run-campaign-FFRM3RH5.js → run-campaign-3A2EBYBE.js} +4 -3
  89. package/dist/supervisor-run/index.d.ts +7 -15
  90. package/dist/supervisor-run/index.js +2 -2
  91. package/dist/traces.d.ts +66 -41
  92. package/dist/traces.js +9 -5
  93. package/dist/wire/index.d.ts +1 -0
  94. package/dist/wire/index.js +2 -2
  95. package/docs/concepts.md +18 -1
  96. package/docs/hosted-ingest-spec.md +37 -40
  97. package/docs/insight-report.md +57 -7
  98. package/docs/research-report-methodology.md +20 -21
  99. package/docs/rollout.md +13 -8
  100. package/package.json +21 -14
  101. package/dist/chunk-474LBSOX.js.map +0 -1
  102. package/dist/chunk-7VYEGHWF.js.map +0 -1
  103. package/dist/chunk-ARU2PZFM.js.map +0 -1
  104. package/dist/chunk-BTACVO2W.js.map +0 -1
  105. package/dist/chunk-DPZAEKA6.js.map +0 -1
  106. package/dist/chunk-E3IADPLG.js.map +0 -1
  107. package/dist/chunk-H5UD2323.js.map +0 -1
  108. package/dist/chunk-IILEIWGW.js.map +0 -1
  109. package/dist/chunk-IPYXE555.js.map +0 -1
  110. package/dist/chunk-IR3KBHOY.js.map +0 -1
  111. package/dist/chunk-J5SQWP6Y.js.map +0 -1
  112. package/dist/chunk-K6IAZZ6L.js.map +0 -1
  113. package/dist/chunk-M7AH34KV.js.map +0 -1
  114. package/dist/chunk-MAX3TN3C.js.map +0 -1
  115. package/dist/chunk-MOXWMGPC.js.map +0 -1
  116. package/dist/chunk-OCFJACJU.js.map +0 -1
  117. package/dist/chunk-P22LJ3Y2.js.map +0 -1
  118. package/dist/chunk-PJQFMIOX.js.map +0 -1
  119. package/dist/chunk-ZVCHKKOP.js.map +0 -1
  120. package/dist/chunk-ZZUXHH3R.js +0 -99
  121. package/dist/chunk-ZZUXHH3R.js.map +0 -1
  122. /package/dist/{chunk-NUKSVU3W.js.map → chunk-5DTSBUL2.js.map} +0 -0
  123. /package/dist/{chunk-CGG5SLH3.js.map → chunk-ARCFIY7U.js.map} +0 -0
  124. /package/dist/{chunk-LUNF2SEL.js.map → chunk-DJKY2TSY.js.map} +0 -0
  125. /package/dist/{chunk-QOTFXW5L.js.map → chunk-P5W7RQKK.js.map} +0 -0
  126. /package/dist/{chunk-X4UCIOTZ.js.map → chunk-S5YLIBFX.js.map} +0 -0
  127. /package/dist/{chunk-FO7HEH76.js.map → chunk-YJBNWCAA.js.map} +0 -0
  128. /package/dist/{chunk-KE2VWPZX.js.map → chunk-ZUUWPZCV.js.map} +0 -0
  129. /package/dist/{run-campaign-FFRM3RH5.js.map → run-campaign-3A2EBYBE.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/agent-profile-cell.ts","../src/run-record.ts"],"sourcesContent":["import type { AgentProfile } from '@tangle-network/agent-interface'\nimport { ValidationError } from './errors'\nimport { hashJson } from './pre-registration'\n\nexport type AgentProfileCellSchemaVersion = 'agent-profile-cell/v1'\n\nexport type AgentProfileJsonObject = { [key: string]: AgentProfileJson }\n\nexport type AgentProfileJson =\n | string\n | number\n | boolean\n | null\n | AgentProfileJson[]\n | AgentProfileJsonObject\n\nexport type AgentProfileDimensionValue = string | number | boolean | null\n\nexport interface AgentProfileSource {\n /** Runtime/profile contract being fingerprinted, e.g. `agent-interface-profile`. */\n kind: string\n /** sha256 over the canonical source profile object. */\n hash: string\n}\n\nexport interface AgentProfileSourceInput {\n kind: string\n /** Precomputed sha256 for callers that already sign their profile artifact. */\n hash?: string\n /** Full canonical runtime profile; hashed and then discarded from the cell. */\n profile?: AgentProfileJson\n}\n\nexport interface AgentProfileHarness {\n id: string\n version?: string\n hash?: string\n}\n\nexport interface AgentProfileCellInput {\n profileId: string\n sourceProfile: AgentProfileSourceInput\n harness?: AgentProfileHarness\n model?: string\n promptHash?: string\n dimensions?: Record<string, AgentProfileDimensionValue>\n}\n\nexport interface AgentProfileCell {\n schemaVersion: AgentProfileCellSchemaVersion\n cellId: string\n profileId: string\n sourceProfile: AgentProfileSource\n harness?: AgentProfileHarness\n model?: string\n promptHash?: string\n dimensions?: Record<string, AgentProfileDimensionValue>\n}\n\nexport class AgentProfileCellValidationError extends ValidationError {\n readonly path: string\n constructor(message: string, path = '') {\n super(path ? `${message} (at ${path})` : message)\n this.path = path\n }\n}\n\nconst SHA256_HEX = /^[0-9a-f]{64}$/\nconst CELL_ID = /^agent-profile-cell:sha256:[0-9a-f]{64}$/\n\nexport async function buildAgentProfileCell(\n input: AgentProfileCellInput,\n): Promise<AgentProfileCell> {\n const material = await normalizeAgentProfileCellInput(input)\n const cellId = `agent-profile-cell:sha256:${await hashJson(material)}`\n return { ...material, cellId }\n}\n\nexport function agentProfileCellHashMaterial(\n cell: AgentProfileCell,\n): Omit<AgentProfileCell, 'cellId'> {\n const { cellId: _cellId, ...material } = cell\n void _cellId\n return normalizeAgentProfileCell(material)\n}\n\n/**\n * Verify an `AgentProfileCell`'s `cellId` matches the sha256 of its hash-material fields, confirming the record has not been tampered with.\n */\nexport async function verifyAgentProfileCell(cell: AgentProfileCell): Promise<boolean> {\n validateAgentProfileCell(cell)\n return (\n cell.cellId ===\n `agent-profile-cell:sha256:${await hashJson(agentProfileCellHashMaterial(cell))}`\n )\n}\n\nexport function validateAgentProfileCell(input: unknown): AgentProfileCell {\n if (input === null || typeof input !== 'object') {\n throw new AgentProfileCellValidationError('expected object')\n }\n const obj = input as Record<string, unknown>\n expectLiteral(obj.schemaVersion, 'agent-profile-cell/v1', 'schemaVersion')\n if (typeof obj.cellId !== 'string' || !CELL_ID.test(obj.cellId)) {\n throw new AgentProfileCellValidationError(\n 'cellId must match agent-profile-cell:sha256:<64 lowercase hex chars>',\n 'cellId',\n )\n }\n expectString(obj.profileId, 'profileId')\n validateSource(obj.sourceProfile, 'sourceProfile')\n if (obj.harness !== undefined) validateHarness(obj.harness, 'harness')\n if (obj.model !== undefined) expectString(obj.model, 'model')\n if (obj.promptHash !== undefined) expectString(obj.promptHash, 'promptHash')\n if (obj.dimensions !== undefined) validateDimensions(obj.dimensions, 'dimensions')\n return input as AgentProfileCell\n}\n\nexport function requireAgentProfileCell(record: {\n runId: string\n agentProfile?: AgentProfileCell\n}): AgentProfileCell {\n if (!record.agentProfile) {\n throw new AgentProfileCellValidationError(\n `run \"${record.runId}\" is missing agentProfile; profile-cell grouping requires explicit profile identity`,\n 'agentProfile',\n )\n }\n return validateAgentProfileCell(record.agentProfile)\n}\n\nexport function agentProfileCellKey(record: {\n runId: string\n agentProfile?: AgentProfileCell\n}): string {\n return requireAgentProfileCell(record).cellId\n}\n\nexport async function assertRunAgentProfileCell(record: {\n runId: string\n model: string\n promptHash: string\n agentProfile?: AgentProfileCell\n}): Promise<AgentProfileCell> {\n const profile = requireAgentProfileCell(record)\n if (!(await verifyAgentProfileCell(profile))) {\n throw new AgentProfileCellValidationError(\n `run \"${record.runId}\" has an agentProfile.cellId that does not match its content`,\n 'agentProfile.cellId',\n )\n }\n if (profile.model !== undefined && profile.model !== record.model) {\n throw new AgentProfileCellValidationError(\n `run \"${record.runId}\" agentProfile.model \"${profile.model}\" does not match model \"${record.model}\"`,\n 'agentProfile.model',\n )\n }\n if (profile.promptHash !== undefined && profile.promptHash !== record.promptHash) {\n throw new AgentProfileCellValidationError(\n `run \"${record.runId}\" agentProfile.promptHash \"${profile.promptHash}\" does not match promptHash \"${record.promptHash}\"`,\n 'agentProfile.promptHash',\n )\n }\n return profile\n}\n\nexport function groupRunsByAgentProfileCell<\n T extends { runId: string; agentProfile?: AgentProfileCell },\n>(records: readonly T[]): Map<string, T[]> {\n const groups = new Map<string, T[]>()\n for (const record of records) {\n const key = agentProfileCellKey(record)\n const bucket = groups.get(key)\n if (bucket) bucket.push(record)\n else groups.set(key, [record])\n }\n return groups\n}\n\nasync function normalizeAgentProfileCellInput(\n input: AgentProfileCellInput,\n): Promise<Omit<AgentProfileCell, 'cellId'>> {\n return normalizeAgentProfileCell({\n schemaVersion: 'agent-profile-cell/v1',\n profileId: input.profileId,\n sourceProfile: await normalizeSourceInput(input.sourceProfile),\n harness: input.harness,\n model: input.model,\n promptHash: input.promptHash,\n dimensions: input.dimensions,\n })\n}\n\nfunction normalizeAgentProfileCell(\n input: Omit<AgentProfileCell, 'cellId'>,\n): Omit<AgentProfileCell, 'cellId'> {\n return compactObject({\n schemaVersion: 'agent-profile-cell/v1' as const,\n profileId: requireNonEmpty(input.profileId, 'profileId'),\n sourceProfile: normalizeSource(input.sourceProfile),\n harness: input.harness ? normalizeHarness(input.harness, 'harness') : undefined,\n model: optionalNonEmpty(input.model, 'model'),\n promptHash: optionalNonEmpty(input.promptHash, 'promptHash'),\n dimensions: input.dimensions\n ? nonEmptyRecord(normalizeDimensions(input.dimensions))\n : undefined,\n })\n}\n\nasync function normalizeSourceInput(input: AgentProfileSourceInput): Promise<AgentProfileSource> {\n const kind = requireNonEmpty(input.kind, 'sourceProfile.kind')\n if (input.hash !== undefined && input.profile !== undefined) {\n throw new AgentProfileCellValidationError(\n 'sourceProfile must provide either hash or profile, not both',\n 'sourceProfile',\n )\n }\n if (input.hash !== undefined) {\n return { kind, hash: requireSha256Hex(input.hash, 'sourceProfile.hash') }\n }\n if (input.profile === undefined) {\n throw new AgentProfileCellValidationError(\n 'sourceProfile must provide hash or profile',\n 'sourceProfile',\n )\n }\n assertJson(input.profile, 'sourceProfile.profile')\n return { kind, hash: await hashJson(input.profile) }\n}\n\nfunction normalizeSource(input: AgentProfileSource): AgentProfileSource {\n return {\n kind: requireNonEmpty(input.kind, 'sourceProfile.kind'),\n hash: requireSha256Hex(input.hash, 'sourceProfile.hash'),\n }\n}\n\nfunction normalizeHarness(input: AgentProfileHarness, path: string): AgentProfileHarness {\n return compactObject({\n id: requireNonEmpty(input.id, `${path}.id`),\n version: optionalNonEmpty(input.version, `${path}.version`),\n hash: optionalNonEmpty(input.hash, `${path}.hash`),\n })\n}\n\nfunction normalizeDimensions(\n input: Record<string, AgentProfileDimensionValue>,\n): Record<string, AgentProfileDimensionValue> {\n const out: Record<string, AgentProfileDimensionValue> = {}\n for (const key of Object.keys(input).sort()) {\n const value = input[key]\n requireNonEmpty(key, 'dimensions.<key>')\n if (\n value !== null &&\n typeof value !== 'string' &&\n typeof value !== 'number' &&\n typeof value !== 'boolean'\n ) {\n throw new AgentProfileCellValidationError(\n 'expected primitive dimension value',\n `dimensions.${key}`,\n )\n }\n if (typeof value === 'number' && !Number.isFinite(value)) {\n throw new AgentProfileCellValidationError('expected finite number', `dimensions.${key}`)\n }\n out[key] = value\n }\n return out\n}\n\nfunction compactObject<T extends Record<string, unknown>>(input: T): T {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(input)) {\n if (value !== undefined) out[key] = value\n }\n return out as T\n}\n\nfunction nonEmptyRecord<T extends Record<string, unknown>>(input: T): T | undefined {\n return Object.keys(input).length > 0 ? input : undefined\n}\n\nfunction validateSource(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new AgentProfileCellValidationError('expected object', path)\n }\n const rec = value as Record<string, unknown>\n expectString(rec.kind, `${path}.kind`)\n requireSha256Hex(rec.hash, `${path}.hash`)\n}\n\nfunction validateHarness(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new AgentProfileCellValidationError('expected object', path)\n }\n const rec = value as Record<string, unknown>\n expectString(rec.id, `${path}.id`)\n if (rec.version !== undefined) expectString(rec.version, `${path}.version`)\n if (rec.hash !== undefined) expectString(rec.hash, `${path}.hash`)\n}\n\nfunction validateDimensions(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n throw new AgentProfileCellValidationError('expected object', path)\n }\n normalizeDimensions(value as Record<string, AgentProfileDimensionValue>)\n}\n\nfunction assertJson(value: AgentProfileJson, path: string): void {\n if (value === null) return\n const type = typeof value\n if (type === 'string' || type === 'boolean') return\n if (type === 'number') {\n if (!Number.isFinite(value)) {\n throw new AgentProfileCellValidationError('expected finite number', path)\n }\n return\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n assertJson(item, `${path}[${index}]`)\n })\n return\n }\n if (type === 'object') {\n for (const [key, nested] of Object.entries(value)) {\n requireNonEmpty(key, `${path}.<key>`)\n assertJson(nested, `${path}.${key}`)\n }\n return\n }\n throw new AgentProfileCellValidationError('expected JSON-compatible value', path)\n}\n\nfunction expectLiteral(value: unknown, expected: string, path: string): void {\n if (value !== expected) {\n throw new AgentProfileCellValidationError(`expected ${expected}`, path)\n }\n}\n\nfunction expectString(value: unknown, path: string): void {\n if (typeof value !== 'string' || value.length === 0) {\n throw new AgentProfileCellValidationError('expected non-empty string', path)\n }\n}\n\nfunction requireNonEmpty(value: string, path: string): string {\n if (typeof value !== 'string' || value.length === 0) {\n throw new AgentProfileCellValidationError('expected non-empty string', path)\n }\n return value\n}\n\nfunction optionalNonEmpty(value: string | undefined, path: string): string | undefined {\n if (value === undefined) return undefined\n return requireNonEmpty(value, path)\n}\n\nfunction requireSha256Hex(value: unknown, path: string): string {\n if (typeof value !== 'string' || !SHA256_HEX.test(value)) {\n throw new AgentProfileCellValidationError('expected 64 lowercase sha256 hex chars', path)\n }\n return value\n}\n\n// ── Consumer helpers ─────────────────────────────────────────────────\n//\n// Boilerplate every product consuming `buildAgentProfileCell` used to duplicate:\n//\n// 1. A `JSON.parse(JSON.stringify(value))` helper that canonicalizes an\n// arbitrary `@tangle-network/agent-interface` `AgentProfile` into the recursive\n// `AgentProfileJson` shape, with a fail-loud error when the profile\n// is not JSON-serializable.\n//\n// 2. The magic string `'agent-interface-profile'` for `sourceProfile.kind`.\n//\n// Both belong here so the cross-product cell join (same canonical profile\n// hashes to the same `sourceProfile.hash` across products) is enforced by\n// the type system, not by every consumer remembering to do it right.\n// See blueprint-agent issue tangle-network/agent-eval#82.\n\n/** Canonical `sourceProfile.kind` values. Two products fingerprinting the\n * same canonical profile MUST use the same kind for their cells to share\n * `sourceProfile.hash`. Extend rather than create new strings — adding a\n * new kind is a deliberate cross-product schema change. */\nexport const AGENT_PROFILE_KINDS = {\n /** A profile declared via `defineAgentProfile(...)` from\n * `@tangle-network/agent-interface`. The default kind for router-backed\n * and sandbox-backed products. */\n AGENT_INTERFACE_PROFILE: 'agent-interface-profile',\n} as const\n\nexport type AgentProfileKind = (typeof AGENT_PROFILE_KINDS)[keyof typeof AGENT_PROFILE_KINDS]\n\n/** Canonicalize an arbitrary value into `AgentProfileJson` by JSON\n * round-trip. Throws when the value contains anything not representable\n * as JSON (functions, BigInt, cycles) — non-portable profiles fail loud\n * rather than silently dropping fields. */\nexport function toAgentProfileJson(value: unknown): AgentProfileJson {\n let serialized: string | undefined\n try {\n serialized = JSON.stringify(value)\n } catch (err) {\n throw new AgentProfileCellValidationError(\n `agent profile must be JSON-serializable: ${err instanceof Error ? err.message : String(err)}`,\n 'sourceProfile.profile',\n )\n }\n if (serialized === undefined) {\n throw new AgentProfileCellValidationError(\n 'agent profile must be JSON-serializable (got undefined after JSON.stringify)',\n 'sourceProfile.profile',\n )\n }\n return JSON.parse(serialized) as AgentProfileJson\n}\n\n/** Canonical AgentProfile shape required when deriving a stable cell id. */\nexport type AgentInterfaceProfileLike = AgentProfile & { name: string; version: string }\n\n/** Higher-level helper that hard-codes the canonical\n * `agent-interface-profile` kind plus the JSON canonicalization. Equivalent\n * to calling `buildAgentProfileCell` with `profileId = \\`${name}@${version}\\``\n * and `sourceProfile = { kind: AGENT_INTERFACE_PROFILE, profile: <round-tripped> }`.\n *\n * Use this from any product consuming an agent-interface `AgentProfile`; the\n * manual `buildAgentProfileCell` call is reserved for advanced cases\n * (custom kinds, pre-computed source hashes, alternate profileId\n * conventions). */\nexport async function buildAgentInterfaceProfileCell(\n profile: AgentInterfaceProfileLike,\n input: Omit<AgentProfileCellInput, 'profileId' | 'sourceProfile'>,\n): Promise<AgentProfileCell> {\n if (!profile || typeof profile !== 'object') {\n throw new AgentProfileCellValidationError('AgentProfile must be an object', 'profile')\n }\n if (typeof profile.name !== 'string' || profile.name.length === 0) {\n throw new AgentProfileCellValidationError(\n 'AgentProfile must have a non-empty `name`',\n 'profile.name',\n )\n }\n if (typeof profile.version !== 'string' || profile.version.length === 0) {\n throw new AgentProfileCellValidationError(\n 'AgentProfile must have a non-empty `version`',\n 'profile.version',\n )\n }\n return buildAgentProfileCell({\n ...input,\n profileId: `${profile.name}@${profile.version}`,\n sourceProfile: {\n kind: AGENT_PROFILE_KINDS.AGENT_INTERFACE_PROFILE,\n profile: toAgentProfileJson(profile),\n },\n })\n}\n","/**\n * Paper-grade RunRecord schema + runtime validator.\n *\n * Every run that participates in a promotion gate, paper table, or\n * researcher loop SHOULD be recorded as a `RunRecord`. The mandatory\n * fields are exactly those the paper \"Two Loops, Three Roles\" requires\n * for reproducibility: who/what/when/cost/seed/hash, plus the search vs\n * holdout split tag. A task score is optional because execution-only records\n * must preserve missing labels instead of converting errors into zero quality.\n *\n * This is intentionally NOT a replacement for the rich `Run` /\n * `ProposeReviewReport` / `ScenarioResult` types already in the\n * package. Those are runtime structures with full provenance. A\n * `RunRecord` is the analysis-time projection — the JSON-friendly\n * row you'd put in a parquet file or paste into a notebook.\n *\n * Validate at the boundary:\n *\n * const rec = validateRunRecord(rawJson) // throws on missing\n * const ok = isRunRecord(rawJson) // boolean check\n * const rec = parseRunRecordSafe(rawJson) // { ok, value | error }\n *\n * The validator runs in pure TS — zod is intentionally NOT a\n * dependency. Round-trip tested in `tests/run-record.test.ts`.\n */\n\nimport type { AgentProfileCell } from './agent-profile-cell'\nimport { validateAgentProfileCell } from './agent-profile-cell'\nimport { ValidationError } from './errors'\nimport { FAILURE_CLASSES, type FailureClass } from './trace/schema'\n\n/** Search/dev/holdout split tag. 'search' is the paper-grade alias for the\n * combined train+test pool that the optimizer is allowed to read. */\nexport type RunSplitTag = 'search' | 'dev' | 'holdout'\n\n/**\n * Explicit execution-lifecycle result for a run.\n *\n * This is separate from task quality (`outcome`) and failure classification.\n * Producers set it only from root-run or process evidence.\n */\nexport type RunTerminalOutcome = 'succeeded' | 'failed' | 'cancelled' | 'incomplete' | 'unknown'\n\nexport interface RunTokenUsage {\n input: number\n /** All generated tokens charged as output, including reasoning tokens. */\n output: number\n /** Reasoning-token subset of `output`, when the provider reports it. */\n reasoning?: number\n /** Prompt tokens served from a provider cache. */\n cached?: number\n /** Prompt tokens written into a provider cache. */\n cacheWrite?: number\n}\n\n/**\n * How a run's USD amount was obtained.\n */\nexport type RunCostProvenance =\n | { kind: 'observed'; usd: number }\n | { kind: 'estimated'; usd: number }\n | { kind: 'uncaptured'; usd: null }\n\nexport interface RunJudgeMetadata {\n model: string\n promptVersion: string\n /** [0,1] confidence the judge declared. Constant judge confidence\n * across many runs is a fallback signal (see `canary.ts`). */\n confidence: number\n /** True if the judge degraded to a fallback path (rules-only,\n * prior-call cache, etc.). The canary uses this to alert. */\n fallback: boolean\n}\n\n/**\n * Per-judge / per-dimension breakdown for runs scored by an ensemble of\n * judges over a multi-dimensional rubric.\n *\n * The collapsed `outcome.searchScore` / `holdoutScore` carries the\n * composite the gate uses. The full breakdown belongs here so consumers\n * can answer \"which judge disagreed?\", \"which dimension dragged the\n * composite down?\", and \"did half the panel fail?\" without re-running.\n *\n * `perJudge[judgeId][dim]` is the canonical source; `perDimMean` and\n * `composite` are convenience projections — derivable but precomputed so\n * downstream IRR primitives (`interRaterReliability`,\n * `corpusInterRaterAgreement`) and reporters don't pay the same\n * aggregation twice.\n *\n * Fail-loud discipline: judges that errored out land in `failedJudges`\n * by id. A missing key in `perJudge` is ambiguous (silent zero vs not\n * run); the explicit list makes a partial-failure recorded as such.\n */\nexport interface JudgeScoresRecord {\n /** Per-judge per-dimension scores. `{ \"kimi-k2.6\": { helpfulness: 0.8, clarity: 0.7 }, ... }`. */\n perJudge: Record<string, Record<string, number>>\n /** Per-dim mean across judges. Convenience — derivable from `perJudge`. */\n perDimMean: Record<string, number>\n /** Composite mean across successful judges. Mirrors the task score only\n * when `failedJudges` is empty. */\n composite: number\n /** Judges that errored or returned an unparseable verdict. Recorded\n * by id (e.g. `['glm-5.1']`) so a partial-failure case is explicit,\n * not inferred from missing keys in `perJudge`. */\n failedJudges?: string[]\n /** Free-form notes the judges emitted (joined across judges or\n * first-judge only — consumer's choice). */\n notes?: string\n}\n\nexport interface RunOutcome {\n /** Score on the search/optimization split. Optional for holdout-only and\n * execution-only records. */\n searchScore?: number\n /** Score on the held-out split. Optional for search-only and execution-only\n * records. When both scores are absent, the run is explicitly unlabeled. */\n holdoutScore?: number\n /** Bag of any other metric the run produced — judge dimensions,\n * pass/fail counters, latency stats, etc. Numeric only — keeps\n * reporters honest. */\n raw: Record<string, number>\n /** Per-judge / per-dim breakdown. Consumers writing ensemble\n * judgements populate this; substrate primitives like\n * `interRaterReliability` and `corpusInterRaterAgreement` accept\n * these records as input. Optional — single-judge or scalar-only\n * runs leave it unset. */\n judgeScores?: JudgeScoresRecord\n /** Authenticity / realness verdict — did the run build the REAL thing on the\n * intended infra, or fake it (see `./authenticity`)? Optional: only domains\n * with an authenticity config populate it. Carried in the corpus so the\n * flywheel / off-policy learning can optimize for real completion, not gamed\n * pass-rate. `score` is 0-1; `gated` is the anti-Goodhart flag — a gated run\n * must not count as a real success regardless of `score`. */\n realness?: { score: number; gated: boolean; reason?: string }\n}\n\n/**\n * Mandatory paper-grade fields for a single evaluation run. Optional\n * fields are extension points; mandatory fields throw if missing.\n *\n * Hash discipline:\n * - `promptHash` is the sha256 of the EFFECTIVE prompt sent to the\n * model (after any steering bundle merge).\n * - `configHash` is the sha256 of the effective run config (model,\n * temperature, tools, judges, splits). The pair (promptHash,\n * configHash) uniquely identifies an experiment cell.\n *\n * Model snapshot discipline:\n * - `model` MUST encode a snapshot version. Bare aliases like\n * `claude-sonnet-4` or `gpt-4o` are banned — they remap silently.\n * Use `claude-sonnet-4-6@2025-04-15` or `gpt-4o-2024-11-20`.\n */\nexport interface RunRecord {\n /** UUID for the run. */\n runId: string\n /** Logical experiment grouping (a treatment vs a baseline within\n * the same sweep should share `experimentId`). */\n experimentId: string\n /** Stable identifier for the candidate (variant) being run. The\n * promotion gate compares two `candidateId`s on matched items. */\n candidateId: string\n /** RNG seed for the run. Always recorded — silent re-seeding is\n * the most common cause of non-reproducible numbers. */\n seed: number\n /** Model identifier WITH snapshot version. */\n model: string\n /** sha256 of the effective prompt (post-steering). */\n promptHash: string\n /** sha256 of the effective config. */\n configHash: string\n /** Git SHA the harness was run from. */\n commitSha: string\n /** End-to-end wall-clock duration in milliseconds. */\n wallMs: number\n /** Time spent queued before execution started, if known. */\n queueMs?: number\n /** Total USD cost, or null when the producer could not capture one. */\n costUsd: number | null\n /** Whether `costUsd` came from billing data, a price calculation, or is unavailable. */\n costProvenance: RunCostProvenance\n /** Token usage breakdown. */\n tokenUsage: RunTokenUsage\n /** Root-run or process terminal result. Never inferred from a child span. */\n terminalOutcome: RunTerminalOutcome\n /** Root-run or process failure reason. Valid only for a failed, cancelled,\n * or incomplete terminal result; never populated from a child span. */\n terminalFailureReason?: string\n /** Judge-side metadata, if a judge was used. */\n judgeMetadata?: RunJudgeMetadata\n /** Per-split scores + raw bag. */\n outcome: RunOutcome\n /** Canonical task-failure class drawn from the shared\n * `FAILURE_CLASSES` taxonomy. This is the aggregation key that makes\n * \"which failure dominates across the whole fleet\" answerable in ONE\n * vocabulary — every agent classifies against the same enum. Producers\n * set it only from task-result evidence. Execution errors belong in\n * `outcome.raw.execution_error_count`, even when the run later fails. */\n failureClass?: FailureClass\n /** Free-form task-failure detail, scoped UNDER `failureClass`\n * (e.g. failureClass='tool_recovery_failure', failureMode='forge_build_unsatisfied').\n * Do not populate this from a child execution error alone. */\n failureMode?: string\n /** Which split this run was drawn from. */\n splitTag: RunSplitTag\n /**\n * Stable scenario identifier the run observed or was scored against.\n * Comparison primitives match this identity rather than input order.\n */\n scenarioId: string\n /**\n * Canonical identity for the agent profile cell that produced this row:\n * profile artifact hash plus optional harness/model/prompt/reporting\n * dimensions. Use `agentProfile.cellId` to group persona sweeps and\n * longitudinal reports by the complete source profile, not by a loose\n * candidate label or opaque config hash.\n */\n agentProfile?: AgentProfileCell\n}\n\n/** Return task quality, preferring held-out evidence when both scores exist. */\nexport function runTaskScore(record: RunRecord): number | undefined {\n const score = record.outcome.holdoutScore ?? record.outcome.searchScore\n return typeof score === 'number' && Number.isFinite(score) ? score : undefined\n}\n\n// ── Validation ───────────────────────────────────────────────────────\n\nconst MANDATORY_TOP_LEVEL = [\n 'runId',\n 'experimentId',\n 'candidateId',\n 'seed',\n 'model',\n 'promptHash',\n 'configHash',\n 'commitSha',\n 'wallMs',\n 'costUsd',\n 'costProvenance',\n 'tokenUsage',\n 'terminalOutcome',\n 'outcome',\n 'splitTag',\n 'scenarioId',\n] as const\n\nconst SPLIT_TAGS: ReadonlyArray<RunSplitTag> = ['search', 'dev', 'holdout']\nconst TERMINAL_OUTCOMES: ReadonlyArray<RunTerminalOutcome> = [\n 'succeeded',\n 'failed',\n 'cancelled',\n 'incomplete',\n 'unknown',\n]\n\nexport class RunRecordValidationError extends ValidationError {\n readonly path: string\n constructor(message: string, path = '') {\n super(path ? `${message} (at ${path})` : message)\n this.path = path\n }\n}\n\n/**\n * Strict validator. Throws `RunRecordValidationError` on the first\n * missing or wrongly-typed field. Returns the input cast to\n * `RunRecord` on success — the validator does not coerce.\n */\nexport function validateRunRecord(input: unknown): RunRecord {\n if (input === null || typeof input !== 'object') {\n throw new RunRecordValidationError('expected object')\n }\n const obj = input as Record<string, unknown>\n\n for (const key of MANDATORY_TOP_LEVEL) {\n if (!(key in obj)) {\n throw new RunRecordValidationError(`missing mandatory field \"${key}\"`)\n }\n }\n\n expectString(obj.runId, 'runId')\n expectString(obj.experimentId, 'experimentId')\n expectString(obj.candidateId, 'candidateId')\n expectFiniteNumber(obj.seed, 'seed')\n expectString(obj.model, 'model')\n expectString(obj.promptHash, 'promptHash')\n expectString(obj.configHash, 'configHash')\n expectString(obj.commitSha, 'commitSha')\n expectNonNegativeNumber(obj.wallMs, 'wallMs')\n if (obj.queueMs !== undefined) expectNonNegativeNumber(obj.queueMs, 'queueMs')\n validateCost(obj.costUsd, obj.costProvenance)\n\n // Snapshot discipline: bare model aliases are not paper-grade.\n if (!modelHasSnapshot(obj.model as string)) {\n throw new RunRecordValidationError(\n `model \"${obj.model}\" lacks a snapshot version (use 'name@YYYY-MM-DD' or 'name-YYYYMMDD')`,\n 'model',\n )\n }\n\n // Token usage.\n const tu = obj.tokenUsage\n if (tu === null || typeof tu !== 'object') {\n throw new RunRecordValidationError('tokenUsage must be an object', 'tokenUsage')\n }\n const tuRec = tu as Record<string, unknown>\n expectNonNegativeNumber(tuRec.input, 'tokenUsage.input')\n expectNonNegativeNumber(tuRec.output, 'tokenUsage.output')\n if (tuRec.reasoning !== undefined) {\n expectNonNegativeNumber(tuRec.reasoning, 'tokenUsage.reasoning')\n if ((tuRec.reasoning as number) > (tuRec.output as number)) {\n throw new RunRecordValidationError(\n 'reasoning tokens must be a subset of output tokens',\n 'tokenUsage.reasoning',\n )\n }\n }\n if (tuRec.cached !== undefined) expectNonNegativeNumber(tuRec.cached, 'tokenUsage.cached')\n if (tuRec.cacheWrite !== undefined) {\n expectNonNegativeNumber(tuRec.cacheWrite, 'tokenUsage.cacheWrite')\n }\n\n // Judge metadata, optional.\n if (obj.judgeMetadata !== undefined) {\n const jm = obj.judgeMetadata\n if (jm === null || typeof jm !== 'object') {\n throw new RunRecordValidationError('judgeMetadata must be an object', 'judgeMetadata')\n }\n const jmRec = jm as Record<string, unknown>\n expectString(jmRec.model, 'judgeMetadata.model')\n expectString(jmRec.promptVersion, 'judgeMetadata.promptVersion')\n expectFiniteNumber(jmRec.confidence, 'judgeMetadata.confidence')\n if (typeof jmRec.fallback !== 'boolean') {\n throw new RunRecordValidationError(\n 'judgeMetadata.fallback must be boolean',\n 'judgeMetadata.fallback',\n )\n }\n }\n\n // Outcome.\n const out = obj.outcome\n if (out === null || typeof out !== 'object') {\n throw new RunRecordValidationError('outcome must be an object', 'outcome')\n }\n const outRec = out as Record<string, unknown>\n if (outRec.searchScore !== undefined)\n expectFiniteNumber(outRec.searchScore, 'outcome.searchScore')\n if (outRec.holdoutScore !== undefined)\n expectFiniteNumber(outRec.holdoutScore, 'outcome.holdoutScore')\n const raw = outRec.raw\n if (raw === null || typeof raw !== 'object') {\n throw new RunRecordValidationError('outcome.raw must be an object', 'outcome.raw')\n }\n for (const [k, v] of Object.entries(raw as Record<string, unknown>)) {\n expectFiniteNumber(v, `outcome.raw.${k}`)\n }\n // Realness verdict, optional.\n if (outRec.realness !== undefined) {\n const r = outRec.realness\n if (r === null || typeof r !== 'object') {\n throw new RunRecordValidationError('outcome.realness must be an object', 'outcome.realness')\n }\n const rr = r as Record<string, unknown>\n expectFiniteNumber(rr.score, 'outcome.realness.score')\n if (typeof rr.gated !== 'boolean') {\n throw new RunRecordValidationError(\n 'outcome.realness.gated must be a boolean',\n 'outcome.realness.gated',\n )\n }\n }\n\n // Per-judge / per-dim breakdown, optional.\n if (outRec.judgeScores !== undefined) {\n validateJudgeScores(outRec.judgeScores, 'outcome.judgeScores')\n }\n\n // Failure mode optional.\n if (\n obj.failureClass !== undefined &&\n (typeof obj.failureClass !== 'string' ||\n !FAILURE_CLASSES.includes(obj.failureClass as FailureClass))\n ) {\n throw new RunRecordValidationError(\n `failureClass must be one of ${FAILURE_CLASSES.join(', ')}`,\n 'failureClass',\n )\n }\n if (obj.failureMode !== undefined) expectString(obj.failureMode, 'failureMode')\n\n if (\n typeof obj.terminalOutcome !== 'string' ||\n !TERMINAL_OUTCOMES.includes(obj.terminalOutcome as RunTerminalOutcome)\n ) {\n throw new RunRecordValidationError(\n `terminalOutcome must be one of ${TERMINAL_OUTCOMES.join(', ')}`,\n 'terminalOutcome',\n )\n }\n if (obj.terminalFailureReason !== undefined) {\n expectString(obj.terminalFailureReason, 'terminalFailureReason')\n if (\n obj.terminalOutcome !== 'failed' &&\n obj.terminalOutcome !== 'cancelled' &&\n obj.terminalOutcome !== 'incomplete'\n ) {\n throw new RunRecordValidationError(\n 'terminalFailureReason requires terminalOutcome failed, cancelled, or incomplete',\n 'terminalFailureReason',\n )\n }\n }\n\n if (obj.agentProfile !== undefined) {\n try {\n const profile = validateAgentProfileCell(obj.agentProfile)\n if (profile.model !== undefined && profile.model !== obj.model) {\n throw new RunRecordValidationError(\n `agentProfile.model \"${profile.model}\" does not match model \"${obj.model}\"`,\n 'agentProfile.model',\n )\n }\n if (profile.promptHash !== undefined && profile.promptHash !== obj.promptHash) {\n throw new RunRecordValidationError(\n `agentProfile.promptHash \"${profile.promptHash}\" does not match promptHash \"${obj.promptHash}\"`,\n 'agentProfile.promptHash',\n )\n }\n } catch (error) {\n if (error instanceof RunRecordValidationError) throw error\n if (error instanceof Error) {\n throw new RunRecordValidationError(error.message, 'agentProfile')\n }\n throw error\n }\n }\n\n expectString(obj.scenarioId, 'scenarioId')\n\n // Split tag.\n if (typeof obj.splitTag !== 'string' || !SPLIT_TAGS.includes(obj.splitTag as RunSplitTag)) {\n throw new RunRecordValidationError(\n `splitTag must be one of ${SPLIT_TAGS.join(', ')}, got ${String(obj.splitTag)}`,\n 'splitTag',\n )\n }\n\n return input as RunRecord\n}\n\nfunction validateCost(costUsd: unknown, provenance: unknown): void {\n if (provenance === null || typeof provenance !== 'object') {\n throw new RunRecordValidationError('costProvenance must be an object', 'costProvenance')\n }\n const value = provenance as Record<string, unknown>\n if (value.kind !== 'observed' && value.kind !== 'estimated' && value.kind !== 'uncaptured') {\n throw new RunRecordValidationError(\n 'costProvenance.kind must be observed, estimated, or uncaptured',\n 'costProvenance.kind',\n )\n }\n if (value.kind === 'uncaptured') {\n if (value.usd !== null) {\n throw new RunRecordValidationError(\n 'uncaptured costProvenance.usd must be null',\n 'costProvenance.usd',\n )\n }\n if (costUsd !== null) {\n throw new RunRecordValidationError('uncaptured cost requires costUsd to be null', 'costUsd')\n }\n return\n }\n expectNonNegativeNumber(costUsd, 'costUsd')\n expectNonNegativeNumber(value.usd, 'costProvenance.usd')\n if (value.usd !== costUsd) {\n throw new RunRecordValidationError(\n 'costProvenance.usd must equal costUsd',\n 'costProvenance.usd',\n )\n }\n}\n\n/** Boolean validator — convenience for filtering arrays. */\nexport function isRunRecord(input: unknown): input is RunRecord {\n try {\n validateRunRecord(input)\n return true\n } catch {\n return false\n }\n}\n\n/** Non-throwing validator — returns a discriminated union. */\nexport function parseRunRecordSafe(\n input: unknown,\n): { ok: true; value: RunRecord } | { ok: false; error: RunRecordValidationError } {\n try {\n return { ok: true, value: validateRunRecord(input) }\n } catch (e) {\n if (e instanceof RunRecordValidationError) return { ok: false, error: e }\n throw e\n }\n}\n\n/** Round-trip helper — `JSON.parse(JSON.stringify(record))` then validate. */\nexport function roundTripRunRecord(record: RunRecord): RunRecord {\n const json = JSON.stringify(record)\n return validateRunRecord(JSON.parse(json))\n}\n\n// ── Internals ────────────────────────────────────────────────────────\n\nfunction expectString(value: unknown, path: string): void {\n if (typeof value !== 'string' || value.length === 0) {\n throw new RunRecordValidationError(`expected non-empty string`, path)\n }\n}\n\nfunction expectFiniteNumber(value: unknown, path: string): void {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new RunRecordValidationError(`expected finite number`, path)\n }\n}\n\nfunction expectNonNegativeNumber(value: unknown, path: string): void {\n expectFiniteNumber(value, path)\n if ((value as number) < 0) {\n throw new RunRecordValidationError('expected non-negative number', path)\n }\n}\n\nfunction validateJudgeScores(value: unknown, path: string): void {\n if (value === null || typeof value !== 'object') {\n throw new RunRecordValidationError('judgeScores must be an object', path)\n }\n const rec = value as Record<string, unknown>\n\n const perJudge = rec.perJudge\n if (perJudge === null || typeof perJudge !== 'object') {\n throw new RunRecordValidationError('perJudge must be an object', `${path}.perJudge`)\n }\n for (const [judgeId, dims] of Object.entries(perJudge as Record<string, unknown>)) {\n if (dims === null || typeof dims !== 'object') {\n throw new RunRecordValidationError(\n 'per-judge entry must be an object of dimension scores',\n `${path}.perJudge.${judgeId}`,\n )\n }\n for (const [dim, score] of Object.entries(dims as Record<string, unknown>)) {\n expectFiniteNumber(score, `${path}.perJudge.${judgeId}.${dim}`)\n }\n }\n\n const perDimMean = rec.perDimMean\n if (perDimMean === null || typeof perDimMean !== 'object') {\n throw new RunRecordValidationError('perDimMean must be an object', `${path}.perDimMean`)\n }\n for (const [dim, mean] of Object.entries(perDimMean as Record<string, unknown>)) {\n expectFiniteNumber(mean, `${path}.perDimMean.${dim}`)\n }\n\n expectFiniteNumber(rec.composite, `${path}.composite`)\n\n if (rec.failedJudges !== undefined) {\n if (!Array.isArray(rec.failedJudges)) {\n throw new RunRecordValidationError(\n 'failedJudges must be an array of strings',\n `${path}.failedJudges`,\n )\n }\n for (let i = 0; i < rec.failedJudges.length; i++) {\n const id = rec.failedJudges[i]\n if (typeof id !== 'string' || id.length === 0) {\n throw new RunRecordValidationError(\n 'failedJudges entry must be a non-empty string',\n `${path}.failedJudges[${i}]`,\n )\n }\n }\n }\n\n if (rec.notes !== undefined && typeof rec.notes !== 'string') {\n throw new RunRecordValidationError('notes must be a string', `${path}.notes`)\n }\n}\n\n/**\n * Heuristic snapshot check. Accepts:\n * - `name@YYYY-MM-DD` (Anthropic style: `claude-sonnet-4-6@2025-04-15`)\n * - `name-YYYYMMDD` (OpenAI style: `gpt-4o-2024-11-20`)\n * - `name@<arbitrary-token>` (allow opaque snapshots like `@v3`)\n * - explicit `:date-...` Vertex-style tags\n *\n * Rejects bare aliases like `claude-sonnet-4` or `gpt-4o` that remap\n * silently as providers ship new snapshots.\n */\nexport function modelHasSnapshot(model: string): boolean {\n if (model.includes('@')) return true\n if (/-\\d{8}$/.test(model)) return true\n if (/-\\d{4}-\\d{2}-\\d{2}$/.test(model)) return true\n if (/:date-/.test(model)) return true\n return false\n}\n"],"mappings":"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","names":["expectString"]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-VQMK5FMP.js";
4
4
  import {
5
5
  validateRunRecord
6
- } from "./chunk-IILEIWGW.js";
6
+ } from "./chunk-NL33OXEP.js";
7
7
 
8
8
  // src/action-policy.ts
9
9
  function evaluateActionPolicy(action, policy = {}, options = {}) {
@@ -981,10 +981,21 @@ async function finish(emitter, result) {
981
981
 
982
982
  // src/run-evidence.ts
983
983
  function controlRunToRunRecord(run, options) {
984
- const score = clampScore(
985
- options.score ?? run.score ?? scoreFromEvals(run.finalEvals) ?? (run.pass ? 1 : 0)
986
- );
987
- const outcome = options.splitTag === "holdout" ? { holdoutScore: score, raw: normalizeRawMetrics(options.raw, run, score) } : { searchScore: score, raw: normalizeRawMetrics(options.raw, run, score) };
984
+ const score = finiteScore(options.score) ?? finiteScore(run.score) ?? scoreFromEvals(run.finalEvals);
985
+ const outcome = options.splitTag === "holdout" ? {
986
+ ...score !== void 0 ? { holdoutScore: score } : {},
987
+ raw: normalizeRawMetrics(options.raw, run, score)
988
+ } : {
989
+ ...score !== void 0 ? { searchScore: score } : {},
990
+ raw: normalizeRawMetrics(options.raw, run, score)
991
+ };
992
+ const terminalOutcome = run.stoppedBy === "abort" ? "cancelled" : run.stoppedBy === "runtime-error" ? "failed" : run.completed ? "succeeded" : "incomplete";
993
+ const costUsd = options.costProvenance.kind === "uncaptured" ? null : options.costProvenance.usd;
994
+ if (costUsd !== null && costUsd !== run.spentCostUsd) {
995
+ throw new Error(
996
+ `cost provenance amount ${costUsd} does not match control run spend ${run.spentCostUsd}`
997
+ );
998
+ }
988
999
  return validateRunRecord({
989
1000
  runId: options.runId ?? run.runId ?? `control:${options.experimentId}:${options.candidateId}:${options.seed}:${options.splitTag}`,
990
1001
  experimentId: options.experimentId,
@@ -996,12 +1007,16 @@ function controlRunToRunRecord(run, options) {
996
1007
  commitSha: options.commitSha,
997
1008
  wallMs: run.wallMs,
998
1009
  ...options.queueMs !== void 0 ? { queueMs: options.queueMs } : {},
999
- costUsd: run.spentCostUsd,
1010
+ costUsd,
1011
+ costProvenance: options.costProvenance,
1000
1012
  tokenUsage: options.tokenUsage,
1013
+ terminalOutcome,
1014
+ ...terminalOutcome !== "succeeded" ? { terminalFailureReason: run.reason } : {},
1001
1015
  ...options.judgeMetadata ? { judgeMetadata: options.judgeMetadata } : {},
1002
1016
  outcome,
1003
- failureMode: options.failureMode ?? failureModeFromRun(run),
1004
- splitTag: options.splitTag
1017
+ ...options.failureMode !== void 0 ? { failureMode: options.failureMode } : {},
1018
+ splitTag: options.splitTag,
1019
+ scenarioId: options.scenarioId
1005
1020
  });
1006
1021
  }
1007
1022
  function scoreFromEvals(evals) {
@@ -1010,15 +1025,27 @@ function scoreFromEvals(evals) {
1010
1025
  return clampScore(scores.reduce((sum, score) => sum + score, 0) / scores.length);
1011
1026
  }
1012
1027
  function normalizeRawMetrics(raw, run, score) {
1028
+ const normalizedRaw = finiteOnly(raw ?? {});
1029
+ delete normalizedRaw.score;
1013
1030
  return {
1014
- ...finiteOnly(raw ?? {}),
1015
- score,
1031
+ ...normalizedRaw,
1032
+ ...score !== void 0 ? { score } : {},
1016
1033
  pass: run.pass ? 1 : 0,
1017
1034
  completed: run.completed ? 1 : 0,
1018
1035
  steps: run.steps.length,
1019
- runtimeErrors: run.runtimeErrors.length
1036
+ runtimeErrors: run.runtimeErrors.length,
1037
+ execution_error_count: executionErrorCount(run)
1020
1038
  };
1021
1039
  }
1040
+ function executionErrorCount(run) {
1041
+ const thrownActionSteps = new Set(
1042
+ run.runtimeErrors.filter((error) => error.phase === "act").map((error) => error.stepIndex)
1043
+ );
1044
+ const failedActionsWithoutRuntimeError = run.steps.filter(
1045
+ (step) => step.actionOutcome?.ok === false && !thrownActionSteps.has(step.index)
1046
+ ).length;
1047
+ return run.runtimeErrors.length + failedActionsWithoutRuntimeError;
1048
+ }
1022
1049
  function finiteOnly(values) {
1023
1050
  const out = {};
1024
1051
  for (const [key, value] of Object.entries(values)) {
@@ -1026,12 +1053,10 @@ function finiteOnly(values) {
1026
1053
  }
1027
1054
  return out;
1028
1055
  }
1029
- function failureModeFromRun(run) {
1030
- if (run.pass) return void 0;
1031
- return run.failureClass ?? "unknown";
1056
+ function finiteScore(value) {
1057
+ return value !== void 0 && Number.isFinite(value) ? clampScore(value) : void 0;
1032
1058
  }
1033
1059
  function clampScore(value) {
1034
- if (!Number.isFinite(value)) return 0;
1035
1060
  return Math.max(0, Math.min(1, value));
1036
1061
  }
1037
1062
 
@@ -1523,4 +1548,4 @@ export {
1523
1548
  runProposeReviewAsControlLoop,
1524
1549
  controlFailureClassFromVerification
1525
1550
  };
1526
- //# sourceMappingURL=chunk-474LBSOX.js.map
1551
+ //# sourceMappingURL=chunk-OD5NQ2CS.js.map
@@ -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'\n\nexport interface RunEvidenceMetadata {\n experimentId: string\n scenarioId: 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 costProvenance: RunRecord['costProvenance']\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 =\n finiteScore(options.score) ?? finiteScore(run.score) ?? scoreFromEvals(run.finalEvals)\n const outcome =\n options.splitTag === 'holdout'\n ? {\n ...(score !== undefined ? { holdoutScore: score } : {}),\n raw: normalizeRawMetrics(options.raw, run, score),\n }\n : {\n ...(score !== undefined ? { searchScore: score } : {}),\n raw: normalizeRawMetrics(options.raw, run, score),\n }\n const terminalOutcome =\n run.stoppedBy === 'abort'\n ? 'cancelled'\n : run.stoppedBy === 'runtime-error'\n ? 'failed'\n : run.completed\n ? 'succeeded'\n : 'incomplete'\n const costUsd = options.costProvenance.kind === 'uncaptured' ? null : options.costProvenance.usd\n if (costUsd !== null && costUsd !== run.spentCostUsd) {\n throw new Error(\n `cost provenance amount ${costUsd} does not match control run spend ${run.spentCostUsd}`,\n )\n }\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,\n costProvenance: options.costProvenance,\n tokenUsage: options.tokenUsage,\n terminalOutcome,\n ...(terminalOutcome !== 'succeeded' ? { terminalFailureReason: run.reason } : {}),\n ...(options.judgeMetadata ? { judgeMetadata: options.judgeMetadata } : {}),\n outcome,\n ...(options.failureMode !== undefined ? { failureMode: options.failureMode } : {}),\n splitTag: options.splitTag,\n scenarioId: options.scenarioId,\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 | undefined,\n): Record<string, number> {\n const normalizedRaw = finiteOnly(raw ?? {})\n delete normalizedRaw.score\n return {\n ...normalizedRaw,\n ...(score !== undefined ? { score } : {}),\n pass: run.pass ? 1 : 0,\n completed: run.completed ? 1 : 0,\n steps: run.steps.length,\n runtimeErrors: run.runtimeErrors.length,\n execution_error_count: executionErrorCount(run),\n }\n}\n\nfunction executionErrorCount<TState, TAction, TActionResult, TEval extends ControlEvalResult>(\n run: ControlRunResult<TState, TAction, TActionResult, TEval>,\n): number {\n const thrownActionSteps = new Set(\n run.runtimeErrors.filter((error) => error.phase === 'act').map((error) => error.stepIndex),\n )\n const failedActionsWithoutRuntimeError = run.steps.filter(\n (step) => step.actionOutcome?.ok === false && !thrownActionSteps.has(step.index),\n ).length\n return run.runtimeErrors.length + failedActionsWithoutRuntimeError\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 finiteScore(value: number | undefined): number | undefined {\n return value !== undefined && Number.isFinite(value) ? clampScore(value) : undefined\n}\n\nfunction clampScore(value: number): number {\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,6 +1,6 @@
1
1
  import {
2
2
  cohensD
3
- } from "./chunk-PJQFMIOX.js";
3
+ } from "./chunk-MHELPNRP.js";
4
4
  import {
5
5
  argHash,
6
6
  groupBy,
@@ -573,4 +573,4 @@ export {
573
573
  iqr,
574
574
  welchsTTest
575
575
  };
576
- //# sourceMappingURL=chunk-QOTFXW5L.js.map
576
+ //# sourceMappingURL=chunk-P5W7RQKK.js.map
@@ -20,6 +20,33 @@ var TOOL_SPAN_ATTRIBUTE_KEYS = [
20
20
  INPUT_VALUE,
21
21
  OUTPUT_VALUE
22
22
  ];
23
+ var EXPLICIT_SPAN_ROLES = /* @__PURE__ */ new Set([
24
+ "AGENT",
25
+ "CHAIN",
26
+ "EVALUATOR",
27
+ "GUARDRAIL",
28
+ "LLM",
29
+ "SPAN",
30
+ "TOOL"
31
+ ]);
32
+ function classifyOtlpSpanRole(input) {
33
+ const explicitKind = input.kind ?? firstStringAttribute(input.attributes, SPAN_KIND_ATTR_KEYS);
34
+ if (explicitKind) {
35
+ const normalized = explicitKind.toUpperCase();
36
+ if (EXPLICIT_SPAN_ROLES.has(normalized)) return normalized;
37
+ }
38
+ if (firstStringAttribute(input.attributes, TOOL_NAME_ATTR_KEYS) !== void 0 || /^(?:function|tool)[.:/]/i.test(input.name)) {
39
+ return "TOOL";
40
+ }
41
+ const spanType = input.attributes["span.type"];
42
+ if (typeof spanType === "string" && spanType.toLowerCase() === "llm_request" || /(?:^|[.:/_-])(?:chat[._-]?completions?|llm)(?:$|[.:/_-])/i.test(input.name) || firstStringAttribute(input.attributes, LLM_MODEL_ATTR_KEYS) !== void 0 || typeof input.attributes["gen_ai.operation.name"] === "string") {
43
+ return "LLM";
44
+ }
45
+ return "UNKNOWN";
46
+ }
47
+ function isOtlpModelCall(input) {
48
+ return classifyOtlpSpanRole(input) === "LLM";
49
+ }
23
50
  function toolSpanOtlpAttributes(span) {
24
51
  const argsCaptured = span.argsCaptured !== false;
25
52
  const attributes = {
@@ -44,7 +71,7 @@ function traceSpanKindToOpenInferenceKind(kind) {
44
71
  case "retrieval":
45
72
  return "CHAIN";
46
73
  case "judge":
47
- return "GUARDRAIL";
74
+ return "EVALUATOR";
48
75
  case "sandbox":
49
76
  return "CHAIN";
50
77
  case "agent":
@@ -53,6 +80,13 @@ function traceSpanKindToOpenInferenceKind(kind) {
53
80
  return "SPAN";
54
81
  }
55
82
  }
83
+ function firstStringAttribute(attributes, keys) {
84
+ for (const key of keys) {
85
+ const value = attributes[key];
86
+ if (typeof value === "string" && value.length > 0) return value;
87
+ }
88
+ return void 0;
89
+ }
56
90
  function stringifyTraceValue(value) {
57
91
  if (value === void 0) return "null";
58
92
  if (typeof value === "string") return value;
@@ -124,7 +158,7 @@ function inferOtlpKind(attrs) {
124
158
  const opik = firstStringAttr(attrs, SPAN_KIND_ATTR_KEYS);
125
159
  if (opik) {
126
160
  const upper = opik.toUpperCase();
127
- if (upper === "AGENT" || upper === "LLM" || upper === "TOOL" || upper === "CHAIN" || upper === "GUARDRAIL" || upper === "SPAN") {
161
+ if (upper === "AGENT" || upper === "LLM" || upper === "TOOL" || upper === "CHAIN" || upper === "EVALUATOR" || upper === "GUARDRAIL" || upper === "SPAN") {
128
162
  return upper;
129
163
  }
130
164
  }
@@ -1101,6 +1135,8 @@ function validateLoopLimits(options) {
1101
1135
  }
1102
1136
 
1103
1137
  export {
1138
+ classifyOtlpSpanRole,
1139
+ isOtlpModelCall,
1104
1140
  applyToolSpanOtlpAttributes,
1105
1141
  traceSpanKindToOpenInferenceKind,
1106
1142
  projectOtlpFlatLine,
@@ -1122,4 +1158,4 @@ export {
1122
1158
  buildTraceAnalystTools,
1123
1159
  traceAnalystFunctionGroup
1124
1160
  };
1125
- //# sourceMappingURL=chunk-IR3KBHOY.js.map
1161
+ //# sourceMappingURL=chunk-P6FYH6K4.js.map