@nodetool-ai/runtime 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 (373) hide show
  1. package/dist/.nodetool-build-stamp +1 -1
  2. package/dist/context.d.ts +31 -3
  3. package/dist/context.d.ts.map +1 -1
  4. package/dist/context.js +369 -160
  5. package/dist/context.js.map +1 -1
  6. package/dist/generation-registry.d.ts +8 -0
  7. package/dist/generation-registry.d.ts.map +1 -1
  8. package/dist/generation-registry.js +18 -0
  9. package/dist/generation-registry.js.map +1 -1
  10. package/dist/host-binaries.d.ts.map +1 -1
  11. package/dist/host-binaries.js +18 -10
  12. package/dist/host-binaries.js.map +1 -1
  13. package/dist/image-codec.d.ts +2 -0
  14. package/dist/image-codec.d.ts.map +1 -1
  15. package/dist/image-codec.js +23 -3
  16. package/dist/image-codec.js.map +1 -1
  17. package/dist/image-model-tasks.d.ts +35 -0
  18. package/dist/image-model-tasks.d.ts.map +1 -0
  19. package/dist/image-model-tasks.js +67 -0
  20. package/dist/image-model-tasks.js.map +1 -0
  21. package/dist/index.d.ts +14 -3
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +10 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/media-ref-bytes.d.ts +18 -2
  26. package/dist/media-ref-bytes.d.ts.map +1 -1
  27. package/dist/media-ref-bytes.js +26 -16
  28. package/dist/media-ref-bytes.js.map +1 -1
  29. package/dist/node-executor.d.ts +6 -0
  30. package/dist/node-executor.d.ts.map +1 -1
  31. package/dist/prompt-asset-refs.d.ts +12 -1
  32. package/dist/prompt-asset-refs.d.ts.map +1 -1
  33. package/dist/prompt-asset-refs.js +9 -4
  34. package/dist/prompt-asset-refs.js.map +1 -1
  35. package/dist/providers/aki-provider.d.ts +2 -0
  36. package/dist/providers/aki-provider.d.ts.map +1 -1
  37. package/dist/providers/aki-provider.js +6 -0
  38. package/dist/providers/aki-provider.js.map +1 -1
  39. package/dist/providers/api-route-provider.d.ts +22 -0
  40. package/dist/providers/api-route-provider.d.ts.map +1 -0
  41. package/dist/providers/api-route-provider.js +56 -0
  42. package/dist/providers/api-route-provider.js.map +1 -0
  43. package/dist/providers/atlascloud-provider.d.ts +2 -0
  44. package/dist/providers/atlascloud-provider.d.ts.map +1 -1
  45. package/dist/providers/atlascloud-provider.js +22 -0
  46. package/dist/providers/atlascloud-provider.js.map +1 -1
  47. package/dist/providers/base-provider.d.ts +36 -24
  48. package/dist/providers/base-provider.d.ts.map +1 -1
  49. package/dist/providers/base-provider.js +145 -150
  50. package/dist/providers/base-provider.js.map +1 -1
  51. package/dist/providers/chatgpt-provider.d.ts +48 -0
  52. package/dist/providers/chatgpt-provider.d.ts.map +1 -0
  53. package/dist/providers/chatgpt-provider.js +506 -0
  54. package/dist/providers/chatgpt-provider.js.map +1 -0
  55. package/dist/providers/claude-agent-provider.d.ts +6 -36
  56. package/dist/providers/claude-agent-provider.d.ts.map +1 -1
  57. package/dist/providers/claude-agent-provider.js +208 -26
  58. package/dist/providers/claude-agent-provider.js.map +1 -1
  59. package/dist/providers/codex-provider.d.ts +2 -0
  60. package/dist/providers/codex-provider.d.ts.map +1 -1
  61. package/dist/providers/codex-provider.js +15 -2
  62. package/dist/providers/codex-provider.js.map +1 -1
  63. package/dist/providers/cohere-provider.d.ts +2 -1
  64. package/dist/providers/cohere-provider.d.ts.map +1 -1
  65. package/dist/providers/cohere-provider.js +5 -0
  66. package/dist/providers/cohere-provider.js.map +1 -1
  67. package/dist/providers/context-window.d.ts.map +1 -1
  68. package/dist/providers/context-window.js +1 -0
  69. package/dist/providers/context-window.js.map +1 -1
  70. package/dist/providers/core-tools.d.ts +2 -1
  71. package/dist/providers/core-tools.d.ts.map +1 -1
  72. package/dist/providers/core-tools.js +2 -1
  73. package/dist/providers/core-tools.js.map +1 -1
  74. package/dist/providers/cost-calculator.d.ts.map +1 -1
  75. package/dist/providers/cost-calculator.js +9 -0
  76. package/dist/providers/cost-calculator.js.map +1 -1
  77. package/dist/providers/credential-check.d.ts +8 -0
  78. package/dist/providers/credential-check.d.ts.map +1 -1
  79. package/dist/providers/credential-check.js +27 -0
  80. package/dist/providers/credential-check.js.map +1 -1
  81. package/dist/providers/custom-openai-provider.d.ts +2 -0
  82. package/dist/providers/custom-openai-provider.d.ts.map +1 -1
  83. package/dist/providers/custom-openai-provider.js +27 -1
  84. package/dist/providers/custom-openai-provider.js.map +1 -1
  85. package/dist/providers/dreamina-models.d.ts +5 -0
  86. package/dist/providers/dreamina-models.d.ts.map +1 -0
  87. package/dist/providers/dreamina-models.js +57 -0
  88. package/dist/providers/dreamina-models.js.map +1 -0
  89. package/dist/providers/dreamina-music.d.ts +52 -0
  90. package/dist/providers/dreamina-music.d.ts.map +1 -0
  91. package/dist/providers/dreamina-music.js +115 -0
  92. package/dist/providers/dreamina-music.js.map +1 -0
  93. package/dist/providers/dreamina-provider.d.ts +64 -0
  94. package/dist/providers/dreamina-provider.d.ts.map +1 -0
  95. package/dist/providers/dreamina-provider.js +1001 -0
  96. package/dist/providers/dreamina-provider.js.map +1 -0
  97. package/dist/providers/elevenlabs-provider.d.ts +2 -1
  98. package/dist/providers/elevenlabs-provider.d.ts.map +1 -1
  99. package/dist/providers/elevenlabs-provider.js +5 -0
  100. package/dist/providers/elevenlabs-provider.js.map +1 -1
  101. package/dist/providers/evolink-provider.d.ts +2 -0
  102. package/dist/providers/evolink-provider.d.ts.map +1 -1
  103. package/dist/providers/evolink-provider.js +8 -0
  104. package/dist/providers/evolink-provider.js.map +1 -1
  105. package/dist/providers/extension-tab.d.ts +29 -0
  106. package/dist/providers/extension-tab.d.ts.map +1 -0
  107. package/dist/providers/extension-tab.js +144 -0
  108. package/dist/providers/extension-tab.js.map +1 -0
  109. package/dist/providers/fake-provider.d.ts +5 -2
  110. package/dist/providers/fake-provider.d.ts.map +1 -1
  111. package/dist/providers/fake-provider.js +73 -9
  112. package/dist/providers/fake-provider.js.map +1 -1
  113. package/dist/providers/fake-schema-answer.d.ts +10 -0
  114. package/dist/providers/fake-schema-answer.d.ts.map +1 -0
  115. package/dist/providers/fake-schema-answer.js +64 -0
  116. package/dist/providers/fake-schema-answer.js.map +1 -0
  117. package/dist/providers/fal-provider.d.ts +2 -1
  118. package/dist/providers/fal-provider.d.ts.map +1 -1
  119. package/dist/providers/fal-provider.js +32 -2
  120. package/dist/providers/fal-provider.js.map +1 -1
  121. package/dist/providers/gemini-provider.d.ts +2 -1
  122. package/dist/providers/gemini-provider.d.ts.map +1 -1
  123. package/dist/providers/gemini-provider.js +15 -0
  124. package/dist/providers/gemini-provider.js.map +1 -1
  125. package/dist/providers/gemini-web-provider.d.ts +76 -0
  126. package/dist/providers/gemini-web-provider.d.ts.map +1 -0
  127. package/dist/providers/gemini-web-provider.js +752 -0
  128. package/dist/providers/gemini-web-provider.js.map +1 -0
  129. package/dist/providers/higgsfield-provider.d.ts +2 -1
  130. package/dist/providers/higgsfield-provider.d.ts.map +1 -1
  131. package/dist/providers/higgsfield-provider.js +12 -0
  132. package/dist/providers/higgsfield-provider.js.map +1 -1
  133. package/dist/providers/huggingface-provider.d.ts +2 -1
  134. package/dist/providers/huggingface-provider.d.ts.map +1 -1
  135. package/dist/providers/huggingface-provider.js +27 -1
  136. package/dist/providers/huggingface-provider.js.map +1 -1
  137. package/dist/providers/index.d.ts +14 -3
  138. package/dist/providers/index.d.ts.map +1 -1
  139. package/dist/providers/index.js +48 -9
  140. package/dist/providers/index.js.map +1 -1
  141. package/dist/providers/jina-provider.d.ts +2 -1
  142. package/dist/providers/jina-provider.d.ts.map +1 -1
  143. package/dist/providers/jina-provider.js +5 -0
  144. package/dist/providers/jina-provider.js.map +1 -1
  145. package/dist/providers/kie-provider.d.ts +2 -1
  146. package/dist/providers/kie-provider.d.ts.map +1 -1
  147. package/dist/providers/kie-provider.js +14 -0
  148. package/dist/providers/kie-provider.js.map +1 -1
  149. package/dist/providers/llama-provider.d.ts +12 -1
  150. package/dist/providers/llama-provider.d.ts.map +1 -1
  151. package/dist/providers/llama-provider.js +29 -5
  152. package/dist/providers/llama-provider.js.map +1 -1
  153. package/dist/providers/lmstudio-provider.js +2 -2
  154. package/dist/providers/lmstudio-provider.js.map +1 -1
  155. package/dist/providers/loop-tracing.d.ts +17 -0
  156. package/dist/providers/loop-tracing.d.ts.map +1 -0
  157. package/dist/providers/loop-tracing.js +132 -0
  158. package/dist/providers/loop-tracing.js.map +1 -0
  159. package/dist/providers/manifest-models.d.ts +2 -12
  160. package/dist/providers/manifest-models.d.ts.map +1 -1
  161. package/dist/providers/manifest-models.js +45 -3
  162. package/dist/providers/manifest-models.js.map +1 -1
  163. package/dist/providers/meshy-provider.d.ts +2 -1
  164. package/dist/providers/meshy-provider.d.ts.map +1 -1
  165. package/dist/providers/meshy-provider.js +6 -0
  166. package/dist/providers/meshy-provider.js.map +1 -1
  167. package/dist/providers/meta-provider.d.ts +53 -6
  168. package/dist/providers/meta-provider.d.ts.map +1 -1
  169. package/dist/providers/meta-provider.js +289 -6
  170. package/dist/providers/meta-provider.js.map +1 -1
  171. package/dist/providers/meta-segmentation.d.ts +27 -0
  172. package/dist/providers/meta-segmentation.d.ts.map +1 -0
  173. package/dist/providers/meta-segmentation.js +141 -0
  174. package/dist/providers/meta-segmentation.js.map +1 -0
  175. package/dist/providers/meta-transcription.d.ts +31 -0
  176. package/dist/providers/meta-transcription.d.ts.map +1 -0
  177. package/dist/providers/meta-transcription.js +187 -0
  178. package/dist/providers/meta-transcription.js.map +1 -0
  179. package/dist/providers/minimax-provider.d.ts +2 -0
  180. package/dist/providers/minimax-provider.d.ts.map +1 -1
  181. package/dist/providers/minimax-provider.js +11 -0
  182. package/dist/providers/minimax-provider.js.map +1 -1
  183. package/dist/providers/mistral-provider.d.ts +2 -0
  184. package/dist/providers/mistral-provider.d.ts.map +1 -1
  185. package/dist/providers/mistral-provider.js +5 -0
  186. package/dist/providers/mistral-provider.js.map +1 -1
  187. package/dist/providers/node-llama-cpp-provider.d.ts +8 -4
  188. package/dist/providers/node-llama-cpp-provider.d.ts.map +1 -1
  189. package/dist/providers/node-llama-cpp-provider.js +83 -61
  190. package/dist/providers/node-llama-cpp-provider.js.map +1 -1
  191. package/dist/providers/nodetool-provider.d.ts +1 -1
  192. package/dist/providers/nodetool-provider.d.ts.map +1 -1
  193. package/dist/providers/nodetool-provider.js +0 -2
  194. package/dist/providers/nodetool-provider.js.map +1 -1
  195. package/dist/providers/ollama-provider.d.ts +25 -1
  196. package/dist/providers/ollama-provider.d.ts.map +1 -1
  197. package/dist/providers/ollama-provider.js +145 -27
  198. package/dist/providers/ollama-provider.js.map +1 -1
  199. package/dist/providers/openai-compat/client.d.ts +10 -1
  200. package/dist/providers/openai-compat/client.d.ts.map +1 -1
  201. package/dist/providers/openai-compat/client.js +21 -3
  202. package/dist/providers/openai-compat/client.js.map +1 -1
  203. package/dist/providers/openai-compat/index.d.ts +1 -1
  204. package/dist/providers/openai-compat/index.d.ts.map +1 -1
  205. package/dist/providers/openai-compat/index.js +1 -1
  206. package/dist/providers/openai-compat/index.js.map +1 -1
  207. package/dist/providers/openai-compat/types.d.ts +4 -0
  208. package/dist/providers/openai-compat/types.d.ts.map +1 -1
  209. package/dist/providers/openai-compat-provider.d.ts +11 -0
  210. package/dist/providers/openai-compat-provider.d.ts.map +1 -1
  211. package/dist/providers/openai-compat-provider.js +47 -2
  212. package/dist/providers/openai-compat-provider.js.map +1 -1
  213. package/dist/providers/openai-provider.d.ts +23 -2
  214. package/dist/providers/openai-provider.d.ts.map +1 -1
  215. package/dist/providers/openai-provider.js +102 -21
  216. package/dist/providers/openai-provider.js.map +1 -1
  217. package/dist/providers/openrouter-provider.d.ts +52 -1
  218. package/dist/providers/openrouter-provider.d.ts.map +1 -1
  219. package/dist/providers/openrouter-provider.js +372 -11
  220. package/dist/providers/openrouter-provider.js.map +1 -1
  221. package/dist/providers/opper-provider.d.ts +31 -0
  222. package/dist/providers/opper-provider.d.ts.map +1 -0
  223. package/dist/providers/opper-provider.js +91 -0
  224. package/dist/providers/opper-provider.js.map +1 -0
  225. package/dist/providers/provider-error.d.ts.map +1 -1
  226. package/dist/providers/provider-error.js +7 -1
  227. package/dist/providers/provider-error.js.map +1 -1
  228. package/dist/providers/provider-generations.d.ts +2 -2
  229. package/dist/providers/provider-generations.js +2 -2
  230. package/dist/providers/provider-request-log.d.ts.map +1 -1
  231. package/dist/providers/provider-request-log.js +19 -7
  232. package/dist/providers/provider-request-log.js.map +1 -1
  233. package/dist/providers/python-provider.d.ts +6 -1
  234. package/dist/providers/python-provider.d.ts.map +1 -1
  235. package/dist/providers/python-provider.js +35 -14
  236. package/dist/providers/python-provider.js.map +1 -1
  237. package/dist/providers/replicate-provider.d.ts +2 -1
  238. package/dist/providers/replicate-provider.d.ts.map +1 -1
  239. package/dist/providers/replicate-provider.js +22 -0
  240. package/dist/providers/replicate-provider.js.map +1 -1
  241. package/dist/providers/requesty-provider.d.ts +30 -0
  242. package/dist/providers/requesty-provider.d.ts.map +1 -0
  243. package/dist/providers/requesty-provider.js +87 -0
  244. package/dist/providers/requesty-provider.js.map +1 -0
  245. package/dist/providers/responses-api.d.ts +12 -2
  246. package/dist/providers/responses-api.d.ts.map +1 -1
  247. package/dist/providers/responses-api.js +54 -3
  248. package/dist/providers/responses-api.js.map +1 -1
  249. package/dist/providers/reve-provider.d.ts +2 -1
  250. package/dist/providers/reve-provider.d.ts.map +1 -1
  251. package/dist/providers/reve-provider.js +6 -0
  252. package/dist/providers/reve-provider.js.map +1 -1
  253. package/dist/providers/rodin-provider.d.ts +2 -1
  254. package/dist/providers/rodin-provider.d.ts.map +1 -1
  255. package/dist/providers/rodin-provider.js +6 -0
  256. package/dist/providers/rodin-provider.js.map +1 -1
  257. package/dist/providers/scripted-provider.d.ts.map +1 -1
  258. package/dist/providers/scripted-provider.js +6 -1
  259. package/dist/providers/scripted-provider.js.map +1 -1
  260. package/dist/providers/together-operations.d.ts +27 -0
  261. package/dist/providers/together-operations.d.ts.map +1 -0
  262. package/dist/providers/together-operations.js +95 -0
  263. package/dist/providers/together-operations.js.map +1 -0
  264. package/dist/providers/together-provider.d.ts +5 -8
  265. package/dist/providers/together-provider.d.ts.map +1 -1
  266. package/dist/providers/together-provider.js +54 -159
  267. package/dist/providers/together-provider.js.map +1 -1
  268. package/dist/providers/topaz-provider.d.ts +2 -1
  269. package/dist/providers/topaz-provider.d.ts.map +1 -1
  270. package/dist/providers/topaz-provider.js +5 -0
  271. package/dist/providers/topaz-provider.js.map +1 -1
  272. package/dist/providers/types.d.ts +54 -0
  273. package/dist/providers/types.d.ts.map +1 -1
  274. package/dist/providers/types.js.map +1 -1
  275. package/dist/providers/useapi-provider.d.ts +2 -1
  276. package/dist/providers/useapi-provider.d.ts.map +1 -1
  277. package/dist/providers/useapi-provider.js +8 -0
  278. package/dist/providers/useapi-provider.js.map +1 -1
  279. package/dist/providers/vllm-provider.d.ts +9 -4
  280. package/dist/providers/vllm-provider.d.ts.map +1 -1
  281. package/dist/providers/vllm-provider.js +16 -8
  282. package/dist/providers/vllm-provider.js.map +1 -1
  283. package/dist/providers/voyage-provider.d.ts +2 -1
  284. package/dist/providers/voyage-provider.d.ts.map +1 -1
  285. package/dist/providers/voyage-provider.js +5 -0
  286. package/dist/providers/voyage-provider.js.map +1 -1
  287. package/dist/providers/xai-provider.d.ts +2 -0
  288. package/dist/providers/xai-provider.d.ts.map +1 -1
  289. package/dist/providers/xai-provider.js +8 -0
  290. package/dist/providers/xai-provider.js.map +1 -1
  291. package/dist/python-bridge-base.d.ts +16 -6
  292. package/dist/python-bridge-base.d.ts.map +1 -1
  293. package/dist/python-bridge-base.js +117 -40
  294. package/dist/python-bridge-base.js.map +1 -1
  295. package/dist/python-bridge-codec.d.ts +16 -1
  296. package/dist/python-bridge-codec.d.ts.map +1 -1
  297. package/dist/python-bridge-codec.js +60 -2
  298. package/dist/python-bridge-codec.js.map +1 -1
  299. package/dist/python-bridge-framing.d.ts +10 -1
  300. package/dist/python-bridge-framing.d.ts.map +1 -1
  301. package/dist/python-bridge-framing.js +33 -8
  302. package/dist/python-bridge-framing.js.map +1 -1
  303. package/dist/python-bridge-types.d.ts +26 -5
  304. package/dist/python-bridge-types.d.ts.map +1 -1
  305. package/dist/python-bridge-types.js.map +1 -1
  306. package/dist/python-node-executor.d.ts +14 -3
  307. package/dist/python-node-executor.d.ts.map +1 -1
  308. package/dist/python-node-executor.js +185 -3
  309. package/dist/python-node-executor.js.map +1 -1
  310. package/dist/python-stdio-bridge.d.ts +6 -0
  311. package/dist/python-stdio-bridge.d.ts.map +1 -1
  312. package/dist/python-stdio-bridge.js +25 -2
  313. package/dist/python-stdio-bridge.js.map +1 -1
  314. package/dist/recommended-models.d.ts.map +1 -1
  315. package/dist/recommended-models.js +20 -0
  316. package/dist/recommended-models.js.map +1 -1
  317. package/dist/run-context.d.ts +20 -0
  318. package/dist/run-context.d.ts.map +1 -0
  319. package/dist/run-context.js +18 -0
  320. package/dist/run-context.js.map +1 -0
  321. package/dist/run-trace-context.d.ts +5 -0
  322. package/dist/run-trace-context.d.ts.map +1 -0
  323. package/dist/run-trace-context.js +33 -0
  324. package/dist/run-trace-context.js.map +1 -0
  325. package/dist/run-trace-processor.d.ts +65 -0
  326. package/dist/run-trace-processor.d.ts.map +1 -0
  327. package/dist/run-trace-processor.js +418 -0
  328. package/dist/run-trace-processor.js.map +1 -0
  329. package/dist/run-trace-scope.d.ts +28 -0
  330. package/dist/run-trace-scope.d.ts.map +1 -0
  331. package/dist/run-trace-scope.js +51 -0
  332. package/dist/run-trace-scope.js.map +1 -0
  333. package/dist/run-trace-serialization.d.ts +5 -0
  334. package/dist/run-trace-serialization.d.ts.map +1 -0
  335. package/dist/run-trace-serialization.js +114 -0
  336. package/dist/run-trace-serialization.js.map +1 -0
  337. package/dist/span-record.d.ts +4 -0
  338. package/dist/span-record.d.ts.map +1 -0
  339. package/dist/span-record.js +48 -0
  340. package/dist/span-record.js.map +1 -0
  341. package/dist/storage-workspace.d.ts +3 -0
  342. package/dist/storage-workspace.d.ts.map +1 -1
  343. package/dist/storage-workspace.js +32 -17
  344. package/dist/storage-workspace.js.map +1 -1
  345. package/dist/swappable-python-bridge.d.ts +6 -6
  346. package/dist/swappable-python-bridge.d.ts.map +1 -1
  347. package/dist/swappable-python-bridge.js +10 -10
  348. package/dist/swappable-python-bridge.js.map +1 -1
  349. package/dist/telemetry.d.ts +9 -3
  350. package/dist/telemetry.d.ts.map +1 -1
  351. package/dist/telemetry.js +53 -20
  352. package/dist/telemetry.js.map +1 -1
  353. package/dist/testing.d.ts +1 -1
  354. package/dist/testing.d.ts.map +1 -1
  355. package/dist/testing.js +55 -3
  356. package/dist/testing.js.map +1 -1
  357. package/dist/trace-exporters.d.ts +2 -30
  358. package/dist/trace-exporters.d.ts.map +1 -1
  359. package/dist/trace-exporters.js +4 -42
  360. package/dist/trace-exporters.js.map +1 -1
  361. package/dist/traced-storage.d.ts +17 -0
  362. package/dist/traced-storage.d.ts.map +1 -0
  363. package/dist/traced-storage.js +41 -0
  364. package/dist/traced-storage.js.map +1 -0
  365. package/dist/tracing-helpers.d.ts +15 -22
  366. package/dist/tracing-helpers.d.ts.map +1 -1
  367. package/dist/tracing-helpers.js +38 -6
  368. package/dist/tracing-helpers.js.map +1 -1
  369. package/dist/trim-video-window.d.ts +8 -0
  370. package/dist/trim-video-window.d.ts.map +1 -0
  371. package/dist/trim-video-window.js +50 -0
  372. package/dist/trim-video-window.js.map +1 -0
  373. package/package.json +21 -5
package/dist/context.js CHANGED
@@ -1,22 +1,14 @@
1
- /**
2
- * ProcessingContext – runtime context for node execution.
3
- *
4
- * Port of src/nodetool/workflows/processing_context.py.
5
- *
6
- * Provides:
7
- * - Message queue for emitting ProcessingMessages.
8
- * - Cache get/set interface.
9
- * - Output normalization (sanitize memory URIs, etc.).
10
- * - Asset handling with pluggable storage adapters.
11
- */
12
- import { buildAssetGenerationMetadata, isShortResourceId, packageAssetHttpPath, parsePackageAssetUri } from "@nodetool-ai/protocol";
1
+ import { getRunTraceScope } from "./run-trace-context.js";
2
+ import { withSpan } from "./tracing-helpers.js";
3
+ import { traceStorageAdapter } from "./traced-storage.js";
4
+ import { assetFileNameCandidates, buildAssetGenerationMetadata, isShortResourceId, packageAssetHttpPath, parsePackageAssetUri } from "@nodetool-ai/protocol";
13
5
  import { AgentMemory } from "./agent-memory.js";
14
6
  import { recordInvocationAsset, recordInvocationCost } from "./invocation-account.js";
15
7
  import { VariableChannel } from "./variable-channel.js";
16
8
  import { loadMediaRefBytes } from "./media-ref-bytes.js";
