@qduc/term2 0.22.1 → 0.23.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 (380) hide show
  1. package/dist/agent.d.ts +1 -0
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +18 -10
  4. package/dist/agent.js.map +1 -1
  5. package/dist/app.d.ts.map +1 -1
  6. package/dist/app.js +19 -1
  7. package/dist/app.js.map +1 -1
  8. package/dist/cli.js +26 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/components/input/ApplicationInputSurface.js +1 -1
  11. package/dist/components/input/ApplicationInputSurface.js.map +1 -1
  12. package/dist/components/input/SettingsMenuSession.d.ts.map +1 -1
  13. package/dist/components/input/SettingsMenuSession.js +8 -5
  14. package/dist/components/input/SettingsMenuSession.js.map +1 -1
  15. package/dist/components/input/SubagentPoolMenuSession.d.ts +9 -0
  16. package/dist/components/input/SubagentPoolMenuSession.d.ts.map +1 -0
  17. package/dist/components/input/{MentorPoolMenuSession.js → SubagentPoolMenuSession.js} +17 -10
  18. package/dist/components/input/SubagentPoolMenuSession.js.map +1 -0
  19. package/dist/components/input/menu-controller.d.ts.map +1 -1
  20. package/dist/components/input/menu-controller.js +4 -3
  21. package/dist/components/input/menu-controller.js.map +1 -1
  22. package/dist/components/input/menu-registry.js +2 -2
  23. package/dist/components/input/menu-registry.js.map +1 -1
  24. package/dist/components/input/menu-types.d.ts +5 -1
  25. package/dist/components/input/menu-types.d.ts.map +1 -1
  26. package/dist/components/input/triggers.d.ts.map +1 -1
  27. package/dist/components/input/triggers.js +10 -7
  28. package/dist/components/input/triggers.js.map +1 -1
  29. package/dist/components/layout/Banner.d.ts.map +1 -1
  30. package/dist/components/layout/Banner.js +4 -1
  31. package/dist/components/layout/Banner.js.map +1 -1
  32. package/dist/components/layout/StatusBar.d.ts.map +1 -1
  33. package/dist/components/layout/StatusBar.js +10 -17
  34. package/dist/components/layout/StatusBar.js.map +1 -1
  35. package/dist/components/menu/SettingsSelectionMenu.d.ts.map +1 -1
  36. package/dist/components/menu/SettingsSelectionMenu.js +3 -1
  37. package/dist/components/menu/SettingsSelectionMenu.js.map +1 -1
  38. package/dist/components/menu/SubagentPoolSelectionMenu.d.ts +19 -0
  39. package/dist/components/menu/SubagentPoolSelectionMenu.d.ts.map +1 -0
  40. package/dist/components/menu/{MentorPoolSelectionMenu.js → SubagentPoolSelectionMenu.js} +29 -15
  41. package/dist/components/menu/SubagentPoolSelectionMenu.js.map +1 -0
  42. package/dist/context/InputContext.d.ts +1 -1
  43. package/dist/context/InputContext.d.ts.map +1 -1
  44. package/dist/context/InputContext.js +2 -2
  45. package/dist/context/InputContext.js.map +1 -1
  46. package/dist/contracts/conversation-items.d.ts +4 -0
  47. package/dist/contracts/conversation-items.d.ts.map +1 -1
  48. package/dist/contracts/provider-input.d.ts +2 -0
  49. package/dist/contracts/provider-input.d.ts.map +1 -1
  50. package/dist/contracts/provider-input.js.map +1 -1
  51. package/dist/gateway/assertion.d.ts +1 -1
  52. package/dist/gateway/assertion.d.ts.map +1 -1
  53. package/dist/gateway/contracts.d.ts +13 -3
  54. package/dist/gateway/contracts.d.ts.map +1 -1
  55. package/dist/gateway/contracts.js +56 -0
  56. package/dist/gateway/contracts.js.map +1 -1
  57. package/dist/gateway/gateway.d.ts +40 -1
  58. package/dist/gateway/gateway.d.ts.map +1 -1
  59. package/dist/gateway/gateway.js +1319 -76
  60. package/dist/gateway/gateway.js.map +1 -1
  61. package/dist/gateway/persistence/admission-persistence.d.ts +3 -3
  62. package/dist/gateway/persistence/admission-persistence.d.ts.map +1 -1
  63. package/dist/gateway/persistence/admission-persistence.js +25 -11
  64. package/dist/gateway/persistence/admission-persistence.js.map +1 -1
  65. package/dist/gateway/persistence/contracts.d.ts +5 -3
  66. package/dist/gateway/persistence/contracts.d.ts.map +1 -1
  67. package/dist/gateway/persistence/contracts.js +13 -0
  68. package/dist/gateway/persistence/contracts.js.map +1 -1
  69. package/dist/gateway/persistence/interaction-checkpoint.d.ts +5 -0
  70. package/dist/gateway/persistence/interaction-checkpoint.d.ts.map +1 -1
  71. package/dist/gateway/persistence/interaction-checkpoint.js +22 -0
  72. package/dist/gateway/persistence/interaction-checkpoint.js.map +1 -1
  73. package/dist/gateway/persistence/projection.d.ts.map +1 -1
  74. package/dist/gateway/persistence/projection.js +4 -1
  75. package/dist/gateway/persistence/projection.js.map +1 -1
  76. package/dist/gateway/persistence/session-index.d.ts +1 -1
  77. package/dist/gateway/persistence/session-index.d.ts.map +1 -1
  78. package/dist/gateway/persistence/session-index.js +2 -2
  79. package/dist/gateway/persistence/session-index.js.map +1 -1
  80. package/dist/gateway/persistence/session-snapshot.d.ts +32 -0
  81. package/dist/gateway/persistence/session-snapshot.d.ts.map +1 -0
  82. package/dist/gateway/persistence/session-snapshot.js +50 -0
  83. package/dist/gateway/persistence/session-snapshot.js.map +1 -0
  84. package/dist/gateway/runtime-factory.d.ts +37 -1
  85. package/dist/gateway/runtime-factory.d.ts.map +1 -1
  86. package/dist/gateway/runtime-factory.js +155 -24
  87. package/dist/gateway/runtime-factory.js.map +1 -1
  88. package/dist/gateway/safe-log.d.ts +1 -1
  89. package/dist/gateway/safe-log.d.ts.map +1 -1
  90. package/dist/gateway/safe-log.js +5 -46
  91. package/dist/gateway/safe-log.js.map +1 -1
  92. package/dist/gateway/serve-args.d.ts +53 -0
  93. package/dist/gateway/serve-args.d.ts.map +1 -0
  94. package/dist/gateway/serve-args.js +172 -0
  95. package/dist/gateway/serve-args.js.map +1 -0
  96. package/dist/gateway/serve.d.ts +79 -0
  97. package/dist/gateway/serve.d.ts.map +1 -0
  98. package/dist/gateway/serve.js +375 -0
  99. package/dist/gateway/serve.js.map +1 -0
  100. package/dist/gateway/server-session.d.ts +9 -0
  101. package/dist/gateway/server-session.d.ts.map +1 -1
  102. package/dist/gateway/server-session.js +142 -26
  103. package/dist/gateway/server-session.js.map +1 -1
  104. package/dist/gateway/server.d.ts.map +1 -1
  105. package/dist/gateway/server.js +13 -2
  106. package/dist/gateway/server.js.map +1 -1
  107. package/dist/hooks/use-subagent-pool-selection.d.ts +115 -0
  108. package/dist/hooks/use-subagent-pool-selection.d.ts.map +1 -0
  109. package/dist/hooks/{use-mentor-pool-selection.js → use-subagent-pool-selection.js} +110 -54
  110. package/dist/hooks/use-subagent-pool-selection.js.map +1 -0
  111. package/dist/lib/agent-client.d.ts +3 -0
  112. package/dist/lib/agent-client.d.ts.map +1 -1
  113. package/dist/lib/agent-client.js +7 -0
  114. package/dist/lib/agent-client.js.map +1 -1
  115. package/dist/lib/agent-configuration.d.ts +1 -0
  116. package/dist/lib/agent-configuration.d.ts.map +1 -1
  117. package/dist/lib/agent-configuration.js +3 -0
  118. package/dist/lib/agent-configuration.js.map +1 -1
  119. package/dist/lib/agent-factory.d.ts +2 -0
  120. package/dist/lib/agent-factory.d.ts.map +1 -1
  121. package/dist/lib/agent-factory.js +5 -0
  122. package/dist/lib/agent-factory.js.map +1 -1
  123. package/dist/lib/subagent-bridge.d.ts +5 -0
  124. package/dist/lib/subagent-bridge.d.ts.map +1 -1
  125. package/dist/lib/subagent-bridge.js +5 -0
  126. package/dist/lib/subagent-bridge.js.map +1 -1
  127. package/dist/lib/tool-selection-policy.d.ts +2 -0
  128. package/dist/lib/tool-selection-policy.d.ts.map +1 -1
  129. package/dist/lib/tool-selection-policy.js +6 -1
  130. package/dist/lib/tool-selection-policy.js.map +1 -1
  131. package/dist/prompts/explorer-delegation-contract.test.ts +1 -1
  132. package/dist/prompts/prompt-constructor.d.ts.map +1 -1
  133. package/dist/prompts/prompt-constructor.js +1 -0
  134. package/dist/prompts/prompt-constructor.js.map +1 -1
  135. package/dist/prompts/prompt-constructor.test.ts +3 -0
  136. package/dist/prompts/prompt-constructor.ts +1 -0
  137. package/dist/prompts/prompt-profiles.d.ts.map +1 -1
  138. package/dist/prompts/prompt-profiles.js +3 -2
  139. package/dist/prompts/prompt-profiles.js.map +1 -1
  140. package/dist/prompts/prompt-profiles.ts +4 -2
  141. package/dist/prompts/subagent-delegation.d.ts +2 -1
  142. package/dist/prompts/subagent-delegation.d.ts.map +1 -1
  143. package/dist/prompts/subagent-delegation.js +10 -5
  144. package/dist/prompts/subagent-delegation.js.map +1 -1
  145. package/dist/prompts/subagent-delegation.test.ts +10 -3
  146. package/dist/prompts/subagent-delegation.ts +16 -4
  147. package/dist/prompts/subagents/librarian.md +26 -21
  148. package/dist/prompts/subagents/reviewer.md +33 -0
  149. package/dist/services/agent-runtime/application-run-loop.d.ts.map +1 -1
  150. package/dist/services/agent-runtime/application-run-loop.js +10 -5
  151. package/dist/services/agent-runtime/application-run-loop.js.map +1 -1
  152. package/dist/services/agent-runtime/context-compaction/local-context-compactor.d.ts +9 -0
  153. package/dist/services/agent-runtime/context-compaction/local-context-compactor.d.ts.map +1 -1
  154. package/dist/services/agent-runtime/context-compaction/local-context-compactor.js +6 -0
  155. package/dist/services/agent-runtime/context-compaction/local-context-compactor.js.map +1 -1
  156. package/dist/services/agent-runtime/model-resolver.d.ts +6 -0
  157. package/dist/services/agent-runtime/model-resolver.d.ts.map +1 -1
  158. package/dist/services/agent-runtime/model-resolver.js +18 -4
  159. package/dist/services/agent-runtime/model-resolver.js.map +1 -1
  160. package/dist/services/approval/non-interactive-approval-policy.d.ts.map +1 -1
  161. package/dist/services/approval/non-interactive-approval-policy.js +2 -1
  162. package/dist/services/approval/non-interactive-approval-policy.js.map +1 -1
  163. package/dist/services/approval/shell-auto-approval-evaluator.js +2 -2
  164. package/dist/services/approval/shell-auto-approval-evaluator.js.map +1 -1
  165. package/dist/services/conversation/conversation-service.d.ts +28 -0
  166. package/dist/services/conversation/conversation-service.d.ts.map +1 -1
  167. package/dist/services/conversation/conversation-service.js +95 -27
  168. package/dist/services/conversation/conversation-service.js.map +1 -1
  169. package/dist/services/conversation/run-item-normalizer.d.ts.map +1 -1
  170. package/dist/services/conversation/run-item-normalizer.js +3 -0
  171. package/dist/services/conversation/run-item-normalizer.js.map +1 -1
  172. package/dist/services/conversation/session-browser.d.ts +5 -0
  173. package/dist/services/conversation/session-browser.d.ts.map +1 -1
  174. package/dist/services/conversation/session-browser.js +94 -31
  175. package/dist/services/conversation/session-browser.js.map +1 -1
  176. package/dist/services/conversation/session-index/session-index-database.d.ts +1 -0
  177. package/dist/services/conversation/session-index/session-index-database.d.ts.map +1 -1
  178. package/dist/services/conversation/session-index/session-index-database.js +6 -4
  179. package/dist/services/conversation/session-index/session-index-database.js.map +1 -1
  180. package/dist/services/conversation/session-index/session-index-schema.d.ts +1 -1
  181. package/dist/services/conversation/session-index/session-index-schema.d.ts.map +1 -1
  182. package/dist/services/conversation/session-index/session-index-schema.js +2 -1
  183. package/dist/services/conversation/session-index/session-index-schema.js.map +1 -1
  184. package/dist/services/conversation-agent-client.d.ts +3 -0
  185. package/dist/services/conversation-agent-client.d.ts.map +1 -1
  186. package/dist/services/memory/memory-capabilities.d.ts.map +1 -1
  187. package/dist/services/memory/memory-capabilities.js +2 -5
  188. package/dist/services/memory/memory-capabilities.js.map +1 -1
  189. package/dist/services/plan-mode-interceptor.js +2 -2
  190. package/dist/services/plan-mode-interceptor.js.map +1 -1
  191. package/dist/services/sandboxed-code-host/host-types.d.ts +12 -1
  192. package/dist/services/sandboxed-code-host/host-types.d.ts.map +1 -1
  193. package/dist/services/sandboxed-code-host/host-types.js.map +1 -1
  194. package/dist/services/sandboxed-code-host/host-worker.d.ts.map +1 -1
  195. package/dist/services/sandboxed-code-host/host-worker.js +146 -31
  196. package/dist/services/sandboxed-code-host/host-worker.js.map +1 -1
  197. package/dist/services/sandboxed-code-host/sandbox.d.ts +6 -1
  198. package/dist/services/sandboxed-code-host/sandbox.d.ts.map +1 -1
  199. package/dist/services/sandboxed-code-host/sandbox.js +5 -0
  200. package/dist/services/sandboxed-code-host/sandbox.js.map +1 -1
  201. package/dist/services/sandboxed-code-host/sandboxed-code-host.d.ts +3 -3
  202. package/dist/services/sandboxed-code-host/sandboxed-code-host.d.ts.map +1 -1
  203. package/dist/services/sandboxed-code-host/sandboxed-code-host.js +173 -22
  204. package/dist/services/sandboxed-code-host/sandboxed-code-host.js.map +1 -1
  205. package/dist/services/session/session-access-state.d.ts +5 -1
  206. package/dist/services/session/session-access-state.d.ts.map +1 -1
  207. package/dist/services/session/session-access-state.js +8 -1
  208. package/dist/services/session/session-access-state.js.map +1 -1
  209. package/dist/services/session/session-client-factory.d.ts +1 -0
  210. package/dist/services/session/session-client-factory.d.ts.map +1 -1
  211. package/dist/services/session/session-client-factory.js +1 -1
  212. package/dist/services/session/session-client-factory.js.map +1 -1
  213. package/dist/services/session/session-composition.d.ts +22 -4
  214. package/dist/services/session/session-composition.d.ts.map +1 -1
  215. package/dist/services/session/session-composition.js +9 -5
  216. package/dist/services/session/session-composition.js.map +1 -1
  217. package/dist/services/settings/ancillary-settings-migration.d.ts.map +1 -1
  218. package/dist/services/settings/ancillary-settings-migration.js +8 -1
  219. package/dist/services/settings/ancillary-settings-migration.js.map +1 -1
  220. package/dist/services/settings/settings-schema.d.ts +12 -40
  221. package/dist/services/settings/settings-schema.d.ts.map +1 -1
  222. package/dist/services/settings/settings-schema.js +27 -53
  223. package/dist/services/settings/settings-schema.js.map +1 -1
  224. package/dist/services/settings/settings-sources.d.ts +0 -3
  225. package/dist/services/settings/settings-sources.d.ts.map +1 -1
  226. package/dist/services/settings/settings-sources.js +0 -3
  227. package/dist/services/settings/settings-sources.js.map +1 -1
  228. package/dist/services/settings/settings-ui-metadata.d.ts.map +1 -1
  229. package/dist/services/settings/settings-ui-metadata.js +3 -3
  230. package/dist/services/settings/settings-ui-metadata.js.map +1 -1
  231. package/dist/services/settings/test-helpers/settings-consumer-inventory.d.ts +1 -1
  232. package/dist/services/settings/test-helpers/settings-consumer-inventory.d.ts.map +1 -1
  233. package/dist/services/settings/test-helpers/settings-consumer-inventory.js +5 -8
  234. package/dist/services/settings/test-helpers/settings-consumer-inventory.js.map +1 -1
  235. package/dist/services/subagents/nested-runner.d.ts +3 -0
  236. package/dist/services/subagents/nested-runner.d.ts.map +1 -1
  237. package/dist/services/subagents/nested-runner.js +31 -4
  238. package/dist/services/subagents/nested-runner.js.map +1 -1
  239. package/dist/services/subagents/role-loader.d.ts.map +1 -1
  240. package/dist/services/subagents/role-loader.js +7 -12
  241. package/dist/services/subagents/role-loader.js.map +1 -1
  242. package/dist/services/subagents/runtime.d.ts +3 -0
  243. package/dist/services/subagents/runtime.d.ts.map +1 -1
  244. package/dist/services/subagents/runtime.js +35 -3
  245. package/dist/services/subagents/runtime.js.map +1 -1
  246. package/dist/services/subagents/subagent-async-registry.d.ts +10 -1
  247. package/dist/services/subagents/subagent-async-registry.d.ts.map +1 -1
  248. package/dist/services/subagents/subagent-async-registry.js +21 -4
  249. package/dist/services/subagents/subagent-async-registry.js.map +1 -1
  250. package/dist/services/subagents/subagent-manager.d.ts +3 -0
  251. package/dist/services/subagents/subagent-manager.d.ts.map +1 -1
  252. package/dist/services/subagents/subagent-manager.js.map +1 -1
  253. package/dist/services/subagents/subagent-pool-config.d.ts +39 -0
  254. package/dist/services/subagents/subagent-pool-config.d.ts.map +1 -0
  255. package/dist/services/subagents/subagent-pool-config.js +84 -0
  256. package/dist/services/subagents/subagent-pool-config.js.map +1 -0
  257. package/dist/services/subagents/subagent-role-pool-selector.d.ts +29 -0
  258. package/dist/services/subagents/subagent-role-pool-selector.d.ts.map +1 -0
  259. package/dist/services/subagents/subagent-role-pool-selector.js +56 -0
  260. package/dist/services/subagents/subagent-role-pool-selector.js.map +1 -0
  261. package/dist/services/subagents/tool-policy.d.ts +13 -0
  262. package/dist/services/subagents/tool-policy.d.ts.map +1 -1
  263. package/dist/services/subagents/tool-policy.js +36 -4
  264. package/dist/services/subagents/tool-policy.js.map +1 -1
  265. package/dist/services/subagents/types.d.ts +1 -1
  266. package/dist/services/subagents/types.d.ts.map +1 -1
  267. package/dist/services/subagents/types.js +1 -1
  268. package/dist/services/subagents/types.js.map +1 -1
  269. package/dist/test-helpers/outside-sandbox-temp-dir.d.ts +2 -0
  270. package/dist/test-helpers/outside-sandbox-temp-dir.d.ts.map +1 -0
  271. package/dist/test-helpers/outside-sandbox-temp-dir.js +38 -0
  272. package/dist/test-helpers/outside-sandbox-temp-dir.js.map +1 -0
  273. package/dist/tools/agent/configure-task-check-in.d.ts +2 -0
  274. package/dist/tools/agent/configure-task-check-in.d.ts.map +1 -1
  275. package/dist/tools/agent/configure-task-check-in.js +3 -0
  276. package/dist/tools/agent/configure-task-check-in.js.map +1 -1
  277. package/dist/tools/agent/run-explorer.d.ts +6 -0
  278. package/dist/tools/agent/run-explorer.d.ts.map +1 -0
  279. package/dist/tools/agent/run-explorer.js +58 -0
  280. package/dist/tools/agent/run-explorer.js.map +1 -0
  281. package/dist/tools/agent/run-subagent-async.d.ts +2 -0
  282. package/dist/tools/agent/run-subagent-async.d.ts.map +1 -1
  283. package/dist/tools/agent/run-subagent-async.js +3 -3
  284. package/dist/tools/agent/run-subagent-async.js.map +1 -1
  285. package/dist/tools/agent/run-subagent.d.ts +2 -2
  286. package/dist/tools/agent/run-subagent.d.ts.map +1 -1
  287. package/dist/tools/agent/run-subagent.js +8 -6
  288. package/dist/tools/agent/run-subagent.js.map +1 -1
  289. package/dist/tools/file/apply-patch.d.ts.map +1 -1
  290. package/dist/tools/file/apply-patch.js +7 -2
  291. package/dist/tools/file/apply-patch.js.map +1 -1
  292. package/dist/tools/file/create-file.d.ts.map +1 -1
  293. package/dist/tools/file/create-file.js +4 -0
  294. package/dist/tools/file/create-file.js.map +1 -1
  295. package/dist/tools/file/glob.d.ts.map +1 -1
  296. package/dist/tools/file/glob.js +6 -0
  297. package/dist/tools/file/glob.js.map +1 -1
  298. package/dist/tools/file/search-replace.d.ts.map +1 -1
  299. package/dist/tools/file/search-replace.js +6 -2
  300. package/dist/tools/file/search-replace.js.map +1 -1
  301. package/dist/tools/format-helpers.d.ts +5 -0
  302. package/dist/tools/format-helpers.d.ts.map +1 -1
  303. package/dist/tools/format-helpers.js.map +1 -1
  304. package/dist/tools/memory/memory-tools.d.ts +0 -1
  305. package/dist/tools/memory/memory-tools.d.ts.map +1 -1
  306. package/dist/tools/memory/memory-tools.js +1 -116
  307. package/dist/tools/memory/memory-tools.js.map +1 -1
  308. package/dist/tools/scripted-return-contract.d.ts +24 -0
  309. package/dist/tools/scripted-return-contract.d.ts.map +1 -0
  310. package/dist/tools/scripted-return-contract.js +36 -0
  311. package/dist/tools/scripted-return-contract.js.map +1 -0
  312. package/dist/tools/session-browser/session-browser-tools.d.ts.map +1 -1
  313. package/dist/tools/session-browser/session-browser-tools.js +21 -8
  314. package/dist/tools/session-browser/session-browser-tools.js.map +1 -1
  315. package/dist/tools/system/run-code/index.d.ts +3 -0
  316. package/dist/tools/system/run-code/index.d.ts.map +1 -1
  317. package/dist/tools/system/run-code/index.js +3 -0
  318. package/dist/tools/system/run-code/index.js.map +1 -1
  319. package/dist/tools/system/run-code/run-code-execution.d.ts +56 -0
  320. package/dist/tools/system/run-code/run-code-execution.d.ts.map +1 -0
  321. package/dist/tools/system/run-code/run-code-execution.js +68 -0
  322. package/dist/tools/system/run-code/run-code-execution.js.map +1 -0
  323. package/dist/tools/system/run-code/run-code-runtime-contract.d.ts +20 -0
  324. package/dist/tools/system/run-code/run-code-runtime-contract.d.ts.map +1 -0
  325. package/dist/tools/system/run-code/run-code-runtime-contract.js +2 -0
  326. package/dist/tools/system/run-code/run-code-runtime-contract.js.map +1 -0
  327. package/dist/tools/system/run-code/run-code-runtime.d.ts +99 -0
  328. package/dist/tools/system/run-code/run-code-runtime.d.ts.map +1 -0
  329. package/dist/tools/system/run-code/run-code-runtime.js +719 -0
  330. package/dist/tools/system/run-code/run-code-runtime.js.map +1 -0
  331. package/dist/tools/system/run-code/run-code-telemetry.d.ts +12 -10
  332. package/dist/tools/system/run-code/run-code-telemetry.d.ts.map +1 -1
  333. package/dist/tools/system/run-code/run-code-telemetry.js +48 -72
  334. package/dist/tools/system/run-code/run-code-telemetry.js.map +1 -1
  335. package/dist/tools/system/run-code/run-code.d.ts +22 -59
  336. package/dist/tools/system/run-code/run-code.d.ts.map +1 -1
  337. package/dist/tools/system/run-code/run-code.js +118 -784
  338. package/dist/tools/system/run-code/run-code.js.map +1 -1
  339. package/dist/tools/system/run-code/tools-header.d.ts +16 -4
  340. package/dist/tools/system/run-code/tools-header.d.ts.map +1 -1
  341. package/dist/tools/system/run-code/tools-header.js +32 -16
  342. package/dist/tools/system/run-code/tools-header.js.map +1 -1
  343. package/dist/tools/system/shell.d.ts +3 -0
  344. package/dist/tools/system/shell.d.ts.map +1 -1
  345. package/dist/tools/system/shell.js +13 -3
  346. package/dist/tools/system/shell.js.map +1 -1
  347. package/dist/tools/types.d.ts +12 -4
  348. package/dist/tools/types.d.ts.map +1 -1
  349. package/dist/tools/types.js.map +1 -1
  350. package/dist/utils/ai/model-settings.d.ts +6 -0
  351. package/dist/utils/ai/model-settings.d.ts.map +1 -1
  352. package/dist/utils/ai/model-settings.js +7 -1
  353. package/dist/utils/ai/model-settings.js.map +1 -1
  354. package/dist/utils/ai/token-usage.d.ts +4 -5
  355. package/dist/utils/ai/token-usage.d.ts.map +1 -1
  356. package/dist/utils/ai/token-usage.js +3 -3
  357. package/dist/utils/ai/token-usage.js.map +1 -1
  358. package/dist/utils/conversation/conversation-utils.d.ts.map +1 -1
  359. package/dist/utils/conversation/conversation-utils.js +3 -0
  360. package/dist/utils/conversation/conversation-utils.js.map +1 -1
  361. package/dist/utils/settings-command.d.ts.map +1 -1
  362. package/dist/utils/settings-command.js +2 -1
  363. package/dist/utils/settings-command.js.map +1 -1
  364. package/dist/utils/shell/sandbox/sandbox-policy.d.ts +2 -0
  365. package/dist/utils/shell/sandbox/sandbox-policy.d.ts.map +1 -1
  366. package/dist/utils/shell/sandbox/sandbox-policy.js +1 -1
  367. package/dist/utils/shell/sandbox/sandbox-policy.js.map +1 -1
  368. package/dist/utils/streaming/streaming-session-factory.d.ts.map +1 -1
  369. package/dist/utils/streaming/streaming-session-factory.js +22 -22
  370. package/dist/utils/streaming/streaming-session-factory.js.map +1 -1
  371. package/package.json +1 -1
  372. package/dist/components/input/MentorPoolMenuSession.d.ts +0 -9
  373. package/dist/components/input/MentorPoolMenuSession.d.ts.map +0 -1
  374. package/dist/components/input/MentorPoolMenuSession.js.map +0 -1
  375. package/dist/components/menu/MentorPoolSelectionMenu.d.ts +0 -13
  376. package/dist/components/menu/MentorPoolSelectionMenu.d.ts.map +0 -1
  377. package/dist/components/menu/MentorPoolSelectionMenu.js.map +0 -1
  378. package/dist/hooks/use-mentor-pool-selection.d.ts +0 -105
  379. package/dist/hooks/use-mentor-pool-selection.d.ts.map +0 -1
  380. package/dist/hooks/use-mentor-pool-selection.js.map +0 -1
