@codemation/core 0.0.19 → 0.2.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 (80) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/EngineRuntimeRegistration.types-0sgV2XL2.d.ts +42 -0
  3. package/dist/EngineWorkflowRunnerService-Dx7bJsJR.d.cts +73 -0
  4. package/dist/InMemoryRunDataFactory-qIYQEar7.d.cts +94 -0
  5. package/dist/{InMemoryLiveWorkflowRepository-DxoualoC.d.ts → RunIntentService-BCvGdOSY.d.ts} +438 -9
  6. package/dist/{RunIntentService-C1nu_YwM.js → RunIntentService-BFA48UpH.js} +252 -67
  7. package/dist/RunIntentService-BFA48UpH.js.map +1 -0
  8. package/dist/{InMemoryLiveWorkflowRepository-orY1VsWG.d.cts → RunIntentService-CV8izV8t.d.cts} +214 -7
  9. package/dist/{RunIntentService-ZkjpY7MS.cjs → RunIntentService-DcxXf_AM.cjs} +262 -65
  10. package/dist/RunIntentService-DcxXf_AM.cjs.map +1 -0
  11. package/dist/bootstrap/index.cjs +14 -1135
  12. package/dist/bootstrap/index.d.cts +7 -60
  13. package/dist/bootstrap/index.d.ts +4 -40
  14. package/dist/bootstrap/index.js +3 -1122
  15. package/dist/bootstrap-D67Sf2BF.js +1136 -0
  16. package/dist/bootstrap-D67Sf2BF.js.map +1 -0
  17. package/dist/bootstrap-DoQHAEQJ.cjs +1203 -0
  18. package/dist/bootstrap-DoQHAEQJ.cjs.map +1 -0
  19. package/dist/{index-BIewO9-9.d.ts → index-BHmrZIHp.d.ts} +32 -260
  20. package/dist/index.cjs +98 -223
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +196 -6
  23. package/dist/index.d.ts +3 -3
  24. package/dist/index.js +92 -218
  25. package/dist/index.js.map +1 -1
  26. package/dist/testing.cjs +329 -3
  27. package/dist/testing.cjs.map +1 -1
  28. package/dist/testing.d.cts +181 -4
  29. package/dist/testing.d.ts +181 -3
  30. package/dist/testing.js +319 -2
  31. package/dist/testing.js.map +1 -1
  32. package/dist/workflowActivationPolicy-B8HzTk3o.js +201 -0
  33. package/dist/workflowActivationPolicy-B8HzTk3o.js.map +1 -0
  34. package/dist/workflowActivationPolicy-BzyzXLa_.cjs +231 -0
  35. package/dist/workflowActivationPolicy-BzyzXLa_.cjs.map +1 -0
  36. package/package.json +1 -1
  37. package/src/ai/AgentConnectionNodeCollector.ts +99 -0
  38. package/src/ai/AgentToolFactory.ts +38 -2
  39. package/src/ai/AiHost.ts +1 -1
  40. package/src/browser.ts +11 -0
  41. package/src/contracts/executionPersistenceContracts.ts +186 -0
  42. package/src/contracts/index.ts +1 -0
  43. package/src/contracts/runFinishedAtFactory.ts +5 -2
  44. package/src/contracts/runTypes.ts +10 -0
  45. package/src/contracts/runtimeTypes.ts +6 -2
  46. package/src/contracts/workflowTypes.ts +3 -2
  47. package/src/events/EventPublishingWorkflowExecutionRepository.ts +5 -0
  48. package/src/execution/ActivationEnqueueService.ts +8 -8
  49. package/src/execution/PersistedRunStateTerminalBuilder.ts +3 -0
  50. package/src/index.ts +6 -0
  51. package/src/orchestration/NodeExecutionRequestHandlerService.ts +11 -6
  52. package/src/orchestration/RunContinuationService.ts +94 -24
  53. package/src/runStorage/InMemoryWorkflowExecutionRepository.ts +14 -1
  54. package/src/scheduler/DefaultDrivingScheduler.ts +21 -11
  55. package/src/scheduler/InlineDrivingScheduler.ts +17 -21
  56. package/src/testing/CapturingScheduler.ts +15 -0
  57. package/src/testing/EngineTestKitRunIdFactory.ts +24 -0
  58. package/src/testing/InMemoryTriggerSetupStateRepository.ts +21 -0
  59. package/src/testing/PrefixedSequentialIdGenerator.ts +17 -0
  60. package/src/testing/RegistrarEngineTestKit.types.ts +76 -0
  61. package/src/testing/RegistrarEngineTestKitFactory.ts +154 -0
  62. package/src/testing/SubWorkflowRunnerTestNode.ts +83 -0
  63. package/src/testing/WorkflowTestHarnessManualTrigger.ts +39 -0
  64. package/src/testing/WorkflowTestKit.types.ts +9 -0
  65. package/src/testing/WorkflowTestKitBuilder.ts +77 -0
  66. package/src/testing/WorkflowTestKitNodeRegistrationContextFactory.ts +17 -0
  67. package/src/testing/WorkflowTestKitRunNodeWorkflowFactory.ts +26 -0
  68. package/src/testing.ts +19 -0
  69. package/src/types/index.ts +1 -0
  70. package/src/workflow/definition/ConnectionNodeIdFactory.ts +28 -0
  71. package/dist/InMemoryLiveWorkflowRepository-BTzHpQ6e.cjs +0 -151
  72. package/dist/InMemoryLiveWorkflowRepository-BTzHpQ6e.cjs.map +0 -1
  73. package/dist/InMemoryLiveWorkflowRepository-BoLNnVLg.js +0 -139
  74. package/dist/InMemoryLiveWorkflowRepository-BoLNnVLg.js.map +0 -1
  75. package/dist/RunIntentService-C1nu_YwM.js.map +0 -1
  76. package/dist/RunIntentService-DjbxzBBP.d.cts +0 -288
  77. package/dist/RunIntentService-ZkjpY7MS.cjs.map +0 -1
  78. package/dist/WorkflowSnapshotCodec-DSEzKyt3.d.cts +0 -22
  79. package/dist/bootstrap/index.cjs.map +0 -1
  80. package/dist/bootstrap/index.js.map +0 -1
@@ -0,0 +1,201 @@
1
+ //#region src/workflow/dsl/WhenBuilder.ts
2
+ var WhenBuilder = class WhenBuilder {
3
+ constructor(wf, from, branchPort) {
4
+ this.wf = wf;
5
+ this.from = from;
6
+ this.branchPort = branchPort;
7
+ }
8
+ addBranch(steps) {
9
+ const created = [];
10
+ let prev = null;
11
+ for (const cfg of steps) {
12
+ const ref = this.wf.add(cfg);
13
+ created.push(ref);
14
+ if (!prev) this.wf.connect(this.from, ref, this.branchPort, "in");
15
+ else this.wf.connect(prev, ref, "main", "in");
16
+ prev = ref;
17
+ }
18
+ for (const cfg of steps) {
19
+ const maybe = cfg;
20
+ if (!Array.isArray(maybe.upstreamRefs) || maybe.upstreamRefs.length === 0) continue;
21
+ maybe.upstreamRefs = maybe.upstreamRefs.map((r) => {
22
+ if (typeof r !== "string") return r;
23
+ const nodeId = created[parseInt(r.slice(1), 10)]?.id;
24
+ return nodeId ? { nodeId } : { nodeId: r };
25
+ });
26
+ }
27
+ return this;
28
+ }
29
+ when = (branch, steps, ...more) => {
30
+ const list = Array.isArray(steps) ? steps : [steps, ...more];
31
+ const port = branch ? "true" : "false";
32
+ const b = new WhenBuilder(this.wf, this.from, port);
33
+ b.addBranch(list);
34
+ return b;
35
+ };
36
+ build() {
37
+ return this.wf.build();
38
+ }
39
+ };
40
+
41
+ //#endregion
42
+ //#region src/workflow/dsl/ChainCursorResolver.ts
43
+ var ChainCursor = class ChainCursor {
44
+ constructor(wf, cursor, cursorOutput) {
45
+ this.wf = wf;
46
+ this.cursor = cursor;
47
+ this.cursorOutput = cursorOutput;
48
+ }
49
+ then(config) {
50
+ const next = this.wf.add(config);
51
+ this.wf.connect(this.cursor, next, this.cursorOutput);
52
+ return new ChainCursor(this.wf, next, "main");
53
+ }
54
+ when = ((arg1, steps, ...more) => {
55
+ if (typeof arg1 === "boolean") {
56
+ const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;
57
+ const port = arg1 ? "true" : "false";
58
+ const b = new WhenBuilder(this.wf, this.cursor, port);
59
+ b.addBranch(list);
60
+ return b;
61
+ }
62
+ const branches = arg1;
63
+ const makeMerge = this.wf.options?.makeMergeNode;
64
+ if (!makeMerge) throw new Error("WorkflowBuilder is missing options.makeMergeNode (required for when({true,false}). Use createWorkflowBuilder from \"@codemation/core-nodes\".");
65
+ const wfAny = this.wf;
66
+ const buildBranch = (port, branchSteps) => {
67
+ const list = branchSteps ?? [];
68
+ let prev = null;
69
+ for (const cfg of list) {
70
+ const ref = wfAny.add(cfg);
71
+ if (!prev) wfAny.connect(this.cursor, ref, port, "in");
72
+ else wfAny.connect(prev, ref, "main", "in");
73
+ prev = ref;
74
+ }
75
+ if (!prev) return {
76
+ end: this.cursor,
77
+ endOutput: port
78
+ };
79
+ return {
80
+ end: prev,
81
+ endOutput: "main"
82
+ };
83
+ };
84
+ const t = buildBranch("true", branches.true);
85
+ const f = buildBranch("false", branches.false);
86
+ const merge = wfAny.add(makeMerge("Merge (auto)"));
87
+ wfAny.connect(t.end, merge, t.endOutput, "true");
88
+ wfAny.connect(f.end, merge, f.endOutput, "false");
89
+ return new ChainCursor(this.wf, merge, "main");
90
+ });
91
+ build() {
92
+ return this.wf.build();
93
+ }
94
+ };
95
+
96
+ //#endregion
97
+ //#region src/workflow/dsl/WorkflowBuilder.ts
98
+ var WorkflowBuilder = class {
99
+ nodes = [];
100
+ edges = [];
101
+ seq = 0;
102
+ constructor(meta, options) {
103
+ this.meta = meta;
104
+ this.options = options;
105
+ }
106
+ add(config) {
107
+ const tokenName = typeof config.type === "function" ? config.type.name : String(config.type);
108
+ const id = config.id ?? `${tokenName}:${++this.seq}`;
109
+ this.nodes.push({
110
+ id,
111
+ kind: config.kind,
112
+ type: config.type,
113
+ name: config.name,
114
+ config
115
+ });
116
+ return {
117
+ id,
118
+ kind: config.kind,
119
+ name: config.name
120
+ };
121
+ }
122
+ connect(from, to, fromOutput = "main", toInput = "in") {
123
+ this.edges.push({
124
+ from: {
125
+ nodeId: from.id,
126
+ output: fromOutput
127
+ },
128
+ to: {
129
+ nodeId: to.id,
130
+ input: toInput
131
+ }
132
+ });
133
+ }
134
+ trigger(config) {
135
+ const ref = this.add(config);
136
+ return new ChainCursor(this, ref, "main");
137
+ }
138
+ start(config) {
139
+ const ref = this.add(config);
140
+ return new ChainCursor(this, ref, "main");
141
+ }
142
+ build() {
143
+ return {
144
+ ...this.meta,
145
+ nodes: this.nodes,
146
+ edges: this.edges
147
+ };
148
+ }
149
+ };
150
+
151
+ //#endregion
152
+ //#region src/events/InMemoryRunEventSubscription.ts
153
+ var InMemoryRunEventSubscription = class {
154
+ constructor(onClose) {
155
+ this.onClose = onClose;
156
+ }
157
+ async close() {
158
+ this.onClose();
159
+ }
160
+ };
161
+
162
+ //#endregion
163
+ //#region src/events/InMemoryRunEventBusRegistry.ts
164
+ var InMemoryRunEventBus = class {
165
+ globalListeners = /* @__PURE__ */ new Set();
166
+ listenersByWorkflowId = /* @__PURE__ */ new Map();
167
+ async publish(event) {
168
+ for (const listener of this.globalListeners) listener(event);
169
+ for (const listener of this.listenersByWorkflowId.get(event.workflowId) ?? []) listener(event);
170
+ }
171
+ async subscribe(onEvent) {
172
+ this.globalListeners.add(onEvent);
173
+ return new InMemoryRunEventSubscription(() => {
174
+ this.globalListeners.delete(onEvent);
175
+ });
176
+ }
177
+ async subscribeToWorkflow(workflowId, onEvent) {
178
+ const existing = this.listenersByWorkflowId.get(workflowId) ?? /* @__PURE__ */ new Set();
179
+ existing.add(onEvent);
180
+ this.listenersByWorkflowId.set(workflowId, existing);
181
+ return new InMemoryRunEventSubscription(() => {
182
+ const listeners = this.listenersByWorkflowId.get(workflowId);
183
+ if (!listeners) return;
184
+ listeners.delete(onEvent);
185
+ if (listeners.size === 0) this.listenersByWorkflowId.delete(workflowId);
186
+ });
187
+ }
188
+ };
189
+
190
+ //#endregion
191
+ //#region src/contracts/workflowActivationPolicy.ts
192
+ /** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */
193
+ var AllWorkflowsActiveWorkflowActivationPolicy = class {
194
+ isActive(_workflowId) {
195
+ return true;
196
+ }
197
+ };
198
+
199
+ //#endregion
200
+ export { WhenBuilder as a, ChainCursor as i, InMemoryRunEventBus as n, WorkflowBuilder as r, AllWorkflowsActiveWorkflowActivationPolicy as t };
201
+ //# sourceMappingURL=workflowActivationPolicy-B8HzTk3o.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflowActivationPolicy-B8HzTk3o.js","names":["wf: WorkflowBuilder","from: NodeRef","branchPort: OutputPortKey","created: NodeRef[]","prev: NodeRef | null","port: OutputPortKey","wf: WorkflowBuilder","cursor: NodeRef","cursorOutput: OutputPortKey","port: OutputPortKey","prev: NodeRef | null","meta: { id: WorkflowId; name: string }","options?: Readonly<{\n makeMergeNode?: (name: string) => AnyRunnableNodeConfig;\n }>","onClose: () => void"],"sources":["../src/workflow/dsl/WhenBuilder.ts","../src/workflow/dsl/ChainCursorResolver.ts","../src/workflow/dsl/WorkflowBuilder.ts","../src/events/InMemoryRunEventSubscription.ts","../src/events/InMemoryRunEventBusRegistry.ts","../src/contracts/workflowActivationPolicy.ts"],"sourcesContent":["import type { NodeId, NodeRef, OutputPortKey, UpstreamRefPlaceholder, WorkflowDefinition } from \"../../types\";\n\nimport { WorkflowBuilder } from \"./WorkflowBuilder\";\nimport type { AnyRunnableNodeConfig, BooleanWhenOverloads, ValidStepSequence } from \"./workflowBuilderTypes\";\n\nexport class WhenBuilder<TCurrentJson> {\n constructor(\n private readonly wf: WorkflowBuilder,\n private readonly from: NodeRef,\n private readonly branchPort: OutputPortKey,\n ) {}\n\n addBranch<TSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(\n steps: TSteps & ValidStepSequence<TCurrentJson, TSteps>,\n ): this {\n const created: NodeRef[] = [];\n\n let prev: NodeRef | null = null;\n for (const cfg of steps) {\n const ref = (this.wf as any).add(cfg) as NodeRef;\n created.push(ref);\n if (!prev) (this.wf as any).connect(this.from, ref, this.branchPort, \"in\");\n else (this.wf as any).connect(prev, ref, \"main\", \"in\");\n prev = ref;\n }\n\n for (const cfg of steps) {\n const maybe = cfg as unknown as { upstreamRefs?: Array<{ nodeId: NodeId } | UpstreamRefPlaceholder> };\n if (!Array.isArray(maybe.upstreamRefs) || maybe.upstreamRefs.length === 0) continue;\n\n maybe.upstreamRefs = maybe.upstreamRefs.map((r) => {\n if (typeof r !== \"string\") return r;\n const idx = parseInt(r.slice(1), 10);\n const nodeId = created[idx]?.id;\n return nodeId ? { nodeId } : { nodeId: r };\n });\n }\n\n return this;\n }\n\n readonly when: BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> = (\n branch: boolean,\n steps: ReadonlyArray<AnyRunnableNodeConfig> | AnyRunnableNodeConfig,\n ...more: AnyRunnableNodeConfig[]\n ): WhenBuilder<TCurrentJson> => {\n const list = Array.isArray(steps) ? steps : [steps, ...more];\n const port: OutputPortKey = branch ? \"true\" : \"false\";\n const b = new WhenBuilder<TCurrentJson>(this.wf, this.from, port);\n b.addBranch(list);\n return b;\n };\n\n build(): WorkflowDefinition {\n return this.wf.build();\n }\n}\n","import type {\n NodeRef,\n OutputPortKey,\n RunnableNodeConfig,\n RunnableNodeOutputJson,\n WorkflowDefinition,\n} from \"../../types\";\n\nimport { WorkflowBuilder } from \"./WorkflowBuilder\";\nimport { WhenBuilder } from \"./WhenBuilder\";\nimport type {\n AnyRunnableNodeConfig,\n BooleanWhenOverloads,\n BranchOutputGuard,\n BranchStepsArg,\n StepSequenceOutput,\n} from \"./workflowBuilderTypes\";\n\ntype ChainCursorWhenOverloads<TCurrentJson> = BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> & {\n <\n TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n >(\n branches: Readonly<{\n true?: TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? BranchStepsArg<TCurrentJson, TTrueSteps> : never;\n false?: TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig>\n ? BranchStepsArg<TCurrentJson, TFalseSteps>\n : never;\n }> &\n BranchOutputGuard<TCurrentJson, TTrueSteps, TFalseSteps>,\n ): ChainCursor<StepSequenceOutput<TCurrentJson, TTrueSteps>>;\n};\n\nexport class ChainCursor<TCurrentJson> {\n constructor(\n private readonly wf: WorkflowBuilder,\n private readonly cursor: NodeRef,\n private readonly cursorOutput: OutputPortKey,\n ) {}\n\n then<TConfig extends RunnableNodeConfig<TCurrentJson, any>>(\n config: TConfig,\n ): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const next = (this.wf as any).add(config) as NodeRef;\n (this.wf as any).connect(this.cursor, next, this.cursorOutput);\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this.wf, next, \"main\");\n }\n\n readonly when: ChainCursorWhenOverloads<TCurrentJson> = ((\n arg1:\n | boolean\n | Readonly<{ true?: ReadonlyArray<AnyRunnableNodeConfig>; false?: ReadonlyArray<AnyRunnableNodeConfig> }>,\n steps?: ReadonlyArray<AnyRunnableNodeConfig> | AnyRunnableNodeConfig,\n ...more: AnyRunnableNodeConfig[]\n ): WhenBuilder<TCurrentJson> | ChainCursor<TCurrentJson> => {\n if (typeof arg1 === \"boolean\") {\n const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;\n const port: OutputPortKey = arg1 ? \"true\" : \"false\";\n const b = new WhenBuilder<TCurrentJson>(this.wf, this.cursor, port);\n b.addBranch(list);\n return b;\n }\n\n const branches = arg1;\n const makeMerge = (this.wf as any).options?.makeMergeNode as ((name: string) => AnyRunnableNodeConfig) | undefined;\n if (!makeMerge) {\n throw new Error(\n 'WorkflowBuilder is missing options.makeMergeNode (required for when({true,false}). Use createWorkflowBuilder from \"@codemation/core-nodes\".',\n );\n }\n\n const wfAny = this.wf as any;\n\n const buildBranch = (\n port: OutputPortKey,\n branchSteps: ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n ): Readonly<{ end: NodeRef; endOutput: OutputPortKey }> => {\n const list = branchSteps ?? [];\n let prev: NodeRef | null = null;\n for (const cfg of list) {\n const ref = wfAny.add(cfg) as NodeRef;\n if (!prev) wfAny.connect(this.cursor, ref, port, \"in\");\n else wfAny.connect(prev, ref, \"main\", \"in\");\n prev = ref;\n }\n if (!prev) return { end: this.cursor, endOutput: port };\n return { end: prev, endOutput: \"main\" };\n };\n\n const t = buildBranch(\"true\", branches.true);\n const f = buildBranch(\"false\", branches.false);\n\n const merge = wfAny.add(makeMerge(\"Merge (auto)\")) as NodeRef;\n wfAny.connect(t.end, merge, t.endOutput, \"true\");\n wfAny.connect(f.end, merge, f.endOutput, \"false\");\n\n return new ChainCursor<TCurrentJson>(this.wf, merge, \"main\");\n }) as ChainCursorWhenOverloads<TCurrentJson>;\n\n build(): WorkflowDefinition {\n return this.wf.build();\n }\n}\n","import type {\n InputPortKey,\n NodeConfigBase,\n NodeDefinition,\n NodeRef,\n OutputPortKey,\n RunnableNodeOutputJson,\n TriggerNodeOutputJson,\n WorkflowDefinition,\n WorkflowId,\n} from \"../../types\";\n\nimport { ChainCursor } from \"./ChainCursorResolver\";\nimport type { AnyRunnableNodeConfig, AnyTriggerNodeConfig } from \"./workflowBuilderTypes\";\n\nexport class WorkflowBuilder {\n private readonly nodes: NodeDefinition[] = [];\n private readonly edges: WorkflowDefinition[\"edges\"] = [];\n private seq = 0;\n\n constructor(\n private readonly meta: { id: WorkflowId; name: string },\n private readonly options?: Readonly<{\n makeMergeNode?: (name: string) => AnyRunnableNodeConfig;\n }>,\n ) {}\n\n private add(config: NodeConfigBase): NodeRef {\n const tokenName = typeof config.type === \"function\" ? config.type.name : String(config.type);\n const id = config.id ?? `${tokenName}:${++this.seq}`;\n this.nodes.push({ id, kind: config.kind, type: config.type, name: config.name, config });\n return { id, kind: config.kind, name: config.name };\n }\n\n private connect(from: NodeRef, to: NodeRef, fromOutput: OutputPortKey = \"main\", toInput: InputPortKey = \"in\"): void {\n this.edges.push({ from: { nodeId: from.id, output: fromOutput }, to: { nodeId: to.id, input: toInput } });\n }\n\n trigger<TConfig extends AnyTriggerNodeConfig>(config: TConfig): ChainCursor<TriggerNodeOutputJson<TConfig>> {\n const ref = this.add(config);\n return new ChainCursor<TriggerNodeOutputJson<TConfig>>(this, ref, \"main\");\n }\n\n start<TConfig extends AnyRunnableNodeConfig>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const ref = this.add(config);\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this, ref, \"main\");\n }\n\n build(): WorkflowDefinition {\n return { ...this.meta, nodes: this.nodes, edges: this.edges };\n }\n}\n\nexport { ChainCursor } from \"./ChainCursorResolver\";\nexport { WhenBuilder } from \"./WhenBuilder\";\n","import type { RunEventSubscription } from \"./runEvents\";\n\nexport class InMemoryRunEventSubscription implements RunEventSubscription {\n constructor(private readonly onClose: () => void) {}\n\n async close(): Promise<void> {\n this.onClose();\n }\n}\n","import type { WorkflowId } from \"../types\";\n\nimport type { RunEvent, RunEventBus, RunEventSubscription } from \"./runEvents\";\n\nimport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n\nexport class InMemoryRunEventBus implements RunEventBus {\n private readonly globalListeners = new Set<(event: RunEvent) => void>();\n private readonly listenersByWorkflowId = new Map<WorkflowId, Set<(event: RunEvent) => void>>();\n\n async publish(event: RunEvent): Promise<void> {\n for (const listener of this.globalListeners) listener(event);\n for (const listener of this.listenersByWorkflowId.get(event.workflowId) ?? []) listener(event);\n }\n\n async subscribe(onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n this.globalListeners.add(onEvent);\n return new InMemoryRunEventSubscription(() => {\n this.globalListeners.delete(onEvent);\n });\n }\n\n async subscribeToWorkflow(workflowId: WorkflowId, onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n const existing = this.listenersByWorkflowId.get(workflowId) ?? new Set<(event: RunEvent) => void>();\n existing.add(onEvent);\n this.listenersByWorkflowId.set(workflowId, existing);\n\n return new InMemoryRunEventSubscription(() => {\n const listeners = this.listenersByWorkflowId.get(workflowId);\n if (!listeners) return;\n listeners.delete(onEvent);\n if (listeners.size === 0) this.listenersByWorkflowId.delete(workflowId);\n });\n }\n}\n\nexport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n","import type { WorkflowId } from \"./workflowTypes\";\n\n/**\n * Host-controlled policy: when false, trigger {@link TriggerNode} setup is skipped and webhook routes\n * for that workflow are not registered (see engine trigger runtime + webhook matcher).\n */\nexport interface WorkflowActivationPolicy {\n isActive(workflowId: WorkflowId): boolean;\n}\n\n/** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */\nexport class AllWorkflowsActiveWorkflowActivationPolicy implements WorkflowActivationPolicy {\n isActive(_workflowId: WorkflowId): boolean {\n return true;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,231 @@
1
+
2
+ //#region src/workflow/dsl/WhenBuilder.ts
3
+ var WhenBuilder = class WhenBuilder {
4
+ constructor(wf, from, branchPort) {
5
+ this.wf = wf;
6
+ this.from = from;
7
+ this.branchPort = branchPort;
8
+ }
9
+ addBranch(steps) {
10
+ const created = [];
11
+ let prev = null;
12
+ for (const cfg of steps) {
13
+ const ref = this.wf.add(cfg);
14
+ created.push(ref);
15
+ if (!prev) this.wf.connect(this.from, ref, this.branchPort, "in");
16
+ else this.wf.connect(prev, ref, "main", "in");
17
+ prev = ref;
18
+ }
19
+ for (const cfg of steps) {
20
+ const maybe = cfg;
21
+ if (!Array.isArray(maybe.upstreamRefs) || maybe.upstreamRefs.length === 0) continue;
22
+ maybe.upstreamRefs = maybe.upstreamRefs.map((r) => {
23
+ if (typeof r !== "string") return r;
24
+ const nodeId = created[parseInt(r.slice(1), 10)]?.id;
25
+ return nodeId ? { nodeId } : { nodeId: r };
26
+ });
27
+ }
28
+ return this;
29
+ }
30
+ when = (branch, steps, ...more) => {
31
+ const list = Array.isArray(steps) ? steps : [steps, ...more];
32
+ const port = branch ? "true" : "false";
33
+ const b = new WhenBuilder(this.wf, this.from, port);
34
+ b.addBranch(list);
35
+ return b;
36
+ };
37
+ build() {
38
+ return this.wf.build();
39
+ }
40
+ };
41
+
42
+ //#endregion
43
+ //#region src/workflow/dsl/ChainCursorResolver.ts
44
+ var ChainCursor = class ChainCursor {
45
+ constructor(wf, cursor, cursorOutput) {
46
+ this.wf = wf;
47
+ this.cursor = cursor;
48
+ this.cursorOutput = cursorOutput;
49
+ }
50
+ then(config) {
51
+ const next = this.wf.add(config);
52
+ this.wf.connect(this.cursor, next, this.cursorOutput);
53
+ return new ChainCursor(this.wf, next, "main");
54
+ }
55
+ when = ((arg1, steps, ...more) => {
56
+ if (typeof arg1 === "boolean") {
57
+ const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;
58
+ const port = arg1 ? "true" : "false";
59
+ const b = new WhenBuilder(this.wf, this.cursor, port);
60
+ b.addBranch(list);
61
+ return b;
62
+ }
63
+ const branches = arg1;
64
+ const makeMerge = this.wf.options?.makeMergeNode;
65
+ if (!makeMerge) throw new Error("WorkflowBuilder is missing options.makeMergeNode (required for when({true,false}). Use createWorkflowBuilder from \"@codemation/core-nodes\".");
66
+ const wfAny = this.wf;
67
+ const buildBranch = (port, branchSteps) => {
68
+ const list = branchSteps ?? [];
69
+ let prev = null;
70
+ for (const cfg of list) {
71
+ const ref = wfAny.add(cfg);
72
+ if (!prev) wfAny.connect(this.cursor, ref, port, "in");
73
+ else wfAny.connect(prev, ref, "main", "in");
74
+ prev = ref;
75
+ }
76
+ if (!prev) return {
77
+ end: this.cursor,
78
+ endOutput: port
79
+ };
80
+ return {
81
+ end: prev,
82
+ endOutput: "main"
83
+ };
84
+ };
85
+ const t = buildBranch("true", branches.true);
86
+ const f = buildBranch("false", branches.false);
87
+ const merge = wfAny.add(makeMerge("Merge (auto)"));
88
+ wfAny.connect(t.end, merge, t.endOutput, "true");
89
+ wfAny.connect(f.end, merge, f.endOutput, "false");
90
+ return new ChainCursor(this.wf, merge, "main");
91
+ });
92
+ build() {
93
+ return this.wf.build();
94
+ }
95
+ };
96
+
97
+ //#endregion
98
+ //#region src/workflow/dsl/WorkflowBuilder.ts
99
+ var WorkflowBuilder = class {
100
+ nodes = [];
101
+ edges = [];
102
+ seq = 0;
103
+ constructor(meta, options) {
104
+ this.meta = meta;
105
+ this.options = options;
106
+ }
107
+ add(config) {
108
+ const tokenName = typeof config.type === "function" ? config.type.name : String(config.type);
109
+ const id = config.id ?? `${tokenName}:${++this.seq}`;
110
+ this.nodes.push({
111
+ id,
112
+ kind: config.kind,
113
+ type: config.type,
114
+ name: config.name,
115
+ config
116
+ });
117
+ return {
118
+ id,
119
+ kind: config.kind,
120
+ name: config.name
121
+ };
122
+ }
123
+ connect(from, to, fromOutput = "main", toInput = "in") {
124
+ this.edges.push({
125
+ from: {
126
+ nodeId: from.id,
127
+ output: fromOutput
128
+ },
129
+ to: {
130
+ nodeId: to.id,
131
+ input: toInput
132
+ }
133
+ });
134
+ }
135
+ trigger(config) {
136
+ const ref = this.add(config);
137
+ return new ChainCursor(this, ref, "main");
138
+ }
139
+ start(config) {
140
+ const ref = this.add(config);
141
+ return new ChainCursor(this, ref, "main");
142
+ }
143
+ build() {
144
+ return {
145
+ ...this.meta,
146
+ nodes: this.nodes,
147
+ edges: this.edges
148
+ };
149
+ }
150
+ };
151
+
152
+ //#endregion
153
+ //#region src/events/InMemoryRunEventSubscription.ts
154
+ var InMemoryRunEventSubscription = class {
155
+ constructor(onClose) {
156
+ this.onClose = onClose;
157
+ }
158
+ async close() {
159
+ this.onClose();
160
+ }
161
+ };
162
+
163
+ //#endregion
164
+ //#region src/events/InMemoryRunEventBusRegistry.ts
165
+ var InMemoryRunEventBus = class {
166
+ globalListeners = /* @__PURE__ */ new Set();
167
+ listenersByWorkflowId = /* @__PURE__ */ new Map();
168
+ async publish(event) {
169
+ for (const listener of this.globalListeners) listener(event);
170
+ for (const listener of this.listenersByWorkflowId.get(event.workflowId) ?? []) listener(event);
171
+ }
172
+ async subscribe(onEvent) {
173
+ this.globalListeners.add(onEvent);
174
+ return new InMemoryRunEventSubscription(() => {
175
+ this.globalListeners.delete(onEvent);
176
+ });
177
+ }
178
+ async subscribeToWorkflow(workflowId, onEvent) {
179
+ const existing = this.listenersByWorkflowId.get(workflowId) ?? /* @__PURE__ */ new Set();
180
+ existing.add(onEvent);
181
+ this.listenersByWorkflowId.set(workflowId, existing);
182
+ return new InMemoryRunEventSubscription(() => {
183
+ const listeners = this.listenersByWorkflowId.get(workflowId);
184
+ if (!listeners) return;
185
+ listeners.delete(onEvent);
186
+ if (listeners.size === 0) this.listenersByWorkflowId.delete(workflowId);
187
+ });
188
+ }
189
+ };
190
+
191
+ //#endregion
192
+ //#region src/contracts/workflowActivationPolicy.ts
193
+ /** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */
194
+ var AllWorkflowsActiveWorkflowActivationPolicy = class {
195
+ isActive(_workflowId) {
196
+ return true;
197
+ }
198
+ };
199
+
200
+ //#endregion
201
+ Object.defineProperty(exports, 'AllWorkflowsActiveWorkflowActivationPolicy', {
202
+ enumerable: true,
203
+ get: function () {
204
+ return AllWorkflowsActiveWorkflowActivationPolicy;
205
+ }
206
+ });
207
+ Object.defineProperty(exports, 'ChainCursor', {
208
+ enumerable: true,
209
+ get: function () {
210
+ return ChainCursor;
211
+ }
212
+ });
213
+ Object.defineProperty(exports, 'InMemoryRunEventBus', {
214
+ enumerable: true,
215
+ get: function () {
216
+ return InMemoryRunEventBus;
217
+ }
218
+ });
219
+ Object.defineProperty(exports, 'WhenBuilder', {
220
+ enumerable: true,
221
+ get: function () {
222
+ return WhenBuilder;
223
+ }
224
+ });
225
+ Object.defineProperty(exports, 'WorkflowBuilder', {
226
+ enumerable: true,
227
+ get: function () {
228
+ return WorkflowBuilder;
229
+ }
230
+ });
231
+ //# sourceMappingURL=workflowActivationPolicy-BzyzXLa_.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflowActivationPolicy-BzyzXLa_.cjs","names":["wf: WorkflowBuilder","from: NodeRef","branchPort: OutputPortKey","created: NodeRef[]","prev: NodeRef | null","port: OutputPortKey","wf: WorkflowBuilder","cursor: NodeRef","cursorOutput: OutputPortKey","port: OutputPortKey","prev: NodeRef | null","meta: { id: WorkflowId; name: string }","options?: Readonly<{\n makeMergeNode?: (name: string) => AnyRunnableNodeConfig;\n }>","onClose: () => void"],"sources":["../src/workflow/dsl/WhenBuilder.ts","../src/workflow/dsl/ChainCursorResolver.ts","../src/workflow/dsl/WorkflowBuilder.ts","../src/events/InMemoryRunEventSubscription.ts","../src/events/InMemoryRunEventBusRegistry.ts","../src/contracts/workflowActivationPolicy.ts"],"sourcesContent":["import type { NodeId, NodeRef, OutputPortKey, UpstreamRefPlaceholder, WorkflowDefinition } from \"../../types\";\n\nimport { WorkflowBuilder } from \"./WorkflowBuilder\";\nimport type { AnyRunnableNodeConfig, BooleanWhenOverloads, ValidStepSequence } from \"./workflowBuilderTypes\";\n\nexport class WhenBuilder<TCurrentJson> {\n constructor(\n private readonly wf: WorkflowBuilder,\n private readonly from: NodeRef,\n private readonly branchPort: OutputPortKey,\n ) {}\n\n addBranch<TSteps extends ReadonlyArray<AnyRunnableNodeConfig>>(\n steps: TSteps & ValidStepSequence<TCurrentJson, TSteps>,\n ): this {\n const created: NodeRef[] = [];\n\n let prev: NodeRef | null = null;\n for (const cfg of steps) {\n const ref = (this.wf as any).add(cfg) as NodeRef;\n created.push(ref);\n if (!prev) (this.wf as any).connect(this.from, ref, this.branchPort, \"in\");\n else (this.wf as any).connect(prev, ref, \"main\", \"in\");\n prev = ref;\n }\n\n for (const cfg of steps) {\n const maybe = cfg as unknown as { upstreamRefs?: Array<{ nodeId: NodeId } | UpstreamRefPlaceholder> };\n if (!Array.isArray(maybe.upstreamRefs) || maybe.upstreamRefs.length === 0) continue;\n\n maybe.upstreamRefs = maybe.upstreamRefs.map((r) => {\n if (typeof r !== \"string\") return r;\n const idx = parseInt(r.slice(1), 10);\n const nodeId = created[idx]?.id;\n return nodeId ? { nodeId } : { nodeId: r };\n });\n }\n\n return this;\n }\n\n readonly when: BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> = (\n branch: boolean,\n steps: ReadonlyArray<AnyRunnableNodeConfig> | AnyRunnableNodeConfig,\n ...more: AnyRunnableNodeConfig[]\n ): WhenBuilder<TCurrentJson> => {\n const list = Array.isArray(steps) ? steps : [steps, ...more];\n const port: OutputPortKey = branch ? \"true\" : \"false\";\n const b = new WhenBuilder<TCurrentJson>(this.wf, this.from, port);\n b.addBranch(list);\n return b;\n };\n\n build(): WorkflowDefinition {\n return this.wf.build();\n }\n}\n","import type {\n NodeRef,\n OutputPortKey,\n RunnableNodeConfig,\n RunnableNodeOutputJson,\n WorkflowDefinition,\n} from \"../../types\";\n\nimport { WorkflowBuilder } from \"./WorkflowBuilder\";\nimport { WhenBuilder } from \"./WhenBuilder\";\nimport type {\n AnyRunnableNodeConfig,\n BooleanWhenOverloads,\n BranchOutputGuard,\n BranchStepsArg,\n StepSequenceOutput,\n} from \"./workflowBuilderTypes\";\n\ntype ChainCursorWhenOverloads<TCurrentJson> = BooleanWhenOverloads<TCurrentJson, WhenBuilder<TCurrentJson>> & {\n <\n TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n >(\n branches: Readonly<{\n true?: TTrueSteps extends ReadonlyArray<AnyRunnableNodeConfig> ? BranchStepsArg<TCurrentJson, TTrueSteps> : never;\n false?: TFalseSteps extends ReadonlyArray<AnyRunnableNodeConfig>\n ? BranchStepsArg<TCurrentJson, TFalseSteps>\n : never;\n }> &\n BranchOutputGuard<TCurrentJson, TTrueSteps, TFalseSteps>,\n ): ChainCursor<StepSequenceOutput<TCurrentJson, TTrueSteps>>;\n};\n\nexport class ChainCursor<TCurrentJson> {\n constructor(\n private readonly wf: WorkflowBuilder,\n private readonly cursor: NodeRef,\n private readonly cursorOutput: OutputPortKey,\n ) {}\n\n then<TConfig extends RunnableNodeConfig<TCurrentJson, any>>(\n config: TConfig,\n ): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const next = (this.wf as any).add(config) as NodeRef;\n (this.wf as any).connect(this.cursor, next, this.cursorOutput);\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this.wf, next, \"main\");\n }\n\n readonly when: ChainCursorWhenOverloads<TCurrentJson> = ((\n arg1:\n | boolean\n | Readonly<{ true?: ReadonlyArray<AnyRunnableNodeConfig>; false?: ReadonlyArray<AnyRunnableNodeConfig> }>,\n steps?: ReadonlyArray<AnyRunnableNodeConfig> | AnyRunnableNodeConfig,\n ...more: AnyRunnableNodeConfig[]\n ): WhenBuilder<TCurrentJson> | ChainCursor<TCurrentJson> => {\n if (typeof arg1 === \"boolean\") {\n const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;\n const port: OutputPortKey = arg1 ? \"true\" : \"false\";\n const b = new WhenBuilder<TCurrentJson>(this.wf, this.cursor, port);\n b.addBranch(list);\n return b;\n }\n\n const branches = arg1;\n const makeMerge = (this.wf as any).options?.makeMergeNode as ((name: string) => AnyRunnableNodeConfig) | undefined;\n if (!makeMerge) {\n throw new Error(\n 'WorkflowBuilder is missing options.makeMergeNode (required for when({true,false}). Use createWorkflowBuilder from \"@codemation/core-nodes\".',\n );\n }\n\n const wfAny = this.wf as any;\n\n const buildBranch = (\n port: OutputPortKey,\n branchSteps: ReadonlyArray<AnyRunnableNodeConfig> | undefined,\n ): Readonly<{ end: NodeRef; endOutput: OutputPortKey }> => {\n const list = branchSteps ?? [];\n let prev: NodeRef | null = null;\n for (const cfg of list) {\n const ref = wfAny.add(cfg) as NodeRef;\n if (!prev) wfAny.connect(this.cursor, ref, port, \"in\");\n else wfAny.connect(prev, ref, \"main\", \"in\");\n prev = ref;\n }\n if (!prev) return { end: this.cursor, endOutput: port };\n return { end: prev, endOutput: \"main\" };\n };\n\n const t = buildBranch(\"true\", branches.true);\n const f = buildBranch(\"false\", branches.false);\n\n const merge = wfAny.add(makeMerge(\"Merge (auto)\")) as NodeRef;\n wfAny.connect(t.end, merge, t.endOutput, \"true\");\n wfAny.connect(f.end, merge, f.endOutput, \"false\");\n\n return new ChainCursor<TCurrentJson>(this.wf, merge, \"main\");\n }) as ChainCursorWhenOverloads<TCurrentJson>;\n\n build(): WorkflowDefinition {\n return this.wf.build();\n }\n}\n","import type {\n InputPortKey,\n NodeConfigBase,\n NodeDefinition,\n NodeRef,\n OutputPortKey,\n RunnableNodeOutputJson,\n TriggerNodeOutputJson,\n WorkflowDefinition,\n WorkflowId,\n} from \"../../types\";\n\nimport { ChainCursor } from \"./ChainCursorResolver\";\nimport type { AnyRunnableNodeConfig, AnyTriggerNodeConfig } from \"./workflowBuilderTypes\";\n\nexport class WorkflowBuilder {\n private readonly nodes: NodeDefinition[] = [];\n private readonly edges: WorkflowDefinition[\"edges\"] = [];\n private seq = 0;\n\n constructor(\n private readonly meta: { id: WorkflowId; name: string },\n private readonly options?: Readonly<{\n makeMergeNode?: (name: string) => AnyRunnableNodeConfig;\n }>,\n ) {}\n\n private add(config: NodeConfigBase): NodeRef {\n const tokenName = typeof config.type === \"function\" ? config.type.name : String(config.type);\n const id = config.id ?? `${tokenName}:${++this.seq}`;\n this.nodes.push({ id, kind: config.kind, type: config.type, name: config.name, config });\n return { id, kind: config.kind, name: config.name };\n }\n\n private connect(from: NodeRef, to: NodeRef, fromOutput: OutputPortKey = \"main\", toInput: InputPortKey = \"in\"): void {\n this.edges.push({ from: { nodeId: from.id, output: fromOutput }, to: { nodeId: to.id, input: toInput } });\n }\n\n trigger<TConfig extends AnyTriggerNodeConfig>(config: TConfig): ChainCursor<TriggerNodeOutputJson<TConfig>> {\n const ref = this.add(config);\n return new ChainCursor<TriggerNodeOutputJson<TConfig>>(this, ref, \"main\");\n }\n\n start<TConfig extends AnyRunnableNodeConfig>(config: TConfig): ChainCursor<RunnableNodeOutputJson<TConfig>> {\n const ref = this.add(config);\n return new ChainCursor<RunnableNodeOutputJson<TConfig>>(this, ref, \"main\");\n }\n\n build(): WorkflowDefinition {\n return { ...this.meta, nodes: this.nodes, edges: this.edges };\n }\n}\n\nexport { ChainCursor } from \"./ChainCursorResolver\";\nexport { WhenBuilder } from \"./WhenBuilder\";\n","import type { RunEventSubscription } from \"./runEvents\";\n\nexport class InMemoryRunEventSubscription implements RunEventSubscription {\n constructor(private readonly onClose: () => void) {}\n\n async close(): Promise<void> {\n this.onClose();\n }\n}\n","import type { WorkflowId } from \"../types\";\n\nimport type { RunEvent, RunEventBus, RunEventSubscription } from \"./runEvents\";\n\nimport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n\nexport class InMemoryRunEventBus implements RunEventBus {\n private readonly globalListeners = new Set<(event: RunEvent) => void>();\n private readonly listenersByWorkflowId = new Map<WorkflowId, Set<(event: RunEvent) => void>>();\n\n async publish(event: RunEvent): Promise<void> {\n for (const listener of this.globalListeners) listener(event);\n for (const listener of this.listenersByWorkflowId.get(event.workflowId) ?? []) listener(event);\n }\n\n async subscribe(onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n this.globalListeners.add(onEvent);\n return new InMemoryRunEventSubscription(() => {\n this.globalListeners.delete(onEvent);\n });\n }\n\n async subscribeToWorkflow(workflowId: WorkflowId, onEvent: (event: RunEvent) => void): Promise<RunEventSubscription> {\n const existing = this.listenersByWorkflowId.get(workflowId) ?? new Set<(event: RunEvent) => void>();\n existing.add(onEvent);\n this.listenersByWorkflowId.set(workflowId, existing);\n\n return new InMemoryRunEventSubscription(() => {\n const listeners = this.listenersByWorkflowId.get(workflowId);\n if (!listeners) return;\n listeners.delete(onEvent);\n if (listeners.size === 0) this.listenersByWorkflowId.delete(workflowId);\n });\n }\n}\n\nexport { InMemoryRunEventSubscription } from \"./InMemoryRunEventSubscription\";\n","import type { WorkflowId } from \"./workflowTypes\";\n\n/**\n * Host-controlled policy: when false, trigger {@link TriggerNode} setup is skipped and webhook routes\n * for that workflow are not registered (see engine trigger runtime + webhook matcher).\n */\nexport interface WorkflowActivationPolicy {\n isActive(workflowId: WorkflowId): boolean;\n}\n\n/** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */\nexport class AllWorkflowsActiveWorkflowActivationPolicy implements WorkflowActivationPolicy {\n isActive(_workflowId: WorkflowId): boolean {\n return true;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@codemation/core",
3
- "version": "0.0.19",
3
+ "version": "0.2.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -0,0 +1,99 @@
1
+ import type { CredentialRequirement } from "../contracts/credentialTypes";
2
+ import type { NodeConfigBase, NodeConnectionName, NodeId } from "../types";
3
+ import { ConnectionNodeIdFactory } from "../workflow/definition/ConnectionNodeIdFactory";
4
+ import { AgentConfigInspector } from "./AgentConfigInspectorFactory";
5
+ import type { AgentNodeConfig, ToolConfig } from "./AiHost";
6
+ import { NodeBackedToolConfig } from "./NodeBackedToolConfig";
7
+
8
+ export type AgentConnectionNodeRole = "languageModel" | "tool" | "nestedAgent";
9
+
10
+ export type AgentConnectionCredentialSource = Readonly<{
11
+ getCredentialRequirements?(): ReadonlyArray<CredentialRequirement>;
12
+ }>;
13
+
14
+ export type AgentConnectionNodeDescriptor = Readonly<{
15
+ nodeId: NodeId;
16
+ parentNodeId: NodeId;
17
+ connectionName: NodeConnectionName;
18
+ role: AgentConnectionNodeRole;
19
+ name: string;
20
+ typeName: string;
21
+ icon?: string;
22
+ credentialSource: AgentConnectionCredentialSource;
23
+ }>;
24
+
25
+ type AgentConnectionNodeCollectorApi = Readonly<{
26
+ collect(parentNodeId: NodeId, agentConfig: AgentNodeConfig<any, any>): ReadonlyArray<AgentConnectionNodeDescriptor>;
27
+ }>;
28
+
29
+ export const AgentConnectionNodeCollector: AgentConnectionNodeCollectorApi = new (class {
30
+ collect(parentNodeId: NodeId, agentConfig: AgentNodeConfig<any, any>): ReadonlyArray<AgentConnectionNodeDescriptor> {
31
+ const collected: AgentConnectionNodeDescriptor[] = [];
32
+ this.collectInto(parentNodeId, agentConfig, collected);
33
+ return collected;
34
+ }
35
+
36
+ private collectInto(
37
+ parentNodeId: NodeId,
38
+ agentConfig: AgentNodeConfig<any, any>,
39
+ collected: AgentConnectionNodeDescriptor[],
40
+ ): void {
41
+ collected.push({
42
+ nodeId: ConnectionNodeIdFactory.languageModelConnectionNodeId(parentNodeId),
43
+ parentNodeId,
44
+ connectionName: "llm",
45
+ role: "languageModel",
46
+ name: agentConfig.chatModel.presentation?.label ?? agentConfig.chatModel.name,
47
+ typeName: agentConfig.chatModel.name,
48
+ icon: agentConfig.chatModel.presentation?.icon,
49
+ credentialSource: agentConfig.chatModel,
50
+ });
51
+
52
+ for (const tool of agentConfig.tools ?? []) {
53
+ const toolNodeId = ConnectionNodeIdFactory.toolConnectionNodeId(parentNodeId, tool.name);
54
+ const isNestedAgent = this.isNodeBackedAgentTool(tool);
55
+ collected.push({
56
+ nodeId: toolNodeId,
57
+ parentNodeId,
58
+ connectionName: "tools",
59
+ role: isNestedAgent ? "nestedAgent" : "tool",
60
+ name: tool.presentation?.label ?? tool.name,
61
+ typeName: tool.name,
62
+ icon: tool.presentation?.icon,
63
+ credentialSource: tool,
64
+ });
65
+ this.collectNestedAgentTools(toolNodeId, tool, collected);
66
+ }
67
+ }
68
+
69
+ private collectNestedAgentTools(
70
+ toolNodeId: NodeId,
71
+ tool: ToolConfig,
72
+ collected: AgentConnectionNodeDescriptor[],
73
+ ): void {
74
+ if (!this.isNodeBackedAgentTool(tool)) {
75
+ return;
76
+ }
77
+ const innerAgent =
78
+ tool instanceof NodeBackedToolConfig ? tool.node : (tool as unknown as { node: AgentNodeConfig<any, any> }).node;
79
+ this.collectInto(toolNodeId, innerAgent, collected);
80
+ }
81
+
82
+ /**
83
+ * After JSON round-trip (persisted snapshots), tools are plain objects — `instanceof NodeBackedToolConfig` fails.
84
+ * Detect node-backed tools structurally via {@link NodeBackedToolConfig#toolKind}.
85
+ */
86
+ private isNodeBackedAgentTool(tool: ToolConfig): boolean {
87
+ if (tool instanceof NodeBackedToolConfig) {
88
+ return AgentConfigInspector.isAgentNodeConfig(tool.node);
89
+ }
90
+ if (!tool || typeof tool !== "object") {
91
+ return false;
92
+ }
93
+ const t = tool as unknown as Record<string, unknown>;
94
+ if (t.toolKind !== "nodeBacked") {
95
+ return false;
96
+ }
97
+ return AgentConfigInspector.isAgentNodeConfig(t.node as NodeConfigBase);
98
+ }
99
+ })();
@@ -1,5 +1,6 @@
1
- import type { RunnableNodeConfig } from "../types";
1
+ import type { Item, RunnableNodeConfig } from "../types";
2
2
  import type { NodeBackedToolConfigOptions, ZodSchemaAny } from "./AiHost";
