@ai-setting/roy-agent-core 1.5.88 → 1.5.89

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 (37) hide show
  1. package/dist/env/agent/index.js +6 -6
  2. package/dist/env/event-source/index.js +6 -2
  3. package/dist/env/index.js +16 -11
  4. package/dist/env/prompt/index.js +2 -1
  5. package/dist/env/session/index.js +1 -2
  6. package/dist/env/task/delegate/index.js +3 -2
  7. package/dist/env/task/index.js +4 -3
  8. package/dist/env/task/plugins/index.js +7 -4
  9. package/dist/env/tool/built-in/index.js +2 -1
  10. package/dist/env/tool/index.js +11 -8
  11. package/dist/env/workflow/engine/index.js +4 -2
  12. package/dist/env/workflow/index.js +5 -3
  13. package/dist/env/workflow/tools/index.js +7 -1
  14. package/dist/env/workflow/utils/index.js +5 -0
  15. package/dist/index.js +31 -24
  16. package/dist/shared/@ai-setting/{roy-agent-core-6mk0m4t3.js → roy-agent-core-2q7cshpm.js} +1 -1
  17. package/dist/shared/@ai-setting/{roy-agent-core-0y64qaac.js → roy-agent-core-32m0nb9j.js} +119 -30
  18. package/dist/shared/@ai-setting/{roy-agent-core-9y09xfav.js → roy-agent-core-3f6k060j.js} +5 -417
  19. package/dist/shared/@ai-setting/roy-agent-core-4yq23m5g.js +421 -0
  20. package/dist/shared/@ai-setting/{roy-agent-core-mmkyydw7.js → roy-agent-core-83d035pp.js} +91 -579
  21. package/dist/shared/@ai-setting/roy-agent-core-8wd3qwx5.js +35 -0
  22. package/dist/shared/@ai-setting/{roy-agent-core-29fh9mxg.js → roy-agent-core-bwjpte58.js} +1 -2
  23. package/dist/shared/@ai-setting/{roy-agent-core-4cdtdxqx.js → roy-agent-core-ewr1nw7t.js} +1 -1
  24. package/dist/shared/@ai-setting/{roy-agent-core-yx0vw1aw.js → roy-agent-core-fgpnv7dt.js} +31 -4
  25. package/dist/shared/@ai-setting/{roy-agent-core-jymz9fzp.js → roy-agent-core-fvfc7f6v.js} +64 -33
  26. package/dist/shared/@ai-setting/roy-agent-core-hvdfgvfz.js +114 -0
  27. package/dist/shared/@ai-setting/{roy-agent-core-3arrpf7n.js → roy-agent-core-hxsbegfc.js} +229 -9
  28. package/dist/shared/@ai-setting/{roy-agent-core-7fdzfsm6.js → roy-agent-core-m3dkyprg.js} +35 -211
  29. package/dist/shared/@ai-setting/{roy-agent-core-bgw4dq11.js → roy-agent-core-mw4ty0ba.js} +44 -5
  30. package/dist/shared/@ai-setting/{roy-agent-core-7z4xtrmw.js → roy-agent-core-nqzt9ne4.js} +53 -0
  31. package/dist/shared/@ai-setting/roy-agent-core-pt7as39r.js +0 -0
  32. package/dist/shared/@ai-setting/{roy-agent-core-6n7xwv4v.js → roy-agent-core-qbq3jgrn.js} +5 -3
  33. package/dist/shared/@ai-setting/roy-agent-core-w6bmrgap.js +581 -0
  34. package/dist/shared/@ai-setting/{roy-agent-core-qhjb153z.js → roy-agent-core-xnxyzaw4.js} +27 -4
  35. package/dist/shared/@ai-setting/roy-agent-core-yanpq5gb.js +116 -0
  36. package/package.json +1 -1
  37. package/dist/shared/@ai-setting/roy-agent-core-x3gtyqax.js +0 -378
@@ -2,6 +2,9 @@ import {
2
2
  TAG_MAX_COUNT,
3
3
  TAG_MIN_COUNT
4
4
  } from "./roy-agent-core-tq9528d3.js";
