@zhivex-ai/core 0.7.0 → 0.8.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 (77) hide show
  1. package/README.md +5 -0
  2. package/dist/advanced-tool-registry.d.ts +112 -0
  3. package/dist/advanced-tool-registry.d.ts.map +1 -0
  4. package/dist/advanced-tool-registry.js +407 -0
  5. package/dist/advanced-tool-registry.js.map +1 -0
  6. package/dist/agent-evaluation.d.ts +176 -0
  7. package/dist/agent-evaluation.d.ts.map +1 -0
  8. package/dist/agent-evaluation.js +334 -0
  9. package/dist/agent-evaluation.js.map +1 -0
  10. package/dist/agent-store.d.ts.map +1 -1
  11. package/dist/agent-store.js +226 -8
  12. package/dist/agent-store.js.map +1 -1
  13. package/dist/agent-trace.d.ts +127 -0
  14. package/dist/agent-trace.d.ts.map +1 -0
  15. package/dist/agent-trace.js +331 -0
  16. package/dist/agent-trace.js.map +1 -0
  17. package/dist/agent.d.ts +12 -1
  18. package/dist/agent.d.ts.map +1 -1
  19. package/dist/agent.js +469 -36
  20. package/dist/agent.js.map +1 -1
  21. package/dist/api-stability.d.ts +9 -0
  22. package/dist/api-stability.d.ts.map +1 -0
  23. package/dist/api-stability.js +261 -0
  24. package/dist/api-stability.js.map +1 -0
  25. package/dist/artifact.d.ts +165 -0
  26. package/dist/artifact.d.ts.map +1 -0
  27. package/dist/artifact.js +994 -0
  28. package/dist/artifact.js.map +1 -0
  29. package/dist/errors.d.ts +2 -0
  30. package/dist/errors.d.ts.map +1 -1
  31. package/dist/errors.js +2 -0
  32. package/dist/errors.js.map +1 -1
  33. package/dist/generate-text.d.ts.map +1 -1
  34. package/dist/generate-text.js +6 -2
  35. package/dist/generate-text.js.map +1 -1
  36. package/dist/index.d.ts +27 -1
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +14 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/live-agent.d.ts.map +1 -1
  41. package/dist/live-agent.js +7 -1
  42. package/dist/live-agent.js.map +1 -1
  43. package/dist/provider-parity.d.ts +63 -0
  44. package/dist/provider-parity.d.ts.map +1 -0
  45. package/dist/provider-parity.js +175 -0
  46. package/dist/provider-parity.js.map +1 -0
  47. package/dist/runner.d.ts +111 -0
  48. package/dist/runner.d.ts.map +1 -0
  49. package/dist/runner.js +635 -0
  50. package/dist/runner.js.map +1 -0
  51. package/dist/safety-policy.d.ts +65 -0
  52. package/dist/safety-policy.d.ts.map +1 -0
  53. package/dist/safety-policy.js +308 -0
  54. package/dist/safety-policy.js.map +1 -0
  55. package/dist/types.d.ts +119 -3
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/workflow-artifacts.d.ts +28 -0
  58. package/dist/workflow-artifacts.d.ts.map +1 -0
  59. package/dist/workflow-artifacts.js +86 -0
  60. package/dist/workflow-artifacts.js.map +1 -0
  61. package/dist/workflow-evaluation-diff.d.ts +51 -0
  62. package/dist/workflow-evaluation-diff.d.ts.map +1 -0
  63. package/dist/workflow-evaluation-diff.js +141 -0
  64. package/dist/workflow-evaluation-diff.js.map +1 -0
  65. package/dist/workflow-evaluation.d.ts +94 -0
  66. package/dist/workflow-evaluation.d.ts.map +1 -0
  67. package/dist/workflow-evaluation.js +210 -0
  68. package/dist/workflow-evaluation.js.map +1 -0
  69. package/dist/workflow-state-service.d.ts +67 -0
  70. package/dist/workflow-state-service.d.ts.map +1 -0
  71. package/dist/workflow-state-service.js +498 -0
  72. package/dist/workflow-state-service.js.map +1 -0
  73. package/dist/workflow.d.ts +206 -0
  74. package/dist/workflow.d.ts.map +1 -0
  75. package/dist/workflow.js +727 -0
  76. package/dist/workflow.js.map +1 -0
  77. package/package.json +1 -1