3
+ import { AgentConfigInspector } from "./AgentConfigInspectorFactory";
3
4
  import { NodeBackedToolConfig } from "./NodeBackedToolConfig";
4
5
 
5
6
  class AgentToolFactoryImpl {
@@ -11,7 +12,42 @@ class AgentToolFactoryImpl {
11
12
  node: TNodeConfig,
12
13
  options: Readonly<{ name?: string } & NodeBackedToolConfigOptions<TNodeConfig, TInputSchema, TOutputSchema>>,
13
14
  ): NodeBackedToolConfig<TNodeConfig, TInputSchema, TOutputSchema> {
14
- return new NodeBackedToolConfig(options.name ?? node.name ?? "tool", node, options);
15
+ return new NodeBackedToolConfig(
16
+ options.name ?? node.name ?? "tool",
17
+ node,
18
+ this.withDefaultAgentInputMapper(node, options),
19
+ );
20
+ }
21
+
22
+ private withDefaultAgentInputMapper<
23
+ TNodeConfig extends RunnableNodeConfig<any, any>,
24
+ TInputSchema extends ZodSchemaAny,
25
+ TOutputSchema extends ZodSchemaAny,
26
+ >(
27
+ node: TNodeConfig,
28
+ options: Readonly<{ name?: string } & NodeBackedToolConfigOptions<TNodeConfig, TInputSchema, TOutputSchema>>,
29
+ ): Readonly<{ name?: string } & NodeBackedToolConfigOptions<TNodeConfig, TInputSchema, TOutputSchema>> {
30
+ if (options.mapInput || !AgentConfigInspector.isAgentNodeConfig(node)) {
31
+ return options;
32
+ }
33
+ return {
34
+ ...options,
35
+ mapInput: ({ input, item }) => this.mergeAgentToolInputWithCurrentItem(input, item) as never,
36
+ };
37
+ }
38
+
39
+ private mergeAgentToolInputWithCurrentItem(input: unknown, item: Item): unknown {
40
+ if (!this.isMergeableRecord(input) || !this.isMergeableRecord(item.json)) {
41
+ return input;
42
+ }
43
+ return {
44
+ ...item.json,
45
+ ...input,
46
+ };
47
+ }
48
+
49
+ private isMergeableRecord(value: unknown): value is Record<string, unknown> {
50
+ return typeof value === "object" && value !== null && !Array.isArray(value);
15
51
  }
16
52
  }
17
53
 
package/src/ai/AiHost.ts CHANGED
@@ -207,7 +207,7 @@ export interface AgentNodeConfig<TInputJson = unknown, TOutputJson = unknown> ex
207
207
  readonly guardrails?: AgentGuardrailConfig;
208
208
  }
209
209
 
210
- export type AgentAttachmentRole = "languageModel" | "tool";
210
+ export type AgentAttachmentRole = "languageModel" | "tool" | "nestedAgent";
211
211
 
212
212
  export { NodeBackedToolConfig } from "./NodeBackedToolConfig";
213
213
  export { AgentToolFactory } from "./AgentToolFactory";