5
+ import {
6
+ validateWorkflowDefinition
7
+ } from "./roy-agent-core-8wd3qwx5.js";
5
8
  import {
6
9
  AskUserError,
7
10
  init_workflow_hil
@@ -409,6 +412,15 @@ function createWorkflowAddTool(workflowService) {
409
412
  metadata: { execution_time_ms: 0 }
410
413
  };
411
414
  }
415
+ const validation = validateWorkflowDefinition(definition);
416
+ if (!validation.valid) {
417
+ return {
418
+ success: false,
419
+ output: "",
420
+ error: `Validation failed: ${validation.errors.join("; ")}`,
421
+ metadata: { execution_time_ms: 0 }
422
+ };
423
+ }
412
424
  const workflow = await workflowService.createWorkflow(definition, {
413
425
  tags: params.tags
414
426
  });
@@ -453,15 +465,92 @@ function createWorkflowAddTool(workflowService) {
453
465
  };
454
466
  }
455
467
 
456
- // src/env/workflow/tools/workflow-search-tool.ts
468
+ // src/env/workflow/tools/workflow-validate-tool.ts
457
469
  init_logger();
458
470
  import { z as z6 } from "zod";
459
- var logger5 = createLogger("workflow-search-tool");
460
- var WorkflowSearchInputSchema = z6.object({
461
- keyword: z6.string().optional().describe("Search keyword in name and description (case-insensitive substring)"),
462
- tags: z6.array(z6.string()).optional().describe("Filter by tags (ALL must match - AND filter)"),
463
- limit: z6.number().positive().optional().describe("Maximum number of results"),
464
- offset: z6.number().min(0).optional().describe("Pagination offset")
471
+ import yaml2 from "yaml";
472
+ var logger5 = createLogger("workflow-validate-tool");
473
+ var WorkflowValidateInputSchema = z6.object({
474
+ definition: z6.any().optional().describe("Workflow definition object (alternative to definition_yaml)"),
475
+ definition_yaml: z6.string().optional().describe("Workflow definition as YAML or JSON string"),
476
+ yaml: z6.string().optional().describe("Alias for definition_yaml — workflow definition as YAML or JSON string")
477
+ });
478
+ function createWorkflowValidateTool(_workflowService) {
479
+ return {
480
+ name: "workflow_validate",
481
+ description: `Validate a workflow definition (YAML or JSON) without persisting it. ` + `Checks for: duplicate node IDs, missing dependencies, cycles, empty node IDs. ` + `Returns { valid: boolean, errors: string[], workflowName?, nodeCount }. ` + `Use this BEFORE workflow_add to ensure the workflow is structurally sound.`,
482
+ parameters: WorkflowValidateInputSchema,
483
+ execute: async (args, _ctx) => {
484
+ try {
485
+ const params = WorkflowValidateInputSchema.parse(args);
486
+ let definition;
487
+ if (params.definition && typeof params.definition === "object") {
488
+ definition = params.definition;
489
+ } else {
490
+ const yamlText = params.yaml ?? params.definition_yaml;
491
+ if (!yamlText || typeof yamlText !== "string") {
492
+ return {
493
+ success: false,
494
+ output: "",
495
+ error: "Must provide either 'definition' (object), 'definition_yaml', or 'yaml' (string)",
496
+ metadata: { execution_time_ms: 0 }
497
+ };
498
+ }
499
+ try {
500
+ definition = yaml2.parse(yamlText);
501
+ } catch (yamlErr) {
502
+ return {
503
+ success: false,
504
+ output: "",
505
+ error: `Invalid YAML: ${yamlErr instanceof Error ? yamlErr.message : String(yamlErr)}`,
506
+ metadata: { execution_time_ms: 0 }
507
+ };
508
+ }
509
+ }
510
+ if (!definition || typeof definition !== "object") {
511
+ return {
512
+ success: false,
513
+ output: "",
514
+ error: "Parsed definition is not an object",
515
+ metadata: { execution_time_ms: 0 }
516
+ };
517
+ }
518
+ const result = validateWorkflowDefinition(definition);
519
+ const nodeCount = Array.isArray(definition.nodes) ? definition.nodes.length : 0;
520
+ const output = {
521
+ valid: result.valid,
522
+ errors: result.errors,
523
+ workflowName: definition.name,
524
+ nodeCount
525
+ };
526
+ return {
527
+ success: result.valid,
528
+ output: JSON.stringify(output, null, 2),
529
+ error: result.valid ? undefined : `Validation failed: ${result.errors.join("; ")}`,
530
+ metadata: { execution_time_ms: 0 }
531
+ };
532
+ } catch (error) {
533
+ logger5.error("[workflow_validate] failed", { error });
534
+ return {
535
+ success: false,
536
+ output: "",
537
+ error: error instanceof Error ? error.message : String(error),
538
+ metadata: { execution_time_ms: 0 }
539
+ };
540
+ }
541
+ }
542
+ };
543
+ }
544
+
545
+ // src/env/workflow/tools/workflow-search-tool.ts
546
+ init_logger();
547
+ import { z as z7 } from "zod";
548
+ var logger6 = createLogger("workflow-search-tool");
549
+ var WorkflowSearchInputSchema = z7.object({
550
+ keyword: z7.string().optional().describe("Search keyword in name and description (case-insensitive substring)"),
551
+ tags: z7.array(z7.string()).optional().describe("Filter by tags (ALL must match - AND filter)"),
552
+ limit: z7.number().positive().optional().describe("Maximum number of results"),
553
+ offset: z7.number().min(0).optional().describe("Pagination offset")
465
554
  });
466
555
  function createWorkflowSearchTool(workflowService) {
467
556
  return {
@@ -507,7 +596,7 @@ function createWorkflowSearchTool(workflowService) {
507
596
  metadata: { execution_time_ms: 0 }
508
597
  };
509
598
  } catch (error) {
510
- logger5.error("Failed to search workflows", { error });
599
+ logger6.error("Failed to search workflows", { error });
511
600
  return {
512
601
  success: false,
513
602
  output: "",
@@ -521,13 +610,13 @@ function createWorkflowSearchTool(workflowService) {
521
610
 
522
611
  // src/env/workflow/tools/run-workflow.ts
523
612
  init_logger();
524
- import { z as z7 } from "zod";
525
- var logger6 = createLogger("run-workflow-tool");
526
- var RunWorkflowInputSchema = z7.object({
527
- workflow_name: z7.string().describe("Name of the workflow to run"),
528
- input: z7.record(z7.any()).optional().describe("Input to pass to the workflow"),
529
- sync: z7.boolean().default(true).describe("Wait for completion (default: true)"),
530
- timeout: z7.number().positive().optional().describe("Timeout in milliseconds (default: 1800000 = 30 min)")
613
+ import { z as z8 } from "zod";
614
+ var logger7 = createLogger("run-workflow-tool");
615
+ var RunWorkflowInputSchema = z8.object({
616
+ workflow_name: z8.string().describe("Name of the workflow to run"),
617
+ input: z8.record(z8.any()).optional().describe("Input to pass to the workflow"),
618
+ sync: z8.boolean().default(true).describe("Wait for completion (default: true)"),
619
+ timeout: z8.number().positive().optional().describe("Timeout in milliseconds (default: 1800000 = 30 min)")
531
620
  });
532
621
  function createRunWorkflowTool(workflowService) {
533
622
  return {
@@ -549,7 +638,7 @@ function createRunWorkflowTool(workflowService) {
549
638
  execute: async (args, ctx) => {
550
639
  const startTime = Date.now();
551
640
  const { workflow_name, input, sync = true, timeout = 1800000 } = args;
552
- logger6.info(`Running workflow: ${workflow_name}`, { input, sync, timeout });
641
+ logger7.info(`Running workflow: ${workflow_name}`, { input, sync, timeout });
553
642
  let timeoutHandle;
554
643
  let durationMs;
555
644
  try {
@@ -623,8 +712,8 @@ function createRunWorkflowTool(workflowService) {
623
712
  }
624
713
  };
625
714
  }
626
- if (logger6?.error) {
627
- logger6.error(`Failed to run workflow: ${workflow_name}`, { error: errorMessage });
715
+ if (logger7?.error) {
716
+ logger7.error(`Failed to run workflow: ${workflow_name}`, { error: errorMessage });
628
717
  }
629
718
  return {
630
719
  success: false,
@@ -664,10 +753,10 @@ function createLegacyRunWorkflowTool(workflowService) {
664
753
 
665
754
  // src/env/workflow/tools/workflow-run-status-tool.ts
666
755
  init_logger();
667
- import { z as z8 } from "zod";
668
- var logger7 = createLogger("workflow-run-status-tool");
669
- var WorkflowRunStatusInputSchema = z8.object({
670
- run_id: z8.string().describe("Run/session ID to query status")
756
+ import { z as z9 } from "zod";
757
+ var logger8 = createLogger("workflow-run-status-tool");
758
+ var WorkflowRunStatusInputSchema = z9.object({
759
+ run_id: z9.string().describe("Run/session ID to query status")
671
760
  });
672
761
  function createWorkflowRunStatusTool(workflowService) {
673
762
  return {
@@ -707,7 +796,7 @@ function createWorkflowRunStatusTool(workflowService) {
707
796
  metadata: { execution_time_ms: 0 }
708
797
  };
709
798
  } catch (error) {
710
- logger7.error("Failed to get run status", { error });
799
+ logger8.error("Failed to get run status", { error });
711
800
  return {
712
801
  success: false,
713
802
  output: "",
@@ -721,11 +810,11 @@ function createWorkflowRunStatusTool(workflowService) {
721
810
 
722
811
  // src/env/workflow/tools/workflow-run-stop-tool.ts
723
812
  init_logger();
724
- import { z as z9 } from "zod";
725
- var logger8 = createLogger("workflow-run-stop-tool");
726
- var WorkflowRunStopInputSchema = z9.object({
727
- run_id: z9.string().describe("Run/session ID to stop"),
728
- reason: z9.string().optional().describe("Optional reason for stopping the workflow")
813
+ import { z as z10 } from "zod";
814
+ var logger9 = createLogger("workflow-run-stop-tool");
815
+ var WorkflowRunStopInputSchema = z10.object({
816
+ run_id: z10.string().describe("Run/session ID to stop"),
817
+ reason: z10.string().optional().describe("Optional reason for stopping the workflow")
729
818
  });
730
819
  function createWorkflowRunStopTool(workflowService) {
731
820
  return {
@@ -747,7 +836,7 @@ function createWorkflowRunStopTool(workflowService) {
747
836
  metadata: { execution_time_ms: 0 }
748
837
  };
749
838
  } catch (error) {
750
- logger8.error("Failed to stop workflow run", { error });
839
+ logger9.error("Failed to stop workflow run", { error });
751
840
  return {
752
841
  success: false,
753
842
  output: "",
@@ -759,4 +848,4 @@ function createWorkflowRunStopTool(workflowService) {
759
848
  };
760
849
  }
761
850
 
762
- export { AskUserInputSchema, askUserTool, askUserToolInstance, WorkflowGetInputSchema, createWorkflowGetTool, WorkflowListInputSchema, createWorkflowListTool, WorkflowTagListInputSchema, createWorkflowTagListTool, WorkflowAddInputSchema, createWorkflowAddTool, WorkflowSearchInputSchema, createWorkflowSearchTool, RunWorkflowInputSchema, createRunWorkflowTool, initRunWorkflowTool, getRunWorkflowTool, resetRunWorkflowTool, createLegacyRunWorkflowTool, WorkflowRunStatusInputSchema, createWorkflowRunStatusTool, WorkflowRunStopInputSchema, createWorkflowRunStopTool };
851
+ export { AskUserInputSchema, askUserTool, askUserToolInstance, WorkflowGetInputSchema, createWorkflowGetTool, WorkflowListInputSchema, createWorkflowListTool, WorkflowTagListInputSchema, createWorkflowTagListTool, WorkflowAddInputSchema, createWorkflowAddTool, WorkflowValidateInputSchema, createWorkflowValidateTool, WorkflowSearchInputSchema, createWorkflowSearchTool, RunWorkflowInputSchema, createRunWorkflowTool, initRunWorkflowTool, getRunWorkflowTool, resetRunWorkflowTool, createLegacyRunWorkflowTool, WorkflowRunStatusInputSchema, createWorkflowRunStatusTool, WorkflowRunStopInputSchema, createWorkflowRunStopTool };
@@ -35,6 +35,10 @@ import {
35
35
  parseWorkflowJsonOutput,
36
36
  validateJsonOutputSchema
37
37
  } from "./roy-agent-core-1db4vpc6.js";
38
+ import {
39
+ DAGManager,
40
+ init_dag_manager
41
+ } from "./roy-agent-core-4yq23m5g.js";
38
42
  import {
39
43
  AskUserError,
40
44
  createNodeInterruptEvent,
@@ -147,422 +151,6 @@ var init_event_bus = __esm(() => {
147
151
  logger = createLogger("workflow.eventbus");
148
152
  });
149
153
 
150
- // src/env/workflow/engine/dag-manager.ts
151
- class DAGManager {
152
- workflow;
153
- nodeMap;
154
- extendedDefinition = null;
155
- cachedAnalysis = null;
156
- allowCycles;
157
- constructor(workflow, options) {
158
- if (!workflow.nodes || workflow.nodes.length === 0) {
159
- throw new Error("At least one node is required");
160
- }
161
- this.workflow = workflow;
162
- this.nodeMap = new Map;
163
- this.allowCycles = options?.allowCycles ?? false;
164
- for (const node of workflow.nodes) {
165
- if (node.id === "") {
166
- throw new Error("Node ID cannot be empty");
167
- }
168
- if (this.nodeMap.has(node.id)) {
169
- throw new Error(`Duplicate node ID: ${node.id}`);
170
- }
171
- this.nodeMap.set(node.id, node);
172
- }
173
- }
174
- getExtendedDefinition() {
175
- if (this.extendedDefinition) {
176
- return this.extendedDefinition;
177
- }
178
- const analysis = this.analyze();
179
- this.extendedDefinition = {
180
- ...this.workflow,
181
- computedEntry: analysis.entryNodes,
182
- nodeMap: this.nodeMap,
183
- topologicalOrder: this.getTopologicalOrder()
184
- };
185
- return this.extendedDefinition;
186
- }
187
- analyze() {
188
- if (this.cachedAnalysis) {
189
- return this.cachedAnalysis;
190
- }
191
- const dependencies = this.buildDependenciesMap();
192
- const dependents = this.buildDependentsMap(dependencies);
193
- const entryNodes = this.findEntryNodes(dependencies);
194
- const exitNodes = this.findExitNodes(dependents);
195
- const levels = this.computeLevels(dependencies);
196
- const criticalPath = this.findCriticalPath(levels, dependencies);
197
- this.cachedAnalysis = {
198
- entryNodes,
199
- exitNodes,
200
- levels,
201
- dependencies,
202
- dependents,
203
- criticalPath
204
- };
205
- return this.cachedAnalysis;
206
- }
207
- buildDependenciesMap() {
208
- const dependencies = new Map;
209
- for (const node of this.workflow.nodes) {
210
- const deps = node.depends_on || [];
211
- dependencies.set(node.id, [...deps]);
212
- }
213
- if (this.workflow.edges) {
214
- for (const edge of this.workflow.edges) {
215
- const targetDeps = dependencies.get(edge.to);
216
- if (!targetDeps)
217
- continue;
218
- if (targetDeps.includes(edge.from))
219
- continue;
220
- if (!this.isReachable(edge.from, edge.to, dependencies)) {
221
- targetDeps.push(edge.from);
222
- }
223
- }
224
- }
225
- return dependencies;
226
- }
227
- isReachable(source, target, dependencies) {
228
- if (source === target)
229
- return true;
230
- const visited = new Set;
231
- const queue = [source];
232
- while (queue.length > 0) {
233
- const current = queue.shift();
234
- if (current === target)
235
- return true;
236
- if (visited.has(current))
237
- continue;
238
- visited.add(current);
239
- const deps = dependencies.get(current) || [];
240
- for (const dep of deps) {
241
- if (!visited.has(dep))
242
- queue.push(dep);
243
- }
244
- }
245
- return false;
246
- }
247
- buildDependentsMap(dependencies) {
248
- const dependentsMap = new Map;
249
- for (const nodeId of dependencies.keys()) {
250
- dependentsMap.set(nodeId, []);
251
- }
252
- for (const [nodeId, deps] of dependencies.entries()) {
253
- for (const dep of deps) {
254
- const nodeDependents = dependentsMap.get(dep) || [];
255
- nodeDependents.push(nodeId);
256
- dependentsMap.set(dep, nodeDependents);
257
- }
258
- }
259
- return dependentsMap;
260
- }
261
- findEntryNodes(dependencies) {
262
- const entryNodes = [];
263
- for (const [nodeId, deps] of dependencies.entries()) {
264
- if (deps.length === 0) {
265
- entryNodes.push(nodeId);
266
- }
267
- }
268
- return entryNodes;
269
- }
270
- findExitNodes(dependents) {
271
- const exitNodes = [];
272
- for (const [nodeId, deps] of dependents.entries()) {
273
- if (deps.length === 0) {
274
- exitNodes.push(nodeId);
275
- }
276
- }
277
- return exitNodes;
278
- }
279
- computeLevels(dependencies) {
280
- const levels = [];
281
- const assigned = new Set;
282
- const nodeLevels = new Map;
283
- const dependentsMap = this.buildDependentsMap(dependencies);
284
- const entryNodes = this.findEntryNodes(dependencies);
285
- const queue = [];
286
- for (const entry of entryNodes) {
287
- queue.push({ nodeId: entry, level: 0 });
288
- nodeLevels.set(entry, 0);
289
- }
290
- while (queue.length > 0) {
291
- const { nodeId, level } = queue.shift();
292
- if (assigned.has(nodeId)) {
293
- const currentLevel = nodeLevels.get(nodeId) || 0;
294
- if (level > currentLevel) {
295
- nodeLevels.set(nodeId, level);
296
- }
297
- continue;
298
- }
299
- assigned.add(nodeId);
300
- nodeLevels.set(nodeId, level);
301
- const dependentsOfNode = dependentsMap.get(nodeId) || [];
302
- for (const dependent of dependentsOfNode) {
303
- if (!assigned.has(dependent)) {
304
- queue.push({ nodeId: dependent, level: level + 1 });
305
- }
306
- }
307
- }
308
- for (const nodeId of dependencies.keys()) {
309
- if (!nodeLevels.has(nodeId)) {
310
- nodeLevels.set(nodeId, 0);
311
- }
312
- }
313
- const maxLevel = Math.max(...nodeLevels.values(), 0);
314
- for (let i = 0;i <= maxLevel; i++) {
315
- levels.push([]);
316
- }
317
- for (const [nodeId, level] of nodeLevels.entries()) {
318
- levels[level].push(nodeId);
319
- }
320
- return levels;
321
- }
322
- findCriticalPath(levels, dependencies) {
323
- if (levels.length === 0) {
324
- return [];
325
- }
326
- const longestPath = new Map;
327
- const allNodes = [];
328
- for (const level of levels) {
329
- allNodes.push(...level);
330
- }
331
- for (const nodeId of allNodes) {
332
- const deps = dependencies.get(nodeId) || [];
333
- if (deps.length === 0) {
334
- longestPath.set(nodeId, { length: 1, path: [nodeId] });
335
- } else {
336
- let maxLength2 = 0;
337
- let maxPath = [];
338
- for (const dep of deps) {
339
- const depInfo = longestPath.get(dep);
340
- if (depInfo && depInfo.length > maxLength2) {
341
- maxLength2 = depInfo.length;
342
- maxPath = depInfo.path;
343
- }
344
- }
345
- longestPath.set(nodeId, {
346
- length: maxLength2 + 1,
347
- path: [...maxPath, nodeId]
348
- });
349
- }
350
- }
351
- let maxLength = 0;
352
- let criticalPath = [];
353
- for (const [, info] of longestPath.entries()) {
354
- if (info.length > maxLength) {
355
- maxLength = info.length;
356
- criticalPath = info.path;
357
- }
358
- }
359
- return criticalPath;
360
- }
361
- getTopologicalOrder() {
362
- const dependencies = this.buildDependenciesMap();
363
- const dependents = this.buildDependentsMap(dependencies);
364
- const inDegree = new Map;
365
- for (const nodeId of dependencies.keys()) {
366
- inDegree.set(nodeId, dependencies.get(nodeId)?.length || 0);
367
- }
368
- const queue = [];
369
- for (const [nodeId, degree] of inDegree.entries()) {
370
- if (degree === 0) {
371
- queue.push(nodeId);
372
- }
373
- }
374
- const result = [];
375
- while (queue.length > 0) {
376
- const nodeId = queue.shift();
377
- result.push(nodeId);
378
- const nodeDependents = dependents.get(nodeId) || [];
379
- for (const dependent of nodeDependents) {
380
- const currentDegree = inDegree.get(dependent) || 0;
381
- inDegree.set(dependent, currentDegree - 1);
382
- if (currentDegree - 1 === 0) {
383
- queue.push(dependent);
384
- }
385
- }
386
- }
387
- return result;
388
- }
389
- getReadyNodes(completedNodes) {
390
- const dependencies = this.buildDependenciesMap();
391
- const ready = [];
392
- for (const nodeId of dependencies.keys()) {
393
- if (completedNodes.has(nodeId)) {
394
- continue;
395
- }
396
- if (this.areDependenciesMet(nodeId, completedNodes)) {
397
- ready.push(nodeId);
398
- }
399
- }
400
- return ready;
401
- }
402
- areDependenciesMet(nodeId, completedNodes) {
403
- const analysis = this.analyze();
404
- const deps = analysis.dependencies.get(nodeId);
405
- if (!deps) {
406
- return true;
407
- }
408
- for (const dep of deps) {
409
- if (!completedNodes.has(dep)) {
410
- return false;
411
- }
412
- }
413
- return true;
414
- }
415
- isCyclic() {
416
- const dependencies = this.buildDependenciesMap();
417
- const order = this.getTopologicalOrderInternal(dependencies);
418
- return order.length !== this.workflow.nodes.length;
419
- }
420
- getTopologicalOrderInternal(dependencies) {
421
- const dependents = this.buildDependentsMap(dependencies);
422
- const inDegree = new Map;
423
- for (const nodeId of dependencies.keys()) {
424
- inDegree.set(nodeId, dependencies.get(nodeId)?.length || 0);
425
- }
426
- const queue = [];
427
- for (const [nodeId, degree] of inDegree.entries()) {
428
- if (degree === 0) {
429
- queue.push(nodeId);
430
- }
431
- }
432
- const result = [];
433
- while (queue.length > 0) {
434
- const nodeId = queue.shift();
435
- result.push(nodeId);
436
- const nodeDependents = dependents.get(nodeId) || [];
437
- for (const dependent of nodeDependents) {
438
- const currentDegree = inDegree.get(dependent) || 0;
439
- inDegree.set(dependent, currentDegree - 1);
440
- if (currentDegree - 1 === 0) {
441
- queue.push(dependent);
442
- }
443
- }
444
- }
445
- return result;
446
- }
447
- validate(options) {
448
- const errors = [];
449
- const nodeIds = new Set;
450
- for (const node of this.workflow.nodes) {
451
- if (node.id === "") {
452
- errors.push("Node ID cannot be empty");
453
- continue;
454
- }
455
- if (nodeIds.has(node.id)) {
456
- errors.push(`Duplicate node ID: ${node.id}`);
457
- }
458
- nodeIds.add(node.id);
459
- }
460
- for (const node of this.workflow.nodes) {
461
- const deps = node.depends_on || [];
462
- for (const dep of deps) {
463
- if (!nodeIds.has(dep)) {
464
- errors.push(`Node '${node.id}' depends on non-existent node '${dep}'`);
465
- }
466
- }
467
- }
468
- if (!this.allowCycles && !options?.skipCycleCheck && this.isCyclic()) {
469
- errors.push("Workflow contains a cycle");
470
- }
471
- return {
472
- valid: errors.length === 0,
473
- errors
474
- };
475
- }
476
- addNode(node) {
477
- if (!node.id || node.id.trim() === "") {
478
- throw new Error("Node ID cannot be empty");
479
- }
480
- if (this.nodeMap.has(node.id)) {
481
- throw new Error(`Node with ID '${node.id}' already exists`);
482
- }
483
- const deps = node.depends_on || [];
484
- for (const dep of deps) {
485
- if (!this.nodeMap.has(dep)) {
486
- throw new Error(`Cannot add node '${node.id}': depends on non-existent node '${dep}'`);
487
- }
488
- }
489
- const originalNodes = [...this.workflow.nodes];
490
- this.workflow.nodes.push(node);
491
- if (this.isCyclic()) {
492
- this.workflow.nodes = originalNodes;
493
- throw new Error(`Cannot add node '${node.id}': would create a cycle in the workflow`);
494
- }
495
- this.nodeMap.set(node.id, node);
496
- this.cachedAnalysis = null;
497
- this.extendedDefinition = null;
498
- }
499
- removeNode(nodeId) {
500
- if (!this.nodeMap.has(nodeId)) {
501
- throw new Error(`Node '${nodeId}' does not exist`);
502
- }
503
- const dependents = this.getDependents(nodeId);
504
- if (dependents.length > 0) {
505
- throw new Error(`Cannot remove node '${nodeId}': other nodes depend on it: ${dependents.join(", ")}`);
506
- }
507
- this.workflow.nodes = this.workflow.nodes.filter((n) => n.id !== nodeId);
508
- this.nodeMap.delete(nodeId);
509
- this.cachedAnalysis = null;
510
- this.extendedDefinition = null;
511
- }
512
- getDependents(nodeId) {
513
- const analysis = this.analyze();
514
- return analysis.dependents.get(nodeId) || [];
515
- }
516
- getDownstreamUntil(fromNodeId, untilNodeId) {
517
- const result = [];
518
- const visited = new Set;
519
- const queue = [...this.getDependents(fromNodeId)];
520
- while (queue.length > 0) {
521
- const nodeId = queue.shift();
522
- if (visited.has(nodeId))
523
- continue;
524
- visited.add(nodeId);
525
- result.push(nodeId);
526
- if (nodeId === untilNodeId) {
527
- continue;
528
- }
529
- for (const dependent of this.getDependents(nodeId)) {
530
- if (!visited.has(dependent)) {
531
- queue.push(dependent);
532
- }
533
- }
534
- }
535
- return result;
536
- }
537
- getDefinition() {
538
- return this.workflow;
539
- }
540
- getNode(nodeId) {
541
- return this.nodeMap.get(nodeId);
542
- }
543
- getNodeIds() {
544
- return Array.from(this.nodeMap.keys());
545
- }
546
- getNodeCount() {
547
- return this.nodeMap.size;
548
- }
549
- buildEdges(explicitEdges = []) {
550
- const derivedEdges = [];
551
- const explicitEdgeSet = new Set(explicitEdges.map((e) => `${e.from}->${e.to}`));
552
- for (const node of this.workflow.nodes) {
553
- const deps = node.depends_on || [];
554
- for (const dep of deps) {
555
- const edgeKey = `${dep}->${node.id}`;
556
- if (!explicitEdgeSet.has(edgeKey)) {
557
- derivedEdges.push({ from: dep, to: node.id });
558
- }
559
- }
560
- }
561
- return [...explicitEdges, ...derivedEdges];
562
- }
563
- }
564
- var init_dag_manager = () => {};
565
-
566
154
  // src/env/workflow/engine/scheduler.ts
567
155
  class Scheduler {
568
156
  dagManager;
@@ -2584,4 +2172,4 @@ var init_engine2 = __esm(() => {
2584
2172
  init_node_registry();
2585
2173
  });
2586
2174
 
2587
- export { EventBus, DAGManager, Scheduler, Executor, NodeRegistry, WorkflowEngine, exports_engine, init_engine2 as init_engine };
2175
+ export { EventBus, Scheduler, Executor, NodeRegistry, WorkflowEngine, exports_engine, init_engine2 as init_engine };