@@ -0,0 +1,727 @@
1
+ import { ValidationError } from "./errors.js";
2
+ const randomId = (prefix) => `${prefix}_${Math.random().toString(36).slice(2, 10)}`;
3
+ const cloneJson = (value) => JSON.parse(JSON.stringify(value));
4
+ export const WORKFLOW_RUN_STATE_SCHEMA_VERSION = 1;
5
+ const toOutput = (state) => ({
6
+ status: state.status,
7
+ state: cloneJson(state),
8
+ outputs: cloneJson(state.outputs),
9
+ steps: cloneJson(state.steps),
10
+ session: state.session ? cloneJson(state.session) : undefined
11
+ });
12
+ const createBaseState = (workflow, input) => {
13
+ const now = Date.now();
14
+ return {
15
+ schemaVersion: WORKFLOW_RUN_STATE_SCHEMA_VERSION,
16
+ workflowId: workflow.id,
17
+ runId: randomId("wfr"),
18
+ userId: input.userId,
19
+ sessionId: input.sessionId ?? randomId("sess"),
20
+ status: "running",
21
+ input: input.input === undefined ? undefined : cloneJson(input.input),
22
+ outputs: {},
23
+ steps: [],
24
+ currentStepIndex: 0,
25
+ metadata: input.metadata ? cloneJson(input.metadata) : undefined,
26
+ createdAt: now,
27
+ updatedAt: now
28
+ };
29
+ };
30
+ export const normalizeWorkflowRunState = (value) => {
31
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
32
+ throw new ValidationError("WorkflowRunState must be an object.");
33
+ }
34
+ const state = value;
35
+ if (state.schemaVersion !== undefined && state.schemaVersion > WORKFLOW_RUN_STATE_SCHEMA_VERSION) {
36
+ throw new ValidationError(`Unsupported WorkflowRunState schemaVersion ${state.schemaVersion}.`);
37
+ }
38
+ if (typeof state.runId !== "string" ||
39
+ typeof state.userId !== "string" ||
40
+ typeof state.sessionId !== "string" ||
41
+ typeof state.status !== "string" ||
42
+ !state.outputs ||
43
+ typeof state.outputs !== "object" ||
44
+ Array.isArray(state.outputs) ||
45
+ !Array.isArray(state.steps) ||
46
+ typeof state.currentStepIndex !== "number" ||
47
+ typeof state.createdAt !== "number" ||
48
+ typeof state.updatedAt !== "number") {
49
+ throw new ValidationError("WorkflowRunState is missing required fields.");
50
+ }
51
+ return {
52
+ schemaVersion: WORKFLOW_RUN_STATE_SCHEMA_VERSION,
53
+ workflowId: state.workflowId,
54
+ runId: state.runId,
55
+ userId: state.userId,
56
+ sessionId: state.sessionId,
57
+ status: state.status,
58
+ input: state.input === undefined ? undefined : cloneJson(state.input),
59
+ outputs: cloneJson(state.outputs),
60
+ steps: cloneJson(state.steps),
61
+ currentStepIndex: state.currentStepIndex,
62
+ session: state.session ? cloneJson(state.session) : undefined,
63
+ metadata: state.metadata ? cloneJson(state.metadata) : undefined,
64
+ createdAt: state.createdAt,
65
+ updatedAt: state.updatedAt
66
+ };
67
+ };
68
+ export const migrateWorkflowRunState = (value, targetVersion = WORKFLOW_RUN_STATE_SCHEMA_VERSION) => {
69
+ if (targetVersion !== WORKFLOW_RUN_STATE_SCHEMA_VERSION) {
70
+ throw new ValidationError(`Unsupported WorkflowRunState migration target ${targetVersion}.`);
71
+ }
72
+ return normalizeWorkflowRunState(value);
73
+ };
74
+ const normalizeState = (state) => normalizeWorkflowRunState(state);
75
+ const workflowPersistenceKey = (workflow) => workflow.persistence?.workflowKey ?? workflow.id ?? "default";
76
+ const workflowMetadataKey = (workflow) => workflow.persistence?.metadataKey ?? "workflowRuns";
77
+ const toPersistedWorkflowState = (state) => {
78
+ const { session: _session, ...persisted } = state;
79
+ return cloneJson(persisted);
80
+ };
81
+ const getWorkflowRunsMetadata = (metadata, key) => {
82
+ const value = metadata?.[key];
83
+ return value && typeof value === "object" && !Array.isArray(value)
84
+ ? cloneJson(value)
85
+ : {};
86
+ };
87
+ export const loadWorkflowState = async (workflow, input) => {
88
+ const definition = validateWorkflow(workflow);
89
+ const persistence = definition.persistence;
90
+ if (!persistence) {
91
+ return undefined;
92
+ }
93
+ if (persistence.workflowStateService) {
94
+ const record = await persistence.workflowStateService.loadWorkflowState({
95
+ appName: persistence.appName,
96
+ userId: input.userId,
97
+ sessionId: input.sessionId,
98
+ workflowKey: workflowPersistenceKey(definition)
99
+ });
100
+ if (!record) {
101
+ return undefined;
102
+ }
103
+ const session = await persistence.sessionService.loadSession({
104
+ appName: persistence.appName,
105
+ userId: input.userId,
106
+ sessionId: input.sessionId
107
+ });
108
+ return {
109
+ ...normalizeWorkflowRunState(record.state),
110
+ session: session ? cloneJson(session) : undefined
111
+ };
112
+ }
113
+ const session = await persistence.sessionService.loadSession({
114
+ appName: persistence.appName,
115
+ userId: input.userId,
116
+ sessionId: input.sessionId
117
+ });
118
+ const runs = getWorkflowRunsMetadata(session?.metadata, workflowMetadataKey(definition));
119
+ const persisted = runs[workflowPersistenceKey(definition)];
120
+ if (!persisted || typeof persisted !== "object" || Array.isArray(persisted)) {
121
+ return undefined;
122
+ }
123
+ return {
124
+ ...normalizeWorkflowRunState(persisted),
125
+ session: session ? cloneJson(session) : undefined
126
+ };
127
+ };
128
+ export const saveWorkflowState = async (workflow, state) => {
129
+ const definition = validateWorkflow(workflow);
130
+ const persistence = definition.persistence;
131
+ if (!persistence) {
132
+ return undefined;
133
+ }
134
+ const lookup = {
135
+ appName: persistence.appName,
136
+ userId: state.userId,
137
+ sessionId: state.sessionId
138
+ };
139
+ const existing = await persistence.sessionService.loadSession(lookup);
140
+ const session = existing ??
141
+ await persistence.sessionService.createSession({
142
+ ...lookup,
143
+ metadata: {}
144
+ });
145
+ if (persistence.workflowStateService) {
146
+ const workflowKey = workflowPersistenceKey(definition);
147
+ await persistence.workflowStateService.saveWorkflowState({
148
+ ...lookup,
149
+ workflowKey,
150
+ state: toPersistedWorkflowState(normalizeWorkflowRunState(state))
151
+ });
152
+ const next = {
153
+ ...session,
154
+ updatedAt: Date.now(),
155
+ metadata: {
156
+ ...(session.metadata ?? {}),
157
+ workflowStateRefs: {
158
+ ...(session.metadata?.workflowStateRefs &&
159
+ typeof session.metadata.workflowStateRefs === "object" &&
160
+ !Array.isArray(session.metadata.workflowStateRefs)
161
+ ? session.metadata.workflowStateRefs
162
+ : {}),
163
+ [workflowKey]: {
164
+ runId: state.runId,
165
+ status: state.status,
166
+ updatedAt: state.updatedAt
167
+ }
168
+ }
169
+ }
170
+ };
171
+ await persistence.sessionService.saveSession(next);
172
+ return cloneJson(next);
173
+ }
174
+ const metadataKey = workflowMetadataKey(definition);
175
+ const workflowRuns = getWorkflowRunsMetadata(session.metadata, metadataKey);
176
+ workflowRuns[workflowPersistenceKey(definition)] = toPersistedWorkflowState(normalizeWorkflowRunState(state));
177
+ const next = {
178
+ ...session,
179
+ updatedAt: Date.now(),
180
+ metadata: {
181
+ ...(session.metadata ?? {}),
182
+ [metadataKey]: workflowRuns
183
+ }
184
+ };
185
+ await persistence.sessionService.saveSession(next);
186
+ return cloneJson(next);
187
+ };
188
+ const resolveInitialState = async (workflow, input) => {
189
+ if (input.state) {
190
+ return normalizeState(input.state);
191
+ }
192
+ if (input.resumeFromPersistedState && input.sessionId) {
193
+ const persisted = await loadWorkflowState(workflow, {
194
+ userId: input.userId,
195
+ sessionId: input.sessionId
196
+ });
197
+ if (persisted) {
198
+ return normalizeState(persisted);
199
+ }
200
+ }
201
+ return createBaseState(workflow, input);
202
+ };
203
+ const finalizeWorkflowOutput = async (workflow, state) => {
204
+ const session = await saveWorkflowState(workflow, state);
205
+ if (session) {
206
+ state.session = session;
207
+ }
208
+ return toOutput(state);
209
+ };
210
+ const setStepResult = (state, index, result) => {
211
+ state.steps = [...state.steps.slice(0, index), cloneJson(result)];
212
+ };
213
+ const isParallelStep = (step) => step.kind === "parallel";
214
+ const isLoopStep = (step) => step.kind === "loop";
215
+ const resolveTaskPrompt = async (workflow, state, step, input) => {
216
+ if (typeof step.prompt === "string") {
217
+ return step.prompt;
218
+ }
219
+ return step.prompt({
220
+ workflowId: workflow.id,
221
+ runId: state.runId,
222
+ userId: state.userId,
223
+ sessionId: state.sessionId,
224
+ input: state.input,
225
+ outputs: cloneJson(state.outputs),
226
+ steps: cloneJson(state.steps),
227
+ step,
228
+ metadata: input.metadata
229
+ });
230
+ };
231
+ const createStepResult = (step, status, startedAt, output, error) => ({
232
+ id: step.id,
233
+ kind: "task",
234
+ status,
235
+ outputKey: step.outputKey,
236
+ outputText: output?.output.steps.at(-1)?.response?.text ?? output?.output.outputText,
237
+ runId: output?.output.state.runId,
238
+ agentStatus: output?.output.status,
239
+ approvals: output?.output.state.pendingApprovals.length ? cloneJson(output.output.state.pendingApprovals) : undefined,
240
+ startedAt,
241
+ finishedAt: Date.now(),
242
+ error: error
243
+ ? {
244
+ message: error instanceof Error ? error.message : String(error)
245
+ }
246
+ : output?.output.error
247
+ });
248
+ const createParallelResult = (step, status, startedAt, children, error) => ({
249
+ id: step.id,
250
+ kind: "parallel",
251
+ status,
252
+ children: cloneJson(children),
253
+ startedAt,
254
+ finishedAt: Date.now(),
255
+ error,
256
+ metadata: step.metadata ? cloneJson(step.metadata) : undefined
257
+ });
258
+ const createLoopResult = (step, status, startedAt, children, error) => ({
259
+ id: step.id,
260
+ kind: "loop",
261
+ status,
262
+ children: cloneJson(children),
263
+ startedAt,
264
+ finishedAt: Date.now(),
265
+ error,
266
+ metadata: step.metadata ? cloneJson(step.metadata) : undefined
267
+ });
268
+ const stepStatusFromAgentStatus = (status) => {
269
+ if (status === "completed") {
270
+ return "completed";
271
+ }
272
+ if (status === "waiting_approval") {
273
+ return "waiting_approval";
274
+ }
275
+ return "failed";
276
+ };
277
+ const validateWorkflow = (definition) => {
278
+ if (!definition.steps.length) {
279
+ throw new Error("Workflow must include at least one step.");
280
+ }
281
+ const ids = new Set();
282
+ for (const step of definition.steps) {
283
+ if (ids.has(step.id)) {
284
+ throw new Error(`Workflow step id "${step.id}" is duplicated.`);
285
+ }
286
+ ids.add(step.id);
287
+ if (isParallelStep(step)) {
288
+ if (!step.steps.length) {
289
+ throw new Error(`Workflow parallel step "${step.id}" must include at least one child step.`);
290
+ }
291
+ for (const child of step.steps) {
292
+ if (isParallelStep(child)) {
293
+ throw new Error("Nested parallel workflow steps are not supported yet.");
294
+ }
295
+ if (ids.has(child.id)) {
296
+ throw new Error(`Workflow step id "${child.id}" is duplicated.`);
297
+ }
298
+ ids.add(child.id);
299
+ }
300
+ continue;
301
+ }
302
+ if (isLoopStep(step)) {
303
+ if (!Number.isInteger(step.maxIterations) || step.maxIterations <= 0) {
304
+ throw new Error(`Workflow loop step "${step.id}" must include a positive integer maxIterations.`);
305
+ }
306
+ if (step.step.kind === "parallel") {
307
+ throw new Error("Workflow loop steps can only wrap task steps in this release.");
308
+ }
309
+ if (step.step.kind === "loop") {
310
+ throw new Error("Nested loop workflow steps are not supported yet.");
311
+ }
312
+ if (ids.has(step.step.id)) {
313
+ throw new Error(`Workflow step id "${step.step.id}" is duplicated.`);
314
+ }
315
+ ids.add(step.step.id);
316
+ }
317
+ }
318
+ return {
319
+ ...definition,
320
+ metadata: definition.metadata ? cloneJson(definition.metadata) : undefined,
321
+ steps: definition.steps.map((step) => isParallelStep(step)
322
+ ? {
323
+ ...step,
324
+ metadata: step.metadata ? cloneJson(step.metadata) : undefined,
325
+ steps: step.steps.map((child) => ({
326
+ ...child,
327
+ metadata: child.metadata ? cloneJson(child.metadata) : undefined
328
+ }))
329
+ }
330
+ : isLoopStep(step)
331
+ ? {
332
+ ...step,
333
+ metadata: step.metadata ? cloneJson(step.metadata) : undefined,
334
+ step: {
335
+ ...step.step,
336
+ metadata: step.step.metadata ? cloneJson(step.step.metadata) : undefined
337
+ }
338
+ }
339
+ : {
340
+ ...step,
341
+ metadata: step.metadata ? cloneJson(step.metadata) : undefined
342
+ })
343
+ };
344
+ };
345
+ export const createWorkflow = (definition) => validateWorkflow(definition);
346
+ const runTaskStep = async (workflow, state, step, input, options) => {
347
+ const runnerInput = options.isApprovalResume
348
+ ? {
349
+ userId: state.userId,
350
+ sessionId: state.sessionId,
351
+ approvals: input.approvals,
352
+ sessionMetadata: input.sessionMetadata,
353
+ eventMetadata: input.eventMetadata
354
+ }
355
+ : {
356
+ userId: state.userId,
357
+ sessionId: state.sessionId,
358
+ prompt: await resolveTaskPrompt(workflow, state, step, input),
359
+ system: step.system,
360
+ sessionMetadata: input.sessionMetadata,
361
+ eventMetadata: {
362
+ ...(input.eventMetadata ?? {}),
363
+ workflowRunId: state.runId,
364
+ workflowStepId: step.id
365
+ }
366
+ };
367
+ const output = await step.runner.run(runnerInput);
368
+ const status = stepStatusFromAgentStatus(output.output.status);
369
+ return {
370
+ result: createStepResult(step, status, options.startedAt, output),
371
+ output
372
+ };
373
+ };
374
+ const collectStepOutputs = (outputs, step, result, output) => {
375
+ if (result.status === "completed" && step.outputKey) {
376
+ outputs[step.outputKey] = result.outputText ?? output?.output.outputText ?? "";
377
+ }
378
+ };
379
+ const runParallelStep = async (workflow, state, step, input, existingResult, startedAt) => {
380
+ const previousChildren = existingResult?.children ?? [];
381
+ const hasWaitingChild = previousChildren.some((child) => child.status === "waiting_approval");
382
+ const runnableSteps = step.steps.map((child, childIndex) => {
383
+ const previous = previousChildren.find((result) => result.id === child.id);
384
+ if (previous?.status === "completed") {
385
+ return Promise.resolve({ child, childIndex, result: previous, output: undefined, skipped: true });
386
+ }
387
+ if (hasWaitingChild && previous?.status !== "waiting_approval") {
388
+ return Promise.resolve({
389
+ child,
390
+ childIndex,
391
+ result: previous ?? {
392
+ id: child.id,
393
+ kind: "task",
394
+ status: "pending",
395
+ outputKey: child.outputKey,
396
+ metadata: child.metadata ? cloneJson(child.metadata) : undefined
397
+ },
398
+ output: undefined,
399
+ skipped: true
400
+ });
401
+ }
402
+ return runTaskStep(workflow, state, child, input, {
403
+ startedAt: Date.now(),
404
+ isApprovalResume: previous?.status === "waiting_approval" && Boolean(input.approvals?.length)
405
+ })
406
+ .then(({ result, output }) => ({ child, childIndex, result, output, skipped: false }))
407
+ .catch((error) => ({
408
+ child,
409
+ childIndex,
410
+ result: createStepResult(child, "failed", Date.now(), undefined, error),
411
+ output: undefined,
412
+ skipped: false
413
+ }));
414
+ });
415
+ const settled = await Promise.allSettled(runnableSteps);
416
+ const childRuns = settled.map((settledResult, index) => {
417
+ if (settledResult.status === "fulfilled") {
418
+ return settledResult.value;
419
+ }
420
+ const child = step.steps[index];
421
+ return {
422
+ child,
423
+ childIndex: index,
424
+ result: createStepResult(child, "failed", Date.now(), undefined, settledResult.reason),
425
+ output: undefined,
426
+ skipped: false
427
+ };
428
+ });
429
+ const children = childRuns
430
+ .sort((left, right) => left.childIndex - right.childIndex)
431
+ .map((childRun) => childRun.result);
432
+ for (const childRun of childRuns) {
433
+ if (!childRun.skipped) {
434
+ collectStepOutputs(state.outputs, childRun.child, childRun.result, childRun.output);
435
+ if (childRun.output?.session) {
436
+ state.session = childRun.output.session;
437
+ }
438
+ }
439
+ }
440
+ const waiting = children.some((child) => child.status === "waiting_approval");
441
+ const failed = children.some((child) => child.status === "failed");
442
+ const status = waiting ? "waiting_approval" : failed ? "failed" : "completed";
443
+ const firstError = children.find((child) => child.error)?.error;
444
+ return {
445
+ result: createParallelResult(step, step.failFast && failed ? "failed" : status, startedAt, children, firstError),
446
+ session: state.session
447
+ };
448
+ };
449
+ const shouldStopLoop = async (workflow, state, step, input, iteration, result) => {
450
+ if (!step.until) {
451
+ return false;
452
+ }
453
+ return step.until({
454
+ workflowId: workflow.id,
455
+ runId: state.runId,
456
+ userId: state.userId,
457
+ sessionId: state.sessionId,
458
+ input: state.input,
459
+ outputs: cloneJson(state.outputs),
460
+ steps: cloneJson(state.steps),
461
+ step,
462
+ iteration,
463
+ result: cloneJson(result),
464
+ metadata: input.metadata
465
+ });
466
+ };
467
+ const runLoopStep = async (workflow, state, step, input, existingResult, startedAt) => {
468
+ const previousChildren = existingResult?.children ?? [];
469
+ const waitingIndex = previousChildren.findIndex((child) => child.status === "waiting_approval");
470
+ const children = waitingIndex >= 0
471
+ ? previousChildren.slice(0, waitingIndex)
472
+ : previousChildren.filter((child) => child.status === "completed");
473
+ const firstIteration = waitingIndex >= 0 ? waitingIndex : children.length;
474
+ for (let iteration = firstIteration; iteration < step.maxIterations; iteration += 1) {
475
+ const childStartedAt = Date.now();
476
+ const isApprovalResume = waitingIndex === iteration && Boolean(input.approvals?.length);
477
+ const { result, output } = await runTaskStep(workflow, state, step.step, input, {
478
+ startedAt: childStartedAt,
479
+ isApprovalResume
480
+ }).catch((error) => ({
481
+ result: createStepResult(step.step, "failed", childStartedAt, undefined, error),
482
+ output: undefined
483
+ }));
484
+ children[iteration] = result;
485
+ if (output?.session) {
486
+ state.session = output.session;
487
+ }
488
+ if (result.status === "completed") {
489
+ collectStepOutputs(state.outputs, step.step, result, output);
490
+ if (await shouldStopLoop(workflow, state, step, input, iteration, result)) {
491
+ return {
492
+ result: createLoopResult(step, "completed", startedAt, children),
493
+ session: state.session
494
+ };
495
+ }
496
+ continue;
497
+ }
498
+ return {
499
+ result: createLoopResult(step, result.status === "waiting_approval" ? "waiting_approval" : "failed", startedAt, children, result.error),
500
+ session: state.session
501
+ };
502
+ }
503
+ return {
504
+ result: createLoopResult(step, "completed", startedAt, children),
505
+ session: state.session
506
+ };
507
+ };
508
+ export const runWorkflow = async (workflow, input) => {
509
+ const definition = validateWorkflow(workflow);
510
+ const state = await resolveInitialState(definition, input);
511
+ state.status = "running";
512
+ state.updatedAt = Date.now();
513
+ const waitingIndex = state.steps.findIndex((step) => step.status === "waiting_approval");
514
+ if (waitingIndex >= 0 && !input.approvals?.length) {
515
+ state.status = "waiting_approval";
516
+ state.currentStepIndex = waitingIndex;
517
+ state.updatedAt = Date.now();
518
+ return finalizeWorkflowOutput(definition, state);
519
+ }
520
+ const startIndex = waitingIndex >= 0 ? waitingIndex : state.currentStepIndex;
521
+ for (let index = startIndex; index < definition.steps.length; index += 1) {
522
+ const step = definition.steps[index];
523
+ const startedAt = Date.now();
524
+ state.currentStepIndex = index;
525
+ const existingResult = state.steps[index];
526
+ setStepResult(state, index, isParallelStep(step)
527
+ ? {
528
+ id: step.id,
529
+ kind: "parallel",
530
+ status: "running",
531
+ children: existingResult?.children,
532
+ metadata: step.metadata ? cloneJson(step.metadata) : undefined,
533
+ startedAt
534
+ }
535
+ : isLoopStep(step)
536
+ ? {
537
+ id: step.id,
538
+ kind: "loop",
539
+ status: "running",
540
+ children: existingResult?.children,
541
+ metadata: step.metadata ? cloneJson(step.metadata) : undefined,
542
+ startedAt
543
+ }
544
+ : {
545
+ id: step.id,
546
+ kind: "task",
547
+ status: "running",
548
+ outputKey: step.outputKey,
549
+ metadata: step.metadata ? cloneJson(step.metadata) : undefined,
550
+ startedAt
551
+ });
552
+ try {
553
+ const stepRun = isParallelStep(step)
554
+ ? await runParallelStep(definition, state, step, input, existingResult, startedAt)
555
+ : isLoopStep(step)
556
+ ? await runLoopStep(definition, state, step, input, existingResult, startedAt)
557
+ : await runTaskStep(definition, state, step, input, {
558
+ startedAt,
559
+ isApprovalResume: index === waitingIndex && Boolean(input.approvals?.length)
560
+ });
561
+ const { result } = stepRun;
562
+ const output = "output" in stepRun ? stepRun.output : undefined;
563
+ const session = "session" in stepRun ? stepRun.session : undefined;
564
+ if (output?.session) {
565
+ state.session = output.session;
566
+ }
567
+ else if (session) {
568
+ state.session = session;
569
+ }
570
+ const status = result.status;
571
+ setStepResult(state, index, result);
572
+ if (status === "completed") {
573
+ if (!isParallelStep(step) && !isLoopStep(step)) {
574
+ collectStepOutputs(state.outputs, step, result, output);
575
+ }
576
+ state.currentStepIndex = index + 1;
577
+ state.updatedAt = Date.now();
578
+ continue;
579
+ }
580
+ state.status = status === "waiting_approval" ? "waiting_approval" : "failed";
581
+ state.currentStepIndex = index;
582
+ state.updatedAt = Date.now();
583
+ return finalizeWorkflowOutput(definition, state);
584
+ }
585
+ catch (error) {
586
+ setStepResult(state, index, isParallelStep(step)
587
+ ? createParallelResult(step, "failed", startedAt, existingResult?.children ?? [], {
588
+ message: error instanceof Error ? error.message : String(error)
589
+ })
590
+ : isLoopStep(step)
591
+ ? createLoopResult(step, "failed", startedAt, existingResult?.children ?? [], {
592
+ message: error instanceof Error ? error.message : String(error)
593
+ })
594
+ : createStepResult(step, "failed", startedAt, undefined, error));
595
+ state.status = "failed";
596
+ state.currentStepIndex = index;
597
+ state.updatedAt = Date.now();
598
+ return finalizeWorkflowOutput(definition, state);
599
+ }
600
+ }
601
+ state.status = "completed";
602
+ state.currentStepIndex = definition.steps.length;
603
+ state.updatedAt = Date.now();
604
+ return finalizeWorkflowOutput(definition, state);
605
+ };
606
+ export const replayWorkflowRun = (state) => {
607
+ const timeline = [
608
+ {
609
+ type: "workflow-start",
610
+ runId: state.runId,
611
+ workflowId: state.workflowId,
612
+ createdAt: state.createdAt
613
+ }
614
+ ];
615
+ for (const step of state.steps) {
616
+ if (step.kind === "parallel") {
617
+ timeline.push({
618
+ type: "parallel-start",
619
+ stepId: step.id,
620
+ startedAt: step.startedAt
621
+ });
622
+ for (const child of step.children ?? []) {
623
+ if (child.approvals?.length) {
624
+ timeline.push({
625
+ type: "approval-required",
626
+ stepId: child.id,
627
+ approvals: cloneJson(child.approvals)
628
+ });
629
+ }
630
+ timeline.push({
631
+ type: "parallel-step-finish",
632
+ stepId: child.id,
633
+ parentStepId: step.id,
634
+ status: child.status,
635
+ outputText: child.outputText,
636
+ error: child.error,
637
+ finishedAt: child.finishedAt
638
+ });
639
+ }
640
+ timeline.push({
641
+ type: "parallel-finish",
642
+ stepId: step.id,
643
+ status: step.status,
644
+ finishedAt: step.finishedAt
645
+ });
646
+ if (step.approvals?.length) {
647
+ timeline.push({
648
+ type: "approval-required",
649
+ stepId: step.id,
650
+ approvals: cloneJson(step.approvals)
651
+ });
652
+ }
653
+ continue;
654
+ }
655
+ if (step.kind === "loop") {
656
+ timeline.push({
657
+ type: "loop-start",
658
+ stepId: step.id,
659
+ startedAt: step.startedAt
660
+ });
661
+ for (const [index, child] of (step.children ?? []).entries()) {
662
+ if (child.approvals?.length) {
663
+ timeline.push({
664
+ type: "approval-required",
665
+ stepId: child.id,
666
+ approvals: cloneJson(child.approvals)
667
+ });
668
+ }
669
+ timeline.push({
670
+ type: "loop-iteration-finish",
671
+ stepId: child.id,
672
+ parentStepId: step.id,
673
+ iteration: index,
674
+ status: child.status,
675
+ outputText: child.outputText,
676
+ error: child.error,
677
+ finishedAt: child.finishedAt
678
+ });
679
+ }
680
+ timeline.push({
681
+ type: "loop-finish",
682
+ stepId: step.id,
683
+ status: step.status,
684
+ finishedAt: step.finishedAt
685
+ });
686
+ if (step.approvals?.length) {
687
+ timeline.push({
688
+ type: "approval-required",
689
+ stepId: step.id,
690
+ approvals: cloneJson(step.approvals)
691
+ });
692
+ }
693
+ continue;
694
+ }
695
+ timeline.push({
696
+ type: "step-start",
697
+ stepId: step.id,
698
+ startedAt: step.startedAt
699
+ });
700
+ if (step.approvals?.length) {
701
+ timeline.push({
702
+ type: "approval-required",
703
+ stepId: step.id,
704
+ approvals: cloneJson(step.approvals)
705
+ });
706
+ }
707
+ timeline.push({
708
+ type: "step-finish",
709
+ stepId: step.id,
710
+ status: step.status,
711
+ outputText: step.outputText,
712
+ error: step.error,
713
+ finishedAt: step.finishedAt
714
+ });
715
+ }
716
+ timeline.push({
717
+ type: "workflow-finish",
718
+ status: state.status,
719
+ updatedAt: state.updatedAt
720
+ });
721
+ return {
722
+ status: state.status,
723
+ timeline,
724
+ outputs: cloneJson(state.outputs)
725
+ };
726
+ };
727
+ //# sourceMappingURL=workflow.js.map