@pikku/core 0.11.2 → 0.12.1

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 (436) hide show
  1. package/CHANGELOG.md +57 -2
  2. package/dist/crypto-utils.d.ts +2 -0
  3. package/dist/crypto-utils.js +78 -0
  4. package/dist/errors/errors.d.ts +14 -0
  5. package/dist/errors/errors.js +26 -0
  6. package/dist/errors/index.d.ts +1 -1
  7. package/dist/errors/index.js +1 -1
  8. package/dist/function/function-runner.d.ts +10 -4
  9. package/dist/function/function-runner.js +126 -45
  10. package/dist/function/functions.types.d.ts +32 -87
  11. package/dist/function/functions.types.js +16 -46
  12. package/dist/function/index.d.ts +2 -2
  13. package/dist/function/index.js +1 -2
  14. package/dist/handle-error.d.ts +2 -2
  15. package/dist/handle-error.js +3 -12
  16. package/dist/index.d.ts +30 -26
  17. package/dist/index.js +19 -29
  18. package/dist/internal.d.ts +3 -0
  19. package/dist/internal.js +2 -0
  20. package/dist/middleware/auth-apikey.d.ts +2 -2
  21. package/dist/middleware/auth-apikey.js +3 -3
  22. package/dist/middleware/auth-bearer.d.ts +3 -3
  23. package/dist/middleware/auth-bearer.js +4 -7
  24. package/dist/middleware/auth-cookie.d.ts +4 -4
  25. package/dist/middleware/auth-cookie.js +7 -9
  26. package/dist/middleware/cors.d.ts +46 -0
  27. package/dist/middleware/cors.js +81 -0
  28. package/dist/middleware/index.d.ts +5 -3
  29. package/dist/middleware/index.js +5 -3
  30. package/dist/middleware/remote-auth.d.ts +5 -0
  31. package/dist/middleware/remote-auth.js +55 -0
  32. package/dist/middleware/timeout.d.ts +2 -2
  33. package/dist/middleware-runner.d.ts +1 -1
  34. package/dist/middleware-runner.js +8 -10
  35. package/dist/permissions.d.ts +2 -2
  36. package/dist/permissions.js +11 -15
  37. package/dist/pikku-state.d.ts +10 -8
  38. package/dist/pikku-state.js +48 -25
  39. package/dist/schema.d.ts +4 -4
  40. package/dist/schema.js +20 -15
  41. package/dist/services/ai-agent-runner-service.d.ts +43 -0
  42. package/dist/services/ai-agent-runner-service.js +1 -0
  43. package/dist/services/ai-run-state-service.d.ts +13 -0
  44. package/dist/services/ai-run-state-service.js +1 -0
  45. package/dist/services/ai-storage-service.d.ts +18 -0
  46. package/dist/services/ai-storage-service.js +1 -0
  47. package/dist/services/content-service.d.ts +6 -0
  48. package/dist/services/deployment-service.d.ts +19 -0
  49. package/dist/services/deployment-service.js +1 -0
  50. package/dist/services/gopass-secrets.d.ts +47 -0
  51. package/dist/services/gopass-secrets.js +97 -0
  52. package/dist/services/in-memory-ai-run-state-service.d.ts +15 -0
  53. package/dist/services/in-memory-ai-run-state-service.js +44 -0
  54. package/dist/services/in-memory-trigger-service.d.ts +22 -0
  55. package/dist/services/in-memory-trigger-service.js +48 -0
  56. package/dist/services/in-memory-workflow-service.d.ts +59 -0
  57. package/dist/services/in-memory-workflow-service.js +287 -0
  58. package/dist/services/index.d.ts +26 -11
  59. package/dist/services/index.js +11 -13
  60. package/dist/services/local-content.d.ts +2 -1
  61. package/dist/services/local-content.js +6 -1
  62. package/dist/services/local-secrets.d.ts +25 -2
  63. package/dist/services/local-secrets.js +45 -0
  64. package/dist/services/local-variables.d.ts +6 -1
  65. package/dist/services/local-variables.js +18 -0
  66. package/dist/services/logger-console.d.ts +2 -1
  67. package/dist/services/scheduler-service.d.ts +9 -1
  68. package/dist/services/scheduler-service.js +8 -0
  69. package/dist/services/schema-service.d.ts +6 -0
  70. package/dist/services/scoped-secret-service.d.ts +16 -0
  71. package/dist/services/scoped-secret-service.js +35 -0
  72. package/dist/services/secret-service.d.ts +25 -4
  73. package/dist/services/trigger-service.d.ts +16 -0
  74. package/dist/services/trigger-service.js +1 -0
  75. package/dist/services/typed-secret-service.d.ts +30 -0
  76. package/dist/services/typed-secret-service.js +40 -0
  77. package/dist/services/typed-variables-service.d.ts +27 -0
  78. package/dist/services/typed-variables-service.js +46 -0
  79. package/dist/services/user-session-service.d.ts +15 -2
  80. package/dist/services/user-session-service.js +17 -0
  81. package/dist/services/variables-service.d.ts +5 -0
  82. package/dist/services/workflow-service.d.ts +9 -5
  83. package/dist/types/core.types.d.ts +67 -25
  84. package/dist/types/core.types.js +8 -1
  85. package/dist/types/state.types.d.ts +53 -59
  86. package/dist/utils.d.ts +7 -6
  87. package/dist/utils.js +27 -12
  88. package/dist/version.d.ts +6 -0
  89. package/dist/version.js +19 -0
  90. package/dist/wirings/ai-agent/ai-agent-assistant-ui.d.ts +5 -0
  91. package/dist/wirings/ai-agent/ai-agent-assistant-ui.js +146 -0
  92. package/dist/wirings/ai-agent/ai-agent-helpers.d.ts +28 -0
  93. package/dist/wirings/ai-agent/ai-agent-helpers.js +40 -0
  94. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +29 -0
  95. package/dist/wirings/ai-agent/ai-agent-memory.js +199 -0
  96. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +9 -0
  97. package/dist/wirings/ai-agent/ai-agent-model-config.js +36 -0
  98. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +59 -0
  99. package/dist/wirings/ai-agent/ai-agent-prepare.js +348 -0
  100. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +15 -0
  101. package/dist/wirings/ai-agent/ai-agent-registry.js +47 -0
  102. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +3 -0
  103. package/dist/wirings/ai-agent/ai-agent-runner.js +195 -0
  104. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +12 -0
  105. package/dist/wirings/ai-agent/ai-agent-stream.js +662 -0
  106. package/dist/wirings/ai-agent/ai-agent.types.d.ts +313 -0
  107. package/dist/wirings/ai-agent/ai-agent.types.js +1 -0
  108. package/dist/wirings/ai-agent/index.d.ts +7 -0
  109. package/dist/wirings/ai-agent/index.js +6 -0
  110. package/dist/wirings/channel/channel-common.d.ts +8 -5
  111. package/dist/wirings/channel/channel-common.js +15 -8
  112. package/dist/wirings/channel/channel-handler.d.ts +3 -3
  113. package/dist/wirings/channel/channel-handler.js +15 -6
  114. package/dist/wirings/channel/channel-middleware-runner.d.ts +9 -0
  115. package/dist/wirings/channel/channel-middleware-runner.js +73 -0
  116. package/dist/wirings/channel/channel-runner.d.ts +5 -5
  117. package/dist/wirings/channel/channel-runner.js +10 -9
  118. package/dist/wirings/channel/channel-store.d.ts +1 -1
  119. package/dist/wirings/channel/channel.types.d.ts +9 -7
  120. package/dist/wirings/channel/define-channel-routes.d.ts +21 -0
  121. package/dist/wirings/channel/define-channel-routes.js +23 -0
  122. package/dist/wirings/channel/index.d.ts +10 -8
  123. package/dist/wirings/channel/index.js +7 -8
  124. package/dist/wirings/channel/local/index.d.ts +3 -3
  125. package/dist/wirings/channel/local/index.js +3 -3
  126. package/dist/wirings/channel/local/local-channel-runner.d.ts +7 -2
  127. package/dist/wirings/channel/local/local-channel-runner.js +22 -9
  128. package/dist/wirings/channel/local/local-eventhub-service.d.ts +2 -2
  129. package/dist/wirings/channel/log-channels.d.ts +1 -1
  130. package/dist/wirings/channel/pikku-abstract-channel-handler.d.ts +1 -1
  131. package/dist/wirings/channel/serverless/index.d.ts +1 -1
  132. package/dist/wirings/channel/serverless/index.js +1 -1
  133. package/dist/wirings/channel/serverless/serverless-channel-runner.d.ts +4 -4
  134. package/dist/wirings/channel/serverless/serverless-channel-runner.js +40 -23
  135. package/dist/wirings/cli/channel/cli-channel-runner.d.ts +1 -1
  136. package/dist/wirings/cli/channel/index.d.ts +1 -1
  137. package/dist/wirings/cli/channel/index.js +1 -1
  138. package/dist/wirings/cli/cli-runner.d.ts +3 -3
  139. package/dist/wirings/cli/cli-runner.js +12 -8
  140. package/dist/wirings/cli/cli.types.d.ts +9 -9
  141. package/dist/wirings/cli/command-parser.d.ts +1 -1
  142. package/dist/wirings/cli/define-cli-commands.d.ts +19 -0
  143. package/dist/wirings/cli/define-cli-commands.js +20 -0
  144. package/dist/wirings/cli/index.d.ts +2 -3
  145. package/dist/wirings/cli/index.js +1 -3
  146. package/dist/wirings/http/http-routes.d.ts +69 -0
  147. package/dist/wirings/http/http-routes.js +139 -0
  148. package/dist/wirings/http/http-runner.d.ts +9 -9
  149. package/dist/wirings/http/http-runner.js +79 -34
  150. package/dist/wirings/http/http.types.d.ts +77 -41
  151. package/dist/wirings/http/index.d.ts +5 -4
  152. package/dist/wirings/http/index.js +4 -3
  153. package/dist/wirings/http/log-http-routes.d.ts +1 -1
  154. package/dist/wirings/http/pikku-fetch-http-request.d.ts +1 -1
  155. package/dist/wirings/http/pikku-fetch-http-response.d.ts +2 -2
  156. package/dist/wirings/http/pikku-fetch-http-response.js +6 -1
  157. package/dist/wirings/http/routers/http-router.d.ts +1 -1
  158. package/dist/wirings/http/routers/path-to-regex.d.ts +2 -2
  159. package/dist/wirings/mcp/index.d.ts +4 -3
  160. package/dist/wirings/mcp/index.js +3 -3
  161. package/dist/wirings/mcp/mcp-endpoint-registry.d.ts +1 -1
  162. package/dist/wirings/mcp/mcp-runner.d.ts +1 -6
  163. package/dist/wirings/mcp/mcp-runner.js +28 -40
  164. package/dist/wirings/mcp/mcp.types.d.ts +5 -5
  165. package/dist/wirings/node/index.d.ts +2 -0
  166. package/dist/wirings/node/index.js +1 -0
  167. package/dist/wirings/node/node.types.d.ts +20 -0
  168. package/dist/wirings/node/node.types.js +1 -0
  169. package/dist/wirings/oauth2/index.d.ts +3 -0
  170. package/dist/wirings/oauth2/index.js +2 -0
  171. package/dist/wirings/oauth2/oauth2-client.d.ts +47 -0
  172. package/dist/wirings/oauth2/oauth2-client.js +267 -0
  173. package/dist/wirings/oauth2/oauth2.types.d.ts +65 -0
  174. package/dist/wirings/oauth2/oauth2.types.js +4 -0
  175. package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +20 -0
  176. package/dist/wirings/oauth2/wire-oauth2-credential.js +21 -0
  177. package/dist/wirings/queue/index.d.ts +1 -1
  178. package/dist/wirings/queue/queue-runner.d.ts +1 -5
  179. package/dist/wirings/queue/queue-runner.js +11 -8
  180. package/dist/wirings/queue/queue.types.d.ts +5 -5
  181. package/dist/wirings/queue/register-queue-helper.d.ts +2 -2
  182. package/dist/wirings/queue/register-queue-helper.js +1 -1
  183. package/dist/wirings/queue/validate-worker-config.d.ts +1 -1
  184. package/dist/wirings/rpc/index.d.ts +3 -1
  185. package/dist/wirings/rpc/index.js +2 -1
  186. package/dist/wirings/rpc/rpc-runner.d.ts +58 -8
  187. package/dist/wirings/rpc/rpc-runner.js +177 -31
  188. package/dist/wirings/rpc/rpc-types.d.ts +20 -4
  189. package/dist/wirings/rpc/wire-addon.d.ts +10 -0
  190. package/dist/wirings/rpc/wire-addon.js +9 -0
  191. package/dist/wirings/scheduler/index.d.ts +2 -2
  192. package/dist/wirings/scheduler/index.js +1 -2
  193. package/dist/wirings/scheduler/log-schedulers.d.ts +1 -1
  194. package/dist/wirings/scheduler/scheduler-runner.d.ts +3 -5
  195. package/dist/wirings/scheduler/scheduler-runner.js +11 -14
  196. package/dist/wirings/scheduler/scheduler.types.d.ts +2 -2
  197. package/dist/wirings/secret/index.d.ts +3 -0
  198. package/dist/wirings/secret/index.js +2 -0
  199. package/dist/wirings/secret/secret.types.d.ts +27 -0
  200. package/dist/wirings/secret/secret.types.js +1 -0
  201. package/dist/wirings/secret/validate-secret-definitions.d.ts +6 -0
  202. package/dist/wirings/secret/validate-secret-definitions.js +55 -0
  203. package/dist/wirings/trigger/index.d.ts +3 -2
  204. package/dist/wirings/trigger/index.js +2 -2
  205. package/dist/wirings/trigger/pikku-trigger-service.d.ts +22 -0
  206. package/dist/wirings/trigger/pikku-trigger-service.js +70 -0
  207. package/dist/wirings/trigger/trigger-runner.d.ts +18 -9
  208. package/dist/wirings/trigger/trigger-runner.js +48 -19
  209. package/dist/wirings/trigger/trigger.types.d.ts +99 -11
  210. package/dist/wirings/trigger/trigger.types.js +40 -1
  211. package/dist/wirings/variable/index.d.ts +3 -0
  212. package/dist/wirings/variable/index.js +2 -0
  213. package/dist/wirings/variable/validate-variable-definitions.d.ts +6 -0
  214. package/dist/wirings/variable/validate-variable-definitions.js +45 -0
  215. package/dist/wirings/variable/variable.types.d.ts +18 -0
  216. package/dist/wirings/variable/variable.types.js +1 -0
  217. package/dist/wirings/workflow/dsl/index.d.ts +1 -1
  218. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +7 -1
  219. package/dist/wirings/workflow/dsl/workflow-runner.js +3 -2
  220. package/dist/wirings/workflow/graph/graph-node.d.ts +1 -6
  221. package/dist/wirings/workflow/graph/graph-runner.d.ts +5 -31
  222. package/dist/wirings/workflow/graph/graph-runner.js +384 -296
  223. package/dist/wirings/workflow/graph/index.d.ts +4 -3
  224. package/dist/wirings/workflow/graph/index.js +3 -3
  225. package/dist/wirings/workflow/graph/template.d.ts +15 -0
  226. package/dist/wirings/workflow/graph/template.js +27 -0
  227. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +15 -0
  228. package/dist/wirings/workflow/graph/wire-workflow-graph.js +8 -0
  229. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -13
  230. package/dist/wirings/workflow/index.d.ts +6 -6
  231. package/dist/wirings/workflow/index.js +6 -4
  232. package/dist/wirings/workflow/pikku-workflow-service.d.ts +29 -19
  233. package/dist/wirings/workflow/pikku-workflow-service.js +217 -82
  234. package/dist/wirings/workflow/workflow-helpers.d.ts +36 -0
  235. package/dist/wirings/workflow/workflow-helpers.js +38 -0
  236. package/dist/wirings/workflow/workflow.types.d.ts +42 -95
  237. package/package.json +14 -15
  238. package/run-tests.sh +4 -1
  239. package/src/crypto-utils.test.ts +116 -0
  240. package/src/crypto-utils.ts +99 -0
  241. package/src/errors/error.test.ts +143 -2
  242. package/src/errors/errors.ts +27 -0
  243. package/src/errors/index.ts +1 -1
  244. package/src/factory-functions.test.ts +42 -2
  245. package/src/function/function-runner.test.ts +6 -13
  246. package/src/function/function-runner.ts +161 -53
  247. package/src/function/functions.types.ts +63 -132
  248. package/src/function/index.ts +5 -2
  249. package/src/handle-error.test.ts +361 -0
  250. package/src/handle-error.ts +6 -14
  251. package/src/index.ts +97 -30
  252. package/src/internal.ts +6 -0
  253. package/src/middleware/auth-apikey.test.ts +16 -13
  254. package/src/middleware/auth-apikey.ts +3 -3
  255. package/src/middleware/auth-bearer.test.ts +18 -15
  256. package/src/middleware/auth-bearer.ts +27 -32
  257. package/src/middleware/auth-cookie.test.ts +17 -14
  258. package/src/middleware/auth-cookie.ts +9 -13
  259. package/src/middleware/cors.test.ts +424 -0
  260. package/src/middleware/cors.ts +104 -0
  261. package/src/middleware/index.ts +5 -3
  262. package/src/middleware/remote-auth.test.ts +488 -0
  263. package/src/middleware/remote-auth.ts +68 -0
  264. package/src/middleware-runner.test.ts +123 -1
  265. package/src/middleware-runner.ts +13 -13
  266. package/src/permissions.test.ts +83 -9
  267. package/src/permissions.ts +17 -19
  268. package/src/pikku-state.test.ts +224 -0
  269. package/src/pikku-state.ts +59 -35
  270. package/src/run-tests-script.test.ts +49 -0
  271. package/src/schema.test.ts +198 -6
  272. package/src/schema.ts +28 -21
  273. package/src/services/ai-agent-runner-service.ts +41 -0
  274. package/src/services/ai-run-state-service.ts +20 -0
  275. package/src/services/ai-storage-service.ts +39 -0
  276. package/src/services/content-service.ts +7 -0
  277. package/src/services/deployment-service.ts +22 -0
  278. package/src/services/gopass-secrets.ts +98 -0
  279. package/src/services/in-memory-ai-run-state-service.ts +73 -0
  280. package/src/services/in-memory-trigger-service.ts +64 -0
  281. package/src/services/in-memory-workflow-service.test.ts +351 -0
  282. package/src/services/in-memory-workflow-service.ts +395 -0
  283. package/src/services/index.ts +50 -14
  284. package/src/services/local-content.ts +9 -3
  285. package/src/services/local-secrets.test.ts +80 -0
  286. package/src/services/local-secrets.ts +53 -2
  287. package/src/services/local-variables.test.ts +61 -0
  288. package/src/services/local-variables.ts +23 -1
  289. package/src/services/logger-console.test.ts +118 -0
  290. package/src/services/logger-console.ts +2 -1
  291. package/src/services/scheduler-service.ts +11 -1
  292. package/src/services/schema-service.ts +7 -0
  293. package/src/services/scoped-secret-service.test.ts +74 -0
  294. package/src/services/scoped-secret-service.ts +41 -0
  295. package/src/services/secret-service.ts +25 -4
  296. package/src/services/trigger-service.ts +17 -0
  297. package/src/services/typed-secret-service.test.ts +93 -0
  298. package/src/services/typed-secret-service.ts +70 -0
  299. package/src/services/typed-variables-service.test.ts +73 -0
  300. package/src/services/typed-variables-service.ts +81 -0
  301. package/src/services/user-session-service.test.ts +113 -0
  302. package/src/services/user-session-service.ts +25 -2
  303. package/src/services/variables-service.ts +5 -0
  304. package/src/services/workflow-service.ts +23 -13
  305. package/src/time-utils.test.ts +1 -1
  306. package/src/types/core.types.ts +95 -24
  307. package/src/types/state.types.ts +56 -73
  308. package/src/utils.test.ts +350 -0
  309. package/src/utils.ts +33 -18
  310. package/src/version.test.ts +80 -0
  311. package/src/version.ts +25 -0
  312. package/src/wirings/ai-agent/ai-agent-assistant-ui.test.ts +363 -0
  313. package/src/wirings/ai-agent/ai-agent-assistant-ui.ts +214 -0
  314. package/src/wirings/ai-agent/ai-agent-helpers.test.ts +152 -0
  315. package/src/wirings/ai-agent/ai-agent-helpers.ts +76 -0
  316. package/src/wirings/ai-agent/ai-agent-memory.ts +300 -0
  317. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +115 -0
  318. package/src/wirings/ai-agent/ai-agent-model-config.ts +43 -0
  319. package/src/wirings/ai-agent/ai-agent-prepare.ts +504 -0
  320. package/src/wirings/ai-agent/ai-agent-registry.test.ts +37 -0
  321. package/src/wirings/ai-agent/ai-agent-registry.ts +82 -0
  322. package/src/wirings/ai-agent/ai-agent-runner.test.ts +317 -0
  323. package/src/wirings/ai-agent/ai-agent-runner.ts +251 -0
  324. package/src/wirings/ai-agent/ai-agent-stream.test.ts +652 -0
  325. package/src/wirings/ai-agent/ai-agent-stream.ts +1049 -0
  326. package/src/wirings/ai-agent/ai-agent.types.ts +328 -0
  327. package/src/wirings/ai-agent/index.ts +39 -0
  328. package/src/wirings/channel/channel-common.ts +33 -20
  329. package/src/wirings/channel/channel-handler.ts +26 -9
  330. package/src/wirings/channel/channel-middleware-runner.ts +119 -0
  331. package/src/wirings/channel/channel-runner.ts +15 -16
  332. package/src/wirings/channel/channel-store.ts +1 -1
  333. package/src/wirings/channel/channel.types.ts +21 -9
  334. package/src/wirings/channel/define-channel-routes.ts +25 -0
  335. package/src/wirings/channel/index.ts +23 -8
  336. package/src/wirings/channel/local/index.ts +3 -3
  337. package/src/wirings/channel/local/local-channel-runner.test.ts +57 -7
  338. package/src/wirings/channel/local/local-channel-runner.ts +40 -19
  339. package/src/wirings/channel/local/local-eventhub-service.test.ts +2 -2
  340. package/src/wirings/channel/local/local-eventhub-service.ts +2 -2
  341. package/src/wirings/channel/log-channels.ts +1 -1
  342. package/src/wirings/channel/pikku-abstract-channel-handler.ts +1 -1
  343. package/src/wirings/channel/serverless/index.ts +5 -1
  344. package/src/wirings/channel/serverless/serverless-channel-runner.ts +57 -36
  345. package/src/wirings/cli/channel/cli-channel-runner.ts +1 -1
  346. package/src/wirings/cli/channel/index.ts +1 -1
  347. package/src/wirings/cli/cli-runner.test.ts +10 -10
  348. package/src/wirings/cli/cli-runner.ts +28 -14
  349. package/src/wirings/cli/cli.types.ts +14 -14
  350. package/src/wirings/cli/command-parser.test.ts +9 -9
  351. package/src/wirings/cli/command-parser.ts +1 -1
  352. package/src/wirings/cli/define-cli-commands.ts +24 -0
  353. package/src/wirings/cli/index.ts +10 -4
  354. package/src/wirings/http/http-routes.test.ts +322 -0
  355. package/src/wirings/http/http-routes.ts +198 -0
  356. package/src/wirings/http/http-runner.test.ts +12 -20
  357. package/src/wirings/http/http-runner.ts +101 -51
  358. package/src/wirings/http/http.types.ts +119 -48
  359. package/src/wirings/http/index.ts +16 -4
  360. package/src/wirings/http/log-http-routes.ts +1 -1
  361. package/src/wirings/http/pikku-fetch-http-request.ts +1 -1
  362. package/src/wirings/http/pikku-fetch-http-response.ts +12 -5
  363. package/src/wirings/http/routers/http-router.ts +1 -1
  364. package/src/wirings/http/routers/path-to-regex.test.ts +1 -1
  365. package/src/wirings/http/routers/path-to-regex.ts +4 -3
  366. package/src/wirings/mcp/index.ts +27 -3
  367. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +3 -3
  368. package/src/wirings/mcp/mcp-endpoint-registry.ts +5 -1
  369. package/src/wirings/mcp/mcp-runner.ts +48 -65
  370. package/src/wirings/mcp/mcp.types.ts +5 -5
  371. package/src/wirings/node/index.ts +2 -0
  372. package/src/wirings/node/node.types.ts +23 -0
  373. package/src/wirings/oauth2/index.ts +3 -0
  374. package/src/wirings/oauth2/oauth2-client.test.ts +929 -0
  375. package/src/wirings/oauth2/oauth2-client.ts +335 -0
  376. package/src/wirings/oauth2/oauth2.types.ts +69 -0
  377. package/src/wirings/oauth2/wire-oauth2-credential.ts +23 -0
  378. package/src/wirings/queue/index.ts +13 -2
  379. package/src/wirings/queue/queue-runner.test.ts +142 -73
  380. package/src/wirings/queue/queue-runner.ts +18 -14
  381. package/src/wirings/queue/queue.types.ts +5 -5
  382. package/src/wirings/queue/register-queue-helper.ts +3 -5
  383. package/src/wirings/queue/validate-worker-config.test.ts +108 -0
  384. package/src/wirings/queue/validate-worker-config.ts +4 -1
  385. package/src/wirings/rpc/index.ts +3 -1
  386. package/src/wirings/rpc/rpc-runner.ts +254 -41
  387. package/src/wirings/rpc/rpc-types.ts +28 -4
  388. package/src/wirings/rpc/wire-addon.ts +20 -0
  389. package/src/wirings/scheduler/index.ts +6 -4
  390. package/src/wirings/scheduler/log-schedulers.ts +1 -1
  391. package/src/wirings/scheduler/scheduler-runner.test.ts +78 -45
  392. package/src/wirings/scheduler/scheduler-runner.ts +20 -27
  393. package/src/wirings/scheduler/scheduler.types.ts +2 -2
  394. package/src/wirings/secret/index.ts +9 -0
  395. package/src/wirings/secret/secret.types.ts +32 -0
  396. package/src/wirings/secret/validate-secret-definitions.test.ts +140 -0
  397. package/src/wirings/secret/validate-secret-definitions.ts +82 -0
  398. package/src/wirings/trigger/index.ts +10 -2
  399. package/src/wirings/trigger/pikku-trigger-service.ts +112 -0
  400. package/src/wirings/trigger/trigger-runner.test.ts +79 -0
  401. package/src/wirings/trigger/trigger-runner.ts +80 -41
  402. package/src/wirings/trigger/trigger.types.ts +144 -22
  403. package/src/wirings/variable/index.ts +8 -0
  404. package/src/wirings/variable/validate-variable-definitions.test.ts +91 -0
  405. package/src/wirings/variable/validate-variable-definitions.ts +69 -0
  406. package/src/wirings/variable/variable.types.ts +22 -0
  407. package/src/wirings/workflow/dsl/index.ts +1 -0
  408. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +9 -1
  409. package/src/wirings/workflow/dsl/workflow-runner.ts +4 -3
  410. package/src/wirings/workflow/graph/graph-node.ts +1 -6
  411. package/src/wirings/workflow/graph/graph-runner.test.ts +487 -0
  412. package/src/wirings/workflow/graph/graph-runner.ts +496 -374
  413. package/src/wirings/workflow/graph/index.ts +14 -3
  414. package/src/wirings/workflow/graph/template.test.ts +49 -0
  415. package/src/wirings/workflow/graph/template.ts +42 -0
  416. package/src/wirings/workflow/graph/wire-workflow-graph.ts +29 -0
  417. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -22
  418. package/src/wirings/workflow/index.ts +21 -10
  419. package/src/wirings/workflow/pikku-workflow-service.test.ts +200 -0
  420. package/src/wirings/workflow/pikku-workflow-service.ts +308 -105
  421. package/src/wirings/workflow/workflow-helpers.test.ts +129 -0
  422. package/src/wirings/workflow/workflow-helpers.ts +79 -0
  423. package/src/wirings/workflow/workflow.types.ts +47 -92
  424. package/tsconfig.tsbuildinfo +1 -1
  425. package/dist/wirings/forge-node/forge-node.types.d.ts +0 -120
  426. package/dist/wirings/forge-node/forge-node.types.js +0 -38
  427. package/dist/wirings/forge-node/index.d.ts +0 -1
  428. package/dist/wirings/forge-node/index.js +0 -1
  429. package/dist/wirings/workflow/wire-workflow.d.ts +0 -42
  430. package/dist/wirings/workflow/wire-workflow.js +0 -53
  431. package/dist/wirings/workflow/workflow-utils.d.ts +0 -23
  432. package/dist/wirings/workflow/workflow-utils.js +0 -66
  433. package/src/wirings/forge-node/forge-node.types.ts +0 -135
  434. package/src/wirings/forge-node/index.ts +0 -1
  435. package/src/wirings/workflow/wire-workflow.ts +0 -94
  436. package/src/wirings/workflow/workflow-utils.ts +0 -120
@@ -0,0 +1,1049 @@
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, getSingletonServices } 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
+ import type {
20
+ AIAgentRunnerParams,
21
+ AIAgentStepResult,
22
+ } from '../../services/ai-agent-runner-service.js'
23
+
24
+ import {
25
+ parseWorkingMemory,
26
+ deepMergeWorkingMemory,
27
+ resolveMemoryServices,
28
+ loadContextMessages,
29
+ trimMessages,
30
+ } from './ai-agent-memory.js'
31
+ import {
32
+ prepareAgentRun,
33
+ resolveAgent,
34
+ buildInstructions,
35
+ buildToolDefs,
36
+ createScopedChannel,
37
+ ToolApprovalRequired,
38
+ type RunAIAgentParams,
39
+ type StreamAIAgentOptions,
40
+ type StreamContext,
41
+ } from './ai-agent-prepare.js'
42
+ import {
43
+ createAssistantUIChannel,
44
+ parseAssistantUIInput,
45
+ } from './ai-agent-assistant-ui.js'
46
+ import { resolveModelConfig } from './ai-agent-model-config.js'
47
+ import type { AIRunStateService } from '../../services/ai-run-state-service.js'
48
+ import type { AIAgentRunnerService } from '../../services/ai-agent-runner-service.js'
49
+
50
+ type PersistingChannel = AIStreamChannel & {
51
+ fullText: string
52
+ flush: () => Promise<void>
53
+ totalUsage: { inputTokens: number; outputTokens: number; model?: string }
54
+ }
55
+
56
+ function createPersistingChannel(
57
+ parent: AIStreamChannel,
58
+ storage: AIStorageService | undefined,
59
+ threadId: string
60
+ ): PersistingChannel {
61
+ let fullText = ''
62
+ let stepText = ''
63
+ let stepToolCalls: AIToolCall[] = []
64
+ let stepToolResults: AIToolResult[] = []
65
+ const totalUsage: {
66
+ inputTokens: number
67
+ outputTokens: number
68
+ model?: string
69
+ } = {
70
+ inputTokens: 0,
71
+ outputTokens: 0,
72
+ }
73
+
74
+ const flushStep = async () => {
75
+ if (!storage) return
76
+ const text = stepText
77
+ const calls = stepToolCalls
78
+ const results = stepToolResults
79
+ stepText = ''
80
+ stepToolCalls = []
81
+ stepToolResults = []
82
+ if (text || calls.length > 0) {
83
+ const assistantMsg: AIMessage = {
84
+ id: randomUUID(),
85
+ role: 'assistant',
86
+ content: text || undefined,
87
+ toolCalls: calls.length > 0 ? calls : undefined,
88
+ createdAt: new Date(),
89
+ }
90
+ const messages: AIMessage[] = [assistantMsg]
91
+ if (results.length > 0) {
92
+ messages.push({
93
+ id: randomUUID(),
94
+ role: 'tool',
95
+ toolResults: results,
96
+ createdAt: new Date(),
97
+ })
98
+ }
99
+ await storage.saveMessages(threadId, messages)
100
+ }
101
+ }
102
+
103
+ const channel: PersistingChannel = {
104
+ channelId: parent.channelId,
105
+ openingData: parent.openingData,
106
+ get state() {
107
+ return parent.state
108
+ },
109
+ get fullText() {
110
+ return fullText
111
+ },
112
+ get totalUsage() {
113
+ return totalUsage
114
+ },
115
+ flush: flushStep,
116
+ close: () => parent.close(),
117
+ send: (event: AIStreamEvent) => {
118
+ if (storage) {
119
+ switch (event.type) {
120
+ case 'text-delta':
121
+ stepText += event.text
122
+ fullText += event.text
123
+ break
124
+ case 'tool-call':
125
+ stepToolCalls.push({
126
+ id: event.toolCallId,
127
+ name: event.toolName,
128
+ args: event.args as Record<string, unknown>,
129
+ })
130
+ break
131
+ case 'tool-result':
132
+ stepToolResults.push({
133
+ id: event.toolCallId,
134
+ name: event.toolName,
135
+ result:
136
+ typeof event.result === 'string'
137
+ ? event.result
138
+ : JSON.stringify(event.result),
139
+ })
140
+ break
141
+ case 'usage':
142
+ totalUsage.inputTokens += event.tokens.input
143
+ totalUsage.outputTokens += event.tokens.output
144
+ if (event.model) totalUsage.model = event.model
145
+ flushStep()
146
+ break
147
+ case 'done':
148
+ flushStep()
149
+ break
150
+ }
151
+ }
152
+ parent.send(event)
153
+ },
154
+ }
155
+ return channel
156
+ }
157
+
158
+ async function postStreamCleanup(
159
+ persistingChannel: PersistingChannel,
160
+ aiMiddlewares: PikkuAIMiddlewareHooks[],
161
+ singletonServices: any,
162
+ storage: AIStorageService | undefined,
163
+ memoryConfig: any,
164
+ threadId: string,
165
+ workingMemorySchemaName: string | null,
166
+ messages: AIMessage[],
167
+ aiRunState: AIRunStateService,
168
+ runId: string
169
+ ): Promise<void> {
170
+ const usage = persistingChannel.totalUsage
171
+ let outputText = persistingChannel.fullText
172
+ let outputMessages = messages
173
+ for (let i = aiMiddlewares.length - 1; i >= 0; i--) {
174
+ const mw = aiMiddlewares[i]
175
+ if (mw.modifyOutput) {
176
+ const result = await mw.modifyOutput(singletonServices, {
177
+ text: outputText,
178
+ messages: outputMessages,
179
+ usage: {
180
+ inputTokens: usage.inputTokens,
181
+ outputTokens: usage.outputTokens,
182
+ },
183
+ })
184
+ outputText = result.text
185
+ outputMessages = result.messages
186
+ }
187
+ }
188
+
189
+ if (storage && memoryConfig?.workingMemory && outputText) {
190
+ const parsed = parseWorkingMemory(outputText)
191
+ if (parsed) {
192
+ const existing =
193
+ (await storage.getWorkingMemory(threadId, 'thread')) ?? {}
194
+ const merged = deepMergeWorkingMemory(existing, parsed)
195
+
196
+ if (singletonServices.schema && workingMemorySchemaName) {
197
+ try {
198
+ await singletonServices.schema.validateSchema(
199
+ workingMemorySchemaName,
200
+ merged
201
+ )
202
+ } catch (err) {
203
+ singletonServices.logger.warn(
204
+ `Working memory validation failed: ${err instanceof Error ? err.message : String(err)}`
205
+ )
206
+ }
207
+ }
208
+
209
+ await storage.saveWorkingMemory(threadId, 'thread', merged)
210
+ }
211
+ }
212
+
213
+ await aiRunState.updateRun(runId, {
214
+ status: 'completed',
215
+ ...(usage.model
216
+ ? {
217
+ usage: {
218
+ inputTokens: usage.inputTokens,
219
+ outputTokens: usage.outputTokens,
220
+ model: usage.model,
221
+ },
222
+ }
223
+ : {}),
224
+ })
225
+ }
226
+
227
+ type StepLoopParams = {
228
+ agent: CoreAIAgent
229
+ runnerParams: AIAgentRunnerParams
230
+ maxSteps: number
231
+ agentRunner: AIAgentRunnerService
232
+ persistingChannel: PersistingChannel
233
+ channel: AIStreamChannel
234
+ runId: string
235
+ aiMiddlewares: PikkuAIMiddlewareHooks[]
236
+ }
237
+
238
+ type StepLoopResult =
239
+ | { outcome: 'done' }
240
+ | { outcome: 'approval'; approval: ToolApprovalRequired }
241
+
242
+ async function runStreamStepLoop(
243
+ params: StepLoopParams
244
+ ): Promise<StepLoopResult> {
245
+ const {
246
+ agent,
247
+ runnerParams,
248
+ maxSteps,
249
+ agentRunner,
250
+ persistingChannel,
251
+ channel,
252
+ runId,
253
+ aiMiddlewares,
254
+ } = params
255
+
256
+ const singletonServices = getSingletonServices()
257
+
258
+ for (let step = 0; step < maxSteps; step++) {
259
+ if (agent.prepareStep) {
260
+ let stopped = false
261
+ await agent.prepareStep({
262
+ stepNumber: step,
263
+ messages: runnerParams.messages,
264
+ tools: runnerParams.tools,
265
+ toolChoice: runnerParams.toolChoice,
266
+ model: runnerParams.model,
267
+ stop: () => {
268
+ stopped = true
269
+ },
270
+ })
271
+ if (stopped) break
272
+ }
273
+
274
+ channel.send({ type: 'step-start', stepNumber: step })
275
+
276
+ const stepResult = await agentRunner.stream(runnerParams, persistingChannel)
277
+
278
+ for (const mw of aiMiddlewares) {
279
+ if (mw.afterStep) {
280
+ await mw.afterStep(singletonServices, {
281
+ stepNumber: step,
282
+ text: stepResult.text,
283
+ toolCalls: stepResult.toolCalls,
284
+ toolResults: stepResult.toolResults,
285
+ usage: stepResult.usage,
286
+ finishReason: stepResult.finishReason,
287
+ })
288
+ }
289
+ }
290
+
291
+ if (stepResult.toolCalls.length === 0) break
292
+
293
+ const approvalNeeded = checkForApproval(
294
+ stepResult,
295
+ runnerParams.tools,
296
+ runId
297
+ )
298
+ if (approvalNeeded) {
299
+ return { outcome: 'approval', approval: approvalNeeded }
300
+ }
301
+
302
+ appendStepMessages(runnerParams, stepResult)
303
+ }
304
+
305
+ return { outcome: 'done' }
306
+ }
307
+
308
+ function checkForApproval(
309
+ stepResult: AIAgentStepResult,
310
+ tools: AIAgentRunnerParams['tools'],
311
+ runId: string
312
+ ): ToolApprovalRequired | null {
313
+ for (const tc of stepResult.toolCalls) {
314
+ const toolDef = tools.find((t) => t.name === tc.toolName)
315
+
316
+ if (toolDef?.needsApproval) {
317
+ return new ToolApprovalRequired(tc.toolCallId, tc.toolName, tc.args)
318
+ }
319
+
320
+ const tr = stepResult.toolResults.find(
321
+ (r) => r.toolCallId === tc.toolCallId
322
+ )
323
+ if (
324
+ tr?.result &&
325
+ typeof tr.result === 'object' &&
326
+ '__approvalRequired' in (tr.result as object)
327
+ ) {
328
+ const r = tr.result as {
329
+ toolName: string
330
+ args: unknown
331
+ reason?: string
332
+ displayToolName?: string
333
+ displayArgs?: unknown
334
+ agentRunId?: string
335
+ }
336
+ return new ToolApprovalRequired(
337
+ tc.toolCallId,
338
+ r.toolName,
339
+ r.args,
340
+ r.reason,
341
+ r.displayToolName,
342
+ r.displayArgs,
343
+ r.agentRunId
344
+ )
345
+ }
346
+ }
347
+ return null
348
+ }
349
+
350
+ function appendStepMessages(
351
+ runnerParams: AIAgentRunnerParams,
352
+ stepResult: AIAgentStepResult
353
+ ): void {
354
+ const assistantMsg: AIMessage = {
355
+ id: randomUUID(),
356
+ role: 'assistant',
357
+ content: stepResult.text || undefined,
358
+ toolCalls:
359
+ stepResult.toolCalls.length > 0
360
+ ? stepResult.toolCalls.map((tc) => ({
361
+ id: tc.toolCallId,
362
+ name: tc.toolName,
363
+ args: tc.args as Record<string, unknown>,
364
+ }))
365
+ : undefined,
366
+ createdAt: new Date(),
367
+ }
368
+ runnerParams.messages.push(assistantMsg)
369
+
370
+ if (stepResult.toolResults.length > 0) {
371
+ const toolMsg: AIMessage = {
372
+ id: randomUUID(),
373
+ role: 'tool',
374
+ toolResults: stepResult.toolResults.map((tr) => ({
375
+ id: tr.toolCallId,
376
+ name: tr.toolName,
377
+ result:
378
+ typeof tr.result === 'string' ? tr.result : JSON.stringify(tr.result),
379
+ })),
380
+ createdAt: new Date(),
381
+ }
382
+ runnerParams.messages.push(toolMsg)
383
+ }
384
+ }
385
+
386
+ function handleApproval(
387
+ err: ToolApprovalRequired,
388
+ runId: string,
389
+ channel: AIStreamChannel,
390
+ aiRunState: AIRunStateService,
391
+ persistingChannel: PersistingChannel
392
+ ): Promise<void> {
393
+ return (async () => {
394
+ await persistingChannel.flush()
395
+
396
+ const pendingApproval = err.agentRunId
397
+ ? {
398
+ type: 'agent-call' as const,
399
+ toolCallId: err.toolCallId,
400
+ agentName: err.toolName,
401
+ agentRunId: err.agentRunId,
402
+ displayToolName: err.displayToolName ?? err.toolName,
403
+ displayArgs: err.displayArgs ?? err.args,
404
+ }
405
+ : {
406
+ type: 'tool-call' as const,
407
+ toolCallId: err.toolCallId,
408
+ toolName: err.toolName,
409
+ args: err.args,
410
+ }
411
+
412
+ await aiRunState.updateRun(runId, {
413
+ status: 'suspended',
414
+ suspendReason: 'approval',
415
+ pendingApprovals: [pendingApproval],
416
+ })
417
+
418
+ const approvalEvent = {
419
+ type: 'approval-request' as const,
420
+ toolCallId: err.toolCallId,
421
+ toolName: err.displayToolName ?? err.toolName,
422
+ args: err.displayArgs ?? err.args,
423
+ reason: err.reason,
424
+ runId,
425
+ }
426
+ channel.send(approvalEvent as any)
427
+ channel.send({ type: 'done' })
428
+ channel.close()
429
+ })()
430
+ }
431
+
432
+ export async function streamAIAgent(
433
+ agentName: string,
434
+ input:
435
+ | { message: string; threadId: string; resourceId: string }
436
+ | Record<string, unknown>,
437
+ channel: AIStreamChannel,
438
+ params: RunAIAgentParams,
439
+ agentSessionMap?: Map<string, string>,
440
+ options?: StreamAIAgentOptions
441
+ ): Promise<void> {
442
+ const sessionMap = agentSessionMap ?? new Map<string, string>()
443
+
444
+ const { agent: resolvedAgentForProtocol } = resolveAgent(agentName)
445
+ const inputRecord = input as Record<string, unknown>
446
+ const useUIMessageStream =
447
+ resolvedAgentForProtocol.protocol === 'ui-message-stream' ||
448
+ Array.isArray(inputRecord.messages)
449
+ let normalizedInput: { message: string; threadId: string; resourceId: string }
450
+ if (useUIMessageStream) {
451
+ normalizedInput = parseAssistantUIInput(inputRecord)
452
+ channel = createAssistantUIChannel(channel)
453
+ } else {
454
+ normalizedInput = input as {
455
+ message: string
456
+ threadId: string
457
+ resourceId: string
458
+ }
459
+ }
460
+
461
+ const streamContext: StreamContext = { channel, options }
462
+
463
+ const {
464
+ agent,
465
+ packageName,
466
+ resolvedName,
467
+ agentRunner,
468
+ storage,
469
+ memoryConfig,
470
+ threadId,
471
+ userMessage,
472
+ runnerParams,
473
+ maxSteps,
474
+ missingRpcs,
475
+ workingMemorySchemaName,
476
+ } = await prepareAgentRun(
477
+ agentName,
478
+ normalizedInput,
479
+ params,
480
+ sessionMap,
481
+ streamContext
482
+ )
483
+
484
+ const singletonServices = getSingletonServices()
485
+ const { aiRunState } = singletonServices
486
+ if (!aiRunState) {
487
+ throw new Error('AIRunStateService not available in singletonServices')
488
+ }
489
+
490
+ if (missingRpcs.length > 0) {
491
+ await aiRunState.createRun({
492
+ agentName,
493
+ threadId,
494
+ resourceId: normalizedInput.resourceId,
495
+ status: 'suspended',
496
+ suspendReason: 'rpc-missing',
497
+ missingRpcs,
498
+ usage: { inputTokens: 0, outputTokens: 0, model: agent.model },
499
+ createdAt: new Date(),
500
+ updatedAt: new Date(),
501
+ })
502
+ channel.send({ type: 'suspended', reason: 'rpc-missing', missingRpcs })
503
+ channel.send({ type: 'done' })
504
+ return
505
+ }
506
+
507
+ const aiMiddlewares: PikkuAIMiddlewareHooks[] = agent.aiMiddleware ?? []
508
+
509
+ let modifiedMessages = runnerParams.messages
510
+ let modifiedInstructions = runnerParams.instructions
511
+ for (const mw of aiMiddlewares) {
512
+ if (mw.modifyInput) {
513
+ const result = await mw.modifyInput(singletonServices, {
514
+ messages: modifiedMessages,
515
+ instructions: modifiedInstructions,
516
+ })
517
+ modifiedMessages = result.messages
518
+ modifiedInstructions = result.instructions
519
+ }
520
+ }
521
+ runnerParams.messages = modifiedMessages
522
+ runnerParams.instructions = modifiedInstructions
523
+
524
+ const runId = await aiRunState.createRun({
525
+ agentName,
526
+ threadId,
527
+ resourceId: normalizedInput.resourceId,
528
+ status: 'running',
529
+ usage: { inputTokens: 0, outputTokens: 0, model: agent.model },
530
+ createdAt: new Date(),
531
+ updatedAt: new Date(),
532
+ })
533
+
534
+ if (storage) {
535
+ await storage.saveMessages(threadId, [userMessage])
536
+ }
537
+
538
+ const streamMiddleware = aiMiddlewares
539
+ .filter((mw) => mw.modifyOutputStream)
540
+ .map((mw) => {
541
+ const state: Record<string, unknown> = {}
542
+ const allEvents: AIStreamEvent[] = []
543
+ return async (services: any, event: any, next: any) => {
544
+ allEvents.push(event)
545
+ const result = await mw.modifyOutputStream!(services, {
546
+ event,
547
+ allEvents,
548
+ state,
549
+ })
550
+ if (result != null) await next(result)
551
+ }
552
+ })
553
+
554
+ const agentsMeta = pikkuState(packageName, 'agent', 'agentsMeta')
555
+ const meta = agentsMeta[resolvedName]
556
+ const allChannelMiddleware = combineChannelMiddleware(
557
+ 'agent',
558
+ `stream:${agentName}`,
559
+ {
560
+ wireInheritedChannelMiddleware: meta?.channelMiddleware,
561
+ wireChannelMiddleware: [
562
+ ...((agent.channelMiddleware as any[]) ?? []),
563
+ ...streamMiddleware,
564
+ ],
565
+ }
566
+ )
567
+
568
+ const wrappedChannel =
569
+ allChannelMiddleware.length > 0
570
+ ? (wrapChannelWithMiddleware(
571
+ { channel },
572
+ singletonServices,
573
+ allChannelMiddleware
574
+ ).channel as AIStreamChannel)
575
+ : channel
576
+
577
+ const persistingChannel = createPersistingChannel(
578
+ wrappedChannel,
579
+ storage,
580
+ threadId
581
+ )
582
+
583
+ try {
584
+ const loopResult = await runStreamStepLoop({
585
+ agent,
586
+ runnerParams,
587
+ maxSteps,
588
+ agentRunner,
589
+ persistingChannel,
590
+ channel,
591
+ runId,
592
+ aiMiddlewares,
593
+ })
594
+
595
+ if (loopResult.outcome === 'approval') {
596
+ await handleApproval(
597
+ loopResult.approval,
598
+ runId,
599
+ channel,
600
+ aiRunState,
601
+ persistingChannel
602
+ )
603
+ return
604
+ }
605
+
606
+ await postStreamCleanup(
607
+ persistingChannel,
608
+ aiMiddlewares,
609
+ singletonServices,
610
+ storage,
611
+ memoryConfig,
612
+ threadId,
613
+ workingMemorySchemaName,
614
+ runnerParams.messages,
615
+ aiRunState,
616
+ runId
617
+ )
618
+
619
+ channel.send({ type: 'done' })
620
+ channel.close()
621
+ } catch (err) {
622
+ for (const mw of aiMiddlewares) {
623
+ if (mw.onError) {
624
+ try {
625
+ await mw.onError(singletonServices, {
626
+ error: err instanceof Error ? err : new Error(String(err)),
627
+ stepNumber: -1,
628
+ messages: runnerParams.messages,
629
+ })
630
+ } catch {
631
+ // onError hooks must not affect error flow
632
+ }
633
+ }
634
+ }
635
+ await aiRunState.updateRun(runId, { status: 'failed' })
636
+ channel.send({
637
+ type: 'error',
638
+ message: err instanceof Error ? err.message : String(err),
639
+ })
640
+ channel.send({ type: 'done' })
641
+ channel.close()
642
+ }
643
+ }
644
+
645
+ export async function resumeAIAgent(
646
+ input: {
647
+ runId: string
648
+ toolCallId: string
649
+ approved: boolean
650
+ },
651
+ channel: AIStreamChannel,
652
+ params: RunAIAgentParams,
653
+ options?: StreamAIAgentOptions
654
+ ): Promise<void> {
655
+ const singletonServices = getSingletonServices()
656
+ const { aiRunState } = singletonServices
657
+ if (!aiRunState) {
658
+ throw new Error('AIRunStateService not available in singletonServices')
659
+ }
660
+
661
+ const run = await aiRunState.getRun(input.runId)
662
+ if (!run) {
663
+ throw new Error(`No run found for runId ${input.runId}`)
664
+ }
665
+
666
+ const pending = run.pendingApprovals?.find(
667
+ (p) => p.toolCallId === input.toolCallId
668
+ )
669
+ if (!pending) {
670
+ throw new Error(
671
+ `No pending approval for toolCallId ${input.toolCallId} on run ${input.runId}`
672
+ )
673
+ }
674
+
675
+ await aiRunState.resolveApproval(
676
+ input.toolCallId,
677
+ input.approved ? 'approved' : 'denied'
678
+ )
679
+
680
+ const { agent, packageName, resolvedName } = resolveAgent(run.agentName)
681
+ const { storage } = resolveMemoryServices(agent, singletonServices)
682
+ const memoryConfig = agent.memory
683
+ const agentRunner = singletonServices.aiAgentRunner
684
+ if (!agentRunner) {
685
+ throw new Error('AIAgentRunnerService not available in singletonServices')
686
+ }
687
+
688
+ if (!input.approved) {
689
+ if (pending.type === 'agent-call') {
690
+ await aiRunState.updateRun(pending.agentRunId, { status: 'failed' })
691
+ }
692
+
693
+ const denialResult = 'Tool call was not approved by the user'
694
+
695
+ if (storage) {
696
+ await storage.saveMessages(run.threadId, [
697
+ {
698
+ id: randomUUID(),
699
+ role: 'tool',
700
+ toolResults: [
701
+ {
702
+ id: input.toolCallId,
703
+ name:
704
+ pending.type === 'tool-call'
705
+ ? pending.toolName
706
+ : pending.agentName,
707
+ result: denialResult,
708
+ },
709
+ ],
710
+ createdAt: new Date(),
711
+ },
712
+ ])
713
+ }
714
+
715
+ await aiRunState.updateRun(run.runId, { status: 'running' })
716
+
717
+ await continueAfterToolResult(
718
+ run,
719
+ agent,
720
+ packageName,
721
+ resolvedName,
722
+ storage,
723
+ memoryConfig,
724
+ agentRunner,
725
+ channel,
726
+ params,
727
+ aiRunState,
728
+ options
729
+ )
730
+ return
731
+ }
732
+
733
+ if (pending.type === 'agent-call') {
734
+ const subRun = await aiRunState.getRun(pending.agentRunId)
735
+ if (!subRun) {
736
+ throw new Error(`Sub-agent run not found: ${pending.agentRunId}`)
737
+ }
738
+ const subPending = subRun.pendingApprovals?.[0]
739
+ if (!subPending) {
740
+ throw new Error(
741
+ `No pending approval on sub-agent run ${pending.agentRunId}`
742
+ )
743
+ }
744
+
745
+ const subChannel = createScopedChannel(channel, subRun.agentName, 'resume')
746
+ channel.send({
747
+ type: 'agent-call',
748
+ agentName: subRun.agentName,
749
+ session: 'resume',
750
+ input: null,
751
+ })
752
+
753
+ await resumeAIAgent(
754
+ {
755
+ runId: pending.agentRunId,
756
+ toolCallId: subPending.toolCallId,
757
+ approved: true,
758
+ },
759
+ subChannel,
760
+ params,
761
+ options
762
+ )
763
+
764
+ channel.send({
765
+ type: 'agent-result',
766
+ agentName: subRun.agentName,
767
+ session: 'resume',
768
+ result: null,
769
+ })
770
+
771
+ if (storage) {
772
+ await storage.saveMessages(run.threadId, [
773
+ {
774
+ id: randomUUID(),
775
+ role: 'tool',
776
+ toolResults: [
777
+ {
778
+ id: input.toolCallId,
779
+ name: pending.agentName,
780
+ result: 'Sub-agent completed successfully',
781
+ },
782
+ ],
783
+ createdAt: new Date(),
784
+ },
785
+ ])
786
+ }
787
+ } else {
788
+ const streamContext: StreamContext = {
789
+ channel,
790
+ options: { ...options, requiresToolApproval: false },
791
+ }
792
+ const aiMiddlewaresForResume: PikkuAIMiddlewareHooks[] =
793
+ agent.aiMiddleware ?? []
794
+ const { tools } = buildToolDefs(
795
+ params,
796
+ new Map<string, string>(),
797
+ run.resourceId,
798
+ resolvedName,
799
+ packageName,
800
+ streamContext,
801
+ aiMiddlewaresForResume
802
+ )
803
+
804
+ const matchingTool = tools.find((t) => t.name === pending.toolName)
805
+ if (!matchingTool) {
806
+ throw new Error(
807
+ `Tool "${pending.toolName}" not found in agent definition`
808
+ )
809
+ }
810
+
811
+ const toolArgs =
812
+ typeof pending.args === 'string' ? JSON.parse(pending.args) : pending.args
813
+
814
+ let toolResult: unknown
815
+ try {
816
+ toolResult = await matchingTool.execute(toolArgs)
817
+ } catch (execErr) {
818
+ toolResult = `Error: ${execErr instanceof Error ? execErr.message : String(execErr)}`
819
+ }
820
+
821
+ const resultStr =
822
+ typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult)
823
+ if (storage) {
824
+ await storage.saveMessages(run.threadId, [
825
+ {
826
+ id: randomUUID(),
827
+ role: 'tool',
828
+ toolResults: [
829
+ {
830
+ id: input.toolCallId,
831
+ name: pending.toolName,
832
+ result: resultStr,
833
+ },
834
+ ],
835
+ createdAt: new Date(),
836
+ },
837
+ ])
838
+ }
839
+
840
+ channel.send({
841
+ type: 'tool-result',
842
+ toolCallId: input.toolCallId,
843
+ toolName: pending.toolName,
844
+ result: toolResult,
845
+ })
846
+ }
847
+
848
+ await aiRunState.updateRun(run.runId, { status: 'running' })
849
+
850
+ await continueAfterToolResult(
851
+ run,
852
+ agent,
853
+ packageName,
854
+ resolvedName,
855
+ storage,
856
+ memoryConfig,
857
+ agentRunner,
858
+ channel,
859
+ params,
860
+ aiRunState,
861
+ options
862
+ )
863
+ }
864
+
865
+ async function continueAfterToolResult(
866
+ run: AgentRunState,
867
+ agent: CoreAIAgent,
868
+ packageName: string | null,
869
+ resolvedName: string,
870
+ storage: AIStorageService | undefined,
871
+ memoryConfig: AIAgentMemoryConfig | undefined,
872
+ agentRunner: AIAgentRunnerService,
873
+ channel: AIStreamChannel,
874
+ params: RunAIAgentParams,
875
+ aiRunState: AIRunStateService,
876
+ options?: StreamAIAgentOptions
877
+ ): Promise<void> {
878
+ const singletonServices = getSingletonServices()
879
+ const agentsMeta = pikkuState(packageName, 'agent', 'agentsMeta')
880
+ const meta = agentsMeta[resolvedName]
881
+ const workingMemorySchemaName = meta?.workingMemorySchema ?? null
882
+
883
+ const messages = storage
884
+ ? await storage.getMessages(run.threadId, {
885
+ lastN: memoryConfig?.lastMessages ?? 20,
886
+ })
887
+ : []
888
+
889
+ const workingMemoryJsonSchema = workingMemorySchemaName
890
+ ? pikkuState(packageName, 'misc', 'schemas').get(workingMemorySchemaName)
891
+ : undefined
892
+
893
+ const contextMessages = await loadContextMessages(
894
+ memoryConfig,
895
+ storage,
896
+ { message: '', threadId: run.threadId, resourceId: run.resourceId },
897
+ workingMemoryJsonSchema
898
+ )
899
+
900
+ const allMessages = [...contextMessages, ...messages]
901
+ const trimmedMessages = trimMessages(allMessages)
902
+
903
+ const instructions = buildInstructions(resolvedName, packageName)
904
+
905
+ const aiMiddlewares: PikkuAIMiddlewareHooks[] = agent.aiMiddleware ?? []
906
+ let modifiedMessages = trimmedMessages
907
+ let modifiedInstructions = instructions
908
+ for (const mw of aiMiddlewares) {
909
+ if (mw.modifyInput) {
910
+ const result = await mw.modifyInput(singletonServices, {
911
+ messages: modifiedMessages,
912
+ instructions: modifiedInstructions,
913
+ })
914
+ modifiedMessages = result.messages
915
+ modifiedInstructions = result.instructions
916
+ }
917
+ }
918
+
919
+ const streamMiddleware = aiMiddlewares
920
+ .filter((mw) => mw.modifyOutputStream)
921
+ .map((mw) => {
922
+ const state: Record<string, unknown> = {}
923
+ const allEvents: AIStreamEvent[] = []
924
+ return async (services: any, event: any, next: any) => {
925
+ allEvents.push(event)
926
+ const result = await mw.modifyOutputStream!(services, {
927
+ event,
928
+ allEvents,
929
+ state,
930
+ })
931
+ if (result != null) await next(result)
932
+ }
933
+ })
934
+
935
+ const allChannelMiddleware = combineChannelMiddleware(
936
+ 'agent',
937
+ `stream:${run.agentName}`,
938
+ {
939
+ wireInheritedChannelMiddleware: meta?.channelMiddleware,
940
+ wireChannelMiddleware: [
941
+ ...((agent.channelMiddleware as any[]) ?? []),
942
+ ...streamMiddleware,
943
+ ],
944
+ }
945
+ )
946
+
947
+ const wrappedChannel =
948
+ allChannelMiddleware.length > 0
949
+ ? (wrapChannelWithMiddleware(
950
+ { channel },
951
+ singletonServices,
952
+ allChannelMiddleware
953
+ ).channel as AIStreamChannel)
954
+ : channel
955
+
956
+ const persistingChannel = createPersistingChannel(
957
+ wrappedChannel,
958
+ storage,
959
+ run.threadId
960
+ )
961
+
962
+ const streamContext: StreamContext = { channel, options }
963
+ const resumeTools = buildToolDefs(
964
+ params,
965
+ new Map<string, string>(),
966
+ run.resourceId,
967
+ resolvedName,
968
+ packageName,
969
+ streamContext,
970
+ aiMiddlewares
971
+ ).tools
972
+
973
+ const resolved = resolveModelConfig(resolvedName, agent)
974
+ const maxSteps = resolved.maxSteps ?? 10
975
+
976
+ const runnerParams: AIAgentRunnerParams = {
977
+ model: resolved.model,
978
+ temperature: resolved.temperature,
979
+ instructions: modifiedInstructions,
980
+ messages: modifiedMessages,
981
+ tools: resumeTools,
982
+ maxSteps: 1,
983
+ toolChoice: (agent.toolChoice ?? 'auto') as 'auto' | 'required' | 'none',
984
+ outputSchema: meta?.outputSchema
985
+ ? pikkuState(packageName, 'misc', 'schemas').get(meta.outputSchema)
986
+ : undefined,
987
+ }
988
+
989
+ try {
990
+ const loopResult = await runStreamStepLoop({
991
+ agent,
992
+ runnerParams,
993
+ maxSteps,
994
+ agentRunner,
995
+ persistingChannel,
996
+ channel,
997
+ runId: run.runId,
998
+ aiMiddlewares,
999
+ })
1000
+
1001
+ if (loopResult.outcome === 'approval') {
1002
+ await handleApproval(
1003
+ loopResult.approval,
1004
+ run.runId,
1005
+ channel,
1006
+ aiRunState,
1007
+ persistingChannel
1008
+ )
1009
+ return
1010
+ }
1011
+
1012
+ await postStreamCleanup(
1013
+ persistingChannel,
1014
+ aiMiddlewares,
1015
+ singletonServices,
1016
+ storage,
1017
+ memoryConfig,
1018
+ run.threadId,
1019
+ workingMemorySchemaName,
1020
+ runnerParams.messages,
1021
+ aiRunState,
1022
+ run.runId
1023
+ )
1024
+
1025
+ channel.send({ type: 'done' })
1026
+ channel.close()
1027
+ } catch (err) {
1028
+ for (const mw of aiMiddlewares) {
1029
+ if (mw.onError) {
1030
+ try {
1031
+ await mw.onError(singletonServices, {
1032
+ error: err instanceof Error ? err : new Error(String(err)),
1033
+ stepNumber: -1,
1034
+ messages: runnerParams.messages,
1035
+ })
1036
+ } catch {
1037
+ // onError hooks must not affect error flow
1038
+ }
1039
+ }
1040
+ }
1041
+ await aiRunState.updateRun(run.runId, { status: 'failed' })
1042
+ channel.send({
1043
+ type: 'error',
1044
+ message: err instanceof Error ? err.message : String(err),
1045
+ })
1046
+ channel.send({ type: 'done' })
1047
+ channel.close()
1048
+ }
1049
+ }