@pikku/core 0.11.2 → 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 (344) hide show
  1. package/CHANGELOG.md +33 -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 +8 -0
  5. package/dist/errors/errors.js +16 -0
  6. package/dist/errors/index.d.ts +0 -1
  7. package/dist/errors/index.js +0 -1
  8. package/dist/function/function-runner.d.ts +7 -1
  9. package/dist/function/function-runner.js +82 -23
  10. package/dist/function/functions.types.d.ts +31 -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.js +1 -10
  15. package/dist/index.d.ts +28 -26
  16. package/dist/index.js +18 -29
  17. package/dist/middleware/auth-apikey.d.ts +2 -2
  18. package/dist/middleware/auth-apikey.js +3 -3
  19. package/dist/middleware/auth-bearer.d.ts +2 -2
  20. package/dist/middleware/auth-bearer.js +3 -6
  21. package/dist/middleware/auth-cookie.d.ts +2 -2
  22. package/dist/middleware/auth-cookie.js +6 -8
  23. package/dist/middleware/cors.d.ts +46 -0
  24. package/dist/middleware/cors.js +73 -0
  25. package/dist/middleware/index.d.ts +5 -3
  26. package/dist/middleware/index.js +5 -3
  27. package/dist/middleware/remote-auth.d.ts +5 -0
  28. package/dist/middleware/remote-auth.js +55 -0
  29. package/dist/middleware/timeout.d.ts +2 -2
  30. package/dist/middleware-runner.js +8 -10
  31. package/dist/permissions.js +11 -15
  32. package/dist/pikku-state.d.ts +1 -0
  33. package/dist/pikku-state.js +18 -8
  34. package/dist/schema.js +12 -11
  35. package/dist/services/ai-agent-runner-service.d.ts +24 -0
  36. package/dist/services/ai-agent-runner-service.js +1 -0
  37. package/dist/services/ai-run-state-service.d.ts +13 -0
  38. package/dist/services/ai-run-state-service.js +1 -0
  39. package/dist/services/ai-storage-service.d.ts +18 -0
  40. package/dist/services/ai-storage-service.js +1 -0
  41. package/dist/services/deployment-service.d.ts +19 -0
  42. package/dist/services/deployment-service.js +1 -0
  43. package/dist/services/gopass-secrets.d.ts +47 -0
  44. package/dist/services/gopass-secrets.js +94 -0
  45. package/dist/services/in-memory-trigger-service.d.ts +23 -0
  46. package/dist/services/in-memory-trigger-service.js +50 -0
  47. package/dist/services/in-memory-workflow-service.d.ts +59 -0
  48. package/dist/services/in-memory-workflow-service.js +287 -0
  49. package/dist/services/index.d.ts +25 -11
  50. package/dist/services/index.js +10 -13
  51. package/dist/services/local-secrets.d.ts +23 -0
  52. package/dist/services/local-secrets.js +45 -0
  53. package/dist/services/local-variables.d.ts +5 -0
  54. package/dist/services/local-variables.js +18 -0
  55. package/dist/services/scheduler-service.d.ts +21 -1
  56. package/dist/services/scheduler-service.js +14 -0
  57. package/dist/services/schema-service.d.ts +6 -0
  58. package/dist/services/scoped-secret-service.d.ts +16 -0
  59. package/dist/services/scoped-secret-service.js +35 -0
  60. package/dist/services/secret-service.d.ts +25 -4
  61. package/dist/services/trigger-service.d.ts +23 -0
  62. package/dist/services/trigger-service.js +1 -0
  63. package/dist/services/typed-secret-service.d.ts +30 -0
  64. package/dist/services/typed-secret-service.js +40 -0
  65. package/dist/services/typed-variables-service.d.ts +27 -0
  66. package/dist/services/typed-variables-service.js +46 -0
  67. package/dist/services/user-session-service.d.ts +13 -0
  68. package/dist/services/user-session-service.js +17 -0
  69. package/dist/services/variables-service.d.ts +5 -0
  70. package/dist/services/workflow-service.d.ts +9 -4
  71. package/dist/types/core.types.d.ts +48 -12
  72. package/dist/types/core.types.js +8 -1
  73. package/dist/types/state.types.d.ts +43 -51
  74. package/dist/utils.d.ts +3 -2
  75. package/dist/utils.js +15 -3
  76. package/dist/version.d.ts +6 -0
  77. package/dist/version.js +19 -0
  78. package/dist/wirings/ai-agent/ai-agent-memory.d.ts +29 -0
  79. package/dist/wirings/ai-agent/ai-agent-memory.js +199 -0
  80. package/dist/wirings/ai-agent/ai-agent-model-config.d.ts +9 -0
  81. package/dist/wirings/ai-agent/ai-agent-model-config.js +36 -0
  82. package/dist/wirings/ai-agent/ai-agent-prepare.d.ts +60 -0
  83. package/dist/wirings/ai-agent/ai-agent-prepare.js +312 -0
  84. package/dist/wirings/ai-agent/ai-agent-registry.d.ts +15 -0
  85. package/dist/wirings/ai-agent/ai-agent-registry.js +47 -0
  86. package/dist/wirings/ai-agent/ai-agent-runner.d.ts +3 -0
  87. package/dist/wirings/ai-agent/ai-agent-runner.js +96 -0
  88. package/dist/wirings/ai-agent/ai-agent-stream.d.ts +11 -0
  89. package/dist/wirings/ai-agent/ai-agent-stream.js +503 -0
  90. package/dist/wirings/ai-agent/ai-agent.types.d.ts +254 -0
  91. package/dist/wirings/ai-agent/ai-agent.types.js +1 -0
  92. package/dist/wirings/ai-agent/index.d.ts +5 -0
  93. package/dist/wirings/ai-agent/index.js +4 -0
  94. package/dist/wirings/channel/channel-common.d.ts +7 -4
  95. package/dist/wirings/channel/channel-common.js +15 -8
  96. package/dist/wirings/channel/channel-handler.js +12 -3
  97. package/dist/wirings/channel/channel-middleware-runner.d.ts +9 -0
  98. package/dist/wirings/channel/channel-middleware-runner.js +73 -0
  99. package/dist/wirings/channel/channel-runner.js +7 -7
  100. package/dist/wirings/channel/channel.types.d.ts +5 -1
  101. package/dist/wirings/channel/define-channel-routes.d.ts +21 -0
  102. package/dist/wirings/channel/define-channel-routes.js +23 -0
  103. package/dist/wirings/channel/index.d.ts +10 -8
  104. package/dist/wirings/channel/index.js +7 -8
  105. package/dist/wirings/channel/local/index.d.ts +3 -3
  106. package/dist/wirings/channel/local/index.js +3 -3
  107. package/dist/wirings/channel/local/local-channel-runner.js +18 -6
  108. package/dist/wirings/channel/serverless/index.d.ts +1 -1
  109. package/dist/wirings/channel/serverless/index.js +1 -1
  110. package/dist/wirings/channel/serverless/serverless-channel-runner.js +15 -4
  111. package/dist/wirings/cli/channel/index.d.ts +1 -1
  112. package/dist/wirings/cli/channel/index.js +1 -1
  113. package/dist/wirings/cli/cli-runner.d.ts +1 -1
  114. package/dist/wirings/cli/cli-runner.js +12 -8
  115. package/dist/wirings/cli/cli.types.d.ts +6 -6
  116. package/dist/wirings/cli/define-cli-commands.d.ts +19 -0
  117. package/dist/wirings/cli/define-cli-commands.js +20 -0
  118. package/dist/wirings/cli/index.d.ts +2 -3
  119. package/dist/wirings/cli/index.js +1 -3
  120. package/dist/wirings/http/http-routes.d.ts +69 -0
  121. package/dist/wirings/http/http-routes.js +139 -0
  122. package/dist/wirings/http/http-runner.js +49 -23
  123. package/dist/wirings/http/http.types.d.ts +78 -38
  124. package/dist/wirings/http/index.d.ts +5 -4
  125. package/dist/wirings/http/index.js +4 -3
  126. package/dist/wirings/mcp/index.d.ts +4 -3
  127. package/dist/wirings/mcp/index.js +3 -3
  128. package/dist/wirings/mcp/mcp-runner.d.ts +1 -3
  129. package/dist/wirings/mcp/mcp-runner.js +25 -39
  130. package/dist/wirings/mcp/mcp.types.d.ts +3 -3
  131. package/dist/wirings/node/index.d.ts +2 -0
  132. package/dist/wirings/node/index.js +1 -0
  133. package/dist/wirings/node/node.types.d.ts +20 -0
  134. package/dist/wirings/node/node.types.js +1 -0
  135. package/dist/wirings/oauth2/index.d.ts +3 -0
  136. package/dist/wirings/oauth2/index.js +2 -0
  137. package/dist/wirings/oauth2/oauth2-client.d.ts +47 -0
  138. package/dist/wirings/oauth2/oauth2-client.js +267 -0
  139. package/dist/wirings/oauth2/oauth2.types.d.ts +65 -0
  140. package/dist/wirings/oauth2/oauth2.types.js +4 -0
  141. package/dist/wirings/oauth2/wire-oauth2-credential.d.ts +20 -0
  142. package/dist/wirings/oauth2/wire-oauth2-credential.js +21 -0
  143. package/dist/wirings/queue/index.d.ts +2 -2
  144. package/dist/wirings/queue/index.js +1 -1
  145. package/dist/wirings/queue/queue-runner.d.ts +7 -0
  146. package/dist/wirings/queue/queue-runner.js +17 -6
  147. package/dist/wirings/queue/queue.types.d.ts +8 -2
  148. package/dist/wirings/rpc/index.d.ts +1 -1
  149. package/dist/wirings/rpc/index.js +1 -1
  150. package/dist/wirings/rpc/rpc-runner.d.ts +33 -5
  151. package/dist/wirings/rpc/rpc-runner.js +134 -16
  152. package/dist/wirings/rpc/rpc-types.d.ts +8 -4
  153. package/dist/wirings/scheduler/index.d.ts +3 -3
  154. package/dist/wirings/scheduler/index.js +2 -3
  155. package/dist/wirings/scheduler/scheduler-runner.d.ts +5 -0
  156. package/dist/wirings/scheduler/scheduler-runner.js +23 -5
  157. package/dist/wirings/secret/index.d.ts +3 -0
  158. package/dist/wirings/secret/index.js +2 -0
  159. package/dist/wirings/secret/secret.types.d.ts +27 -0
  160. package/dist/wirings/secret/secret.types.js +1 -0
  161. package/dist/wirings/secret/validate-secret-definitions.d.ts +6 -0
  162. package/dist/wirings/secret/validate-secret-definitions.js +55 -0
  163. package/dist/wirings/trigger/index.d.ts +3 -2
  164. package/dist/wirings/trigger/index.js +2 -2
  165. package/dist/wirings/trigger/pikku-trigger-service.d.ts +26 -0
  166. package/dist/wirings/trigger/pikku-trigger-service.js +75 -0
  167. package/dist/wirings/trigger/trigger-runner.d.ts +21 -8
  168. package/dist/wirings/trigger/trigger-runner.js +46 -18
  169. package/dist/wirings/trigger/trigger.types.d.ts +99 -11
  170. package/dist/wirings/trigger/trigger.types.js +40 -1
  171. package/dist/wirings/variable/index.d.ts +3 -0
  172. package/dist/wirings/variable/index.js +2 -0
  173. package/dist/wirings/variable/validate-variable-definitions.d.ts +6 -0
  174. package/dist/wirings/variable/validate-variable-definitions.js +45 -0
  175. package/dist/wirings/variable/variable.types.d.ts +18 -0
  176. package/dist/wirings/variable/variable.types.js +1 -0
  177. package/dist/wirings/workflow/dsl/index.d.ts +1 -1
  178. package/dist/wirings/workflow/dsl/workflow-dsl.types.d.ts +7 -1
  179. package/dist/wirings/workflow/dsl/workflow-runner.js +3 -2
  180. package/dist/wirings/workflow/graph/graph-node.d.ts +1 -6
  181. package/dist/wirings/workflow/graph/graph-runner.d.ts +5 -31
  182. package/dist/wirings/workflow/graph/graph-runner.js +384 -296
  183. package/dist/wirings/workflow/graph/index.d.ts +4 -3
  184. package/dist/wirings/workflow/graph/index.js +3 -3
  185. package/dist/wirings/workflow/graph/template.d.ts +15 -0
  186. package/dist/wirings/workflow/graph/template.js +27 -0
  187. package/dist/wirings/workflow/graph/wire-workflow-graph.d.ts +15 -0
  188. package/dist/wirings/workflow/graph/wire-workflow-graph.js +8 -0
  189. package/dist/wirings/workflow/graph/workflow-graph.types.d.ts +0 -13
  190. package/dist/wirings/workflow/index.d.ts +6 -6
  191. package/dist/wirings/workflow/index.js +6 -4
  192. package/dist/wirings/workflow/pikku-workflow-service.d.ts +28 -14
  193. package/dist/wirings/workflow/pikku-workflow-service.js +200 -56
  194. package/dist/wirings/workflow/workflow-helpers.d.ts +36 -0
  195. package/dist/wirings/workflow/workflow-helpers.js +38 -0
  196. package/dist/wirings/workflow/workflow-utils.d.ts +1 -23
  197. package/dist/wirings/workflow/workflow-utils.js +1 -66
  198. package/dist/wirings/workflow/workflow.types.d.ts +40 -93
  199. package/package.json +13 -15
  200. package/run-tests.sh +4 -1
  201. package/src/crypto-utils.ts +99 -0
  202. package/src/errors/errors.ts +17 -0
  203. package/src/errors/index.ts +0 -1
  204. package/src/factory-functions.test.ts +42 -2
  205. package/src/function/function-runner.test.ts +4 -11
  206. package/src/function/function-runner.ts +114 -29
  207. package/src/function/functions.types.ts +62 -132
  208. package/src/function/index.ts +5 -2
  209. package/src/handle-error.ts +2 -10
  210. package/src/index.ts +99 -25
  211. package/src/middleware/auth-apikey.test.ts +15 -12
  212. package/src/middleware/auth-apikey.ts +3 -3
  213. package/src/middleware/auth-bearer.test.ts +17 -14
  214. package/src/middleware/auth-bearer.ts +25 -27
  215. package/src/middleware/auth-cookie.test.ts +16 -13
  216. package/src/middleware/auth-cookie.ts +6 -8
  217. package/src/middleware/cors.ts +96 -0
  218. package/src/middleware/index.ts +5 -3
  219. package/src/middleware/remote-auth.ts +68 -0
  220. package/src/middleware-runner.test.ts +122 -0
  221. package/src/middleware-runner.ts +12 -12
  222. package/src/permissions.test.ts +81 -7
  223. package/src/permissions.ts +15 -17
  224. package/src/pikku-state.ts +20 -8
  225. package/src/run-tests-script.test.ts +49 -0
  226. package/src/schema.ts +18 -15
  227. package/src/services/ai-agent-runner-service.ts +29 -0
  228. package/src/services/ai-run-state-service.ts +20 -0
  229. package/src/services/ai-storage-service.ts +39 -0
  230. package/src/services/deployment-service.ts +22 -0
  231. package/src/services/gopass-secrets.ts +95 -0
  232. package/src/services/in-memory-trigger-service.ts +68 -0
  233. package/src/services/in-memory-workflow-service.ts +395 -0
  234. package/src/services/index.ts +49 -14
  235. package/src/services/local-secrets.ts +51 -0
  236. package/src/services/local-variables.ts +22 -0
  237. package/src/services/scheduler-service.ts +29 -1
  238. package/src/services/schema-service.ts +7 -0
  239. package/src/services/scoped-secret-service.ts +41 -0
  240. package/src/services/secret-service.ts +25 -4
  241. package/src/services/trigger-service.ts +38 -0
  242. package/src/services/typed-secret-service.ts +70 -0
  243. package/src/services/typed-variables-service.ts +81 -0
  244. package/src/services/user-session-service.ts +23 -0
  245. package/src/services/variables-service.ts +5 -0
  246. package/src/services/workflow-service.ts +22 -2
  247. package/src/types/core.types.ts +76 -11
  248. package/src/types/state.types.ts +37 -63
  249. package/src/utils.ts +20 -6
  250. package/src/version.test.ts +80 -0
  251. package/src/version.ts +25 -0
  252. package/src/wirings/ai-agent/ai-agent-memory.ts +300 -0
  253. package/src/wirings/ai-agent/ai-agent-model-config.ts +43 -0
  254. package/src/wirings/ai-agent/ai-agent-prepare.ts +470 -0
  255. package/src/wirings/ai-agent/ai-agent-registry.test.ts +37 -0
  256. package/src/wirings/ai-agent/ai-agent-registry.ts +82 -0
  257. package/src/wirings/ai-agent/ai-agent-runner.test.ts +75 -0
  258. package/src/wirings/ai-agent/ai-agent-runner.ts +137 -0
  259. package/src/wirings/ai-agent/ai-agent-stream.test.ts +246 -0
  260. package/src/wirings/ai-agent/ai-agent-stream.ts +774 -0
  261. package/src/wirings/ai-agent/ai-agent.types.ts +273 -0
  262. package/src/wirings/ai-agent/index.ts +28 -0
  263. package/src/wirings/channel/channel-common.ts +32 -19
  264. package/src/wirings/channel/channel-handler.ts +17 -4
  265. package/src/wirings/channel/channel-middleware-runner.ts +119 -0
  266. package/src/wirings/channel/channel-runner.ts +9 -10
  267. package/src/wirings/channel/channel.types.ts +17 -1
  268. package/src/wirings/channel/define-channel-routes.ts +25 -0
  269. package/src/wirings/channel/index.ts +23 -8
  270. package/src/wirings/channel/local/index.ts +3 -3
  271. package/src/wirings/channel/local/local-channel-runner.test.ts +44 -1
  272. package/src/wirings/channel/local/local-channel-runner.ts +22 -6
  273. package/src/wirings/channel/serverless/index.ts +5 -1
  274. package/src/wirings/channel/serverless/serverless-channel-runner.ts +20 -4
  275. package/src/wirings/cli/channel/index.ts +1 -1
  276. package/src/wirings/cli/cli-runner.test.ts +9 -9
  277. package/src/wirings/cli/cli-runner.ts +17 -10
  278. package/src/wirings/cli/cli.types.ts +11 -11
  279. package/src/wirings/cli/command-parser.test.ts +8 -8
  280. package/src/wirings/cli/define-cli-commands.ts +24 -0
  281. package/src/wirings/cli/index.ts +10 -4
  282. package/src/wirings/http/http-routes.test.ts +322 -0
  283. package/src/wirings/http/http-routes.ts +198 -0
  284. package/src/wirings/http/http-runner.test.ts +3 -3
  285. package/src/wirings/http/http-runner.ts +63 -29
  286. package/src/wirings/http/http.types.ts +121 -37
  287. package/src/wirings/http/index.ts +16 -4
  288. package/src/wirings/mcp/index.ts +27 -3
  289. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +3 -3
  290. package/src/wirings/mcp/mcp-runner.ts +39 -50
  291. package/src/wirings/mcp/mcp.types.ts +3 -3
  292. package/src/wirings/node/index.ts +2 -0
  293. package/src/wirings/node/node.types.ts +23 -0
  294. package/src/wirings/oauth2/index.ts +3 -0
  295. package/src/wirings/oauth2/oauth2-client.test.ts +929 -0
  296. package/src/wirings/oauth2/oauth2-client.ts +335 -0
  297. package/src/wirings/oauth2/oauth2.types.ts +69 -0
  298. package/src/wirings/oauth2/wire-oauth2-credential.ts +23 -0
  299. package/src/wirings/queue/index.ts +14 -2
  300. package/src/wirings/queue/queue-runner.test.ts +97 -55
  301. package/src/wirings/queue/queue-runner.ts +33 -7
  302. package/src/wirings/queue/queue.types.ts +12 -2
  303. package/src/wirings/rpc/index.ts +1 -1
  304. package/src/wirings/rpc/rpc-runner.ts +187 -17
  305. package/src/wirings/rpc/rpc-types.ts +13 -4
  306. package/src/wirings/scheduler/index.ts +7 -4
  307. package/src/wirings/scheduler/scheduler-runner.test.ts +70 -26
  308. package/src/wirings/scheduler/scheduler-runner.ts +45 -5
  309. package/src/wirings/secret/index.ts +9 -0
  310. package/src/wirings/secret/secret.types.ts +32 -0
  311. package/src/wirings/secret/validate-secret-definitions.ts +82 -0
  312. package/src/wirings/trigger/index.ts +10 -2
  313. package/src/wirings/trigger/pikku-trigger-service.ts +134 -0
  314. package/src/wirings/trigger/trigger-runner.ts +80 -38
  315. package/src/wirings/trigger/trigger.types.ts +144 -22
  316. package/src/wirings/variable/index.ts +8 -0
  317. package/src/wirings/variable/validate-variable-definitions.ts +69 -0
  318. package/src/wirings/variable/variable.types.ts +22 -0
  319. package/src/wirings/workflow/dsl/index.ts +1 -0
  320. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +9 -1
  321. package/src/wirings/workflow/dsl/workflow-runner.ts +4 -3
  322. package/src/wirings/workflow/graph/graph-node.ts +1 -6
  323. package/src/wirings/workflow/graph/graph-runner.test.ts +495 -0
  324. package/src/wirings/workflow/graph/graph-runner.ts +496 -374
  325. package/src/wirings/workflow/graph/index.ts +14 -3
  326. package/src/wirings/workflow/graph/template.ts +42 -0
  327. package/src/wirings/workflow/graph/wire-workflow-graph.ts +29 -0
  328. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -22
  329. package/src/wirings/workflow/index.ts +21 -10
  330. package/src/wirings/workflow/pikku-workflow-service.test.ts +212 -0
  331. package/src/wirings/workflow/pikku-workflow-service.ts +285 -66
  332. package/src/wirings/workflow/workflow-helpers.ts +79 -0
  333. package/src/wirings/workflow/workflow-utils.ts +0 -120
  334. package/src/wirings/workflow/workflow.types.ts +45 -90
  335. package/tsconfig.tsbuildinfo +1 -1
  336. package/dist/wirings/forge-node/forge-node.types.d.ts +0 -120
  337. package/dist/wirings/forge-node/forge-node.types.js +0 -38
  338. package/dist/wirings/forge-node/index.d.ts +0 -1
  339. package/dist/wirings/forge-node/index.js +0 -1
  340. package/dist/wirings/workflow/wire-workflow.d.ts +0 -42
  341. package/dist/wirings/workflow/wire-workflow.js +0 -53
  342. package/src/wirings/forge-node/forge-node.types.ts +0 -135
  343. package/src/wirings/forge-node/index.ts +0 -1
  344. package/src/wirings/workflow/wire-workflow.ts +0 -94
