@nodetool-ai/websocket 0.8.1 → 0.8.3

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 (471) hide show
  1. package/dist/.nodetool-build-stamp +1 -1
  2. package/dist/chat-turn-registry.d.ts +2 -1
  3. package/dist/chat-turn-registry.d.ts.map +1 -1
  4. package/dist/chat-turn-registry.js +8 -1
  5. package/dist/chat-turn-registry.js.map +1 -1
  6. package/dist/collection-api.d.ts.map +1 -1
  7. package/dist/collection-api.js +41 -6
  8. package/dist/collection-api.js.map +1 -1
  9. package/dist/custom-providers.d.ts.map +1 -1
  10. package/dist/custom-providers.js +6 -1
  11. package/dist/custom-providers.js.map +1 -1
  12. package/dist/error-traces.d.ts +56 -0
  13. package/dist/error-traces.d.ts.map +1 -0
  14. package/dist/error-traces.js +179 -0
  15. package/dist/error-traces.js.map +1 -0
  16. package/dist/example-workflows.d.ts.map +1 -1
  17. package/dist/example-workflows.js +6 -0
  18. package/dist/example-workflows.js.map +1 -1
  19. package/dist/fake-runtime.d.ts +41 -6
  20. package/dist/fake-runtime.d.ts.map +1 -1
  21. package/dist/fake-runtime.js +247 -16
  22. package/dist/fake-runtime.js.map +1 -1
  23. package/dist/file-api.d.ts.map +1 -1
  24. package/dist/file-api.js +6 -8
  25. package/dist/file-api.js.map +1 -1
  26. package/dist/generation-recovery.d.ts.map +1 -1
  27. package/dist/generation-recovery.js +32 -7
  28. package/dist/generation-recovery.js.map +1 -1
  29. package/dist/headless-job-runner.d.ts.map +1 -1
  30. package/dist/headless-job-runner.js +5 -1
  31. package/dist/headless-job-runner.js.map +1 -1
  32. package/dist/http-api.d.ts +3 -1
  33. package/dist/http-api.d.ts.map +1 -1
  34. package/dist/http-api.js +66 -9
  35. package/dist/http-api.js.map +1 -1
  36. package/dist/http-body-schemas.d.ts +2 -0
  37. package/dist/http-body-schemas.d.ts.map +1 -1
  38. package/dist/http-body-schemas.js +8 -1
  39. package/dist/http-body-schemas.js.map +1 -1
  40. package/dist/index.d.ts +0 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +0 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/interrupted-jobs.d.ts +14 -0
  45. package/dist/interrupted-jobs.d.ts.map +1 -0
  46. package/dist/interrupted-jobs.js +28 -0
  47. package/dist/interrupted-jobs.js.map +1 -0
  48. package/dist/lib/admin.d.ts +7 -0
  49. package/dist/lib/admin.d.ts.map +1 -0
  50. package/dist/lib/admin.js +20 -0
  51. package/dist/lib/admin.js.map +1 -0
  52. package/dist/lib/app-debug-service.js +1 -1
  53. package/dist/lib/app-debug-service.js.map +1 -1
  54. package/dist/lib/app-instances-service.d.ts +1319 -0
  55. package/dist/lib/app-instances-service.d.ts.map +1 -0
  56. package/dist/lib/app-instances-service.js +377 -0
  57. package/dist/lib/app-instances-service.js.map +1 -0
  58. package/dist/lib/app-project-export.d.ts +12 -0
  59. package/dist/lib/app-project-export.d.ts.map +1 -0
  60. package/dist/lib/app-project-export.js +42 -0
  61. package/dist/lib/app-project-export.js.map +1 -0
  62. package/dist/lib/app-run-cancellation.d.ts +4 -0
  63. package/dist/lib/app-run-cancellation.d.ts.map +1 -0
  64. package/dist/lib/app-run-cancellation.js +28 -0
  65. package/dist/lib/app-run-cancellation.js.map +1 -0
  66. package/dist/lib/applications-service.d.ts +182 -1
  67. package/dist/lib/applications-service.d.ts.map +1 -1
  68. package/dist/lib/applications-service.js +27 -6
  69. package/dist/lib/applications-service.js.map +1 -1
  70. package/dist/lib/asset-export.d.ts +6 -2
  71. package/dist/lib/asset-export.d.ts.map +1 -1
  72. package/dist/lib/asset-export.js +15 -7
  73. package/dist/lib/asset-export.js.map +1 -1
  74. package/dist/lib/asset-paths.d.ts +7 -11
  75. package/dist/lib/asset-paths.d.ts.map +1 -1
  76. package/dist/lib/asset-paths.js +8 -56
  77. package/dist/lib/asset-paths.js.map +1 -1
  78. package/dist/lib/asset-response.d.ts.map +1 -1
  79. package/dist/lib/asset-response.js +3 -1
  80. package/dist/lib/asset-response.js.map +1 -1
  81. package/dist/lib/audio-peaks.d.ts.map +1 -1
  82. package/dist/lib/audio-peaks.js +5 -1
  83. package/dist/lib/audio-peaks.js.map +1 -1
  84. package/dist/lib/bridge.d.ts.map +1 -1
  85. package/dist/lib/bridge.js.map +1 -1
  86. package/dist/lib/cloud-profile.d.ts +10 -0
  87. package/dist/lib/cloud-profile.d.ts.map +1 -0
  88. package/dist/lib/cloud-profile.js +13 -0
  89. package/dist/lib/cloud-profile.js.map +1 -0
  90. package/dist/lib/document-model-interfaces.d.ts.map +1 -1
  91. package/dist/lib/document-model-interfaces.js +9 -8
  92. package/dist/lib/document-model-interfaces.js.map +1 -1
  93. package/dist/lib/example-apps.d.ts +9 -0
  94. package/dist/lib/example-apps.d.ts.map +1 -1
  95. package/dist/lib/example-apps.js +61 -14
  96. package/dist/lib/example-apps.js.map +1 -1
  97. package/dist/lib/http-tracing.d.ts +12 -0
  98. package/dist/lib/http-tracing.d.ts.map +1 -0
  99. package/dist/lib/http-tracing.js +81 -0
  100. package/dist/lib/http-tracing.js.map +1 -0
  101. package/dist/lib/http-user-id.d.ts +2 -0
  102. package/dist/lib/http-user-id.d.ts.map +1 -0
  103. package/dist/lib/http-user-id.js +4 -0
  104. package/dist/lib/http-user-id.js.map +1 -0
  105. package/dist/lib/json-body.d.ts +11 -0
  106. package/dist/lib/json-body.d.ts.map +1 -0
  107. package/dist/lib/json-body.js +13 -0
  108. package/dist/lib/json-body.js.map +1 -0
  109. package/dist/lib/media.d.ts +1 -6
  110. package/dist/lib/media.d.ts.map +1 -1
  111. package/dist/lib/media.js +8 -44
  112. package/dist/lib/media.js.map +1 -1
  113. package/dist/lib/public-routes.d.ts +22 -0
  114. package/dist/lib/public-routes.d.ts.map +1 -1
  115. package/dist/lib/public-routes.js +41 -0
  116. package/dist/lib/public-routes.js.map +1 -1
  117. package/dist/lib/public-workflow-share.d.ts +31 -0
  118. package/dist/lib/public-workflow-share.d.ts.map +1 -0
  119. package/dist/lib/public-workflow-share.js +88 -0
  120. package/dist/lib/public-workflow-share.js.map +1 -0
  121. package/dist/lib/python-metadata-roots.d.ts +27 -0
  122. package/dist/lib/python-metadata-roots.d.ts.map +1 -0
  123. package/dist/lib/python-metadata-roots.js +92 -0
  124. package/dist/lib/python-metadata-roots.js.map +1 -0
  125. package/dist/lib/run-trace-live-delivery.d.ts +25 -0
  126. package/dist/lib/run-trace-live-delivery.d.ts.map +1 -0
  127. package/dist/lib/run-trace-live-delivery.js +91 -0
  128. package/dist/lib/run-trace-live-delivery.js.map +1 -0
  129. package/dist/lib/runtime-detection.d.ts +1 -1
  130. package/dist/lib/runtime-detection.d.ts.map +1 -1
  131. package/dist/lib/runtime-detection.js +2 -1
  132. package/dist/lib/runtime-detection.js.map +1 -1
  133. package/dist/lib/server-auth-token.d.ts +18 -0
  134. package/dist/lib/server-auth-token.d.ts.map +1 -0
  135. package/dist/lib/server-auth-token.js +28 -0
  136. package/dist/lib/server-auth-token.js.map +1 -0
  137. package/dist/lib/test-ui-run-routes.d.ts +8 -0
  138. package/dist/lib/test-ui-run-routes.d.ts.map +1 -0
  139. package/dist/lib/test-ui-run-routes.js +42 -0
  140. package/dist/lib/test-ui-run-routes.js.map +1 -0
  141. package/dist/lib/thumbnail.d.ts.map +1 -1
  142. package/dist/lib/thumbnail.js +12 -9
  143. package/dist/lib/thumbnail.js.map +1 -1
  144. package/dist/lib/timeline-bundle.d.ts +159 -16
  145. package/dist/lib/timeline-bundle.d.ts.map +1 -1
  146. package/dist/lib/timeline-bundle.js +34 -6
  147. package/dist/lib/timeline-bundle.js.map +1 -1
  148. package/dist/lib/timeline-media-export.d.ts +18 -0
  149. package/dist/lib/timeline-media-export.d.ts.map +1 -0
  150. package/dist/lib/timeline-media-export.js +66 -0
  151. package/dist/lib/timeline-media-export.js.map +1 -0
  152. package/dist/lib/timeline-premiere-import.d.ts +24 -0
  153. package/dist/lib/timeline-premiere-import.d.ts.map +1 -0
  154. package/dist/lib/timeline-premiere-import.js +102 -0
  155. package/dist/lib/timeline-premiere-import.js.map +1 -0
  156. package/dist/lib/timeline-premiere.d.ts +38 -0
  157. package/dist/lib/timeline-premiere.d.ts.map +1 -0
  158. package/dist/lib/timeline-premiere.js +87 -0
  159. package/dist/lib/timeline-premiere.js.map +1 -0
  160. package/dist/lib/video-proxy.d.ts.map +1 -1
  161. package/dist/lib/video-proxy.js +3 -2
  162. package/dist/lib/video-proxy.js.map +1 -1
  163. package/dist/lib/workflow-service.d.ts.map +1 -1
  164. package/dist/lib/workflow-service.js +4 -1
  165. package/dist/lib/workflow-service.js.map +1 -1
  166. package/dist/mcp-agent-tools.d.ts.map +1 -1
  167. package/dist/mcp-agent-tools.js +95 -162
  168. package/dist/mcp-agent-tools.js.map +1 -1
  169. package/dist/mcp-client-config.d.ts +64 -0
  170. package/dist/mcp-client-config.d.ts.map +1 -0
  171. package/dist/mcp-client-config.js +353 -0
  172. package/dist/mcp-client-config.js.map +1 -0
  173. package/dist/mcp-server.d.ts +7 -0
  174. package/dist/mcp-server.d.ts.map +1 -1
  175. package/dist/mcp-server.js +163 -16
  176. package/dist/mcp-server.js.map +1 -1
  177. package/dist/mcp-skill-prompts.d.ts +23 -0
  178. package/dist/mcp-skill-prompts.d.ts.map +1 -0
  179. package/dist/mcp-skill-prompts.js +91 -0
  180. package/dist/mcp-skill-prompts.js.map +1 -0
  181. package/dist/mcp-tool-deps.d.ts.map +1 -1
  182. package/dist/mcp-tool-deps.js +8 -1
  183. package/dist/mcp-tool-deps.js.map +1 -1
  184. package/dist/models-api.d.ts +10 -0
  185. package/dist/models-api.d.ts.map +1 -1
  186. package/dist/models-api.js +29 -2
  187. package/dist/models-api.js.map +1 -1
  188. package/dist/node-registry-setup.d.ts +1 -1
  189. package/dist/node-registry-setup.d.ts.map +1 -1
  190. package/dist/node-registry-setup.js +21 -114
  191. package/dist/node-registry-setup.js.map +1 -1
  192. package/dist/oauth-api.d.ts.map +1 -1
  193. package/dist/oauth-api.js +45 -23
  194. package/dist/oauth-api.js.map +1 -1
  195. package/dist/openai-api.d.ts.map +1 -1
  196. package/dist/openai-api.js +10 -2
  197. package/dist/openai-api.js.map +1 -1
  198. package/dist/plugins/websocket.d.ts.map +1 -1
  199. package/dist/plugins/websocket.js +27 -59
  200. package/dist/plugins/websocket.js.map +1 -1
  201. package/dist/python-bridge-gate.d.ts +28 -0
  202. package/dist/python-bridge-gate.d.ts.map +1 -0
  203. package/dist/python-bridge-gate.js +36 -0
  204. package/dist/python-bridge-gate.js.map +1 -0
  205. package/dist/routes/app-runs.d.ts +4 -0
  206. package/dist/routes/app-runs.d.ts.map +1 -0
  207. package/dist/routes/app-runs.js +173 -0
  208. package/dist/routes/app-runs.js.map +1 -0
  209. package/dist/routes/applications.d.ts +1 -0
  210. package/dist/routes/applications.d.ts.map +1 -1
  211. package/dist/routes/applications.js +24 -0
  212. package/dist/routes/applications.js.map +1 -1
  213. package/dist/routes/assets.d.ts.map +1 -1
  214. package/dist/routes/assets.js +31 -41
  215. package/dist/routes/assets.js.map +1 -1
  216. package/dist/routes/config.d.ts.map +1 -1
  217. package/dist/routes/config.js +6 -0
  218. package/dist/routes/config.js.map +1 -1
  219. package/dist/routes/documents.d.ts.map +1 -1
  220. package/dist/routes/documents.js +24 -0
  221. package/dist/routes/documents.js.map +1 -1
  222. package/dist/routes/fal-pricing-estimate.d.ts.map +1 -1
  223. package/dist/routes/fal-pricing-estimate.js +2 -0
  224. package/dist/routes/fal-pricing-estimate.js.map +1 -1
  225. package/dist/routes/files.d.ts.map +1 -1
  226. package/dist/routes/files.js +2 -0
  227. package/dist/routes/files.js.map +1 -1
  228. package/dist/routes/games.d.ts +38 -0
  229. package/dist/routes/games.d.ts.map +1 -0
  230. package/dist/routes/games.js +158 -0
  231. package/dist/routes/games.js.map +1 -0
  232. package/dist/routes/integrations.d.ts.map +1 -1
  233. package/dist/routes/integrations.js +22 -26
  234. package/dist/routes/integrations.js.map +1 -1
  235. package/dist/routes/js-scripts.d.ts +10 -4
  236. package/dist/routes/js-scripts.d.ts.map +1 -1
  237. package/dist/routes/js-scripts.js +451 -69
  238. package/dist/routes/js-scripts.js.map +1 -1
  239. package/dist/routes/nodes.d.ts.map +1 -1
  240. package/dist/routes/nodes.js +34 -1
  241. package/dist/routes/nodes.js.map +1 -1
  242. package/dist/routes/public-shared-workflows.d.ts +16 -0
  243. package/dist/routes/public-shared-workflows.d.ts.map +1 -0
  244. package/dist/routes/public-shared-workflows.js +55 -0
  245. package/dist/routes/public-shared-workflows.js.map +1 -0
  246. package/dist/routes/run-spans.d.ts +4 -0
  247. package/dist/routes/run-spans.d.ts.map +1 -0
  248. package/dist/routes/run-spans.js +53 -0
  249. package/dist/routes/run-spans.js.map +1 -0
  250. package/dist/routes/storage.d.ts.map +1 -1
  251. package/dist/routes/storage.js +2 -0
  252. package/dist/routes/storage.js.map +1 -1
  253. package/dist/routes/storyboards.d.ts.map +1 -1
  254. package/dist/routes/storyboards.js +6 -3
  255. package/dist/routes/storyboards.js.map +1 -1
  256. package/dist/routes/timeline-fonts.d.ts +22 -0
  257. package/dist/routes/timeline-fonts.d.ts.map +1 -1
  258. package/dist/routes/timeline-fonts.js +138 -7
  259. package/dist/routes/timeline-fonts.js.map +1 -1
  260. package/dist/routes/timelines.d.ts +8 -4
  261. package/dist/routes/timelines.d.ts.map +1 -1
  262. package/dist/routes/timelines.js +209 -16
  263. package/dist/routes/timelines.js.map +1 -1
  264. package/dist/screenshot-docs-seed.d.ts +24 -0
  265. package/dist/screenshot-docs-seed.d.ts.map +1 -0
  266. package/dist/screenshot-docs-seed.js +414 -0
  267. package/dist/screenshot-docs-seed.js.map +1 -0
  268. package/dist/screenshot-projects.d.ts.map +1 -1
  269. package/dist/screenshot-projects.js +9 -9
  270. package/dist/screenshot-projects.js.map +1 -1
  271. package/dist/screenshot-server.js +114 -20
  272. package/dist/screenshot-server.js.map +1 -1
  273. package/dist/sdk/sdk-model-download-service.d.ts.map +1 -1
  274. package/dist/sdk/sdk-model-download-service.js +5 -2
  275. package/dist/sdk/sdk-model-download-service.js.map +1 -1
  276. package/dist/server.js +173 -109
  277. package/dist/server.js.map +1 -1
  278. package/dist/session/app-run-fold.d.ts +7 -0
  279. package/dist/session/app-run-fold.d.ts.map +1 -0
  280. package/dist/session/app-run-fold.js +45 -0
  281. package/dist/session/app-run-fold.js.map +1 -0
  282. package/dist/session/chat-prompt.d.ts.map +1 -1
  283. package/dist/session/chat-prompt.js +37 -15
  284. package/dist/session/chat-prompt.js.map +1 -1
  285. package/dist/session/chat-turn.d.ts +11 -0
  286. package/dist/session/chat-turn.d.ts.map +1 -1
  287. package/dist/session/chat-turn.js +270 -116
  288. package/dist/session/chat-turn.js.map +1 -1
  289. package/dist/session/commands.d.ts +14 -0
  290. package/dist/session/commands.d.ts.map +1 -1
  291. package/dist/session/commands.js +119 -14
  292. package/dist/session/commands.js.map +1 -1
  293. package/dist/session/inference.d.ts +30 -2
  294. package/dist/session/inference.d.ts.map +1 -1
  295. package/dist/session/inference.js +165 -16
  296. package/dist/session/inference.js.map +1 -1
  297. package/dist/session/job-execution.d.ts +7 -1
  298. package/dist/session/job-execution.d.ts.map +1 -1
  299. package/dist/session/job-execution.js +329 -42
  300. package/dist/session/job-execution.js.map +1 -1
  301. package/dist/session/model-interfaces.d.ts +2 -1
  302. package/dist/session/model-interfaces.d.ts.map +1 -1
  303. package/dist/session/model-interfaces.js +1 -0
  304. package/dist/session/model-interfaces.js.map +1 -1
  305. package/dist/storage-api.d.ts +0 -4
  306. package/dist/storage-api.d.ts.map +1 -1
  307. package/dist/storage-api.js +3 -26
  308. package/dist/storage-api.js.map +1 -1
  309. package/dist/storage-retention.d.ts +5 -0
  310. package/dist/storage-retention.d.ts.map +1 -1
  311. package/dist/storage-retention.js +22 -1
  312. package/dist/storage-retention.js.map +1 -1
  313. package/dist/test-ui-server.d.ts +11 -0
  314. package/dist/test-ui-server.d.ts.map +1 -1
  315. package/dist/test-ui-server.js +84 -6
  316. package/dist/test-ui-server.js.map +1 -1
  317. package/dist/timeline-generation-recovery.d.ts +4 -0
  318. package/dist/timeline-generation-recovery.d.ts.map +1 -0
  319. package/dist/timeline-generation-recovery.js +72 -0
  320. package/dist/timeline-generation-recovery.js.map +1 -0
  321. package/dist/triggers/dispatcher.d.ts.map +1 -1
  322. package/dist/triggers/dispatcher.js +26 -6
  323. package/dist/triggers/dispatcher.js.map +1 -1
  324. package/dist/triggers/file-watch.d.ts.map +1 -1
  325. package/dist/triggers/file-watch.js +35 -19
  326. package/dist/triggers/file-watch.js.map +1 -1
  327. package/dist/triggers/scheduler.d.ts.map +1 -1
  328. package/dist/triggers/scheduler.js +7 -5
  329. package/dist/triggers/scheduler.js.map +1 -1
  330. package/dist/triggers/stores.js +8 -8
  331. package/dist/triggers/stores.js.map +1 -1
  332. package/dist/triggers/webhook-route.js +2 -2
  333. package/dist/triggers/webhook-route.js.map +1 -1
  334. package/dist/trpc/error-formatter.d.ts.map +1 -1
  335. package/dist/trpc/error-formatter.js +2 -1
  336. package/dist/trpc/error-formatter.js.map +1 -1
  337. package/dist/trpc/error-logging.d.ts +10 -0
  338. package/dist/trpc/error-logging.d.ts.map +1 -1
  339. package/dist/trpc/error-logging.js +21 -0
  340. package/dist/trpc/error-logging.js.map +1 -1
  341. package/dist/trpc/router.d.ts +100 -31028
  342. package/dist/trpc/router.d.ts.map +1 -1
  343. package/dist/trpc/router.js +12 -3
  344. package/dist/trpc/router.js.map +1 -1
  345. package/dist/trpc/routers/app-instances.d.ts +2332 -0
  346. package/dist/trpc/routers/app-instances.d.ts.map +1 -0
  347. package/dist/trpc/routers/app-instances.js +52 -0
  348. package/dist/trpc/routers/app-instances.js.map +1 -0
  349. package/dist/trpc/routers/app-runs.d.ts +1120 -0
  350. package/dist/trpc/routers/app-runs.d.ts.map +1 -0
  351. package/dist/trpc/routers/app-runs.js +28 -0
  352. package/dist/trpc/routers/app-runs.js.map +1 -0
  353. package/dist/trpc/routers/applications.d.ts +1102 -0
  354. package/dist/trpc/routers/applications.d.ts.map +1 -1
  355. package/dist/trpc/routers/applications.js +5 -2
  356. package/dist/trpc/routers/applications.js.map +1 -1
  357. package/dist/trpc/routers/assets.d.ts +18 -0
  358. package/dist/trpc/routers/assets.d.ts.map +1 -1
  359. package/dist/trpc/routers/assets.js +20 -5
  360. package/dist/trpc/routers/assets.js.map +1 -1
  361. package/dist/trpc/routers/bug-reports.d.ts +33 -0
  362. package/dist/trpc/routers/bug-reports.d.ts.map +1 -0
  363. package/dist/trpc/routers/bug-reports.js +69 -0
  364. package/dist/trpc/routers/bug-reports.js.map +1 -0
  365. package/dist/trpc/routers/collections.d.ts.map +1 -1
  366. package/dist/trpc/routers/collections.js +16 -10
  367. package/dist/trpc/routers/collections.js.map +1 -1
  368. package/dist/trpc/routers/credits.d.ts.map +1 -1
  369. package/dist/trpc/routers/credits.js +11 -1
  370. package/dist/trpc/routers/credits.js.map +1 -1
  371. package/dist/trpc/routers/documents.d.ts.map +1 -1
  372. package/dist/trpc/routers/documents.js +8 -2
  373. package/dist/trpc/routers/documents.js.map +1 -1
  374. package/dist/trpc/routers/error-traces.d.ts +132 -0
  375. package/dist/trpc/routers/error-traces.d.ts.map +1 -0
  376. package/dist/trpc/routers/error-traces.js +118 -0
  377. package/dist/trpc/routers/error-traces.js.map +1 -0
  378. package/dist/trpc/routers/extension.d.ts +3 -3
  379. package/dist/trpc/routers/extension.d.ts.map +1 -1
  380. package/dist/trpc/routers/extension.js +13 -9
  381. package/dist/trpc/routers/extension.js.map +1 -1
  382. package/dist/trpc/routers/gameDraftHistory.d.ts +7 -0
  383. package/dist/trpc/routers/gameDraftHistory.d.ts.map +1 -0
  384. package/dist/trpc/routers/gameDraftHistory.js +40 -0
  385. package/dist/trpc/routers/gameDraftHistory.js.map +1 -0
  386. package/dist/trpc/routers/games.d.ts +59974 -5414
  387. package/dist/trpc/routers/games.d.ts.map +1 -1
  388. package/dist/trpc/routers/games.js +531 -136
  389. package/dist/trpc/routers/games.js.map +1 -1
  390. package/dist/trpc/routers/jobs.d.ts +42 -0
  391. package/dist/trpc/routers/jobs.d.ts.map +1 -1
  392. package/dist/trpc/routers/jobs.js +89 -4
  393. package/dist/trpc/routers/jobs.js.map +1 -1
  394. package/dist/trpc/routers/js-scripts.d.ts.map +1 -1
  395. package/dist/trpc/routers/js-scripts.js +18 -2
  396. package/dist/trpc/routers/js-scripts.js.map +1 -1
  397. package/dist/trpc/routers/mcp-config.d.ts +3 -1
  398. package/dist/trpc/routers/mcp-config.d.ts.map +1 -1
  399. package/dist/trpc/routers/mcp-config.js +46 -208
  400. package/dist/trpc/routers/mcp-config.js.map +1 -1
  401. package/dist/trpc/routers/messages.d.ts +10 -0
  402. package/dist/trpc/routers/messages.d.ts.map +1 -1
  403. package/dist/trpc/routers/messages.js +16 -2
  404. package/dist/trpc/routers/messages.js.map +1 -1
  405. package/dist/trpc/routers/models.d.ts +130 -0
  406. package/dist/trpc/routers/models.d.ts.map +1 -1
  407. package/dist/trpc/routers/models.js +119 -61
  408. package/dist/trpc/routers/models.js.map +1 -1
  409. package/dist/trpc/routers/packs.d.ts.map +1 -1
  410. package/dist/trpc/routers/packs.js +18 -4
  411. package/dist/trpc/routers/packs.js.map +1 -1
  412. package/dist/trpc/routers/projects.d.ts +66 -2
  413. package/dist/trpc/routers/projects.d.ts.map +1 -1
  414. package/dist/trpc/routers/projects.js +19 -2
  415. package/dist/trpc/routers/projects.js.map +1 -1
  416. package/dist/trpc/routers/runs.d.ts +472 -0
  417. package/dist/trpc/routers/runs.d.ts.map +1 -0
  418. package/dist/trpc/routers/runs.js +40 -0
  419. package/dist/trpc/routers/runs.js.map +1 -0
  420. package/dist/trpc/routers/settings.d.ts +3 -0
  421. package/dist/trpc/routers/settings.d.ts.map +1 -1
  422. package/dist/trpc/routers/settings.js +32 -5
  423. package/dist/trpc/routers/settings.js.map +1 -1
  424. package/dist/trpc/routers/sketch.d.ts +44 -0
  425. package/dist/trpc/routers/sketch.d.ts.map +1 -1
  426. package/dist/trpc/routers/sketch.js +2 -2
  427. package/dist/trpc/routers/sketch.js.map +1 -1
  428. package/dist/trpc/routers/storyboards.d.ts +903 -1
  429. package/dist/trpc/routers/storyboards.d.ts.map +1 -1
  430. package/dist/trpc/routers/storyboards.js +8 -5
  431. package/dist/trpc/routers/storyboards.js.map +1 -1
  432. package/dist/trpc/routers/threads.d.ts.map +1 -1
  433. package/dist/trpc/routers/threads.js +8 -2
  434. package/dist/trpc/routers/threads.js.map +1 -1
  435. package/dist/trpc/routers/timeline.d.ts +647 -63
  436. package/dist/trpc/routers/timeline.d.ts.map +1 -1
  437. package/dist/trpc/routers/timeline.js +193 -4
  438. package/dist/trpc/routers/timeline.js.map +1 -1
  439. package/dist/trpc/routers/triggers.d.ts.map +1 -1
  440. package/dist/trpc/routers/triggers.js +18 -3
  441. package/dist/trpc/routers/triggers.js.map +1 -1
  442. package/dist/trpc/routers/users.d.ts +3 -2
  443. package/dist/trpc/routers/users.d.ts.map +1 -1
  444. package/dist/trpc/routers/users.js +25 -27
  445. package/dist/trpc/routers/users.js.map +1 -1
  446. package/dist/trpc/routers/worker.d.ts +10 -9
  447. package/dist/trpc/routers/worker.d.ts.map +1 -1
  448. package/dist/trpc/routers/worker.js +40 -16
  449. package/dist/trpc/routers/worker.js.map +1 -1
  450. package/dist/trpc/routers/workflows.d.ts +202 -3
  451. package/dist/trpc/routers/workflows.d.ts.map +1 -1
  452. package/dist/trpc/routers/workflows.js +72 -12
  453. package/dist/trpc/routers/workflows.js.map +1 -1
  454. package/dist/trpc/sandbox-coverage.d.ts.map +1 -1
  455. package/dist/trpc/sandbox-coverage.js +119 -0
  456. package/dist/trpc/sandbox-coverage.js.map +1 -1
  457. package/dist/websocket-client-session.d.ts +4 -2
  458. package/dist/websocket-client-session.d.ts.map +1 -1
  459. package/dist/websocket-client-session.js +23 -3
  460. package/dist/websocket-client-session.js.map +1 -1
  461. package/dist/worker-settings-env.d.ts +23 -0
  462. package/dist/worker-settings-env.d.ts.map +1 -0
  463. package/dist/worker-settings-env.js +47 -0
  464. package/dist/worker-settings-env.js.map +1 -0
  465. package/dist/workflow-interface-service.d.ts +7 -0
  466. package/dist/workflow-interface-service.d.ts.map +1 -1
  467. package/package.json +58 -41
  468. package/dist/extension-cdp-bridge.d.ts +0 -85
  469. package/dist/extension-cdp-bridge.d.ts.map +0 -1
  470. package/dist/extension-cdp-bridge.js +0 -163
  471. package/dist/extension-cdp-bridge.js.map +0 -1