17
9
  import { objectTrackingRequestSchema, parseObjectTrackingResult } from "./providers/object-tracking.js";
18
10
  import { requestVideoToAudio, VIDEO_TO_AUDIO_TASK, VideoToAudioRequest } from "./providers/video-to-audio.js";
19
- import { encodeRawImageRef } from "./image-codec.js";
11
+ import { encodeRawImageRef, validateImageEvidence } from "./image-codec.js";
20
12
  import { extForImageMime, sniffImageMime } from "./providers/image-mime.js";
21
13
  import { GenerationScopeError, isAuthoritativeProviderTerminalError, runWithGenerationReceipt } from "./generation-receipt.js";
22
14
  import { generationRegistry } from "./generation-registry.js";
@@ -28,11 +20,6 @@ import { getNodeBuiltinSync } from "@nodetool-ai/config";
28
20
  // lazily so this module loads in browser / Edge runtimes. `resolveWorkspacePath`
29
21
  // and the `randomUUID` fallback both degrade gracefully when these are
30
22
  // unavailable.
31
- /**
32
- * Secret values shorter than this are not recorded for masking: redacting a
33
- * two-character value would blank unrelated text wherever it happens to occur.
34
- */
35
- const MIN_MASKABLE_SECRET_LENGTH = 8;
36
23
  /**
37
24
  * ProcessingContext variable key carrying the provider/model the currently
38
25
  * running agent loop is itself talking to. Every loop that executes tools
@@ -481,6 +468,11 @@ export class ProcessingContext {
481
468
  _secretResolver = null;
482
469
  /** Every secret value the resolver handed out this run (see {@link ProcessingContext.getResolvedSecretValues}). */
