@pikku/core 0.11.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (363) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/dist/crypto-utils.d.ts +2 -0
  3. package/dist/crypto-utils.js +78 -0
  4. package/dist/errors/error-handler.js +3 -3
  5. package/dist/errors/errors.d.ts +8 -0
  6. package/dist/errors/errors.js +16 -0
  7. package/dist/errors/index.d.ts +0 -1
  8. package/dist/errors/index.js +0 -1
  9. package/dist/function/function-runner.d.ts +10 -3
  10. package/dist/function/function-runner.js +136 -31
  11. package/dist/function/functions.types.d.ts +35 -12
  12. package/dist/function/functions.types.js +16 -6
  13. package/dist/function/index.d.ts +2 -2
  14. package/dist/function/index.js +1 -2
  15. package/dist/handle-error.js +1 -10
  16. package/dist/index.d.ts +30 -24
  17. package/dist/index.js +19 -27
  18. package/dist/middleware/auth-apikey.d.ts +1 -1
  19. package/dist/middleware/auth-apikey.js +3 -3
  20. package/dist/middleware/auth-bearer.d.ts +1 -1
  21. package/dist/middleware/auth-bearer.js +3 -6
  22. package/dist/middleware/auth-cookie.d.ts +1 -1
  23. package/dist/middleware/auth-cookie.js +6 -8
  24. package/dist/middleware/cors.d.ts +46 -0
  25. package/dist/middleware/cors.js +73 -0
  26. package/dist/middleware/index.d.ts +5 -3
  27. package/dist/middleware/index.js +5 -3
  28. package/dist/middleware/remote-auth.d.ts +5 -0
  29. package/dist/middleware/remote-auth.js +55 -0
  30. package/dist/middleware/timeout.d.ts +1 -1
  31. package/dist/middleware-runner.d.ts +3 -14
  32. package/dist/middleware-runner.js +14 -16
  33. package/dist/permissions.d.ts +3 -86
  34. package/dist/permissions.js +20 -80
  35. package/dist/pikku-state.d.ts +33 -104
  36. package/dist/pikku-state.js +150 -66
  37. package/dist/schema.d.ts +8 -6
  38. package/dist/schema.js +31 -18
  39. package/dist/services/ai-agent-runner-service.d.ts +24 -0
  40. package/dist/services/ai-agent-runner-service.js +1 -0
  41. package/dist/services/ai-run-state-service.d.ts +13 -0
  42. package/dist/services/ai-run-state-service.js +1 -0
  43. package/dist/services/ai-storage-service.d.ts +18 -0
  44. package/dist/services/ai-storage-service.js +1 -0
  45. package/dist/services/deployment-service.d.ts +19 -0
  46. package/dist/services/deployment-service.js +1 -0
  47. package/dist/services/gopass-secrets.d.ts +47 -0
  48. package/dist/services/gopass-secrets.js +94 -0
  49. package/dist/services/in-memory-trigger-service.d.ts +23 -0
  50. package/dist/services/in-memory-trigger-service.js +50 -0
  51. package/dist/services/in-memory-workflow-service.d.ts +59 -0
  52. package/dist/services/in-memory-workflow-service.js +287 -0
  53. package/dist/services/index.d.ts +25 -11
  54. package/dist/services/index.js +10 -13
  55. package/dist/services/local-secrets.d.ts +23 -0
  56. package/dist/services/local-secrets.js +45 -0
  57. package/dist/services/local-variables.d.ts +5 -0
  58. package/dist/services/local-variables.js +18 -0
  59. package/dist/services/scheduler-service.d.ts +21 -1
  60. package/dist/services/scheduler-service.js +14 -0
  61. package/dist/services/schema-service.d.ts +6 -0
  62. package/dist/services/scoped-secret-service.d.ts +16 -0
  63. package/dist/services/scoped-secret-service.js +35 -0
  64. package/dist/services/secret-service.d.ts +25 -4
  65. package/dist/services/trigger-service.d.ts +23 -0
  66. package/dist/services/trigger-service.js +1 -0
  67. package/dist/services/typed-secret-service.d.ts +30 -0
  68. package/dist/services/typed-secret-service.js +40 -0
  69. package/dist/services/typed-variables-service.d.ts +27 -0
  70. package/dist/services/typed-variables-service.js +46 -0
  71. package/dist/services/user-session-service.d.ts +13 -0
  72. package/dist/services/user-session-service.js +17 -0
  73. package/dist/services/variables-service.d.ts +5 -0
  74. package/dist/services/workflow-service.d.ts +43 -0
  75. package/dist/services/workflow-service.js +1 -0
  76. package/dist/types/core.types.d.ts +54 -10
  77. package/dist/types/core.types.js +7 -0
  78. package/dist/types/state.types.d.ts +127 -0
  79. package/dist/types/state.types.js +1 -0
  80. package/dist/utils.d.ts +10 -1
  81. package/dist/utils.js +60 -3
  82. package/dist/version.d.ts +6 -0
  83. package/dist/version.js +19 -0
  84. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +29 -0
  85. package/dist/wirings/ai-agent/ai-agent-memory.js +199 -0
  86. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +9 -0
  87. package/dist/wirings/ai-agent/ai-agent-model-config.js +36 -0
  88. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +60 -0
  89. package/dist/wirings/ai-agent/ai-agent-prepare.js +312 -0
  90. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +15 -0
  91. package/dist/wirings/ai-agent/ai-agent-registry.js +47 -0
  92. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +3 -0
  93. package/dist/wirings/ai-agent/ai-agent-runner.js +96 -0
  94. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +11 -0
  95. package/dist/wirings/ai-agent/ai-agent-stream.js +503 -0
  96. package/dist/wirings/ai-agent/ai-agent.types.d.ts +254 -0
  97. package/dist/wirings/ai-agent/ai-agent.types.js +1 -0
  98. package/dist/wirings/ai-agent/index.d.ts +5 -0
  99. package/dist/wirings/ai-agent/index.js +4 -0
  100. package/dist/wirings/channel/channel-common.d.ts +7 -4
  101. package/dist/wirings/channel/channel-common.js +15 -8
  102. package/dist/wirings/channel/channel-handler.js +13 -4
  103. package/dist/wirings/channel/channel-middleware-runner.d.ts +9 -0
  104. package/dist/wirings/channel/channel-middleware-runner.js +73 -0
  105. package/dist/wirings/channel/channel-runner.js +12 -12
  106. package/dist/wirings/channel/channel.types.d.ts +5 -1
  107. package/dist/wirings/channel/define-channel-routes.d.ts +21 -0
  108. package/dist/wirings/channel/define-channel-routes.js +23 -0
  109. package/dist/wirings/channel/index.d.ts +10 -8
  110. package/dist/wirings/channel/index.js +7 -8
  111. package/dist/wirings/channel/local/index.d.ts +3 -3
  112. package/dist/wirings/channel/local/index.js +3 -3
  113. package/dist/wirings/channel/local/local-channel-runner.js +18 -6
  114. package/dist/wirings/channel/log-channels.js +1 -1
  115. package/dist/wirings/channel/serverless/index.d.ts +1 -1
  116. package/dist/wirings/channel/serverless/index.js +1 -1
  117. package/dist/wirings/channel/serverless/serverless-channel-runner.js +17 -6
  118. package/dist/wirings/cli/channel/cli-channel-runner.js +3 -2
  119. package/dist/wirings/cli/channel/index.d.ts +1 -1
  120. package/dist/wirings/cli/channel/index.js +1 -1
  121. package/dist/wirings/cli/cli-runner.d.ts +1 -1
  122. package/dist/wirings/cli/cli-runner.js +22 -18
  123. package/dist/wirings/cli/cli.types.d.ts +7 -6
  124. package/dist/wirings/cli/define-cli-commands.d.ts +19 -0
  125. package/dist/wirings/cli/define-cli-commands.js +20 -0
  126. package/dist/wirings/cli/index.d.ts +2 -3
  127. package/dist/wirings/cli/index.js +1 -3
  128. package/dist/wirings/http/http-routes.d.ts +69 -0
  129. package/dist/wirings/http/http-routes.js +139 -0
  130. package/dist/wirings/http/http-runner.d.ts +2 -2
  131. package/dist/wirings/http/http-runner.js +62 -27
  132. package/dist/wirings/http/http.types.d.ts +77 -24
  133. package/dist/wirings/http/index.d.ts +5 -4
  134. package/dist/wirings/http/index.js +4 -3
  135. package/dist/wirings/http/log-http-routes.js +1 -1
  136. package/dist/wirings/http/routers/path-to-regex.js +2 -2
  137. package/dist/wirings/mcp/index.d.ts +4 -3
  138. package/dist/wirings/mcp/index.js +3 -3
  139. package/dist/wirings/mcp/mcp-runner.d.ts +1 -3
  140. package/dist/wirings/mcp/mcp-runner.js +42 -56
  141. package/dist/wirings/mcp/mcp.types.d.ts +3 -3
  142. package/dist/wirings/node/index.d.ts +2 -0
  143. package/dist/wirings/node/index.js +1 -0
  144. package/dist/wirings/node/node.types.d.ts +20 -0
  145. package/dist/wirings/node/node.types.js +1 -0
  146. package/dist/wirings/oauth2/index.d.ts +3 -0
  147. package/dist/wirings/oauth2/index.js +2 -0
  148. package/dist/wirings/oauth2/oauth2-client.d.ts +47 -0
  149. package/dist/wirings/oauth2/oauth2-client.js +267 -0
  150. package/dist/wirings/oauth2/oauth2.types.d.ts +65 -0
  151. package/dist/wirings/oauth2/oauth2.types.js +4 -0
  152. package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +20 -0
  153. package/dist/wirings/oauth2/wire-oauth2-credential.js +21 -0
  154. package/dist/wirings/queue/index.d.ts +2 -2
  155. package/dist/wirings/queue/index.js +1 -1
  156. package/dist/wirings/queue/queue-runner.d.ts +7 -0
  157. package/dist/wirings/queue/queue-runner.js +23 -12
  158. package/dist/wirings/queue/queue.types.d.ts +8 -2
  159. package/dist/wirings/rpc/index.d.ts +1 -1
  160. package/dist/wirings/rpc/index.js +1 -1
  161. package/dist/wirings/rpc/rpc-runner.d.ts +40 -13
  162. package/dist/wirings/rpc/rpc-runner.js +191 -25
  163. package/dist/wirings/rpc/rpc-types.d.ts +15 -4
  164. package/dist/wirings/scheduler/index.d.ts +3 -3
  165. package/dist/wirings/scheduler/index.js +2 -3
  166. package/dist/wirings/scheduler/log-schedulers.js +1 -1
  167. package/dist/wirings/scheduler/scheduler-runner.d.ts +5 -0
  168. package/dist/wirings/scheduler/scheduler-runner.js +28 -10
  169. package/dist/wirings/secret/index.d.ts +3 -0
  170. package/dist/wirings/secret/index.js +2 -0
  171. package/dist/wirings/secret/secret.types.d.ts +27 -0
  172. package/dist/wirings/secret/secret.types.js +1 -0
  173. package/dist/wirings/secret/validate-secret-definitions.d.ts +6 -0
  174. package/dist/wirings/secret/validate-secret-definitions.js +55 -0
  175. package/dist/wirings/trigger/index.d.ts +3 -0
  176. package/dist/wirings/trigger/index.js +2 -0
  177. package/dist/wirings/trigger/pikku-trigger-service.d.ts +26 -0
  178. package/dist/wirings/trigger/pikku-trigger-service.js +75 -0
  179. package/dist/wirings/trigger/trigger-runner.d.ts +42 -0
  180. package/dist/wirings/trigger/trigger-runner.js +85 -0
  181. package/dist/wirings/trigger/trigger.types.d.ts +130 -0
  182. package/dist/wirings/trigger/trigger.types.js +40 -0
  183. package/dist/wirings/variable/index.d.ts +3 -0
  184. package/dist/wirings/variable/index.js +2 -0
  185. package/dist/wirings/variable/validate-variable-definitions.d.ts +6 -0
  186. package/dist/wirings/variable/validate-variable-definitions.js +45 -0
  187. package/dist/wirings/variable/variable.types.d.ts +18 -0
  188. package/dist/wirings/variable/variable.types.js +1 -0
  189. package/dist/wirings/workflow/dsl/index.d.ts +5 -0
  190. package/dist/wirings/workflow/dsl/index.js +4 -0
  191. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +292 -0
  192. package/dist/wirings/workflow/dsl/workflow-dsl.types.js +5 -0
  193. package/dist/wirings/workflow/dsl/workflow-runner.d.ts +5 -0
  194. package/dist/wirings/workflow/dsl/workflow-runner.js +23 -0
  195. package/dist/wirings/workflow/graph/graph-node.d.ts +117 -0
  196. package/dist/wirings/workflow/graph/graph-node.js +58 -0
  197. package/dist/wirings/workflow/graph/graph-runner.d.ts +9 -0
  198. package/dist/wirings/workflow/graph/graph-runner.js +540 -0
  199. package/dist/wirings/workflow/graph/index.d.ts +4 -0
  200. package/dist/wirings/workflow/graph/index.js +3 -0
  201. package/dist/wirings/workflow/graph/template.d.ts +15 -0
  202. package/dist/wirings/workflow/graph/template.js +27 -0
  203. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +15 -0
  204. package/dist/wirings/workflow/graph/wire-workflow-graph.js +8 -0
  205. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +82 -0
  206. package/dist/wirings/workflow/graph/workflow-graph.types.js +15 -0
  207. package/dist/wirings/workflow/index.d.ts +7 -12
  208. package/dist/wirings/workflow/index.js +8 -11
  209. package/dist/wirings/workflow/pikku-workflow-service.d.ts +114 -10
  210. package/dist/wirings/workflow/pikku-workflow-service.js +386 -115
  211. package/dist/wirings/workflow/workflow-helpers.d.ts +36 -0
  212. package/dist/wirings/workflow/workflow-helpers.js +38 -0
  213. package/dist/wirings/workflow/workflow-utils.d.ts +1 -0
  214. package/dist/wirings/workflow/workflow-utils.js +1 -0
  215. package/dist/wirings/workflow/workflow.types.d.ts +83 -214
  216. package/package.json +13 -6
  217. package/run-tests.sh +4 -1
  218. package/src/crypto-utils.ts +99 -0
  219. package/src/errors/error-handler.ts +3 -3
  220. package/src/errors/errors.ts +17 -0
  221. package/src/errors/index.ts +0 -1
  222. package/src/factory-functions.test.ts +42 -2
  223. package/src/function/function-runner.test.ts +5 -12
  224. package/src/function/function-runner.ts +195 -40
  225. package/src/function/functions.types.ts +66 -14
  226. package/src/function/index.ts +5 -2
  227. package/src/handle-error.ts +2 -10
  228. package/src/index.ts +106 -27
  229. package/src/middleware/auth-apikey.test.ts +15 -12
  230. package/src/middleware/auth-apikey.ts +3 -3
  231. package/src/middleware/auth-bearer.test.ts +17 -14
  232. package/src/middleware/auth-bearer.ts +25 -27
  233. package/src/middleware/auth-cookie.test.ts +16 -13
  234. package/src/middleware/auth-cookie.ts +6 -8
  235. package/src/middleware/cors.ts +96 -0
  236. package/src/middleware/index.ts +5 -3
  237. package/src/middleware/remote-auth.ts +68 -0
  238. package/src/middleware-runner.test.ts +122 -0
  239. package/src/middleware-runner.ts +24 -17
  240. package/src/permissions.test.ts +102 -86
  241. package/src/permissions.ts +32 -93
  242. package/src/pikku-state.ts +168 -201
  243. package/src/run-tests-script.test.ts +49 -0
  244. package/src/schema.ts +50 -18
  245. package/src/services/ai-agent-runner-service.ts +29 -0
  246. package/src/services/ai-run-state-service.ts +20 -0
  247. package/src/services/ai-storage-service.ts +39 -0
  248. package/src/services/deployment-service.ts +22 -0
  249. package/src/services/gopass-secrets.ts +95 -0
  250. package/src/services/in-memory-trigger-service.ts +68 -0
  251. package/src/services/in-memory-workflow-service.ts +395 -0
  252. package/src/services/index.ts +49 -14
  253. package/src/services/local-secrets.ts +51 -0
  254. package/src/services/local-variables.ts +22 -0
  255. package/src/services/scheduler-service.ts +29 -1
  256. package/src/services/schema-service.ts +7 -0
  257. package/src/services/scoped-secret-service.ts +41 -0
  258. package/src/services/secret-service.ts +25 -4
  259. package/src/services/trigger-service.ts +38 -0
  260. package/src/services/typed-secret-service.ts +70 -0
  261. package/src/services/typed-variables-service.ts +81 -0
  262. package/src/services/user-session-service.ts +23 -0
  263. package/src/services/variables-service.ts +5 -0
  264. package/src/services/workflow-service.ts +94 -0
  265. package/src/types/core.types.ts +82 -8
  266. package/src/types/state.types.ts +169 -0
  267. package/src/utils.ts +74 -5
  268. package/src/version.test.ts +80 -0
  269. package/src/version.ts +25 -0
  270. package/src/wirings/ai-agent/ai-agent-memory.ts +300 -0
  271. package/src/wirings/ai-agent/ai-agent-model-config.ts +43 -0
  272. package/src/wirings/ai-agent/ai-agent-prepare.ts +470 -0
  273. package/src/wirings/ai-agent/ai-agent-registry.test.ts +37 -0
  274. package/src/wirings/ai-agent/ai-agent-registry.ts +82 -0
  275. package/src/wirings/ai-agent/ai-agent-runner.test.ts +75 -0
  276. package/src/wirings/ai-agent/ai-agent-runner.ts +137 -0
  277. package/src/wirings/ai-agent/ai-agent-stream.test.ts +246 -0
  278. package/src/wirings/ai-agent/ai-agent-stream.ts +774 -0
  279. package/src/wirings/ai-agent/ai-agent.types.ts +273 -0
  280. package/src/wirings/ai-agent/index.ts +28 -0
  281. package/src/wirings/channel/channel-common.ts +32 -19
  282. package/src/wirings/channel/channel-handler.ts +18 -5
  283. package/src/wirings/channel/channel-middleware-runner.ts +119 -0
  284. package/src/wirings/channel/channel-runner.ts +14 -15
  285. package/src/wirings/channel/channel.types.ts +17 -1
  286. package/src/wirings/channel/define-channel-routes.ts +25 -0
  287. package/src/wirings/channel/index.ts +23 -8
  288. package/src/wirings/channel/local/index.ts +3 -3
  289. package/src/wirings/channel/local/local-channel-runner.test.ts +47 -2
  290. package/src/wirings/channel/local/local-channel-runner.ts +22 -6
  291. package/src/wirings/channel/log-channels.ts +1 -1
  292. package/src/wirings/channel/serverless/index.ts +5 -1
  293. package/src/wirings/channel/serverless/serverless-channel-runner.ts +22 -6
  294. package/src/wirings/cli/channel/cli-channel-runner.ts +4 -3
  295. package/src/wirings/cli/channel/index.ts +1 -1
  296. package/src/wirings/cli/cli-runner.test.ts +28 -28
  297. package/src/wirings/cli/cli-runner.ts +27 -19
  298. package/src/wirings/cli/cli.types.ts +12 -11
  299. package/src/wirings/cli/command-parser.test.ts +8 -8
  300. package/src/wirings/cli/define-cli-commands.ts +24 -0
  301. package/src/wirings/cli/index.ts +10 -4
  302. package/src/wirings/http/http-routes.test.ts +322 -0
  303. package/src/wirings/http/http-routes.ts +198 -0
  304. package/src/wirings/http/http-runner.test.ts +5 -5
  305. package/src/wirings/http/http-runner.ts +80 -29
  306. package/src/wirings/http/http.types.ts +121 -23
  307. package/src/wirings/http/index.ts +16 -4
  308. package/src/wirings/http/log-http-routes.ts +1 -1
  309. package/src/wirings/http/routers/path-to-regex.test.ts +30 -19
  310. package/src/wirings/http/routers/path-to-regex.ts +2 -2
  311. package/src/wirings/mcp/index.ts +27 -3
  312. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +3 -3
  313. package/src/wirings/mcp/mcp-runner.ts +56 -67
  314. package/src/wirings/mcp/mcp.types.ts +3 -3
  315. package/src/wirings/node/index.ts +2 -0
  316. package/src/wirings/node/node.types.ts +23 -0
  317. package/src/wirings/oauth2/index.ts +3 -0
  318. package/src/wirings/oauth2/oauth2-client.test.ts +929 -0
  319. package/src/wirings/oauth2/oauth2-client.ts +335 -0
  320. package/src/wirings/oauth2/oauth2.types.ts +69 -0
  321. package/src/wirings/oauth2/wire-oauth2-credential.ts +23 -0
  322. package/src/wirings/queue/index.ts +14 -2
  323. package/src/wirings/queue/queue-runner.test.ts +115 -73
  324. package/src/wirings/queue/queue-runner.ts +39 -13
  325. package/src/wirings/queue/queue.types.ts +12 -2
  326. package/src/wirings/rpc/index.ts +1 -1
  327. package/src/wirings/rpc/rpc-runner.ts +270 -34
  328. package/src/wirings/rpc/rpc-types.ts +21 -4
  329. package/src/wirings/scheduler/index.ts +7 -4
  330. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  331. package/src/wirings/scheduler/scheduler-runner.test.ts +97 -53
  332. package/src/wirings/scheduler/scheduler-runner.ts +50 -10
  333. package/src/wirings/secret/index.ts +9 -0
  334. package/src/wirings/secret/secret.types.ts +32 -0
  335. package/src/wirings/secret/validate-secret-definitions.ts +82 -0
  336. package/src/wirings/trigger/index.ts +10 -0
  337. package/src/wirings/trigger/pikku-trigger-service.ts +134 -0
  338. package/src/wirings/trigger/trigger-runner.ts +138 -0
  339. package/src/wirings/trigger/trigger.types.ts +178 -0
  340. package/src/wirings/variable/index.ts +8 -0
  341. package/src/wirings/variable/validate-variable-definitions.ts +69 -0
  342. package/src/wirings/variable/variable.types.ts +22 -0
  343. package/src/wirings/workflow/dsl/index.ts +31 -0
  344. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +320 -0
  345. package/src/wirings/workflow/dsl/workflow-runner.ts +28 -0
  346. package/src/wirings/workflow/graph/graph-node.ts +222 -0
  347. package/src/wirings/workflow/graph/graph-runner.test.ts +495 -0
  348. package/src/wirings/workflow/graph/graph-runner.ts +816 -0
  349. package/src/wirings/workflow/graph/index.ts +14 -0
  350. package/src/wirings/workflow/graph/template.ts +42 -0
  351. package/src/wirings/workflow/graph/wire-workflow-graph.ts +29 -0
  352. package/src/wirings/workflow/graph/workflow-graph.types.ts +104 -0
  353. package/src/wirings/workflow/index.ts +64 -26
  354. package/src/wirings/workflow/pikku-workflow-service.test.ts +212 -0
  355. package/src/wirings/workflow/pikku-workflow-service.ts +571 -136
  356. package/src/wirings/workflow/workflow-helpers.ts +79 -0
  357. package/src/wirings/workflow/workflow-utils.ts +0 -0
  358. package/src/wirings/workflow/workflow.types.ts +123 -279
  359. package/tsconfig.tsbuildinfo +1 -1
  360. package/dist/wirings/workflow/workflow-runner.d.ts +0 -34
  361. package/dist/wirings/workflow/workflow-runner.js +0 -65
  362. package/src/function/function-runner.ts.bak +0 -188
  363. package/src/wirings/workflow/workflow-runner.ts +0 -72