@@ -1,7 +1,14 @@
1
+ import { registerChatRunTrace, registerWorkflowRunTrace, withRegisteredRunTrace, settleRegisteredRunTrace } from "@nodetool-ai/execution";
2
+ import { getRunTraceScope, suppressRunTraceContent } from "@nodetool-ai/runtime";
3
+ import { TRACE_RESTRICTED_CAPABILITY_MODULES, isFullResourceId } from "@nodetool-ai/protocol";
4
+ import { trace, SpanStatusCode } from "@opentelemetry/api";
5
+ import { settleRunTrace, registerRunTraceParent, registerRunTraceParents, threadHasTraceContentTools } from "@nodetool-ai/models";
6
+ import { capabilityModuleOf, listCapabilitySpecs } from "@nodetool-ai/agents";
1
7
  import { createLogger } from "@nodetool-ai/config";
2
8
  import { randomUUID } from "node:crypto";
3
9
  import { SUPERSEDED_TOOL_RESULT, repairOrphanedToolCalls } from "../chat-tool-call-repair.js";
4
10
  import { attachChatPredictionForwarder } from "../chat-prediction-forwarder.js";
11
+ import { admitSpend } from "../credit-gate.js";
5
12
  import { isGoogleWorkspaceEnabled } from "@nodetool-ai/config";