@@ -1,76 +1,71 @@
1
- import { appendFileSync } from 'node:fs';
2
- import { lstat } from 'node:fs/promises';
3
- import { randomUUID } from 'node:crypto';
4
1
  import { z } from 'zod';
5
2
  import { relaxedNumber } from '../../utils.js';
6
- import { normalizeToolParameters } from '../../../lib/tool-invoke.js';
7
- import { SandboxedCodeHostImpl } from '../../../services/sandboxed-code-host/sandboxed-code-host.js';
8
- import { applyApprovalGrant } from '../../../services/approval/approval-grant-executor.js';
9
- import { isZodToolParameterSchema, } from '../../types.js';
10
3
  import { createBaseMessage, getCallIdFromItem, getOutputText, isSuccessOutput, normalizeToolArguments, } from '../../format-helpers.js';
11
- import { WORKFLOW_PROHIBITED_TOOLS } from '../../../services/agent-runtime/workflow/workflow-evaluator.js';
12
- import { renderCompactSignature, renderToolsHeader } from './tools-header.js';
13
- import { emitRunCodeCompletionTelemetry } from './run-code-telemetry.js';
14
- import { resolveWorkspacePath, resolveWorkspacePathPhysically } from '../../utils.js';
15
- import { resolveOutsideWorkspaceEdit } from '../../../services/approval/approval-descriptor.js';
16
- import { parseUpstreamApplyPatch } from '../../file/upstream-apply-patch.js';
17
- import { saveOutputArtifact, formatFullOutputSavedNote } from '../../../utils/shell/shell-output.js';
18
- export const TOOL_NAME_RUN_CODE = 'run_code';
19
- export const TOOL_NAME_DESCRIBE = 'describe';
4
+ import { renderToolsHeader } from './tools-header.js';
5
+ import { RUN_CODE_EXECUTION_RESULT } from './run-code-execution.js';
6
+ import { formatFullOutputSavedNote, saveOutputArtifact } from '../../../utils/shell/shell-output.js';
7
+ import { RUN_CODE_LIMITS, RUN_CODE_PROHIBITED_TOOLS, TOOL_NAME_RUN_CODE, createRunCodeRuntime, } from './run-code-runtime.js';
8
+ export { RUN_CODE_EXECUTION_RESULT, getRunCodeExecutionResult } from './run-code-execution.js';
9
+ export { RUN_CODE_LIMITS, RUN_CODE_PROHIBITED_TOOLS, TOOL_NAME_DESCRIBE, TOOL_NAME_RUN_CODE, isDirectlyCallable, } from './run-code-runtime.js';
20
10
  const DEFAULT_TIMEOUT_MS = 120_000;
