humanish 0.106.0 → 0.107.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 (459) hide show
  1. package/AGENTS.md +4 -2
  2. package/ARCHITECTURE.md +17 -16
  3. package/CHANGELOG.md +24 -0
  4. package/CONTEXT.md +42 -39
  5. package/CONTRIBUTING.md +8 -6
  6. package/README.md +8 -3
  7. package/dist/actors/codex/app-server-client.js +2 -1
  8. package/dist/actors/codex/app-server-trace.d.ts +0 -1
  9. package/dist/actors/codex/app-server-trace.js +1 -3
  10. package/dist/actors/codex/app-server.js +2 -1
  11. package/dist/actors/codex/protocol-compat.d.ts +27 -0
  12. package/dist/actors/codex/protocol-compat.js +357 -0
  13. package/dist/actors/codex/protocol-contract.d.ts +61 -0
  14. package/dist/actors/codex/protocol-contract.js +471 -0
  15. package/dist/actors/codex/qualified-versions.d.ts +31 -4
  16. package/dist/actors/codex/qualified-versions.js +51 -6
  17. package/dist/actors/codex/restricted-executable.d.ts +24 -0
  18. package/dist/actors/codex/restricted-executable.js +97 -22
  19. package/dist/actors/codex/restricted-launch.d.ts +7 -1
  20. package/dist/actors/codex/restricted-launch.js +42 -3
  21. package/dist/actors/codex/restricted-notifications.d.ts +101 -0
  22. package/dist/actors/codex/restricted-notifications.js +277 -0
  23. package/dist/actors/codex/restricted-participant.d.ts +30 -0
  24. package/dist/actors/codex/restricted-participant.js +60 -2
  25. package/dist/actors/codex/restricted-policy.d.ts +9 -1
  26. package/dist/actors/codex/restricted-session.d.ts +14 -1
  27. package/dist/actors/codex/restricted-session.js +50 -17
  28. package/dist/actors/codex/restricted-transport.d.ts +29 -0
  29. package/dist/actors/codex/restricted-transport.js +139 -27
  30. package/dist/actors/codex/restricted-turn.d.ts +19 -4
  31. package/dist/actors/codex/restricted-turn.js +43 -30
  32. package/dist/actors/computer-use/actor.d.ts +1 -1
  33. package/dist/actors/computer-use/actor.js +4 -4
  34. package/dist/actors/computer-use/loop/backstop.js +1 -1
  35. package/dist/actors/computer-use/loop/ending.d.ts +2 -2
  36. package/dist/actors/computer-use/loop/ending.js +2 -2
  37. package/dist/actors/computer-use/loop/spend.d.ts +1 -1
  38. package/dist/actors/computer-use/loop/spend.js +3 -3
  39. package/dist/actors/computer-use/loop/trace.js +2 -2
  40. package/dist/actors/computer-use/loop/types.d.ts +14 -5
  41. package/dist/actors/computer-use/loop.js +4 -4
  42. package/dist/actors/computer-use/openai-provider.d.ts +1 -1
  43. package/dist/actors/computer-use/openai-provider.js +2 -2
  44. package/dist/actors/contract.d.ts +10 -8
  45. package/dist/actors/contract.js +7 -1
  46. package/dist/actors/local-agent/cli.js +1 -1
  47. package/dist/actors/scripted-browser/actor.d.ts +2 -2
  48. package/dist/actors/scripted-browser/journey.js +15 -4
  49. package/dist/actors/scripted-browser/steps.js +18 -0
  50. package/dist/actors/scripted-browser/types.d.ts +11 -1
  51. package/dist/actors/stop-conditions.js +1 -3
  52. package/dist/analysis/automatic-completion.d.ts +13 -8
  53. package/dist/analysis/automatic-completion.js +14 -8
  54. package/dist/analysis/automatic-config.d.ts +1 -1
  55. package/dist/analysis/automatic-config.js +2 -2
  56. package/dist/analysis/automatic.d.ts +10 -4
  57. package/dist/analysis/automatic.js +17 -13
  58. package/dist/analysis/diagnostics.d.ts +23 -0
  59. package/dist/analysis/diagnostics.js +112 -0
  60. package/dist/analysis/evidence-sources.js +2 -2
  61. package/dist/analysis/evidence.js +6 -6
  62. package/dist/analysis/execute.d.ts +7 -1
  63. package/dist/analysis/execute.js +39 -12
  64. package/dist/analysis/job.d.ts +8 -5
  65. package/dist/analysis/job.js +15 -14
  66. package/dist/analysis/load.d.ts +1 -1
  67. package/dist/analysis/load.js +5 -5
  68. package/dist/analysis/provider.d.ts +9 -1
  69. package/dist/analysis/restricted-codex.d.ts +2 -0
  70. package/dist/analysis/restricted-codex.js +10 -1
  71. package/dist/analysis/service.d.ts +2 -0
  72. package/dist/analysis/service.js +31 -12
  73. package/dist/analysis/sharing.d.ts +2 -2
  74. package/dist/analysis/sharing.js +5 -5
  75. package/dist/analysis/store-executions.d.ts +5 -5
  76. package/dist/analysis/store-executions.js +12 -12
  77. package/dist/analysis/store.d.ts +4 -4
  78. package/dist/analysis/store.js +13 -13
  79. package/dist/cli/commands/analysis-signals.d.ts +2 -1
  80. package/dist/cli/commands/analysis-signals.js +4 -1
  81. package/dist/cli/commands/analyze.js +4 -2
  82. package/dist/cli/commands/comms.js +8 -1
  83. package/dist/cli/commands/lab-route-computer-use.d.ts +0 -2
  84. package/dist/cli/commands/lab-route-computer-use.js +26 -14
  85. package/dist/cli/commands/lab-route-preview.d.ts +1 -3
  86. package/dist/cli/commands/lab-route-preview.js +3 -4
  87. package/dist/cli/commands/lab-route-run.d.ts +6 -4
  88. package/dist/cli/commands/lab-route-run.js +6 -2
  89. package/dist/cli/commands/lab-route-scripted.d.ts +0 -2
  90. package/dist/cli/commands/lab-route-scripted.js +0 -1
  91. package/dist/cli/commands/lab-route-shared-world.d.ts +0 -2
  92. package/dist/cli/commands/lab-route-shared-world.js +0 -1
  93. package/dist/cli/commands/lab-route-terminal.d.ts +0 -2
  94. package/dist/cli/commands/lab-route-terminal.js +0 -1
  95. package/dist/cli/commands/lab-run.js +76 -45
  96. package/dist/cli/commands/lab-scorer.d.ts +0 -2
  97. package/dist/cli/commands/lab.js +12 -6
  98. package/dist/cli/commands/observe.js +22 -0
  99. package/dist/cli/commands/run-signals.d.ts +30 -0
  100. package/dist/cli/commands/run-signals.js +146 -0
  101. package/dist/cli/commands/runs.js +10 -8
  102. package/dist/cli/commands/watch.js +12 -10
  103. package/dist/cli/doctor.d.ts +3 -0
  104. package/dist/cli/doctor.js +10 -2
  105. package/dist/cli/io.d.ts +5 -4
  106. package/dist/cli/io.js +12 -8
  107. package/dist/cli/program.js +3 -3
  108. package/dist/cli/renamed-options.d.ts +11 -0
  109. package/dist/cli/renamed-options.js +18 -0
  110. package/dist/cli/telemetry.d.ts +2 -2
  111. package/dist/cli/telemetry.js +1 -1
  112. package/dist/comms/capture-surface.d.ts +1 -1
  113. package/dist/comms/catch-host.d.ts +1 -1
  114. package/dist/comms/connections.js +4 -4
  115. package/dist/comms/external-evidence.d.ts +27 -0
  116. package/dist/comms/external-evidence.js +93 -0
  117. package/dist/comms/lease-store.js +7 -7
  118. package/dist/comms/types.js +1 -1
  119. package/dist/evidence/browser-hygiene.d.ts +1 -1
  120. package/dist/evidence/browser-hygiene.js +1 -1
  121. package/dist/evidence/redaction.js +1 -1
  122. package/dist/evidence/secret-scrub.d.ts +9 -0
  123. package/dist/evidence/secret-scrub.js +96 -0
  124. package/dist/feedback/draft.js +7 -9
  125. package/dist/feedback/export-bundle.js +4 -4
  126. package/dist/feedback/export.js +9 -9
  127. package/dist/feedback/feedback.d.ts +1 -1
  128. package/dist/index.d.ts +3 -6
  129. package/dist/index.js +3 -6
  130. package/dist/keys/key-resolution.d.ts +3 -1
  131. package/dist/keys/key-resolution.js +18 -16
  132. package/dist/lab/adapter-extension.d.ts +28 -6
  133. package/dist/lab/adapter-extension.js +65 -126
  134. package/dist/lab/adapter-scorer-loader.d.ts +25 -5
  135. package/dist/lab/adapter-scorer-loader.js +24 -0
  136. package/dist/lab/composition-rules.d.ts +2 -0
  137. package/dist/lab/composition-rules.js +35 -26
  138. package/dist/lab/config.js +28 -26
  139. package/dist/lab/device-presets.d.ts +2 -2
  140. package/dist/lab/discover.js +1 -3
  141. package/dist/lab/doctor.d.ts +44 -9
  142. package/dist/lab/doctor.js +149 -41
  143. package/dist/lab/init-plan.js +1 -3
  144. package/dist/lab/keys.js +1 -1
  145. package/dist/lab/lab-deps.d.ts +85 -0
  146. package/dist/lab/lab-deps.js +4 -0
  147. package/dist/lab/parse/actors.js +8 -7
  148. package/dist/lab/parse/comms.js +3 -2
  149. package/dist/lab/parse/execution.js +3 -2
  150. package/dist/lab/parse/subject-state.js +2 -1
  151. package/dist/lab/parse/subject.js +2 -1
  152. package/dist/lab/parse/values.d.ts +0 -1
  153. package/dist/lab/parse/values.js +0 -3
  154. package/dist/lab/persona-resolve.d.ts +3 -3
  155. package/dist/lab/persona-resolve.js +4 -4
  156. package/dist/lab/persona.js +1 -3
  157. package/dist/lab/plan-base.d.ts +6 -2
  158. package/dist/lab/plan-base.js +22 -7
  159. package/dist/lab/plan-participants.d.ts +5 -5
  160. package/dist/lab/plan-participants.js +2 -2
  161. package/dist/lab/plan-types.d.ts +33 -7
  162. package/dist/lab/plan.d.ts +3 -11
  163. package/dist/lab/plan.js +18 -42
  164. package/dist/lab/preflight-result.js +0 -2
  165. package/dist/lab/preflight.d.ts +0 -3
  166. package/dist/lab/preflight.js +1 -1
  167. package/dist/lab/requirements.d.ts +20 -0
  168. package/dist/lab/requirements.js +54 -0
  169. package/dist/lab/route-inputs.d.ts +23 -12
  170. package/dist/lab/route-inputs.js +48 -51
  171. package/dist/lab/routing.d.ts +19 -24
  172. package/dist/lab/routing.js +14 -47
  173. package/dist/lab/run-lab-events.d.ts +6 -11
  174. package/dist/lab/run-lab-events.js +3 -11
  175. package/dist/lab/run-lab-homes.d.ts +64 -0
  176. package/dist/lab/run-lab-homes.js +3 -0
  177. package/dist/lab/run-lab-options.d.ts +12 -66
  178. package/dist/lab/run-lab-options.js +45 -275
  179. package/dist/lab/summary.d.ts +9 -4
  180. package/dist/lab/summary.js +15 -8
  181. package/dist/lab/types.d.ts +132 -132
  182. package/dist/lab/validation.d.ts +15 -15
  183. package/dist/lab/validation.js +28 -28
  184. package/dist/lab/warnings.js +20 -19
  185. package/dist/observer/artifact.d.ts +1 -1
  186. package/dist/observer/artifact.js +3 -3
  187. package/dist/observer/data.js +2 -2
  188. package/dist/observer/render.js +2 -2
  189. package/dist/observer/run-routes.d.ts +1 -1
  190. package/dist/observer/run-routes.js +5 -5
  191. package/dist/observer/serve.d.ts +17 -0
  192. package/dist/observer/serve.js +34 -3
  193. package/dist/observer-app.html +1 -1
  194. package/dist/routes/computer-use/bundle-parts.d.ts +1 -1
  195. package/dist/routes/computer-use/bundle-parts.js +10 -3
  196. package/dist/routes/computer-use/bundle.d.ts +4 -11
  197. package/dist/routes/computer-use/bundle.js +9 -15
  198. package/dist/routes/computer-use/diagnostics.d.ts +1 -1
  199. package/dist/routes/computer-use/diagnostics.js +1 -1
  200. package/dist/routes/computer-use/e2b-desktop/comms.d.ts +10 -10
  201. package/dist/routes/computer-use/e2b-desktop/comms.js +11 -14
  202. package/dist/routes/computer-use/e2b-desktop/desktop.d.ts +2 -2
  203. package/dist/routes/computer-use/e2b-desktop/desktop.js +4 -7
  204. package/dist/routes/computer-use/e2b-desktop/fidelity.d.ts +13 -13
  205. package/dist/routes/computer-use/e2b-desktop/fidelity.js +11 -11
  206. package/dist/routes/computer-use/e2b-desktop/prepare.d.ts +3 -3
  207. package/dist/routes/computer-use/e2b-desktop/prepare.js +33 -36
  208. package/dist/routes/computer-use/e2b-desktop/start.d.ts +1 -1
  209. package/dist/routes/computer-use/e2b-desktop/start.js +24 -23
  210. package/dist/routes/computer-use/e2b-desktop/state.d.ts +5 -4
  211. package/dist/routes/computer-use/e2b-desktop/state.js +5 -3
  212. package/dist/routes/computer-use/e2b-desktop/teardown.d.ts +1 -1
  213. package/dist/routes/computer-use/e2b-desktop/teardown.js +29 -17
  214. package/dist/routes/computer-use/external-comms.d.ts +4 -4
  215. package/dist/routes/computer-use/external-comms.js +19 -43
  216. package/dist/routes/computer-use/fanout-bundle.d.ts +3 -3
  217. package/dist/routes/computer-use/fanout-bundle.js +25 -29
  218. package/dist/routes/computer-use/{fanout-lanes.js → fanout-records.js} +25 -19
  219. package/dist/routes/computer-use/in-process-desktop.d.ts +3 -10
  220. package/dist/routes/computer-use/in-process-desktop.js +3 -9
  221. package/dist/routes/computer-use/live-flush.d.ts +7 -5
  222. package/dist/routes/computer-use/live-flush.js +19 -27
  223. package/dist/routes/computer-use/{run-lanes.js → live-phase.js} +14 -13
  224. package/dist/routes/computer-use/local-tree-pack.d.ts +3 -3
  225. package/dist/routes/computer-use/local-tree-pack.js +4 -5
  226. package/dist/routes/computer-use/local-vm.d.ts +11 -8
  227. package/dist/routes/computer-use/local-vm.js +39 -66
  228. package/dist/routes/computer-use/participant-desktop.d.ts +8 -23
  229. package/dist/routes/computer-use/participant-desktop.js +5 -25
  230. package/dist/routes/computer-use/{lanes.d.ts → participant-execution.d.ts} +10 -10
  231. package/dist/routes/computer-use/{lanes.js → participant-execution.js} +35 -22
  232. package/dist/routes/computer-use/participant-facts.d.ts +7 -1
  233. package/dist/routes/computer-use/participant-facts.js +12 -1
  234. package/dist/routes/computer-use/participant-model.d.ts +19 -11
  235. package/dist/routes/computer-use/participant-model.js +58 -33
  236. package/dist/routes/computer-use/participant-prompt.d.ts +3 -3
  237. package/dist/routes/computer-use/participant-prompt.js +4 -4
  238. package/dist/routes/computer-use/participant-runs.d.ts +6 -6
  239. package/dist/routes/computer-use/participant-runs.js +8 -8
  240. package/dist/routes/computer-use/plan.d.ts +21 -29
  241. package/dist/routes/computer-use/plan.js +59 -65
  242. package/dist/routes/computer-use/preflight.d.ts +6 -11
  243. package/dist/routes/computer-use/preflight.js +26 -18
  244. package/dist/routes/computer-use/rerun-selection.js +10 -6
  245. package/dist/routes/computer-use/result.d.ts +1 -1
  246. package/dist/routes/computer-use/result.js +40 -30
  247. package/dist/routes/computer-use/route.d.ts +3 -4
  248. package/dist/routes/computer-use/route.js +21 -19
  249. package/dist/routes/computer-use/self-report.d.ts +2 -2
  250. package/dist/routes/computer-use/self-report.js +4 -4
  251. package/dist/routes/computer-use/setup.d.ts +8 -17
  252. package/dist/routes/computer-use/setup.js +98 -86
  253. package/dist/routes/computer-use/single-bundle.d.ts +8 -11
  254. package/dist/routes/computer-use/single-bundle.js +20 -25
  255. package/dist/routes/computer-use/subject-projection.d.ts +5 -7
  256. package/dist/routes/computer-use/subject-projection.js +20 -19
  257. package/dist/routes/computer-use/types.d.ts +169 -211
  258. package/dist/routes/computer-use/types.js +13 -6
  259. package/dist/routes/preview.js +0 -1
  260. package/dist/routes/scripted/bundle.d.ts +3 -6
  261. package/dist/routes/scripted/bundle.js +11 -16
  262. package/dist/routes/scripted/plan.d.ts +5 -7
  263. package/dist/routes/scripted/plan.js +6 -4
  264. package/dist/routes/scripted/result.d.ts +4 -1
  265. package/dist/routes/scripted/result.js +10 -6
  266. package/dist/routes/scripted/route.js +10 -11
  267. package/dist/routes/scripted/scenario.d.ts +1 -1
  268. package/dist/routes/scripted/scenario.js +1 -1
  269. package/dist/routes/scripted/setup.d.ts +3 -2
  270. package/dist/routes/scripted/setup.js +22 -21
  271. package/dist/routes/scripted/subject.d.ts +8 -3
  272. package/dist/routes/scripted/subject.js +11 -6
  273. package/dist/routes/scripted/surface-records.js +1 -1
  274. package/dist/routes/scripted/surface-sessions.d.ts +2 -2
  275. package/dist/routes/scripted/surface-sessions.js +4 -4
  276. package/dist/routes/scripted/types.d.ts +19 -36
  277. package/dist/routes/scripted/types.js +1 -2
  278. package/dist/routes/shared-world/{seat-records.js → bundle-records.js} +8 -8
  279. package/dist/routes/shared-world/bundle.d.ts +2 -2
  280. package/dist/routes/shared-world/bundle.js +22 -26
  281. package/dist/routes/shared-world/checkpoints.d.ts +4 -4
  282. package/dist/routes/shared-world/checkpoints.js +4 -4
  283. package/dist/routes/shared-world/comms.d.ts +5 -4
  284. package/dist/routes/shared-world/comms.js +28 -41
  285. package/dist/routes/shared-world/external-public.d.ts +5 -5
  286. package/dist/routes/shared-world/external-public.js +19 -20
  287. package/dist/routes/shared-world/handoff.d.ts +4 -4
  288. package/dist/routes/shared-world/handoff.js +50 -50
  289. package/dist/routes/shared-world/lobby-code.d.ts +5 -5
  290. package/dist/routes/shared-world/lobby-code.js +13 -13
  291. package/dist/routes/shared-world/{seats.d.ts → participant-specs.d.ts} +8 -6
  292. package/dist/routes/shared-world/{seats.js → participant-specs.js} +46 -51
  293. package/dist/routes/shared-world/plan.d.ts +2 -6
  294. package/dist/routes/shared-world/plan.js +1 -2
  295. package/dist/routes/shared-world/provenance.d.ts +4 -4
  296. package/dist/routes/shared-world/provenance.js +4 -4
  297. package/dist/routes/shared-world/provisioned.d.ts +3 -2
  298. package/dist/routes/shared-world/provisioned.js +48 -41
  299. package/dist/routes/shared-world/result.js +31 -19
  300. package/dist/routes/shared-world/route.js +37 -41
  301. package/dist/routes/shared-world/setup.d.ts +5 -4
  302. package/dist/routes/shared-world/setup.js +12 -14
  303. package/dist/routes/shared-world/types.d.ts +53 -126
  304. package/dist/routes/shared-world/types.js +2 -2
  305. package/dist/routes/terminal/adapter.d.ts +8 -8
  306. package/dist/routes/terminal/adapter.js +28 -125
  307. package/dist/routes/terminal/bundle.d.ts +7 -12
  308. package/dist/routes/terminal/bundle.js +24 -34
  309. package/dist/routes/terminal/credentials.d.ts +2 -2
  310. package/dist/routes/terminal/credentials.js +16 -16
  311. package/dist/routes/terminal/dry-run.d.ts +1 -1
  312. package/dist/routes/terminal/dry-run.js +9 -11
  313. package/dist/routes/terminal/encoding.d.ts +1 -1
  314. package/dist/routes/terminal/encoding.js +2 -2
  315. package/dist/routes/terminal/ledger.d.ts +6 -6
  316. package/dist/routes/terminal/ledger.js +9 -9
  317. package/dist/routes/terminal/live-finish.d.ts +1 -2
  318. package/dist/routes/terminal/live-finish.js +21 -20
  319. package/dist/routes/terminal/live-sandbox.d.ts +4 -2
  320. package/dist/routes/terminal/live-sandbox.js +25 -21
  321. package/dist/routes/terminal/participant-text.d.ts +23 -0
  322. package/dist/routes/terminal/participant-text.js +165 -0
  323. package/dist/routes/terminal/plan.d.ts +2 -6
  324. package/dist/routes/terminal/plan.js +13 -9
  325. package/dist/routes/terminal/recorder.d.ts +6 -1
  326. package/dist/routes/terminal/recorder.js +12 -4
  327. package/dist/routes/terminal/result.js +4 -4
  328. package/dist/routes/terminal/route.js +26 -26
  329. package/dist/routes/terminal/runtime.d.ts +3 -2
  330. package/dist/routes/terminal/runtime.js +3 -3
  331. package/dist/routes/terminal/sandbox.d.ts +5 -3
  332. package/dist/routes/terminal/sandbox.js +13 -16
  333. package/dist/routes/terminal/session.js +16 -14
  334. package/dist/routes/terminal/token-usage.js +5 -5
  335. package/dist/routes/terminal/trace.d.ts +5 -8
  336. package/dist/routes/terminal/trace.js +9 -64
  337. package/dist/routes/terminal/types.d.ts +85 -93
  338. package/dist/routes/terminal/types.js +9 -4
  339. package/dist/run/active-runs.d.ts +13 -0
  340. package/dist/run/active-runs.js +12 -0
  341. package/dist/run/bundle-shape.d.ts +2 -1
  342. package/dist/run/bundle-shape.js +4 -4
  343. package/dist/run/bundle.d.ts +63 -56
  344. package/dist/run/bundle.js +9 -8
  345. package/dist/run/cost-summary.js +3 -2
  346. package/dist/run/costs.d.ts +6 -6
  347. package/dist/run/costs.js +10 -10
  348. package/dist/run/detail.d.ts +5 -5
  349. package/dist/run/detail.js +6 -6
  350. package/dist/run/dry-run.js +5 -12
  351. package/dist/run/{study-files.d.ts → evidence-files.d.ts} +4 -4
  352. package/dist/run/{study-files.js → evidence-files.js} +5 -5
  353. package/dist/run/feedback-shape.js +1 -1
  354. package/dist/run/judge.d.ts +16 -4
  355. package/dist/run/judge.js +24 -7
  356. package/dist/run/locate.d.ts +2 -0
  357. package/dist/run/locate.js +3 -1
  358. package/dist/run/outcomes.d.ts +3 -3
  359. package/dist/run/outcomes.js +3 -3
  360. package/dist/run/participant-records.d.ts +2 -2
  361. package/dist/run/participant-records.js +2 -2
  362. package/dist/run/paths.js +1 -1
  363. package/dist/run/pricing.d.ts +19 -9
  364. package/dist/run/pricing.js +30 -18
  365. package/dist/run/projection.d.ts +13 -13
  366. package/dist/run/projection.js +8 -8
  367. package/dist/run/reclaim.d.ts +7 -1
  368. package/dist/run/reclaim.js +24 -4
  369. package/dist/run/results.d.ts +1 -1
  370. package/dist/run/run-index.d.ts +1 -1
  371. package/dist/run/run-index.js +11 -11
  372. package/dist/run/run.d.ts +4 -2
  373. package/dist/run/run.js +9 -5
  374. package/dist/run/sandbox-receipts.d.ts +4 -4
  375. package/dist/run/sandbox-receipts.js +4 -4
  376. package/dist/run/shared-world-evidence.d.ts +47 -47
  377. package/dist/run/shared-world-shape.d.ts +3 -3
  378. package/dist/run/shared-world-shape.js +11 -11
  379. package/dist/run/stats.d.ts +5 -5
  380. package/dist/run/stats.js +8 -8
  381. package/dist/run/status.d.ts +16 -6
  382. package/dist/run/status.js +31 -8
  383. package/dist/run/streams.d.ts +26 -19
  384. package/dist/run/terminal-contract.d.ts +5 -5
  385. package/dist/run/terminal-contract.js +4 -4
  386. package/dist/run/transient-comms-secrets.d.ts +5 -0
  387. package/dist/run/transient-comms-secrets.js +12 -0
  388. package/dist/run-lab.d.ts +36 -34
  389. package/dist/run-lab.js +41 -37
  390. package/dist/subject/desktop-cli.d.ts +1 -1
  391. package/dist/subject/desktop-cli.js +1 -1
  392. package/dist/subject/local-tree-archive.d.ts +1 -1
  393. package/dist/subject/local-tree-archive.js +4 -4
  394. package/dist/subject/local-tree.d.ts +2 -2
  395. package/dist/subject/local-tree.js +1 -1
  396. package/dist/subject/node-bootstrap.d.ts +1 -1
  397. package/dist/subject/node-bootstrap.js +4 -4
  398. package/dist/subject/runtime.js +5 -5
  399. package/dist/subject/serve.js +1 -1
  400. package/dist/subject/steps.d.ts +4 -4
  401. package/dist/subject/steps.js +5 -5
  402. package/dist/substrates/desktop-session.d.ts +2 -0
  403. package/dist/substrates/e2b/cdp-probe.d.ts +2 -2
  404. package/dist/substrates/e2b/cdp-probe.js +1 -1
  405. package/dist/substrates/e2b/desktop-browser.d.ts +3 -3
  406. package/dist/substrates/e2b/desktop-browser.js +4 -4
  407. package/dist/substrates/e2b/desktop-cdp.d.ts +7 -7
  408. package/dist/substrates/e2b/desktop-cdp.js +4 -4
  409. package/dist/substrates/e2b/desktop-geometry.d.ts +4 -4
  410. package/dist/substrates/e2b/desktop-geometry.js +3 -3
  411. package/dist/substrates/e2b/desktop-media.js +2 -2
  412. package/dist/substrates/e2b/sandbox.d.ts +2 -0
  413. package/dist/substrates/e2b/sandbox.js +22 -8
  414. package/dist/substrates/e2b/sdk.d.ts +12 -1
  415. package/dist/substrates/e2b/sdk.js +30 -9
  416. package/dist/substrates/local/runtime-host.d.ts +2 -0
  417. package/dist/substrates/local/runtime-host.js +6 -0
  418. package/dist/tui/actions.d.ts +7 -5
  419. package/dist/tui/actions.js +18 -9
  420. package/dist/tui-app.js +42 -42
  421. package/dist/verify/actor.d.ts +10 -10
  422. package/dist/verify/actor.js +15 -15
  423. package/dist/verify/artifacts.d.ts +1 -1
  424. package/dist/verify/artifacts.js +3 -3
  425. package/dist/verify/costs.d.ts +2 -2
  426. package/dist/verify/costs.js +2 -2
  427. package/dist/verify/liveness.d.ts +1 -1
  428. package/dist/verify/liveness.js +4 -1
  429. package/dist/verify/rerun.d.ts +1 -1
  430. package/dist/verify/rerun.js +1 -1
  431. package/dist/verify/shared-world.js +2 -2
  432. package/dist/verify/verify.js +6 -6
  433. package/docs/README.md +1 -1
  434. package/docs/architecture/actor-contract.md +60 -22
  435. package/docs/architecture/desktop-sessions.md +9 -9
  436. package/docs/architecture/external-public-shared-world.md +5 -0
  437. package/docs/architecture/observer.md +4 -4
  438. package/docs/architecture/restricted-codex-analysis.md +40 -4
  439. package/docs/architecture/state-driven-executor.md +4 -5
  440. package/docs/architecture/task-protocol-support.md +3 -5
  441. package/docs/architecture/{terminal-product-lane.md → terminal-product-route.md} +24 -16
  442. package/docs/contracts/run-bundle.md +10 -8
  443. package/docs/contracts/schemas.md +109 -53
  444. package/docs/contracts/study-analysis.md +24 -0
  445. package/docs/decisions/0004-participant-desktops-stay-in-the-route.md +2 -1
  446. package/docs/product/automatic-analysis.md +1 -0
  447. package/docs/ramp/README.md +2 -1
  448. package/package.json +4 -4
  449. package/skills/humanish/SKILL.md +3 -2
  450. package/skills/humanish/agents/openai.yaml +1 -1
  451. package/dist/deprecated.d.ts +0 -90
  452. package/dist/deprecated.js +0 -106
  453. package/dist/lab/bag-overrides.d.ts +0 -18
  454. package/dist/lab/bag-overrides.js +0 -121
  455. package/dist/routes/computer-use/legacy-lane-spec.d.ts +0 -62
  456. package/dist/routes/computer-use/legacy-lane-spec.js +0 -39
  457. /package/dist/routes/computer-use/{fanout-lanes.d.ts → fanout-records.d.ts} +0 -0
  458. /package/dist/routes/computer-use/{run-lanes.d.ts → live-phase.d.ts} +0 -0
  459. /package/dist/routes/shared-world/{seat-records.d.ts → bundle-records.d.ts} +0 -0
