@nebulaos/core 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/README.md +206 -0
  2. package/dist/__tests__/mocks/mock-provider.d.ts +15 -0
  3. package/dist/__tests__/mocks/mock-provider.js +44 -0
  4. package/dist/agent/Agent.d.ts +96 -0
  5. package/dist/agent/Agent.js +861 -0
  6. package/dist/agent/BaseAgent.d.ts +53 -0
  7. package/dist/agent/BaseAgent.js +126 -0
  8. package/dist/agent/events/events.d.ts +14 -0
  9. package/dist/agent/events/events.js +2 -0
  10. package/dist/agent/events/events.spec.d.ts +1 -0
  11. package/dist/agent/events/events.spec.js +75 -0
  12. package/dist/agent/instruction/index.d.ts +23 -0
  13. package/dist/agent/instruction/index.js +76 -0
  14. package/dist/agent/memory/in-memory.d.ts +24 -0
  15. package/dist/agent/memory/in-memory.js +78 -0
  16. package/dist/agent/memory/index.d.ts +2 -0
  17. package/dist/agent/memory/index.js +18 -0
  18. package/dist/agent/memory/memory.d.ts +43 -0
  19. package/dist/agent/memory/memory.js +7 -0
  20. package/dist/agent/provider/file-parts.spec.d.ts +1 -0
  21. package/dist/agent/provider/file-parts.spec.js +83 -0
  22. package/dist/agent/provider/index.d.ts +130 -0
  23. package/dist/agent/provider/index.js +8 -0
  24. package/dist/agent/skills/index.d.ts +61 -0
  25. package/dist/agent/skills/index.js +9 -0
  26. package/dist/agent/tools/index.d.ts +35 -0
  27. package/dist/agent/tools/index.js +87 -0
  28. package/dist/cost/add-cost.d.ts +10 -0
  29. package/dist/cost/add-cost.js +80 -0
  30. package/dist/cost/add-cost.spec.d.ts +1 -0
  31. package/dist/cost/add-cost.spec.js +36 -0
  32. package/dist/cost/index.d.ts +1 -0
  33. package/dist/cost/index.js +17 -0
  34. package/dist/domain-events/index.d.ts +16 -0
  35. package/dist/domain-events/index.js +38 -0
  36. package/dist/eval/index.d.ts +19 -0
  37. package/dist/eval/index.js +24 -0
  38. package/dist/events/base.d.ts +5 -0
  39. package/dist/events/base.js +2 -0
  40. package/dist/events/schemas.d.ts +3463 -0
  41. package/dist/events/schemas.js +244 -0
  42. package/dist/execution-context/index.d.ts +21 -0
  43. package/dist/execution-context/index.js +17 -0
  44. package/dist/index.cjs +2958 -0
  45. package/dist/index.cjs.map +1 -0
  46. package/dist/index.d.cts +3425 -0
  47. package/dist/index.d.ts +22 -0
  48. package/dist/index.js +53 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/lgpd/index.d.ts +7 -0
  51. package/dist/lgpd/index.js +21 -0
  52. package/dist/logger/agent-logger.d.ts +16 -0
  53. package/dist/logger/agent-logger.js +110 -0
  54. package/dist/logger/formatters.d.ts +32 -0
  55. package/dist/logger/formatters.js +146 -0
  56. package/dist/logger/index.d.ts +30 -0
  57. package/dist/logger/index.js +88 -0
  58. package/dist/logger/styles.d.ts +46 -0
  59. package/dist/logger/styles.js +53 -0
  60. package/dist/logger/workflow-logger.d.ts +16 -0
  61. package/dist/logger/workflow-logger.js +79 -0
  62. package/dist/multi-agent/agent-as-tool/AgentAsTool.d.ts +16 -0
  63. package/dist/multi-agent/agent-as-tool/AgentAsTool.js +54 -0
  64. package/dist/multi-agent/agent-as-tool/AgentAsTool.spec.d.ts +1 -0
  65. package/dist/multi-agent/agent-as-tool/AgentAsTool.spec.js +76 -0
  66. package/dist/multi-agent/committee-team/CommitteeTeam.d.ts +16 -0
  67. package/dist/multi-agent/committee-team/CommitteeTeam.js +150 -0
  68. package/dist/multi-agent/committee-team/CommitteeTeam.spec.d.ts +1 -0
  69. package/dist/multi-agent/committee-team/CommitteeTeam.spec.js +43 -0
  70. package/dist/multi-agent/handoff-team/HandoffTeam.d.ts +16 -0
  71. package/dist/multi-agent/handoff-team/HandoffTeam.js +185 -0
  72. package/dist/multi-agent/handoff-team/HandoffTeam.spec.d.ts +1 -0
  73. package/dist/multi-agent/handoff-team/HandoffTeam.spec.js +105 -0
  74. package/dist/multi-agent/hierarchical-team/HierarchicalTeam.d.ts +18 -0
  75. package/dist/multi-agent/hierarchical-team/HierarchicalTeam.js +164 -0
  76. package/dist/multi-agent/hierarchical-team/HierarchicalTeam.spec.d.ts +1 -0
  77. package/dist/multi-agent/hierarchical-team/HierarchicalTeam.spec.js +53 -0
  78. package/dist/multi-agent/index.d.ts +10 -0
  79. package/dist/multi-agent/index.js +26 -0
  80. package/dist/multi-agent/pipeline-team/PipelineTeam.d.ts +13 -0
  81. package/dist/multi-agent/pipeline-team/PipelineTeam.js +104 -0
  82. package/dist/multi-agent/pipeline-team/PipelineTeam.spec.d.ts +1 -0
  83. package/dist/multi-agent/pipeline-team/PipelineTeam.spec.js +54 -0
  84. package/dist/multi-agent/router-team/RouterTeam.d.ts +15 -0
  85. package/dist/multi-agent/router-team/RouterTeam.js +153 -0
  86. package/dist/multi-agent/router-team/RouterTeam.spec.d.ts +1 -0
  87. package/dist/multi-agent/router-team/RouterTeam.spec.js +69 -0
  88. package/dist/multi-agent/types/index.d.ts +349 -0
  89. package/dist/multi-agent/types/index.js +79 -0
  90. package/dist/multi-agent/utils/guardrails.d.ts +6 -0
  91. package/dist/multi-agent/utils/guardrails.js +34 -0
  92. package/dist/multi-agent/utils/memory.d.ts +8 -0
  93. package/dist/multi-agent/utils/memory.js +40 -0
  94. package/dist/multi-agent/utils/prompts.d.ts +4 -0
  95. package/dist/multi-agent/utils/prompts.js +25 -0
  96. package/dist/tracing/index.d.ts +89 -0
  97. package/dist/tracing/index.js +188 -0
  98. package/dist/tsup.config.d.ts +2 -0
  99. package/dist/tsup.config.js +11 -0
  100. package/dist/utils/schema-to-zod.d.ts +7 -0
  101. package/dist/utils/schema-to-zod.js +36 -0
  102. package/dist/workflow/Workflow.d.ts +106 -0
  103. package/dist/workflow/Workflow.js +204 -0
  104. package/dist/workflow/adapters.d.ts +61 -0
  105. package/dist/workflow/adapters.js +29 -0
  106. package/dist/workflow/definition/DefinitionBuilder.d.ts +9 -0
  107. package/dist/workflow/definition/DefinitionBuilder.js +91 -0
  108. package/dist/workflow/definition/DefinitionBuilder.spec.d.ts +1 -0
  109. package/dist/workflow/definition/DefinitionBuilder.spec.js +66 -0
  110. package/dist/workflow/definition/DefinitionHasher.d.ts +8 -0
  111. package/dist/workflow/definition/DefinitionHasher.js +11 -0
  112. package/dist/workflow/definition/DefinitionHasher.spec.d.ts +1 -0
  113. package/dist/workflow/definition/DefinitionHasher.spec.js +28 -0
  114. package/dist/workflow/definition/types.d.ts +27 -0
  115. package/dist/workflow/definition/types.js +2 -0
  116. package/dist/workflow/events.d.ts +9 -0
  117. package/dist/workflow/events.js +2 -0
  118. package/dist/workflow/execution/AgentNodeIntegration.spec.d.ts +1 -0
  119. package/dist/workflow/execution/AgentNodeIntegration.spec.js +50 -0
  120. package/dist/workflow/execution/NodeExecutor.d.ts +9 -0
  121. package/dist/workflow/execution/NodeExecutor.js +43 -0
  122. package/dist/workflow/execution/NodeExecutor.spec.d.ts +1 -0
  123. package/dist/workflow/execution/NodeExecutor.spec.js +45 -0
  124. package/dist/workflow/execution/WorkflowEventBus.d.ts +14 -0
  125. package/dist/workflow/execution/WorkflowEventBus.js +42 -0
  126. package/dist/workflow/execution/WorkflowEventBus.spec.d.ts +1 -0
  127. package/dist/workflow/execution/WorkflowEventBus.spec.js +78 -0
  128. package/dist/workflow/execution/WorkflowRunner.d.ts +26 -0
  129. package/dist/workflow/execution/WorkflowRunner.js +212 -0
  130. package/dist/workflow/execution/WorkflowRunner.spec.d.ts +1 -0
  131. package/dist/workflow/execution/WorkflowRunner.spec.js +92 -0
  132. package/dist/workflow/execution/WorkflowTelemetry.d.ts +13 -0
  133. package/dist/workflow/execution/WorkflowTelemetry.js +43 -0
  134. package/dist/workflow/execution/WorkflowTelemetry.spec.d.ts +1 -0
  135. package/dist/workflow/execution/WorkflowTelemetry.spec.js +31 -0
  136. package/dist/workflow/graph/NodeNameRegistry.d.ts +20 -0
  137. package/dist/workflow/graph/NodeNameRegistry.js +21 -0
  138. package/dist/workflow/graph/NodeNameRegistry.spec.d.ts +1 -0
  139. package/dist/workflow/graph/NodeNameRegistry.spec.js +18 -0
  140. package/dist/workflow/graph/WorkflowGraph.d.ts +14 -0
  141. package/dist/workflow/graph/WorkflowGraph.js +23 -0
  142. package/dist/workflow/graph/nodes.d.ts +26 -0
  143. package/dist/workflow/graph/nodes.js +2 -0
  144. package/dist/workflow/queue/WorkflowQueueService.d.ts +22 -0
  145. package/dist/workflow/queue/WorkflowQueueService.js +47 -0
  146. package/dist/workflow/state/WorkflowStateService.d.ts +7 -0
  147. package/dist/workflow/state/WorkflowStateService.js +20 -0
  148. package/dist/workflow/types.d.ts +16 -0
  149. package/dist/workflow/types.js +2 -0
  150. package/package.json +56 -0