21
11
  /** Node `setTimeout` wraps delays above `2**31-1` to ~1 ms. */
22
12
  const MAX_TIMEOUT_MS = 2_147_483_647;
23
13
  const MAX_OUTPUT_CHARS = 30_000;
24
- let nextBridgeRunId = 0;
25
- const createBridgeRunId = () => `run_code_bridge_${++nextBridgeRunId}`;
14
+ const encodeInputKeysForValidation = (value) => {
15
+ if (Array.isArray(value))
16
+ return value.map(encodeInputKeysForValidation);
17
+ if (value === null || typeof value !== 'object')
18
+ return value;
19
+ const encoded = Object.create(null);
20
+ for (const [key, item] of Object.entries(value)) {
21
+ Object.defineProperty(encoded, `$${key}`, {
22
+ value: encodeInputKeysForValidation(item),
23
+ enumerable: true,
24
+ configurable: true,
25
+ writable: true,
26
+ });
27
+ }
28
+ return encoded;
29
+ };
30
+ const decodeValidatedInputKeys = (value) => {
31
+ const decode = (item) => {
32
+ if (Array.isArray(item))
33
+ return item.map(decode);
34
+ if (item === null || typeof item !== 'object')
35
+ return item;
36
+ const decoded = Object.create(null);
37
+ for (const [key, nested] of Object.entries(item)) {
38
+ Object.defineProperty(decoded, key.slice(1), {
39
+ value: decode(nested),
40
+ enumerable: true,
41
+ configurable: true,
42
+ writable: true,
43
+ });
44
+ }
45
+ return decoded;
46
+ };
47
+ return decode(value);
48
+ };
49
+ const runCodeInputsSchema = z
50
+ .preprocess(encodeInputKeysForValidation, z.record(z.string(), z.json()))
51
+ // Zod records omit `__proto__`; prefixing every key before validation and
52
+ // removing exactly one prefix afterward keeps all JSON object keys inert.
53
+ .overwrite(decodeValidatedInputKeys);
26
54
  /**
27
55
  * Script-shaped limits. They are deliberately not the workflow's: a workflow
28
56
  * spawns a handful of agents, while a script's whole point is looping over many
29
57
  * cheap tool calls.
30
58
  */