@@ -1,8 +1,9 @@
1
1
  import { runPikkuFunc } from '../../function/function-runner.js';
2
2
  import { pikkuState } from '../../pikku-state.js';
3
3
  import { getDurationInMilliseconds } from '../../time-utils.js';
4
- import { executeGraphStep, runWorkflowGraph } from './graph/graph-runner.js';
5
- import { PikkuError } from '../../errors/error-handler.js';
4
+ import { continueGraph, executeGraphStep, runWorkflowGraph, runFromMeta, } from './graph/graph-runner.js';
5
+ import { PikkuError, addError } from '../../errors/error-handler.js';
6
+ import { RPCNotFoundError } from '../rpc/rpc-runner.js';
6
7
  /**
7
8
  * Exception thrown when workflow needs to pause for async step
8
9
  */
@@ -29,6 +30,19 @@ export class WorkflowCancelledException extends Error {
29
30
  this.name = 'WorkflowCancelledException';
30
31
  }
31
32
  }
33
+ /**
34
+ * Exception thrown when workflow is suspended
35
+ */
36
+ export class WorkflowSuspendedException extends Error {
37
+ runId;
38
+ reason;
39
+ constructor(runId, reason) {
40
+ super(reason || 'Workflow suspended');
41
+ this.runId = runId;
42
+ this.reason = reason;
43
+ this.name = 'WorkflowSuspendedException';
44
+ }
45
+ }
32
46
  /**
33
47
  * Error class for workflow not found
34
48
  */