@@ -1,8 +1,13 @@
1
1
  import type { CuaProvider } from "../computer-use/loop.js";
2
2
  import { type RestrictedCodexSessionOptions } from "./restricted-session.js";
3
+ import type { RestrictedCodexAnalysisErrorCode } from "./restricted-policy.js";
3
4
  import type { ReasoningEffort } from "../reasoning-effort.js";
4
5
  export type ParticipantProviderCloseResult = {
5
6
  status: "confirmed" | "unconfirmed";
7
+ /** Run warnings from the native session, such as notification methods humanish does not know. */
8
+ warnings?: string[];
9
+ /** A refusal after the last request, such as a disallowed item outside a turn. It fails the run. */
10
+ refusal?: RestrictedCodexAnalysisErrorCode;
6
11
  };
7
12
  export interface RestrictedParticipantOptions {
8
13
  session?: RestrictedCodexSessionOptions;
@@ -13,6 +18,31 @@ export interface RestrictedParticipantOptions {
13
18
  /** Admit speech actions and heard-speaker evidence for a speech-capable desktop only. */
14
19
  speechEnabled?: boolean;
15
20
  }
21
+ /** What doctor's hosted-participant check found, before any turn. */
22
+ export interface ParticipantReadiness {
23
+ ready: boolean;
24
+ errorCode: RestrictedCodexAnalysisErrorCode | null;
25
+ /** The release the launch admitted. */
26
+ cliVersion?: string;
27
+ /** How the release's schema differs from the fields humanish reads, when that refused it. */
28
+ protocolIncompatibilities?: readonly string[];
29
+ /** Schema values beyond the baseline, recorded by a launch that passed. */
30
+ protocolAdditions?: readonly string[];
31
+ /** The model thread/start resolved from the operator's configuration or the declared model. */
32
+ resolvedModel?: string;
33
+ authentication?: "chatgpt-account" | "api-key";
34
+ }
35
+ /**
36
+ * doctor's check for a hosted Codex participant: the operator-auth launch up to an ephemeral
37
+ * thread (the version check, initialize, config/read, account/read and thread/start). It sends no
38
+ * turn, so no model request is made, and its tool is never called.
39
+ */
40
+ export declare function checkRestrictedCodexParticipantReadiness(options: {
41
+ session?: RestrictedCodexSessionOptions;
42
+ model?: string;
43
+ reasoningEffort?: ReasoningEffort;
44
+ timeoutMs?: number;
45
+ }): Promise<ParticipantReadiness>;
16
46
  /** One native tool-calling conversation; the existing CUA loop owns every input. */
17
47
  export declare function createRestrictedCodexParticipant(options?: RestrictedParticipantOptions): {
18
48
  provider: CuaProvider;
@@ -4,6 +4,8 @@ import { CuaProviderError, isCuaProviderError, } from "../computer-use/provider-
4
4
  import { validateBrowserControlPng, validateHeardSpeech } from "../../browser-control/protocol.js";
5
5
  import { createRestrictedCodexSession, } from "./restricted-session.js";
6
6
  import { PARTICIPANT_PROFILE, PARTICIPANT_LIMITS as L, PARTICIPANT_FINAL_SCHEMA, participantToolSchema, parseParticipantTool, parseParticipantFinal, } from "./restricted-participant-policy.js";
7
+ import { truncatedFrameWarning, unknownNotificationsWarning } from "./restricted-notifications.js";
8
+ import { protocolAdditionsWarning, protocolIncompatibilityMessage } from "./protocol-compat.js";
7
9
  const codeOf = (code) => {
8
10
  if (code === "cancelled" || code === "timeout" || code === "refusal")
9
11
  return code === "refusal" ? "refused" : code;
@@ -37,7 +39,7 @@ function deferred() {
37
39
  return { promise, resolve, reject };
38
40
  }
39
41
  const toolDescription = (speechEnabled) => `Act on the participant's browser through humanish. Submit one to four UI actions${speechEnabled ? ", including speak when you need to reply aloud," : ""} and a short public comment; never private reasoning. humanish returns a JSON STRING with execution acknowledgments${speechEnabled ? ", speech heard from the actual participant speaker sink," : ""} and a fresh screenshot. In Code Mode use: const r = JSON.parse(await tools.humanish_ui({narration: "...", actions: [...]})); text({acknowledgments: r.acknowledgments${speechEnabled ? ", heardSpeech: r.heardSpeech" : ""}, contextHint: r.contextHint, closing: r.closing}); image(r.imageUrl). Call serially and inspect each returned screenshot${speechEnabled ? " and heardSpeech array" : ""} before deciding what to do next.${speechEnabled ? " Use speak only after the visible UI shows that you joined the call and your microphone is unmuted; it sends audio into that call." : ""} Acknowledged input does not prove an application outcome. If closing is true, stop calling tools and give your final account.`;
40
- const participantInstructions = (study, speechEnabled) => `${study}\n\nYou are the study participant throughout this conversation, including its closing account. Use only the supplied screenshots and humanish_ui tool to interact. The tool returns a JSON string: parse it, inspect acknowledgments${speechEnabled ? " and heardSpeech captured from the actual participant speaker sink" : ""}, and display imageUrl with Code Mode image(). Do not print the image data URL as text. Keep your persona and earlier observations throughout the session.${speechEnabled ? " A speak action plays into the participant microphone; use it only after the visible UI shows that you joined the call and the microphone is unmuted." : ""} Speak publicly about your experience, never reveal private reasoning. Completed inputs do not prove application outcomes; verify on the next screenshot. When the task ends, return only the required final JSON with outcome, summary and frictionReports. Report observed confusion and recovered mistakes as well as blockers. Do not invent observations.`;
42
+ const participantInstructions = (prompt, speechEnabled) => `${prompt}\n\nYou are the study participant throughout this conversation, including its closing account. Use only the supplied screenshots and humanish_ui tool to interact. The tool returns a JSON string: parse it, inspect acknowledgments${speechEnabled ? " and heardSpeech captured from the actual participant speaker sink" : ""}, and display imageUrl with Code Mode image(). Do not print the image data URL as text. Keep your persona and earlier observations throughout the session.${speechEnabled ? " A speak action plays into the participant microphone; use it only after the visible UI shows that you joined the call and the microphone is unmuted." : ""} Speak publicly about your experience, never reveal private reasoning. Completed inputs do not prove application outcomes; verify on the next screenshot. When the task ends, return only the required final JSON with outcome, summary and frictionReports. Report observed confusion and recovered mistakes as well as blockers. Do not invent observations.`;
41
43
  /** Turns and failures from the native run, handed in order to the next provider request. */
42
44
  class ParticipantEvents {
43
45
  queued = [];
@@ -194,6 +196,43 @@ function participantSession(options, speechEnabled, effort, call) {
194
196
  },
195
197
  });
196
198
  }
199
+ /**
200
+ * doctor's check for a hosted Codex participant: the operator-auth launch up to an ephemeral
201
+ * thread (the version check, initialize, config/read, account/read and thread/start). It sends no
202
+ * turn, so no model request is made, and its tool is never called.
203
+ */
204
+ export async function checkRestrictedCodexParticipantReadiness(options) {
205
+ const session = participantSession({
206
+ authMode: "operator",
207
+ ...(options.session === undefined ? {} : { session: options.session }),
208
+ }, false, options.reasoningEffort ?? "low", async () => {
209
+ throw new Error("A readiness check makes no tool call");
210
+ });
211
+ const result = await session.run({
212
+ ...(options.model === undefined ? {} : { model: options.model }),
213
+ instructions: participantInstructions("Readiness check only.", false),
214
+ evidence: "",
215
+ images: [],
216
+ schema: PARTICIPANT_FINAL_SCHEMA,
217
+ maxOutputTokens: null,
218
+ timeoutMs: options.timeoutMs ?? 15_000,
219
+ }, true);
220
+ const closed = await session.close();
221
+ const errorCode = closed ? result.errorCode : (result.errorCode ?? "codex_cleanup_failed");
222
+ return {
223
+ ready: errorCode === null && result.status === "completed",
224
+ errorCode,
225
+ ...(session.cliVersion === undefined ? {} : { cliVersion: session.cliVersion }),
226
+ ...(session.protocolIncompatibilities === undefined
227
+ ? {}
228
+ : { protocolIncompatibilities: session.protocolIncompatibilities }),
229
+ ...(session.protocolAdditions === undefined || session.protocolAdditions.length === 0
230
+ ? {}
231
+ : { protocolAdditions: session.protocolAdditions }),
232
+ ...(session.resolvedModel === undefined ? {} : { resolvedModel: session.resolvedModel }),
233
+ ...(session.authentication === undefined ? {} : { authentication: session.authentication }),
234
+ };
235
+ }
197
236
  /**
198
237
  * The profile a run records: the detected release, or the host default before the first launch.
199
238
  * An operator-auth session has one only once it resolved a model on a ChatGPT account.
@@ -244,6 +283,22 @@ function closeParticipantSession(state) {
244
283
  return confirmed;
245
284
  }));
246
285
  }
286
+ /** What the closed native session reports beside cleanup: its run warnings and a late refusal. */
287
+ function sessionReport(session) {
288
+ const warnings = [
289
+ session.protocolIncompatibilities === undefined
290
+ ? undefined
291
+ : protocolIncompatibilityMessage(session.cliVersion, session.protocolIncompatibilities),
292
+ protocolAdditionsWarning(session.cliVersion, session.protocolAdditions),
293
+ unknownNotificationsWarning(session.unknownNotifications, session.cliVersion),
294
+ truncatedFrameWarning(session.truncatedFrameBytes),
295
+ ].filter((warning) => warning !== undefined);
296
+ const refusal = session.policyRefusal;
297
+ return {
298
+ ...(warnings.length === 0 ? {} : { warnings }),
299
+ ...(refusal === undefined ? {} : { refusal }),
300
+ };
301
+ }
247
302
  /** Stops the conversation: abort the native run, reject a waiting tool call, close the session. */
248
303
  function revokeParticipant(state) {
249
304
  state.closed = true;
@@ -424,7 +479,10 @@ export function createRestrictedCodexParticipant(options = {}) {
424
479
  const work = Promise.all([state.nativeTask, closeParticipantSession(state)]).then(([, ok]) => ok);
425
480
  if (!(await withinCleanupBudget(work, state.abortAt)))
426
481
  state.failedCleanup = true;
427
- return { status: state.failedCleanup ? "unconfirmed" : "confirmed" };
482
+ return {
483
+ status: state.failedCleanup ? "unconfirmed" : "confirmed",
484
+ ...sessionReport(state.session),
485
+ };
428
486
  })();
429
487
  return closing;
430
488
  },