31
- export const RUN_CODE_LIMITS = {
32
- /** Total `tools.*` calls one script may make. */
33
- maxCalls: 200,
34
- /** Parallel-safe calls that may overlap; others take a serial lane of one. */
35
- maxConcurrency: 8,
36
- /** Per-result cap. A larger result is truncated with an explicit marker. */
37
- maxResultChars: 100_000,
38
- /** Maximum raw bytes in one media attachment retained outside the script. */
39
- maxMediaBytes: 8 * 1024 * 1024,
40
- /** Maximum raw bytes and attachment count retained for one script run. */
41
- maxMediaTotalBytes: 32 * 1024 * 1024,
42
- maxMediaAttachments: 32,
43
- maxCodeBytes: 65_536,
44
- maxOutputBytes: 262_144,
45
- maxConsoleBytes: 262_144,
46
- };
47
- /**
48
- * Tools a script may never call.
49
- *
50
- * `run_code` excludes itself because each run owns its own call budget, and
51
- * nesting would let one run spend many. The rest are the workflow's prohibited
52
- * set: `run_subagent` in particular spawns agents outside any run budget, so a
53
- * script could loop on it indefinitely. Shell tools are excluded because their
54
- * complete approval state also lives in the interactive batch coordinator.
55
- */
56
- export const RUN_CODE_PROHIBITED_TOOLS = new Set([
57
- ...WORKFLOW_PROHIBITED_TOOLS,
58
- TOOL_NAME_RUN_CODE,
59
- 'ask_mentor',
60
- 'session_rollover',
61
- // Shell approval also depends on coordinator-owned Docker/session state that
62
- // the raw policy registry cannot express for an out-of-band script call.
63
- 'shell',
64
- 'bash',
65
- 'enter_worktree',
66
- 'exit_worktree',
67
- ]);
68
59
  export const runCodeParametersSchema = z.object({
69
60
  code: z
70
61
  .string()
71
62
  .min(1)
72
63
  .describe('JavaScript (not TypeScript) executed as the body of an async function. Top-level await is available. ' +
73
64
  'Return the value you want the model to receive. Use console.log only for debugging.'),
65
+ inputs: runCodeInputsSchema
66
+ .optional()
67
+ .describe('JSON data exposed to the script as the global `inputs`. Use this for patch or file text. ' +
68
+ 'Code and serialized inputs share the 65,536-byte admission limit.'),
74
69
  include_console: z
75
70
  .boolean()
76
71
  .optional()
@@ -106,59 +101,21 @@ const RUN_CODE_DESCRIPTION = 'Write a JavaScript program and execute it. Return
106
101
  'If the final result says `Full output saved to`, read that exact path with `read_file` rather than repeating completed calls; ' +
107
102
  'for a large artifact, use line ranges or a focused `grep` projection. A scripted `read_file` result may itself have ' +
108
103
  '`truncated: true` and a `fullOutputPath`; follow that path or narrow the projection before returning it. ' +
109
- 'Use `tools.describe` before guessing parameters or returned fields. If a patch is scripted, escape backticks and ' +
110
- '${...} inside a template literal, or use ordinary quoted strings with escaped newlines. ' +
104
+ 'Use `tools.describe` before guessing parameters or returned fields. If a patch or file body contains JavaScript ' +
105
+ 'syntax such as backticks or `${...}`, pass it through the `inputs` parameter and read it from the global `inputs` ' +
106
+ 'object instead of embedding it in code. Code and serialized inputs share the 65,536-byte admission limit. ' +
111
107
  'Example: `const r = await Promise.allSettled([tools.read_file({path:"a.ts"}), tools.read_file({path:"b.ts"})]); ' +
112
108
  'return r.map(x => x.status === "fulfilled" ? {content:(typeof x.value === "string" ? x.value : x.value.content).slice(0,2000)} : {error:x.reason.message});`';
113
- /**
114
- * Static host-owned classification: exactly the action tools with an explicit
115
- * outcome adapter. Not a naming convention, not a script declaration, and not
116
- * the generic `effect` flag (a stall-detection marker, not an action contract).
117
- */
118
- const ACTION_SEMANTICS = {
119
- configure_task_check_in: (raw) => {
120
- const parsed = parseActionPayload(raw);
121
- if (!isRecord(parsed) || typeof parsed.ok !== 'boolean') {
122
- return { outcome: 'unknown', reason: 'unrecognized action result shape' };
123
- }
124
- if (parsed.ok === true)
125
- return { outcome: 'applied' };
126
- const detail = typeof parsed.error === 'string' && parsed.error ? parsed.error : 'action reported ok:false';
127
- return { outcome: 'not_applied', reason: detail };
128
- },
129
- cancel_run: (raw) => {
130
- const parsed = parseActionPayload(raw);
131
- if (!isRecord(parsed) || typeof parsed.ok !== 'boolean') {
132
- return { outcome: 'unknown', reason: 'unrecognized action result shape' };
133
- }
134
- if (parsed.ok === true &&
135
- typeof parsed.runId === 'string' &&
136
- parsed.runId.length > 0 &&
137
- parsed.status === 'cancelling') {
138
- return { outcome: 'applied', reason: 'cancellation requested and accepted; settlement is reported separately' };
139
- }
140
- if (parsed.ok === false &&
141
- parsed.code === 'not_active' &&
142
- typeof parsed.target === 'string' &&
143
- parsed.target.length > 0) {
144
- return { outcome: 'not_applied', reason: `not_active (target: ${parsed.target})` };
145
- }
146
- return { outcome: 'unknown', reason: 'unrecognized action result shape' };
147
- },
148
- };
149
- const isActionTool = (name) => ACTION_SEMANTICS[name] !== undefined;
150
- const parseActionPayload = (raw) => {
151
- if (typeof raw !== 'string')
152
- return raw;
153
- try {
154
- return JSON.parse(raw);
155
- }
156
- catch {
157
- return raw;
158
- }
159
- };
160
- const MAX_RECEIPT_REASON_CHARS = 280;
161
- const clipReason = (reason) => reason.length <= MAX_RECEIPT_REASON_CHARS ? reason : `${reason.slice(0, MAX_RECEIPT_REASON_CHARS)}…`;
109
+ function attachRunCodeExecution(value, execution) {
110
+ if (Array.isArray(value)) {
111
+ const result = [...value];
112
+ Object.defineProperty(result, RUN_CODE_EXECUTION_RESULT, { value: execution });
113
+ return result;
114
+ }
115
+ const result = new String(value);
116
+ Object.defineProperty(result, RUN_CODE_EXECUTION_RESULT, { value: execution });
117
+ return result;
118
+ }
162
119
  /**
163
120
  * Marks a definition as accepting the final, wrapped tool registry.
164
121
  *
@@ -181,45 +138,6 @@ export function bindRunCodeNestedApprovalOwner(tools, owner) {
181
138
  tool[NESTED_OWNER_BINDER]?.(owner, tools);
182
139
  }
183
140
  }
184
- /**
185
- * Direct calls are the tools a script structurally cannot reach, including
186
- * `run_code` itself. Visibility does not depend on `canRequireApproval`.
187
- */
188
- export function isDirectlyCallable(tool) {
189
- return RUN_CODE_PROHIBITED_TOOLS.has(tool.name);
190
- }
191
- function unknownToolMessage(name, registry) {
192
- return `Unknown tool "${name}". Available: ${registry.map((entry) => entry.name).join(', ')}`;
193
- }
194
- function describeTool(tool) {
195
- let parameters;
196
- const targetSchema = tool.canonicalParameters ?? tool.parameters;
197
- if (isZodToolParameterSchema(targetSchema)) {
198
- try {
199
- parameters = z.toJSONSchema(targetSchema, { io: 'input' });
200
- }
201
- catch {
202
- parameters = { unconvertible: true };
203
- }
204
- }
205
- else if (targetSchema && typeof targetSchema === 'object') {
206
- parameters = targetSchema;
207
- }
208
- else {
209
- parameters = { unconvertible: true };
210
- }
211
- return {
212
- name: tool.name,
213
- description: tool.description,
214
- parameters,
215
- // The scripted-path return contract. Agents discover it here before
216
- // calling, and the tools header renders the same string for essential
217
- // tools, so both surfaces stay consistent.
218
- ...(typeof tool.scriptedReturnShape === 'string' && tool.scriptedReturnShape
219
- ? { scriptedReturnShape: tool.scriptedReturnShape }
220
- : {}),
221
- };
222
- }
223
141
  const summarizeCalls = (calls) => {
224
142
  const describeCalls = calls.filter((call) => call.outcome === 'describe');
225
143
  const executionCalls = calls.filter((call) => call.outcome !== 'describe');
@@ -263,112 +181,23 @@ const clip = async (text, protectedAction) => {
263
181
  prefix = prefix.slice(0, -1);
264
182
  return `${prefix}${marker}${action}`;
265
183
  };
266
- const FAILURE_PREFIXES = [
267
- 'Error:',
268
- 'Script failed',
269
- 'Script timed out',
270
- 'Script was cancelled',
271
- 'Script exceeded its deadline',
272
- ];
273
- /**
274
- * Whether a rendered run_code result reads as unsuccessful. Script-level
275
- * failures start with a known prefix; a script can also complete at the JS
276
- * level while its nested result is an error string (status-string tools such as
277
- * apply_patch), which the renderer places under a `Result:` heading. Lifecycle
278
- * status stays 'completed' in both cases — this is the call-level success bit,
279
- * kept separate from script success (visible in the text) and task success
280
- * (conversation-level).
281
- */
282
- const isUnsuccessfulRunCodeOutput = (output) => {
283
- if (FAILURE_PREFIXES.some((prefix) => output.startsWith(prefix)))
284
- return true;
184
+ /** Compatibility-only reader for old persisted messages. New executions carry
185
+ * a typed marker and never use rendered text for their success bit. */
186
+ const legacyRunCodeSuccess = (output) => {
187
+ if (/^(?:Error:|Script failed|Script timed out|Script was cancelled|Script exceeded its deadline)/.test(output)) {
188
+ return false;
189
+ }
285
190
  if (output.startsWith('Result:')) {
286
- // The renderer joins the rendered value and the trailing tool-call summary
287
- // with a blank line. Evaluate only the value block, using the shared
288
- // success heuristic: an 'Error:' text prefix or a JSON value carrying an
289
- // 'error' key (string or structured envelope) both read as unsuccessful.
290
191
  const valueBlock = output.slice('Result:'.length).trimStart().split('\n\n')[0];
291
- return !isSuccessOutput(valueBlock);
192
+ return isSuccessOutput(valueBlock);
292
193
  }
293
- return false;
194
+ return true;
294
195
  };
295
- /**
296
- * Truncation is a display concern, but a script may branch on the result, so
297
- * the marker has to be unmistakable rather than a silent cut.
298
- */
299
- const truncate = (text, limit) => text.length <= limit ? text : `${text.slice(0, limit)}\n[truncated: result exceeded ${limit} characters]`;
300
196
  const isRecord = (value) => typeof value === 'object' && value !== null;
301
197
  const isMediaContentPart = (value) => isRecord(value) && ((value.type === 'image' && 'image' in value) || (value.type === 'file' && 'file' in value));
302
198
  const isContentPartArray = (value) => Array.isArray(value) &&
303
199
  value.length > 0 &&
304
200
  value.every((part) => isRecord(part) && (part.type === 'text' || isMediaContentPart(part)));
305
- const MEDIA_REFERENCE_KEY = '__term2_run_code_media_reference__';
306
- const isMediaReference = (value) => isRecord(value) && typeof value[MEDIA_REFERENCE_KEY] === 'string' && Object.keys(value).length === 1;
307
- /** Count the bytes that will eventually be sent to the model, not its JSON wrapper. */
308
- function mediaBytes(value) {
309
- const payload = value.type === 'image' ? value.image : value.type === 'file' ? value.file : undefined;
310
- if (isRecord(payload) && typeof payload.data === 'string') {
311
- try {
312
- return Buffer.from(payload.data, 'base64').byteLength;
313
- }
314
- catch {
315
- return Buffer.byteLength(payload.data, 'utf8');
316
- }
317
- }
318
- try {
319
- return Buffer.byteLength(JSON.stringify(payload) ?? '', 'utf8');
320
- }
321
- catch {
322
- return Number.POSITIVE_INFINITY;
323
- }
324
- }
325
- /**
326
- * Keep large media out of both the worker transport and its generic result
327
- * budget. The reference is deliberately scoped to one execute call: a token
328
- * from another run is just an ordinary object and cannot recover its bytes.
329
- */
330
- function createMediaReferenceStore() {
331
- const attachments = new Map();
332
- const byValue = new WeakMap();
333
- let totalBytes = 0;
334
- const capture = (value) => {
335
- if (isMediaContentPart(value)) {
336
- const existing = byValue.get(value);
337
- if (existing !== undefined)
338
- return existing ? { [MEDIA_REFERENCE_KEY]: existing } : '[media content omitted]';
339
- const size = mediaBytes(value);
340
- if (!Number.isFinite(size) ||
341
- size > RUN_CODE_LIMITS.maxMediaBytes ||
342
- attachments.size >= RUN_CODE_LIMITS.maxMediaAttachments ||
343
- totalBytes + size > RUN_CODE_LIMITS.maxMediaTotalBytes) {
344
- byValue.set(value, null);
345
- return (`[media content omitted: attachment exceeds the ${RUN_CODE_LIMITS.maxMediaBytes}-byte per-image or ` +
346
- `${RUN_CODE_LIMITS.maxMediaTotalBytes}-byte per-run limit]`);
347
- }
348
- const token = `run_code_media_${randomUUID()}`;
349
- byValue.set(value, token);
350
- attachments.set(token, value);
351
- totalBytes += size;
352
- return { [MEDIA_REFERENCE_KEY]: token };
353
- }
354
- if (Array.isArray(value))
355
- return value.map(capture);
356
- if (isRecord(value)) {
357
- return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, capture(entry)]));
358
- }
359
- return value;
360
- };
361
- const resolve = (value) => {
362
- if (isMediaReference(value))
363
- return attachments.get(value[MEDIA_REFERENCE_KEY]) ?? value;
364
- if (Array.isArray(value))
365
- return value.map(resolve);
366
- if (isRecord(value))
367
- return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, resolve(entry)]));
368
- return value;
369
- };
370
- return { capture, resolve };
371
- }
372
201
  /** Look through script wrappers without mistaking ordinary arrays for media. */
