@pikku/core 0.12.3 → 0.12.4

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 (218) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/services/in-memory-workflow-service.d.ts +15 -2
  3. package/dist/services/in-memory-workflow-service.js +49 -0
  4. package/lcov.info +18891 -0
  5. package/package.json +1 -1
  6. package/src/crypto-utils.test.ts +0 -214
  7. package/src/crypto-utils.ts +0 -213
  8. package/src/errors/error-handler.ts +0 -62
  9. package/src/errors/error.test.ts +0 -195
  10. package/src/errors/errors.ts +0 -374
  11. package/src/errors/index.ts +0 -2
  12. package/src/factory-functions.test.ts +0 -109
  13. package/src/function/function-runner.test.ts +0 -536
  14. package/src/function/function-runner.ts +0 -365
  15. package/src/function/functions.types.ts +0 -304
  16. package/src/function/index.ts +0 -5
  17. package/src/handle-error.test.ts +0 -424
  18. package/src/handle-error.ts +0 -69
  19. package/src/index.ts +0 -118
  20. package/src/internal.ts +0 -6
  21. package/src/middleware/auth-apikey.test.ts +0 -363
  22. package/src/middleware/auth-apikey.ts +0 -47
  23. package/src/middleware/auth-bearer.test.ts +0 -450
  24. package/src/middleware/auth-bearer.ts +0 -72
  25. package/src/middleware/auth-cookie.test.ts +0 -528
  26. package/src/middleware/auth-cookie.ts +0 -80
  27. package/src/middleware/cors.test.ts +0 -424
  28. package/src/middleware/cors.ts +0 -104
  29. package/src/middleware/index.ts +0 -5
  30. package/src/middleware/remote-auth.test.ts +0 -488
  31. package/src/middleware/remote-auth.ts +0 -68
  32. package/src/middleware/timeout.ts +0 -15
  33. package/src/middleware-runner.test.ts +0 -418
  34. package/src/middleware-runner.ts +0 -234
  35. package/src/permissions.test.ts +0 -434
  36. package/src/permissions.ts +0 -319
  37. package/src/pikku-request.ts +0 -23
  38. package/src/pikku-response.ts +0 -5
  39. package/src/pikku-state.test.ts +0 -224
  40. package/src/pikku-state.ts +0 -216
  41. package/src/run-tests-script.test.ts +0 -49
  42. package/src/schema.test.ts +0 -249
  43. package/src/schema.ts +0 -151
  44. package/src/services/ai-agent-runner-service.ts +0 -41
  45. package/src/services/ai-run-state-service.ts +0 -20
  46. package/src/services/ai-storage-service.ts +0 -39
  47. package/src/services/content-service.ts +0 -76
  48. package/src/services/deployment-service.ts +0 -22
  49. package/src/services/gateway-service.ts +0 -20
  50. package/src/services/gopass-secrets.ts +0 -98
  51. package/src/services/in-memory-ai-run-state-service.ts +0 -73
  52. package/src/services/in-memory-trigger-service.ts +0 -64
  53. package/src/services/in-memory-workflow-service.test.ts +0 -351
  54. package/src/services/in-memory-workflow-service.ts +0 -438
  55. package/src/services/index.ts +0 -56
  56. package/src/services/jwt-service.ts +0 -30
  57. package/src/services/local-content.ts +0 -120
  58. package/src/services/local-gateway-service.ts +0 -62
  59. package/src/services/local-secrets.test.ts +0 -80
  60. package/src/services/local-secrets.ts +0 -94
  61. package/src/services/local-variables.test.ts +0 -61
  62. package/src/services/local-variables.ts +0 -39
  63. package/src/services/logger-console.test.ts +0 -118
  64. package/src/services/logger-console.ts +0 -98
  65. package/src/services/logger.ts +0 -57
  66. package/src/services/scheduler-service.ts +0 -86
  67. package/src/services/schema-service.ts +0 -33
  68. package/src/services/scoped-secret-service.test.ts +0 -74
  69. package/src/services/scoped-secret-service.ts +0 -41
  70. package/src/services/secret-service.ts +0 -38
  71. package/src/services/trigger-service.ts +0 -17
  72. package/src/services/typed-secret-service.test.ts +0 -93
  73. package/src/services/typed-secret-service.ts +0 -70
  74. package/src/services/typed-variables-service.test.ts +0 -73
  75. package/src/services/typed-variables-service.ts +0 -81
  76. package/src/services/user-session-service.test.ts +0 -113
  77. package/src/services/user-session-service.ts +0 -86
  78. package/src/services/variables-service.ts +0 -11
  79. package/src/services/workflow-service.ts +0 -95
  80. package/src/testing/index.ts +0 -2
  81. package/src/testing/service-tests.ts +0 -873
  82. package/src/time-utils.test.ts +0 -56
  83. package/src/time-utils.ts +0 -107
  84. package/src/types/core.types.ts +0 -478
  85. package/src/types/state.types.ts +0 -188
  86. package/src/utils/hash.test.ts +0 -68
  87. package/src/utils/hash.ts +0 -26
  88. package/src/utils.test.ts +0 -350
  89. package/src/utils.ts +0 -129
  90. package/src/version.test.ts +0 -80
  91. package/src/version.ts +0 -25
  92. package/src/wirings/ai-agent/agent-dynamic-workflow.ts +0 -469
  93. package/src/wirings/ai-agent/ai-agent-helpers.test.ts +0 -152
  94. package/src/wirings/ai-agent/ai-agent-helpers.ts +0 -76
  95. package/src/wirings/ai-agent/ai-agent-memory.ts +0 -310
  96. package/src/wirings/ai-agent/ai-agent-model-config.test.ts +0 -115
  97. package/src/wirings/ai-agent/ai-agent-model-config.ts +0 -43
  98. package/src/wirings/ai-agent/ai-agent-prepare.ts +0 -636
  99. package/src/wirings/ai-agent/ai-agent-registry.test.ts +0 -37
  100. package/src/wirings/ai-agent/ai-agent-registry.ts +0 -82
  101. package/src/wirings/ai-agent/ai-agent-runner.test.ts +0 -319
  102. package/src/wirings/ai-agent/ai-agent-runner.ts +0 -773
  103. package/src/wirings/ai-agent/ai-agent-stream.test.ts +0 -859
  104. package/src/wirings/ai-agent/ai-agent-stream.ts +0 -1153
  105. package/src/wirings/ai-agent/ai-agent.types.ts +0 -382
  106. package/src/wirings/ai-agent/index.ts +0 -37
  107. package/src/wirings/channel/channel-common.ts +0 -90
  108. package/src/wirings/channel/channel-handler.ts +0 -250
  109. package/src/wirings/channel/channel-middleware-runner.ts +0 -120
  110. package/src/wirings/channel/channel-runner.ts +0 -166
  111. package/src/wirings/channel/channel-store.ts +0 -29
  112. package/src/wirings/channel/channel.types.ts +0 -172
  113. package/src/wirings/channel/define-channel-routes.ts +0 -25
  114. package/src/wirings/channel/eventhub-service.ts +0 -34
  115. package/src/wirings/channel/eventhub-store.ts +0 -13
  116. package/src/wirings/channel/index.ts +0 -24
  117. package/src/wirings/channel/local/index.ts +0 -3
  118. package/src/wirings/channel/local/local-channel-handler.ts +0 -81
  119. package/src/wirings/channel/local/local-channel-runner.test.ts +0 -215
  120. package/src/wirings/channel/local/local-channel-runner.ts +0 -210
  121. package/src/wirings/channel/local/local-eventhub-service.test.ts +0 -95
  122. package/src/wirings/channel/local/local-eventhub-service.ts +0 -101
  123. package/src/wirings/channel/log-channels.ts +0 -20
  124. package/src/wirings/channel/pikku-abstract-channel-handler.test.ts +0 -54
  125. package/src/wirings/channel/pikku-abstract-channel-handler.ts +0 -45
  126. package/src/wirings/channel/serverless/index.ts +0 -5
  127. package/src/wirings/channel/serverless/serverless-channel-runner.ts +0 -289
  128. package/src/wirings/cli/channel/cli-channel-runner.ts +0 -136
  129. package/src/wirings/cli/channel/index.ts +0 -1
  130. package/src/wirings/cli/cli-runner.test.ts +0 -403
  131. package/src/wirings/cli/cli-runner.ts +0 -529
  132. package/src/wirings/cli/cli.types.ts +0 -358
  133. package/src/wirings/cli/command-parser.test.ts +0 -445
  134. package/src/wirings/cli/command-parser.ts +0 -504
  135. package/src/wirings/cli/define-cli-commands.ts +0 -24
  136. package/src/wirings/cli/index.ts +0 -19
  137. package/src/wirings/gateway/gateway-runner.test.ts +0 -474
  138. package/src/wirings/gateway/gateway-runner.ts +0 -411
  139. package/src/wirings/gateway/gateway.types.ts +0 -149
  140. package/src/wirings/gateway/index.ts +0 -13
  141. package/src/wirings/http/http-routes.test.ts +0 -322
  142. package/src/wirings/http/http-routes.ts +0 -197
  143. package/src/wirings/http/http-runner.test.ts +0 -144
  144. package/src/wirings/http/http-runner.ts +0 -588
  145. package/src/wirings/http/http.types.ts +0 -369
  146. package/src/wirings/http/index.ts +0 -28
  147. package/src/wirings/http/log-http-routes.ts +0 -22
  148. package/src/wirings/http/pikku-fetch-http-request.test.ts +0 -237
  149. package/src/wirings/http/pikku-fetch-http-request.ts +0 -170
  150. package/src/wirings/http/pikku-fetch-http-response.test.ts +0 -82
  151. package/src/wirings/http/pikku-fetch-http-response.ts +0 -147
  152. package/src/wirings/http/routers/http-router.ts +0 -13
  153. package/src/wirings/http/routers/path-to-regex.test.ts +0 -319
  154. package/src/wirings/http/routers/path-to-regex.ts +0 -126
  155. package/src/wirings/http/web-request.test.ts +0 -236
  156. package/src/wirings/http/web-request.ts +0 -104
  157. package/src/wirings/mcp/index.ts +0 -27
  158. package/src/wirings/mcp/mcp-endpoint-registry.test.ts +0 -389
  159. package/src/wirings/mcp/mcp-endpoint-registry.ts +0 -159
  160. package/src/wirings/mcp/mcp-runner.ts +0 -323
  161. package/src/wirings/mcp/mcp.types.ts +0 -216
  162. package/src/wirings/node/index.ts +0 -2
  163. package/src/wirings/node/node.types.ts +0 -23
  164. package/src/wirings/oauth2/index.ts +0 -3
  165. package/src/wirings/oauth2/oauth2-client.test.ts +0 -929
  166. package/src/wirings/oauth2/oauth2-client.ts +0 -335
  167. package/src/wirings/oauth2/oauth2.types.ts +0 -69
  168. package/src/wirings/oauth2/wire-oauth2-credential.ts +0 -23
  169. package/src/wirings/queue/index.ts +0 -31
  170. package/src/wirings/queue/queue-runner.test.ts +0 -710
  171. package/src/wirings/queue/queue-runner.ts +0 -192
  172. package/src/wirings/queue/queue.types.ts +0 -189
  173. package/src/wirings/queue/register-queue-helper.ts +0 -60
  174. package/src/wirings/queue/validate-worker-config.test.ts +0 -108
  175. package/src/wirings/queue/validate-worker-config.ts +0 -116
  176. package/src/wirings/rpc/index.ts +0 -4
  177. package/src/wirings/rpc/rpc-runner.ts +0 -460
  178. package/src/wirings/rpc/rpc-types.ts +0 -56
  179. package/src/wirings/rpc/wire-addon.ts +0 -21
  180. package/src/wirings/scheduler/index.ts +0 -11
  181. package/src/wirings/scheduler/log-schedulers.ts +0 -20
  182. package/src/wirings/scheduler/scheduler-runner.test.ts +0 -660
  183. package/src/wirings/scheduler/scheduler-runner.ts +0 -133
  184. package/src/wirings/scheduler/scheduler.types.ts +0 -53
  185. package/src/wirings/secret/index.ts +0 -9
  186. package/src/wirings/secret/secret.types.ts +0 -32
  187. package/src/wirings/secret/validate-secret-definitions.test.ts +0 -140
  188. package/src/wirings/secret/validate-secret-definitions.ts +0 -82
  189. package/src/wirings/trigger/index.ts +0 -10
  190. package/src/wirings/trigger/pikku-trigger-service.ts +0 -112
  191. package/src/wirings/trigger/trigger-runner.test.ts +0 -79
  192. package/src/wirings/trigger/trigger-runner.ts +0 -135
  193. package/src/wirings/trigger/trigger.types.ts +0 -178
  194. package/src/wirings/variable/index.ts +0 -8
  195. package/src/wirings/variable/validate-variable-definitions.test.ts +0 -91
  196. package/src/wirings/variable/validate-variable-definitions.ts +0 -69
  197. package/src/wirings/variable/variable.types.ts +0 -22
  198. package/src/wirings/workflow/dsl/index.ts +0 -31
  199. package/src/wirings/workflow/dsl/workflow-dsl.types.ts +0 -320
  200. package/src/wirings/workflow/dsl/workflow-runner.ts +0 -28
  201. package/src/wirings/workflow/graph/graph-node.ts +0 -222
  202. package/src/wirings/workflow/graph/graph-runner.test.ts +0 -487
  203. package/src/wirings/workflow/graph/graph-runner.ts +0 -816
  204. package/src/wirings/workflow/graph/graph-validation.test.ts +0 -170
  205. package/src/wirings/workflow/graph/graph-validation.ts +0 -237
  206. package/src/wirings/workflow/graph/index.ts +0 -19
  207. package/src/wirings/workflow/graph/template.test.ts +0 -49
  208. package/src/wirings/workflow/graph/template.ts +0 -42
  209. package/src/wirings/workflow/graph/wire-workflow-graph.ts +0 -29
  210. package/src/wirings/workflow/graph/workflow-graph.types.ts +0 -104
  211. package/src/wirings/workflow/index.ts +0 -82
  212. package/src/wirings/workflow/pikku-workflow-service.test.ts +0 -200
  213. package/src/wirings/workflow/pikku-workflow-service.ts +0 -1176
  214. package/src/wirings/workflow/workflow-helpers.test.ts +0 -129
  215. package/src/wirings/workflow/workflow-helpers.ts +0 -79
  216. package/src/wirings/workflow/workflow.types.ts +0 -274
  217. package/tsconfig.json +0 -14
  218. package/tsconfig.tsbuildinfo +0 -1