@@ -0,0 +1,212 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkflowRunner = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ const promises_1 = require("node:timers/promises");
6
+ const adapters_js_1 = require("../adapters.js");
7
+ const index_js_1 = require("../../execution-context/index.js");
8
+ class WorkflowRunner {
9
+ config;
10
+ events;
11
+ telemetry;
12
+ state;
13
+ nodeExecutor;
14
+ constructor(config, events, telemetry, state, nodeExecutor) {
15
+ this.config = config;
16
+ this.events = events;
17
+ this.telemetry = telemetry;
18
+ this.state = state;
19
+ this.nodeExecutor = nodeExecutor;
20
+ }
21
+ async run(params) {
22
+ const executionId = params.options?.executionId ?? (0, node_crypto_1.randomUUID)();
23
+ const startTime = Date.now();
24
+ const timeoutMs = this.config.timeoutMs;
25
+ const maxSteps = this.config.maxSteps;
26
+ const stateMap = {};
27
+ let currentInput = params.input;
28
+ const exec = async () => {
29
+ return index_js_1.ExecutionContext.run({
30
+ executionId,
31
+ rootExecutionId: executionId,
32
+ }, async () => this.telemetry.inWorkflowSpan({
33
+ workflowId: params.workflowId,
34
+ executionId,
35
+ workflowName: params.workflowNameForTelemetry,
36
+ workflowInput: params.input,
37
+ }, async () => {
38
+ this.events.emit("workflow:run:start", {
39
+ executionId,
40
+ data: { workflowId: params.workflowId, definitionVersion: params.definition.version, input: params.input },
41
+ });
42
+ await this.state.save(executionId, {
43
+ workflowId: params.workflowId,
44
+ executionId,
45
+ definitionVersion: params.definition.version,
46
+ status: "running",
47
+ currentNodeId: undefined,
48
+ nodeStates: {},
49
+ input: params.input,
50
+ startedAt: new Date(),
51
+ updatedAt: new Date(),
52
+ });
53
+ try {
54
+ let executed = 0;
55
+ for (const node of params.nodes) {
56
+ executed++;
57
+ if (maxSteps && executed > maxSteps) {
58
+ const output = currentInput;
59
+ this.events.emit("workflow:run:end", {
60
+ executionId,
61
+ data: {
62
+ workflowId: params.workflowId,
63
+ definitionVersion: params.definition.version,
64
+ status: "truncated",
65
+ output,
66
+ durationMs: Date.now() - startTime,
67
+ },
68
+ });
69
+ return output;
70
+ }
71
+ currentInput = await this.executeNodeWithRetry({
72
+ workflowId: params.workflowId,
73
+ definitionVersion: params.definition.version,
74
+ executionId,
75
+ node,
76
+ currentInput,
77
+ state: stateMap,
78
+ });
79
+ stateMap[node.id] = currentInput;
80
+ await this.state.save(executionId, {
81
+ workflowId: params.workflowId,
82
+ executionId,
83
+ definitionVersion: params.definition.version,
84
+ status: "running",
85
+ currentNodeId: node.id,
86
+ nodeStates: Object.fromEntries(Object.entries(stateMap).map(([nodeId, value]) => [nodeId, { status: "success", output: value }])),
87
+ input: params.input,
88
+ startedAt: new Date(startTime),
89
+ updatedAt: new Date(),
90
+ });
91
+ }
92
+ const output = currentInput;
93
+ this.events.emit("workflow:run:end", {
94
+ executionId,
95
+ data: {
96
+ workflowId: params.workflowId,
97
+ definitionVersion: params.definition.version,
98
+ status: "success",
99
+ output,
100
+ durationMs: Date.now() - startTime,
101
+ },
102
+ });
103
+ await this.state.save(executionId, {
104
+ workflowId: params.workflowId,
105
+ executionId,
106
+ definitionVersion: params.definition.version,
107
+ status: "completed",
108
+ currentNodeId: params.nodes[params.nodes.length - 1]?.id,
109
+ nodeStates: {},
110
+ input: params.input,
111
+ output,
112
+ startedAt: new Date(startTime),
113
+ updatedAt: new Date(),
114
+ completedAt: new Date(),
115
+ });
116
+ return output;
117
+ }
118
+ catch (error) {
119
+ const err = error instanceof Error ? error : new Error(String(error));
120
+ this.events.emit("workflow:run:error", {
121
+ executionId,
122
+ data: {
123
+ workflowId: params.workflowId,
124
+ definitionVersion: params.definition.version,
125
+ error: { message: err.message, stack: err.stack, name: err.name },
126
+ durationMs: Date.now() - startTime,
127
+ },
128
+ });
129
+ throw error;
130
+ }
131
+ }));
132
+ };
133
+ if (!timeoutMs)
134
+ return exec();
135
+ return Promise.race([
136
+ exec(),
137
+ (0, promises_1.setTimeout)(timeoutMs).then(() => {
138
+ throw new Error(`Workflow timed out after ${timeoutMs}ms`);
139
+ }),
140
+ ]);
141
+ }
142
+ async executeNodeWithRetry(params) {
143
+ const policy = this.config.retryPolicy;
144
+ const maxAttempts = policy?.maxAttempts ?? 1;
145
+ let lastError;
146
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
147
+ const nodeStartTime = Date.now();
148
+ this.events.emit("workflow:node:start", {
149
+ executionId: params.executionId,
150
+ data: {
151
+ workflowId: params.workflowId,
152
+ nodeId: params.node.id,
153
+ nodeType: params.node.type,
154
+ attempt,
155
+ input: params.currentInput,
156
+ },
157
+ });
158
+ try {
159
+ const result = await this.telemetry.inNodeSpan({
160
+ executionId: params.executionId,
161
+ nodeId: params.node.id,
162
+ data: {
163
+ workflowId: params.workflowId,
164
+ executionId: params.executionId,
165
+ nodeId: params.node.id,
166
+ nodeType: params.node.type,
167
+ definitionVersion: params.definitionVersion,
168
+ attempt,
169
+ input: params.currentInput, // Use full input, not truncated
170
+ },
171
+ }, async () => this.nodeExecutor.executeOnce({ node: params.node, currentInput: params.currentInput, state: params.state, executionId: params.executionId }));
172
+ this.events.emit("workflow:node:end", {
173
+ executionId: params.executionId,
174
+ data: {
175
+ workflowId: params.workflowId,
176
+ nodeId: params.node.id,
177
+ nodeType: params.node.type,
178
+ attempt,
179
+ status: "success",
180
+ output: result,
181
+ durationMs: Date.now() - nodeStartTime,
182
+ },
183
+ });
184
+ return result;
185
+ }
186
+ catch (err) {
187
+ lastError = err instanceof Error ? err : new Error(String(err));
188
+ this.events.emit("workflow:node:end", {
189
+ executionId: params.executionId,
190
+ data: {
191
+ workflowId: params.workflowId,
192
+ nodeId: params.node.id,
193
+ nodeType: params.node.type,
194
+ attempt,
195
+ status: "error",
196
+ output: undefined,
197
+ durationMs: Date.now() - nodeStartTime,
198
+ error: { message: lastError.message, stack: lastError.stack, name: lastError.name },
199
+ },
200
+ });
201
+ if (!policy)
202
+ throw lastError;
203
+ if (!(0, adapters_js_1.isRetryableError)(lastError, policy) || attempt >= maxAttempts)
204
+ throw lastError;
205
+ const delay = (0, adapters_js_1.calculateRetryDelay)(policy, attempt);
206
+ await (0, promises_1.setTimeout)(delay);
207
+ }
208
+ }
209
+ throw lastError;
210
+ }
211
+ }
212
+ exports.WorkflowRunner = WorkflowRunner;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_events_1 = require("node:events");
4
+ const Workflow_1 = require("../Workflow");
5
+ const WorkflowEventBus_1 = require("./WorkflowEventBus");
6
+ const WorkflowRunner_1 = require("./WorkflowRunner");
7
+ const WorkflowTelemetry_1 = require("./WorkflowTelemetry");
8
+ const WorkflowStateService_1 = require("../state/WorkflowStateService");
9
+ const NodeExecutor_1 = require("./NodeExecutor");
10
+ describe("WorkflowRunner", () => {
11
+ it("should emit run/node events in expected order", async () => {
12
+ const wf = new Workflow_1.Workflow({ id: "wf" })
13
+ .step("a", async ({ input }) => `${input}-a`)
14
+ .step("b", async ({ input }) => `${input}-b`);
15
+ const emitter = new node_events_1.EventEmitter();
16
+ const bus = new WorkflowEventBus_1.WorkflowEventBus(emitter);
17
+ const types = [];
18
+ emitter.on("workflow:run:start", (e) => types.push(e.type));
19
+ emitter.on("workflow:node:start", (e) => types.push(e.type));
20
+ emitter.on("workflow:node:end", (e) => types.push(e.type));
21
+ emitter.on("workflow:run:end", (e) => types.push(e.type));
22
+ const runner = new WorkflowRunner_1.WorkflowRunner({ id: "wf" }, bus, new WorkflowTelemetry_1.WorkflowTelemetry(), new WorkflowStateService_1.WorkflowStateService(undefined), new NodeExecutor_1.NodeExecutor());
23
+ const out = await runner.run({
24
+ workflowId: "wf",
25
+ workflowNameForTelemetry: "workflow:wf",
26
+ definition: wf.describe(),
27
+ nodes: wf.__internalNodes(),
28
+ input: "x",
29
+ options: { executionId: "exec-1" },
30
+ });
31
+ expect(out).toBe("x-a-b");
32
+ expect(types[0]).toBe("workflow:run:start");
33
+ expect(types[types.length - 1]).toBe("workflow:run:end");
34
+ });
35
+ it("should truncate when maxSteps is exceeded", async () => {
36
+ const wf = new Workflow_1.Workflow({ id: "wf", maxSteps: 1 })
37
+ .step("a", async ({ input }) => `${input}-a`)
38
+ .step("b", async ({ input }) => `${input}-b`);
39
+ const events = [];
40
+ wf.on("workflow:run:end", (e) => events.push(e));
41
+ const out = await wf.run("x", { executionId: "exec-2" });
42
+ expect(out).toBe("x-a"); // only first node executed
43
+ expect(events[0]?.data?.status).toBe("truncated");
44
+ });
45
+ it("should retry a failing node and succeed", async () => {
46
+ let attempts = 0;
47
+ const wf = new Workflow_1.Workflow({
48
+ id: "wf",
49
+ retryPolicy: { maxAttempts: 3, backoff: "fixed", initialDelay: 1 },
50
+ }).step("flaky", async () => {
51
+ attempts++;
52
+ if (attempts < 3)
53
+ throw new Error("fail");
54
+ return "ok";
55
+ });
56
+ const nodeEnds = [];
57
+ wf.on("workflow:node:end", (e) => nodeEnds.push(e));
58
+ const out = await wf.run("x", { executionId: "exec-3" });
59
+ expect(out).toBe("ok");
60
+ expect(attempts).toBe(3);
61
+ expect(nodeEnds.filter((e) => e.data.status === "error").length).toBe(2);
62
+ expect(nodeEnds.filter((e) => e.data.status === "success").length).toBe(1);
63
+ });
64
+ it("should error on unknown branch key", async () => {
65
+ const wf = new Workflow_1.Workflow({ id: "wf" }).branch("route", async () => "missing", {
66
+ ok: (w) => w.step("ok", async () => "ok"),
67
+ });
68
+ await expect(wf.run("x", { executionId: "exec-4" })).rejects.toThrow("Unknown branch key");
69
+ });
70
+ it("should throw on timeout", async () => {
71
+ const wf = new Workflow_1.Workflow({ id: "wf", timeoutMs: 30 }).step("slow", async () => {
72
+ await new Promise((r) => setTimeout(r, 200));
73
+ return "done";
74
+ });
75
+ await expect(wf.run("x", { executionId: "exec-5" })).rejects.toThrow("timed out");
76
+ });
77
+ it("should propagate error when a parallel subflow fails", async () => {
78
+ const wf = new Workflow_1.Workflow({ id: "wf" })
79
+ .step("before", async ({ input }) => input)
80
+ .parallel("fanout", [
81
+ (p) => p.step("ok", async () => "ok"),
82
+ (p) => p.step("boom", async () => { throw new Error("boom"); }),
83
+ ])
84
+ .step("after", async ({ input }) => input);
85
+ const runErrors = [];
86
+ wf.on("workflow:run:error", (e) => runErrors.push(e));
87
+ await expect(wf.run("x", { executionId: "exec-parallel-fail" })).rejects.toThrow("boom");
88
+ expect(runErrors.length).toBeGreaterThanOrEqual(1);
89
+ expect(runErrors[0].executionId).toBe("exec-parallel-fail");
90
+ expect(runErrors[0].data.error.message).toContain("boom");
91
+ });
92
+ });
@@ -0,0 +1,13 @@
1
+ export declare class WorkflowTelemetry {
2
+ inWorkflowSpan<T>(input: {
3
+ workflowId: string;
4
+ executionId: string;
5
+ workflowName: string;
6
+ workflowInput: unknown;
7
+ }, fn: () => Promise<T>): Promise<T>;
8
+ inNodeSpan<T>(input: {
9
+ executionId: string;
10
+ nodeId: string;
11
+ data: Record<string, unknown>;
12
+ }, fn: () => Promise<T>): Promise<T>;
13
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkflowTelemetry = void 0;
4
+ const index_js_1 = require("../../tracing/index.js");
5
+ class WorkflowTelemetry {
6
+ async inWorkflowSpan(input, fn) {
7
+ return index_js_1.Tracing.withSpan({
8
+ kind: "workflow",
9
+ name: input.workflowName,
10
+ executionId: input.executionId,
11
+ data: { workflowId: input.workflowId, input: input.workflowInput },
12
+ }, async (span) => {
13
+ const result = await fn();
14
+ if (!span.isEnded)
15
+ await span.end({ status: "success" });
16
+ return result;
17
+ });
18
+ }
19
+ async inNodeSpan(input, fn) {
20
+ return index_js_1.Tracing.withSpan({
21
+ kind: "workflow.node",
22
+ name: `workflow:node:${input.nodeId}`,
23
+ executionId: input.executionId,
24
+ data: {
25
+ workflowId: input.data.workflowId,
26
+ nodeId: input.nodeId,
27
+ nodeType: input.data.nodeType,
28
+ input: input.data.input,
29
+ },
30
+ }, async (span) => {
31
+ try {
32
+ const result = await fn();
33
+ await span.end({ status: "success", data: { output: result } });
34
+ return result;
35
+ }
36
+ catch (e) {
37
+ await span.end({ status: "error" });
38
+ throw e;
39
+ }
40
+ });
41
+ }
42
+ }
43
+ exports.WorkflowTelemetry = WorkflowTelemetry;
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tracing_1 = require("../../tracing");
4
+ const WorkflowTelemetry_1 = require("./WorkflowTelemetry");
5
+ class CapturingExporter {
6
+ events = [];
7
+ async exportBatch(events) {
8
+ this.events.push(...events);
9
+ }
10
+ }
11
+ describe("WorkflowTelemetry", () => {
12
+ it("should emit workflow and node spans via Tracing exporter", async () => {
13
+ const exporter = new CapturingExporter();
14
+ tracing_1.Tracing.setExporter(exporter);
15
+ const telemetry = new WorkflowTelemetry_1.WorkflowTelemetry();
16
+ const out = await telemetry.inWorkflowSpan({ workflowId: "wf", executionId: "exec-1", workflowName: "workflow:wf", workflowInput: { x: 1 } }, async () => {
17
+ return telemetry.inNodeSpan({ executionId: "exec-1", nodeId: "n1", data: { workflowId: "wf", nodeId: "n1", nodeType: "step" } }, async () => "ok");
18
+ });
19
+ expect(out).toBe("ok");
20
+ const types = exporter.events.map((e) => e.type);
21
+ expect(types).toEqual(expect.arrayContaining(["telemetry:span:start", "telemetry:span:end"]));
22
+ // Should have at least 2 spans (workflow root + node)
23
+ const starts = exporter.events.filter((e) => e.type === "telemetry:span:start");
24
+ expect(starts.length).toBeGreaterThanOrEqual(2);
25
+ const workflowStart = starts.find((e) => e.span?.kind === "workflow");
26
+ expect(workflowStart).toBeDefined();
27
+ const nodeStart = starts.find((e) => (e.span?.kind === "workflow.node" || e.span?.kind === "custom") &&
28
+ e.span?.name?.includes("workflow:node:n1"));
29
+ expect(nodeStart).toBeDefined();
30
+ });
31
+ });
@@ -0,0 +1,20 @@
1
+ export interface NodeIdAllocator {
2
+ allocate(name: string): {
3
+ id: string;
4
+ displayName: string;
5
+ };
6
+ }
7
+ /**
8
+ * Shared registry that ensures node IDs are stable and deduped across the entire workflow tree.
9
+ *
10
+ * Rule:
11
+ * - First occurrence: "name"
12
+ * - Subsequent occurrences: "name-2", "name-3", ...
13
+ */
14
+ export declare class SharedNodeNameRegistry implements NodeIdAllocator {
15
+ private readonly counters;
16
+ allocate(name: string): {
17
+ id: string;
18
+ displayName: string;
19
+ };
20
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SharedNodeNameRegistry = void 0;
4
+ /**
5
+ * Shared registry that ensures node IDs are stable and deduped across the entire workflow tree.
6
+ *
7
+ * Rule:
8
+ * - First occurrence: "name"
9
+ * - Subsequent occurrences: "name-2", "name-3", ...
10
+ */
11
+ class SharedNodeNameRegistry {
12
+ counters = new Map();
13
+ allocate(name) {
14
+ const current = this.counters.get(name) ?? 0;
15
+ const next = current + 1;
16
+ this.counters.set(name, next);
17
+ const id = next === 1 ? name : `${name}-${next}`;
18
+ return { id, displayName: name };
19
+ }
20
+ }
21
+ exports.SharedNodeNameRegistry = SharedNodeNameRegistry;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const NodeNameRegistry_1 = require("./NodeNameRegistry");
4
+ describe("SharedNodeNameRegistry", () => {
5
+ it("should allocate stable ids and dedupe with -2 suffix", () => {
6
+ const reg = new NodeNameRegistry_1.SharedNodeNameRegistry();
7
+ expect(reg.allocate("triage")).toEqual({ id: "triage", displayName: "triage" });
8
+ expect(reg.allocate("triage")).toEqual({ id: "triage-2", displayName: "triage" });
9
+ expect(reg.allocate("triage")).toEqual({ id: "triage-3", displayName: "triage" });
10
+ });
11
+ it("should keep independent counters per name", () => {
12
+ const reg = new NodeNameRegistry_1.SharedNodeNameRegistry();
13
+ expect(reg.allocate("a").id).toBe("a");
14
+ expect(reg.allocate("b").id).toBe("b");
15
+ expect(reg.allocate("a").id).toBe("a-2");
16
+ expect(reg.allocate("b").id).toBe("b-2");
17
+ });
18
+ });
@@ -0,0 +1,14 @@
1
+ import type { SharedNodeNameRegistry } from "./NodeNameRegistry.js";
2
+ import type { InternalNode } from "./nodes.js";
3
+ export declare class WorkflowGraph {
4
+ private readonly registry;
5
+ private readonly nodes;
6
+ constructor(registry: SharedNodeNameRegistry);
7
+ allocateId(name: string): {
8
+ id: string;
9
+ displayName: string;
10
+ };
11
+ add(node: InternalNode): void;
12
+ list(): readonly InternalNode[];
13
+ getRegistry(): SharedNodeNameRegistry;
14
+ }
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkflowGraph = void 0;
4
+ class WorkflowGraph {
5
+ registry;
6
+ nodes = [];
7
+ constructor(registry) {
8
+ this.registry = registry;
9
+ }
10
+ allocateId(name) {
11
+ return this.registry.allocate(name);
12
+ }
13
+ add(node) {
14
+ this.nodes.push(node);
15
+ }
16
+ list() {
17
+ return this.nodes;
18
+ }
19
+ getRegistry() {
20
+ return this.registry;
21
+ }
22
+ }
23
+ exports.WorkflowGraph = WorkflowGraph;
@@ -0,0 +1,26 @@
1
+ import type { Agent } from "../../agent/Agent.js";
2
+ import type { Workflow } from "../Workflow.js";
3
+ import type { WorkflowAgentNodeOptions, WorkflowNodeHandler } from "../types.js";
4
+ export type InternalNode = {
5
+ id: string;
6
+ displayName: string;
7
+ type: "start" | "step" | "finish";
8
+ handler: WorkflowNodeHandler<any, any>;
9
+ } | {
10
+ id: string;
11
+ displayName: string;
12
+ type: "agent";
13
+ agent: Agent;
14
+ toInput?: WorkflowAgentNodeOptions["toInput"];
15
+ } | {
16
+ id: string;
17
+ displayName: string;
18
+ type: "branch";
19
+ selector: WorkflowNodeHandler<any, string>;
20
+ branches: Record<string, Workflow<any, any>>;
21
+ } | {
22
+ id: string;
23
+ displayName: string;
24
+ type: "parallel";
25
+ workflows: Workflow<any, any>[];
26
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,22 @@
1
+ import type { IWorkflowQueue } from "../adapters.js";
2
+ import type { InternalNode } from "../graph/nodes.js";
3
+ import type { WorkflowDefinition } from "../definition/types.js";
4
+ import { WorkflowStateService } from "../state/WorkflowStateService.js";
5
+ export declare class WorkflowQueueService {
6
+ private readonly queue;
7
+ private readonly state;
8
+ constructor(queue: IWorkflowQueue | undefined, state: WorkflowStateService);
9
+ enqueue(input: {
10
+ workflowId: string;
11
+ definition: WorkflowDefinition;
12
+ nodes: readonly InternalNode[];
13
+ rawInput: unknown;
14
+ }): Promise<{
15
+ executionId: string;
16
+ }>;
17
+ getStatus(executionId: string): Promise<{
18
+ status: any;
19
+ currentStep?: string;
20
+ progress?: number;
21
+ }>;
22
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkflowQueueService = void 0;
4
+ const node_crypto_1 = require("node:crypto");
5
+ class WorkflowQueueService {
6
+ queue;
7
+ state;
8
+ constructor(queue, state) {
9
+ this.queue = queue;
10
+ this.state = state;
11
+ }
12
+ async enqueue(input) {
13
+ if (!this.queue)
14
+ throw new Error("Queue adapter not configured");
15
+ const executionId = (0, node_crypto_1.randomUUID)();
16
+ await this.state.save(executionId, {
17
+ workflowId: input.workflowId,
18
+ executionId,
19
+ definitionVersion: input.definition.version,
20
+ status: "pending",
21
+ currentNodeId: undefined,
22
+ nodeStates: {},
23
+ input: input.rawInput,
24
+ startedAt: new Date(),
25
+ updatedAt: new Date(),
26
+ });
27
+ const first = input.nodes[0];
28
+ if (first) {
29
+ await this.queue.enqueue({
30
+ executionId,
31
+ workflowId: input.workflowId,
32
+ nodeId: first.id,
33
+ nodeName: first.displayName,
34
+ input: input.rawInput,
35
+ attempt: 1,
36
+ createdAt: new Date(),
37
+ });
38
+ }
39
+ return { executionId };
40
+ }
41
+ async getStatus(executionId) {
42
+ if (!this.queue?.getStatus)
43
+ throw new Error("Queue adapter does not implement getStatus()");
44
+ return this.queue.getStatus(executionId);
45
+ }
46
+ }
47
+ exports.WorkflowQueueService = WorkflowQueueService;
@@ -0,0 +1,7 @@
1
+ import type { WorkflowState, IWorkflowStateStore } from "../adapters.js";
2
+ export declare class WorkflowStateService {
3
+ private readonly store;
4
+ constructor(store: IWorkflowStateStore | undefined);
5
+ save(executionId: string, state: WorkflowState): Promise<void>;
6
+ load(executionId: string): Promise<WorkflowState | null>;
7
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WorkflowStateService = void 0;
4
+ class WorkflowStateService {
5
+ store;
6
+ constructor(store) {
7
+ this.store = store;
8
+ }
9
+ async save(executionId, state) {
10
+ if (!this.store)
11
+ return;
12
+ await this.store.save(executionId, state);
13
+ }
14
+ async load(executionId) {
15
+ if (!this.store)
16
+ return null;
17
+ return this.store.load(executionId);
18
+ }
19
+ }
20
+ exports.WorkflowStateService = WorkflowStateService;
@@ -0,0 +1,16 @@
1
+ export type WorkflowNodeContext<TInput = any> = {
2
+ input: TInput;
3
+ state: Record<string, any>;
4
+ };
5
+ export type WorkflowNodeHandler<TInput, TOutput> = (ctx: WorkflowNodeContext<TInput>) => Promise<TOutput>;
6
+ export type WorkflowRunStatus = "success" | "error" | "truncated";
7
+ export type WorkflowRunOptions = {
8
+ executionId?: string;
9
+ };
10
+ export type WorkflowAgentNodeOptions = {
11
+ /**
12
+ * Maps the current workflow input into a user message for the agent.
13
+ * If not provided, strings are passed as-is and non-strings are JSON.stringified.
14
+ */
15
+ toInput?: (input: unknown, state: Record<string, any>) => string;
16
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });