@tangle-network/agent-runtime 0.105.0 → 0.106.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 (218) hide show
  1. package/README.md +2 -2
  2. package/dist/activation-CRjVfOiy.js +203 -0
  3. package/dist/activation-CRjVfOiy.js.map +1 -0
  4. package/dist/activation-DyWB0K6E.d.ts +98 -0
  5. package/dist/agent.d.ts +216 -234
  6. package/dist/agent.js +615 -547
  7. package/dist/agent.js.map +1 -1
  8. package/dist/analyst-loop-DGdtVENg.js +517 -0
  9. package/dist/analyst-loop-DGdtVENg.js.map +1 -0
  10. package/dist/analyst-loop.d.ts +10 -43
  11. package/dist/analyst-loop.js +2 -11
  12. package/dist/backends-Dy8NujB4.js +713 -0
  13. package/dist/backends-Dy8NujB4.js.map +1 -0
  14. package/dist/candidate-execution/index.d.ts +4 -192
  15. package/dist/candidate-execution/index.js +5 -66
  16. package/dist/candidate-execution-DqMbv1rU.js +488 -0
  17. package/dist/candidate-execution-DqMbv1rU.js.map +1 -0
  18. package/dist/coder-yhVWbdWc.js +40 -0
  19. package/dist/coder-yhVWbdWc.js.map +1 -0
  20. package/dist/conversation-XucG_K3l.js +1265 -0
  21. package/dist/conversation-XucG_K3l.js.map +1 -0
  22. package/dist/conversation.d.ts +2 -804
  23. package/dist/conversation.js +2 -55
  24. package/dist/environment-provider-CfLUmKmf.js +1168 -0
  25. package/dist/environment-provider-CfLUmKmf.js.map +1 -0
  26. package/dist/environment-provider-IUGU3epE.d.ts +964 -0
  27. package/dist/environment-provider.d.ts +2 -78
  28. package/dist/environment-provider.js +2 -18
  29. package/dist/errors-DEAvWQPy.js +111 -0
  30. package/dist/errors-DEAvWQPy.js.map +1 -0
  31. package/dist/improvement-adapter-Cr5TBSji.d.ts +166 -0
  32. package/dist/improvement-cycle-C095kS_g.js +2624 -0
  33. package/dist/improvement-cycle-C095kS_g.js.map +1 -0
  34. package/dist/index-BGdxAwfO.d.ts +838 -0
  35. package/dist/index-C-FYUuFG.d.ts +193 -0
  36. package/dist/index-CbNM40xG.d.ts +140 -0
  37. package/dist/index-DruSKs3Z.d.ts +7224 -0
  38. package/dist/index-Efjb3nrQ.d.ts +671 -0
  39. package/dist/index.d.ts +14 -1058
  40. package/dist/index.js +2106 -2082
  41. package/dist/index.js.map +1 -1
  42. package/dist/intelligence.d.ts +768 -889
  43. package/dist/intelligence.js +1466 -1367
  44. package/dist/intelligence.js.map +1 -1
  45. package/dist/{kb-gate-CwHO0vz6.d.ts → kb-gate-C8z2juK8.d.ts} +33 -31
  46. package/dist/kb-gate-DpaSwXVx.js +80 -0
  47. package/dist/kb-gate-DpaSwXVx.js.map +1 -0
  48. package/dist/knowledge-Ku-mPP4f.js +433 -0
  49. package/dist/knowledge-Ku-mPP4f.js.map +1 -0
  50. package/dist/knowledge.d.ts +2 -150
  51. package/dist/knowledge.js +2 -40
  52. package/dist/local-harness-Dh8PJ0ot.d.ts +455 -0
  53. package/dist/loop-runner-bin-BXsFEUcf.d.ts +162 -0
  54. package/dist/loop-runner-bin-BwjQ1NfH.js +268 -0
  55. package/dist/loop-runner-bin-BwjQ1NfH.js.map +1 -0
  56. package/dist/loop-runner-bin.d.ts +2 -15
  57. package/dist/loop-runner-bin.js +2 -24
  58. package/dist/loops.d.ts +5 -4164
  59. package/dist/loops.js +8 -419
  60. package/dist/mcp/bin.d.ts +1 -1
  61. package/dist/mcp/bin.js +116 -146
  62. package/dist/mcp/bin.js.map +1 -1
  63. package/dist/mcp/index.d.ts +295 -436
  64. package/dist/mcp/index.js +1242 -1177
  65. package/dist/mcp/index.js.map +1 -1
  66. package/dist/mcp/memory-bin.d.ts +1 -1
  67. package/dist/mcp/memory-bin.js +37 -16
  68. package/dist/mcp/memory-bin.js.map +1 -1
  69. package/dist/memory-server-DL6cE2Ag.js +234 -0
  70. package/dist/memory-server-DL6cE2Ag.js.map +1 -0
  71. package/dist/model-resolution-Btd9iIKV.js +98 -0
  72. package/dist/model-resolution-Btd9iIKV.js.map +1 -0
  73. package/dist/openai-tools-B68JaOCx.d.ts +24 -0
  74. package/dist/openai-tools-CKLy1C7M.js +44 -0
  75. package/dist/openai-tools-CKLy1C7M.js.map +1 -0
  76. package/dist/otel-export-D34IQW1C.js +843 -0
  77. package/dist/otel-export-D34IQW1C.js.map +1 -0
  78. package/dist/platform.d.ts +188 -185
  79. package/dist/platform.js +185 -218
  80. package/dist/platform.js.map +1 -1
  81. package/dist/prepare-B53sPV7M.js +4292 -0
  82. package/dist/prepare-B53sPV7M.js.map +1 -0
  83. package/dist/primeintellect/index.d.ts +149 -145
  84. package/dist/primeintellect/index.js +626 -1003
  85. package/dist/primeintellect/index.js.map +1 -1
  86. package/dist/profiles.d.ts +296 -490
  87. package/dist/profiles.js +722 -749
  88. package/dist/profiles.js.map +1 -1
  89. package/dist/protected-model-port-BLPH5VVv.js +722 -0
  90. package/dist/protected-model-port-BLPH5VVv.js.map +1 -0
  91. package/dist/protected-model-port-BP6Z4eau.d.ts +283 -0
  92. package/dist/protected-redaction--F3v1oo8.js +200 -0
  93. package/dist/protected-redaction--F3v1oo8.js.map +1 -0
  94. package/dist/redact-D-u-rrcn.js +82 -0
  95. package/dist/redact-D-u-rrcn.js.map +1 -0
  96. package/dist/redact-kbIOjfjM.d.ts +452 -0
  97. package/dist/researcher-CoVqNhfI.js +433 -0
  98. package/dist/researcher-CoVqNhfI.js.map +1 -0
  99. package/dist/runtime-BG0BziaP.js +5408 -0
  100. package/dist/runtime-BG0BziaP.js.map +1 -0
  101. package/dist/sandbox-events-DeI5xX8P.js +316 -0
  102. package/dist/sandbox-events-DeI5xX8P.js.map +1 -0
  103. package/dist/spawn-journal-CwPvKUTa.js +456 -0
  104. package/dist/spawn-journal-CwPvKUTa.js.map +1 -0
  105. package/dist/structural-rollout-IXUEplky.js +1445 -0
  106. package/dist/structural-rollout-IXUEplky.js.map +1 -0
  107. package/dist/substrate-B0TYNrXn.js +27 -0
  108. package/dist/substrate-B0TYNrXn.js.map +1 -0
  109. package/dist/{substrate-Dyiqmd3o.d.ts → substrate-BcnuSHXm.d.ts} +57 -54
  110. package/dist/supervise-BiRutHS9.js +7321 -0
  111. package/dist/supervise-BiRutHS9.js.map +1 -0
  112. package/dist/supervisor-DTKhF-RV.js +3826 -0
  113. package/dist/supervisor-DTKhF-RV.js.map +1 -0
  114. package/dist/testing.d.ts +4 -3
  115. package/dist/testing.js +2478 -2637
  116. package/dist/testing.js.map +1 -1
  117. package/dist/tool-server-RcWgLIsL.js +141 -0
  118. package/dist/tool-server-RcWgLIsL.js.map +1 -0
  119. package/dist/trace-propagation-CJJC7SVB.js +57 -0
  120. package/dist/trace-propagation-CJJC7SVB.js.map +1 -0
  121. package/dist/types-BaIpb0XT.d.ts +492 -0
  122. package/dist/types-BevOjfTY.d.ts +765 -0
  123. package/dist/types-C9j4qg6l.d.ts +500 -0
  124. package/dist/types-Cja5OTGh.d.ts +190 -0
  125. package/dist/util-MVgdwuIS.js +145 -0
  126. package/dist/util-MVgdwuIS.js.map +1 -0
  127. package/dist/workspace-archive-BosQiotA.js +575 -0
  128. package/dist/workspace-archive-BosQiotA.js.map +1 -0
  129. package/package.json +43 -56
  130. package/skills/build-with-agent-runtime/SKILL.md +1 -0
  131. package/dist/activation-Cm-9MMX1.d.ts +0 -69
  132. package/dist/analyst-loop.js.map +0 -1
  133. package/dist/backends-BO4Jqoe2.d.ts +0 -134
  134. package/dist/candidate-execution/index.js.map +0 -1
  135. package/dist/chunk-2KGAN2HM.js +0 -1256
  136. package/dist/chunk-2KGAN2HM.js.map +0 -1
  137. package/dist/chunk-2VZYRB55.js +0 -834
  138. package/dist/chunk-2VZYRB55.js.map +0 -1
  139. package/dist/chunk-3MDZX7YU.js +0 -125
  140. package/dist/chunk-3MDZX7YU.js.map +0 -1
  141. package/dist/chunk-5IBQAPVB.js +0 -29
  142. package/dist/chunk-5IBQAPVB.js.map +0 -1
  143. package/dist/chunk-5QOB7H74.js +0 -387
  144. package/dist/chunk-5QOB7H74.js.map +0 -1
  145. package/dist/chunk-C5RTIBNZ.js +0 -48
  146. package/dist/chunk-C5RTIBNZ.js.map +0 -1
  147. package/dist/chunk-CTRA64LY.js +0 -680
  148. package/dist/chunk-CTRA64LY.js.map +0 -1
  149. package/dist/chunk-DPEUKJRO.js +0 -27
  150. package/dist/chunk-DPEUKJRO.js.map +0 -1
  151. package/dist/chunk-FD2MBMOH.js +0 -494
  152. package/dist/chunk-FD2MBMOH.js.map +0 -1
  153. package/dist/chunk-H5QPIZNX.js +0 -907
  154. package/dist/chunk-H5QPIZNX.js.map +0 -1
  155. package/dist/chunk-HLKC4UYB.js +0 -3514
  156. package/dist/chunk-HLKC4UYB.js.map +0 -1
  157. package/dist/chunk-HNP72PNU.js +0 -192
  158. package/dist/chunk-HNP72PNU.js.map +0 -1
  159. package/dist/chunk-ISPWRSEC.js +0 -408
  160. package/dist/chunk-ISPWRSEC.js.map +0 -1
  161. package/dist/chunk-KRBFHMV6.js +0 -1228
  162. package/dist/chunk-KRBFHMV6.js.map +0 -1
  163. package/dist/chunk-M22PL4GH.js +0 -171
  164. package/dist/chunk-M22PL4GH.js.map +0 -1
  165. package/dist/chunk-NURIQBJQ.js +0 -72
  166. package/dist/chunk-NURIQBJQ.js.map +0 -1
  167. package/dist/chunk-OPVWXJ2H.js +0 -75
  168. package/dist/chunk-OPVWXJ2H.js.map +0 -1
  169. package/dist/chunk-PZZKQVQV.js +0 -52
  170. package/dist/chunk-PZZKQVQV.js.map +0 -1
  171. package/dist/chunk-Q2JSAVQ3.js +0 -671
  172. package/dist/chunk-Q2JSAVQ3.js.map +0 -1
  173. package/dist/chunk-RDOAVVHY.js +0 -699
  174. package/dist/chunk-RDOAVVHY.js.map +0 -1
  175. package/dist/chunk-SGKPNBXE.js +0 -60
  176. package/dist/chunk-SGKPNBXE.js.map +0 -1
  177. package/dist/chunk-SMQXZGLZ.js +0 -351
  178. package/dist/chunk-SMQXZGLZ.js.map +0 -1
  179. package/dist/chunk-UHEZW5BU.js +0 -2918
  180. package/dist/chunk-UHEZW5BU.js.map +0 -1
  181. package/dist/chunk-UPWGXKXB.js +0 -254
  182. package/dist/chunk-UPWGXKXB.js.map +0 -1
  183. package/dist/chunk-VISA6CI3.js +0 -200
  184. package/dist/chunk-VISA6CI3.js.map +0 -1
  185. package/dist/chunk-WMTCUOQL.js +0 -474
  186. package/dist/chunk-WMTCUOQL.js.map +0 -1
  187. package/dist/chunk-WRTOVNN4.js +0 -4728
  188. package/dist/chunk-WRTOVNN4.js.map +0 -1
  189. package/dist/chunk-WSTRQZYQ.js +0 -5576
  190. package/dist/chunk-WSTRQZYQ.js.map +0 -1
  191. package/dist/chunk-XBG2W2VW.js +0 -6434
  192. package/dist/chunk-XBG2W2VW.js.map +0 -1
  193. package/dist/chunk-YEJR7IXO.js +0 -68
  194. package/dist/chunk-YEJR7IXO.js.map +0 -1
  195. package/dist/chunk-YJZA2BIK.js +0 -1338
  196. package/dist/chunk-YJZA2BIK.js.map +0 -1
  197. package/dist/completion-gate-BMy5LGoP.d.ts +0 -256
  198. package/dist/conversation.js.map +0 -1
  199. package/dist/coordination-BZZSVYpZ.d.ts +0 -2570
  200. package/dist/environment-provider.js.map +0 -1
  201. package/dist/improvement-adapter-HAZz-7vK.d.ts +0 -203
  202. package/dist/knowledge.js.map +0 -1
  203. package/dist/local-harness-BDNcl6jI.d.ts +0 -175
  204. package/dist/loop-runner-bin-68aoM9-7.d.ts +0 -199
  205. package/dist/loop-runner-bin.js.map +0 -1
  206. package/dist/loops.js.map +0 -1
  207. package/dist/openai-tools-fnj6SRVg.d.ts +0 -46
  208. package/dist/protected-model-port-B4t-OQjL.d.ts +0 -271
  209. package/dist/redact-BuFjxBUJ.d.ts +0 -481
  210. package/dist/sanitize-DEbPNtyI.d.ts +0 -328
  211. package/dist/structural-rollout-DEh6CEsa.d.ts +0 -446
  212. package/dist/supervise-4_48wwvy.d.ts +0 -379
  213. package/dist/types-BCoemcXU.d.ts +0 -802
  214. package/dist/types-BwoZWq-i.d.ts +0 -510
  215. package/dist/types-Cbp72qyu.d.ts +0 -491
  216. package/dist/types-CmYCMbFT.d.ts +0 -203
  217. package/dist/types-CvNwMzQt.d.ts +0 -957
  218. package/dist/worktree-fanout-DxhAWr5Z.d.ts +0 -999
@@ -0,0 +1,1445 @@
1
+ import { i as InMemorySpawnJournal, r as InMemoryResultBlobStore } from "./spawn-journal-CwPvKUTa.js";
2
+ import { C as routerToolLoop, i as withDriverExecutor, t as createSupervisor } from "./supervisor-DTKhF-RV.js";
3
+ import { createChatClient, estimateCost, isModelPriced, makeFinding } from "@tangle-network/agent-eval";
4
+ import { randomBytes } from "node:crypto";
5
+ //#region src/improvement/optimizer-prompt.ts
6
+ /**
7
+ * The senior scientific-method optimizer doctrine — the ONE substantial prompt
8
+ * core shared by every builder/author surface (tool build, MCP build, codebase
9
+ * improvement, strategy authoring) and by the driver that steers build workers
10
+ * (`driverLoopGenerator`).
11
+ *
12
+ * Seeded from the proven senior prompts rather than invented: GEPA's
13
+ * `REFLECTION_SYSTEM` (localize → diagnose → minimal generalizable fix →
14
+ * preserve what works), the /evolve loop (one hypothesis with a mechanism and a
15
+ * falsifiable prediction; attack the largest measured gap first), /pursue (one
16
+ * coherent change set, no partial scaffolding), and the self-improving-loop /
17
+ * supervisor doctrine (a keep is decided by a real check, never by the author;
18
+ * observe → rate → decide). Generalized from "mutate a prompt string" to
19
+ * "build a code surface a held-out measurement will grade".
20
+ */
21
+ /**
22
+ * The shared method block every build/author prompt embeds. Domain framing
23
+ * (what a tool/MCP/codebase-edit deliverable looks like) wraps around it; this
24
+ * is the process itself.
25
+ */
26
+ const optimizerMethod = [
27
+ "THE METHOD — you are a senior engineer-scientist improving a measured system, not a code",
28
+ "generator. Your change is an experiment: it exists to move a real, externally graded number,",
29
+ "and it will be measured against a baseline on held-out tasks you cannot see. Work in this order:",
30
+ "",
31
+ "1. DIAGNOSE FIRST. Read every finding before touching anything — findings are ranked evidence",
32
+ " from real failed runs. Name the DOMINANT failure mode (the single mechanism behind the",
33
+ " largest share of failures) in one sentence. Attack that first; leave long-tail noise until",
34
+ " the dominant mode is closed. A fix aimed at the wrong mechanism measures zero however clean",
35
+ " the code is.",
36
+ "2. STATE A HYPOTHESIS WITH A PREDICTED LIFT. Before designing, write down: \"failures like X",
37
+ " happen because MECHANISM; this change interrupts that mechanism; I predict it addresses",
38
+ " roughly N of the M findings shown.\" A change you cannot connect to a mechanism is a guess,",
39
+ " not an experiment.",
40
+ "3. DECOMPOSE INTO SUB-GOALS. Break the work into steps that are each independently checkable",
41
+ " (it compiles, a test passes, the server answers). Sequence them so the riskiest assumption",
42
+ " is tested first — if the hypothesis is wrong, find out on step 1, not step 5.",
43
+ "4. DESIGN TO ISOLATE THE MECHANISM. Make the smallest COHERENT change that fully tests the",
44
+ " hypothesis: small enough that a measured lift is attributable to this change alone, complete",
45
+ " enough that it actually fires on the real execution path (a lever that exists but never",
46
+ " fires measures zero). No drive-by refactors, no unrelated cleanup, no speculative scope —",
47
+ " anything changed alongside confounds the measurement.",
48
+ "5. GENERALIZE, NEVER MEMORIZE. Fix the failure CLASS, not the shown instances: encode rules and",
49
+ " logic that transfer to unseen tasks. A patch memorized to the quoted examples will not",
50
+ " survive the held-out measurement — that is overfitting, and the gate will catch it.",
51
+ "6. PRESERVE WHAT WORKS. The baseline already passes tasks; do not delete or weaken the behavior",
52
+ " those passes depend on. A fix that trades one failure class for a new one measures as noise.",
53
+ "7. VERIFY FOR REAL, THEN REFLECT. Run the verification you were given and make it genuinely",
54
+ " pass — never weaken a check, stub the thing it exercises, or special-case its inputs; a",
55
+ " gamed check delivers nothing because promotion is decided by a separate measurement you",
56
+ " never see. Then record briefly: what you predicted, what the verifier actually showed, and",
57
+ " what you would try next if the measured lift comes back null."
58
+ ].join("\n");
59
+ /**
60
+ * The driver's stance for `driverLoopGenerator` — the build-domain instance of
61
+ * the supervisor doctrine (observe → rate → decide; refine / re-scope /
62
+ * decompose; the check decides delivery, never the driver's prose).
63
+ */
64
+ const buildDriverSystem = [
65
+ "You are the DRIVER of a build loop: a senior engineering lead steering a coding WORKER inside",
66
+ "an isolated git worktree toward a verified artifact. You never edit files yourself — your only",
67
+ "levers are the tools below. Your intelligence goes into three places: how you AUTHOR each",
68
+ "worker instruction, how you OBSERVE and RATE what a session actually produced, and what you",
69
+ "DECIDE next.",
70
+ "",
71
+ "TOOLS",
72
+ "- run_worker{instruction}: one full coding-harness session in the worktree, with your",
73
+ " instruction as its entire goal. Sessions are expensive and capped — author each one well.",
74
+ " The worktree PERSISTS between sessions: a later worker resumes on top of earlier edits.",
75
+ "- inspect_worktree{}: current git status + diff — what has actually changed so far.",
76
+ "- read_file{path,maxBytes?}: read one file from the worktree (new untracked files do not show",
77
+ " in the diff — read them to rate the work).",
78
+ "- run_verifier{}: the intrinsic check of the surface (compile+tests for a tool, boot-and-probe",
79
+ " for an MCP server). Its exit decides what counts as delivered — your opinion does not.",
80
+ "",
81
+ "AUTHOR RICHLY. A worker handed a one-line label will flail. Each instruction must carry: the",
82
+ "outcome in concrete terms; the hypothesis and sub-goal it serves; what already exists in the",
83
+ "tree that it must build on, not duplicate; where the deliverable must land; and the exact check",
84
+ "it will be held to. The worker sees NOTHING you were given (no findings, no method, no prior",
85
+ "session context) unless you fold it into the instruction.",
86
+ "",
87
+ "THE LOOP — every turn: observe, rate, decide.",
88
+ "- OBSERVE: after each session, inspect the worktree and run the verifier. Read WHAT failed and",
89
+ " WHY — \"it failed\" alone tells you nothing.",
90
+ "- RATE: judge with a reason. Verified and complete → stop. Close, one correctable fault →",
91
+ " REFINE: author \"continue from the current tree; the check fails because X; fix X\" (depth,",
92
+ " not a fresh start — never let a worker revert its own near-miss). Empty tree, or it solved a",
93
+ " different problem → RE-SCOPE: re-author narrower and more concrete; a second identical",
94
+ " instruction fails identically. Too big for one session → DECOMPOSE: author the first",
95
+ " self-contained slice, verify it, then author the next on top.",
96
+ "- DECIDE: exactly one move per turn, with the reason stated in one line.",
97
+ "",
98
+ "STOP when the verifier passes — reply with no tool call and a short reflection: what you",
99
+ "predicted, what the verifier showed, what you would try next if the measured lift comes back",
100
+ "null. If the session budget runs out first, say plainly what remains and why. An honest",
101
+ "no-winner is a real result; a claimed success is not — the final keep/discard decision is made",
102
+ "by code from the verifier exit and the tree state, never from your words."
103
+ ].join("\n");
104
+ /**
105
+ * The driver's ADOPT-not-build doctrine, appended to `buildDriverSystem` when
106
+ * a `research` tool is wired into the loop (`DriverLoopGeneratorOptions.
107
+ * research`). Kept separate so a driver WITHOUT the tool is never told to
108
+ * call a tool it does not have.
109
+ */
110
+ const researchDriverNote = [
111
+ "RESEARCH — ADOPT BEFORE BUILD. A research{query} tool is provisioned for this run. Before",
112
+ "authoring a from-scratch build, spend one turn researching whether an EXISTING external MCP",
113
+ "server already provides the missing capability — registries and vendor docs list maintained",
114
+ "servers for most common gaps (web search, fetch, GitHub, filesystems, databases).",
115
+ "- If a maintained server fits, ADOPT it: report in your final reflection its endpoint or",
116
+ " launch command and the API key it needs BY NAME (e.g. EXA_API_KEY) — never a key value —",
117
+ " so the dispatch can emit a connection candidate with provisioned secrets. Adopting a fit",
118
+ " server beats rebuilding it: less code to verify, maintained upstream, same measured gate.",
119
+ "- If nothing fits (unmaintained, wrong tool surface, heavier than the gap), build — and state",
120
+ " in one line why adoption lost."
121
+ ].join("\n");
122
+ /**
123
+ * The senior authoring process for `authorStrategy` — the same method, shaped
124
+ * to the strategy contract (author-blind, conserved budget, one module out).
125
+ */
126
+ const strategyAuthorMethod = [
127
+ "Work as a senior researcher, in this order:",
128
+ "1. DIAGNOSE: read the per-task losses above and name the DOMINANT failure mode in one sentence",
129
+ " — the single mechanism behind the largest share of lost score (e.g. first attempts near-miss",
130
+ " and never get corrected; fresh retries discard progress; one persona plateaus).",
131
+ "2. HYPOTHESIS + PREDICTED LIFT: state \"these losses happen because MECHANISM; the composition",
132
+ " below interrupts it; I predict roughly +N on this environment at the same budget.\"",
133
+ "3. DESIGN TO ISOLATE THE MECHANISM: change ONE coordination mechanism relative to the baselines",
134
+ " (carry vs fresh, where the critique lands, a persona split, a tool restriction) so any",
135
+ " measured lift is attributable to it. Do not stack three clever ideas — a tangled win teaches",
136
+ " nothing and a tangled loss cannot be debugged.",
137
+ "4. DECOMPOSE THE BUDGET: plan how the shots divide across explore / attempt / critique / repair",
138
+ " before writing code, and spend the whole budget — an early stop on a mid score is a loss.",
139
+ "5. GENERALIZE: the strategy runs on unseen tasks from this environment. Read tools via",
140
+ " listTools(handle), never hardcode task specifics from the losses shown.",
141
+ "6. PREDICT, THEN REFLECT: put the hypothesis, the mechanism, and the predicted lift in a",
142
+ " comment at the top of the module — the holdout verdict will be read against it."
143
+ ].join("\n");
144
+ //#endregion
145
+ //#region src/runtime/observe.ts
146
+ /**
147
+ * The third-person observer — the connective tissue that closes the loop.
148
+ *
149
+ * A driver spawns a worker; the worker can't see itself. `observe` reads the
150
+ * worker's TRACE (what it actually did — every tool call, cost, failure) and
151
+ * produces two streams:
152
+ * - `findings` / `report` — fed back DOWN (a steer for the next attempt) and
153
+ * OUT (the operator-facing "what I noticed + what to change").
154
+ * - `learned` — durable facts written to the cross-run `Corpus` so the NEXT
155
+ * run starts smarter (the continuous half of "continuous self-improvement").
156
+ *
157
+ * Findings are TRACE-derived, never JUDGE-derived (`derived_from_judge:false`):
158
+ * the observer reads behavior, never the acceptance verdict — the selector≠judge
159
+ * firewall (docs/learning-flywheel.md). The observer is harness-agnostic: it
160
+ * reads a trace + an output, so it watches opencode, codex, hermes, or a BYO
161
+ * agent identically.
162
+ */
163
+ const observerId = "observe/trace";
164
+ /** The default observer instruction — exported so an optimizer can seed its population. */
165
+ const defaultAnalystInstruction = "You are a third-person OBSERVER watching an AI agent work. You see its TRACE (what it did), not its grader. From the trace, name SPECIFIC, behavior-grounded findings: wasted/duplicated tool calls, thrash/retries, token/cost waste, missing verification, failure patterns. For each, a concrete recommended_action, and whether the AGENT (fix its skills/prompt/tools) or the OPERATOR (fix framing/decomposition/config) should act. Only claim what the trace shows. No findings if the run was clean.";
166
+ /** Compact the trace into the lines the observer reasons over — tool calls,
167
+ * errors, and statuses, in order. Keeps the model call bounded + grounded. */
168
+ function summarizeTrace(trace, maxLines) {
169
+ const lines = [];
170
+ for (const ev of trace) {
171
+ const e = ev;
172
+ const t = (e.type ?? "").toLowerCase();
173
+ const d = e.data ?? {};
174
+ const part = d.part ?? {};
175
+ if (part.type === "tool") lines.push(`tool:${part.tool}${part.state?.status ? `(${part.state.status})` : ""}`);
176
+ else if (t.includes("error")) lines.push(`ERROR: ${String(d.message ?? d.detail ?? "").slice(0, 200)}`);
177
+ else if (t === "status" && typeof d.status === "string") lines.push(`status:${d.status}`);
178
+ else if (t.includes("tool")) lines.push(`tool-event:${t}`);
179
+ }
180
+ const out = [];
181
+ for (const ln of lines) {
182
+ const m = out[out.length - 1]?.match(/^(.*?)(?: x(\d+))?$/);
183
+ if (m && m[1] === ln) out[out.length - 1] = `${ln} x${(Number(m[2]) || 1) + 1}`;
184
+ else out.push(ln);
185
+ }
186
+ return out.slice(0, maxLines).join("\n") || "(no tool/error events in trace)";
187
+ }
188
+ const findingsSchema = {
189
+ name: "observer_findings",
190
+ schema: {
191
+ type: "object",
192
+ additionalProperties: false,
193
+ properties: { findings: {
194
+ type: "array",
195
+ items: {
196
+ type: "object",
197
+ additionalProperties: false,
198
+ properties: {
199
+ area: {
200
+ type: "string",
201
+ description: "tool-use | cost | verification | process | failure | latency"
202
+ },
203
+ severity: {
204
+ type: "string",
205
+ enum: [
206
+ "critical",
207
+ "high",
208
+ "medium",
209
+ "low",
210
+ "info"
211
+ ]
212
+ },
213
+ claim: {
214
+ type: "string",
215
+ description: "what you OBSERVED in the trace (a fact, with the evidence)"
216
+ },
217
+ recommended_action: {
218
+ type: "string",
219
+ description: "the concrete change for the agent or operator"
220
+ },
221
+ audience: {
222
+ type: "string",
223
+ enum: ["agent", "operator"],
224
+ description: "who should act on this"
225
+ },
226
+ confidence: { type: "number" }
227
+ },
228
+ required: [
229
+ "area",
230
+ "severity",
231
+ "claim",
232
+ "recommended_action",
233
+ "audience",
234
+ "confidence"
235
+ ]
236
+ }
237
+ } },
238
+ required: ["findings"]
239
+ }
240
+ };
241
+ /** The third-person trace analyst: read a worker's trace and produce steer findings for the next attempt plus durable `learned` facts for the cross-run corpus. */
242
+ async function observe(input, opts) {
243
+ const traceSummary = summarizeTrace(input.trace, opts.maxTraceLines ?? 80);
244
+ const parsed = parseFindings((await opts.chat.chat({
245
+ ...opts.model ? { model: opts.model } : {},
246
+ jsonSchema: findingsSchema,
247
+ messages: [{
248
+ role: "system",
249
+ content: opts.analystInstruction ?? "You are a third-person OBSERVER watching an AI agent work. You see its TRACE (what it did), not its grader. From the trace, name SPECIFIC, behavior-grounded findings: wasted/duplicated tool calls, thrash/retries, token/cost waste, missing verification, failure patterns. For each, a concrete recommended_action, and whether the AGENT (fix its skills/prompt/tools) or the OPERATOR (fix framing/decomposition/config) should act. Only claim what the trace shows. No findings if the run was clean."
250
+ }, {
251
+ role: "user",
252
+ content: `TASK: ${input.task}\n\nOUTCOME: ${input.outcome ?? "unknown"}\n\nFINAL OUTPUT (truncated):\n${input.output.slice(0, 1200)}\n\nTRACE (in order; "xN" = repeated):\n${traceSummary}`
253
+ }]
254
+ }, { ...opts.signal ? { signal: opts.signal } : {} })).content);
255
+ const producedAt = input.runId ? `${input.runId}` : observerId;
256
+ const findings = parsed.map((f) => makeFinding({
257
+ analyst_id: observerId,
258
+ area: `${f.area}`,
259
+ severity: f.severity,
260
+ claim: f.claim,
261
+ recommended_action: f.recommended_action,
262
+ confidence: typeof f.confidence === "number" ? f.confidence : .5,
263
+ evidence_refs: [],
264
+ derived_from_judge: false,
265
+ metadata: { audience: f.audience },
266
+ ...input.runId ? { subject: input.runId } : {}
267
+ }));
268
+ const learned = [];
269
+ if (opts.corpus) for (const f of findings) {
270
+ const record = {
271
+ schemaVersion: "1.0.0",
272
+ id: f.finding_id,
273
+ runId: input.runId ?? observerId,
274
+ producedAt: f.produced_at ?? producedAt,
275
+ area: f.area,
276
+ claim: f.recommended_action ?? f.claim,
277
+ ...f.claim ? { rationale: f.claim } : {},
278
+ tags: [...opts.tags ?? [], `audience:${f.metadata?.audience ?? "agent"}`],
279
+ confidence: f.confidence,
280
+ evidence: [{
281
+ kind: "finding",
282
+ uri: f.finding_id
283
+ }]
284
+ };
285
+ if ((await opts.corpus.append(record)).succeeded) learned.push(record);
286
+ }
287
+ return {
288
+ findings,
289
+ learned,
290
+ report: renderReport(findings)
291
+ };
292
+ }
293
+ function parseFindings(content) {
294
+ let obj;
295
+ try {
296
+ obj = JSON.parse(content);
297
+ } catch {
298
+ const m = content.match(/\{[\s\S]*\}/);
299
+ obj = m ? JSON.parse(m[0]) : { findings: [] };
300
+ }
301
+ const arr = obj.findings;
302
+ return Array.isArray(arr) ? arr : [];
303
+ }
304
+ /** Operator-facing report, split by who should act. The agent block is the
305
+ * steer; the operator block is the advice. */
306
+ function renderReport(findings) {
307
+ if (findings.length === 0) return "✓ clean run — the observer found nothing to change.";
308
+ const audience = (f) => f.metadata?.audience ?? "agent";
309
+ const forAgent = findings.filter((f) => audience(f) === "agent");
310
+ const forOperator = findings.filter((f) => audience(f) === "operator");
311
+ const block = (title, fs) => fs.length === 0 ? "" : `**${title}**\n${fs.map((f) => `- [${f.severity}] ${f.claim}\n → ${f.recommended_action ?? ""}`).join("\n")}\n`;
312
+ return [block("For the agent (fix skills / prompt / tools)", forAgent), block("For you (the operator)", forOperator)].filter(Boolean).join("\n");
313
+ }
314
+ //#endregion
315
+ //#region src/runtime/strategy.ts
316
+ /**
317
+ * The general agentic primitive — sequential (depth) and parallel (breadth) over a shared,
318
+ * checkable artifact, driven through the keystone Supervisor as one recursive `Agent.act`.
319
+ *
320
+ * The domain lives behind ONE seam — `AgenticSurface` (open an artifact, list tools, call a tool,
321
+ * score the artifact, close it). EnterpriseOps implements it (seed a gym DB, MCP tools, SQL
322
+ * verifier); Commit0/AppWorld/terminal-bench implement it the same way (a repo workspace, shell
323
+ * tools, the test suite). The drivers below are domain-blind: they run over any surface.
324
+ *
325
+ * Two shapes, the agent's POMDP rollout as the unit:
326
+ * - DEPTH one persistent artifact carried across shots. Each shot the agent works the tool loop;
327
+ * between shots a trace-analyst (selector≠judge: reads the trajectory, never the score)
328
+ * steers the resumed session toward what's unfinished. shot n stands on shot n-1's
329
+ * artifact state + history. This is continuation — long-horizon, same artifact.
330
+ * - BREADTH K independent artifacts, each a fresh rollout, the deployable verifier picks the best.
331
+ *
332
+ * Both are an `Agent` whose `act` spawns leaf shots through `scope.spawn` and reacts via
333
+ * `scope.next()` — so the conserved budget pool meters them (equal-k by construction), the journal
334
+ * records the tree, and the same primitive nests. `runAgentic` runs the chosen driver through
335
+ * `createSupervisor().run`. The leaf (one shot over a handle) is resolved per-spawn from a
336
+ * surface-closed registry — the open `Executor` seam, not bespoke per-benchmark glue.
337
+ */
338
+ const taskNudge = "Use the available tools to bring the artifact to the required final state. Address EVERY distinct change the request implies. After each tool result, check what remains and continue. Re-read the values you set to confirm they took. Reply DONE only once every required change is made and verified.";
339
+ /** One shot: run the agent's tool loop (≤ innerTurns) over the handle, mutating the artifact via
340
+ * `surface.call`, carrying `messages`. Returns the updated conversation + counts. */
341
+ async function runShot(surface, _task, handle, tools, messages, opts, modelOverride) {
342
+ let toolErrors = 0;
343
+ const execute = async (name, args) => {
344
+ try {
345
+ const out = await surface.call(handle, name, args);
346
+ if (out.startsWith("ERROR:")) toolErrors += 1;
347
+ return out;
348
+ } catch (e) {
349
+ toolErrors += 1;
350
+ return `ERROR: ${e instanceof Error ? e.message : String(e)}`;
351
+ }
352
+ };
353
+ const r = await routerToolLoop({
354
+ routerBaseUrl: opts.routerBaseUrl,
355
+ routerKey: opts.routerKey,
356
+ model: modelOverride ?? opts.model,
357
+ ...opts.complete ? { complete: opts.complete } : {}
358
+ }, "", "", tools, execute, {
359
+ maxTurns: opts.innerTurns ?? 4,
360
+ temperature: opts.temperature ?? .7,
361
+ initialMessages: messages,
362
+ ...opts.maxTokens ? { maxTokens: opts.maxTokens } : {}
363
+ });
364
+ return {
365
+ messages: r.messages,
366
+ completions: r.turns,
367
+ toolCalls: r.toolCalls,
368
+ toolErrors,
369
+ tokens: r.usage
370
+ };
371
+ }
372
+ /** The firewall's input shape: the trajectory as compacted text — calls, results,
373
+ * assistant text. NEVER scores, NEVER check internals. Shared by both analyst channels. */
374
+ function compactTrajectory(messages) {
375
+ return messages.filter((m) => m.role === "assistant" || m.role === "tool").map((m) => {
376
+ if (m.role === "tool") return `RESULT ${String(m.content).slice(0, 280)}`;
377
+ const calls = m.tool_calls?.map((c) => `${c.function.name}(${c.function.arguments})`).join(", ");
378
+ return calls ? `CALL ${calls}` : `SAY ${String(m.content).slice(0, 200)}`;
379
+ }).join("\n").slice(0, 7e3);
380
+ }
381
+ /** The analyst's chat seam: the live router by default, or — when a `complete` transport is
382
+ * injected — that SAME transport, so an offline run drives the critic with no network too (the
383
+ * worker and the analyst share the one injected responder, exactly as a localhost mock would
384
+ * serve both). The critic speaks the OpenAI request shape; we forward it to `complete` and lift
385
+ * the parsed `/chat/completions` JSON back into a `ChatResponse`. */
386
+ function analystChat(opts, defaultModel) {
387
+ if (!opts.complete) return createChatClient({
388
+ transport: "router",
389
+ apiKey: opts.routerKey,
390
+ baseUrl: opts.routerBaseUrl,
391
+ defaultModel
392
+ });
393
+ const complete = opts.complete;
394
+ return createChatClient({
395
+ transport: "mock",
396
+ defaultModel,
397
+ handler: async (req) => {
398
+ const raw = await complete({
399
+ model: req.model ?? defaultModel,
400
+ messages: req.messages,
401
+ ...req.temperature !== void 0 ? { temperature: req.temperature } : {},
402
+ ...req.maxTokens !== void 0 ? { max_tokens: req.maxTokens } : {}
403
+ });
404
+ const content = raw.choices?.[0]?.message?.content ?? "";
405
+ const promptTokens = raw.usage?.prompt_tokens ?? 0;
406
+ const completionTokens = raw.usage?.completion_tokens ?? 0;
407
+ return {
408
+ content,
409
+ usage: {
410
+ promptTokens,
411
+ completionTokens,
412
+ totalTokens: promptTokens + completionTokens
413
+ },
414
+ costUsd: null,
415
+ model: req.model ?? defaultModel,
416
+ durationMs: 0,
417
+ finishReason: raw.choices?.[0]?.finish_reason ?? null,
418
+ contentEmpty: content.trim().length === 0,
419
+ raw
420
+ };
421
+ }
422
+ });
423
+ }
424
+ /** The RAW analyst channel: the firewalled critic answers `instruction` over the
425
+ * trajectory directly — no findings schema, no recommended-action extraction. The
426
+ * channel for verdict-shaped steering (budget controllers, calibrated predictions)
427
+ * whose output format the findings protocol would strip. Same firewall as analyze():
428
+ * trajectory in, never scores. */
429
+ async function consultAnalyst(task, messages, instruction, opts) {
430
+ const trajectory = compactTrajectory(messages);
431
+ const analystModel = opts.analystModel ?? opts.model;
432
+ const chat = analystChat(opts, analystModel);
433
+ const consultMessages = trajectory ? [{
434
+ role: "system",
435
+ content: instruction
436
+ }, {
437
+ role: "user",
438
+ content: `TASK: ${task.userPrompt.slice(0, 1500)}\n\nTRAJECTORY:\n${trajectory}`
439
+ }] : [{
440
+ role: "user",
441
+ content: `${instruction}\n\nTASK:\n${task.userPrompt.slice(0, 1500)}`
442
+ }];
443
+ const res = await chat.chat({
444
+ model: analystModel,
445
+ temperature: .2,
446
+ maxTokens: 1024,
447
+ messages: consultMessages
448
+ });
449
+ const usage = res.usage;
450
+ return {
451
+ steer: res.content.trim(),
452
+ tokens: {
453
+ input: usage?.promptTokens ?? usage?.prompt_tokens ?? 0,
454
+ output: usage?.completionTokens ?? usage?.completion_tokens ?? 0
455
+ }
456
+ };
457
+ }
458
+ async function analyze(task, messages, opts) {
459
+ const trajectory = compactTrajectory(messages);
460
+ const analystModel = opts.analystModel ?? opts.model;
461
+ const inner = analystChat(opts, analystModel);
462
+ const tokens = {
463
+ input: 0,
464
+ output: 0
465
+ };
466
+ const chat = {
467
+ ...inner,
468
+ chat: async (req, callOpts) => {
469
+ const res = await inner.chat(req, callOpts);
470
+ const u = res.usage;
471
+ if (u) {
472
+ tokens.input += u.promptTokens ?? u.prompt_tokens ?? 0;
473
+ tokens.output += u.completionTokens ?? u.completion_tokens ?? 0;
474
+ }
475
+ return res;
476
+ }
477
+ };
478
+ return {
479
+ steer: (await observe({
480
+ task: task.userPrompt,
481
+ output: trajectory,
482
+ trace: messages,
483
+ outcome: "failed",
484
+ runId: task.id
485
+ }, {
486
+ chat,
487
+ model: analystModel,
488
+ ...opts.analystInstruction ? { analystInstruction: opts.analystInstruction } : {},
489
+ ...opts.corpus ? {
490
+ corpus: opts.corpus,
491
+ tags: opts.corpusTags ?? []
492
+ } : {}
493
+ })).findings.map((f) => f.recommended_action).filter((a) => typeof a === "string" && a.trim().length > 0).join("\n").trim() || "COMPLETE",
494
+ tokens
495
+ };
496
+ }
497
+ async function renderCorpusReadback(opts) {
498
+ if (!opts.corpus || !opts.corpusReadback) return "";
499
+ const maxFacts = opts.corpusReadback.maxFacts ?? 3;
500
+ if (!Number.isInteger(maxFacts) || maxFacts < 0) throw new Error(`corpusReadback.maxFacts must be a non-negative integer, got ${maxFacts}`);
501
+ if (maxFacts === 0) return "";
502
+ const tags = [
503
+ ...opts.corpusTags ?? [],
504
+ ...opts.corpusReadback.tags ?? [],
505
+ ...opts.corpusReadback.includeOperatorFacts ? [] : ["audience:agent"]
506
+ ];
507
+ const facts = await opts.corpus.query({
508
+ ...tags.length > 0 ? { tags } : {},
509
+ minConfidence: opts.corpusReadback.minConfidence ?? .7,
510
+ limit: maxFacts
511
+ });
512
+ if (facts.length === 0) return "";
513
+ return `Relevant learned facts from prior attempts:\n${facts.map((fact) => fact.rationale ? `- ${fact.claim} (${fact.rationale})` : `- ${fact.claim}`).join("\n")}`;
514
+ }
515
+ /** Resolve a shot: if `handle` given, operate on the SHARED artifact (depth); else open+score+close
516
+ * an OWN artifact (breadth). Always scores the artifact's final state as the deployable verdict. */
517
+ function shotExecutor(surface, opts) {
518
+ let artifact;
519
+ return {
520
+ runtime: "agentic-shot",
521
+ async execute(task) {
522
+ const t = task;
523
+ const own = !t.handle;
524
+ const handle = t.handle ?? await surface.open(t.task);
525
+ try {
526
+ const allTools = await surface.tools(t.task, handle);
527
+ let tools = allTools;
528
+ if (t.tools) {
529
+ const known = new Set(allTools.map((tool) => tool.function.name));
530
+ const unknown = t.tools.filter((name) => !known.has(name));
531
+ if (unknown.length > 0) throw new Error(`shot tools: unknown tool name(s) ${unknown.join(", ")} — domain offers: ${[...known].join(", ")}`);
532
+ const want = new Set(t.tools);
533
+ tools = allTools.filter((tool) => want.has(tool.function.name));
534
+ }
535
+ const messages = t.messages?.length ? t.messages : [{
536
+ role: "system",
537
+ content: t.persona?.systemPrompt ?? t.task.systemPrompt
538
+ }, {
539
+ role: "user",
540
+ content: `${t.task.userPrompt}\n\n${taskNudge}`
541
+ }];
542
+ if (t.messages?.length && t.persona?.systemPrompt) messages.push({
543
+ role: "user",
544
+ content: `[hand-off] You are now acting as: ${t.persona.systemPrompt}`
545
+ });
546
+ if (t.steer) messages.push({
547
+ role: "user",
548
+ content: t.steer
549
+ });
550
+ const shot = await runShot(surface, t.task, handle, tools, messages, opts, t.persona?.model);
551
+ const s = await surface.score(t.task, handle);
552
+ const score = s.total > 0 ? s.passes / s.total : 0;
553
+ const out = {
554
+ messages: shot.messages,
555
+ score,
556
+ passes: s.passes,
557
+ total: s.total,
558
+ completions: shot.completions,
559
+ toolErrors: shot.toolErrors
560
+ };
561
+ artifact = {
562
+ outRef: `shot:${handle.id}:${shot.completions}:${s.passes}/${s.total}`,
563
+ out,
564
+ verdict: {
565
+ valid: s.total > 0 && s.passes === s.total,
566
+ score
567
+ },
568
+ spent: {
569
+ iterations: shot.completions,
570
+ tokens: shot.tokens,
571
+ usd: isModelPriced(opts.model) ? estimateCost(shot.tokens.input, shot.tokens.output, opts.model) : 0,
572
+ ms: 0
573
+ }
574
+ };
575
+ return artifact;
576
+ } finally {
577
+ if (own) await surface.close(handle);
578
+ }
579
+ },
580
+ teardown: () => Promise.resolve({ destroyed: true }),
581
+ resultArtifact() {
582
+ if (!artifact) throw new Error("shotExecutor: resultArtifact before execute");
583
+ return artifact;
584
+ }
585
+ };
586
+ }
587
+ function analystExecutor(opts) {
588
+ let artifact;
589
+ return {
590
+ runtime: "agentic-analyst",
591
+ async execute(task) {
592
+ const t = task;
593
+ const { steer, tokens } = t.rawInstruction ? await consultAnalyst(t.task, t.messages, t.rawInstruction, opts) : await analyze(t.task, t.messages, opts);
594
+ const analystModel = opts.analystModel ?? opts.model;
595
+ artifact = {
596
+ outRef: `analyst:${steer.length}`,
597
+ out: steer,
598
+ spent: {
599
+ iterations: 1,
600
+ tokens,
601
+ usd: isModelPriced(analystModel) ? estimateCost(tokens.input, tokens.output, analystModel) : 0,
602
+ ms: 0
603
+ }
604
+ };
605
+ return artifact;
606
+ },
607
+ teardown: () => Promise.resolve({ destroyed: true }),
608
+ resultArtifact() {
609
+ if (!artifact) throw new Error("analystExecutor: resultArtifact before execute");
610
+ return artifact;
611
+ }
612
+ };
613
+ }
614
+ /**
615
+ * Registry dispatching on the child's role tag — fresh executor per spawn (no
616
+ * shared-instance race). `withDriverExecutor` wraps it so a `role:'driver'` child resolves
617
+ * to the recursive driver-executor (a child that drives its OWN children — agents drive
618
+ * agents) before this leaf dispatch; `shot`/`analyst` children resolve to their leaf
619
+ * executors here unchanged.
620
+ */
621
+ function agenticRegistry(surface, opts) {
622
+ return withDriverExecutor({
623
+ register() {
624
+ throw new Error("agenticRegistry: register unsupported");
625
+ },
626
+ resolve(spec) {
627
+ const role = spec.profile.metadata?.role;
628
+ const factory = (_s, _ctx) => role === "analyst" ? analystExecutor(opts) : shotExecutor(surface, opts);
629
+ return {
630
+ succeeded: true,
631
+ value: factory
632
+ };
633
+ }
634
+ });
635
+ }
636
+ function leaf(name, role) {
637
+ return {
638
+ name,
639
+ executorSpec: {
640
+ profile: {
641
+ name,
642
+ metadata: { role }
643
+ },
644
+ harness: null
645
+ },
646
+ act() {
647
+ throw new Error(`agentic: spawned child "${name}" was run directly (the executor drives it)`);
648
+ }
649
+ };
650
+ }
651
+ /** Drain exactly one settlement (the just-spawned child). */
652
+ async function drainOne(scope) {
653
+ const s = await scope.next();
654
+ if (!s) throw new Error("agentic: spawned child never settled");
655
+ return s;
656
+ }
657
+ const perChild = (innerTurns) => ({
658
+ maxIterations: innerTurns + 1,
659
+ maxTokens: 1e6
660
+ });
661
+ /** DEPTH: one persistent artifact, carried across analyst-steered shots. */
662
+ function depthStrategy(surface, task, opts, cfg) {
663
+ const innerTurns = opts.innerTurns ?? 4;
664
+ let pendingSteer;
665
+ return {
666
+ name: "depth",
667
+ async act(_t, scope) {
668
+ const handle = await surface.open(task);
669
+ const progression = [];
670
+ let messages;
671
+ let completions = 0;
672
+ let shots = 0;
673
+ try {
674
+ for (shots = 0; shots < cfg.maxShots; shots += 1) {
675
+ const child = leaf(`shot:${shots}`, "shot");
676
+ const memorySteer = await renderCorpusReadback(opts);
677
+ const steer = [shots === 0 ? void 0 : pendingSteer, memorySteer].filter((part) => typeof part === "string" && part.trim().length > 0).join("\n\n");
678
+ if (!scope.spawn(child, {
679
+ task,
680
+ handle,
681
+ messages,
682
+ steer
683
+ }, {
684
+ budget: perChild(innerTurns),
685
+ label: `shot:${shots}`
686
+ }).ok) break;
687
+ const settled = await drainOne(scope);
688
+ if (settled.kind === "down") break;
689
+ const out = settled.out;
690
+ messages = out.messages;
691
+ completions += out.completions;
692
+ progression.push(out.score);
693
+ if (out.score >= 1 || shots === cfg.maxShots - 1) break;
694
+ const aChild = leaf(`analyst:${shots}`, "analyst");
695
+ if (!scope.spawn(aChild, {
696
+ task,
697
+ messages
698
+ }, {
699
+ budget: perChild(1),
700
+ label: `analyst:${shots}`
701
+ }).ok) break;
702
+ const aSettled = await drainOne(scope);
703
+ completions += 1;
704
+ if (aSettled.kind === "down") break;
705
+ const findings = aSettled.out;
706
+ if (/^\s*COMPLETE\b/i.test(findings)) break;
707
+ pendingSteer = `A reviewer flagged unfinished items:\n${findings}\n\nAddress each with the tools, verify they took, then continue.`;
708
+ }
709
+ const final = await surface.score(task, handle);
710
+ return {
711
+ kind: "done",
712
+ deliverable: {
713
+ mode: "depth",
714
+ score: final.total > 0 ? final.passes / final.total : 0,
715
+ resolved: final.total > 0 && final.passes === final.total,
716
+ completions,
717
+ progression,
718
+ shots: shots + 1
719
+ }
720
+ };
721
+ } finally {
722
+ await surface.close(handle);
723
+ }
724
+ }
725
+ };
726
+ }
727
+ /** BREADTH: K independent rollouts (each own artifact), verifier picks the best. */
728
+ function breadthStrategy(_surface, task, opts, cfg) {
729
+ const innerTurns = opts.innerTurns ?? 4;
730
+ return {
731
+ name: "breadth",
732
+ async act(_t, scope) {
733
+ let opened = 0;
734
+ for (let k = 0; k < cfg.width; k += 1) if (scope.spawn(leaf(`rollout:${k}`, "shot"), { task }, {
735
+ budget: perChild(innerTurns),
736
+ label: `rollout:${k}`
737
+ }).ok) opened += 1;
738
+ if (opened === 0) return {
739
+ kind: "blocked",
740
+ blockers: ["breadth: pool admitted no rollout"]
741
+ };
742
+ let best = -1;
743
+ let bestResolved = false;
744
+ let completions = 0;
745
+ const progression = [];
746
+ for (let s = await scope.next(); s !== null; s = await scope.next()) {
747
+ if (s.kind === "down") continue;
748
+ const out = s.out;
749
+ completions += out.completions;
750
+ if (out.score > best) best = out.score;
751
+ if (out.total > 0 && out.passes === out.total) bestResolved = true;
752
+ progression.push(best);
753
+ }
754
+ if (best < 0) return {
755
+ kind: "blocked",
756
+ blockers: ["breadth: every rollout went down"]
757
+ };
758
+ return {
759
+ kind: "done",
760
+ deliverable: {
761
+ mode: "breadth",
762
+ score: best,
763
+ resolved: bestResolved,
764
+ completions,
765
+ progression,
766
+ shots: opened
767
+ }
768
+ };
769
+ }
770
+ };
771
+ }
772
+ /** Built-in `Strategy`: K independent attempts, keep the best-verifying (best-of-N / resample). */
773
+ const sample = {
774
+ name: "sample",
775
+ driver: (surface, task, opts, budget) => breadthStrategy(surface, task, opts, { width: budget })
776
+ };
777
+ /** Built-in `Strategy`: attempt → `observe()` reads the trace → steer the next attempt → repeat (deepen one lineage). */
778
+ const refine = {
779
+ name: "refine",
780
+ driver: (surface, task, opts, budget) => depthStrategy(surface, task, opts, { maxShots: budget })
781
+ };
782
+ /** Author a Strategy from the composable steps — the open, compact way. */
783
+ function defineStrategy(name, run) {
784
+ return {
785
+ name,
786
+ driver: (surface, task, opts, budget) => ({
787
+ name,
788
+ async act(_t, scope) {
789
+ let seq = 0;
790
+ const innerTurns = opts.innerTurns ?? 4;
791
+ let verifiedBest = 0;
792
+ let verifiedResolved = false;
793
+ const openHandles = /* @__PURE__ */ new Set();
794
+ const r = await run({
795
+ surface: {
796
+ name: surface.name,
797
+ open: async (t) => {
798
+ const h = await surface.open(t);
799
+ openHandles.add(h.id);
800
+ return h;
801
+ },
802
+ close: async (h) => {
803
+ if (!h || !openHandles.has(h.id)) return;
804
+ openHandles.delete(h.id);
805
+ await surface.close(h);
806
+ }
807
+ },
808
+ task,
809
+ opts,
810
+ budget,
811
+ scope,
812
+ async shot(spec) {
813
+ const child = leaf(`shot:${seq}`, "shot");
814
+ seq += 1;
815
+ if (!scope.spawn(child, {
816
+ task,
817
+ handle: spec?.handle,
818
+ messages: spec?.messages,
819
+ steer: spec?.steer,
820
+ persona: spec?.persona,
821
+ tools: spec?.tools
822
+ }, {
823
+ budget: perChild(innerTurns),
824
+ label: child.name
825
+ }).ok) return null;
826
+ const settled = await drainOne(scope);
827
+ if (settled.kind === "down") return null;
828
+ const out = settled.out;
829
+ if (out.score > verifiedBest) verifiedBest = out.score;
830
+ if (out.total > 0 && out.passes === out.total) verifiedResolved = true;
831
+ return out;
832
+ },
833
+ async listTools(handle) {
834
+ return (await surface.tools(task, handle)).map((t) => ({
835
+ name: t.function.name,
836
+ ...t.function.description ? { description: t.function.description } : {}
837
+ }));
838
+ },
839
+ async critique(messages) {
840
+ const child = leaf(`analyst:${seq}`, "analyst");
841
+ seq += 1;
842
+ if (!scope.spawn(child, {
843
+ task,
844
+ messages
845
+ }, {
846
+ budget: perChild(1),
847
+ label: child.name
848
+ }).ok) return null;
849
+ const settled = await drainOne(scope);
850
+ if (settled.kind === "down") return null;
851
+ const findings = settled.out;
852
+ return /^\s*COMPLETE\b/i.test(findings) ? null : findings;
853
+ },
854
+ async consult(messages, instruction) {
855
+ const child = leaf(`analyst:${seq}`, "analyst");
856
+ seq += 1;
857
+ if (!scope.spawn(child, {
858
+ task,
859
+ messages,
860
+ rawInstruction: instruction
861
+ }, {
862
+ budget: perChild(1),
863
+ label: child.name
864
+ }).ok) return null;
865
+ const settled = await drainOne(scope);
866
+ if (settled.kind === "down") return null;
867
+ return settled.out;
868
+ }
869
+ });
870
+ return {
871
+ kind: "done",
872
+ deliverable: {
873
+ mode: name,
874
+ ...r,
875
+ progression: Array.isArray(r.progression) ? r.progression : [],
876
+ completions: typeof r.completions === "number" ? r.completions : 0,
877
+ shots: typeof r.shots === "number" ? r.shots : 0,
878
+ score: verifiedBest,
879
+ resolved: verifiedResolved
880
+ }
881
+ };
882
+ }
883
+ })
884
+ };
885
+ }
886
+ /** A NEW strategy, authored from the steps (~20 lines): refine, but when a steered shot
887
+ * fails to improve the score it ABANDONS that line and restarts fresh (branch-when-stuck)
888
+ * — the widen/MCTS idea the depth-stuck failure motivated. Scored keep-best (the best
889
+ * checkpoint across all lines), the deployable metric. This is the "experts build BETTER
890
+ * optimizations" path: a new technique, compact, with zero Supervisor ceremony. */
891
+ const adaptiveRefine = defineStrategy("adaptiveRefine", async ({ surface, task, budget, shot, critique }) => {
892
+ let handle = await surface.open(task);
893
+ const progression = [];
894
+ let messages;
895
+ let steer;
896
+ let completions = 0;
897
+ let best = -1;
898
+ let shots = 0;
899
+ try {
900
+ for (shots = 0; shots < budget; shots += 1) {
901
+ const out = await shot({
902
+ handle,
903
+ messages,
904
+ steer
905
+ });
906
+ if (!out) break;
907
+ completions += out.completions;
908
+ progression.push(out.score);
909
+ if (out.score >= 1) break;
910
+ if (out.score <= best) {
911
+ await surface.close(handle);
912
+ handle = await surface.open(task);
913
+ messages = void 0;
914
+ steer = void 0;
915
+ continue;
916
+ }
917
+ best = out.score;
918
+ messages = out.messages;
919
+ const findings = await critique(out.messages);
920
+ completions += 1;
921
+ if (!findings) break;
922
+ steer = `A reviewer flagged unfinished items:\n${findings}\n\nAddress each with the tools, verify they took, then continue.`;
923
+ }
924
+ const score = progression.length ? Math.max(...progression) : 0;
925
+ return {
926
+ score,
927
+ resolved: score >= 1,
928
+ completions,
929
+ progression,
930
+ shots
931
+ };
932
+ } finally {
933
+ await surface.close(handle);
934
+ }
935
+ });
936
+ /** The explore-then-exploit MIX: spend ⌈budget/2⌉ on independent samples (kept open),
937
+ * then refine the best-verifying line with the remaining budget. Sample's basin escape +
938
+ * refine's accumulation — the third built-in, authored from the public steps. */
939
+ const sampleThenRefine = defineStrategy("sampleThenRefine", async ({ surface, task, budget, shot, critique }) => {
940
+ const explore = Math.max(1, Math.ceil(budget / 2));
941
+ const open = /* @__PURE__ */ new Set();
942
+ const progression = [];
943
+ let completions = 0;
944
+ let shots = 0;
945
+ try {
946
+ let best;
947
+ for (let i = 0; i < explore; i += 1) {
948
+ const handle = await surface.open(task);
949
+ open.add(handle);
950
+ const out = await shot({ handle });
951
+ if (!out) continue;
952
+ shots += 1;
953
+ completions += out.completions;
954
+ progression.push(out.score);
955
+ if (!best || out.score > best.out.score) best = {
956
+ handle,
957
+ out
958
+ };
959
+ if (out.score >= 1) break;
960
+ }
961
+ if (!best) return {
962
+ score: 0,
963
+ resolved: false,
964
+ completions,
965
+ progression,
966
+ shots
967
+ };
968
+ for (const h of [...open]) if (h !== best.handle) {
969
+ await surface.close(h);
970
+ open.delete(h);
971
+ }
972
+ let messages = best.out.messages;
973
+ let topScore = best.out.score;
974
+ for (let i = explore; i < budget && topScore < 1; i += 1) {
975
+ const findings = await critique(messages);
976
+ completions += 1;
977
+ if (!findings) break;
978
+ const out = await shot({
979
+ handle: best.handle,
980
+ messages,
981
+ steer: `A reviewer flagged unfinished items:\n${findings}\n\nAddress each with the tools, verify they took, then continue.`
982
+ });
983
+ if (!out) break;
984
+ shots += 1;
985
+ completions += out.completions;
986
+ progression.push(out.score);
987
+ messages = out.messages;
988
+ if (out.score > topScore) topScore = out.score;
989
+ }
990
+ const score = progression.length ? Math.max(...progression) : 0;
991
+ return {
992
+ score,
993
+ resolved: score >= 1,
994
+ completions,
995
+ progression,
996
+ shots
997
+ };
998
+ } finally {
999
+ for (const h of open) await surface.close(h);
1000
+ }
1001
+ });
1002
+ /** Run a Strategy through the keystone Supervisor — `Agent.act` over a conserved-budget Scope. */
1003
+ async function runAgentic(opts) {
1004
+ const strategy = opts.strategy ?? (opts.mode === "breadth" ? sample : refine);
1005
+ const driver = strategy.driver(opts.surface, opts.task, opts, opts.budget);
1006
+ const supervisor = createSupervisor();
1007
+ const root = opts.rootBudget ?? {
1008
+ maxIterations: opts.budget * ((opts.innerTurns ?? 4) + 2),
1009
+ maxTokens: 1e9
1010
+ };
1011
+ const started = Date.now();
1012
+ const result = await supervisor.run(driver, void 0, {
1013
+ budget: root,
1014
+ runId: `agentic:${strategy.name}:${opts.task.id}`,
1015
+ journal: new InMemorySpawnJournal(),
1016
+ blobs: new InMemoryResultBlobStore(),
1017
+ executors: agenticRegistry(opts.surface, opts),
1018
+ maxDepth: 3,
1019
+ ...opts.hooks ? { hooks: opts.hooks } : {}
1020
+ });
1021
+ if (result.kind !== "winner" || result.out.kind !== "done") {
1022
+ const reason = result.kind === "winner" ? `blocked: ${result.out.blockers?.join("; ")}` : `no-winner: ${result.reason}`;
1023
+ throw new Error(`runAgentic(${strategy.name}) produced no result — ${reason}`);
1024
+ }
1025
+ return {
1026
+ ...result.out.deliverable,
1027
+ usd: result.spentTotal.usd,
1028
+ tokens: result.spentTotal.tokens,
1029
+ ms: Date.now() - started
1030
+ };
1031
+ }
1032
+ //#endregion
1033
+ //#region src/runtime/structural-rollout.ts
1034
+ /**
1035
+ * structuralRollout — the measured structural lever as a fourth member of the
1036
+ * sample/refine/sampleThenRefine strategy family: k independent samples, selection by
1037
+ * TASK-VISIBLE checks only, then a guarded self-repair loop steered by the checks'
1038
+ * failure output. Design: docs/design/structural-rollout-integration.md; measured basis
1039
+ * (bench/src/hev-structural.mts, bench/src/mbpp-structural.mts): +8.5..+21.3pp hidden-test
1040
+ * lift across Llama-3-8B/Qwen2.5-7B × HumanEval/MBPP, null only at saturation.
1041
+ *
1042
+ * Honesty invariants carried over from the proven rigs:
1043
+ * - Visible checks are generated from task-visible information only, BEFORE any
1044
+ * candidate exists, and FROZEN for every sample and repair round of the task.
1045
+ * - OFFICIAL checks (shown in the task itself) rank lexicographically above
1046
+ * model-AUTHORED guesses. This ordering is measured, not stylistic: authored guesses
1047
+ * run 17–70% wrong depending on model × spec richness, and unweighted they flipped
1048
+ * selection NEGATIVE on MBPP (6 noisy guesses outvoting the one reliable check).
1049
+ * - A candidate that crashed before the checks could run ranks below one that ran and
1050
+ * failed everything.
1051
+ * - Repair sees ONLY the checks' failure output, and never displaces a candidate that
1052
+ * passes more official checks with one that passes fewer (wrong visible examples
1053
+ * poison repair at saturation — the glm /47,/116 regressions).
1054
+ *
1055
+ * Placement rule: this is an INFERENCE-TIME capability (it wraps the model call via the
1056
+ * strategy seam). It does not belong in `improve()` (training-time); `improve()`
1057
+ * may later tune `StructuralRolloutPolicy` as an optimizable surface.
1058
+ */
1059
+ /** The measured default recipe: 5 samples, 2 guarded repair rounds, 6 authored checks. */
1060
+ const defaultStructuralRolloutPolicy = {
1061
+ k: 5,
1062
+ repairRounds: 2,
1063
+ testgen: 6
1064
+ };
1065
+ function resolvePolicy(overrides) {
1066
+ const policy = {
1067
+ ...defaultStructuralRolloutPolicy,
1068
+ ...overrides
1069
+ };
1070
+ if (!Number.isInteger(policy.k) || policy.k < 1) throw new Error(`structuralRollout: policy.k must be an integer >= 1, got ${policy.k}`);
1071
+ if (!Number.isInteger(policy.repairRounds) || policy.repairRounds < 0) throw new Error(`structuralRollout: policy.repairRounds must be an integer >= 0, got ${policy.repairRounds}`);
1072
+ if (!Number.isInteger(policy.testgen) || policy.testgen < 0) throw new Error(`structuralRollout: policy.testgen must be an integer >= 0, got ${policy.testgen}`);
1073
+ return policy;
1074
+ }
1075
+ const authorInstruction = (count, entry) => `Read the task below. Write exactly ${count} single-line assert statements that test the function \`${entry}\`, based ONLY on the behavior the task itself describes. Each assert must be one physical line of the form \`assert ${entry}(...) == expected\` (or a True/False check). Do NOT implement the function. Do NOT copy shown examples verbatim if you can test other cases too. Output ONLY the assert lines inside a single \`\`\`python code block.`;
1076
+ /** The proven authored-assert filter (lifted from the rigs' generateTests): keep only
1077
+ * single-line, paren-balanced asserts that reference the entry symbol — malformed lines
1078
+ * are dropped here rather than poisoning every candidate's score identically. */
1079
+ function filterAuthoredAsserts(reply, entrySymbol, count) {
1080
+ const fences = [...reply.matchAll(/```(?:python|py)?\s*\n([\s\S]*?)```/gi)].map((m) => (m[1] ?? "").trim());
1081
+ const block = fences.length > 0 ? fences.join("\n") : reply;
1082
+ const balanced = (s) => {
1083
+ let d = 0;
1084
+ for (const ch of s) {
1085
+ if (ch === "(" || ch === "[" || ch === "{") d += 1;
1086
+ else if (ch === ")" || ch === "]" || ch === "}") d -= 1;
1087
+ if (d < 0) return false;
1088
+ }
1089
+ return d === 0;
1090
+ };
1091
+ return block.split("\n").map((l) => l.trim()).filter((l) => l.startsWith("assert ") && l.includes(entrySymbol) && balanced(l)).slice(0, count);
1092
+ }
1093
+ /** Default authored-check source: one metered LLM call per task, before sampling,
1094
+ * filtered through `filterAuthoredAsserts`. Returns [] (no signal, never a fabricated
1095
+ * check) when the budget is 0, no entry symbol resolves, or the channel went down. */
1096
+ function modelAuthoredChecks(overrides = {}) {
1097
+ return { async generate(_task, ctx) {
1098
+ const count = overrides.count ?? ctx.count;
1099
+ if (count <= 0 || !ctx.entrySymbol) return [];
1100
+ const entry = ctx.entrySymbol;
1101
+ const reply = await ctx.consult(authorInstruction(count, entry));
1102
+ if (!reply) return [];
1103
+ return filterAuthoredAsserts(reply, entry, count).map((code) => ({
1104
+ code,
1105
+ kind: "authored"
1106
+ }));
1107
+ } };
1108
+ }
1109
+ /** Official checks the surface stashed on the task (e.g. MBPP's shown assert). Reads
1110
+ * `task.meta[key]` as a string array; anything else means no official checks. */
1111
+ function officialChecksFromMeta(key = "visibleChecks") {
1112
+ return { async generate(task) {
1113
+ const raw = task.meta?.[key];
1114
+ if (!Array.isArray(raw)) return [];
1115
+ return raw.filter((c) => typeof c === "string" && c.trim().length > 0).map((code) => ({
1116
+ code,
1117
+ kind: "official"
1118
+ }));
1119
+ } };
1120
+ }
1121
+ /** Concatenate check sources (official first by convention — ordering does not affect
1122
+ * scoring, which reads each check's `kind`). */
1123
+ function composeCheckSources(...sources) {
1124
+ return { async generate(task, ctx) {
1125
+ const all = [];
1126
+ for (const source of sources) all.push(...await source.generate(task, ctx));
1127
+ return all;
1128
+ } };
1129
+ }
1130
+ /** The symbol authored checks are pinned to: `task.meta.entryPoint` when the surface
1131
+ * provides it, else the LAST `def name(` in the visible prompt (a code-completion stub
1132
+ * lists helpers first, the entry stub last). Undefined ⇒ authoring is skipped. */
1133
+ function resolveEntrySymbol(task) {
1134
+ const meta = task.meta?.entryPoint;
1135
+ if (typeof meta === "string" && meta.trim().length > 0) return meta.trim();
1136
+ const defs = [...task.userPrompt.matchAll(/(?:^|\n)\s*def\s+([A-Za-z_]\w*)\s*\(/g)];
1137
+ return defs[defs.length - 1]?.[1];
1138
+ }
1139
+ /** The check program (mirrors the rigs' visible-check judge): candidate executes at
1140
+ * module level, then each check runs INDIVIDUALLY in try/except so one malformed line
1141
+ * cannot zero the rest; the summary line carries a per-call NONCE so a candidate
1142
+ * printing a forged summary cannot be parsed as the verdict. */
1143
+ function buildCheckProgram(candidate, official, authored, nonce) {
1144
+ return `${candidate}\n
1145
+ import base64 as _b64, json as _json, sys as _sys
1146
+ _official = _json.loads(_b64.b64decode("${Buffer.from(JSON.stringify(official), "utf8").toString("base64")}").decode("utf8"))
1147
+ _authored = _json.loads(_b64.b64decode("${Buffer.from(JSON.stringify(authored), "utf8").toString("base64")}").decode("utf8"))
1148
+ _lines = []
1149
+ def _run(_tests):
1150
+ _att, _fail = 0, 0
1151
+ for _t in _tests:
1152
+ _att += 1
1153
+ try:
1154
+ exec(_t, dict(globals()))
1155
+ except Exception as _e:
1156
+ _fail += 1
1157
+ _lines.append("CHECK FAILED: %s -> %s: %s" % (_t.strip()[:200], type(_e).__name__, str(_e)[:200]))
1158
+ return _att, _fail
1159
+ _o_att, _o_fail = _run(_official)
1160
+ _a_att, _a_fail = _run(_authored)
1161
+ print("SRCK-${nonce} official=%d/%d authored=%d/%d" % (_o_att - _o_fail, _o_att, _a_att - _a_fail, _a_att))
1162
+ _sys.stdout.write("\\n".join(_lines)[-1500:])
1163
+ _sys.exit(0 if (_o_fail + _a_fail) == 0 and (_o_att + _a_att) > 0 else 1)
1164
+ `;
1165
+ }
1166
+ /** Default CheckRunner backend: pipes the check program into `python3` over the sandbox
1167
+ * exec channel (`ctx.box`, or one bound at construction). Never shells out to docker
1168
+ * itself — the jail is the sandbox's concern. No channel ⇒ throws; it must never
1169
+ * silently score 0. Empty check sets short-circuit to a no-signal outcome (nothing to
1170
+ * execute, so no channel is required). */
1171
+ function sandboxCheckRunner(options = {}) {
1172
+ const python = options.python ?? "python3";
1173
+ const timeoutMs = options.timeoutMs ?? 2e4;
1174
+ return { async run(candidate, checks, ctx) {
1175
+ if (checks.length === 0) return {
1176
+ passedOfficial: 0,
1177
+ totalOfficial: 0,
1178
+ passedAuthored: 0,
1179
+ totalAuthored: 0,
1180
+ failureOutput: ""
1181
+ };
1182
+ const box = ctx.box ?? options.box;
1183
+ if (!box) throw new Error("sandboxCheckRunner: no execution channel — bind one via sandboxCheckRunner({ box }) or CheckRunContext.box (ValidationCtx.box / a sandbox instance). Refusing to score without executing: a silent 0 would poison selection.");
1184
+ const nonce = randomBytes(8).toString("hex");
1185
+ const program = buildCheckProgram(candidate, checks.filter((c) => c.kind === "official").map((c) => c.code), checks.filter((c) => c.kind === "authored").map((c) => c.code), nonce);
1186
+ const b64 = Buffer.from(program, "utf8").toString("base64");
1187
+ const r = await box.exec(`printf '%s' '${b64}' | base64 -d | ${python} -`, { timeoutMs });
1188
+ const summary = new RegExp(`SRCK-${nonce} official=(\\d+)/(\\d+) authored=(\\d+)/(\\d+)`).exec(r.stdout);
1189
+ if (!summary) return {
1190
+ passedOfficial: 0,
1191
+ totalOfficial: 0,
1192
+ passedAuthored: 0,
1193
+ totalAuthored: 0,
1194
+ failureOutput: (r.stderr || r.stdout).slice(-1500) || "no output (crashed or timed out before the checks could run)",
1195
+ crashed: true
1196
+ };
1197
+ const failureOutput = r.stdout.replace(summary[0], "").slice(-1500).trim();
1198
+ return {
1199
+ passedOfficial: Number(summary[1]),
1200
+ totalOfficial: Number(summary[2]),
1201
+ passedAuthored: Number(summary[3]),
1202
+ totalAuthored: Number(summary[4]),
1203
+ failureOutput
1204
+ };
1205
+ } };
1206
+ }
1207
+ const frac = (passed, total) => total > 0 ? passed / total : 0;
1208
+ /** The selection order: crash < ran; then official pass-fraction; authored guesses only
1209
+ * break ties. Returns > 0 when `a` outranks `b`. Strictly lexicographic — on MBPP,
1210
+ * letting 6 noisy guesses outvote the one official check flipped selection negative. */
1211
+ function compareCheckOutcomes(a, b) {
1212
+ const aCrashed = a.crashed === true;
1213
+ if (aCrashed !== (b.crashed === true)) return aCrashed ? -1 : 1;
1214
+ if (aCrashed) return 0;
1215
+ const official = frac(a.passedOfficial, a.totalOfficial) - frac(b.passedOfficial, b.totalOfficial);
1216
+ if (official !== 0) return official;
1217
+ return frac(a.passedAuthored, a.totalAuthored) - frac(b.passedAuthored, b.totalAuthored);
1218
+ }
1219
+ /** Display scalar for receipts/reports (the rigs' `visibleScore` shape): crash = -1,
1220
+ * else official fraction + 0.001 × authored fraction. Selection itself uses the exact
1221
+ * lexicographic comparator, never this scalar. */
1222
+ function visibleCheckScore(o) {
1223
+ if (o.crashed) return -1;
1224
+ return frac(o.passedOfficial, o.totalOfficial) + .001 * frac(o.passedAuthored, o.totalAuthored);
1225
+ }
1226
+ /** Argmax by `compareCheckOutcomes`, FIRST index wins ties (deterministic; with zero
1227
+ * visible coverage every candidate ties at no-signal and index 0 is the blind pick). */
1228
+ function selectBestIndex(outcomes) {
1229
+ let best = 0;
1230
+ for (let i = 1; i < outcomes.length; i += 1) if (compareCheckOutcomes(outcomes[i], outcomes[best]) > 0) best = i;
1231
+ return best;
1232
+ }
1233
+ /** The repair keep-best guard: a challenger displaces the incumbent only when it is
1234
+ * strictly better in the selection order AND passes at least as many official checks.
1235
+ * The raw-count clause is deliberate belt-and-braces over the comparator (a custom
1236
+ * runner can report shifted totals): repair must NEVER replace a candidate that passes
1237
+ * more official checks with one that passes fewer. */
1238
+ function canDisplace(challenger, incumbent) {
1239
+ if (challenger.crashed === true) return false;
1240
+ if (challenger.passedOfficial < incumbent.passedOfficial) return false;
1241
+ return compareCheckOutcomes(challenger, incumbent) > 0;
1242
+ }
1243
+ const totalChecks = (o) => o.totalOfficial + o.totalAuthored;
1244
+ const passesAllChecks = (o) => o.crashed !== true && totalChecks(o) > 0 && o.passedOfficial === o.totalOfficial && o.passedAuthored === o.totalAuthored;
1245
+ /** The candidate a shot produced, read from its conversation: the LAST `submit_answer`
1246
+ * tool-call argument (verifier environments submit the artifact explicitly), else the
1247
+ * latest assistant reply's fenced code block — preferring a block containing a `def`,
1248
+ * because repair replies echo the failure report in a bare fence BEFORE the fixed code
1249
+ * (the rigs' extractRepairCode lesson) — else the latest non-empty assistant text. */
1250
+ function defaultExtractCandidate(messages) {
1251
+ for (let i = messages.length - 1; i >= 0; i -= 1) {
1252
+ const calls = messages[i]?.tool_calls;
1253
+ if (!calls) continue;
1254
+ for (let j = calls.length - 1; j >= 0; j -= 1) {
1255
+ const call = calls[j];
1256
+ if (call?.function?.name !== "submit_answer") continue;
1257
+ try {
1258
+ const args = JSON.parse(call.function.arguments ?? "{}");
1259
+ if (typeof args.answer === "string" && args.answer.trim()) return args.answer.trim();
1260
+ } catch {}
1261
+ }
1262
+ }
1263
+ const contents = [];
1264
+ for (const m of messages) if (m.role === "assistant" && typeof m.content === "string" && m.content.trim()) contents.push(m.content);
1265
+ const fencesOf = (text) => [...text.matchAll(/```(?:python|py)?\s*\n([\s\S]*?)```/gi)].map((m) => (m[1] ?? "").trim());
1266
+ for (let i = contents.length - 1; i >= 0; i -= 1) {
1267
+ const fences = fencesOf(contents[i]);
1268
+ for (let j = fences.length - 1; j >= 0; j -= 1) if (/(^|\n)\s*def\s+\w+/.test(fences[j])) return fences[j];
1269
+ }
1270
+ for (let i = contents.length - 1; i >= 0; i -= 1) {
1271
+ const fences = fencesOf(contents[i]);
1272
+ if (fences.length > 0) return fences[fences.length - 1];
1273
+ }
1274
+ return (contents[contents.length - 1] ?? "").trim();
1275
+ }
1276
+ /** Per-slot approach lenses for `diverse` mode — copied from bench/src/directives.ts
1277
+ * (the measured rig plumbing; a paired null there, kept as an optional knob). */
1278
+ const DIVERSE_LENSES = [
1279
+ "Answer directly and decisively from what you already know. State the single best answer without hedging.",
1280
+ "Decompose the question into the sub-facts it depends on. Establish each sub-fact explicitly, then compose them into the answer.",
1281
+ "Reason from first principles. Ignore the most obvious or popular guess; derive the answer from underlying facts and relationships.",
1282
+ "Name the most plausible WRONG answer and the trap that makes it tempting. Rule it out, then commit to the answer that survives."
1283
+ ];
1284
+ function slotLens(slot) {
1285
+ return `${DIVERSE_LENSES[slot % DIVERSE_LENSES.length]}${slot < DIVERSE_LENSES.length ? "" : ` (variant ${Math.floor(slot / DIVERSE_LENSES.length) + 1})`}`;
1286
+ }
1287
+ function repairSteer(outcome) {
1288
+ return [
1289
+ "Your latest solution failed some of the task-visible checks.",
1290
+ "Result of running the visible checks against it:",
1291
+ "```",
1292
+ outcome.failureOutput.trim() || "(the code crashed before the checks could run)",
1293
+ "```",
1294
+ "Fix the solution so the visible checks pass. Provide the COMPLETE corrected solution the",
1295
+ "same way you provided the original (same tool or format) — not a fragment or a diff."
1296
+ ].join("\n");
1297
+ }
1298
+ function describeOutcome(label, o) {
1299
+ if (o.crashed) return `${label}: crashed before the checks could run`;
1300
+ return `${label}: official ${o.passedOfficial}/${o.totalOfficial}, authored ${o.passedAuthored}/${o.totalAuthored}`;
1301
+ }
1302
+ /**
1303
+ * Build the structuralRollout `Strategy`: k shots → score each by the frozen visible
1304
+ * checks (official above authored, crash lowest) → argmax with first-index tie-break →
1305
+ * up to `repairRounds` repair shots steered by the failure output, keep-best under the
1306
+ * official-check guard. Authored via `defineStrategy`, so the deliverable score stays
1307
+ * harness-verified and every shot is metered by the conserved pool.
1308
+ *
1309
+ * Budget note: `runAgentic`'s `budget` sizes the pool — pass at least
1310
+ * `k + repairRounds + 1` so the samples, repairs, and the check-author consult all admit.
1311
+ */
1312
+ function structuralRollout(config = {}) {
1313
+ const policy = resolvePolicy(config.policy);
1314
+ const checkSource = config.checkSource ?? composeCheckSources(officialChecksFromMeta(), modelAuthoredChecks());
1315
+ const checkRunner = config.checkRunner ?? sandboxCheckRunner();
1316
+ const extract = config.extractCandidate ?? defaultExtractCandidate;
1317
+ const inner = defineStrategy("structuralRollout", async (ctx) => {
1318
+ const { task, shot } = ctx;
1319
+ const progression = [];
1320
+ const receipts = [];
1321
+ let completions = 0;
1322
+ let shots = 0;
1323
+ const consult = async (instruction) => {
1324
+ const reply = await ctx.consult([], instruction);
1325
+ completions += 1;
1326
+ return reply;
1327
+ };
1328
+ const entrySymbol = resolveEntrySymbol(task);
1329
+ const checks = await checkSource.generate(task, {
1330
+ count: policy.testgen,
1331
+ ...entrySymbol ? { entrySymbol } : {},
1332
+ consult
1333
+ });
1334
+ const officialChecks = checks.filter((c) => c.kind === "official").length;
1335
+ const authoredChecks = checks.length - officialChecks;
1336
+ const runCtx = {
1337
+ task,
1338
+ ...config.box ? { box: config.box } : {}
1339
+ };
1340
+ const candidates = [];
1341
+ for (let i = 0; i < policy.k; i += 1) {
1342
+ const out = await shot(policy.diverse ? { steer: slotLens(i) } : void 0);
1343
+ if (!out) break;
1344
+ shots += 1;
1345
+ completions += out.completions;
1346
+ progression.push(out.score);
1347
+ const artifact = extract(out.messages);
1348
+ const outcome = await checkRunner.run(artifact, checks, runCtx);
1349
+ candidates.push({
1350
+ index: candidates.length,
1351
+ messages: out.messages,
1352
+ artifact,
1353
+ outcome,
1354
+ shotScore: out.score,
1355
+ shotResolved: out.total > 0 && out.passes === out.total
1356
+ });
1357
+ }
1358
+ if (candidates.length === 0) return {
1359
+ score: 0,
1360
+ resolved: false,
1361
+ completions,
1362
+ progression,
1363
+ shots,
1364
+ artifact: null,
1365
+ selection: receipts,
1366
+ repairStop: "no-candidates",
1367
+ officialChecks,
1368
+ authoredChecks
1369
+ };
1370
+ let best = candidates[selectBestIndex(candidates.map((c) => c.outcome))];
1371
+ for (const c of candidates) receipts.push({
1372
+ candidateIndex: c.index,
1373
+ selected: false,
1374
+ score: visibleCheckScore(c.outcome),
1375
+ reason: describeOutcome("sample", c.outcome),
1376
+ selector: "driver"
1377
+ });
1378
+ let seq = candidates.length;
1379
+ let repairStop = "already-passing";
1380
+ if (!passesAllChecks(best.outcome)) if (best.outcome.crashed !== true && totalChecks(best.outcome) === 0) repairStop = "no-signal";
1381
+ else {
1382
+ repairStop = "rounds-exhausted";
1383
+ for (let r = 0; r < policy.repairRounds; r += 1) {
1384
+ const out = await shot({
1385
+ messages: best.messages,
1386
+ steer: repairSteer(best.outcome)
1387
+ });
1388
+ if (!out) break;
1389
+ shots += 1;
1390
+ completions += out.completions;
1391
+ progression.push(out.score);
1392
+ const artifact = extract(out.messages);
1393
+ const outcome = await checkRunner.run(artifact, checks, runCtx);
1394
+ const displaced = canDisplace(outcome, best.outcome);
1395
+ const label = displaced ? "repair (displaced the incumbent)" : outcome.crashed !== true && outcome.passedOfficial < best.outcome.passedOfficial ? "repair (held out: passes fewer official checks than the incumbent)" : "repair (held out: no improvement)";
1396
+ receipts.push({
1397
+ candidateIndex: seq,
1398
+ selected: false,
1399
+ score: visibleCheckScore(outcome),
1400
+ reason: describeOutcome(label, outcome),
1401
+ selector: "driver"
1402
+ });
1403
+ if (displaced) best = {
1404
+ index: seq,
1405
+ messages: out.messages,
1406
+ artifact,
1407
+ outcome,
1408
+ shotScore: out.score,
1409
+ shotResolved: out.total > 0 && out.passes === out.total
1410
+ };
1411
+ seq += 1;
1412
+ if (passesAllChecks(best.outcome)) {
1413
+ repairStop = "repaired-pass";
1414
+ break;
1415
+ }
1416
+ }
1417
+ }
1418
+ const winner = receipts.find((r) => r.candidateIndex === best.index);
1419
+ if (winner) winner.selected = true;
1420
+ return {
1421
+ score: best.shotScore,
1422
+ resolved: best.shotResolved,
1423
+ completions,
1424
+ progression,
1425
+ shots,
1426
+ artifact: best.artifact,
1427
+ selection: receipts,
1428
+ repairStop,
1429
+ officialChecks,
1430
+ authoredChecks
1431
+ };
1432
+ });
1433
+ if (policy.temperature === void 0) return inner;
1434
+ return {
1435
+ name: inner.name,
1436
+ driver: (surface, task, opts, budget) => inner.driver(surface, task, {
1437
+ ...opts,
1438
+ temperature: policy.temperature
1439
+ }, budget)
1440
+ };
1441
+ }
1442
+ //#endregion
1443
+ export { observe as C, researchDriverNote as D, optimizerMethod as E, strategyAuthorMethod as O, defaultAnalystInstruction as S, buildDriverSystem as T, depthStrategy as _, defaultStructuralRolloutPolicy as a, sample as b, officialChecksFromMeta as c, selectBestIndex as d, structuralRollout as f, defineStrategy as g, breadthStrategy as h, defaultExtractCandidate as i, resolveEntrySymbol as l, adaptiveRefine as m, compareCheckOutcomes as n, filterAuthoredAsserts as o, visibleCheckScore as p, composeCheckSources as r, modelAuthoredChecks as s, canDisplace as t, sandboxCheckRunner as u, refine as v, renderReport as w, sampleThenRefine as x, runAgentic as y };
1444
+
1445
+ //# sourceMappingURL=structural-rollout-IXUEplky.js.map