@@ -11,7 +11,7 @@ export declare const RESTRICTED_CODEX_ANALYSIS_IDENTITY: {
11
11
  readonly reasoningEffort: "low";
12
12
  };
13
13
  export declare const RESTRICTED_CODEX_ANALYSIS_MODELS: readonly ["gpt-6-astra"];
14
- export type RestrictedCodexAnalysisErrorCode = "invalid_request" | "cancelled" | "timeout" | "response_too_large" | "invalid_response" | "refusal" | "output_incomplete" | "codex_unavailable" | "codex_unsupported_version" | "codex_unsupported_platform" | "codex_login_required" | "codex_unsupported_auth" | "codex_unsafe_configuration" | "codex_model_unavailable" | "codex_protocol_error" | "codex_tool_call" | "codex_process_failed" | "codex_cleanup_failed" | "codex_busy";
14
+ export type RestrictedCodexAnalysisErrorCode = "invalid_request" | "cancelled" | "timeout" | "response_too_large" | "invalid_response" | "refusal" | "output_incomplete" | "codex_unavailable" | "codex_unsupported_version" | "codex_incompatible_release" | "codex_unsupported_platform" | "codex_login_required" | "codex_unsupported_auth" | "codex_unsafe_configuration" | "codex_model_unavailable" | "codex_protocol_error" | "codex_tool_call" | "codex_process_failed" | "codex_cleanup_failed" | "codex_busy";
15
15
  export interface RestrictedCodexRequest {
16
16
  model?: string | undefined;
17
17
  instructions: string;
@@ -40,6 +40,14 @@ export interface RestrictedCodexResult {
40
40
  usageComplete: boolean;
41
41
  dispatched: boolean;
42
42
  errorCode: RestrictedCodexAnalysisErrorCode | null;
43
+ /** Notification methods this humanish does not know that carried no item, by count. */
44
+ unknownNotifications?: Readonly<Record<string, number>>;
45
+ /** How the release's app-server schema differs from the fields humanish reads (protocol-compat). */
46
+ protocolIncompatibilities?: readonly string[];
47
+ /** Schema values beyond the baseline humanish knows; recorded, and the launch continued. */
48
+ protocolAdditions?: readonly string[];
49
+ /** Bytes of a last frame cut off when humanish stopped the app-server. */
50
+ truncatedFrameBytes?: number;
43
51
  }
44
52
  export declare const CODEX_MAX_REQUEST_BYTES: number;
45
53
  export declare const CODEX_MAX_OUTPUT_BYTES: number;
@@ -14,7 +14,7 @@ export interface RestrictedCodexSessionOptions {
14
14
  /**
15
15
  * Bypasses qualification: replaces this host's admitted releases with any list. It exists only
16
16
  * so scripts/codex-qualify.mjs can launch an unqualified candidate. No library export, lab
17
- * manifest, CLI flag, RunLabOptions field or cuaHooks entry reaches it
17
+ * manifest, CLI flag, RunLabOptions field or LabDeps seam reaches it
18
18
  * (tests/actors/codex/cli-versions-seam.test.ts).
19
19
  */
20
20
  cliVersions?: readonly string[];
@@ -40,6 +40,19 @@ export interface RestrictedCodexSession {
40
40
  readonly authentication?: "chatgpt-account" | "api-key" | undefined;
41
41
  /** The admitted release this session launched, once its version check has passed. */
42
42
  readonly cliVersion?: string | undefined;
43
+ /** Notification methods this humanish does not know that carried no item, by count. */
44
+ readonly unknownNotifications?: Readonly<Record<string, number>>;
45
+ /**
46
+ * The first policy refusal or unchecked output in the session, whether or not a request reported
47
+ * it. A participant's close fails the run with it.
48
+ */
49
+ readonly policyRefusal?: RestrictedCodexAnalysisErrorCode | undefined;
50
+ /** Bytes of last frames cut off after humanish stopped the app-server; a run warning. */
51
+ readonly truncatedFrameBytes?: number | undefined;
52
+ /** How the release's schema differs from the fields humanish reads, when that refused it. */
53
+ readonly protocolIncompatibilities?: readonly string[] | undefined;
54
+ /** Schema values beyond the baseline humanish knows, recorded at launch. */
55
+ readonly protocolAdditions?: readonly string[] | undefined;
43
56
  run(request: RestrictedCodexRequest, readinessOnly?: boolean): Promise<RestrictedCodexResult>;
44
57
  close(): Promise<boolean>;
45
58
  }
@@ -5,9 +5,10 @@ import path from "node:path";
5
5
  import { admittedCodexCliVersions } from "./qualified-versions.js";
6
6
  import { launchAdmittedAppServer, } from "./restricted-launch.js";
7
7
  import { CODEX_IMAGE, CODEX_MAX_OUTPUT_BYTES, CODEX_MAX_REQUEST_BYTES, RESTRICTED_CODEX_ANALYSIS_MODELS, codexRecord, restrictedCodexFailure, restrictedCodexRequestError, } from "./restricted-policy.js";
8
- import { RestrictedCodexDeadline, RestrictedCodexStop, RestrictedCodexTransport, hasUnclosedChildren, retainUnclosedChild, } from "./restricted-transport.js";
8
+ import { RestrictedCodexDeadline, RestrictedCodexStop, hasUnclosedChildren, retainUnclosedChild, } from "./restricted-transport.js";
9
9
  import { checkVersion, childEnvironment, resolveExecutable, restrictedCodexNpmTarget, } from "./restricted-executable.js";
10
10
  import { RestrictedCodexTurn } from "./restricted-turn.js";
11
+ import { countUnknownNotification, detachTurn, idleNotifications, installSessionHandlers, notificationPolicyOf, refuseSession, } from "./restricted-notifications.js";
11
12
  function validParticipant(options) {
12
13
  if (!options)
13
14
  return true;
@@ -34,12 +35,29 @@ function validParticipant(options) {
34
35
  export async function runRestrictedCodexSession(request, options = {}, readinessOnly = false) {
35
36
  const session = createRestrictedCodexSession(options);
36
37
  const result = await session.run(request, readinessOnly);
37
- return (await session.close())
38
- ? result
39
- : {
38
+ const closed = await session.close();
39
+ const unknownNotifications = session.unknownNotifications ?? {};
40
+ const truncatedFrameBytes = session.truncatedFrameBytes;
41
+ const { protocolIncompatibilities, protocolAdditions } = session;
42
+ const noted = {
43
+ ...(Object.keys(unknownNotifications).length === 0 ? {} : { unknownNotifications }),
44
+ ...(truncatedFrameBytes === undefined ? {} : { truncatedFrameBytes }),
45
+ ...(protocolIncompatibilities === undefined ? {} : { protocolIncompatibilities }),
46
+ ...(protocolAdditions === undefined || protocolAdditions.length === 0
47
+ ? {}
48
+ : { protocolAdditions }),
49
+ };
50
+ if (!closed)
51
+ return {
40
52
  ...restrictedCodexFailure("codex_cleanup_failed", result.dispatched, result.usage),
41
53
  failurePhase: "cleanup",
54
+ ...noted,
42
55
  };
56
+ // A disallowed item while the app-server shut down fails a request that had completed.
57
+ const refusal = session.policyRefusal;
58
+ return refusal !== undefined && result.errorCode === null
59
+ ? { ...restrictedCodexFailure(refusal, result.dispatched, result.usage), ...noted }
60
+ : { ...result, ...noted };
43
61
  }
44
62
  async function writeRecoveryMarker(work, sourceEnv, reason) {
45
63
  const cache = sourceEnv.XDG_CACHE_HOME ?? path.join(sourceEnv.HOME ?? homedir(), ".cache");
@@ -200,17 +218,12 @@ function newTurn(settings, state, deadline) {
200
218
  turnStarted: (turnId) => {
201
219
  state.interrupt = { threadId: state.threadId, turnId };
202
220
  },
221
+ policy: notificationPolicyOf(participant),
222
+ idle: (method, params) => idleNotifications(participant, state)(method, params),
223
+ recordUnknown: (method) => countUnknownNotification(state.unknownNotifications, method),
224
+ refuse: (code) => refuseSession(state, code),
203
225
  });
204
226
  }
205
- /** After a request: the turn's handlers come off the transport. */
206
- function detachTurn(transport) {
207
- if (transport)
208
- transport.onNotification = () => undefined;
209
- if (transport)
210
- transport.onRequest = undefined;
211
- if (transport)
212
- transport.onRequestComplete = undefined;
213
- }
214
227
  /** Request dispatch: launch on the first request, then one turn; a failed request tears down. */
215
228
  async function runTurn(settings, state, dispose, request, readinessOnly) {
216
229
  const participant = settings.participant;
@@ -228,13 +241,13 @@ async function runTurn(settings, state, dispose, request, readinessOnly) {
228
241
  if (!state.transport) {
229
242
  state.transport = await launchAdmittedAppServer(settings, state, request, deadline, frameLimit, (next) => {
230
243
  phase = next;
231
- });
244
+ }, (transport) => installSessionHandlers(participant, state, transport));
232
245
  selectedModel = state.identity.model;
233
246
  }
234
247
  else
235
248
  state.transport.beginRequest(deadline, frameLimit);
236
- // onNotification ignores events before dispatch and onRequestComplete follows only a host
237
- // callback, so wiring both after the first launch's handshake loses nothing.
249
+ // Before dispatch the turn passes notifications to the idle handler the launch installed,
250
+ // and onRequestComplete follows only a host callback, so wiring both here loses nothing.
238
251
  state.transport.onNotification = turn.onNotification;
239
252
  state.transport.onRequestComplete = turn.onRequestComplete;
240
253
  if (readinessOnly)
@@ -269,7 +282,7 @@ async function runTurn(settings, state, dispose, request, readinessOnly) {
269
282
  state.pendingInferenceUsage = undefined;
270
283
  deadline.close();
271
284
  state.activeDeadline = undefined;
272
- detachTurn(state.transport);
285
+ detachTurn(participant, state);
273
286
  if (result.errorCode !== null) {
274
287
  if (result.errorCode === "codex_cleanup_failed")
275
288
  state.cleanupTrusted = false;
@@ -335,10 +348,15 @@ export function createRestrictedCodexSession(options = {}) {
335
348
  resolvedModel: undefined,
336
349
  authentication: undefined,
337
350
  cliVersion: undefined,
351
+ unknownNotifications: new Map(),
352
+ protocolIncompatibilities: undefined,
353
+ protocolAdditions: undefined,
338
354
  activeDeadline: undefined,
339
355
  interrupt: undefined,
340
356
  closed: false,
341
357
  cleanupTrusted: true,
358
+ policyRefusal: undefined,
359
+ truncatedFrameBytes: undefined,
342
360
  };
343
361
  let pending, closing, disposing;
344
362
  const dispose = () => {
@@ -361,6 +379,21 @@ export function createRestrictedCodexSession(options = {}) {
361
379
  get cliVersion() {
362
380
  return state.cliVersion;
363
381
  },
382
+ get unknownNotifications() {
383
+ return Object.fromEntries(state.unknownNotifications);
384
+ },
385
+ get policyRefusal() {
386
+ return state.policyRefusal;
387
+ },
388
+ get truncatedFrameBytes() {
389
+ return state.truncatedFrameBytes;
390
+ },
391
+ get protocolIncompatibilities() {
392
+ return state.protocolIncompatibilities;
393
+ },
394
+ get protocolAdditions() {
395
+ return state.protocolAdditions;
396
+ },
364
397
  run(request, readinessOnly = false) {
365
398
  const refusal = refusedRun(settings, state, request, () => pending !== undefined);
366
399
  if (refusal)
@@ -34,11 +34,21 @@ export declare class RestrictedCodexDeadline {
34
34
  }
35
35
  export declare function retainUnclosedChild(closed: Promise<void>): void;
36
36
  export declare const hasUnclosedChildren: () => boolean;
37
+ /** How the process exited: its exit code, or the signal that ended it. */
38
+ interface OwnedCodexExit {
39
+ code: number | null;
40
+ signal: NodeJS.Signals | null;
41
+ }
37
42
  export interface OwnedCodexProcess {
38
43
  child: ChildProcessWithoutNullStreams;
39
44
  closed: Promise<void>;
40
45
  isClosed(): boolean;
41
46
  hasExited(): boolean;
47
+ /** Resolves with the 'exit' event's code and signal. */
48
+ readonly exit: Promise<OwnedCodexExit>;
49
+ /** The signals humanish delivered while the process was still running (signalOwnedChild). */
50
+ signalsSent(): readonly NodeJS.Signals[];
51
+ recordSignal(signal: NodeJS.Signals): void;
42
52
  }
43
53
  export declare function ownCodexProcess(child: ChildProcessWithoutNullStreams): OwnedCodexProcess;
44
54
  export declare function closeOwnedCodexProcess(owned: OwnedCodexProcess): Promise<boolean>;
@@ -55,11 +65,29 @@ export declare class RestrictedCodexTransport {
55
65
  private eventCount;
56
66
  private closing;
57
67
  onNotification: (method: string, params: Record<string, unknown>) => void;
68
+ /** Notifications after the deadline stopped or close began: no turn handles them, only the policy. */
69
+ onPolicyOnlyNotification: (method: string, params: Record<string, unknown>) => void;
70
+ /** A server request with no handler, or output that could not be checked (failUninspected). */
71
+ onPolicyFailure: (code: RestrictedCodexAnalysisErrorCode) => void;
72
+ /** The size of a last frame cut off after humanish stopped the process: a warning only. */
73
+ onTruncatedFrame: (bytes: number) => void;
58
74
  onRequest: ((method: string, params: Record<string, unknown>) => Promise<Record<string, unknown>>) | undefined;
59
75
  onRequestComplete: (() => void) | undefined;
60
76
  constructor(owned: OwnedCodexProcess, deadline: RestrictedCodexDeadline, frameLimit?: number);
61
77
  /** A completed turn releases its deadline and wire budget, not its conversation. */
62
78
  beginRequest(deadline: RestrictedCodexDeadline, frameLimit: number): void;
79
+ /** One line of output: a malformed line could not be checked. */
80
+ private frame;
81
+ /**
82
+ * Output that could not be checked: past a byte, frame or event limit, malformed, or cut off.
83
+ * The session records it through onPolicyFailure, whatever state the transport is in.
84
+ */
85
+ private failUninspected;
86
+ /**
87
+ * Refuses the session with `code`: stops the current deadline and rejects pending requests.
88
+ * Between requests the stopped deadline makes the next beginRequest throw the code.
89
+ */
90
+ refuse(code: RestrictedCodexAnalysisErrorCode): void;
63
91
  private fail;
64
92
  private message;
65
93
  private write;
@@ -71,3 +99,4 @@ export declare class RestrictedCodexTransport {
71
99
  turnId: string;
72
100
  }): Promise<boolean>;
73
101
  }
102
+ export {};
@@ -91,8 +91,12 @@ export function retainUnclosedChild(closed) {
91
91
  export const hasUnclosedChildren = () => unclosedChildren.size > 0;
92
92
  export function ownCodexProcess(child) {
93
93
  let closed = false, exited = false;
94
- child.once("exit", () => {
95
- exited = true;
94
+ const sent = [];
95
+ const exit = new Promise((resolve) => {
96
+ child.once("exit", (code, signal) => {
97
+ exited = true;
98
+ resolve({ code, signal });
99
+ });
96
100
  });
97
101
  const completion = new Promise((resolve) => {
98
102
  child.once("close", () => {
@@ -100,7 +104,17 @@ export function ownCodexProcess(child) {
100
104
  resolve();
101
105
  });
102
106
  });
103
- return { child, closed: completion, isClosed: () => closed, hasExited: () => exited };
107
+ return {
108
+ child,
109
+ closed: completion,
110
+ isClosed: () => closed,
111
+ hasExited: () => exited,
112
+ exit,
113
+ signalsSent: () => sent,
114
+ recordSignal: (signal) => {
115
+ sent.push(signal);
116
+ },
117
+ };
104
118
  }
105
119
  async function settlesWithin(promise, ms) {
106
120
  let timer;
@@ -122,7 +136,9 @@ function signalOwnedChild(owned, signal) {
122
136
  if (owned.hasExited() || owned.isClosed())
123
137
  return;
124
138
  try {
125
- owned.child.kill(signal);
139
+ // kill() is true when the signal was delivered.
140
+ if (owned.child.kill(signal))
141
+ owned.recordSignal(signal);
126
142
  }
127
143
  catch {
128
144
  /* Closing is still checked below. */
@@ -142,6 +158,15 @@ export async function closeOwnedCodexProcess(owned) {
142
158
  owned.child.stderr.destroy();
143
159
  return closed;
144
160
  }
161
+ function isJson(text) {
162
+ try {
163
+ JSON.parse(text);
164
+ return true;
165
+ }
166
+ catch {
167
+ return false;
168
+ }
169
+ }
145
170
  export class RestrictedCodexTransport {
146
171
  owned;
147
172
  deadline;
@@ -155,6 +180,12 @@ export class RestrictedCodexTransport {
155
180
  eventCount = 0;
156
181
  closing = false;
157
182
  onNotification = () => undefined;
183
+ /** Notifications after the deadline stopped or close began: no turn handles them, only the policy. */
184
+ onPolicyOnlyNotification = () => undefined;
185
+ /** A server request with no handler, or output that could not be checked (failUninspected). */
186
+ onPolicyFailure = () => undefined;
187
+ /** The size of a last frame cut off after humanish stopped the process: a warning only. */
188
+ onTruncatedFrame = () => undefined;
158
189
  onRequest;
159
190
  onRequestComplete;
160
191
  constructor(owned, deadline, frameLimit = CODEX_MAX_OUTPUT_BYTES) {
@@ -165,38 +196,59 @@ export class RestrictedCodexTransport {
165
196
  child.on("error", () => this.fail("codex_process_failed"));
166
197
  child.stdin.on("error", () => this.fail("codex_process_failed"));
167
198
  child.on("close", () => this.fail("codex_process_failed"));
199
+ // Output is read until the process exits. Once the deadline stops or close begins, it is read
200
+ // for the item policy only (message); only the byte and frame limits stop reading, and they
201
+ // count as unchecked output.
168
202
  child.stdout.on("data", (chunk) => {
169
- if ((!this.closing && this.deadline.code !== null) ||
170
- (this.closing && this.pending.size === 0))
171
- return;
172
203
  this.stdoutBytes += chunk.length;
173
204
  if (this.stdoutBytes >
174
205
  Math.max(CODEX_MAX_STDOUT_BYTES, this.frameLimit * 2 + CODEX_MAX_OUTPUT_BYTES * 2)) {
175
- this.fail("response_too_large");
206
+ this.failUninspected("response_too_large");
176
207
  return;
177
208
  }
178
209
  this.line += this.decoder.write(chunk);
179
210
  if (Buffer.byteLength(this.line) > this.frameLimit) {
180
- this.fail("response_too_large");
211
+ this.failUninspected("response_too_large");
181
212
  return;
182
213
  }
183
214
  while (this.line.includes("\n")) {
184
- const split = this.line.indexOf("\n"), line = this.line.slice(0, split);
215
+ const split = this.line.indexOf("\n");
216
+ const line = this.line.slice(0, split);
185
217
  this.line = this.line.slice(split + 1);
186
- if (line.length === 0) {
187
- this.fail("codex_protocol_error");
188
- return;
189
- }
190
- try {
191
- this.message(JSON.parse(line));
192
- }
193
- catch {
194
- this.fail("codex_protocol_error");
195
- }
196
- if (this.deadline.code !== null && !this.closing)
197
- return;
218
+ this.frame(line);
198
219
  }
199
220
  });
221
+ // A last frame without its newline is parsed when it is whole JSON. A cut-off frame is a
222
+ // warning with its size only when humanish's own signal cut it: the signal reached the running
223
+ // process before its output ended, and the process then exited by that signal or with a code.
224
+ // Any other cut-off frame (an exit on its own, a crash, a signal humanish did not send) went
225
+ // unchecked.
226
+ child.stdout.on("end", () => {
227
+ const rest = this.line + this.decoder.end();
228
+ this.line = "";
229
+ const lines = rest.split("\n").filter((line) => line.length > 0);
230
+ const last = lines.pop();
231
+ for (const line of lines)
232
+ this.frame(line);
233
+ if (last === undefined)
234
+ return;
235
+ if (isJson(last)) {
236
+ this.frame(last);
237
+ return;
238
+ }
239
+ if (this.owned.signalsSent().length === 0) {
240
+ this.failUninspected("codex_protocol_error");
241
+ return;
242
+ }
243
+ const bytes = Buffer.byteLength(last);
244
+ void this.owned.exit.then(({ code, signal }) => {
245
+ const ours = signal === null ? code !== null : this.owned.signalsSent().includes(signal);
246
+ if (ours)
247
+ this.onTruncatedFrame(bytes);
248
+ else
249
+ this.failUninspected("codex_protocol_error");
250
+ });
251
+ });
200
252
  child.stderr.on("data", (chunk) => {
201
253
  this.stderrBytes += chunk.length;
202
254
  if (this.stderrBytes > CODEX_MAX_OUTPUT_BYTES)
@@ -215,6 +267,41 @@ export class RestrictedCodexTransport {
215
267
  this.stderrBytes = 0;
216
268
  this.eventCount = 0;
217
269
  }
270
+ /** One line of output: a malformed line could not be checked. */
271
+ frame(line) {
272
+ let parsed;
273
+ try {
274
+ parsed = line.length === 0 ? undefined : JSON.parse(line);
275
+ }
276
+ catch {
277
+ parsed = undefined;
278
+ }
279
+ if (parsed === undefined) {
280
+ this.failUninspected("codex_protocol_error");
281
+ return;
282
+ }
283
+ try {
284
+ this.message(parsed);
285
+ }
286
+ catch {
287
+ this.fail("codex_protocol_error");
288
+ }
289
+ }
290
+ /**
291
+ * Output that could not be checked: past a byte, frame or event limit, malformed, or cut off.
292
+ * The session records it through onPolicyFailure, whatever state the transport is in.
293
+ */
294
+ failUninspected(code) {
295
+ this.onPolicyFailure(code);
296
+ this.fail(code);
297
+ }
298
+ /**
299
+ * Refuses the session with `code`: stops the current deadline and rejects pending requests.
300
+ * Between requests the stopped deadline makes the next beginRequest throw the code.
301
+ */
302
+ refuse(code) {
303
+ this.fail(code);
304
+ }
218
305
  fail(code) {
219
306
  if (!this.closing)
220
307
  this.deadline.stop(code);
@@ -225,13 +312,31 @@ export class RestrictedCodexTransport {
225
312
  message(raw) {
226
313
  const value = codexRecord(raw);
227
314
  if (Object.keys(value).length === 0) {
228
- this.fail("codex_protocol_error");
315
+ this.failUninspected("codex_protocol_error");
229
316
  return;
230
317
  }
318
+ // After the deadline stopped or close began, output is read for the item policy only.
319
+ const policyOnly = this.closing || this.deadline.code !== null;
231
320
  if (value.id !== undefined && typeof value.method === "string") {
321
+ // A server request is then declined unhandled: its turn is over or being interrupted, so a
322
+ // tool call that crossed the stop runs nothing and is not a policy refusal.
323
+ if (policyOnly) {
324
+ try {
325
+ this.write({
326
+ id: value.id,
327
+ error: { code: -32601, message: "Host request is disabled" },
328
+ });
329
+ }
330
+ catch {
331
+ /* The process is already closing. */
332
+ }
333
+ return;
334
+ }
232
335
  if (!this.onRequest || ++this.eventCount > CODEX_MAX_EVENTS) {
336
+ const code = this.eventCount > CODEX_MAX_EVENTS ? "response_too_large" : "codex_tool_call";
337
+ this.onPolicyFailure(code);
233
338
  this.write({ id: value.id, error: { code: -32601, message: "Host request is disabled" } });
234
- this.fail(this.eventCount > CODEX_MAX_EVENTS ? "response_too_large" : "codex_tool_call");
339
+ this.fail(code);
235
340
  return;
236
341
  }
237
342
  const id = value.id;
@@ -263,7 +368,9 @@ export class RestrictedCodexTransport {
263
368
  if (typeof value.id === "number" && value.method === undefined) {
264
369
  const pending = this.pending.get(value.id);
265
370
  if (!pending) {
266
- this.fail("codex_protocol_error");
371
+ // A late reply, such as an interrupt's after its wait, carries no item.
372
+ if (!policyOnly)
373
+ this.fail("codex_protocol_error");
267
374
  return;
268
375
  }
269
376
  this.pending.delete(value.id);
@@ -280,10 +387,12 @@ export class RestrictedCodexTransport {
280
387
  if (typeof value.method !== "string" ||
281
388
  value.id !== undefined ||
282
389
  ++this.eventCount > CODEX_MAX_EVENTS) {
283
- this.fail(this.eventCount > CODEX_MAX_EVENTS ? "response_too_large" : "codex_protocol_error");
390
+ this.failUninspected(this.eventCount > CODEX_MAX_EVENTS ? "response_too_large" : "codex_protocol_error");
284
391
  return;
285
392
  }
286
- if (!this.closing)
393
+ if (policyOnly)
394
+ this.onPolicyOnlyNotification(value.method, codexRecord(value.params));
395
+ else
287
396
  this.onNotification(value.method, codexRecord(value.params));
288
397
  }
289
398
  write(value) {
@@ -324,6 +433,9 @@ export class RestrictedCodexTransport {
324
433
  }
325
434
  async close(interrupt) {
326
435
  this.closing = true;
436
+ // Shutdown output gets its own byte and event budget.
437
+ this.stdoutBytes = 0;
438
+ this.eventCount = 0;
327
439
  if (interrupt && !this.owned.isClosed()) {
328
440
  const { id, result } = this.request("turn/interrupt", interrupt);
329
441
  await settlesWithin(result, 1000);