483
470
  _resolvedSecrets = new Set();
471
+ /** Identity shared by all work beneath an app operation. */
472
+ appRunContext;
473
+ runTraceContext;
474
+ appRunCostAccount;
475
+ _appRunDocuments = new Map();
484
476
  /** Fetch function used by HTTP helpers. */
485
477
  _fetch;
486
478
  /** Optional temporary URL resolver for stored assets. */
@@ -526,9 +518,15 @@ export class ProcessingContext {
526
518
  this.assetOutputMode = opts.assetOutputMode ?? "native";
527
519
  this.persistOutputAssets = opts.persistOutputAssets ?? true;
528
520
  this._generationLifecycle = opts.generationLifecycle ?? null;
521
+ this.appRunContext = opts.appRunContext ? Object.freeze({ ...opts.appRunContext }) : null;
522
+ this.runTraceContext = opts.runTraceContext ?? getRunTraceScope() ?? null;
523
+ if (this.runTraceContext?.secretValues instanceof Set) {
524
+ this._resolvedSecrets = this.runTraceContext.secretValues;
525
+ }
526
+ this.appRunCostAccount = opts.appRunCostAccount ?? (this.appRunContext ? { llmCostUsd: 0, unpriced: false } : null);
529
527
  this.cache = opts.cache ?? new MemoryCache();
530
- this.storage = opts.storage ?? null;
531
- this.assetStorage = opts.assetStorage ?? null;
528
+ this.storage = traceStorageAdapter(opts.storage ?? null);
529
+ this.assetStorage = traceStorageAdapter(opts.assetStorage ?? null);
532
530
  this.workspaceStorage = opts.workspaceStorage ?? null;
533
531
  if (opts.onMessage) {
534
532
  this._messageListeners.add(opts.onMessage);
@@ -575,12 +573,12 @@ export class ProcessingContext {
575
573
  */
576
574
  copy(opts) {
577
575
  const next = new ProcessingContext({
578
- jobId: this.jobId,
576
+ jobId: opts?.jobId ?? this.jobId,
579
577
  projectId: this.projectId,
580
- workflowId: this.workflowId,
578
+ workflowId: opts?.workflowId !== undefined ? opts.workflowId : this.workflowId,
581
579
  threadId: this.threadId,
582
580
  userId: this.userId,
583
- workspaceDir: this.workspaceDir,
581
+ workspace: opts?.workspace !== undefined ? opts.workspace : this.workspace,
584
582
  assetOutputMode: this.assetOutputMode,
585
583
  persistOutputAssets: this.persistOutputAssets,
586
584
  cache: this.cache,
@@ -596,7 +594,11 @@ export class ProcessingContext {
596
594
  tempUrlResolver: this._tempUrlResolver ?? undefined,
597
595
  modelInterfaces: this._modelInterfaces ?? undefined,
598
596
  retainMessageQueue: this._retainMessageQueue,
599
- triggerEvent: this.triggerEvent
597
+ triggerEvent: this.triggerEvent,
598
+ generationLifecycle: opts?.generationLifecycle ?? this._generationLifecycle ?? undefined,
599
+ appRunContext: opts?.appRunContext ?? this.appRunContext ?? undefined,
600
+ runTraceContext: opts?.runTraceContext ?? this.runTraceContext ?? undefined,
601
+ appRunCostAccount: !opts?.appRunContext || opts.appRunContext.appRunId === this.appRunContext?.appRunId ? this.appRunCostAccount ?? undefined : undefined
600
602
  });
601
603
  if (opts?.inheritMessageListeners !== false) {
602
604
  for (const listener of this._messageListeners) {
@@ -606,6 +608,12 @@ export class ProcessingContext {
606
608
  if (opts?.shareMemory) {
607
609
  next.memory = this.memory;
608
610
  }
611
+ if (!opts?.runTraceContext) {
612
+ next._resolvedSecrets = this._resolvedSecrets;
613
+ }
614
+ if (next.appRunContext?.appRunId === this.appRunContext?.appRunId) {
615
+ next._appRunDocuments = this._appRunDocuments;
616
+ }
609
617
  next.signal = this.signal;
610
618
  next._providerResolver = this._providerResolver;
611
619
  next._modelInterfaces = this._modelInterfaces;
@@ -813,7 +821,7 @@ export class ProcessingContext {
813
821
  if (!this._secretResolver)
814
822
  return null;
815
823
  const value = await this._secretResolver(key, this.userId);
816
- if (value != null && value.length >= MIN_MASKABLE_SECRET_LENGTH) {
824
+ if (value != null && value.length > 0) {
817
825
  this._resolvedSecrets.add(value);
818
826
  }
819
827
  return value ?? null;
@@ -1041,6 +1049,26 @@ export class ProcessingContext {
1041
1049
  getTotalCost() {
1042
1050
  return this._totalCost;
1043
1051
  }
1052
+ /** Null means at least one LLM call could not be priced. */
1053
+ getAppRunLlmCost() {
1054
+ return this.appRunCostAccount && !this.appRunCostAccount.unpriced
1055
+ ? this.appRunCostAccount.llmCostUsd
1056
+ : null;
1057
+ }
1058
+ getAppRunDocuments() {
1059
+ return [...this._appRunDocuments.values()].map((reference) => ({
1060
+ ...reference
1061
+ }));
1062
+ }
1063
+ recordAppRunDocument(kind, document) {
1064
+ if (this.appRunContext && document) {
1065
+ this._appRunDocuments.set(`${kind}:${document.id}`, {
1066
+ kind,
1067
+ id: document.id
1068
+ });
1069
+ }
1070
+ return document;
1071
+ }
1044
1072
  getOperationCosts() {
1045
1073
  return this._operationCosts;
1046
1074
  }
@@ -1199,7 +1227,8 @@ export class ProcessingContext {
1199
1227
  /** Create a persisted sketch (image document) owned by the current user. */
1200
1228
  async createImageDocument(args) {
1201
1229
  const fn = this.requireModelInterface("createImageDocument");
1202
- return fn({ userId: this.userId, ...args });
1230
+ const document = await fn({ userId: this.userId, ...args });
1231
+ return this.recordAppRunDocument("sketch", document);
1203
1232
  }
1204
1233
  /** Load a persisted timeline sequence owned by the current user. */
1205
1234
  async getTimelineSequence(id) {
@@ -1209,12 +1238,14 @@ export class ProcessingContext {
1209
1238
  /** Create a persisted timeline sequence owned by the current user. */
1210
1239
  async createTimelineSequence(sequence) {
1211
1240
  const fn = this.requireModelInterface("createTimelineSequence");
1212
- return fn({ userId: this.userId, sequence });
1241
+ const document = await fn({ userId: this.userId, sequence });
1242
+ return this.recordAppRunDocument("timeline", document);
1213
1243
  }
1214
1244
  /** Replace a persisted timeline sequence's document. */
1215
1245
  async updateTimelineSequence(id, sequence) {
1216
1246
  const fn = this.requireModelInterface("updateTimelineSequence");
1217
- return fn({ userId: this.userId, id, sequence });
1247
+ const document = await fn({ userId: this.userId, id, sequence });
1248
+ return this.recordAppRunDocument("timeline", document);
1218
1249
  }
1219
1250
  /** Load a persisted script owned by the current user. */
1220
1251
  async getScript(id) {
@@ -1224,12 +1255,14 @@ export class ProcessingContext {
1224
1255
  /** Create a persisted script owned by the current user. */
1225
1256
  async createScript(args) {
1226
1257
  const fn = this.requireModelInterface("createScript");
1227
- return fn({ userId: this.userId, ...args });
1258
+ const document = await fn({ userId: this.userId, ...args });
1259
+ return this.recordAppRunDocument("script", document);
1228
1260
  }
1229
1261
  /** Replace a persisted script's document (and optional timeline link). */
1230
1262
  async updateScript(id, args) {
1231
1263
  const fn = this.requireModelInterface("updateScript");
1232
- return fn({ userId: this.userId, id, ...args });
1264
+ const document = await fn({ userId: this.userId, id, ...args });
1265
+ return this.recordAppRunDocument("script", document);
1233
1266
  }
1234
1267
  /** Load a persisted storyboard owned by the current user. */
1235
1268
  async getStoryboard(id) {
@@ -1249,12 +1282,14 @@ export class ProcessingContext {
1249
1282
  /** Create a persisted storyboard owned by the current user. */
1250
1283
  async createStoryboard(args) {
1251
1284
  const fn = this.requireModelInterface("createStoryboard");
1252
- return fn({ userId: this.userId, ...args });
1285
+ const document = await fn({ userId: this.userId, ...args });
1286
+ return this.recordAppRunDocument("storyboard", document);
1253
1287
  }
1254
1288
  /** Replace a persisted storyboard's document (and optional timeline link). */
1255
1289
  async updateStoryboard(id, args) {
1256
1290
  const fn = this.requireModelInterface("updateStoryboard");
1257
- return fn({ userId: this.userId, id, ...args });
1291
+ const document = await fn({ userId: this.userId, id, ...args });
1292
+ return this.recordAppRunDocument("storyboard", document);
1258
1293
  }
1259
1294
  /** The current user's entity library, narrowed by the given filters. */
1260
1295
  async listEntities(args = {}) {
@@ -1289,7 +1324,7 @@ export class ProcessingContext {
1289
1324
  * `null` when that interface is not configured.
1290
1325
  */
1291
1326
  async getAssetInfo(assetId) {
1292
- const fn = this._modelInterfaces?.getAssetInfo;
1327
+ const fn = this.modelInterfaces()?.getAssetInfo;
1293
1328
  if (!fn) {
1294
1329
  return null;
1295
1330
  }
@@ -1507,8 +1542,8 @@ export class ProcessingContext {
1507
1542
  * from the server's `/api/storage` route. Returns the bytes plus an `attempts`
1508
1543
  * trail for callers that build detailed errors; `null` bytes means unresolved.
1509
1544
  */
1510
- async resolveAssetBytes(assetId) {
1511
- const idCandidates = this.parseAssetIdCandidates(assetId);
1545
+ async resolveAssetBytes(assetId, options) {
1546
+ let idCandidates = this.parseAssetIdCandidates(assetId);
1512
1547
  const trimmed = assetId.trim();
1513
1548
  const attempts = [];
1514
1549
  const adapters = this.assetAdapters();
@@ -1595,6 +1630,33 @@ export class ProcessingContext {
1595
1630
  }
1596
1631
  }
1597
1632
  }
1633
+ // An asset row names the stored file exactly (`<owner>/<id>.<ext>`), so a
1634
+ // reference that resolves to one is read by key and never by listing.
1635
+ let assetRowFound = false;
1636
+ if (this.hasModelInterface("getAssetInfo")) {
1637
+ let asset = null;
1638
+ const ownerPrefix = `${this.userId}/`;
1639
+ const rowIdCandidates = new Set(idCandidates);
1640
+ for (const candidate of idCandidates) {
1641
+ if (candidate.startsWith(ownerPrefix)) {
1642
+ rowIdCandidates.add(candidate.slice(ownerPrefix.length));
1643
+ }
1644
+ }
1645
+ for (const candidate of rowIdCandidates) {
1646
+ asset = await this.getAssetInfo(candidate);
1647
+ if (asset) {
1648
+ break;
1649
+ }
1650
+ }
1651
+ if (asset) {
1652
+ assetRowFound = true;
1653
+ idCandidates = assetFileNameCandidates(asset.id, asset.content_type);
1654
+ }
1655
+ else if (options?.requireOwnedAsset) {
1656
+ attempts.push(`asset unavailable or not owned: ${trimmed}`);
1657
+ return { bytes: null, attempts };
1658
+ }
1659
+ }
1598
1660
  for (const adapter of adapters) {
1599
1661
  for (const candidate of idCandidates) {
1600
1662
  for (const key of this.assetKeysFor(candidate)) {
@@ -1606,9 +1668,10 @@ export class ProcessingContext {
1606
1668
  }
1607
1669
  // Extension-tolerant fallback: locate the stored file whose name starts
1608
1670
  // with the id, since the URN extension may differ from the one on disk
1609
- // (e.g. jpeg vs jpg). Only reached when the exact-key lookups all miss.
1671
+ // (e.g. jpeg vs jpg). Only reached when the exact-key lookups all miss
1672
+ // and no asset row named the file.
1610
1673
  const bareId = idCandidates[idCandidates.length - 1];
1611
- if (bareId) {
1674
+ if (bareId && !assetRowFound) {
1612
1675
  for (const prefix of this.assetListingPrefixes(bareId)) {
1613
1676
  try {
1614
1677
  const listing = await adapter.list(prefix);
@@ -1876,8 +1939,9 @@ export class ProcessingContext {
1876
1939
  // Strict, anchored sanitizer for the URIs that may flow into the asset /
1877
1940
  // storage retrieval path. Accept asset references, the browser-facing
1878
1941
  // storage route, and URIs from configured storage adapters. External URLs
1879
- // and unrecognized schemes stay out of the storage adapter.
1880
- const RESOLVABLE_URI_RE = /^(?:asset:\/\/|\/?api\/storage\/|(?:memory|file|s3|supabase):\/\/)[A-Za-z0-9._~/%-]+$/;
1942
+ // and unrecognized schemes stay out of the storage adapter. `:` is allowed
1943
+ // for named owner ids such as `projects/personal:<user_id>/assets/…`.
1944
+ const RESOLVABLE_URI_RE = /^(?:asset:\/\/|\/?api\/storage\/|(?:memory|file|s3|supabase):\/\/)[A-Za-z0-9._~/%:-]+$/;
1881
1945
  const isResolvableUri = (uri) => RESOLVABLE_URI_RE.test(uri);
1882
1946
  // An `asset://` reference that cannot be dereferenced must not reach the
1883
1947
  // provider: providers `fetch` a non-data URI, and the SSRF guard then
@@ -2003,12 +2067,82 @@ export class ProcessingContext {
2003
2067
  }
2004
2068
  return resolved;
2005
2069
  }
2070
+ async resolveRequiredImageEvidence(messages, required = []) {
2071
+ const evidence = new Map();
2072
+ const resolve = async (ref) => {
2073
+ const identity = ref.uri?.startsWith("data:")
2074
+ ? "inline image"
2075
+ : ref.uri ?? ref.asset_id ?? "inline image";
2076
+ const cached = ref.uri ? evidence.get(ref.uri) : undefined;
2077
+ if (cached) {
2078
+ return cached;
2079
+ }
2080
+ try {
2081
+ const bytes = await loadMediaRefBytes(ref, this);
2082
+ if (!bytes?.length) {
2083
+ throw new Error("no image bytes");
2084
+ }
2085
+ const mimeType = sniffImageMime(bytes);
2086
+ if (!mimeType ||
2087
+ !["image/png", "image/jpeg", "image/webp", "image/gif"].includes(mimeType)) {
2088
+ throw new Error("unsupported image format");
2089
+ }
2090
+ await validateImageEvidence(bytes);
2091
+ const block = {
2092
+ type: "image_url",
2093
+ image: {
2094
+ uri: `data:${mimeType};base64,${Buffer.from(bytes).toString("base64")}`,
2095
+ mimeType
2096
+ }
2097
+ };
2098
+ if (ref.uri) {
2099
+ evidence.set(ref.uri, block);
2100
+ }
2101
+ return block;
2102
+ }
2103
+ catch (error) {
2104
+ throw new Error(`Required image evidence unavailable: ${identity} (${error instanceof Error ? error.message : String(error)})`);
2105
+ }
2106
+ };
2107
+ for (const uri of required) {
2108
+ await resolve({ type: "image", uri });
2109
+ }
2110
+ const result = [];
2111
+ for (const message of messages) {
2112
+ if (!Array.isArray(message.content)) {
2113
+ result.push(message);
2114
+ continue;
2115
+ }
2116
+ const content = [];
2117
+ let imageIndex = 0;
2118
+ for (const part of message.content) {
2119
+ if (part.type === "image_url") {
2120
+ imageIndex++;
2121
+ content.push(await resolve(part.image), {
2122
+ type: "text",
2123
+ text: `[required image ${part.image.uri && !part.image.uri.startsWith("data:")
2124
+ ? part.image.uri
2125
+ : `inline image ${imageIndex}`}]`
2126
+ });
2127
+ }
2128
+ else {
2129
+ content.push(part);
2130
+ }
2131
+ }
2132
+ result.push({ ...message, content });
2133
+ }
2134
+ return result;
2135
+ }
2006
2136
  async dispatchCapability(provider, req) {
2007
2137
  const params = req.params ?? {};
2008
2138
  switch (req.capability) {
2009
2139
  case "generate_message":
2010
2140
  return provider.generateMessageTraced({
2011
- messages: await this.resolveMessageMediaUris(params.messages ?? []),
2141
+ messages: params.strict_image_evidence === true
2142
+ ? await this.resolveRequiredImageEvidence(params.messages ?? [], Array.isArray(params.required_images)
2143
+ ? params.required_images.filter(isString)
2144
+ : [])
2145
+ : await this.resolveMessageMediaUris(params.messages ?? []),
2012
2146
  model: req.model,
2013
2147
  tools: params.tools,
2014
2148
  toolChoice: params.tool_choice,
@@ -2163,6 +2297,22 @@ export class ProcessingContext {
2163
2297
  return provider.vectorizeImage(params.image, {
2164
2298
  model: { id: req.model, name: req.model, provider: req.provider }
2165
2299
  });
2300
+ case "estimate_depth":
2301
+ return provider.estimateDepth(params.image, {
2302
+ model: { id: req.model, name: req.model, provider: req.provider },
2303
+ signal: isAbortSignal(params.signal) ? params.signal : this.signal
2304
+ });
2305
+ case "rerank":
2306
+ return provider.rerank({
2307
+ model: req.model,
2308
+ query: isString(params.query) ? params.query : "",
2309
+ // Every entry stays, so result indices point into the caller's list.
2310
+ documents: Array.isArray(params.documents)
2311
+ ? params.documents.map((doc) => (isString(doc) ? doc : String(doc)))
2312
+ : [],
2313
+ topK: isNumber(params.top_k) ? params.top_k : undefined,
2314
+ signal: isAbortSignal(params.signal) ? params.signal : this.signal
2315
+ });
2166
2316
  case "track_object": {
2167
2317
  const request = objectTrackingRequestSchema.parse(params);
2168
2318
  if (!provider.getCapabilities().includes("track_object")) {
@@ -2175,12 +2325,18 @@ export class ProcessingContext {
2175
2325
  throw new Error("The tracking source video could not be loaded.");
2176
2326
  }
2177
2327
  signal.throwIfAborted();
2178
- const output = await provider.trackObject(video, { ...request, model: req.model, signal });
2328
+ const output = await provider.trackObject(video, {
2329
+ ...request,
2330
+ model: req.model,
2331
+ signal
2332
+ });
2179
2333
  signal.throwIfAborted();
2180
2334
  return parseObjectTrackingResult(output, request);
2181
2335
  }
2182
2336
  case "video_to_video": {
2183
- const signal = isAbortSignal(params.signal) ? params.signal : this.signal;
2337
+ const signal = isAbortSignal(params.signal)
2338
+ ? params.signal
2339
+ : this.signal;
2184
2340
  const referenceImages = coerceByteList(params.reference_images ?? params.referenceImages);
2185
2341
  const referenceAssetIds = coerceStringList(params.reference_asset_ids ?? params.referenceAssetIds);
2186
2342
  signal.throwIfAborted();
@@ -2378,137 +2534,174 @@ export class ProcessingContext {
2378
2534
  */
2379
2535
  async runGenerationWith(req, call, opts) {
2380
2536
  const id = req.id ?? randomUUID();
2381
- const startedAt = Date.now();
2382
- const origin = this.generationOrigin(req, req.origin);
2383
- const controller = new AbortController();
2384
- const signals = [controller.signal, this.signal];
2385
- if (req.signal)
2386
- signals.push(req.signal);
2387
- const signal = AbortSignal.any(signals);
2388
- const accept = opts?.onGenerationAccepted ??
2389
- this._generationLifecycle?.onGenerationAccepted;
2390
- const terminal = opts?.onGenerationTerminal ??
2391
- this._generationLifecycle?.onGenerationTerminal;
2392
- let durableAccepted = false;
2393
- let terminalAttempted = false;
2394
- try {
2395
- const accepted = await accept?.({ generationId: id, request: req });
2396
- if (accepted?.skipProvider) {
2397
- throw new GenerationAlreadyAcceptedError(accepted.existingGenerationId ?? id);
2398
- }
2399
- durableAccepted = accepted?.durable === true;
2400
- generationRegistry.register(id, {
2401
- userId: this.userId,
2402
- abort: () => controller.abort(new Error("Generation cancelled"))
2403
- });
2404
- this.emitPrediction("running", req, id, null, undefined, startedAt, {
2405
- origin
2406
- });
2407
- const provider = opts?.withoutProvider
2408
- ? null
2409
- : await this.getProvider(req.provider);
2410
- const { value: output, receipt: recorded, providerResult } = await runWithGenerationReceipt(() => call(provider, signal), {
2411
- providerRequestOptions: accepted ?? undefined,
2412
- onProviderRequestAccepted: opts?.onProviderRequestAccepted ??
2413
- this._generationLifecycle?.onProviderRequestAccepted,
2414
- onProviderRequestBound: opts?.onProviderRequestBound ??
2415
- this._generationLifecycle?.onProviderRequestBound
2416
- });
2417
- const encoded = encodedAudioOf(output);
2418
- const persistedAssets = req.persist
2419
- ? await this.persistGenerationBytes(id, req, encoded ? [encoded.data] : mediaBuffers(output), encoded?.mimeType)
2420
- : [];
2421
- const assets = persistedAssets.filter((asset) => asset !== null);
2422
- const late = opts?.receiptAfterPersist?.() ?? null;
2423
- const receipt = late || recorded ? { ...(recorded ?? {}), ...(late ?? {}) } : null;
2424
- const assetIds = assets
2425
- .map((asset) => asset.asset_id)
2426
- .filter((assetId) => typeof assetId === "string");
2427
- const durableAssetIds = persistedAssets.map((asset) => asset?.asset_id ?? null);
2537
+ return withSpan("generation", { "generation.id": id, "generation.provider": req.provider, "generation.kind": req.capability }, async () => {
2538
+ const startedAt = Date.now();
2539
+ const origin = this.generationOrigin(req, req.origin);
2540
+ const controller = new AbortController();
2541
+ const signals = [controller.signal, this.signal];
2542
+ if (req.signal)
2543
+ signals.push(req.signal);
2544
+ const signal = AbortSignal.any(signals);
2545
+ const accept = opts?.onGenerationAccepted ??
2546
+ this._generationLifecycle?.onGenerationAccepted;
2547
+ const terminal = opts?.onGenerationTerminal ??
2548
+ this._generationLifecycle?.onGenerationTerminal;
2549
+ let durableAccepted = false;
2550
+ let terminalAttempted = false;
2428
2551
  try {
2429
- terminalAttempted = true;
2430
- await terminal?.({
2431
- generationId: id,
2432
- request: req,
2433
- status: "completed",
2434
- output: providerResult ?? output,
2435
- receipt,
2436
- assetIds: durableAssetIds
2552
+ const accepted = await accept?.({ generationId: id, request: req });
2553
+ if (accepted?.skipProvider) {
2554
+ throw new GenerationAlreadyAcceptedError(accepted.existingGenerationId ?? id);
2555
+ }
2556
+ durableAccepted = accepted?.durable === true;
2557
+ generationRegistry.register(id, {
2558
+ userId: this.userId,
2559
+ abort: () => controller.abort(new Error("Generation cancelled"))
2437
2560
  });
2438
- }
2439
- catch (terminalError) {
2440
- this.emit({
2441
- type: "log_update",
2442
- node_id: req.nodeId ?? "",
2443
- node_name: req.nodeId ?? "",
2444
- workflow_id: req.workflowId ?? this.workflowId ?? null,
2445
- severity: "warning",
2446
- content: `Generation ${id} completed but durable finalization will be recovered: ${terminalError instanceof Error ? terminalError.message : String(terminalError)}`
2561
+ this.emitPrediction("running", req, id, null, undefined, startedAt, {
2562
+ origin
2447
2563
  });
2448
- }
2449
- this.emitPrediction("completed", req, id, generationResultData(req.capability, output), undefined, startedAt, { origin, asset_ids: assetIds, receipt });
2450
- generationRegistry.settle(id, {
2451
- status: "completed",
2452
- asset_ids: assetIds,
2453
- receipt
2454
- });
2455
- return {
2456
- id,
2457
- output,
2458
- assets,
2459
- receipt,
2460
- duration_ms: Date.now() - startedAt
2461
- };
2462
- }
2463
- catch (error) {
2464
- const cause = error instanceof GenerationScopeError ? error.cause : error;
2465
- const receipt = error instanceof GenerationScopeError ? error.receipt : null;
2466
- const providerResult = error instanceof GenerationScopeError
2467
- ? error.providerResult
2468
- : undefined;
2469
- const message = cause instanceof Error ? cause.message : String(cause);
2470
- if (cause instanceof GenerationAlreadyAcceptedError) {
2471
- throw cause;
2472
- }
2473
- const status = signal.aborted
2474
- ? durableAccepted
2475
- ? "running"
2476
- : "cancelled"
2477
- : durableAccepted && !isAuthoritativeProviderTerminalError(cause)
2478
- ? "running"
2479
- : "failed";
2480
- if (durableAccepted && !terminalAttempted) {
2564
+ const provider = opts?.withoutProvider
2565
+ ? null
2566
+ : await this.getProvider(req.provider);
2567
+ const { value: output, receipt: recorded, providerResult } = await runWithGenerationReceipt(() => call(provider, signal), {
2568
+ providerRequestOptions: accepted ?? undefined,
2569
+ onProviderRequestAccepted: opts?.onProviderRequestAccepted ??
2570
+ this._generationLifecycle?.onProviderRequestAccepted,
2571
+ onProviderRequestBound: opts?.onProviderRequestBound ??
2572
+ this._generationLifecycle?.onProviderRequestBound
2573
+ });
2574
+ const encoded = encodedAudioOf(output);
2575
+ const persistedAssets = req.persist
2576
+ ? await this.persistGenerationBytes(id, req, encoded ? [encoded.data] : mediaBuffers(output), encoded?.mimeType)
2577
+ : [];
2578
+ const assets = persistedAssets.filter((asset) => asset !== null);
2579
+ let delivery;
2580
+ if (opts?.finalizeOutput) {
2581
+ try {
2582
+ delivery = await opts.finalizeOutput(output, assets);
2583
+ }
2584
+ catch (error) {
2585
+ delivery = {
2586
+ status: "failed",
2587
+ error: error instanceof Error ? error.message : String(error)
2588
+ };
2589
+ }
2590
+ }
2591
+ const deliveryFields = {};
2592
+ if (delivery) {
2593
+ deliveryFields.delivery = delivery;
2594
+ }
2595
+ const late = opts?.receiptAfterPersist?.() ?? null;
2596
+ const receipt = late || recorded ? { ...(recorded ?? {}), ...(late ?? {}) } : null;
2597
+ const assetIds = assets
2598
+ .map((asset) => asset.asset_id)
2599
+ .filter((assetId) => typeof assetId === "string");
2600
+ const durableAssetIds = persistedAssets.map((asset) => asset?.asset_id ?? null);
2481
2601
  try {
2482
2602
  terminalAttempted = true;
2483
2603
  await terminal?.({
2484
2604
  generationId: id,
2485
2605
  request: req,
2486
- status: isAuthoritativeProviderTerminalError(cause)
2487
- ? "failed"
2488
- : "recovering",
2489
- output: providerResult,
2490
- error: message,
2606
+ status: "completed",
2607
+ output: providerResult ?? output,
2491
2608
  receipt,
2492
- assetIds: []
2609
+ assetIds: durableAssetIds,
2610
+ ...deliveryFields
2493
2611
  });
2494
2612
  }
2495
- catch {
2496
- // The provider observation remains authoritative. The durable row
2497
- // can be finalized by the recovery worker.
2613
+ catch (terminalError) {
2614
+ this.emit({
2615
+ type: "log_update",
2616
+ node_id: req.nodeId ?? "",
2617
+ node_name: req.nodeId ?? "",
2618
+ workflow_id: req.workflowId ?? this.workflowId ?? null,
2619
+ severity: "warning",
2620
+ content: `Generation ${id} completed but durable finalization will be recovered: ${terminalError instanceof Error ? terminalError.message : String(terminalError)}`
2621
+ });
2498
2622
  }
2623
+ this.emitPrediction("completed", req, id, delivery ? { delivery } : generationResultData(req.capability, output), undefined, startedAt, { origin, asset_ids: assetIds, receipt });
2624
+ generationRegistry.settle(id, {
2625
+ status: "completed",
2626
+ asset_ids: assetIds,
2627
+ receipt,
2628
+ ...deliveryFields
2629
+ });
2630
+ return {
2631
+ id,
2632
+ output,
2633
+ assets,
2634
+ receipt,
2635
+ duration_ms: Date.now() - startedAt,
2636
+ ...deliveryFields
2637
+ };
2499
2638
  }
2500
- this.emitPrediction(status, req, id, null, message, startedAt, {
2501
- origin,
2502
- receipt
2503
- });
2504
- generationRegistry.settle(id, {
2505
- status,
2506
- error: message,
2507
- asset_ids: [],
2508
- receipt
2509
- });
2510
- throw cause;
2511
- }
2639
+ catch (error) {
2640
+ const cause = error instanceof GenerationScopeError ? error.cause : error;
2641
+ const receipt = error instanceof GenerationScopeError ? error.receipt : null;
2642
+ const providerResult = error instanceof GenerationScopeError
2643
+ ? error.providerResult
2644
+ : undefined;
2645
+ const message = cause instanceof Error ? cause.message : String(cause);
2646
+ if (cause instanceof GenerationAlreadyAcceptedError) {
2647
+ throw cause;
2648
+ }
2649
+ const status = signal.aborted
2650
+ ? durableAccepted
2651
+ ? "running"
2652
+ : "cancelled"
2653
+ : durableAccepted && !isAuthoritativeProviderTerminalError(cause)
2654
+ ? "running"
2655
+ : "failed";
2656
+ if (durableAccepted && !terminalAttempted) {
2657
+ try {
2658
+ terminalAttempted = true;
2659
+ await terminal?.({
2660
+ generationId: id,
2661
+ request: req,
2662
+ status: isAuthoritativeProviderTerminalError(cause)
2663
+ ? "failed"
2664
+ : "recovering",
2665
+ output: providerResult,
2666
+ error: message,
2667
+ receipt,
2668
+ assetIds: []
2669
+ });
2670
+ }
2671
+ catch {
2672
+ // The provider observation remains authoritative. The durable row
2673
+ // can be finalized by the recovery worker.
2674
+ }
2675
+ }
2676
+ if (this.appRunContext && !durableAccepted && !terminalAttempted) {
2677
+ try {
2678
+ terminalAttempted = true;
2679
+ await terminal?.({
2680
+ generationId: id,
2681
+ request: req,
2682
+ status: signal.aborted ? "cancelled" : "failed",
2683
+ error: message,
2684
+ receipt,
2685
+ assetIds: []
2686
+ });
2687
+ }
2688
+ catch {
2689
+ // Preserve the provider failure; the live ledger can retry its write.
2690
+ }
2691
+ }
2692
+ this.emitPrediction(status, req, id, null, message, startedAt, {
2693
+ origin,
2694
+ receipt
2695
+ });
2696
+ generationRegistry.settle(id, {
2697
+ status,
2698
+ error: message,
2699
+ asset_ids: [],
2700
+ receipt
2701
+ });
2702
+ throw cause;
2703
+ }
2704
+ });
2512
2705
  }
2513
2706
  /**
2514
2707
  * Save a generation's media output as assets, stamping the generation id
@@ -2763,6 +2956,22 @@ export class ProcessingContext {
2763
2956
  // retried by the recovery worker.
2764
2957
  }
2765
2958
  }
2959
+ if (this.appRunContext && !durableAccepted && !terminalAttempted) {
2960
+ try {
2961
+ terminalAttempted = true;
2962
+ await terminal?.({
2963
+ generationId: id,
2964
+ request: req,
2965
+ status: signal.aborted ? "cancelled" : "failed",
2966
+ error: message,
2967
+ receipt,
2968
+ assetIds: []
2969
+ });
2970
+ }
2971
+ catch {
2972
+ // Preserve the provider failure; the live ledger can retry its write.
2973
+ }
2974
+ }
2766
2975
  this.emitPrediction(status, req, id, null, message, startedAt, {
2767
2976
  origin,
2768
2977
  receipt