@@ -0,0 +1,774 @@
1
+ import type {
2
+ AIStreamChannel,
3
+ AIStreamEvent,
4
+ AIMessage,
5
+ AIToolCall,
6
+ AIToolResult,
7
+ PikkuAIMiddlewareHooks,
8
+ AgentRunState,
9
+ CoreAIAgent,
10
+ AIAgentMemoryConfig,
11
+ } from './ai-agent.types.js'
12
+ import { pikkuState } from '../../pikku-state.js'
13
+ import {
14
+ combineChannelMiddleware,
15
+ wrapChannelWithMiddleware,
16
+ } from '../channel/channel-middleware-runner.js'
17
+ import { randomUUID } from 'crypto'
18
+ import type { AIStorageService } from '../../services/ai-storage-service.js'
19
+
20
+ import {
21
+ parseWorkingMemory,
22
+ deepMergeWorkingMemory,
23
+ resolveMemoryServices,
24
+ loadContextMessages,
25
+ trimMessages,
26
+ } from './ai-agent-memory.js'
27
+ import {
28
+ prepareAgentRun,
29
+ resolveAgent,
30
+ buildInstructions,
31
+ buildToolDefs,
32
+ createScopedChannel,
33
+ ToolApprovalRequired,
34
+ type RunAIAgentParams,
35
+ type StreamAIAgentOptions,
36
+ type StreamContext,
37
+ } from './ai-agent-prepare.js'
38
+ import { resolveModelConfig } from './ai-agent-model-config.js'
39
+ import type { AIRunStateService } from '../../services/ai-run-state-service.js'
40
+ import type { AIAgentRunnerService } from '../../services/ai-agent-runner-service.js'
41
+
42
+ type PersistingChannel = AIStreamChannel & {
43
+ fullText: string
44
+ flush: () => Promise<void>
45
+ }
46
+
47
+ function createPersistingChannel(
48
+ parent: AIStreamChannel,
49
+ storage: AIStorageService | undefined,
50
+ threadId: string
51
+ ): PersistingChannel {
52
+ let fullText = ''
53
+ let stepText = ''
54
+ let stepToolCalls: AIToolCall[] = []
55
+ let stepToolResults: AIToolResult[] = []
56
+
57
+ const flushStep = async () => {
58
+ if (!storage) return
59
+ const text = stepText
60
+ const calls = stepToolCalls
61
+ const results = stepToolResults
62
+ stepText = ''
63
+ stepToolCalls = []
64
+ stepToolResults = []
65
+ if (text || calls.length > 0) {
66
+ const assistantMsg: AIMessage = {
67
+ id: randomUUID(),
68
+ role: 'assistant',
69
+ content: text || undefined,
70
+ toolCalls: calls.length > 0 ? calls : undefined,
71
+ createdAt: new Date(),
72
+ }
73
+ const messages: AIMessage[] = [assistantMsg]
74
+ if (results.length > 0) {
75
+ messages.push({
76
+ id: randomUUID(),
77
+ role: 'tool',
78
+ toolResults: results,
79
+ createdAt: new Date(),
80
+ })
81
+ }
82
+ await storage.saveMessages(threadId, messages)
83
+ }
84
+ }
85
+
86
+ const channel: PersistingChannel = {
87
+ channelId: parent.channelId,
88
+ openingData: parent.openingData,
89
+ get state() {
90
+ return parent.state
91
+ },
92
+ get fullText() {
93
+ return fullText
94
+ },
95
+ flush: flushStep,
96
+ close: () => parent.close(),
97
+ send: (event: AIStreamEvent) => {
98
+ if (storage) {
99
+ switch (event.type) {
100
+ case 'text-delta':
101
+ stepText += event.text
102
+ fullText += event.text
103
+ break
104
+ case 'tool-call':
105
+ stepToolCalls.push({
106
+ id: event.toolCallId,
107
+ name: event.toolName,
108
+ args: event.args as Record<string, unknown>,
109
+ })
110
+ break
111
+ case 'tool-result':
112
+ stepToolResults.push({
113
+ id: event.toolCallId,
114
+ name: event.toolName,
115
+ result:
116
+ typeof event.result === 'string'
117
+ ? event.result
118
+ : JSON.stringify(event.result),
119
+ })
120
+ break
121
+ case 'usage':
122
+ flushStep()
123
+ break
124
+ case 'done':
125
+ flushStep()
126
+ break
127
+ }
128
+ }
129
+ parent.send(event)
130
+ },
131
+ }
132
+ return channel
133
+ }
134
+
135
+ async function postStreamCleanup(
136
+ persistingChannel: PersistingChannel,
137
+ aiMiddlewares: PikkuAIMiddlewareHooks[],
138
+ singletonServices: any,
139
+ storage: AIStorageService | undefined,
140
+ memoryConfig: any,
141
+ threadId: string,
142
+ workingMemorySchemaName: string | null,
143
+ messages: AIMessage[],
144
+ aiRunState: AIRunStateService,
145
+ runId: string
146
+ ): Promise<void> {
147
+ let outputText = persistingChannel.fullText
148
+ let outputMessages = messages
149
+ for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
150
+ const mw = aiMiddlewares[i]
151
+ if (mw.modifyOutput) {
152
+ const result = await mw.modifyOutput(singletonServices, {
153
+ text: outputText,
154
+ messages: outputMessages,
155
+ usage: { inputTokens: 0, outputTokens: 0 },
156
+ })
157
+ outputText = result.text
158
+ outputMessages = result.messages
159
+ }
160
+ }
161
+
162
+ if (storage && memoryConfig?.workingMemory && outputText) {
163
+ const parsed = parseWorkingMemory(outputText)
164
+ if (parsed) {
165
+ const existing =
166
+ (await storage.getWorkingMemory(threadId, 'thread')) ?? {}
167
+ const merged = deepMergeWorkingMemory(existing, parsed)
168
+
169
+ if (singletonServices.schema && workingMemorySchemaName) {
170
+ try {
171
+ await singletonServices.schema.validateSchema(
172
+ workingMemorySchemaName,
173
+ merged
174
+ )
175
+ } catch (err) {
176
+ singletonServices.logger.warn(
177
+ `Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`
178
+ )
179
+ }
180
+ }
181
+
182
+ await storage.saveWorkingMemory(threadId, 'thread', merged)
183
+ }
184
+ }
185
+
186
+ await aiRunState.updateRun(runId, { status: 'completed' })
187
+ }
188
+
189
+ export async function streamAIAgent(
190
+ agentName: string,
191
+ input: { message: string; threadId: string; resourceId: string },
192
+ channel: AIStreamChannel,
193
+ params: RunAIAgentParams,
194
+ agentSessionMap?: Map<string, string>,
195
+ options?: StreamAIAgentOptions
196
+ ): Promise<void> {
197
+ const sessionMap = agentSessionMap ?? new Map<string, string>()
198
+ const streamContext: StreamContext = { channel, options }
199
+
200
+ const {
201
+ agent,
202
+ packageName,
203
+ resolvedName,
204
+ agentRunner,
205
+ storage,
206
+ memoryConfig,
207
+ threadId,
208
+ userMessage,
209
+ runnerParams,
210
+ missingRpcs,
211
+ workingMemorySchemaName,
212
+ } = await prepareAgentRun(agentName, input, params, sessionMap, streamContext)
213
+
214
+ const { singletonServices } = params
215
+ const { aiRunState } = singletonServices
216
+ if (!aiRunState) {
217
+ throw new Error('AIRunStateService not available in singletonServices')
218
+ }
219
+
220
+ if (missingRpcs.length > 0) {
221
+ await aiRunState.createRun({
222
+ agentName,
223
+ threadId,
224
+ resourceId: input.resourceId,
225
+ status: 'suspended',
226
+ suspendReason: 'rpc-missing',
227
+ missingRpcs,
228
+ usage: { inputTokens: 0, outputTokens: 0, model: agent.model },
229
+ createdAt: new Date(),
230
+ updatedAt: new Date(),
231
+ })
232
+ channel.send({ type: 'suspended', reason: 'rpc-missing', missingRpcs })
233
+ channel.send({ type: 'done' })
234
+ return
235
+ }
236
+
237
+ const aiMiddlewares: PikkuAIMiddlewareHooks[] = agent.aiMiddleware ?? []
238
+
239
+ let modifiedMessages = runnerParams.messages
240
+ let modifiedInstructions = runnerParams.instructions
241
+ for (const mw of aiMiddlewares) {
242
+ if (mw.modifyInput) {
243
+ const result = await mw.modifyInput(singletonServices, {
244
+ messages: modifiedMessages,
245
+ instructions: modifiedInstructions,
246
+ })
247
+ modifiedMessages = result.messages
248
+ modifiedInstructions = result.instructions
249
+ }
250
+ }
251
+ runnerParams.messages = modifiedMessages
252
+ runnerParams.instructions = modifiedInstructions
253
+
254
+ const runId = await aiRunState.createRun({
255
+ agentName,
256
+ threadId,
257
+ resourceId: input.resourceId,
258
+ status: 'running',
259
+ usage: { inputTokens: 0, outputTokens: 0, model: agent.model },
260
+ createdAt: new Date(),
261
+ updatedAt: new Date(),
262
+ })
263
+
264
+ if (storage) {
265
+ await storage.saveMessages(threadId, [userMessage])
266
+ }
267
+
268
+ const streamMiddleware = aiMiddlewares
269
+ .filter((mw) => mw.modifyOutputStream)
270
+ .map((mw) => {
271
+ const state: Record<string, unknown> = {}
272
+ const allEvents: AIStreamEvent[] = []
273
+ return async (services: any, event: any, next: any) => {
274
+ allEvents.push(event)
275
+ const result = await mw.modifyOutputStream!(services, {
276
+ event,
277
+ allEvents,
278
+ state,
279
+ })
280
+ if (result != null) await next(result)
281
+ }
282
+ })
283
+
284
+ const agentsMeta = pikkuState(packageName, 'agent', 'agentsMeta')
285
+ const meta = agentsMeta[resolvedName]
286
+ const allChannelMiddleware = combineChannelMiddleware(
287
+ 'agent',
288
+ `stream:${agentName}`,
289
+ {
290
+ wireInheritedChannelMiddleware: meta?.channelMiddleware,
291
+ wireChannelMiddleware: [
292
+ ...((agent.channelMiddleware as any[]) ?? []),
293
+ ...streamMiddleware,
294
+ ],
295
+ }
296
+ )
297
+
298
+ const wrappedChannel =
299
+ allChannelMiddleware.length > 0
300
+ ? (wrapChannelWithMiddleware(
301
+ { channel },
302
+ singletonServices,
303
+ allChannelMiddleware
304
+ ).channel as AIStreamChannel)
305
+ : channel
306
+
307
+ const persistingChannel = createPersistingChannel(
308
+ wrappedChannel,
309
+ storage,
310
+ threadId
311
+ )
312
+
313
+ try {
314
+ await agentRunner.stream(runnerParams, persistingChannel)
315
+
316
+ await postStreamCleanup(
317
+ persistingChannel,
318
+ aiMiddlewares,
319
+ singletonServices,
320
+ storage,
321
+ memoryConfig,
322
+ threadId,
323
+ workingMemorySchemaName,
324
+ runnerParams.messages,
325
+ aiRunState,
326
+ runId
327
+ )
328
+ } catch (err) {
329
+ if (err instanceof ToolApprovalRequired) {
330
+ await persistingChannel.flush()
331
+
332
+ const pendingApproval = err.agentRunId
333
+ ? {
334
+ type: 'agent-call' as const,
335
+ toolCallId: err.toolCallId,
336
+ agentName: err.toolName,
337
+ agentRunId: err.agentRunId,
338
+ displayToolName: err.displayToolName ?? err.toolName,
339
+ displayArgs: err.displayArgs ?? err.args,
340
+ }
341
+ : {
342
+ type: 'tool-call' as const,
343
+ toolCallId: err.toolCallId,
344
+ toolName: err.toolName,
345
+ args: err.args,
346
+ }
347
+
348
+ await aiRunState.updateRun(runId, {
349
+ status: 'suspended',
350
+ suspendReason: 'approval',
351
+ pendingApprovals: [pendingApproval],
352
+ })
353
+
354
+ const approvalEvent = {
355
+ type: 'approval-request' as const,
356
+ toolCallId: err.toolCallId,
357
+ toolName: err.displayToolName ?? err.toolName,
358
+ args: err.displayArgs ?? err.args,
359
+ reason: err.reason,
360
+ runId,
361
+ }
362
+ channel.send(approvalEvent as any)
363
+ channel.send({ type: 'done' })
364
+ channel.close()
365
+ return
366
+ }
367
+
368
+ await aiRunState.updateRun(runId, { status: 'failed' })
369
+ channel.send({
370
+ type: 'error',
371
+ message: err instanceof Error ? err.message : String(err),
372
+ })
373
+ channel.send({ type: 'done' })
374
+ channel.close()
375
+ }
376
+ }
377
+
378
+ export async function resumeAIAgent(
379
+ input: {
380
+ toolCallId: string
381
+ approved: boolean
382
+ },
383
+ channel: AIStreamChannel,
384
+ params: RunAIAgentParams,
385
+ options?: StreamAIAgentOptions
386
+ ): Promise<void> {
387
+ const { singletonServices } = params
388
+ const { aiRunState } = singletonServices
389
+ if (!aiRunState) {
390
+ throw new Error('AIRunStateService not available in singletonServices')
391
+ }
392
+
393
+ const found = await aiRunState.findRunByToolCallId(input.toolCallId)
394
+ if (!found) {
395
+ throw new Error(`No suspended run found for toolCallId ${input.toolCallId}`)
396
+ }
397
+
398
+ const { run, approval: pending } = found
399
+
400
+ await aiRunState.resolveApproval(
401
+ input.toolCallId,
402
+ input.approved ? 'approved' : 'denied'
403
+ )
404
+
405
+ const { agent, packageName, resolvedName } = resolveAgent(run.agentName)
406
+ const { storage } = resolveMemoryServices(agent, singletonServices)
407
+ const memoryConfig = agent.memory
408
+ const agentRunner = singletonServices.aiAgentRunner
409
+ if (!agentRunner) {
410
+ throw new Error('AIAgentRunnerService not available in singletonServices')
411
+ }
412
+
413
+ if (!input.approved) {
414
+ if (pending.type === 'agent-call') {
415
+ await aiRunState.updateRun(pending.agentRunId, { status: 'failed' })
416
+ }
417
+
418
+ const denialResult = 'Tool call was not approved by the user'
419
+
420
+ if (storage) {
421
+ await storage.saveMessages(run.threadId, [
422
+ {
423
+ id: randomUUID(),
424
+ role: 'tool',
425
+ toolResults: [
426
+ {
427
+ id: input.toolCallId,
428
+ name:
429
+ pending.type === 'tool-call'
430
+ ? pending.toolName
431
+ : pending.agentName,
432
+ result: denialResult,
433
+ },
434
+ ],
435
+ createdAt: new Date(),
436
+ },
437
+ ])
438
+ }
439
+
440
+ await aiRunState.updateRun(run.runId, { status: 'running' })
441
+
442
+ await continueAfterToolResult(
443
+ run,
444
+ agent,
445
+ packageName,
446
+ resolvedName,
447
+ storage,
448
+ memoryConfig,
449
+ agentRunner,
450
+ channel,
451
+ params,
452
+ aiRunState,
453
+ options
454
+ )
455
+ return
456
+ }
457
+
458
+ if (pending.type === 'agent-call') {
459
+ const subRun = await aiRunState.getRun(pending.agentRunId)
460
+ if (!subRun) {
461
+ throw new Error(`Sub-agent run not found: ${pending.agentRunId}`)
462
+ }
463
+ const subPending = subRun.pendingApprovals?.[0]
464
+ if (!subPending) {
465
+ throw new Error(
466
+ `No pending approval on sub-agent run ${pending.agentRunId}`
467
+ )
468
+ }
469
+
470
+ const subChannel = createScopedChannel(channel, subRun.agentName, 'resume')
471
+ channel.send({
472
+ type: 'agent-call',
473
+ agentName: subRun.agentName,
474
+ session: 'resume',
475
+ input: null,
476
+ })
477
+
478
+ await resumeAIAgent(
479
+ { toolCallId: subPending.toolCallId, approved: true },
480
+ subChannel,
481
+ params,
482
+ options
483
+ )
484
+
485
+ channel.send({
486
+ type: 'agent-result',
487
+ agentName: subRun.agentName,
488
+ session: 'resume',
489
+ result: null,
490
+ })
491
+
492
+ if (storage) {
493
+ await storage.saveMessages(run.threadId, [
494
+ {
495
+ id: randomUUID(),
496
+ role: 'tool',
497
+ toolResults: [
498
+ {
499
+ id: input.toolCallId,
500
+ name: pending.agentName,
501
+ result: 'Sub-agent completed successfully',
502
+ },
503
+ ],
504
+ createdAt: new Date(),
505
+ },
506
+ ])
507
+ }
508
+ } else {
509
+ const streamContext: StreamContext = {
510
+ channel,
511
+ options: { ...options, requiresToolApproval: false },
512
+ }
513
+ const { tools } = buildToolDefs(
514
+ singletonServices,
515
+ params,
516
+ new Map<string, string>(),
517
+ run.resourceId,
518
+ resolvedName,
519
+ packageName,
520
+ streamContext
521
+ )
522
+
523
+ const matchingTool = tools.find((t) => t.name === pending.toolName)
524
+ if (!matchingTool) {
525
+ throw new Error(
526
+ `Tool "${pending.toolName}" not found in agent definition`
527
+ )
528
+ }
529
+
530
+ const toolArgs =
531
+ typeof pending.args === 'string' ? JSON.parse(pending.args) : pending.args
532
+ const { toolApprovalReason: _ignored, ...cleanArgs } = toolArgs as Record<
533
+ string,
534
+ unknown
535
+ >
536
+
537
+ let toolResult: unknown
538
+ try {
539
+ toolResult = await matchingTool.execute(cleanArgs)
540
+ } catch (execErr) {
541
+ toolResult = `Error: ${execErr instanceof Error ? execErr.message : String(execErr)}`
542
+ }
543
+
544
+ const resultStr =
545
+ typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult)
546
+ if (storage) {
547
+ await storage.saveMessages(run.threadId, [
548
+ {
549
+ id: randomUUID(),
550
+ role: 'tool',
551
+ toolResults: [
552
+ {
553
+ id: input.toolCallId,
554
+ name: pending.toolName,
555
+ result: resultStr,
556
+ },
557
+ ],
558
+ createdAt: new Date(),
559
+ },
560
+ ])
561
+ }
562
+
563
+ channel.send({
564
+ type: 'tool-result',
565
+ toolCallId: input.toolCallId,
566
+ toolName: pending.toolName,
567
+ result: toolResult,
568
+ })
569
+ }
570
+
571
+ await aiRunState.updateRun(run.runId, { status: 'running' })
572
+
573
+ await continueAfterToolResult(
574
+ run,
575
+ agent,
576
+ packageName,
577
+ resolvedName,
578
+ storage,
579
+ memoryConfig,
580
+ agentRunner,
581
+ channel,
582
+ params,
583
+ aiRunState,
584
+ options
585
+ )
586
+ }
587
+
588
+ async function continueAfterToolResult(
589
+ run: AgentRunState,
590
+ agent: CoreAIAgent,
591
+ packageName: string | null,
592
+ resolvedName: string,
593
+ storage: AIStorageService | undefined,
594
+ memoryConfig: AIAgentMemoryConfig | undefined,
595
+ agentRunner: AIAgentRunnerService,
596
+ channel: AIStreamChannel,
597
+ params: RunAIAgentParams,
598
+ aiRunState: AIRunStateService,
599
+ options?: StreamAIAgentOptions
600
+ ): Promise<void> {
601
+ const { singletonServices } = params
602
+ const agentsMeta = pikkuState(packageName, 'agent', 'agentsMeta')
603
+ const meta = agentsMeta[resolvedName]
604
+ const workingMemorySchemaName = meta?.workingMemorySchema ?? null
605
+
606
+ const messages = storage
607
+ ? await storage.getMessages(run.threadId, {
608
+ lastN: memoryConfig?.lastMessages ?? 20,
609
+ })
610
+ : []
611
+
612
+ const workingMemoryJsonSchema = workingMemorySchemaName
613
+ ? pikkuState(packageName, 'misc', 'schemas').get(workingMemorySchemaName)
614
+ : undefined
615
+
616
+ const contextMessages = await loadContextMessages(
617
+ memoryConfig,
618
+ storage,
619
+ { message: '', threadId: run.threadId, resourceId: run.resourceId },
620
+ workingMemoryJsonSchema
621
+ )
622
+
623
+ const allMessages = [...contextMessages, ...messages]
624
+ const trimmedMessages = trimMessages(allMessages)
625
+
626
+ const instructions = buildInstructions(resolvedName, packageName)
627
+
628
+ const aiMiddlewares: PikkuAIMiddlewareHooks[] = agent.aiMiddleware ?? []
629
+ let modifiedMessages = trimmedMessages
630
+ let modifiedInstructions = instructions
631
+ for (const mw of aiMiddlewares) {
632
+ if (mw.modifyInput) {
633
+ const result = await mw.modifyInput(singletonServices, {
634
+ messages: modifiedMessages,
635
+ instructions: modifiedInstructions,
636
+ })
637
+ modifiedMessages = result.messages
638
+ modifiedInstructions = result.instructions
639
+ }
640
+ }
641
+
642
+ const streamMiddleware = aiMiddlewares
643
+ .filter((mw) => mw.modifyOutputStream)
644
+ .map((mw) => {
645
+ const state: Record<string, unknown> = {}
646
+ const allEvents: AIStreamEvent[] = []
647
+ return async (services: any, event: any, next: any) => {
648
+ allEvents.push(event)
649
+ const result = await mw.modifyOutputStream!(services, {
650
+ event,
651
+ allEvents,
652
+ state,
653
+ })
654
+ if (result != null) await next(result)
655
+ }
656
+ })
657
+
658
+ const allChannelMiddleware = combineChannelMiddleware(
659
+ 'agent',
660
+ `stream:${run.agentName}`,
661
+ {
662
+ wireInheritedChannelMiddleware: meta?.channelMiddleware,
663
+ wireChannelMiddleware: [
664
+ ...((agent.channelMiddleware as any[]) ?? []),
665
+ ...streamMiddleware,
666
+ ],
667
+ }
668
+ )
669
+
670
+ const wrappedChannel =
671
+ allChannelMiddleware.length > 0
672
+ ? (wrapChannelWithMiddleware(
673
+ { channel },
674
+ singletonServices,
675
+ allChannelMiddleware
676
+ ).channel as AIStreamChannel)
677
+ : channel
678
+
679
+ const persistingChannel = createPersistingChannel(
680
+ wrappedChannel,
681
+ storage,
682
+ run.threadId
683
+ )
684
+
685
+ const streamContext: StreamContext = { channel, options }
686
+ const resumeTools = buildToolDefs(
687
+ singletonServices,
688
+ params,
689
+ new Map<string, string>(),
690
+ run.resourceId,
691
+ resolvedName,
692
+ packageName,
693
+ streamContext
694
+ ).tools
695
+
696
+ const resolved = resolveModelConfig(resolvedName, agent)
697
+
698
+ const runnerParams = {
699
+ model: resolved.model,
700
+ temperature: resolved.temperature,
701
+ instructions: modifiedInstructions,
702
+ messages: modifiedMessages,
703
+ tools: resumeTools,
704
+ maxSteps: resolved.maxSteps ?? 10,
705
+ toolChoice: (agent.toolChoice ?? 'auto') as 'auto' | 'required' | 'none',
706
+ outputSchema: meta?.outputSchema
707
+ ? pikkuState(packageName, 'misc', 'schemas').get(meta.outputSchema)
708
+ : undefined,
709
+ }
710
+
711
+ try {
712
+ await agentRunner.stream(runnerParams, persistingChannel)
713
+
714
+ await postStreamCleanup(
715
+ persistingChannel,
716
+ aiMiddlewares,
717
+ singletonServices,
718
+ storage,
719
+ memoryConfig,
720
+ run.threadId,
721
+ workingMemorySchemaName,
722
+ runnerParams.messages,
723
+ aiRunState,
724
+ run.runId
725
+ )
726
+ } catch (err) {
727
+ if (err instanceof ToolApprovalRequired) {
728
+ await persistingChannel.flush()
729
+
730
+ const pendingApproval = err.agentRunId
731
+ ? {
732
+ type: 'agent-call' as const,
733
+ toolCallId: err.toolCallId,
734
+ agentName: err.toolName,
735
+ agentRunId: err.agentRunId,
736
+ displayToolName: err.displayToolName ?? err.toolName,
737
+ displayArgs: err.displayArgs ?? err.args,
738
+ }
739
+ : {
740
+ type: 'tool-call' as const,
741
+ toolCallId: err.toolCallId,
742
+ toolName: err.toolName,
743
+ args: err.args,
744
+ }
745
+
746
+ await aiRunState.updateRun(run.runId, {
747
+ status: 'suspended',
748
+ suspendReason: 'approval',
749
+ pendingApprovals: [pendingApproval],
750
+ })
751
+
752
+ const approvalEvent = {
753
+ type: 'approval-request' as const,
754
+ toolCallId: err.toolCallId,
755
+ toolName: err.displayToolName ?? err.toolName,
756
+ args: err.displayArgs ?? err.args,
757
+ reason: err.reason,
758
+ runId: run.runId,
759
+ }
760
+ channel.send(approvalEvent as any)
761
+ channel.send({ type: 'done' })
762
+ channel.close()
763
+ return
764
+ }
765
+
766
+ await aiRunState.updateRun(run.runId, { status: 'failed' })
767
+ channel.send({
768
+ type: 'error',
769
+ message: err instanceof Error ? err.message : String(err),
770
+ })
771
+ channel.send({ type: 'done' })
772
+ channel.close()
773
+ }
774
+ }