373
202
  function containsMediaContent(value, ancestors = new Set()) {
374
203
  if (isMediaContentPart(value))
@@ -384,41 +213,6 @@ function containsMediaContent(value, ancestors = new Set()) {
384
213
  ancestors.delete(value);
385
214
  return found;
386
215
  }
387
- const serializeResult = async (result, limit, toolName, callsCompleted) => {
388
- if (typeof result === 'string')
389
- return { ok: true, result: truncate(result, limit) };
390
- try {
391
- const encoded = JSON.stringify(result);
392
- if (encoded === undefined)
393
- return { ok: true, result: null };
394
- if (encoded.length <= limit)
395
- return { ok: true, result: result };
396
- // Never turn a multimodal result into a partial JSON string: that both
397
- // corrupts image data and makes the failure look like a successful text
398
- // result to the script. A clear value lets the script continue (or catch
399
- // the omission) without sending an unusable image to the worker.
400
- if (containsMediaContent(result)) {
401
- return {
402
- ok: true,
403
- result: `[truncated: media result exceeded ${limit} characters; media content omitted]`,
404
- };
405
- }
406
- let retrieval = '';
407
- try {
408
- const artifactPath = await saveOutputArtifact(encoded, { filenamePrefix: 'tool-overflow' });
409
- retrieval = `Full output saved to: ${artifactPath}. `;
410
- }
411
- catch {
412
- retrieval = 'Full output could not be saved; the omitted result is unavailable. ';
413
- }
414
- const callUnit = callsCompleted === 1 ? 'call' : 'calls';
415
- const message = `Tool "${toolName}" result exceeded ${limit} characters and could not be delivered to script. ${retrieval}${callsCompleted} nested tool ${callUnit} completed — inspect state before retrying; tool effects have already completed.`;
416
- return { ok: false, error: message };
417
- }
418
- catch {
419
- return { ok: true, result: truncate(String(result), limit) };
420
- }
421
- };
422
216
  /** Replace embedded media with a text marker while retaining the real parts. */
423
217
  function stripMediaContent(value, media) {
424
218
  if (isMediaContentPart(value)) {
@@ -432,8 +226,6 @@ function stripMediaContent(value, media) {
432
226
  }
433
227
  return value;
434
228
  }
435
- /** Renders one console.log's arguments the way a terminal would. */
436
- const renderConsoleValues = (values) => values.map((value) => (typeof value === 'string' ? value : JSON.stringify(value))).join(' ');
437
229
  export const formatRunCodeCommandMessage = (item, index, toolCallArgumentsById) => {
438
230
  const callId = getCallIdFromItem(item);
439
231
  const fallbackArgs = callId && toolCallArgumentsById.has(callId) ? toolCallArgumentsById.get(callId) : null;
@@ -441,36 +233,17 @@ export const formatRunCodeCommandMessage = (item, index, toolCallArgumentsById)
441
233
  const description = typeof args?.description === 'string' ? args.description : undefined;
442
234
  const code = typeof args?.code === 'string' ? args.code : '';
443
235
  const output = getOutputText(item) || 'No output';
236
+ const semantic = item.runCodeExecution;
444
237
  return [
445
238
  createBaseMessage(item, index, 0, false, {
446
239
  command: description ? `run_code — ${description}` : 'run_code',
447
240
  output,
448
- success: !isUnsuccessfulRunCodeOutput(output),
241
+ success: semantic ? semantic.success : legacyRunCodeSuccess(output),
449
242
  toolName: TOOL_NAME_RUN_CODE,
450
243
  toolArgs: { ...args, code },
451
244
  }),
452
245
  ];
453
246
  };
454
- function getConversationSessionId(context) {
455
- if (!context || typeof context !== 'object')
456
- return undefined;
457
- const runContext = context.context;
458
- if (!runContext || typeof runContext !== 'object')
459
- return undefined;
460
- const sessionId = runContext.sessionId;
461
- return typeof sessionId === 'string' && sessionId.length > 0 ? sessionId : undefined;
462
- }
463
- function writeNestedCallRecord(tool, sessionId, outcome) {
464
- const logPath = process.env.TERM2_NESTED_CALL_LOG;
465
- if (!logPath || !sessionId)
466
- return;
467
- try {
468
- appendFileSync(logPath, `${JSON.stringify({ tool, sessionId, timestamp: new Date().toISOString(), outcome })}\n`, 'utf8');
469
- }
470
- catch {
471
- // Experiment-only logging must never affect tool execution.
472
- }
473
- }
474
247
  export function createRunCodeToolDefinition(options) {
475
248
  const { loggingService, getCwd = () => options.executionContext?.getCwd() || process.cwd() } = options;
476
249
  const approvalRegistry = options.approvalPolicyRegistry;
@@ -478,372 +251,48 @@ export function createRunCodeToolDefinition(options) {
478
251
  let boundRegistry;
479
252
  let nestedApprovalOwner = options.nestedApprovalOwner;
480
253
  const exposedTools = () => (options.getToolRegistry?.() ?? boundRegistry ?? []).filter((tool) => !RUN_CODE_PROHIBITED_TOOLS.has(tool.name));
254
+ const createRuntime = (registry) => createRunCodeRuntime({
255
+ registry,
256
+ graphIdentity: boundRegistry ?? registry,
257
+ loggingService,
258
+ approvalPolicyRegistry: approvalRegistry,
259
+ getCwd,
260
+ executionContext: options.executionContext,
261
+ nestedApprovalOwner,
262
+ sessionAccess: options.sessionAccess,
263
+ nestedCompatibility: options.nestedCompatibility,
264
+ });
481
265
  const definition = {
482
266
  name: TOOL_NAME_RUN_CODE,
483
267
  // Read late, after bindRunCodeRegistry, so the model is told which tools
484
268
  // the script can actually reach rather than a guess made before wrapping.
485
269
  get description() {
486
- const header = renderToolsHeader(exposedTools());
270
+ const header = renderToolsHeader(createRuntime(exposedTools()).discovery());
487
271
  return header ? `${RUN_CODE_DESCRIPTION}\n\n${header}` : RUN_CODE_DESCRIPTION;
488
272
  },
489
273
  parameters: runCodeParametersSchema,
490
274
  effect: 'mutating',
491
275
  needsApproval: () => false,
492
- execute: async (params, context) => {
493
- const { code, timeout_ms, description, include_console = false } = params;
276
+ execute: async (params, context, details) => {
277
+ const { code, inputs = {}, timeout_ms, description, include_console = false } = params;
494
278
  const timeout = timeout_ms ?? DEFAULT_TIMEOUT_MS;
495
279
  const callerSignal = context?.signal;
496
280
  const registry = exposedTools();
497
- const bridgeRunId = createBridgeRunId();
498
- const startedAt = Date.now();
499
- const calls = [];
500
- // Host-private action receipt ledger. Script code has no write path
501
- // here: every entry is recorded by prepare/admit/invoke settlement, so
502
- // a script cannot catch, relabel, or contradict an observed outcome.
503
- const receipts = [];
504
- const pendingReceiptByCallId = new Map();
505
- let rejectedSeq = 0;
506
- const output = [];
507
- const sessionId = getConversationSessionId(context);
508
- const mediaReferences = createMediaReferenceStore();
509
- const record = (tool, outcome, started, directlyCallable) => {
510
- calls.push({ tool, outcome, durationMs: Date.now() - started, directlyCallable });
511
- if (outcome === 'describe')
512
- return;
513
- writeNestedCallRecord(tool, sessionId, outcome === 'ok' ? 'success' : outcome === 'approval_required' ? 'denied-by-approval' : 'failure');
514
- };
515
- const failed = (message) => ({
516
- kind: 'result',
517
- result: { ok: false, error: message },
518
- });
519
- const recordReceipt = (callId, toolName, outcome, reason) => {
520
- const pendingIndex = pendingReceiptByCallId.get(callId);
521
- if (pendingIndex !== undefined) {
522
- receipts[pendingIndex] = {
523
- callId,
524
- tool: toolName,
525
- outcome,
526
- ...(reason ? { reason: clipReason(reason) } : {}),
527
- };
528
- pendingReceiptByCallId.delete(callId);
529
- return;
530
- }
531
- receipts.push({
532
- callId,
533
- tool: toolName,
534
- outcome,
535
- ...(reason ? { reason: clipReason(reason) } : {}),
536
- });
537
- };
538
- const tools = {
539
- binding: {
540
- name: 'tools',
541
- kind: 'namespace',
542
- members: [...new Set([...registry.map((tool) => tool.name), TOOL_NAME_DESCRIBE])],
543
- },
544
- limits: {
545
- maxCalls: RUN_CODE_LIMITS.maxCalls,
546
- maxConcurrency: RUN_CODE_LIMITS.maxConcurrency,
547
- limitExceededMessage: `Tool call limit reached (${RUN_CODE_LIMITS.maxCalls} calls per script run).`,
548
- },
549
- // A budget-exhausted call is the script's problem, not a reason to
550
- // discard the work it has already printed.
551
- overBudget: ({ usedCalls, maxCalls }, rejected) => {
552
- // The host supplies the exact prepared call that was rejected.
553
- // Preparation is async and concurrent, so a local FIFO would be
554
- // unable to attribute a budget rejection safely.
555
- if (isActionTool(rejected.tool.name)) {
556
- rejectedSeq += 1;
557
- recordReceipt(`${bridgeRunId}:rejected-${rejectedSeq}`, rejected.tool.name, 'unknown', 'call budget exhausted before dispatch');
558
- }
559
- return failed(`Tool call limit reached (${maxCalls} calls per script run; ${usedCalls} calls admitted, ${Math.max(0, maxCalls - usedCalls)} remaining). ` +
560
- 'Return the partial results you collected and start another run_code call only for unattempted work; ' +
561
- 'Do not repeat completed tool effects.');
562
- },
563
- onAdmitted: (prepared, callContext) => {
564
- if (!isActionTool(prepared.tool.name))
565
- return;
566
- const callId = `${bridgeRunId}:${callContext.callId}`;
567
- pendingReceiptByCallId.set(callId, receipts.length);
568
- receipts.push({ callId, tool: prepared.tool.name, outcome: 'unknown' });
569
- },
570
- prepare: async (payload) => {
571
- const started = Date.now();
572
- const name = typeof payload.member === 'string' ? payload.member : '';
573
- const tool = registry.find((candidate) => candidate.name === name);
574
- if (name === TOOL_NAME_DESCRIBE && typeof payload.params === 'string') {
575
- const described = registry.find((candidate) => candidate.name === payload.params);
576
- if (!described)
577
- return failed(unknownToolMessage(payload.params, registry));
578
- record(name, 'describe', started);
579
- return {
580
- kind: 'result',
581
- result: { ok: true, result: describeTool(described) },
582
- };
583
- }
584
- if (!tool) {
585
- record(name || '(unnamed)', 'unknown_tool', started);
586
- if (isActionTool(name)) {
587
- rejectedSeq += 1;
588
- recordReceipt(`${bridgeRunId}:rejected-${rejectedSeq}`, name, 'failed', unknownToolMessage(name, registry));
589
- }
590
- return failed(unknownToolMessage(name, registry));
591
- }
592
- const targetSchema = tool.canonicalParameters ?? tool.parameters;
593
- let normalized;
594
- try {
595
- normalized = normalizeToolParameters(payload.params ?? {}, targetSchema);
596
- }
597
- catch {
598
- normalized = payload.params ?? {};
599
- }
600
- if (isZodToolParameterSchema(targetSchema)) {
601
- const parsed = targetSchema.safeParse(normalized);
602
- if (!parsed.success) {
603
- record(name, 'invalid_params', started);
604
- const issues = parsed.error.issues
605
- .map((issue) => `${issue.path.join('.') || '(root)'}: ${issue.message}`)
606
- .join('; ');
607
- if (isActionTool(name)) {
608
- rejectedSeq += 1;
609
- recordReceipt(`${bridgeRunId}:rejected-${rejectedSeq}`, name, 'failed', `Invalid parameters: ${issues}`);
610
- }
611
- return failed(`Invalid parameters for "${name}": ${issues}\nSignature: ${renderCompactSignature(tool)}`);
612
- }
613
- normalized = parsed.data;
614
- }
615
- const authorityRoot = getCwd();
616
- const authority = await bindPreparedAuthority(name, normalized, authorityRoot, options.executionContext);
617
- if (authority.kind === 'denied') {
618
- record(name, 'approval_required', started, isDirectlyCallable(tool));
619
- if (isActionTool(name)) {
620
- rejectedSeq += 1;
621
- recordReceipt(`${bridgeRunId}:rejected-${rejectedSeq}`, name, 'not_applied', authority.message);
622
- }
623
- return failed(authority.message);
624
- }
625
- const prepared = {
626
- tool,
627
- params: authority.params,
628
- originalParams: normalized,
629
- authorityRoot,
630
- authorityMeaning: fingerprint(authority),
631
- parallelSafe: await isParallelSafe(tool, normalized, context),
632
- started,
633
- };
634
- return prepared;
635
- },
636
- // Mirrors the run loop: only a definition that declares itself
637
- // parallel-safe may overlap another call, because tools such as
638
- // enter_worktree mutate shared execution context.
639
- lane: (prepared) => (prepared.parallelSafe ? 'default' : 'serial'),
640
- invoke: async (prepared, callContext) => {
641
- const decision = await approvalRegistry.evaluate({
642
- toolName: prepared.tool.name,
643
- args: prepared.params,
644
- context,
645
- });
646
- if (decision.kind !== 'auto_approve') {
647
- if (decision.kind === 'prompt' && nestedApprovalOwner) {
648
- const nestedCallId = bridgeRunId + ':' + callContext.callId;
649
- const nestedContext = withAbortSignal(context, mergeAbortSignals(callerSignal, callContext.signal), {
650
- scripted: true,
651
- });
652
- tools.onWaiting?.(callContext);
653
- try {
654
- const resolution = await nestedApprovalOwner.request({
655
- requestId: nestedCallId,
656
- sessionId: sessionId ?? 'unknown',
657
- graphIdentity: boundRegistry ?? registry,
658
- outerRunId: bridgeRunId,
659
- nestedCallId,
660
- toolName: prepared.tool.name,
661
- preparedArguments: prepared.params,
662
- authorityContext: context,
663
- approval: {
664
- agentName: 'Nested run_code',
665
- toolName: prepared.tool.name,
666
- argumentsText: JSON.stringify(prepared.params),
667
- rawInterruption: null,
668
- callId: nestedCallId,
669
- outsideWorkspaceEdit: resolveOutsideWorkspaceEdit(prepared.tool.name, prepared.params, prepared.authorityRoot),
670
- },
671
- signal: nestedContext.signal,
672
- revalidateAuthority: async () => {
673
- const currentRoot = getCwd();
674
- const authority = await bindPreparedAuthority(prepared.tool.name, prepared.originalParams, currentRoot, options.executionContext);
675
- return (authority.kind === 'bound' &&
676
- currentRoot === prepared.authorityRoot &&
677
- fingerprint(authority) === prepared.authorityMeaning);
678
- },
679
- revalidate: async () => {
680
- const latest = await approvalRegistry.evaluate({
681
- toolName: prepared.tool.name,
682
- args: prepared.params,
683
- context,
684
- });
685
- return latest.kind;
686
- },
687
- grant: (nestedDecision) => {
688
- if (callContext.signal.aborted)
689
- throw new Error('Tool execution was not approved.');
690
- const applied = applyApprovalGrant({
691
- sessionId: sessionId ?? 'unknown',
692
- sessionAccess: options.sessionAccess,
693
- nestedCompatibility: options.nestedCompatibility,
694
- logger: loggingService,
695
- }, {
696
- answer: nestedDecision.answer,
697
- toolName: prepared.tool.name,
698
- rawArguments: prepared.params,
699
- callId: nestedCallId,
700
- });
701
- if (!applied.isApproved)
702
- throw new Error('Tool execution was not approved.');
703
- },
704
- dispatch: async () => prepared.tool.execute(prepared.params, nestedContext, { toolCall: { callId: nestedCallId } }),
705
- });
706
- if (resolution.kind === 'approved') {
707
- record(prepared.tool.name, 'ok', prepared.started);
708
- if (isActionTool(prepared.tool.name)) {
709
- const semantic = ACTION_SEMANTICS[prepared.tool.name](resolution.result);
710
- recordReceipt(`${bridgeRunId}:${callContext.callId}`, prepared.tool.name, semantic.outcome, semantic.reason);
711
- }
712
- const serialized = await serializeResult(mediaReferences.capture(resolution.result), RUN_CODE_LIMITS.maxResultChars, prepared.tool.name, calls.filter((c) => c.outcome !== 'describe').length);
713
- return {
714
- kind: 'result',
715
- result: serialized,
716
- };
717
- }
718
- if (resolution.kind === 'failed') {
719
- record(prepared.tool.name, 'error', prepared.started);
720
- const message = resolution.error instanceof Error ? resolution.error.message : String(resolution.error);
721
- if (isActionTool(prepared.tool.name)) {
722
- recordReceipt(`${bridgeRunId}:${callContext.callId}`, prepared.tool.name, 'failed', message);
723
- }
724
- return failed(message);
725
- }
726
- record(prepared.tool.name, 'approval_required', prepared.started, isDirectlyCallable(prepared.tool));
727
- if (isActionTool(prepared.tool.name)) {
728
- recordReceipt(`${bridgeRunId}:${callContext.callId}`, prepared.tool.name, 'not_applied', resolution.message);
729
- }
730
- return failed(resolution.message);
731
- }
732
- finally {
733
- tools.onResumed?.(callContext);
734
- }
735
- }
736
- const outcome = decision.kind === 'unknown'
737
- ? 'unknown_policy'
738
- : decision.kind === 'error'
739
- ? 'policy_error'
740
- : decision.kind === 'interceptor_denied'
741
- ? 'interceptor_denied'
742
- : 'approval_required';
743
- const directlyCallable = isDirectlyCallable(prepared.tool);
744
- record(prepared.tool.name, outcome, prepared.started, directlyCallable);
745
- if (isActionTool(prepared.tool.name)) {
746
- const denialReason = decision.kind === 'unknown'
747
- ? 'no registered approval policy'
748
- : decision.kind === 'interceptor_denied'
749
- ? 'refused by an approval interceptor'
750
- : decision.kind === 'error'
751
- ? 'approval policy failed'
752
- : 'requires approval and is unavailable from inside a script';
753
- recordReceipt(`${bridgeRunId}:${callContext.callId}`, prepared.tool.name, 'not_applied', denialReason);
754
- }
755
- return failed(decision.kind === 'unknown'
756
- ? `"${prepared.tool.name}" has no registered approval policy and is unavailable from inside a script.`
757
- : decision.kind === 'interceptor_denied'
758
- ? `"${prepared.tool.name}" was refused by an approval interceptor and is unavailable from inside a script.`
759
- : decision.kind === 'error'
760
- ? `"${prepared.tool.name}" approval policy failed and is unavailable from inside a script.`
761
- : `"${prepared.tool.name}" requires approval and is unavailable from inside a script.`);
762
- }
763
- const started = Date.now();
764
- const callId = `${bridgeRunId}:${callContext.callId}`;
765
- try {
766
- // Marks the call as originating inside a script: the result goes to the
767
- // script, not into model context, so context-protection caps do not apply.
768
- const nestedContext = withAbortSignal(context, mergeAbortSignals(callerSignal, callContext.signal), {
769
- scripted: true,
770
- });
771
- const result = await prepared.tool.execute(prepared.params, nestedContext, { toolCall: { callId } });
772
- record(prepared.tool.name, 'ok', started);
773
- if (isActionTool(prepared.tool.name)) {
774
- const semantic = ACTION_SEMANTICS[prepared.tool.name](result);
775
- recordReceipt(callId, prepared.tool.name, semantic.outcome, semantic.reason);
776
- }
777
- const serialized = await serializeResult(mediaReferences.capture(result), RUN_CODE_LIMITS.maxResultChars, prepared.tool.name, calls.filter((c) => c.outcome !== 'describe').length);
778
- return {
779
- kind: 'result',
780
- result: serialized,
781
- };
782
- }
783
- catch (error) {
784
- record(prepared.tool.name, 'error', started);
785
- const message = error instanceof Error ? error.message : String(error);
786
- if (isActionTool(prepared.tool.name)) {
787
- recordReceipt(callId, prepared.tool.name, 'failed', message);
788
- }
789
- return failed(message);
790
- }
791
- },
792
- };
793
- loggingService.debug('run_code execution started', {
794
- cwd: getCwd(),
281
+ // The runtime is the single owner of the nested-call lifecycle. The
282
+ // definition remains responsible for model parameters and presentation;
283
+ // in particular, it must not expose a partially wrapped registry.
284
+ const runtime = createRuntime(registry);
285
+ const runtimeResult = await runtime.execute({
286
+ code,
287
+ inputs,
795
288
  timeout,
796
- exposedTools: registry.length,
797
289
  description,
798
- });
799
- const result = await new SandboxedCodeHostImpl().run({
800
- code,
801
- capabilities: { tools },
802
- limits: {
803
- timeoutMs: timeout,
804
- maxCodeBytes: RUN_CODE_LIMITS.maxCodeBytes,
805
- maxOutputBytes: RUN_CODE_LIMITS.maxOutputBytes,
806
- maxConsoleBytes: RUN_CODE_LIMITS.maxConsoleBytes,
807
- },
808
- subject: 'Script',
809
- allowVoidOutput: true,
290
+ context,
810
291
  signal: callerSignal,
811
- onConsole: (values) => output.push(renderConsoleValues(values)),
812
- });
813
- const describeCalls = calls.filter((call) => call.outcome === 'describe');
814
- const executionCalls = calls.filter((call) => call.outcome !== 'describe');
815
- loggingService.debug('run_code execution finished', {
816
- ok: result.ok,
817
- toolCalls: executionCalls.length,
818
- schemaLookups: describeCalls.length,
819
292
  });
820
- // Calls admitted but never settled (timeout, deadline, cancellation,
821
- // worker exit) keep their pending `unknown` outcome with an honest
822
- // reason rather than vanishing from the ledger.
823
- for (const [callId, index] of pendingReceiptByCallId) {
824
- receipts[index] = {
825
- ...receipts[index],
826
- outcome: 'unknown',
827
- reason: 'did not settle before the script run ended',
828
- };
829
- pendingReceiptByCallId.delete(callId);
830
- }
831
- // Emitted before rendering: a script whose result cannot be rendered has
832
- // still produced an outcome worth counting.
833
- emitRunCodeCompletionTelemetry(loggingService, {
834
- code,
835
- result,
836
- durationMs: Date.now() - startedAt,
837
- timeoutMs: timeout,
838
- sessionId,
839
- runId: bridgeRunId,
840
- calls,
841
- receipts,
842
- });
843
- const resolvedResult = result.ok && !result.voidOutput
844
- ? { ...result, output: mediaReferences.resolve(result.output) }
845
- : result;
846
- return renderResult(resolvedResult, output, calls, receipts, include_console);
293
+ const runtimeRendered = await renderResult(runtimeResult.execution, runtimeResult.output, include_console);
294
+ const runtimeTransportCall = details && typeof details === 'object' && 'toolCall' in details && typeof details.toolCall === 'object';
295
+ return runtimeTransportCall ? attachRunCodeExecution(runtimeRendered, runtimeResult.execution) : runtimeRendered;
847
296
  },
848
297
  formatCommandMessage: formatRunCodeCommandMessage,
849
298
  };
@@ -858,125 +307,6 @@ export function createRunCodeToolDefinition(options) {
858
307
  };
859
308
  return definition;
860
309
  }
861
- const PATH_TOOLS = new Set([
862
- 'read_file',
863
- 'create_file',
864
- 'search_replace',
865
- 'apply_patch',
866
- 'grep',
867
- 'glob',
868
- 'read_code_outline',
869
- 'code_context_search',
870
- ]);
871
- async function bindPreparedAuthority(toolName, params, cwd, executionContext) {
872
- const isRemote = executionContext?.isRemote() ?? false;
873
- if (isRemote && PATH_TOOLS.has(toolName)) {
874
- return { kind: 'denied', message: 'Cannot establish remote physical path authority for a nested tool call.' };
875
- }
876
- try {
877
- const physicalRoot = isRemote ? cwd : await requirePhysicalPath(cwd, cwd);
878
- return { kind: 'bound', physicalRoot, params: await bindPreparedArguments(toolName, params, cwd) };
879
- }
880
- catch (error) {
881
- return {
882
- kind: 'denied',
883
- message: `Cannot establish physical path authority: ${error instanceof Error ? error.message : String(error)}`,
884
- };
885
- }
886
- }
887
- async function requirePhysicalPath(value, cwd, semantics = 'referent') {
888
- const physicalPath = await resolveWorkspacePathPhysically(value, cwd);
889
- if (physicalPath === undefined)
890
- throw new Error(`Unresolved path: ${value}`);
891
- if (semantics === 'unlink-source') {
892
- // Move sources are both read and unlinked. Following a leaf symlink would
893
- // preserve the read but delete its referent; reject rather than change meaning.
894
- const lexicalPath = resolveWorkspacePath(value, cwd, { allowOutsideWorkspace: true });
895
- const stats = await lstat(lexicalPath);
896
- if (stats.isSymbolicLink())
897
- throw new Error(`Symlink unlink source is unsupported: ${value}`);
898
- }
899
- return physicalPath;
900
- }
901
- async function bindPreparedArguments(toolName, params, cwd) {
902
- if (!params || typeof params !== 'object' || Array.isArray(params) || !PATH_TOOLS.has(toolName))
903
- return params;
904
- const record = params;
905
- const bindPath = async (value, semantics = 'referent') => typeof value === 'string' ? requirePhysicalPath(value, cwd, semantics) : value;
906
- if (toolName === 'apply_patch' && typeof record.patch === 'string') {
907
- return { ...record, patch: await bindPatchPaths(record.patch, bindPath) };
908
- }
909
- return 'path' in record ? { ...record, path: await bindPath(record.path) } : params;
910
- }
911
- async function bindPatchPaths(patch, bindPath) {
912
- let parsed;
913
- try {
914
- parsed = parseUpstreamApplyPatch(patch);
915
- }
916
- catch {
917
- return patch;
918
- }
919
- const targets = parsed.operations.flatMap((operation) => {
920
- const moveTo = 'moveTo' in operation ? operation.moveTo : undefined;
921
- const semantics = operation.type === 'delete_file' || moveTo ? 'unlink-source' : 'referent';
922
- return [{ path: operation.path, semantics }, ...(moveTo ? [{ path: moveTo, semantics: 'referent' }] : [])];
923
- });
924
- let targetIndex = 0;
925
- const lines = patch.replace(/\r\n?/g, '\n').split('\n');
926
- const prefixes = ['*** Add File: ', '*** Update File: ', '*** Delete File: ', '*** Move to: '];
927
- for (let index = 0; index < lines.length; index += 1) {
928
- const prefix = prefixes.find((candidate) => lines[index].startsWith(candidate));
929
- if (!prefix)
930
- continue;
931
- const target = targets[targetIndex++];
932
- const bound = await bindPath(target.path, target.semantics);
933
- lines[index] = prefix + String(bound);
934
- }
935
- return lines.join('\n');
936
- }
937
- function fingerprint(value) {
938
- try {
939
- return JSON.stringify(value) ?? String(value);
940
- }
941
- catch {
942
- return String(value);
943
- }
944
- }
945
- function withAbortSignal(context, signal, extra = {}) {
946
- return context && typeof context === 'object'
947
- ? { ...context, signal, ...extra }
948
- : { signal, ...extra };
949
- }
950
- function mergeAbortSignals(callerSignal, hostSignal) {
951
- if (!callerSignal || callerSignal === hostSignal)
952
- return callerSignal ?? hostSignal;
953
- const controller = new AbortController();
954
- const abort = () => {
955
- callerSignal.removeEventListener('abort', abort);
956
- hostSignal.removeEventListener('abort', abort);
957
- controller.abort();
958
- };
959
- if (callerSignal.aborted || hostSignal.aborted) {
960
- controller.abort();
961
- return controller.signal;
962
- }
963
- callerSignal.addEventListener('abort', abort, { once: true });
964
- hostSignal.addEventListener('abort', abort, { once: true });
965
- return controller.signal;
966
- }
967
- async function isParallelSafe(tool, params, context) {
968
- const declared = tool.parallelSafe;
969
- if (declared === undefined || declared === false)
970
- return false;
971
- if (declared === true)
972
- return true;
973
- try {
974
- return (await declared(params, context)) === true;
975
- }
976
- catch {
977
- return false;
978
- }
979
- }
980
310
  const formatActionOutcome = (outcome) => outcome === 'not_applied' ? 'not applied' : outcome;
981
311
  /**
982
312
  * Host-rendered action section. Present only when at least one covered action
@@ -1007,28 +337,32 @@ const renderActionReceipts = (receipts, includeDetails = true) => {
1007
337
  'they describe tool behavior, not user-request or task outcomes.',
1008
338
  ].join('\n');
1009
339
  };
1010
- function renderResult(result, output, calls, receipts, includeConsole) {
340
+ function renderResult(execution, output, includeConsole) {
1011
341
  const sections = [];
1012
- const media = [];
1013
- if (!result.ok && result.error) {
1014
- sections.push(result.error.code === 'timeout'
1015
- ? `Script timed out. ${result.error.message}`
1016
- : result.error.code === 'deadline'
1017
- ? `Script exceeded its deadline. ${result.error.message}`
1018
- : result.error.code === 'cancelled'
1019
- ? `Script was cancelled. ${result.error.message}`
1020
- : `Script failed: ${result.error.message}`);
1021
- }
1022
- else if (result.voidOutput === true) {
342
+ const media = execution.attachments;
343
+ const calls = execution.calls;
344
+ const receipts = execution.actions;
345
+ if (execution.script.status === 'failed') {
346
+ const { code, message } = execution.script.diagnostic;
347
+ sections.push(code === 'timeout'
348
+ ? `Script timed out. ${message}`
349
+ : code === 'deadline'
350
+ ? `Script exceeded its deadline. ${message}`
351
+ : code === 'cancellation'
352
+ ? `Script was cancelled. ${message}`
353
+ : `Script failed: ${message}`);
354
+ }
355
+ else if (execution.script.voidOutput) {
1023
356
  sections.push('Script returned no result. Return a value from the script to send it to the model.');
1024
357
  }
1025
358
  else {
1026
- const stripped = containsMediaContent(result.output) ? stripMediaContent(result.output, media) : result.output;
359
+ const value = execution.script.value;
360
+ const stripped = containsMediaContent(value) ? stripMediaContent(value, media) : value;
1027
361
  // A top-level content-part array already has a useful text projection;
1028
362
  // wrappers (Promise.all, object fields, etc.) retain their shape in JSON,
1029
363
  // with media replaced by markers so base64 never leaks into text.
1030
- const rendered = media.length > 0 && isContentPartArray(result.output)
1031
- ? result.output
364
+ const rendered = media.length > 0 && isContentPartArray(value)
365
+ ? value
1032
366
  .filter((part) => part.type === 'text' && typeof part.text === 'string')
1033
367
  .map((part) => part.text)
1034
368
  .join('\n')
@@ -1038,7 +372,7 @@ function renderResult(result, output, calls, receipts, includeConsole) {
1038
372
  sections.push(`Result:\n${rendered}`);
1039
373
  }
1040
374
  const printed = output.join('\n').trim();
1041
- if (printed && (!result.ok || includeConsole))
375
+ if (printed && (execution.script.status === 'failed' || includeConsole))
1042
376
  sections.push(`Console trace (debug):\n${printed}`);
1043
377
  const refused = calls.filter((call) => call.outcome === 'approval_required');
1044
378
  const directlyRefused = refused.filter((call) => call.directlyCallable === true);