@@ -37,14 +51,19 @@ export class WorkflowNotFoundError extends PikkuError {
37
51
  super(`Workflow not found: ${name}`);
38
52
  }
39
53
  }
40
- /**
41
- * Error class for workflow not found
42
- */
43
- export class WorkflowRunNotFound extends PikkuError {
54
+ addError(WorkflowNotFoundError, {
55
+ status: 404,
56
+ message: 'Workflow not found.',
57
+ });
58
+ export class WorkflowRunNotFoundError extends PikkuError {
44
59
  constructor(runId) {
45
60
  super(`Workflow run not found: ${runId}`);
46
61
  }
47
62
  }
63
+ addError(WorkflowRunNotFoundError, {
64
+ status: 404,
65
+ message: 'Workflow run not found.',
66
+ });
48
67
  export class WorkflowServiceNotInitialized extends Error {
49
68
  }
50
69
  export class WorkflowStepNameNotString extends Error {
@@ -52,6 +71,12 @@ export class WorkflowStepNameNotString extends Error {
52
71
  super(`Workflow step name must be a string. Received: ${typeof stepName}`);
53
72
  }
54
73
  }
74
+ const WORKFLOW_END_STATES = new Set([
75
+ 'completed',
76
+ 'failed',
77
+ 'cancelled',
78
+ 'suspended',
79
+ ]);
55
80
  /**
56
81
  * Abstract workflow state service
57
82
  * Implementations provide pluggable storage backends (SQLite, PostgreSQL, etc.)
@@ -92,6 +117,14 @@ export class PikkuWorkflowService {
92
117
  sleeperRPCName: workflow?.sleeperRPCName ?? 'pikkuWorkflowSleeper',
93
118
  };
94
119
  }
120
+ async registerWorkflowVersions() {
121
+ const allMeta = pikkuState(null, 'workflows', 'meta');
122
+ for (const [name, meta] of Object.entries(allMeta)) {
123
+ if (!meta.graphHash)
124
+ continue;
125
+ await this.upsertWorkflowVersion(name, meta.graphHash, meta, meta.source);
126
+ }
127
+ }
95
128
  // ============================================================================
96
129
  // Workflow Lifecycle Methods
97
130
  // ============================================================================
@@ -103,6 +136,15 @@ export class PikkuWorkflowService {
103
136
  const queueService = this.verifyQueueService();
104
137
  await queueService.add(this.getConfig().orchestratorQueueName, { runId });
105
138
  }
139
+ async queueStepWorker(runId, stepName, rpcName, data) {
140
+ const queueService = this.verifyQueueService();
141
+ await queueService.add(this.getConfig().stepWorkerQueueName, {
142
+ runId,
143
+ stepName,
144
+ rpcName,
145
+ data,
146
+ });
147
+ }
106
148
  /**
107
149
  * Execute a workflow sleep step completion
108
150
  * Sets the step result to null and resumes the workflow
@@ -127,7 +169,7 @@ export class PikkuWorkflowService {
127
169
  * @param options.inline - If true, execute workflow directly without queue service
128
170
  * @param options.startNode - Starting node ID for graph workflows (from wire config)
129
171
  */
130
- async startWorkflow(name, input, rpcService, options) {
172
+ async startWorkflow(name, input, wire, rpcService, options) {
131
173
  // Check meta to determine workflow type
132
174
  const meta = pikkuState(null, 'workflows', 'meta');
133
175
  const workflowMeta = meta[name];
@@ -136,8 +178,8 @@ export class PikkuWorkflowService {
136
178
  }
137
179
  // Check if this is a graph workflow (source === 'graph')
138
180
  if (workflowMeta.source === 'graph') {
139
- // Graph workflows use the graph scheduler
140
- return runWorkflowGraph(this, name, input, rpcService, options?.inline, options?.startNode);
181
+ const shouldInline = options?.inline || !this.singletonServices?.queueService;
182
+ return runWorkflowGraph(this, name, input, rpcService, shouldInline, options?.startNode, wire);
141
183
  }
142
184
  // DSL workflow - check registration exists
143
185
  const registrations = pikkuState(null, 'workflows', 'registrations');
@@ -145,34 +187,63 @@ export class PikkuWorkflowService {
145
187
  if (!workflow) {
146
188
  throw new WorkflowNotFoundError(name);
147
189
  }
148
- // Create workflow run in state
149
- const runId = await this.createRun(name, input, options?.inline);
150
- // Register inline run for fast lookup
190
+ if (!workflowMeta.graphHash) {
191
+ throw new Error(`Missing workflow graphHash for '${name}'`);
192
+ }
193
+ const runId = await this.createRun(name, input, options?.inline ?? false, workflowMeta.graphHash, wire);
151
194
  if (options?.inline) {
152
195
  this.inlineRuns.add(runId);
153
196
  }
154
- try {
155
- // If inline mode or no queue service, execute directly
156
- // Otherwise, use remote execution (queue-based)
157
- if (options?.inline || !this.singletonServices?.queueService) {
158
- await this.runWorkflowJob(runId, rpcService);
159
- }
160
- else {
161
- await this.resumeWorkflow(runId);
162
- }
163
- return { runId };
197
+ if (options?.inline || !this.singletonServices?.queueService) {
198
+ this.runWorkflowJob(runId, rpcService)
199
+ .catch(() => { })
200
+ .finally(() => {
201
+ if (options?.inline) {
202
+ this.inlineRuns.delete(runId);
203
+ }
204
+ });
205
+ }
206
+ else {
207
+ await this.resumeWorkflow(runId);
164
208
  }
165
- finally {
166
- // Clean up inline tracking
167
- if (options?.inline) {
168
- this.inlineRuns.delete(runId);
209
+ return { runId };
210
+ }
211
+ async runToCompletion(name, input, rpcService, options) {
212
+ const pollInterval = options?.pollIntervalMs ?? 1000;
213
+ const { runId } = await this.startWorkflow(name, input, options?.wire ?? { type: 'internal' }, rpcService, { inline: true });
214
+ while (true) {
215
+ const run = await this.getRun(runId);
216
+ if (!run) {
217
+ throw new WorkflowRunNotFoundError(runId);
169
218
  }
219
+ if (WORKFLOW_END_STATES.has(run.status)) {
220
+ if (run.status === 'failed') {
221
+ throw new Error(run.error?.message || 'Workflow failed');
222
+ }
223
+ if (run.status === 'cancelled') {
224
+ throw new Error('Workflow was cancelled');
225
+ }
226
+ return run.output;
227
+ }
228
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
170
229
  }
171
230
  }
172
231
  async runWorkflowJob(runId, rpcService) {
173
232
  const run = await this.getRun(runId);
174
233
  if (!run) {
175
- throw new WorkflowRunNotFound(runId);
234
+ throw new WorkflowRunNotFoundError(runId);
235
+ }
236
+ const meta = pikkuState(null, 'workflows', 'meta');
237
+ const workflowMeta = meta[run.workflow];
238
+ if (run.graphHash &&
239
+ workflowMeta?.graphHash &&
240
+ run.graphHash !== workflowMeta.graphHash) {
241
+ await this.runVersionMismatchFallback(run, workflowMeta, rpcService);
242
+ return;
243
+ }
244
+ if (workflowMeta?.source === 'graph') {
245
+ await continueGraph(this, runId, run.workflow);
246
+ return;
176
247
  }
177
248
  const registrations = pikkuState(null, 'workflows', 'registrations');
178
249
  const workflow = registrations.get(run.workflow);
@@ -180,12 +251,10 @@ export class PikkuWorkflowService {
180
251
  throw new WorkflowNotFoundError(run.workflow);
181
252
  }
182
253
  await this.withRunLock(runId, async () => {
183
- const meta = pikkuState(null, 'workflows', 'meta');
184
- const workflowMeta = meta[run.workflow];
185
254
  const workflowWire = this.createWorkflowWire(run.workflow, runId, rpcService);
186
255
  const wire = { workflow: workflowWire };
187
256
  try {
188
- const result = await runPikkuFunc('workflow', workflowMeta.name, workflowMeta.pikkuFuncName, {
257
+ const result = await runPikkuFunc('workflow', workflowMeta.name, workflowMeta.pikkuFuncId, {
189
258
  singletonServices: this.singletonServices,
190
259
  wire,
191
260
  createWireServices: this.createWireServices,
@@ -195,12 +264,9 @@ export class PikkuWorkflowService {
195
264
  }
196
265
  catch (error) {
197
266
  if (error instanceof WorkflowAsyncException) {
198
- // Normal - workflow paused for step execution
199
267
  throw error;
200
268
  }
201
- // Check if it's a WorkflowCancelledException
202
269
  if (error instanceof WorkflowCancelledException) {
203
- // Workflow was cancelled - update status and rethrow
204
270
  await this.updateRunStatus(runId, 'cancelled', undefined, {
205
271
  message: error.message || 'Workflow cancelled',
206
272
  stack: '',
@@ -208,6 +274,14 @@ export class PikkuWorkflowService {
208
274
  });
209
275
  throw error;
210
276
  }
277
+ if (error instanceof WorkflowSuspendedException) {
278
+ await this.updateRunStatus(runId, 'suspended', undefined, {
279
+ message: error.message || 'Workflow suspended',
280
+ stack: '',
281
+ code: 'WORKFLOW_SUSPENDED',
282
+ });
283
+ throw error;
284
+ }
211
285
  await this.updateRunStatus(runId, 'failed', undefined, {
212
286
  message: error.message,
213
287
  stack: error.stack,
@@ -217,6 +291,27 @@ export class PikkuWorkflowService {
217
291
  }
218
292
  });
219
293
  }
294
+ async runVersionMismatchFallback(run, currentMeta, rpcService) {
295
+ const source = currentMeta.source;
296
+ if (source === 'complex') {
297
+ await this.updateRunStatus(run.id, 'failed', undefined, {
298
+ message: `Workflow '${run.workflow}' definition changed. Complex workflows with inline steps cannot be migrated.`,
299
+ stack: '',
300
+ code: 'VERSION_CONFLICT',
301
+ });
302
+ return;
303
+ }
304
+ const version = await this.getWorkflowVersion(run.workflow, run.graphHash);
305
+ if (!version) {
306
+ await this.updateRunStatus(run.id, 'failed', undefined, {
307
+ message: `Workflow '${run.workflow}' version '${run.graphHash}' not found. Cannot resume with changed definition.`,
308
+ stack: '',
309
+ code: 'VERSION_NOT_FOUND',
310
+ });
311
+ return;
312
+ }
313
+ await runFromMeta(this, run.id, version.graph, rpcService);
314
+ }
220
315
  /**
221
316
  * Execute a single workflow step (called by worker)
222
317
  * Handles idempotency, RPC execution, result storage, retry logic, and orchestrator triggering
@@ -239,25 +334,22 @@ export class PikkuWorkflowService {
239
334
  if (stepState.status === 'failed') {
240
335
  stepState = await this.createRetryAttempt(stepState.stepId, 'running');
241
336
  }
242
- if (stepState.status !== 'pending') {
243
- // Mark step as running (pending or failed status)
337
+ if (stepState.status === 'pending') {
338
+ // Mark pending step as running before execution
244
339
  await this.setStepRunning(stepState.stepId);
245
340
  }
246
341
  try {
247
342
  let result;
248
- // Check if this is a graph node step (step name starts with 'node:')
249
- if (stepName.startsWith('node:')) {
250
- // Get the graph name from the workflow run
251
- const run = await this.getRun(runId);
252
- if (!run) {
253
- throw new Error(`Workflow run not found: ${runId}`);
254
- }
255
- const graphName = run.workflow;
256
- // Execute as graph step with graph wire context
257
- result = await executeGraphStep(this, rpcService, runId, stepState.stepId, stepName, rpcName, data, graphName);
343
+ const run = await this.getRun(runId);
344
+ if (!run) {
345
+ throw new Error(`Workflow run not found: ${runId}`);
346
+ }
347
+ const meta = pikkuState(null, 'workflows', 'meta');
348
+ const workflowMeta = meta[run.workflow];
349
+ if (workflowMeta?.nodes && stepName in workflowMeta.nodes) {
350
+ result = await executeGraphStep(this, rpcService, runId, stepState.stepId, stepName, rpcName, data, run.workflow);
258
351
  }
259
352
  else {
260
- // Execute RPC with workflow step context (regular workflow)
261
353
  result = await rpcService.rpcWithWire(rpcName, data, {
262
354
  workflowStep: {
263
355
  runId,
@@ -272,6 +364,14 @@ export class PikkuWorkflowService {
272
364
  await this.resumeWorkflow(runId);
273
365
  }
274
366
  catch (error) {
367
+ if (error instanceof RPCNotFoundError) {
368
+ await this.setStepError(stepState.stepId, error);
369
+ await this.updateRunStatus(runId, 'suspended', undefined, {
370
+ message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
371
+ code: 'RPC_NOT_FOUND',
372
+ });
373
+ return;
374
+ }
275
375
  // Store error and mark failed
276
376
  await this.setStepError(stepState.stepId, error);
277
377
  const maxAttempts = (stepState.retries ?? 0) + 1;
@@ -296,7 +396,8 @@ export class PikkuWorkflowService {
296
396
  }
297
397
  catch (error) {
298
398
  if (error.name === 'WorkflowAsyncException' ||
299
- error.name === 'WorkflowCancelledException') {
399
+ error.name === 'WorkflowCancelledException' ||
400
+ error.name === 'WorkflowSuspendedException') {
300
401
  return;
301
402
  }
302
403
  await this.updateRunStatus(runId, 'failed', undefined, {
@@ -385,6 +486,13 @@ export class PikkuWorkflowService {
385
486
  return result;
386
487
  }
387
488
  catch (error) {
489
+ if (error instanceof RPCNotFoundError) {
490
+ await this.updateRunStatus(runId, 'suspended', undefined, {
491
+ message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
492
+ code: 'RPC_NOT_FOUND',
493
+ });
494
+ throw error;
495
+ }
388
496
  // Record the error (marks step as failed)
389
497
  await this.setStepError(currentStepState.stepId, error);
390
498
  // Check if we should retry
@@ -413,9 +521,7 @@ export class PikkuWorkflowService {
413
521
  }
414
522
  catch {
415
523
  // Step doesn't exist - create it (inline, no RPC)
416
- stepState = await this.insertStepState(runId, stepName, null, // No RPC for inline steps
417
- null, // No data for inline steps
418
- stepOptions);
524
+ stepState = await this.insertStepState(runId, stepName, null, null, stepOptions);
419
525
  }
420
526
  if (stepState.status === 'succeeded') {
421
527
  // Return cached result
@@ -488,10 +594,9 @@ export class PikkuWorkflowService {
488
594
  }
489
595
  catch {
490
596
  // Step doesn't exist - create it (sleep step, no RPC)
491
- stepState = await this.insertStepState(runId, stepName, null, // No RPC for sleep steps
492
- { duration }, // Store duration as data
493
- undefined // No retry options for sleep
494
- );
597
+ stepState = await this.insertStepState(runId, stepName, null, {
598
+ duration,
599
+ });
495
600
  }
496
601
  if (stepState.status === 'succeeded') {
497
602
  // Sleep already completed, return immediately
@@ -520,9 +625,45 @@ export class PikkuWorkflowService {
520
625
  return;
521
626
  }
522
627
  }
523
- createWorkflowWire(workflowName, runId, rpcService) {
628
+ getSuspendStepName(reason) {
629
+ if (!reason) {
630
+ return '__workflow_suspend';
631
+ }
632
+ return '__workflow_suspend';
633
+ }
634
+ async suspendStep(runId, reason) {
635
+ const stepName = this.getSuspendStepName(reason);
636
+ await this.withStepLock(runId, stepName, async () => {
637
+ let stepState;
638
+ try {
639
+ stepState = await this.getStepState(runId, stepName);
640
+ }
641
+ catch {
642
+ stepState = await this.insertStepState(runId, stepName, 'pikkuWorkflowSuspend', {
643
+ reason,
644
+ });
645
+ }
646
+ if (!stepState.stepId) {
647
+ stepState = await this.insertStepState(runId, stepName, 'pikkuWorkflowSuspend', {
648
+ reason,
649
+ });
650
+ }
651
+ if (stepState.status === 'succeeded') {
652
+ return;
653
+ }
654
+ if (stepState.status === 'pending') {
655
+ await this.setStepRunning(stepState.stepId);
656
+ }
657
+ await this.setStepResult(stepState.stepId, {
658
+ reason,
659
+ suspendedAt: new Date().toISOString(),
660
+ });
661
+ throw new WorkflowSuspendedException(runId, reason);
662
+ });
663
+ }
664
+ createWorkflowWire(name, runId, rpcService) {
524
665
  const workflowWire = {
525
- workflowName,
666
+ name,
526
667
  runId,
527
668
  getRun: async () => (await this.getRun(runId)),
528
669
  // Implement workflow.do() - RPC form
@@ -540,6 +681,9 @@ export class PikkuWorkflowService {
540
681
  this.verifyStepName(stepName);
541
682
  await this.sleepStep(runId, stepName, getDurationInMilliseconds(duration));
542
683
  },
684
+ suspend: async (reason) => {
685
+ await this.suspendStep(runId, reason || 'Workflow suspended');
686
+ },
543
687
  };
544
688
  return workflowWire;
545
689
  }
@@ -0,0 +1,36 @@
1
+ export declare function workflow<TWorkflowMap extends Record<string, {
2
+ input: any;
3
+ output: any;
4
+ }>>(workflowName: string & keyof TWorkflowMap, options?: {
5
+ pollIntervalMs?: number;
6
+ }): {
7
+ func: (services: any, data: any, wire: any) => Promise<any>;
8
+ };
9
+ export declare function workflowStart<TWorkflowMap extends Record<string, {
10
+ input: any;
11
+ output: any;
12
+ }>>(workflowName: string & keyof TWorkflowMap): {
13
+ func: (services: any, data: any, wire: any) => Promise<{
14
+ runId: string;
15
+ }>;
16
+ };
17
+ export declare function workflowStatus<TWorkflowMap extends Record<string, {
18
+ input: any;
19
+ output: any;
20
+ }>>(_workflowName: string & keyof TWorkflowMap): {
21
+ func: (services: any, data: {
22
+ runId: string;
23
+ }) => Promise<{
24
+ id: string;
25
+ status: 'running' | 'suspended' | 'completed' | 'failed' | 'cancelled';
26
+ output?: any;
27
+ error?: {
28
+ message?: string;
29
+ };
30
+ }>;
31
+ };
32
+ export declare function graphStart<TGraphsMap extends Record<string, Record<string, any>>>(graphName: string & keyof TGraphsMap, startNode: string): {
33
+ func: (services: any, data: any, wire: any) => Promise<{
34
+ runId: string;
35
+ }>;
36
+ };
@@ -0,0 +1,38 @@
1
+ import { WorkflowRunNotFoundError } from './pikku-workflow-service.js';
2
+ export function workflow(workflowName, options) {
3
+ return {
4
+ func: async (services, data, { rpc }) => {
5
+ return services.workflowService.runToCompletion(workflowName, data, rpc, options);
6
+ },
7
+ };
8
+ }
9
+ export function workflowStart(workflowName) {
10
+ return {
11
+ func: async (_services, data, { rpc }) => {
12
+ return rpc.startWorkflow(workflowName, data);
13
+ },
14
+ };
15
+ }
16
+ export function workflowStatus(_workflowName) {
17
+ return {
18
+ func: async (services, data) => {
19
+ const run = await services.workflowService.getRun(data.runId);
20
+ if (!run) {
21
+ throw new WorkflowRunNotFoundError(data.runId);
22
+ }
23
+ return {
24
+ id: run.id,
25
+ status: run.status,
26
+ output: run.output,
27
+ error: run.error ? { message: run.error.message } : undefined,
28
+ };
29
+ },
30
+ };
31
+ }
32
+ export function graphStart(graphName, startNode) {
33
+ return {
34
+ func: async (_services, data, { rpc }) => {
35
+ return rpc.startWorkflow(graphName, data, { startNode });
36
+ },
37
+ };
38
+ }
@@ -1,23 +1 @@
1
- import { PikkuWire, CreateWireServices, CoreSingletonServices, CoreServices, CoreUserSession } from '../../types/core.types.js';
2
- import { HTTPWiringMeta } from '../http/http.types.js';
3
- /**
4
- * Result of finding a workflow by HTTP wire
5
- */
6
- export interface WorkflowHttpMatch {
7
- workflowName: string;
8
- startNode?: string;
9
- }
10
- /**
11
- * Find workflow name by matching route and method against workflow wires
12
- */
13
- export declare const findWorkflowByHttpWire: (route: string, method: string) => WorkflowHttpMatch | undefined;
14
- /**
15
- * Start a workflow triggered by an HTTP wire
16
- * The workflow is responsible for handling the HTTP response
17
- */
18
- export declare const startWorkflowByHttpWire: (singletonServices: CoreSingletonServices, createWireServices: CreateWireServices<CoreSingletonServices, CoreServices<CoreSingletonServices>, CoreUserSession> | undefined, matchedRoute: {
19
- matchedPath: any;
20
- params: any;
21
- route: any;
22
- meta: HTTPWiringMeta;
23
- }, wire: PikkuWire) => Promise<void>;
1
+ export {};
@@ -1,66 +1 @@
1
- import { pikkuState } from '../../pikku-state.js';
2
- import { NotFoundError } from '../../errors/errors.js';
3
- import { ContextAwareRPCService } from '../rpc/rpc-runner.js';
4
- /**
5
- * Find workflow name by matching route and method against workflow wires
6
- */
7
- export const findWorkflowByHttpWire = (route, method) => {
8
- const wirings = pikkuState(null, 'workflows', 'wirings');
9
- const graphWirings = pikkuState(null, 'workflows', 'graphWirings');
10
- // Check DSL workflow wirings
11
- for (const [, wiring] of wirings) {
12
- const httpWires = wiring.wires?.http;
13
- if (httpWires) {
14
- const matchedWire = httpWires.find((w) => w.route === route && w.method === method);
15
- if (matchedWire) {
16
- const meta = pikkuState(null, 'workflows', 'meta');
17
- for (const [name, workflowMeta] of Object.entries(meta)) {
18
- if (workflowMeta.source !== 'graph') {
19
- const registrations = pikkuState(null, 'workflows', 'registrations');
20
- if (registrations.has(name)) {
21
- return { workflowName: name, startNode: matchedWire.startNode };
22
- }
23
- }
24
- }
25
- }
26
- }
27
- }
28
- // Check graph workflow wirings
29
- for (const [, wiring] of graphWirings) {
30
- const httpWires = wiring.wires?.http;
31
- if (httpWires) {
32
- const matchedWire = httpWires.find((w) => w.route === route && w.method === method);
33
- if (matchedWire) {
34
- const meta = pikkuState(null, 'workflows', 'meta');
35
- for (const [name, workflowMeta] of Object.entries(meta)) {
36
- if (workflowMeta.source === 'graph') {
37
- return { workflowName: name, startNode: matchedWire.startNode };
38
- }
39
- }
40
- }
41
- }
42
- }
43
- return undefined;
44
- };
45
- /**
46
- * Start a workflow triggered by an HTTP wire
47
- * The workflow is responsible for handling the HTTP response
48
- */
49
- export const startWorkflowByHttpWire = async (singletonServices, createWireServices, matchedRoute, wire) => {
50
- const { meta } = matchedRoute;
51
- const match = findWorkflowByHttpWire(meta.route, meta.method);
52
- if (!match) {
53
- throw new NotFoundError(`No workflow found for route ${meta.method.toUpperCase()} ${meta.route}`);
54
- }
55
- const workflowService = singletonServices.workflowService;
56
- if (!workflowService) {
57
- throw new Error('WorkflowService not available');
58
- }
59
- const data = await wire.http.request.data();
60
- const wireServices = createWireServices?.(singletonServices, wire);
61
- const rpcService = new ContextAwareRPCService({ ...singletonServices, ...wireServices }, wire, {});
62
- await workflowService.startWorkflow(match.workflowName, data, rpcService, {
63
- inline: true,
64
- startNode: match.startNode,
65
- });
66
- };
1
+ export {};