@@ -1,1176 +0,0 @@
1
- import { runPikkuFunc } from '../../function/function-runner.js'
2
- import {
3
- getSingletonServices,
4
- getCreateWireServices,
5
- pikkuState,
6
- } from '../../pikku-state.js'
7
- import { getDurationInMilliseconds } from '../../time-utils.js'
8
- import type { PikkuWire, SerializedError } from '../../types/core.types.js'
9
- import type { QueueService } from '../queue/queue.types.js'
10
- import type {
11
- PikkuWorkflowWire,
12
- StepState,
13
- WorkflowRun,
14
- WorkflowRunWire,
15
- WorkflowStatus,
16
- WorkflowVersionStatus,
17
- WorkflowServiceConfig,
18
- WorkflowStepOptions,
19
- } from './workflow.types.js'
20
- import {
21
- continueGraph,
22
- executeGraphStep,
23
- runWorkflowGraph,
24
- runFromMeta,
25
- } from './graph/graph-runner.js'
26
- import type { WorkflowService } from '../../services/workflow-service.js'
27
- import { PikkuError, addError } from '../../errors/error-handler.js'
28
- import { RPCNotFoundError } from '../rpc/rpc-runner.js'
29
-
30
- /**
31
- * Exception thrown when workflow needs to pause for async step
32
- */
33
- export class WorkflowAsyncException extends Error {
34
- constructor(
35
- public readonly runId: string,
36
- public readonly stepName: string
37
- ) {
38
- super(`Workflow paused at step: ${stepName}`)
39
- this.name = 'WorkflowAsyncException'
40
- }
41
- }
42
-
43
- /**
44
- * Exception thrown when workflow is cancelled
45
- */
46
- export class WorkflowCancelledException extends Error {
47
- constructor(
48
- public readonly runId: string,
49
- public readonly reason?: string
50
- ) {
51
- super(reason || 'Workflow cancelled')
52
- this.name = 'WorkflowCancelledException'
53
- }
54
- }
55
-
56
- /**
57
- * Exception thrown when workflow is suspended
58
- */
59
- export class WorkflowSuspendedException extends Error {
60
- constructor(
61
- public readonly runId: string,
62
- public readonly reason: string
63
- ) {
64
- super(reason || 'Workflow suspended')
65
- this.name = 'WorkflowSuspendedException'
66
- }
67
- }
68
-
69
- /**
70
- * Error class for workflow not found
71
- */
72
- export class WorkflowNotFoundError extends PikkuError {
73
- constructor(name: string) {
74
- super(`Workflow not found: ${name}`)
75
- }
76
- }
77
- addError(WorkflowNotFoundError, {
78
- status: 404,
79
- message: 'Workflow not found.',
80
- })
81
-
82
- export class WorkflowRunNotFoundError extends PikkuError {
83
- constructor(runId: string) {
84
- super(`Workflow run not found: ${runId}`)
85
- }
86
- }
87
- addError(WorkflowRunNotFoundError, {
88
- status: 404,
89
- message: 'Workflow run not found.',
90
- })
91
-
92
- export class WorkflowServiceNotInitialized extends Error {}
93
- export class WorkflowStepNameNotString extends Error {
94
- constructor(stepName: any) {
95
- super(`Workflow step name must be a string. Received: ${typeof stepName}`)
96
- }
97
- }
98
-
99
- const WORKFLOW_END_STATES: ReadonlySet<string> = new Set([
100
- 'completed',
101
- 'failed',
102
- 'cancelled',
103
- 'suspended',
104
- ])
105
-
106
- /**
107
- * Abstract workflow state service
108
- * Implementations provide pluggable storage backends (SQLite, PostgreSQL, etc.)
109
- * Combines orchestration and step execution
110
- */
111
- export abstract class PikkuWorkflowService implements WorkflowService {
112
- private inlineRuns = new Set<string>()
113
-
114
- constructor() {}
115
-
116
- /**
117
- * Check if a run is executing inline (without queues)
118
- */
119
- protected isInline(runId: string): boolean {
120
- return this.inlineRuns.has(runId)
121
- }
122
-
123
- /**
124
- * Register a run as inline (for graph-runner to use)
125
- */
126
- public registerInlineRun(runId: string): void {
127
- this.inlineRuns.add(runId)
128
- }
129
-
130
- /**
131
- * Unregister a run from inline tracking
132
- */
133
- public unregisterInlineRun(runId: string): void {
134
- this.inlineRuns.delete(runId)
135
- }
136
-
137
- public async registerWorkflowVersions(): Promise<void> {
138
- const allMeta = pikkuState(null, 'workflows', 'meta')
139
- for (const [name, meta] of Object.entries(allMeta)) {
140
- if (!meta.graphHash) continue
141
- await this.upsertWorkflowVersion(name, meta.graphHash, meta, meta.source)
142
- }
143
- }
144
-
145
- abstract createRun(
146
- workflowName: string,
147
- input: any,
148
- inline: boolean,
149
- graphHash: string,
150
- wire: WorkflowRunWire
151
- ): Promise<string>
152
-
153
- /**
154
- * Get a workflow run by ID
155
- * @param id - Run ID
156
- * @returns Workflow run or null if not found
157
- */
158
- abstract getRun(id: string): Promise<WorkflowRun | null>
159
-
160
- /**
161
- * Get workflow run history (all step attempts in chronological order)
162
- * @param runId - Run ID
163
- * @returns Array of step states with step names, ordered oldest to newest
164
- */
165
- abstract getRunHistory(
166
- runId: string
167
- ): Promise<Array<StepState & { stepName: string }>>
168
-
169
- /**
170
- * Update workflow run status
171
- * @param id - Run ID
172
- * @param status - New status
173
- */
174
- abstract updateRunStatus(
175
- id: string,
176
- status: WorkflowStatus,
177
- output?: any,
178
- error?: SerializedError
179
- ): Promise<void>
180
-
181
- /**
182
- * Insert initial step state (called by orchestrator)
183
- * Creates pending step in both workflow_step and workflow_step_history
184
- * @param runId - Run ID
185
- * @param stepName - Step cache key
186
- * @param rpcName - RPC function name
187
- * @param data - Step input data
188
- * @param stepOptions - Step options (retries, retryDelay)
189
- * @returns Step state with generated stepId
190
- */
191
- abstract insertStepState(
192
- runId: string,
193
- stepName: string,
194
- rpcName: string | null,
195
- data: any,
196
- stepOptions?: WorkflowStepOptions
197
- ): Promise<StepState>
198
-
199
- /**
200
- * Get step state by cache key (read-only)
201
- * @param runId - Run ID
202
- * @param stepName - Step cache key (from workflow.do)
203
- * @returns Step state with attemptCount calculated from history
204
- */
205
- abstract getStepState(runId: string, stepName: string): Promise<StepState>
206
-
207
- /**
208
- * Mark step as running
209
- * Updates both workflow_step and workflow_step_history
210
- * @param stepId - Step ID
211
- */
212
- abstract setStepRunning(stepId: string): Promise<void>
213
-
214
- /**
215
- * Mark step as scheduled (queued for execution)
216
- * Updates both workflow_step and workflow_step_history
217
- * @param stepId - Step ID
218
- */
219
- abstract setStepScheduled(stepId: string): Promise<void>
220
-
221
- /**
222
- * Store step result and mark as succeeded
223
- * Updates both workflow_step and workflow_step_history
224
- * @param stepId - Step ID
225
- * @param result - Step result
226
- */
227
- abstract setStepResult(stepId: string, result: any): Promise<void>
228
-
229
- /**
230
- * Store step error and mark as failed
231
- * Updates both workflow_step and workflow_step_history
232
- * @param stepId - Step ID
233
- * @param error - Error object
234
- */
235
- abstract setStepError(stepId: string, error: Error): Promise<void>
236
-
237
- /**
238
- * Create a new retry attempt for a failed step
239
- * Inserts new pending step in both workflow_step and workflow_step_history
240
- * Resets status to 'pending' with new stepId
241
- * Copies metadata (rpcName, data, retries, retryDelay) from failed attempt
242
- * @param failedStepId - Failed step ID to copy from
243
- * @returns New step state for the retry attempt
244
- */
245
- abstract createRetryAttempt(
246
- failedStepId: string,
247
- status: 'pending' | 'running'
248
- ): Promise<StepState>
249
-
250
- /**
251
- * Execute function within a run lock to prevent concurrent modifications
252
- * @param id - Run ID
253
- * @param fn - Function to execute
254
- * @returns Function result
255
- */
256
- abstract withRunLock<T>(id: string, fn: () => Promise<T>): Promise<T>
257
-
258
- /**
259
- * Execute function within a step lock to prevent concurrent step execution
260
- * @param runId - Run ID
261
- * @param stepName - Step name
262
- * @param fn - Function to execute
263
- * @returns Function result
264
- */
265
- abstract withStepLock<T>(
266
- runId: string,
267
- stepName: string,
268
- fn: () => Promise<T>
269
- ): Promise<T>
270
-
271
- /**
272
- * Close any open connections
273
- */
274
- abstract close(): Promise<void>
275
-
276
- // ============================================================================
277
- // Workflow Graph Methods
278
- // ============================================================================
279
-
280
- /**
281
- * Get completed graph state (lightweight - no results)
282
- * @param runId - Run ID
283
- * @returns Completed node IDs and their branch keys
284
- */
285
- abstract getCompletedGraphState(runId: string): Promise<{
286
- completedNodeIds: string[]
287
- failedNodeIds: string[]
288
- branchKeys: Record<string, string>
289
- }>
290
-
291
- /**
292
- * Filter candidate nodes to only those without existing steps
293
- * @param runId - Run ID
294
- * @param nodeIds - Candidate node IDs to check
295
- * @returns Node IDs that don't have a step yet
296
- */
297
- abstract getNodesWithoutSteps(
298
- runId: string,
299
- nodeIds: string[]
300
- ): Promise<string[]>
301
-
302
- /**
303
- * Get results for specific nodes
304
- * @param runId - Run ID
305
- * @param nodeIds - Node IDs to fetch results for
306
- * @returns Map of nodeId to result
307
- */
308
- abstract getNodeResults(
309
- runId: string,
310
- nodeIds: string[]
311
- ): Promise<Record<string, any>>
312
-
313
- /**
314
- * Set the branch key for a graph node step
315
- * @param stepId - Step ID
316
- * @param branchKey - Branch key selected by graph.branch()
317
- */
318
- abstract setBranchTaken(stepId: string, branchKey: string): Promise<void>
319
-
320
- /**
321
- * Update a state variable in the workflow run's state
322
- * @param runId - Run ID
323
- * @param name - Variable name
324
- * @param value - Value to store
325
- */
326
- abstract updateRunState(
327
- runId: string,
328
- name: string,
329
- value: unknown
330
- ): Promise<void>
331
-
332
- /**
333
- * Get the entire state object for a workflow run
334
- * @param runId - Run ID
335
- * @returns The state object with all variables
336
- */
337
- abstract getRunState(runId: string): Promise<Record<string, unknown>>
338
-
339
- abstract upsertWorkflowVersion(
340
- name: string,
341
- graphHash: string,
342
- graph: any,
343
- source: string,
344
- status?: WorkflowVersionStatus
345
- ): Promise<void>
346
-
347
- abstract updateWorkflowVersionStatus(
348
- name: string,
349
- graphHash: string,
350
- status: WorkflowVersionStatus
351
- ): Promise<void>
352
-
353
- abstract getWorkflowVersion(
354
- name: string,
355
- graphHash: string
356
- ): Promise<{ graph: any; source: string } | null>
357
-
358
- abstract getAIGeneratedWorkflows(
359
- agentName?: string
360
- ): Promise<Array<{ workflowName: string; graphHash: string; graph: any }>>
361
-
362
- // ============================================================================
363
- // Workflow Lifecycle Methods
364
- // ============================================================================
365
-
366
- /**
367
- * Resume a paused workflow by triggering the orchestrator
368
- * @param runId - Run ID
369
- */
370
- public async resumeWorkflow(runId: string): Promise<void> {
371
- const queueService = this.verifyQueueService()
372
- await queueService.add(this.getConfig().orchestratorQueueName, { runId })
373
- }
374
-
375
- public async queueStepWorker(
376
- runId: string,
377
- stepName: string,
378
- rpcName: string,
379
- data: any
380
- ): Promise<void> {
381
- const queueService = this.verifyQueueService()
382
- await queueService.add(this.getConfig().stepWorkerQueueName, {
383
- runId,
384
- stepName,
385
- rpcName,
386
- data,
387
- })
388
- }
389
-
390
- /**
391
- * Execute a workflow sleep step completion
392
- * Sets the step result to null and resumes the workflow
393
- * @param data - Sleeper input data
394
- */
395
- public async executeWorkflowSleepCompleted(
396
- runId: string,
397
- stepId: string
398
- ): Promise<void> {
399
- await this.setStepResult(stepId, null)
400
- await this.resumeWorkflow(runId)
401
- }
402
-
403
- /**
404
- * Schedule orchestrator retry with delay
405
- * @param runId - Run ID
406
- * @param retryDelay - Delay in milliseconds or duration string (optional)
407
- */
408
- protected async scheduleOrchestratorRetry(
409
- runId: string,
410
- retryDelay?: number | string
411
- ): Promise<void> {
412
- const queueService = this.verifyQueueService()
413
- await queueService.add(
414
- this.getConfig().orchestratorQueueName,
415
- { runId },
416
- retryDelay ? { delay: getDurationInMilliseconds(retryDelay) } : undefined
417
- )
418
- }
419
-
420
- /**
421
- * Start a new workflow run
422
- * Automatically detects workflow type (DSL or graph) from meta and executes accordingly
423
- * @param options.inline - If true, execute workflow directly without queue service
424
- * @param options.startNode - Starting node ID for graph workflows (from wire config)
425
- */
426
- public async startWorkflow<I>(
427
- name: string,
428
- input: I,
429
- wire: WorkflowRunWire,
430
- rpcService: any,
431
- options?: { inline?: boolean; startNode?: string }
432
- ): Promise<{ runId: string }> {
433
- // Check meta to determine workflow type
434
- const meta = pikkuState(null, 'workflows', 'meta')
435
- const workflowMeta = meta[name]
436
-
437
- if (!workflowMeta) {
438
- throw new WorkflowNotFoundError(name)
439
- }
440
-
441
- if (workflowMeta.source === 'graph' || workflowMeta.source === 'ai-agent') {
442
- const shouldInline =
443
- options?.inline || !getSingletonServices()?.queueService
444
- return runWorkflowGraph(
445
- this,
446
- name,
447
- input,
448
- rpcService,
449
- shouldInline,
450
- options?.startNode,
451
- wire
452
- )
453
- }
454
-
455
- // DSL workflow - check registration exists
456
- const registrations = pikkuState(null, 'workflows', 'registrations')
457
- const workflow = registrations.get(name)
458
-
459
- if (!workflow) {
460
- throw new WorkflowNotFoundError(name)
461
- }
462
-
463
- if (!workflowMeta.graphHash) {
464
- throw new Error(`Missing workflow graphHash for '${name}'`)
465
- }
466
-
467
- const runId = await this.createRun(
468
- name,
469
- input,
470
- options?.inline ?? false,
471
- workflowMeta.graphHash,
472
- wire
473
- )
474
-
475
- if (options?.inline) {
476
- this.inlineRuns.add(runId)
477
- }
478
-
479
- if (options?.inline || !getSingletonServices()?.queueService) {
480
- this.runWorkflowJob(runId, rpcService)
481
- .catch(() => {})
482
- .finally(() => {
483
- if (options?.inline) {
484
- this.inlineRuns.delete(runId)
485
- }
486
- })
487
- } else {
488
- await this.resumeWorkflow(runId)
489
- }
490
-
491
- return { runId }
492
- }
493
-
494
- public async runToCompletion<I>(
495
- name: string,
496
- input: I,
497
- rpcService: any,
498
- options?: { pollIntervalMs?: number; wire?: WorkflowRunWire }
499
- ): Promise<any> {
500
- const pollInterval = options?.pollIntervalMs ?? 1000
501
- const { runId } = await this.startWorkflow(
502
- name,
503
- input,
504
- options?.wire ?? { type: 'internal' },
505
- rpcService,
506
- { inline: true }
507
- )
508
- while (true) {
509
- const run = await this.getRun(runId)
510
- if (!run) {
511
- throw new WorkflowRunNotFoundError(runId)
512
- }
513
- if (WORKFLOW_END_STATES.has(run.status)) {
514
- if (run.status === 'failed') {
515
- throw new Error(run.error?.message || 'Workflow failed')
516
- }
517
- if (run.status === 'cancelled') {
518
- throw new Error('Workflow was cancelled')
519
- }
520
- return run.output
521
- }
522
- await new Promise((resolve) => setTimeout(resolve, pollInterval))
523
- }
524
- }
525
-
526
- public async runWorkflowJob(runId: string, rpcService: any): Promise<void> {
527
- const run = await this.getRun(runId)
528
- if (!run) {
529
- throw new WorkflowRunNotFoundError(runId)
530
- }
531
-
532
- const meta = pikkuState(null, 'workflows', 'meta')
533
- const workflowMeta = meta[run.workflow]
534
-
535
- if (
536
- run.graphHash &&
537
- workflowMeta?.graphHash &&
538
- run.graphHash !== workflowMeta.graphHash
539
- ) {
540
- await this.runVersionMismatchFallback(run, workflowMeta, rpcService)
541
- return
542
- }
543
-
544
- if (workflowMeta?.source === 'graph') {
545
- await continueGraph(this, runId, run.workflow)
546
- return
547
- }
548
-
549
- const registrations = pikkuState(null, 'workflows', 'registrations')
550
- const workflow = registrations.get(run.workflow)
551
- if (!workflow) {
552
- throw new WorkflowNotFoundError(run.workflow)
553
- }
554
-
555
- await this.withRunLock(runId, async () => {
556
- const workflowWire = this.createWorkflowWire(
557
- run.workflow,
558
- runId,
559
- rpcService
560
- )
561
- const wire: PikkuWire = { workflow: workflowWire }
562
- try {
563
- const result = await runPikkuFunc(
564
- 'workflow',
565
- workflowMeta.name,
566
- workflowMeta.pikkuFuncId,
567
- {
568
- singletonServices: getSingletonServices()!,
569
- wire,
570
- createWireServices: getCreateWireServices(),
571
- data: () => run.input,
572
- }
573
- )
574
-
575
- await this.updateRunStatus(runId, 'completed', result)
576
- } catch (error: any) {
577
- if (error instanceof WorkflowAsyncException) {
578
- throw error
579
- }
580
-
581
- if (error instanceof WorkflowCancelledException) {
582
- await this.updateRunStatus(runId, 'cancelled', undefined, {
583
- message: error.message || 'Workflow cancelled',
584
- stack: '',
585
- code: 'WORKFLOW_CANCELLED',
586
- })
587
- throw error
588
- }
589
-
590
- if (error instanceof WorkflowSuspendedException) {
591
- await this.updateRunStatus(runId, 'suspended', undefined, {
592
- message: error.message || 'Workflow suspended',
593
- stack: '',
594
- code: 'WORKFLOW_SUSPENDED',
595
- })
596
- throw error
597
- }
598
-
599
- await this.updateRunStatus(runId, 'failed', undefined, {
600
- message: error.message,
601
- stack: error.stack,
602
- code: error.code,
603
- })
604
-
605
- throw error
606
- }
607
- })
608
- }
609
-
610
- private async runVersionMismatchFallback(
611
- run: WorkflowRun,
612
- currentMeta: { source: string },
613
- rpcService: any
614
- ): Promise<void> {
615
- const source = currentMeta.source
616
-
617
- if (source === 'complex') {
618
- await this.updateRunStatus(run.id, 'failed', undefined, {
619
- message: `Workflow '${run.workflow}' definition changed. Complex workflows with inline steps cannot be migrated.`,
620
- stack: '',
621
- code: 'VERSION_CONFLICT',
622
- })
623
- return
624
- }
625
-
626
- const version = await this.getWorkflowVersion(run.workflow, run.graphHash!)
627
- if (!version) {
628
- await this.updateRunStatus(run.id, 'failed', undefined, {
629
- message: `Workflow '${run.workflow}' version '${run.graphHash}' not found. Cannot resume with changed definition.`,
630
- stack: '',
631
- code: 'VERSION_NOT_FOUND',
632
- })
633
- return
634
- }
635
-
636
- await runFromMeta(this, run.id, version.graph, rpcService)
637
- }
638
-
639
- /**
640
- * Execute a single workflow step (called by worker)
641
- * Handles idempotency, RPC execution, result storage, retry logic, and orchestrator triggering
642
- */
643
- public async executeWorkflowStep(
644
- runId: string,
645
- stepName: string,
646
- rpcName: string,
647
- data: any,
648
- rpcService: any
649
- ): Promise<void> {
650
- // Use step-level lock to prevent concurrent execution of same step
651
- await this.withStepLock(runId, stepName, async () => {
652
- // Get step state
653
- let stepState = await this.getStepState(runId, stepName)
654
-
655
- // Idempotency - if already succeeded, resume orchestrator and return
656
- if (stepState.status === 'succeeded') {
657
- await this.resumeWorkflow(runId)
658
- return
659
- }
660
-
661
- // Log warning if already running (race condition)
662
- if (stepState.status === 'running') {
663
- return
664
- }
665
-
666
- // If status is 'failed', this is a retry - create new attempt history
667
- if (stepState.status === 'failed') {
668
- stepState = await this.createRetryAttempt(stepState.stepId, 'running')
669
- }
670
-
671
- if (stepState.status === 'pending') {
672
- // Mark pending step as running before execution
673
- await this.setStepRunning(stepState.stepId)
674
- }
675
-
676
- try {
677
- let result: any
678
-
679
- const run = await this.getRun(runId)
680
- if (!run) {
681
- throw new Error(`Workflow run not found: ${runId}`)
682
- }
683
-
684
- const meta = pikkuState(null, 'workflows', 'meta')
685
- const workflowMeta = meta[run.workflow]
686
-
687
- if (workflowMeta?.nodes && stepName in workflowMeta.nodes) {
688
- result = await executeGraphStep(
689
- this,
690
- rpcService,
691
- runId,
692
- stepState.stepId,
693
- stepName,
694
- rpcName,
695
- data,
696
- run.workflow
697
- )
698
- } else {
699
- result = await rpcService.rpcWithWire(rpcName, data, {
700
- workflowStep: {
701
- runId,
702
- stepId: stepState.stepId,
703
- attemptCount: stepState.attemptCount,
704
- },
705
- })
706
- }
707
-
708
- // Store result and mark succeeded
709
- await this.setStepResult(stepState.stepId, result)
710
-
711
- // Resume orchestrator to continue workflow
712
- await this.resumeWorkflow(runId)
713
- } catch (error: any) {
714
- if (error instanceof RPCNotFoundError) {
715
- await this.setStepError(stepState.stepId, error)
716
- await this.updateRunStatus(runId, 'suspended', undefined, {
717
- message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
718
- code: 'RPC_NOT_FOUND',
719
- })
720
- return
721
- }
722
-
723
- // Store error and mark failed
724
- await this.setStepError(stepState.stepId, error)
725
-
726
- const maxAttempts = (stepState.retries ?? 0) + 1
727
- const retriesExhausted = stepState.attemptCount >= maxAttempts
728
-
729
- if (retriesExhausted) {
730
- // No more retries - resume orchestrator to mark workflow as failed
731
- await this.resumeWorkflow(runId)
732
- }
733
-
734
- // Always throw so queue knows the job failed and can retry if needed
735
- throw error
736
- }
737
- })
738
- }
739
-
740
- /**
741
- * Orchestrate workflow execution (called by orchestrator)
742
- * Runs workflow job and handles async exceptions
743
- */
744
- public async orchestrateWorkflow(
745
- runId: string,
746
- rpcService: any
747
- ): Promise<void> {
748
- try {
749
- // Run workflow job (replays with caching)
750
- await this.runWorkflowJob(runId, rpcService)
751
- } catch (error: any) {
752
- if (
753
- error.name === 'WorkflowAsyncException' ||
754
- error.name === 'WorkflowCancelledException' ||
755
- error.name === 'WorkflowSuspendedException'
756
- ) {
757
- return
758
- }
759
-
760
- await this.updateRunStatus(runId, 'failed', undefined, {
761
- message: error.message,
762
- stack: error.stack,
763
- code: error.code,
764
- })
765
-
766
- throw error
767
- }
768
- }
769
-
770
- private verifyQueueService(): QueueService {
771
- if (!getSingletonServices()?.queueService) {
772
- throw new Error(
773
- 'QueueService not configured. Remote workflows require a queue service.'
774
- )
775
- }
776
-
777
- return getSingletonServices()!.queueService!
778
- }
779
-
780
- private async rpcStep(
781
- runId: string,
782
- stepName: string,
783
- rpcName: string,
784
- data: any,
785
- rpcService: any,
786
- stepOptions?: WorkflowStepOptions
787
- ): Promise<any> {
788
- // Check if step already exists
789
- let stepState: StepState
790
- try {
791
- stepState = await this.getStepState(runId, stepName)
792
- } catch {
793
- // Step doesn't exist - create it
794
- stepState = await this.insertStepState(
795
- runId,
796
- stepName,
797
- rpcName,
798
- data,
799
- stepOptions
800
- )
801
- }
802
-
803
- if (stepState.status === 'succeeded') {
804
- // Return cached result
805
- return stepState.result
806
- }
807
-
808
- if (stepState.status === 'failed') {
809
- // Step failed with retries exhausted - throw error to fail the workflow
810
- const error = new Error(
811
- stepState.error?.message ||
812
- `Step '${stepName}' failed after exhausting all retries`
813
- )
814
- // Preserve original error properties if available
815
- if (stepState.error) {
816
- Object.assign(error, stepState.error)
817
- }
818
- throw error
819
- }
820
-
821
- if (stepState.status === 'scheduled') {
822
- // Step is already scheduled, pause workflow
823
- throw new WorkflowAsyncException(runId, stepName)
824
- }
825
-
826
- // Step is pending - schedule it
827
- await this.setStepScheduled(stepState.stepId)
828
-
829
- // Enqueue step worker (unless inline mode)
830
- if (!this.isInline(runId) && getSingletonServices()!.queueService) {
831
- // Map step retry options to queue job options
832
- const retries = stepOptions?.retries ?? 0
833
- const retryDelay = stepOptions?.retryDelay
834
-
835
- await getSingletonServices()!.queueService!.add(
836
- this.getConfig().stepWorkerQueueName,
837
- {
838
- runId,
839
- stepName,
840
- rpcName,
841
- data,
842
- },
843
- {
844
- // attempts includes initial attempt, retries doesn't
845
- attempts: retries + 1,
846
- // Map retry delay to backoff
847
- backoff:
848
- typeof retryDelay === 'number'
849
- ? { type: 'fixed', delay: retryDelay }
850
- : retryDelay === 'exponential'
851
- ? 'exponential'
852
- : undefined,
853
- }
854
- )
855
- // Pause workflow - step will callback when done
856
- throw new WorkflowAsyncException(runId, stepName)
857
- } else {
858
- // Inline or no queue service - execute locally with retry loop
859
- const retries = stepOptions?.retries ?? 0
860
- const retryDelay = stepOptions?.retryDelay
861
- let currentStepState = stepState
862
-
863
- while (true) {
864
- try {
865
- await this.setStepRunning(currentStepState.stepId)
866
- const result = await rpcService.rpcWithWire(rpcName, data, {
867
- workflowStep: {
868
- runId,
869
- stepId: currentStepState.stepId,
870
- attemptCount: currentStepState.attemptCount,
871
- },
872
- })
873
- await this.setStepResult(currentStepState.stepId, result)
874
- return result
875
- } catch (error: any) {
876
- if (error instanceof RPCNotFoundError) {
877
- await this.updateRunStatus(runId, 'suspended', undefined, {
878
- message: `RPC '${rpcName}' not found. Deploy the missing function and resume.`,
879
- code: 'RPC_NOT_FOUND',
880
- })
881
- throw error
882
- }
883
-
884
- // Record the error (marks step as failed)
885
- await this.setStepError(currentStepState.stepId, error)
886
-
887
- // Check if we should retry
888
- if (currentStepState.attemptCount < retries) {
889
- // Create a new pending retry attempt
890
- currentStepState = await this.createRetryAttempt(
891
- currentStepState.stepId,
892
- 'pending'
893
- )
894
-
895
- // Wait for retry delay if specified
896
- if (retryDelay) {
897
- await new Promise((resolve) =>
898
- setTimeout(resolve, getDurationInMilliseconds(retryDelay))
899
- )
900
- }
901
- // Continue loop to retry
902
- } else {
903
- // No more retries, fail the workflow
904
- throw error
905
- }
906
- }
907
- }
908
- }
909
- }
910
-
911
- private async inlineStep(
912
- runId: string,
913
- stepName: string,
914
- fn: Function,
915
- stepOptions?: WorkflowStepOptions
916
- ): Promise<any> {
917
- // Check if step already exists
918
- let stepState: StepState
919
- try {
920
- stepState = await this.getStepState(runId, stepName)
921
- } catch {
922
- // Step doesn't exist - create it (inline, no RPC)
923
- stepState = await this.insertStepState(
924
- runId,
925
- stepName,
926
- null,
927
- null,
928
- stepOptions
929
- )
930
- }
931
-
932
- if (stepState.status === 'succeeded') {
933
- // Return cached result
934
- return stepState.result
935
- }
936
-
937
- // Execute inline function
938
- const retries = stepOptions?.retries ?? this.getConfig().retries
939
- const retryDelay = stepOptions?.retryDelay ?? this.getConfig().retryDelay
940
- let currentStepState = stepState
941
-
942
- // Check if we're running inline (in-memory) or remote (queue-based)
943
- if (this.isInline(runId)) {
944
- // Inline mode - execute with retry loop
945
- while (true) {
946
- try {
947
- await this.setStepRunning(currentStepState.stepId)
948
- const result = await fn()
949
- await this.setStepResult(currentStepState.stepId, result)
950
- return result
951
- } catch (error: any) {
952
- // Record the error (marks step as failed)
953
- await this.setStepError(currentStepState.stepId, error)
954
-
955
- // Check if we should retry
956
- if (currentStepState.attemptCount < retries) {
957
- // Create a new pending retry attempt
958
- currentStepState = await this.createRetryAttempt(
959
- currentStepState.stepId,
960
- 'pending'
961
- )
962
-
963
- // Wait for retry delay if specified
964
- if (retryDelay) {
965
- await new Promise((resolve) =>
966
- setTimeout(resolve, getDurationInMilliseconds(retryDelay))
967
- )
968
- }
969
- // Continue loop to retry
970
- } else {
971
- // No more retries, fail the workflow
972
- throw error
973
- }
974
- }
975
- }
976
- } else {
977
- // Remote mode - use queue-based retry
978
- try {
979
- await this.setStepRunning(currentStepState.stepId)
980
- const result = await fn()
981
- await this.setStepResult(currentStepState.stepId, result)
982
- return result
983
- } catch (error: any) {
984
- // Record the error (marks step as failed)
985
- await this.setStepError(currentStepState.stepId, error)
986
-
987
- // Check if we should retry
988
- if (currentStepState.attemptCount < retries) {
989
- // Create a new pending retry attempt (copies metadata from failed step)
990
- await this.createRetryAttempt(currentStepState.stepId, 'pending')
991
-
992
- // Schedule orchestrator to retry after delay
993
- await this.scheduleOrchestratorRetry(runId, retryDelay)
994
-
995
- // Pause workflow - orchestrator will replay and pick up new attempt
996
- throw new WorkflowAsyncException(runId, stepName)
997
- }
998
-
999
- // No more retries, fail the workflow
1000
- throw error
1001
- }
1002
- }
1003
- }
1004
-
1005
- private async sleepStep(runId: string, stepName: string, duration: number) {
1006
- // Check if step already exists
1007
- let stepState: StepState
1008
- try {
1009
- stepState = await this.getStepState(runId, stepName)
1010
- } catch {
1011
- // Step doesn't exist - create it (sleep step, no RPC)
1012
- stepState = await this.insertStepState(runId, stepName, null, {
1013
- duration,
1014
- })
1015
- }
1016
-
1017
- if (stepState.status === 'succeeded') {
1018
- // Sleep already completed, return immediately
1019
- return
1020
- }
1021
-
1022
- if (stepState.status === 'scheduled') {
1023
- // Sleep is already scheduled, pause workflow
1024
- throw new WorkflowAsyncException(runId, stepName)
1025
- }
1026
-
1027
- // Step is pending - schedule it
1028
- await this.setStepScheduled(stepState.stepId)
1029
-
1030
- // Check if inline mode or no scheduler service
1031
- if (!this.isInline(runId) && getSingletonServices()!.schedulerService) {
1032
- // Remote mode - schedule sleep via scheduler service
1033
- await getSingletonServices()!.schedulerService!.scheduleRPC(
1034
- duration,
1035
- this.getConfig().sleeperRPCName,
1036
- {
1037
- runId,
1038
- stepId: stepState.stepId,
1039
- }
1040
- )
1041
- // Pause workflow - sleep will callback when done
1042
- throw new WorkflowAsyncException(runId, stepName)
1043
- } else {
1044
- // Inline mode - use setTimeout with actual duration
1045
- await new Promise((resolve) =>
1046
- setTimeout(resolve, getDurationInMilliseconds(duration))
1047
- )
1048
- await this.setStepResult(stepState.stepId, null)
1049
- return
1050
- }
1051
- }
1052
-
1053
- private getSuspendStepName(reason: string): string {
1054
- if (!reason) {
1055
- return '__workflow_suspend'
1056
- }
1057
- return '__workflow_suspend'
1058
- }
1059
-
1060
- private async suspendStep(runId: string, reason: string): Promise<void> {
1061
- const stepName = this.getSuspendStepName(reason)
1062
- await this.withStepLock(runId, stepName, async () => {
1063
- let stepState: StepState
1064
- try {
1065
- stepState = await this.getStepState(runId, stepName)
1066
- } catch {
1067
- stepState = await this.insertStepState(
1068
- runId,
1069
- stepName,
1070
- 'pikkuWorkflowSuspend',
1071
- {
1072
- reason,
1073
- }
1074
- )
1075
- }
1076
- if (!stepState.stepId) {
1077
- stepState = await this.insertStepState(
1078
- runId,
1079
- stepName,
1080
- 'pikkuWorkflowSuspend',
1081
- {
1082
- reason,
1083
- }
1084
- )
1085
- }
1086
-
1087
- if (stepState.status === 'succeeded') {
1088
- return
1089
- }
1090
-
1091
- if (stepState.status === 'pending') {
1092
- await this.setStepRunning(stepState.stepId)
1093
- }
1094
-
1095
- await this.setStepResult(stepState.stepId, {
1096
- reason,
1097
- suspendedAt: new Date().toISOString(),
1098
- })
1099
- throw new WorkflowSuspendedException(runId, reason)
1100
- })
1101
- }
1102
-
1103
- private createWorkflowWire(
1104
- name: string,
1105
- runId: string,
1106
- rpcService: any
1107
- ): PikkuWorkflowWire {
1108
- const workflowWire: PikkuWorkflowWire = {
1109
- name,
1110
- runId,
1111
- getRun: async () => (await this.getRun(runId)) as WorkflowRun,
1112
-
1113
- // Implement workflow.do() - RPC form
1114
- do: async (
1115
- stepName: string,
1116
- rpcNameOrFn: any,
1117
- dataOrOptions?: any,
1118
- options?: any
1119
- ) => {
1120
- this.verifyStepName(stepName)
1121
- if (typeof rpcNameOrFn === 'string') {
1122
- return await this.rpcStep(
1123
- runId,
1124
- stepName,
1125
- rpcNameOrFn,
1126
- dataOrOptions,
1127
- rpcService,
1128
- options
1129
- )
1130
- } else {
1131
- return await this.inlineStep(
1132
- runId,
1133
- stepName,
1134
- rpcNameOrFn,
1135
- dataOrOptions
1136
- )
1137
- }
1138
- },
1139
-
1140
- // Implement workflow.sleep()
1141
- sleep: async (stepName: string, duration: string | number) => {
1142
- this.verifyStepName(stepName)
1143
- await this.sleepStep(
1144
- runId,
1145
- stepName,
1146
- getDurationInMilliseconds(duration)
1147
- )
1148
- },
1149
-
1150
- suspend: async (reason: string) => {
1151
- await this.suspendStep(runId, reason || 'Workflow suspended')
1152
- },
1153
- }
1154
- return workflowWire
1155
- }
1156
-
1157
- private verifyStepName(stepName: string) {
1158
- if (typeof stepName !== 'string') {
1159
- throw new WorkflowStepNameNotString(stepName)
1160
- }
1161
- }
1162
-
1163
- private getConfig(): WorkflowServiceConfig {
1164
- const singletonServices = getSingletonServices()
1165
- const workflow = singletonServices.config?.workflow
1166
- return {
1167
- retries: workflow?.retries ?? 0,
1168
- retryDelay: workflow?.retryDelay ?? 0,
1169
- orchestratorQueueName:
1170
- workflow?.orchestratorQueueName ?? 'pikku-workflow-orchestrator',
1171
- stepWorkerQueueName:
1172
- workflow?.stepWorkerQueueName ?? 'pikku-workflow-step-worker',
1173
- sleeperRPCName: workflow?.sleeperRPCName ?? 'pikkuWorkflowSleeper',
1174
- }
1175
- }
1176
- }