6
13
  import { isFunctionValue, isNonEmptyString, isNumber, isObjectLike, isRecord, isString } from "../lib/wire-values.js";
7
14
  import { storeAssetWithThumbnail } from "../lib/thumbnail.js";
@@ -13,7 +20,7 @@ import { ACTIVE_MODEL_CONTEXT_KEY, DIRECT_TOOL_NAMES, RUN_BUDGET_CONTEXT_KEY, cr
13
20
  import { isModelSelection, PROVIDER_IDS, NO_MODEL_SELECTED_MESSAGE, noMediaModelSelectedMessage } from "@nodetool-ai/protocol";
14
21
  import { Tool, compactAssetUris, compactResourceIds } from "@nodetool-ai/agents";
15
22
  import { createChatCodeActSession, createSandboxClock, sandboxPackagesForChat, CODEACT_RESIDENT_TOOL_NAMES, EXECUTE_CODE_TOOL_NAME } from "@nodetool-ai/agents";
16
- import { getBuiltinTools, getAllMcpTools, getGoogleWorkspaceTools, getApifyTools, getSerpApiTools, toolForCapabilityName, gateTools, capabilityFromTool, createCapabilityRun, contextSecretAvailability, BackgroundSubtaskRegistry, UNGATED, PERMISSION_GATE_CONTEXT_KEY, GAME_ASSET_NODE_RUNNER_CONTEXT_KEY, extractInjectableImages, registerTemporaryImageHandle } from "@nodetool-ai/agents";
23
+ import { availableBuiltinToolNames, GOOGLE_WORKSPACE_TOOL_NAMES, APIFY_TOOL_NAMES, SERPAPI_TOOL_NAMES, capabilityForName, capabilityProviderTool, getAllMcpCapabilitySpecs, toolFromCapability, capabilityFromTool, createCapabilityRun, contextSecretAvailability, BackgroundSubtaskRegistry, PERMISSION_GATE_CONTEXT_KEY, GAME_ASSET_NODE_RUNNER_CONTEXT_KEY, extractInjectableImages, registerTemporaryImageHandle } from "@nodetool-ai/agents";
17
24
  import { mcpToolHostDeps } from "../mcp-tool-deps.js";
18
25
  import { externalMcpToolsFor } from "../external-mcp.js";
19
26
  import { formatSkillCatalogForPrompt, mergeSystemSkills, formatMemoriesForPrompt } from "@nodetool-ai/agents";
@@ -25,7 +32,41 @@ import { getSetting } from "../settings-registry.js";
25
32
  import { appendContextToLastUser, createWorkflowResponseContent, dbMessageToProviderMessage, extractTextContent, historySinceCompaction, invokedSkillsSection, toolResultDisplayText } from "./chat-history.js";
26
33
  import { chooseCompactionCut, compactionThreshold, COMPACTION_SUMMARY_MAX_TOKENS, holdsTranscriptServerSide, readCompactionSettings, summarizeForCompaction } from "./chat-compaction.js";
27
34
  import { createRelayActivityWaiter, DEFAULT_RUN_JOB_EXECUTION_OPTIONS } from "./job-execution.js";
35
+ function restrictedTraceToolNames() {
36
+ const modules = new Set(TRACE_RESTRICTED_CAPABILITY_MODULES);
37
+ return listCapabilitySpecs().filter((spec) => modules.has(capabilityModuleOf(spec.name) ?? "")).map((spec) => spec.name);
38
+ }
39
+ function seedStoredToolProvenance(messages) {
40
+ for (const message of messages) {
41
+ const names = message.name ? [message.name] : [];
42
+ if (isCompactionMessage(message)) {
43
+ names.push(...(message.tools ?? []));
44
+ }
45
+ for (const call of message.tool_calls ?? []) {
46
+ if (!isRecord(call)) {
47
+ continue;
48
+ }
49
+ if (isString(call.name)) {
50
+ names.push(call.name);
51
+ }
52
+ if (isRecord(call.function) && isString(call.function.name)) {
53
+ names.push(call.function.name);
54
+ }
55
+ }
56
+ for (const name of names) {
57
+ const moduleName = capabilityModuleOf(name);
58
+ if (moduleName === "email" || moduleName === "google" || moduleName === "browser") {
59
+ suppressRunTraceContent();
60
+ }
61
+ }
62
+ }
63
+ }
28
64
  const log = createLogger("nodetool.websocket.runner");
65
+ /** Providers whose credential is an account sign-in, not an API key. */
66
+ const SIGN_IN_PROVIDER_LABELS = {
67
+ [PROVIDER_IDS.CODEX]: "Codex",
68
+ [PROVIDER_IDS.CLAUDE_AGENT_SDK]: "Claude"
69
+ };
29
70
  const GENERIC_CHAT_ERROR = "Something went wrong while processing your request. Please try again.";
30
71
  /**
31
72
  * Keep implementation details out of the client error envelope. Provider
@@ -105,24 +146,20 @@ function providerFailureMessage(error, providerId, model) {
105
146
  const gemini = geminiFailureSummary(error, providerId);
106
147
  const groq = groqRequestFailureMessage(error);
107
148
  const status = httpStatusFromError(error) ?? gemini?.status ?? null;
149
+ const statusCode = status ?? undefined;
108
150
  const rawMessage = groq ?? gemini?.message ?? safeClientErrorText(error);
109
- let bodyMessage = null;
110
- if (isObjectLike(error)) {
111
- const body = error.body ?? error.response;
112
- if (isObjectLike(body)) {
113
- const bodyError = isObjectLike(body.error) ? body.error : body;
114
- if (isObjectLike(bodyError) && isString(bodyError.message)) {
115
- const safe = safeClientErrorText(bodyError.message);
116
- bodyMessage = safe === GENERIC_CHAT_ERROR ? null : safe;
117
- }
118
- }
119
- }
151
+ const body = isObjectLike(error) ? (error.body ?? error.response) : undefined;
152
+ const bodyError = isObjectLike(body) && isObjectLike(body.error) ? body.error : body;
153
+ const bodyText = isObjectLike(bodyError) && isString(bodyError.message)
154
+ ? safeClientErrorText(bodyError.message)
155
+ : null;
156
+ const bodyMessage = bodyText === GENERIC_CHAT_ERROR ? null : bodyText;
120
157
  if (providerId.toLowerCase() === "openai" &&
121
158
  /\borganization must be verified\b/i.test(bodyMessage ?? rawMessage)) {
122
159
  return {
123
160
  errorType: status === null ? "error" : "http_status_error",
124
161
  message: "This model requires a verified OpenAI organization. Verify your provider organization or choose a model your account can access.",
125
- statusCode: status ?? undefined
162
+ statusCode
126
163
  };
127
164
  }
128
165
  const detail = providerFailureDetail(error);
@@ -131,28 +168,31 @@ function providerFailureMessage(error, providerId, model) {
131
168
  return {
132
169
  errorType: "error",
133
170
  message: `The ${target} request is too large for the model context window. Shorten the conversation or remove some attachments and try again.`,
134
- statusCode: status ?? undefined
171
+ statusCode
135
172
  };
136
173
  }
137
174
  if (detail?.code === "provider_auth") {
175
+ const signIn = SIGN_IN_PROVIDER_LABELS[detail.provider];
176
+ const remedy = signIn ? `Sign in to ${signIn} again` : "Check the API key";
138
177
  return {
139
178
  errorType: "error",
140
- message: `Authentication failed: ${detail.provider} rejected the configured credentials. Check the API key in Settings → Models & Providers.`,
141
- statusCode: status ?? undefined
179
+ message: `Authentication failed: ${detail.provider} rejected the configured credentials. ${remedy} in Settings → Models & Providers.`,
180
+ statusCode
142
181
  };
143
182
  }
144
183
  if (status === null) {
145
- return { errorType: "error", message: rawMessage, statusCode: undefined };
184
+ return { errorType: "error", message: rawMessage, statusCode };
146
185
  }
147
- let message = rawMessage;
186
+ const modelName = model || "requested";
187
+ let message;
148
188
  if (gemini?.kind === "quota") {
149
189
  message = `Account quota exhausted for ${providerId}/${model}. Check your ${providerId} quota or billing and try again later.`;
150
190
  }
151
191
  else if (gemini?.kind === "model") {
152
- message = `Model ${model || "requested"} is unavailable on ${providerId}. Choose another model or check that your account has access to it.`;
192
+ message = `Model ${modelName} is unavailable on ${providerId}. Choose another model or check that your account has access to it.`;
153
193
  }
154
194
  else if (gemini?.kind === "tools") {
155
- message = `Model ${model || "requested"} does not support the requested tools on ${providerId}. Choose a model with tool support or disable tools.`;
195
+ message = `Model ${modelName} does not support the requested tools on ${providerId}. Choose a model with tool support or disable tools.`;
156
196
  }
157
197
  else if (status === 400) {
158
198
  message = `Bad request: ${groq ?? bodyMessage ?? rawMessage}`;
@@ -168,20 +208,20 @@ function providerFailureMessage(error, providerId, model) {
168
208
  "Access forbidden: You don't have permission for this resource. Check the provider key's model and account access.";
169
209
  }
170
210
  else if (status === 404) {
171
- message = `Model ${model || "requested"} was not found or is unavailable on ${providerId}. Choose another model or check account access.`;
211
+ message = `Model ${modelName} was not found or is unavailable on ${providerId}. Choose another model or check account access.`;
172
212
  }
173
213
  else if (status === 413) {
174
- const detail = groq ?? bodyMessage ?? rawMessage;
214
+ const bodyDetail = bodyMessage ?? rawMessage;
175
215
  message =
176
216
  groq ??
177
- (detail === GENERIC_CHAT_ERROR
217
+ (bodyDetail === GENERIC_CHAT_ERROR
178
218
  ? "Request is too large for the provider. Shorten the conversation or remove some attachments and try again."
179
- : `Request is too large for the provider (${detail}). Shorten the conversation or remove some attachments and try again.`);
219
+ : `Request is too large for the provider (${bodyDetail}). Shorten the conversation or remove some attachments and try again.`);
180
220
  }
181
221
  else if (status === 429) {
182
- message = groq
183
- ? groq
184
- : "Rate limited: Too many requests or insufficient provider quota. Check your provider plan and try again later.";
222
+ message =
223
+ groq ??
224
+ "Rate limited: Too many requests or insufficient provider quota. Check your provider plan and try again later.";
185
225
  }
186
226
  else if (status >= 500) {
187
227
  message =
@@ -192,7 +232,7 @@ function providerFailureMessage(error, providerId, model) {
192
232
  else {
193
233
  message = `HTTP error (${status}): ${rawMessage}`;
194
234
  }
195
- return { errorType: "http_status_error", message, statusCode: status };
235
+ return { errorType: "http_status_error", message, statusCode };
196
236
  }
197
237
  /**
198
238
  * How many of a user's newest memories the turn reads to build its block. The
@@ -209,6 +249,27 @@ const MEMORY_BLOCK_LIMIT = 100;
209
249
  * full thread load.
210
250
  */
211
251
  const SESSION_PROBE_WINDOW = 50;
252
+ /** The most rows of a thread a turn loads as its history. */
253
+ const THREAD_HISTORY_LIMIT = 1000;
254
+ /**
255
+ * The thread's newest rows, oldest first. An ascending page would return the
256
+ * oldest rows instead, and a thread past the limit would then lose its latest
257
+ * turns, the user message just sent among them.
258
+ *
259
+ * A window cut by the limit starts at its first user row, so it never opens on
260
+ * a tool result whose call fell outside it.
261
+ */
262
+ export async function loadRecentThreadRows(threadId, limit = THREAD_HISTORY_LIMIT) {
263
+ const [newestFirst] = await Message.paginate(threadId, {
264
+ reverse: true,
265
+ limit
266
+ });
267
+ const rows = newestFirst.reverse();
268
+ if (rows.length < limit)
269
+ return rows;
270
+ const firstUser = rows.findIndex((row) => row.role === "user");
271
+ return firstUser > 0 ? rows.slice(firstUser) : rows;
272
+ }
212
273
  /**
213
274
  * Output-token worst case assumed when reserving a chat turn. The chat loop
214
275
  * sends no `maxTokens`, so nothing bounds the answer from this side; the
@@ -466,6 +527,12 @@ export class ChatTurnHandler {
466
527
  const existing = await Thread.find(userId, threadId);
467
528
  if (existing)
468
529
  return existing.id;
530
+ // `create` upserts on the primary key, so creating under an id another
531
+ // user's thread already holds would reassign that thread (and its
532
+ // history) to this caller.
533
+ if (await Thread.get(threadId)) {
534
+ throw new Error("Thread not found");
535
+ }
469
536
  const thread = await Thread.create({
470
537
  id: threadId,
471
538
  user_id: userId,
@@ -479,19 +546,30 @@ export class ChatTurnHandler {
479
546
  * Save a message dict to the database.
480
547
  * Mirrors Python's _save_message_to_db_async: pops id, type, user_id before create.
481
548
  */
482
- async saveMessageToDb(messageData) {
549
+ async saveMessageToDb(messageData, options = {}) {
483
550
  const data = { ...messageData };
551
+ const clientId = data.id;
484
552
  delete data.id;
485
553
  delete data.type;
486
554
  const threadId = isString(data.thread_id) ? data.thread_id : "";
487
555
  delete data.thread_id;
488
556
  const userId = this.session.requireUserId();
489
557
  delete data.user_id;
490
- return Message.create({
491
- thread_id: threadId,
492
- user_id: userId,
493
- ...data
494
- });
558
+ // The user's own turn keeps the id the client minted for it, so the client
559
+ // can name that turn later (Regenerate, edit a sent message) without a
560
+ // round-trip. Anything that is not a fresh 32-hex id is replaced.
561
+ if (options.keepClientId &&
562
+ isString(clientId) &&
563
+ isFullResourceId(clientId) &&
564
+ !(await Message.find(clientId))) {
565
+ data.id = clientId;
566
+ }
567
+ const message = await Message.create({ thread_id: threadId, user_id: userId, ...data });
568
+ const scope = getRunTraceScope();
569
+ if (scope) {
570
+ await registerRunTraceParent(userId, scope.runId, { kind: "message", id: message.id });
571
+ }
572
+ return message;
495
573
  }
496
574
  /**
497
575
  * Persist raw image bytes carried on an assistant message (native providers
@@ -923,6 +1001,7 @@ export class ChatTurnHandler {
923
1001
  : null,
924
1002
  assetOutputMode: this.session.mode === "text" ? "data_uri" : "temp_url"
925
1003
  });
1004
+ context.runTraceContext = getRunTraceScope() ?? null;
926
1005
  // This context is built here rather than copied from the turn, so the
927
1006
  // turn's gate has to be put on it by hand. The node's own loops read it
928
1007
  // with `gateFromContext`; a node run outside a chat turn carries none and
@@ -1042,10 +1121,33 @@ export class ChatTurnHandler {
1042
1121
  const userId = this.session.requireUserId();
1043
1122
  log.debug("Chat message", { threadId, model, provider: providerId });
1044
1123
  // Save user message to DB — matches Python's _save_message_to_db_async(data)
1045
- const turnMessage = await this.saveMessageToDb(data);
1124
+ const turnMessage = await this.saveMessageToDb(data, { keepClientId: true });
1125
+ const rootContext = createRuntimeContext({ jobId: turnMessage.id, threadId, workflowId, userId, workspace: null });
1126
+ await registerChatRunTrace(rootContext, { messageId: turnMessage.id, threadId });
1127
+ return withRegisteredRunTrace(rootContext, "chat.turn", async () => {
1128
+ try {
1129
+ if (await threadHasTraceContentTools(userId, threadId, restrictedTraceToolNames())) {
1130
+ suppressRunTraceContent();
1131
+ }
1132
+ await this.handlePersistedChatTurn(data, turnMessage, rootContext, requestSeq, signal);
1133
+ await settleRegisteredRunTrace(rootContext, signal?.aborted ? "cancelled" : "completed");
1134
+ }
1135
+ catch (error) {
1136
+ await settleRegisteredRunTrace(rootContext, signal?.aborted ? "cancelled" : "failed", error instanceof Error ? error.message : String(error));
1137
+ throw error;
1138
+ }
1139
+ });
1140
+ }
1141
+ async handlePersistedChatTurn(data, turnMessage, rootContext, requestSeq, signal) {
1142
+ const threadId = String(data.thread_id);
1143
+ const workflowId = isString(data.workflow_id) ? data.workflow_id : null;
1144
+ const userId = this.session.requireUserId();
1145
+ const providerId = String(data.provider);
1146
+ const model = String(data.model);
1046
1147
  if (requestSeq !== undefined && requestSeq !== this.chatRequestSeq)
1047
1148
  return;
1048
1149
  if (!this.session.resolveProvider) {
1150
+ await settleRegisteredRunTrace(rootContext, "failed", "No provider resolver configured");
1049
1151
  await this.session.send({
1050
1152
  type: "error",
1051
1153
  message: "No provider resolver configured",
@@ -1053,6 +1155,21 @@ export class ChatTurnHandler {
1053
1155
  });
1054
1156
  return;
1055
1157
  }
1158
+ // The managed provider spends NodeTool's own keys against the user's
1159
+ // credits. Every other managed entry point admits against the balance and
1160
+ // the operator's model whitelist first, and so does a chat turn.
1161
+ if (providerId === "nodetool") {
1162
+ const decision = await admitSpend(userId, 0, [model]);
1163
+ if (!decision.allowed) {
1164
+ await settleRegisteredRunTrace(rootContext, "failed", decision.reason);
1165
+ await this.session.send({
1166
+ type: "error",
1167
+ message: decision.reason,
1168
+ thread_id: threadId
1169
+ });
1170
+ return;
1171
+ }
1172
+ }
1056
1173
  // Route to the workflow processor ONLY when the client explicitly opts in
1057
1174
  // via `workflow_target: "workflow"`. A bare `workflow_id` is context, not a
1058
1175
  // routing signal: the editor binds the open workflow so `ui_*` tools target
@@ -1063,7 +1180,7 @@ export class ChatTurnHandler {
1063
1180
  ? data.workflow_target
1064
1181
  : null;
1065
1182
  if (workflowTarget === "workflow") {
1066
- await this.handleWorkflowMessage(data, requestSeq, signal);
1183
+ await this.handleWorkflowMessage(data, turnMessage.id, requestSeq, signal);
1067
1184
  return;
1068
1185
  }
1069
1186
  // Route to media generation when the client requests a text-to-image or
@@ -1134,9 +1251,12 @@ export class ChatTurnHandler {
1134
1251
  toolCalls: null,
1135
1252
  threadId: null
1136
1253
  });
1254
+ const copiedMessageIds = new Set();
1137
1255
  const convertDbMessages = (rows) => {
1138
1256
  const out = [];
1139
1257
  for (const m of rows) {
1258
+ copiedMessageIds.add(m.id);
1259
+ seedStoredToolProvenance([m]);
1140
1260
  const pm = dbMessageToProviderMessage(m, this.session.userId);
1141
1261
  if (pm)
1142
1262
  out.push(pm);
@@ -1160,6 +1280,7 @@ export class ChatTurnHandler {
1160
1280
  reverse: true,
1161
1281
  limit: SESSION_PROBE_WINDOW
1162
1282
  });
1283
+ seedStoredToolProvenance(recent);
1163
1284
  const probeHasWholeThread = recent.length < SESSION_PROBE_WINDOW;
1164
1285
  // `recent` is newest-first. Walk to the first boundary marker: an
1165
1286
  // assistant carrying a session token, or a compaction record. Both claim
@@ -1209,14 +1330,21 @@ export class ChatTurnHandler {
1209
1330
  systemHash: probeSession.systemHash,
1210
1331
  checkpoint: 1
1211
1332
  };
1333
+ if (probeSession.traceContentSuppressed) {
1334
+ priorSession.traceContentSuppressed = true;
1335
+ }
1212
1336
  // Absolute position to persist: prior prefix + the prior assistant + the
1213
1337
  // new turns — identical to what the full-load path would store.
1214
1338
  sessionCheckpointOverride =
1215
1339
  probeSession.checkpoint + 1 + newTurns.length;
1216
1340
  loadFullHistory = async () => {
1217
- const [rows] = await Message.paginate(threadId, { limit: 1000 });
1341
+ const rows = await loadRecentThreadRows(threadId);
1218
1342
  const full = convertDbMessages(historySinceCompaction(rows));
1219
1343
  full.unshift(systemChatMessage());
1344
+ const scope = getRunTraceScope();
1345
+ if (scope) {
1346
+ await registerRunTraceParents(userId, scope.runId, [...copiedMessageIds].map((id) => ({ kind: "message", id })));
1347
+ }
1220
1348
  return full;
1221
1349
  };
1222
1350
  }
@@ -1231,12 +1359,15 @@ export class ChatTurnHandler {
1231
1359
  // all (a far-back session still resumes via the slice path). A session
1232
1360
  // older than the compaction cut is not one of them: searching only the
1233
1361
  // compacted slice is what keeps the newest marker winning here too.
1234
- const [rows] = await Message.paginate(threadId, { limit: 1000 });
1362
+ const rows = await loadRecentThreadRows(threadId);
1235
1363
  const kept = historySinceCompaction(rows);
1236
1364
  chatHistory = convertDbMessages(kept);
1237
1365
  priorSession = lastMatchingProviderSession(kept, providerId, model);
1238
1366
  }
1239
1367
  }
1368
+ if (priorSession?.traceContentSuppressed) {
1369
+ suppressRunTraceContent();
1370
+ }
1240
1371
  // Expose the read-only `run_search` fan-out primitive by default. A client
1241
1372
  // can opt out by sending `enable_read_only_search: false`.
1242
1373
  const enableReadOnlySearch = data.enable_read_only_search !== false;
@@ -1286,13 +1417,6 @@ export class ChatTurnHandler {
1286
1417
  // it starts (invariant I-2). A loop that made its own would hand every
1287
1418
  // nested agent a fresh allowance, which is no ceiling at all.
1288
1419
  const turnBudget = await createChatTurnBudget();
1289
- const gatedRun = (context) => createCapabilityRun({
1290
- context,
1291
- gate: chatGate,
1292
- projectId: chatProjectId,
1293
- availableSecrets: contextSecretAvailability(context),
1294
- budget: turnBudget
1295
- });
1296
1420
  // The user's external MCP servers (Blender, Hugging Face, …). Their tools
1297
1421
  // are plain belt tools named `mcp_<server>_<tool>`, so every loop reaches
1298
1422
  // them the same way; a server that does not answer is skipped, not fatal.
@@ -1305,40 +1429,48 @@ export class ChatTurnHandler {
1305
1429
  error: err instanceof Error ? err.message : String(err)
1306
1430
  });
1307
1431
  }
1308
- const rawToolbelt = [
1309
- ...getBuiltinTools(),
1310
- ...(googleWorkspace ? getGoogleWorkspaceTools() : []),
1311
- // Apify and SerpAPI have no `nodetool.*` namespace, so the belt is how
1312
- // a chat discovers them (`nodetool.searchTools("apify")`) at all.
1313
- ...getApifyTools(gatedRun),
1314
- ...getSerpApiTools(gatedRun),
1315
- ...externalMcpTools,
1316
- ...getAllMcpTools({
1317
- registry: this.session.nodeRegistry,
1318
- providers: chatProviders,
1319
- ...mcpToolHostDeps()
1320
- }),
1321
- toolForCapabilityName("list_collections"),
1322
- toolForCapabilityName("query_collection"),
1323
- runNodeTool
1432
+ const legacyCapabilities = [runNodeTool, ...externalMcpTools].map(capabilityFromTool);
1433
+ const nativeSpecs = [
1434
+ ...availableBuiltinToolNames().map((name) => capabilityForName(name).spec),
1435
+ ...(googleWorkspace ? GOOGLE_WORKSPACE_TOOL_NAMES : []).map((name) => capabilityForName(name).spec),
1436
+ ...[...APIFY_TOOL_NAMES, ...SERPAPI_TOOL_NAMES].map((name) => capabilityForName(name).spec),
1437
+ ...getAllMcpCapabilitySpecs({ registry: this.session.nodeRegistry, providers: chatProviders }),
1438
+ capabilityForName("list_collections").spec,
1439
+ capabilityForName("query_collection").spec
1324
1440
  ];
1325
- // De-duplicate by name (builtins / mcp / extras may overlap); first wins.
1326
- const dedupedToolbelt = [];
1327
- const seenToolNames = new Set();
1328
- for (const tool of rawToolbelt) {
1329
- if (seenToolNames.has(tool.name))
1330
- continue;
1331
- seenToolNames.add(tool.name);
1332
- dedupedToolbelt.push(tool);
1333
- }
1334
- // Wrap the toolbelt in the permission gate. The wrapper is transparent
1335
- // except for `process()`, so the chat loop AND any `run_subtask` child
1336
- // loop inherit gating by simply calling `tool.process()`.
1337
- const baseTools = gateTools(dedupedToolbelt, chatGate);
1441
+ const specsByName = new Map();
1442
+ for (const spec of [...nativeSpecs, ...legacyCapabilities.map((entry) => entry.spec)]) {
1443
+ if (!specsByName.has(spec.name)) {
1444
+ specsByName.set(spec.name, spec);
1445
+ }
1446
+ }
1447
+ const baseSpecs = [...specsByName.values()];
1448
+ const legacyByName = new Map(legacyCapabilities.map((entry) => [entry.spec.name, entry]));
1449
+ // Delegated executors still consume Tool[]. Adapt only at that boundary.
1450
+ // Each child context owns a separate run so its memory and depth are local.
1451
+ const childRuns = new WeakMap();
1452
+ const childRun = (context) => {
1453
+ let run = childRuns.get(context);
1454
+ if (!run) {
1455
+ run = createCapabilityRun({
1456
+ context, gate: chatGate, nodeRegistry: this.session.nodeRegistry,
1457
+ providers: chatProviders, budget: turnBudget,
1458
+ availableSecrets: contextSecretAvailability(context),
1459
+ ...mcpToolHostDeps(), capabilities: legacyCapabilities
1460
+ });
1461
+ childRuns.set(context, run);
1462
+ }
1463
+ return run;
1464
+ };
1465
+ const baseTools = baseSpecs.map((spec) => {
1466
+ const entry = legacyByName.get(spec.name)
1467
+ ?? capabilityForName(spec.name);
1468
+ return toolFromCapability(entry.spec, entry.impl, childRun);
1469
+ });
1338
1470
  // Inject the recursive-decomposition primitive (ungated — it spawns a
1339
1471
  // child loop whose own tools are the gated `baseTools`). Child events
1340
1472
  // stream back tagged with `parent_tool_call_id` so the UI can nest cards.
1341
- const serverTools = baseTools.slice();
1473
+ const serverTools = baseSpecs.slice();
1342
1474
  // The same runtime the delegation tools take, kept for the capability run
1343
1475
  // below: provider, model, the parent belt, and the event forwarder.
1344
1476
  let subAgentRuntime;
@@ -1384,18 +1516,9 @@ export class ChatTurnHandler {
1384
1516
  // `parent_tool_call_id` / `subtask_depth` tagging are unchanged.
1385
1517
  // `start_subtask` / `wait_subtasks` share the per-turn registry above:
1386
1518
  // spawn returns immediately, and the parent collects on its own terms.
1387
- const delegationRun = (context) => createCapabilityRun({
1388
- context,
1389
- // Ungated on purpose, as before: spawning a child loop has no side
1390
- // effect of its own, and the child's tools are the gated `baseTools`.
1391
- gate: UNGATED,
1392
- availableSecrets: contextSecretAvailability(context),
1393
- subAgent: subAgentRuntime,
1394
- budget: turnBudget
1395
- });
1396
- serverTools.unshift(toolForCapabilityName("run_subtask", delegationRun));
1397
- serverTools.unshift(toolForCapabilityName("start_subtask", delegationRun));
1398
- serverTools.unshift(toolForCapabilityName("wait_subtasks", delegationRun));
1519
+ serverTools.unshift(capabilityForName("run_subtask").spec);
1520
+ serverTools.unshift(capabilityForName("start_subtask").spec);
1521
+ serverTools.unshift(capabilityForName("wait_subtasks").spec);
1399
1522
  // Plan mode's own capability: `create_plan` runs the TaskPlanner over the
1400
1523
  // objective and streams the plan into the thread, executing nothing. It
1401
1524
  // is offered only here, because plan mode is the one place where a plan
@@ -1404,7 +1527,7 @@ export class ChatTurnHandler {
1404
1527
  // mode the turn started in — `liveMode` covers a mid-turn switch for the
1405
1528
  // gate, not for which tools were offered.
1406
1529
  if (permissionMode === "plan") {
1407
- serverTools.unshift(toolForCapabilityName("create_plan", delegationRun));
1530
+ serverTools.unshift(capabilityForName("create_plan").spec);
1408
1531
  }
1409
1532
  // The other half: `execute_plan` runs a plan the user has already seen,
1410
1533
  // on the same ParallelTaskExecutor `Agent` uses. It is on the belt in
@@ -1412,12 +1535,12 @@ export class ChatTurnHandler {
1412
1535
  // `blocked_in_plan_mode`, which tells the model to have the user switch
1413
1536
  // out, where dropping it from the belt entirely would only say the tool
1414
1537
  // does not exist. It is *offered* everywhere but plan mode, below.
1415
- serverTools.unshift(...gateTools([toolForCapabilityName("execute_plan", delegationRun)], chatGate));
1538
+ serverTools.unshift(capabilityForName("execute_plan").spec);
1416
1539
  // Read-only fan-out search (opt-in). Reuses the same runtime — the
1417
1540
  // capability filters the parent belt to its read-only allowlist
1418
1541
  // internally, so passing the full snapshot is correct.
1419
1542
  if (enableReadOnlySearch) {
1420
- serverTools.unshift(toolForCapabilityName("run_search", delegationRun));
1543
+ serverTools.unshift(capabilityForName("run_search").spec);
1421
1544
  }
1422
1545
  }
1423
1546
  const serverToolMap = new Map(serverTools.map((t) => [t.name, t]));
@@ -1426,7 +1549,7 @@ export class ChatTurnHandler {
1426
1549
  permissionMode,
1427
1550
  resolved: serverTools.map((t) => t.name)
1428
1551
  });
1429
- const serverSchemas = serverTools.map((t) => t.toProviderTool());
1552
+ const serverSchemas = serverTools.map((t) => capabilityProviderTool(t));
1430
1553
  // Every client tool the connected UI registered is exposed. They used to be
1431
1554
  // gated on an active workflow, which made the editor tools unreachable from
1432
1555
  // plain chat; they are deferred behind `nodetool.searchTools()` anyway, and each one now
@@ -1484,7 +1607,11 @@ export class ChatTurnHandler {
1484
1607
  workspace: chatWorkspace,
1485
1608
  authToken: this.deps.authToken()
1486
1609
  });
1610
+ ctx.runTraceContext = rootContext.runTraceContext;
1487
1611
  ctx.set("chat_message_id", turnMessage.id);
1612
+ if (ctx.runTraceContext) {
1613
+ await registerRunTraceParents(userId, ctx.runTraceContext.runId, [...copiedMessageIds].map((id) => ({ kind: "message", id })));
1614
+ }
1488
1615
  const detachPredictions = attachChatPredictionForwarder((listener) => ctx.addMessageListener(listener), (msg) => this.session.sendDetached(msg), { threadId: threadId || null, workflowId });
1489
1616
  // A chat turn that generates an image or a video spends real money without
1490
1617
  // ever constructing an ExecutionSession, so the ledger is attached here
@@ -1530,7 +1657,7 @@ export class ChatTurnHandler {
1530
1657
  budget: turnBudget,
1531
1658
  secretPrompt: (request) => this.requestSecretEntry(threadId, request),
1532
1659
  ...mcpToolHostDeps(),
1533
- capabilities: [capabilityFromTool(runNodeTool)]
1660
+ capabilities: legacyCapabilities
1534
1661
  });
1535
1662
  const gameAssetRun = this.chatCapabilityRun;
1536
1663
  const gameAssetNodeRunner = (args) => gameAssetRun.invoke("run_node", args);
@@ -1632,9 +1759,20 @@ export class ChatTurnHandler {
1632
1759
  // What to persist onto the assistant message: the provider's token, but with
1633
1760
  // the absolute checkpoint when the fast path sent only a delta (the
1634
1761
  // provider's emitted checkpoint is relative to the trimmed view).
1635
- const sessionForPersist = () => sessionCheckpointOverride != null && capturedSession
1636
- ? { ...capturedSession, checkpoint: sessionCheckpointOverride }
1637
- : capturedSession;
1762
+ const sessionForPersist = () => {
1763
+ if (!capturedSession) {
1764
+ return null;
1765
+ }
1766
+ const contentSuppressed = getRunTraceScope()?.policy.contentSuppressed || priorSession?.traceContentSuppressed || capturedSession.traceContentSuppressed;
1767
+ const persisted = { ...capturedSession };
1768
+ if (sessionCheckpointOverride != null) {
1769
+ persisted.checkpoint = sessionCheckpointOverride;
1770
+ }
1771
+ if (contentSuppressed) {
1772
+ persisted.traceContentSuppressed = true;
1773
+ }
1774
+ return persisted;
1775
+ };
1638
1776
  // Cap on tool-calling rounds before the loop stops. Generous enough to
1639
1777
  // build a multi-component app UI or run a long edit session in one turn —
1640
1778
  // 10 was too low and cut off the app builder mid-build.
@@ -1715,9 +1853,14 @@ export class ChatTurnHandler {
1715
1853
  }
1716
1854
  else if (serverTool) {
1717
1855
  try {
1718
- toolResult = await Tool.executeTool(serverTool, ctx, toolCall.args, {
1719
- toolCallId: toolCall.id
1720
- });
1856
+ const args = { ...Tool.stripMessage(toolCall.args) };
1857
+ if (serverTool.needsToolCallId) {
1858
+ args["_tool_call_id"] = toolCall.id;
1859
+ }
1860
+ if (!this.chatCapabilityRun) {
1861
+ throw new Error("Chat capability run is unavailable");
1862
+ }
1863
+ toolResult = await this.chatCapabilityRun.invoke(serverTool.name, args);
1721
1864
  }
1722
1865
  catch (err) {
1723
1866
  const errMsg = err instanceof Error ? err.message : String(err);
@@ -1973,7 +2116,7 @@ export class ChatTurnHandler {
1973
2116
  * turn that cannot run at all.
1974
2117
  */
1975
2118
  const compactThread = async (reason) => {
1976
- const [rows] = await Message.paginate(threadId, { limit: 1000 });
2119
+ const rows = await loadRecentThreadRows(threadId);
1977
2120
  const cut = chooseCompactionCut(historySinceCompaction(rows), compaction.keepUserTurns, {
1978
2121
  // Leave room for the summary, turn context and subsequent replies.
1979
2122
  maxTokens: compactionThresholdTokens * 0.75 -
@@ -2020,6 +2163,7 @@ export class ChatTurnHandler {
2020
2163
  role: "user",
2021
2164
  execution_event_type: COMPACTION_EVENT_TYPE,
2022
2165
  content: compactionMessageContent(summary),
2166
+ tools: getRunTraceScope()?.policy.contentSuppressed ? restrictedTraceToolNames() : null,
2023
2167
  created_at: Number.isFinite(boundary)
2024
2168
  ? new Date(boundary - 1).toISOString()
2025
2169
  : cut.keep[0].created_at
@@ -2260,6 +2404,7 @@ export class ChatTurnHandler {
2260
2404
  return;
2261
2405
  }
2262
2406
  const errMsg = err instanceof Error ? err.message : String(err);
2407
+ await settleRegisteredRunTrace(rootContext, "failed", errMsg);
2263
2408
  log.error("Chat processing error", { threadId, error: errMsg });
2264
2409
  let errorType = "error";
2265
2410
  let statusCode;
@@ -3076,6 +3221,11 @@ export class ChatTurnHandler {
3076
3221
  if (cancelled())
3077
3222
  return;
3078
3223
  const errMsg = err instanceof Error ? err.message : String(err);
3224
+ const scope = getRunTraceScope();
3225
+ if (scope) {
3226
+ trace.getActiveSpan()?.setStatus({ code: SpanStatusCode.ERROR });
3227
+ await settleRunTrace(userId, scope.runId, { status: "failed", error: scope.policy.contentSuppressed ? "Execution failed" : errMsg, secretValues: scope.secretValues, contentSuppressed: scope.policy.contentSuppressed });
3228
+ }
3079
3229
  log.error("Media generation error", { threadId, mode, error: errMsg });
3080
3230
  const failure = providerFailureMessage(err, providerId, modelId);
3081
3231
  const failureMessage = `Generation failed: ${failure.message}`;
@@ -3117,7 +3267,7 @@ export class ChatTurnHandler {
3117
3267
  * 6. Collect output_update results
3118
3268
  * 7. Send response message with typed content, then the terminal chunk
3119
3269
  */
3120
- async handleWorkflowMessage(data, requestSeq, signal) {
3270
+ async handleWorkflowMessage(data, turnMessageId, requestSeq, signal) {
3121
3271
  const threadId = isString(data.thread_id) ? data.thread_id : "";
3122
3272
  const workflowId = isString(data.workflow_id) ? data.workflow_id : null;
3123
3273
  const providerId = isString(data.provider)
@@ -3159,7 +3309,12 @@ export class ChatTurnHandler {
3159
3309
  messagesName ??
3160
3310
  "messages";
3161
3311
  // Build chat history for params — matches Python
3162
- const [dbMessages] = await Message.paginate(threadId, { limit: 1000 });
3312
+ const dbMessages = await loadRecentThreadRows(threadId);
3313
+ const inheritedTrace = getRunTraceScope();
3314
+ seedStoredToolProvenance(dbMessages);
3315
+ if (inheritedTrace) {
3316
+ await registerRunTraceParents(userId, inheritedTrace.runId, dbMessages.map((m) => ({ kind: "message", id: m.id })));
3317
+ }
3163
3318
  const chatHistorySerialized = dbMessages.map((m) => ({
3164
3319
  role: m.role,
3165
3320
  content: m.content,
@@ -3178,7 +3333,12 @@ export class ChatTurnHandler {
3178
3333
  // Prepare params — matches Python's WorkflowMessageProcessor
3179
3334
  const params = {
3180
3335
  [messageInputName]: currentMessage,
3181
- [messagesInputName]: [...chatHistorySerialized, currentMessage]
3336
+ // The stored history already holds this turn's message; it is appended
3337
+ // once, as `currentMessage`.
3338
+ [messagesInputName]: [
3339
+ ...chatHistorySerialized.filter((_, i) => dbMessages[i].id !== turnMessageId),
3340
+ currentMessage
3341
+ ]
3182
3342
  };
3183
3343
  if (isObjectLike(data.params)) {
3184
3344
  Object.assign(params, data.params);
@@ -3207,6 +3367,7 @@ export class ChatTurnHandler {
3207
3367
  workspace,
3208
3368
  assetOutputMode: this.session.mode === "text" ? "data_uri" : "temp_url"
3209
3369
  });
3370
+ context.runTraceContext = getRunTraceScope() ?? null;
3210
3371
  // Expose executor/node-type resolution for sub-workflow nodes
3211
3372
  context.setResolveExecutor((node) => this.session.resolveExecutor(node));
3212
3373
  if (this.session.resolveNodeType) {
@@ -3215,6 +3376,8 @@ export class ChatTurnHandler {
3215
3376
  : this.session.resolveNodeType;
3216
3377
  context.setResolveNodeType((nodeType) => resolverObj.resolveNodeType(nodeType));
3217
3378
  }
3379
+ await Job.create({ id: jobId, workflow_id: workflowId, user_id: userId, status: "running", params, graph });
3380
+ await registerWorkflowRunTrace(context, { jobId, workflowId });
3218
3381
  // Create and run workflow (A5: via the ExecutionSession facade — see
3219
3382
  // the identical note in `startJobInner`).
3220
3383
  const session = await ExecutionSession.create({
@@ -3249,20 +3412,6 @@ export class ChatTurnHandler {
3249
3412
  }
3250
3413
  };
3251
3414
  this.deps.jobs.registerJob(jobId, active);
3252
- // Persist job to DB (best-effort)
3253
- try {
3254
- await Job.create({
3255
- id: jobId,
3256
- workflow_id: workflowId,
3257
- user_id: userId,
3258
- status: "running",
3259
- params,
3260
- graph
3261
- });
3262
- }
3263
- catch (error) {
3264
- this.session.logError("workflow job persistence failed", error);
3265
- }
3266
3415
  // The run already started inside `ExecutionSession.create()` above.
3267
3416
  const executePromise = session.result;
3268
3417
  // Stream events, collect output_update results
@@ -3441,6 +3590,11 @@ export class ChatTurnHandler {
3441
3590
  }
3442
3591
  catch (err) {
3443
3592
  const errMsg = err instanceof Error ? err.message : String(err);
3593
+ const scope = getRunTraceScope();
3594
+ if (scope) {
3595
+ trace.getActiveSpan()?.setStatus({ code: SpanStatusCode.ERROR });
3596
+ await settleRunTrace(userId, scope.runId, { status: "failed", error: scope.policy.contentSuppressed ? "Execution failed" : errMsg, secretValues: scope.secretValues, contentSuppressed: scope.policy.contentSuppressed });
3597
+ }
3444
3598
  log.error("Workflow message error", {
3445
3599
  threadId,
3446
3600
  workflowId,