@codemation/core 0.8.0 → 0.10.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.
- package/CHANGELOG.md +390 -0
- package/dist/{EngineRuntimeRegistration.types-BP6tsaNP.d.ts → EngineRuntimeRegistration.types-D1fyApMI.d.ts} +2 -2
- package/dist/{EngineWorkflowRunnerService-DzOCa1BW.d.cts → EngineRuntimeRegistration.types-pB3FnzqR.d.cts} +17 -17
- package/dist/{InMemoryRunDataFactory-1iz7_SnO.d.cts → InMemoryRunDataFactory-Xw7v4-sj.d.cts} +31 -29
- package/dist/InMemoryRunEventBusRegistry-VM3OWnHo.cjs +47 -0
- package/dist/InMemoryRunEventBusRegistry-VM3OWnHo.cjs.map +1 -0
- package/dist/InMemoryRunEventBusRegistry-sM4z4n_i.js +41 -0
- package/dist/InMemoryRunEventBusRegistry-sM4z4n_i.js.map +1 -0
- package/dist/{RunIntentService-BqhmdoA1.d.ts → RunIntentService-BE9CAkbf.d.ts} +966 -471
- package/dist/{RunIntentService-S-1lW-gS.d.cts → RunIntentService-siBSjaaY.d.cts} +859 -493
- package/dist/bootstrap/index.cjs +5 -2
- package/dist/bootstrap/index.d.cts +212 -135
- package/dist/bootstrap/index.d.ts +4 -4
- package/dist/bootstrap/index.js +3 -3
- package/dist/{bootstrap-BaN6hZ5I.cjs → bootstrap-Cm5ruQxx.cjs} +263 -12
- package/dist/bootstrap-Cm5ruQxx.cjs.map +1 -0
- package/dist/bootstrap-D3r505ko.js +454 -0
- package/dist/bootstrap-D3r505ko.js.map +1 -0
- package/dist/{index-CVs9rVhl.d.ts → index-DeLl1Tne.d.ts} +632 -230
- package/dist/index.cjs +323 -176
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +544 -91
- package/dist/index.d.ts +3 -3
- package/dist/index.js +299 -166
- package/dist/index.js.map +1 -1
- package/dist/{runtime-DUW6tIJ1.js → runtime-BGNbRnqs.js} +934 -75
- package/dist/runtime-BGNbRnqs.js.map +1 -0
- package/dist/{runtime-Dvo2ru5A.cjs → runtime-DKXJwTNv.cjs} +1028 -73
- package/dist/runtime-DKXJwTNv.cjs.map +1 -0
- package/dist/testing.cjs +5 -5
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +4 -4
- package/dist/testing.js.map +1 -1
- package/package.json +7 -2
- package/src/ai/AiHost.ts +42 -14
- package/src/authoring/DefinedCollectionRegistry.ts +17 -0
- package/src/authoring/defineCollection.types.ts +181 -0
- package/src/authoring/definePollingTrigger.types.ts +396 -0
- package/src/authoring/definePollingTriggerInternals.ts +74 -0
- package/src/authoring/index.ts +19 -0
- package/src/bootstrap/index.ts +9 -0
- package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +21 -14
- package/src/browser.ts +1 -0
- package/src/contracts/CodemationTelemetryAttributeNames.ts +6 -0
- package/src/contracts/NoOpNodeExecutionTelemetry.ts +2 -11
- package/src/contracts/NoOpTelemetrySpanScope.ts +46 -10
- package/src/contracts/assertionTypes.ts +63 -0
- package/src/contracts/baseTypes.ts +12 -0
- package/src/contracts/collectionTypes.ts +44 -0
- package/src/contracts/credentialTypes.ts +23 -1
- package/src/contracts/executionPersistenceContracts.ts +30 -0
- package/src/contracts/index.ts +4 -0
- package/src/contracts/runTypes.ts +37 -1
- package/src/contracts/runtimeTypes.ts +42 -0
- package/src/contracts/telemetryTypes.ts +8 -0
- package/src/contracts/testTriggerTypes.ts +66 -0
- package/src/contracts/workflowTypes.ts +36 -7
- package/src/contracts.ts +59 -0
- package/src/events/ConnectionInvocationEventPublisher.ts +46 -0
- package/src/events/index.ts +1 -0
- package/src/events/runEvents.ts +74 -0
- package/src/execution/ChildExecutionScopeFactory.ts +55 -0
- package/src/execution/DefaultExecutionContextFactory.ts +6 -0
- package/src/execution/ExecutionTelemetryCostTrackingDecoratorFactory.ts +18 -0
- package/src/execution/NodeExecutor.ts +10 -2
- package/src/execution/NodeInstanceFactory.ts +13 -1
- package/src/execution/NodeInstantiationError.ts +16 -0
- package/src/execution/NodeRunStateWriter.ts +7 -0
- package/src/execution/NodeRunStateWriterFactory.ts +7 -0
- package/src/execution/WorkflowRunExecutionContextFactory.ts +3 -0
- package/src/execution/index.ts +2 -0
- package/src/index.ts +8 -0
- package/src/orchestration/AbortControllerFactory.ts +9 -0
- package/src/orchestration/NodeExecutionRequestHandlerService.ts +1 -0
- package/src/orchestration/RunContinuationService.ts +3 -0
- package/src/orchestration/RunStartService.ts +122 -3
- package/src/orchestration/TestSuiteOrchestrator.ts +350 -0
- package/src/orchestration/TestSuiteRunIdFactory.ts +11 -0
- package/src/orchestration/TriggerRuntimeService.ts +34 -7
- package/src/orchestration/index.ts +9 -0
- package/src/runtime/EngineFactory.ts +12 -0
- package/src/testing/WorkflowTestKitNodeRegistrationContextFactory.ts +1 -3
- package/src/triggers/polling/PollingTriggerDedupWindow.ts +23 -0
- package/src/triggers/polling/PollingTriggerLogger.ts +18 -0
- package/src/triggers/polling/PollingTriggerRuntime.ts +122 -0
- package/src/triggers/polling/index.ts +5 -0
- package/src/types/index.ts +12 -9
- package/src/workflow/definition/NodeIterationIdFactory.ts +26 -0
- package/src/workflow/dsl/NodeIdSlugifier.ts +18 -0
- package/src/workflow/dsl/WorkflowBuilder.ts +71 -3
- package/src/workflow/dsl/WorkflowDefinitionError.ts +15 -0
- package/src/workflow/index.ts +3 -0
- package/dist/InMemoryRunEventBusRegistry-B0_C4OnP.cjs +0 -262
- package/dist/InMemoryRunEventBusRegistry-B0_C4OnP.cjs.map +0 -1
- package/dist/InMemoryRunEventBusRegistry-C2U83Hmv.js +0 -238
- package/dist/InMemoryRunEventBusRegistry-C2U83Hmv.js.map +0 -1
- package/dist/bootstrap-BaN6hZ5I.cjs.map +0 -1
- package/dist/bootstrap-d_BMaDT4.js +0 -221
- package/dist/bootstrap-d_BMaDT4.js.map +0 -1
- package/dist/runtime-DUW6tIJ1.js.map +0 -1
- package/dist/runtime-Dvo2ru5A.cjs.map +0 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
import { container as container$1, delay, inject, injectAll, injectable, instanceCachingFactory, instancePerContainerCachingFactory, predicateAwareClassFactory, registry, singleton } from "tsyringe";
|
|
3
3
|
import { ZodError, z } from "zod";
|
|
4
|
-
import { createHash } from "node:crypto";
|
|
4
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
5
5
|
import { ReadableStream } from "node:stream/web";
|
|
6
6
|
|
|
7
7
|
//#region src/di/CoreTokens.ts
|
|
@@ -137,6 +137,56 @@ function chatModel(options = {}) {
|
|
|
137
137
|
return InjectableRuntimeDecoratorComposer.compose("chatModel", options, import.meta.url);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
//#endregion
|
|
141
|
+
//#region src/ai/NodeBackedToolConfig.ts
|
|
142
|
+
var NodeBackedToolConfig = class {
|
|
143
|
+
type;
|
|
144
|
+
toolKind = "nodeBacked";
|
|
145
|
+
description;
|
|
146
|
+
presentation;
|
|
147
|
+
inputSchemaValue;
|
|
148
|
+
outputSchemaValue;
|
|
149
|
+
mapInputValue;
|
|
150
|
+
mapOutputValue;
|
|
151
|
+
constructor(name, node$1, options) {
|
|
152
|
+
this.name = name;
|
|
153
|
+
this.node = node$1;
|
|
154
|
+
this.type = node$1.type;
|
|
155
|
+
this.description = options.description;
|
|
156
|
+
this.presentation = options.presentation;
|
|
157
|
+
this.inputSchemaValue = options.inputSchema;
|
|
158
|
+
this.outputSchemaValue = options.outputSchema;
|
|
159
|
+
this.mapInputValue = options.mapInput;
|
|
160
|
+
this.mapOutputValue = options.mapOutput;
|
|
161
|
+
}
|
|
162
|
+
getCredentialRequirements() {
|
|
163
|
+
return this.node.getCredentialRequirements?.() ?? [];
|
|
164
|
+
}
|
|
165
|
+
getInputSchema() {
|
|
166
|
+
return this.inputSchemaValue;
|
|
167
|
+
}
|
|
168
|
+
getOutputSchema() {
|
|
169
|
+
return this.outputSchemaValue;
|
|
170
|
+
}
|
|
171
|
+
toNodeItem(args) {
|
|
172
|
+
const mapped = this.mapInputValue?.(args) ?? args.input;
|
|
173
|
+
if (this.isItem(mapped)) return mapped;
|
|
174
|
+
return { json: mapped };
|
|
175
|
+
}
|
|
176
|
+
toToolOutput(args) {
|
|
177
|
+
const raw = this.mapOutputValue?.(args) ?? this.readDefaultToolOutput(args.outputs);
|
|
178
|
+
return this.outputSchemaValue.parse(raw);
|
|
179
|
+
}
|
|
180
|
+
readDefaultToolOutput(outputs) {
|
|
181
|
+
const firstMainItem = outputs.main?.[0];
|
|
182
|
+
if (!firstMainItem) throw new Error(`Node-backed tool "${this.name}" did not produce a main output item.`);
|
|
183
|
+
return firstMainItem.json;
|
|
184
|
+
}
|
|
185
|
+
isItem(value) {
|
|
186
|
+
return typeof value === "object" && value !== null && "json" in value;
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
140
190
|
//#endregion
|
|
141
191
|
//#region src/contracts/itemExpr.ts
|
|
142
192
|
const ITEM_EXPR_BRAND = Symbol.for("codemation.itemExpr");
|
|
@@ -205,6 +255,27 @@ async function resolveItemExprsForExecution(config, nodeCtx, item, itemIndex, it
|
|
|
205
255
|
return await resolveItemExprsInUnknown(config, exprArgs);
|
|
206
256
|
}
|
|
207
257
|
|
|
258
|
+
//#endregion
|
|
259
|
+
//#region src/ai/AgentConfigInspectorFactory.ts
|
|
260
|
+
var AgentConfigInspector = class {
|
|
261
|
+
static isAgentNodeConfig(config) {
|
|
262
|
+
if (!config) return false;
|
|
263
|
+
const candidate = config;
|
|
264
|
+
return !!candidate.chatModel && this.hasCompatibleMessageConfiguration(candidate);
|
|
265
|
+
}
|
|
266
|
+
static hasCompatibleMessageConfiguration(candidate) {
|
|
267
|
+
const messages = candidate.messages;
|
|
268
|
+
if (messages === void 0 || messages === null) return false;
|
|
269
|
+
if (Array.isArray(messages)) return messages.length > 0;
|
|
270
|
+
if (typeof messages === "object") {
|
|
271
|
+
if (isItemExpr(messages)) return true;
|
|
272
|
+
const o = messages;
|
|
273
|
+
return Array.isArray(o.prompt) && o.prompt.length > 0 || typeof o.buildMessages === "function";
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
|
|
208
279
|
//#endregion
|
|
209
280
|
//#region src/workflow/definition/ConnectionNodeIdFactory.ts
|
|
210
281
|
/**
|
|
@@ -255,6 +326,369 @@ var ConnectionNodeIdFactory = class {
|
|
|
255
326
|
}
|
|
256
327
|
};
|
|
257
328
|
|
|
329
|
+
//#endregion
|
|
330
|
+
//#region src/ai/AgentConnectionNodeCollector.ts
|
|
331
|
+
const AgentConnectionNodeCollector = new class {
|
|
332
|
+
collect(parentNodeId, agentConfig) {
|
|
333
|
+
const collected = [];
|
|
334
|
+
this.collectInto(parentNodeId, agentConfig, collected);
|
|
335
|
+
return collected;
|
|
336
|
+
}
|
|
337
|
+
collectInto(parentNodeId, agentConfig, collected) {
|
|
338
|
+
collected.push({
|
|
339
|
+
nodeId: ConnectionNodeIdFactory.languageModelConnectionNodeId(parentNodeId),
|
|
340
|
+
parentNodeId,
|
|
341
|
+
connectionName: "llm",
|
|
342
|
+
role: "languageModel",
|
|
343
|
+
name: agentConfig.chatModel.presentation?.label ?? agentConfig.chatModel.name,
|
|
344
|
+
typeName: agentConfig.chatModel.name,
|
|
345
|
+
icon: agentConfig.chatModel.presentation?.icon,
|
|
346
|
+
credentialSource: agentConfig.chatModel
|
|
347
|
+
});
|
|
348
|
+
for (const tool$1 of agentConfig.tools ?? []) {
|
|
349
|
+
const toolNodeId = ConnectionNodeIdFactory.toolConnectionNodeId(parentNodeId, tool$1.name);
|
|
350
|
+
const isNestedAgent = this.isNodeBackedAgentTool(tool$1);
|
|
351
|
+
collected.push({
|
|
352
|
+
nodeId: toolNodeId,
|
|
353
|
+
parentNodeId,
|
|
354
|
+
connectionName: "tools",
|
|
355
|
+
role: isNestedAgent ? "nestedAgent" : "tool",
|
|
356
|
+
name: tool$1.presentation?.label ?? tool$1.name,
|
|
357
|
+
typeName: tool$1.name,
|
|
358
|
+
icon: tool$1.presentation?.icon,
|
|
359
|
+
credentialSource: tool$1
|
|
360
|
+
});
|
|
361
|
+
this.collectNestedAgentTools(toolNodeId, tool$1, collected);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
collectNestedAgentTools(toolNodeId, tool$1, collected) {
|
|
365
|
+
if (!this.isNodeBackedAgentTool(tool$1)) return;
|
|
366
|
+
const innerAgent = tool$1 instanceof NodeBackedToolConfig ? tool$1.node : tool$1.node;
|
|
367
|
+
this.collectInto(toolNodeId, innerAgent, collected);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* After JSON round-trip (persisted snapshots), tools are plain objects — `instanceof NodeBackedToolConfig` fails.
|
|
371
|
+
* Detect node-backed tools structurally via {@link NodeBackedToolConfig#toolKind}.
|
|
372
|
+
*/
|
|
373
|
+
isNodeBackedAgentTool(tool$1) {
|
|
374
|
+
if (tool$1 instanceof NodeBackedToolConfig) return AgentConfigInspector.isAgentNodeConfig(tool$1.node);
|
|
375
|
+
if (!tool$1 || typeof tool$1 !== "object") return false;
|
|
376
|
+
const t = tool$1;
|
|
377
|
+
if (t.toolKind !== "nodeBacked") return false;
|
|
378
|
+
return AgentConfigInspector.isAgentNodeConfig(t.node);
|
|
379
|
+
}
|
|
380
|
+
}();
|
|
381
|
+
|
|
382
|
+
//#endregion
|
|
383
|
+
//#region src/workflow/dsl/WhenBuilder.ts
|
|
384
|
+
var WhenBuilder = class WhenBuilder {
|
|
385
|
+
constructor(wf, from, branchPort) {
|
|
386
|
+
this.wf = wf;
|
|
387
|
+
this.from = from;
|
|
388
|
+
this.branchPort = branchPort;
|
|
389
|
+
}
|
|
390
|
+
addBranch(steps) {
|
|
391
|
+
const created = [];
|
|
392
|
+
let prev = null;
|
|
393
|
+
for (const cfg of steps) {
|
|
394
|
+
const ref = this.wf.add(cfg);
|
|
395
|
+
created.push(ref);
|
|
396
|
+
if (!prev) this.wf.connect(this.from, ref, this.branchPort, "in");
|
|
397
|
+
else this.wf.connect(prev, ref, "main", "in");
|
|
398
|
+
prev = ref;
|
|
399
|
+
}
|
|
400
|
+
for (const cfg of steps) {
|
|
401
|
+
const maybe = cfg;
|
|
402
|
+
if (!Array.isArray(maybe.upstreamRefs) || maybe.upstreamRefs.length === 0) continue;
|
|
403
|
+
maybe.upstreamRefs = maybe.upstreamRefs.map((r) => {
|
|
404
|
+
if (typeof r !== "string") return r;
|
|
405
|
+
const nodeId = created[parseInt(r.slice(1), 10)]?.id;
|
|
406
|
+
return nodeId ? { nodeId } : { nodeId: r };
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
return this;
|
|
410
|
+
}
|
|
411
|
+
when = (branch, steps, ...more) => {
|
|
412
|
+
const list = Array.isArray(steps) ? steps : [steps, ...more];
|
|
413
|
+
const port = branch ? "true" : "false";
|
|
414
|
+
const b = new WhenBuilder(this.wf, this.from, port);
|
|
415
|
+
b.addBranch(list);
|
|
416
|
+
return b;
|
|
417
|
+
};
|
|
418
|
+
build() {
|
|
419
|
+
return this.wf.build();
|
|
420
|
+
}
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
//#endregion
|
|
424
|
+
//#region src/workflow/dsl/ChainCursorResolver.ts
|
|
425
|
+
var ChainCursor = class ChainCursor {
|
|
426
|
+
constructor(wf, endpoints) {
|
|
427
|
+
this.wf = wf;
|
|
428
|
+
this.endpoints = endpoints;
|
|
429
|
+
}
|
|
430
|
+
then(config) {
|
|
431
|
+
const next = this.wf.add(config);
|
|
432
|
+
const inputPortHint = this.resolveSharedInputPortHint();
|
|
433
|
+
for (const e of this.endpoints) this.wf.connect(e.node, next, e.output);
|
|
434
|
+
return new ChainCursor(this.wf, [{
|
|
435
|
+
node: next,
|
|
436
|
+
output: "main",
|
|
437
|
+
...inputPortHint ? { inputPortHint } : {}
|
|
438
|
+
}]);
|
|
439
|
+
}
|
|
440
|
+
thenIntoInputHints(config) {
|
|
441
|
+
const next = this.wf.add(config);
|
|
442
|
+
for (const e of this.endpoints) this.wf.connect(e.node, next, e.output, e.inputPortHint ?? "in");
|
|
443
|
+
return new ChainCursor(this.wf, [{
|
|
444
|
+
node: next,
|
|
445
|
+
output: "main"
|
|
446
|
+
}]);
|
|
447
|
+
}
|
|
448
|
+
when = ((arg1, steps, ...more) => {
|
|
449
|
+
if (this.endpoints.length !== 1) throw new Error("ChainCursor.when(...) is only supported from a single cursor endpoint");
|
|
450
|
+
const cursor = this.endpoints[0].node;
|
|
451
|
+
if (typeof arg1 === "boolean") {
|
|
452
|
+
const list = Array.isArray(steps) ? steps : steps ? [steps, ...more] : more;
|
|
453
|
+
const port = arg1 ? "true" : "false";
|
|
454
|
+
const b = new WhenBuilder(this.wf, cursor, port);
|
|
455
|
+
b.addBranch(list);
|
|
456
|
+
return b;
|
|
457
|
+
}
|
|
458
|
+
const branches = arg1;
|
|
459
|
+
const wfAny = this.wf;
|
|
460
|
+
const buildBranch = (port, branchSteps) => {
|
|
461
|
+
const list = branchSteps ?? [];
|
|
462
|
+
let prev = null;
|
|
463
|
+
for (const cfg of list) {
|
|
464
|
+
const ref = wfAny.add(cfg);
|
|
465
|
+
if (!prev) wfAny.connect(cursor, ref, port, "in");
|
|
466
|
+
else wfAny.connect(prev, ref, "main", "in");
|
|
467
|
+
prev = ref;
|
|
468
|
+
}
|
|
469
|
+
if (!prev) return {
|
|
470
|
+
end: cursor,
|
|
471
|
+
endOutput: port,
|
|
472
|
+
inputPortHint: port
|
|
473
|
+
};
|
|
474
|
+
return {
|
|
475
|
+
end: prev,
|
|
476
|
+
endOutput: "main",
|
|
477
|
+
inputPortHint: port
|
|
478
|
+
};
|
|
479
|
+
};
|
|
480
|
+
const t = buildBranch("true", branches.true);
|
|
481
|
+
const f = buildBranch("false", branches.false);
|
|
482
|
+
return new ChainCursor(this.wf, [{
|
|
483
|
+
node: t.end,
|
|
484
|
+
output: t.endOutput,
|
|
485
|
+
inputPortHint: t.inputPortHint
|
|
486
|
+
}, {
|
|
487
|
+
node: f.end,
|
|
488
|
+
output: f.endOutput,
|
|
489
|
+
inputPortHint: f.inputPortHint
|
|
490
|
+
}]);
|
|
491
|
+
});
|
|
492
|
+
route(branches) {
|
|
493
|
+
if (this.endpoints.length !== 1) throw new Error("ChainCursor.route(...) is only supported from a single cursor endpoint");
|
|
494
|
+
const cursor = this.endpoints[0];
|
|
495
|
+
const nextEndpoints = [];
|
|
496
|
+
for (const [port, branchFactory] of Object.entries(branches)) {
|
|
497
|
+
if (!branchFactory) continue;
|
|
498
|
+
const builtBranch = branchFactory(new ChainCursor(this.wf, [{
|
|
499
|
+
node: cursor.node,
|
|
500
|
+
output: port,
|
|
501
|
+
inputPortHint: port
|
|
502
|
+
}]));
|
|
503
|
+
if (!builtBranch) continue;
|
|
504
|
+
nextEndpoints.push(...builtBranch.endpoints);
|
|
505
|
+
}
|
|
506
|
+
return new ChainCursor(this.wf, nextEndpoints);
|
|
507
|
+
}
|
|
508
|
+
build() {
|
|
509
|
+
return this.wf.build();
|
|
510
|
+
}
|
|
511
|
+
resolveSharedInputPortHint() {
|
|
512
|
+
const first = this.endpoints[0]?.inputPortHint;
|
|
513
|
+
if (!first) return;
|
|
514
|
+
return this.endpoints.every((endpoint) => endpoint.inputPortHint === first) ? first : void 0;
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
//#endregion
|
|
519
|
+
//#region src/workflow/dsl/NodeIdSlugifier.ts
|
|
520
|
+
/**
|
|
521
|
+
* Converts a human-readable node label into a stable, URL-safe identifier segment.
|
|
522
|
+
*
|
|
523
|
+
* Rules:
|
|
524
|
+
* - Lowercase the entire string.
|
|
525
|
+
* - Replace every run of characters outside `[a-z0-9]` with a single `-`.
|
|
526
|
+
* - Strip any leading or trailing `-` characters.
|
|
527
|
+
* - Return `""` for blank/empty input.
|
|
528
|
+
*/
|
|
529
|
+
const NodeIdSlugifier = { slugify(label) {
|
|
530
|
+
if (!label) return "";
|
|
531
|
+
return label.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
532
|
+
} };
|
|
533
|
+
|
|
534
|
+
//#endregion
|
|
535
|
+
//#region src/workflow/dsl/WorkflowDefinitionError.ts
|
|
536
|
+
/**
|
|
537
|
+
* Thrown by {@link WorkflowBuilder.build} when the workflow definition is structurally invalid.
|
|
538
|
+
*
|
|
539
|
+
* Common causes:
|
|
540
|
+
* - A node has an empty effective id (label is blank and no explicit `id` was given).
|
|
541
|
+
* - Two or more nodes share the same effective id (label slugs collide or explicit ids clash).
|
|
542
|
+
*
|
|
543
|
+
* Fix: provide an explicit `id:` on the offending node configs.
|
|
544
|
+
*/
|
|
545
|
+
var WorkflowDefinitionError = class extends Error {
|
|
546
|
+
constructor(message) {
|
|
547
|
+
super(message);
|
|
548
|
+
this.name = "WorkflowDefinitionError";
|
|
549
|
+
}
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
//#endregion
|
|
553
|
+
//#region src/workflow/dsl/WorkflowBuilder.ts
|
|
554
|
+
var WorkflowBuilder = class {
|
|
555
|
+
nodes = [];
|
|
556
|
+
edges = [];
|
|
557
|
+
constructor(meta, options) {
|
|
558
|
+
this.meta = meta;
|
|
559
|
+
this.options = options;
|
|
560
|
+
}
|
|
561
|
+
add(config) {
|
|
562
|
+
const id = config.id ?? NodeIdSlugifier.slugify(config.name ?? "");
|
|
563
|
+
this.nodes.push({
|
|
564
|
+
id,
|
|
565
|
+
kind: config.kind,
|
|
566
|
+
type: config.type,
|
|
567
|
+
name: config.name,
|
|
568
|
+
config
|
|
569
|
+
});
|
|
570
|
+
return {
|
|
571
|
+
id,
|
|
572
|
+
kind: config.kind,
|
|
573
|
+
name: config.name
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
connect(from, to, fromOutput = "main", toInput = "in") {
|
|
577
|
+
this.edges.push({
|
|
578
|
+
from: {
|
|
579
|
+
nodeId: from.id,
|
|
580
|
+
output: fromOutput
|
|
581
|
+
},
|
|
582
|
+
to: {
|
|
583
|
+
nodeId: to.id,
|
|
584
|
+
input: toInput
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
trigger(config) {
|
|
589
|
+
const ref = this.add(config);
|
|
590
|
+
return new ChainCursor(this, [{
|
|
591
|
+
node: ref,
|
|
592
|
+
output: "main"
|
|
593
|
+
}]);
|
|
594
|
+
}
|
|
595
|
+
start(config) {
|
|
596
|
+
const ref = this.add(config);
|
|
597
|
+
return new ChainCursor(this, [{
|
|
598
|
+
node: ref,
|
|
599
|
+
output: "main"
|
|
600
|
+
}]);
|
|
601
|
+
}
|
|
602
|
+
build() {
|
|
603
|
+
this.validateNodeIds();
|
|
604
|
+
return {
|
|
605
|
+
...this.meta,
|
|
606
|
+
nodes: this.nodes,
|
|
607
|
+
edges: this.edges
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
validateNodeIds() {
|
|
611
|
+
const entries = [];
|
|
612
|
+
for (const node$1 of this.nodes) {
|
|
613
|
+
const tokenName = typeof node$1.type === "function" ? node$1.type.name : String(node$1.type);
|
|
614
|
+
entries.push({
|
|
615
|
+
nodeId: node$1.id,
|
|
616
|
+
tokenName,
|
|
617
|
+
label: node$1.name ?? ""
|
|
618
|
+
});
|
|
619
|
+
if (AgentConfigInspector.isAgentNodeConfig(node$1.config)) for (const child of AgentConnectionNodeCollector.collect(node$1.id, node$1.config)) entries.push({
|
|
620
|
+
nodeId: child.nodeId,
|
|
621
|
+
tokenName: child.typeName,
|
|
622
|
+
label: child.name
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
const emptyIds = [];
|
|
626
|
+
const seenIds = /* @__PURE__ */ new Map();
|
|
627
|
+
const duplicateIds = [];
|
|
628
|
+
for (const entry of entries) {
|
|
629
|
+
if (!entry.nodeId) {
|
|
630
|
+
emptyIds.push(entry);
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
const existing = seenIds.get(entry.nodeId);
|
|
634
|
+
if (existing) {
|
|
635
|
+
if (!duplicateIds.includes(existing)) duplicateIds.push(existing);
|
|
636
|
+
duplicateIds.push(entry);
|
|
637
|
+
} else seenIds.set(entry.nodeId, entry);
|
|
638
|
+
}
|
|
639
|
+
if (emptyIds.length === 0 && duplicateIds.length === 0) return;
|
|
640
|
+
const lines = ["WorkflowBuilder.build() found invalid node ids:"];
|
|
641
|
+
if (emptyIds.length > 0) {
|
|
642
|
+
lines.push(" Empty ids (label is blank and no explicit id was given):");
|
|
643
|
+
for (const e of emptyIds) lines.push(` - type "${e.tokenName}" label "${e.label}"`);
|
|
644
|
+
}
|
|
645
|
+
if (duplicateIds.length > 0) {
|
|
646
|
+
lines.push(" Duplicate ids:");
|
|
647
|
+
for (const e of duplicateIds) lines.push(` - id "${e.nodeId}" type "${e.tokenName}" label "${e.label}"`);
|
|
648
|
+
}
|
|
649
|
+
lines.push(" Fix: set an explicit `id:` on each offending node config.");
|
|
650
|
+
throw new WorkflowDefinitionError(lines.join("\n"));
|
|
651
|
+
}
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
//#endregion
|
|
655
|
+
//#region src/workflow/definition/ConnectionInvocationIdFactory.ts
|
|
656
|
+
/**
|
|
657
|
+
* Unique ids for persisted connection invocation history rows (LLM/tool calls under an owning node).
|
|
658
|
+
*/
|
|
659
|
+
var ConnectionInvocationIdFactory = class {
|
|
660
|
+
static create() {
|
|
661
|
+
return `cinv_${randomUUID()}`;
|
|
662
|
+
}
|
|
663
|
+
/** Deterministic id for tests when a stable sequence is needed. */
|
|
664
|
+
static createForTest(runId, connectionNodeId, sequence) {
|
|
665
|
+
return `cinv_${runId}_${connectionNodeId}_${sequence}`;
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
//#endregion
|
|
670
|
+
//#region src/workflow/definition/NodeIterationIdFactory.ts
|
|
671
|
+
/**
|
|
672
|
+
* Unique ids for one per-item iteration of a runnable node's execute loop.
|
|
673
|
+
*
|
|
674
|
+
* Activations are per-batch (one scheduled execution of a node, possibly with N items).
|
|
675
|
+
* Iterations refine that to one identifier per item-index inside the batch loop, so per-item
|
|
676
|
+
* connection invocations and telemetry can be grouped without time-window heuristics.
|
|
677
|
+
*/
|
|
678
|
+
var NodeIterationIdFactory = class {
|
|
679
|
+
static create() {
|
|
680
|
+
return `iter_${randomUUID()}`;
|
|
681
|
+
}
|
|
682
|
+
/** Deterministic id for tests when a stable sequence is needed. */
|
|
683
|
+
static createForTest(seed, sequence) {
|
|
684
|
+
return `iter_${seed}_${sequence}`;
|
|
685
|
+
}
|
|
686
|
+
/** Deterministic id derived from a connection node id (for sub-agent / tool-call scopes). */
|
|
687
|
+
static createForConnection(connectionNodeId, sequence) {
|
|
688
|
+
return `iter_${connectionNodeId}_${sequence}`;
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
|
|
258
692
|
//#endregion
|
|
259
693
|
//#region src/workflow/definition/WorkflowExecutableNodeClassifier.ts
|
|
260
694
|
/**
|
|
@@ -315,6 +749,69 @@ var WorkflowExecutableNodeClassifierFactory = class {
|
|
|
315
749
|
}
|
|
316
750
|
};
|
|
317
751
|
|
|
752
|
+
//#endregion
|
|
753
|
+
//#region src/workflow/graph/ExecutableGraph.ts
|
|
754
|
+
var ExecutableGraph = class {
|
|
755
|
+
outgoingByNodeAndPort = /* @__PURE__ */ new Map();
|
|
756
|
+
constructor(def) {
|
|
757
|
+
for (const e of def.edges) {
|
|
758
|
+
const byPort = this.outgoingByNodeAndPort.get(e.from.nodeId) ?? /* @__PURE__ */ new Map();
|
|
759
|
+
const next = byPort.get(e.from.output) ?? [];
|
|
760
|
+
next.push({
|
|
761
|
+
nodeId: e.to.nodeId,
|
|
762
|
+
input: e.to.input
|
|
763
|
+
});
|
|
764
|
+
byPort.set(e.from.output, next);
|
|
765
|
+
this.outgoingByNodeAndPort.set(e.from.nodeId, byPort);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
next(nodeId, output$1) {
|
|
769
|
+
return this.outgoingByNodeAndPort.get(nodeId)?.get(output$1) ?? [];
|
|
770
|
+
}
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
//#endregion
|
|
774
|
+
//#region src/workflow/graph/DefaultWorkflowGraphFactory.ts
|
|
775
|
+
var DefaultWorkflowGraphFactory = class {
|
|
776
|
+
create(def) {
|
|
777
|
+
return new ExecutableGraph(def);
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
|
|
781
|
+
//#endregion
|
|
782
|
+
//#region src/events/ConnectionInvocationEventPublisher.ts
|
|
783
|
+
/**
|
|
784
|
+
* Publishes per-invocation lifecycle records onto the run {@link RunEventBus}.
|
|
785
|
+
*
|
|
786
|
+
* Surgical, per-invocation events let the UI update the right-side inspector
|
|
787
|
+
* timeline as each LLM round / tool call transitions through `running` → `completed`
|
|
788
|
+
* (or `failed`) without depending on a coarse `runSaved` poll.
|
|
789
|
+
*/
|
|
790
|
+
var ConnectionInvocationEventPublisher = class {
|
|
791
|
+
constructor(eventBus, parent) {
|
|
792
|
+
this.eventBus = eventBus;
|
|
793
|
+
this.parent = parent;
|
|
794
|
+
}
|
|
795
|
+
async publish(record) {
|
|
796
|
+
if (!this.eventBus) return;
|
|
797
|
+
const kind = this.kindFor(record);
|
|
798
|
+
if (!kind) return;
|
|
799
|
+
await this.eventBus.publish({
|
|
800
|
+
kind,
|
|
801
|
+
runId: record.runId,
|
|
802
|
+
workflowId: record.workflowId,
|
|
803
|
+
parent: this.parent,
|
|
804
|
+
at: record.updatedAt,
|
|
805
|
+
record
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
kindFor(record) {
|
|
809
|
+
if (record.status === "running" || record.status === "queued") return "connectionInvocationStarted";
|
|
810
|
+
if (record.status === "completed") return "connectionInvocationCompleted";
|
|
811
|
+
if (record.status === "failed") return "connectionInvocationFailed";
|
|
812
|
+
}
|
|
813
|
+
};
|
|
814
|
+
|
|
318
815
|
//#endregion
|
|
319
816
|
//#region src/events/NodeEventPublisher.ts
|
|
320
817
|
/** Publishes node lifecycle snapshots onto the run {@link RunEventBus}. */
|
|
@@ -633,6 +1130,48 @@ var ActivationEnqueueService = class {
|
|
|
633
1130
|
}
|
|
634
1131
|
};
|
|
635
1132
|
|
|
1133
|
+
//#endregion
|
|
1134
|
+
//#region src/execution/ChildExecutionScopeFactory.ts
|
|
1135
|
+
/**
|
|
1136
|
+
* Builds a re-rooted child execution context for sub-agent (and other deeply-nested) invocations.
|
|
1137
|
+
*
|
|
1138
|
+
* At the orchestrator's `agent.tool.call` boundary the inner runtime needs a ctx whose:
|
|
1139
|
+
* - `nodeId` is the tool's connection node id (so inner LLM/tool connection ids derive correctly),
|
|
1140
|
+
* - `activationId` is fresh (so its connection-invocation rows are uniquely identifiable),
|
|
1141
|
+
* - `telemetry` parents children under the tool-call span (not the orchestrator's node span),
|
|
1142
|
+
* - `binary` is scoped to the new (nodeId, activationId),
|
|
1143
|
+
* - `parentInvocationId` points back to the tool-call invocation for downstream lineage.
|
|
1144
|
+
*
|
|
1145
|
+
* Registered via factory in {@link EngineRuntimeRegistrar} so constructors stay free of parameter
|
|
1146
|
+
* decorators (Next/SWC and coverage tooling cannot parse them on in-repo sources).
|
|
1147
|
+
*/
|
|
1148
|
+
var ChildExecutionScopeFactory = class {
|
|
1149
|
+
constructor(activationIdFactory) {
|
|
1150
|
+
this.activationIdFactory = activationIdFactory;
|
|
1151
|
+
}
|
|
1152
|
+
forSubAgent(args) {
|
|
1153
|
+
const childActivationId = this.activationIdFactory.makeActivationId();
|
|
1154
|
+
const childTelemetry = args.parentSpan.asNodeTelemetry({
|
|
1155
|
+
nodeId: args.childNodeId,
|
|
1156
|
+
activationId: childActivationId
|
|
1157
|
+
});
|
|
1158
|
+
const childBinary = args.parentCtx.binary.forNode({
|
|
1159
|
+
nodeId: args.childNodeId,
|
|
1160
|
+
activationId: childActivationId
|
|
1161
|
+
});
|
|
1162
|
+
return {
|
|
1163
|
+
...args.parentCtx,
|
|
1164
|
+
nodeId: args.childNodeId,
|
|
1165
|
+
activationId: childActivationId,
|
|
1166
|
+
config: args.childConfig,
|
|
1167
|
+
telemetry: childTelemetry,
|
|
1168
|
+
binary: childBinary,
|
|
1169
|
+
parentInvocationId: args.parentInvocationId,
|
|
1170
|
+
iterationId: void 0
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
};
|
|
1174
|
+
|
|
636
1175
|
//#endregion
|
|
637
1176
|
//#region src/contracts/itemMeta.ts
|
|
638
1177
|
/**
|
|
@@ -773,6 +1312,20 @@ var NodeActivationRequestInputPreparer = class {
|
|
|
773
1312
|
}
|
|
774
1313
|
};
|
|
775
1314
|
|
|
1315
|
+
//#endregion
|
|
1316
|
+
//#region src/execution/NodeInstantiationError.ts
|
|
1317
|
+
var NodeInstantiationError = class extends Error {
|
|
1318
|
+
name = "NodeInstantiationError";
|
|
1319
|
+
originalError;
|
|
1320
|
+
constructor(nodeId, nodeType, originalError) {
|
|
1321
|
+
super(`Failed to instantiate node "${nodeId}" (type ${nodeType}): ${originalError.message}`);
|
|
1322
|
+
this.nodeId = nodeId;
|
|
1323
|
+
this.nodeType = nodeType;
|
|
1324
|
+
this.originalError = originalError;
|
|
1325
|
+
this.stack = originalError.stack;
|
|
1326
|
+
}
|
|
1327
|
+
};
|
|
1328
|
+
|
|
776
1329
|
//#endregion
|
|
777
1330
|
//#region src/execution/CredentialResolverFactory.ts
|
|
778
1331
|
var CredentialResolverFactory = class {
|
|
@@ -933,31 +1486,54 @@ var NoOpTelemetryArtifactReference = class {
|
|
|
933
1486
|
|
|
934
1487
|
//#endregion
|
|
935
1488
|
//#region src/contracts/NoOpTelemetrySpanScope.ts
|
|
1489
|
+
/**
|
|
1490
|
+
* Standalone no-op {@link NodeExecutionTelemetry} value used as the return for `asNodeTelemetry`.
|
|
1491
|
+
*
|
|
1492
|
+
* Defined here (instead of in `NoOpNodeExecutionTelemetry.ts`) so that {@link NoOpTelemetrySpanScope}
|
|
1493
|
+
* can return it without importing the other module — both no-ops share this leaf.
|
|
1494
|
+
*/
|
|
1495
|
+
const noOpNodeExecutionTelemetry = {
|
|
1496
|
+
traceId: "00000000000000000000000000000000",
|
|
1497
|
+
spanId: "0000000000000000",
|
|
1498
|
+
addSpanEvent(_) {},
|
|
1499
|
+
recordMetric(_) {},
|
|
1500
|
+
attachArtifact(_) {
|
|
1501
|
+
return NoOpTelemetryArtifactReference.value;
|
|
1502
|
+
},
|
|
1503
|
+
end(_ = {}) {},
|
|
1504
|
+
asNodeTelemetry(_) {
|
|
1505
|
+
return noOpNodeExecutionTelemetry;
|
|
1506
|
+
},
|
|
1507
|
+
forNode(_) {
|
|
1508
|
+
return noOpNodeExecutionTelemetry;
|
|
1509
|
+
},
|
|
1510
|
+
startChildSpan(_) {
|
|
1511
|
+
return noOpTelemetrySpanScope;
|
|
1512
|
+
}
|
|
1513
|
+
};
|
|
1514
|
+
const noOpTelemetrySpanScope = {
|
|
1515
|
+
traceId: "00000000000000000000000000000000",
|
|
1516
|
+
spanId: "0000000000000000",
|
|
1517
|
+
addSpanEvent(_) {},
|
|
1518
|
+
recordMetric(_) {},
|
|
1519
|
+
attachArtifact(_) {
|
|
1520
|
+
return NoOpTelemetryArtifactReference.value;
|
|
1521
|
+
},
|
|
1522
|
+
end(_ = {}) {},
|
|
1523
|
+
asNodeTelemetry(_) {
|
|
1524
|
+
return noOpNodeExecutionTelemetry;
|
|
1525
|
+
}
|
|
1526
|
+
};
|
|
936
1527
|
var NoOpTelemetrySpanScope = class {
|
|
937
|
-
static value =
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
addSpanEvent(_) {},
|
|
941
|
-
recordMetric(_) {},
|
|
942
|
-
attachArtifact(_) {
|
|
943
|
-
return NoOpTelemetryArtifactReference.value;
|
|
944
|
-
},
|
|
945
|
-
end(_ = {}) {}
|
|
946
|
-
};
|
|
1528
|
+
static value = noOpTelemetrySpanScope;
|
|
1529
|
+
/** Internal: the shared no-op {@link NodeExecutionTelemetry} that {@link NoOpNodeExecutionTelemetry} re-exposes. */
|
|
1530
|
+
static nodeExecutionTelemetryValue = noOpNodeExecutionTelemetry;
|
|
947
1531
|
};
|
|
948
1532
|
|
|
949
1533
|
//#endregion
|
|
950
1534
|
//#region src/contracts/NoOpNodeExecutionTelemetry.ts
|
|
951
|
-
var NoOpNodeExecutionTelemetry = class
|
|
952
|
-
static value =
|
|
953
|
-
...NoOpTelemetrySpanScope.value,
|
|
954
|
-
forNode(_) {
|
|
955
|
-
return NoOpNodeExecutionTelemetry.value;
|
|
956
|
-
},
|
|
957
|
-
startChildSpan(_) {
|
|
958
|
-
return NoOpTelemetrySpanScope.value;
|
|
959
|
-
}
|
|
960
|
-
};
|
|
1535
|
+
var NoOpNodeExecutionTelemetry = class {
|
|
1536
|
+
static value = NoOpTelemetrySpanScope.nodeExecutionTelemetryValue;
|
|
961
1537
|
};
|
|
962
1538
|
|
|
963
1539
|
//#endregion
|
|
@@ -985,6 +1561,28 @@ var NoOpExecutionTelemetryFactory = class {
|
|
|
985
1561
|
}
|
|
986
1562
|
};
|
|
987
1563
|
|
|
1564
|
+
//#endregion
|
|
1565
|
+
//#region src/contracts/runFinishedAtFactory.ts
|
|
1566
|
+
/** Derives workflow end time from persisted run root or node snapshots for run listings. */
|
|
1567
|
+
var RunFinishedAtFactory = class {
|
|
1568
|
+
static resolveIso(state) {
|
|
1569
|
+
if (state.finishedAt && state.status !== "running" && state.status !== "pending") return state.finishedAt;
|
|
1570
|
+
if (state.status === "running" || state.status === "pending") return;
|
|
1571
|
+
let max;
|
|
1572
|
+
for (const snap of Object.values(state.nodeSnapshotsByNodeId)) if (snap?.finishedAt && (!max || snap.finishedAt > max)) max = snap.finishedAt;
|
|
1573
|
+
return max;
|
|
1574
|
+
}
|
|
1575
|
+
};
|
|
1576
|
+
|
|
1577
|
+
//#endregion
|
|
1578
|
+
//#region src/contracts/workflowActivationPolicy.ts
|
|
1579
|
+
/** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */
|
|
1580
|
+
var AllWorkflowsActiveWorkflowActivationPolicy = class {
|
|
1581
|
+
isActive(_workflowId) {
|
|
1582
|
+
return true;
|
|
1583
|
+
}
|
|
1584
|
+
};
|
|
1585
|
+
|
|
988
1586
|
//#endregion
|
|
989
1587
|
//#region src/contracts/CodemationTelemetryAttributeNames.ts
|
|
990
1588
|
var CodemationTelemetryAttributeNames = class {
|
|
@@ -998,6 +1596,12 @@ var CodemationTelemetryAttributeNames = class {
|
|
|
998
1596
|
static connectionInvocationId = "codemation.connection.invocation_id";
|
|
999
1597
|
static toolName = "codemation.tool.name";
|
|
1000
1598
|
static traceParentRunId = "codemation.parent.run.id";
|
|
1599
|
+
/** Per-item iteration that emitted this span/metric. Set on spans recorded inside a runnable per-item loop. */
|
|
1600
|
+
static iterationId = "codemation.iteration.id";
|
|
1601
|
+
/** Item index (0-based) of the iteration. */
|
|
1602
|
+
static iterationIndex = "codemation.iteration.index";
|
|
1603
|
+
/** Set when this span/metric was recorded under a sub-agent triggered by an outer LLM/tool call. */
|
|
1604
|
+
static parentInvocationId = "codemation.parent.invocation_id";
|
|
1001
1605
|
};
|
|
1002
1606
|
|
|
1003
1607
|
//#endregion
|
|
@@ -1023,19 +1627,6 @@ var CodemationTelemetryMetricNames = class {
|
|
|
1023
1627
|
static gmailAttachmentBytes = "codemation.gmail.attachment_bytes";
|
|
1024
1628
|
};
|
|
1025
1629
|
|
|
1026
|
-
//#endregion
|
|
1027
|
-
//#region src/contracts/runFinishedAtFactory.ts
|
|
1028
|
-
/** Derives workflow end time from persisted run root or node snapshots for run listings. */
|
|
1029
|
-
var RunFinishedAtFactory = class {
|
|
1030
|
-
static resolveIso(state) {
|
|
1031
|
-
if (state.finishedAt && state.status !== "running" && state.status !== "pending") return state.finishedAt;
|
|
1032
|
-
if (state.status === "running" || state.status === "pending") return;
|
|
1033
|
-
let max;
|
|
1034
|
-
for (const snap of Object.values(state.nodeSnapshotsByNodeId)) if (snap?.finishedAt && (!max || snap.finishedAt > max)) max = snap.finishedAt;
|
|
1035
|
-
return max;
|
|
1036
|
-
}
|
|
1037
|
-
};
|
|
1038
|
-
|
|
1039
1630
|
//#endregion
|
|
1040
1631
|
//#region src/contracts/workflowTypes.ts
|
|
1041
1632
|
function nodeRef(nodeId) {
|
|
@@ -1043,15 +1634,6 @@ function nodeRef(nodeId) {
|
|
|
1043
1634
|
}
|
|
1044
1635
|
const branchRef = (index) => `$${index}`;
|
|
1045
1636
|
|
|
1046
|
-
//#endregion
|
|
1047
|
-
//#region src/contracts/workflowActivationPolicy.ts
|
|
1048
|
-
/** Default for tests and harnesses: every workflow is treated as active (legacy behavior). */
|
|
1049
|
-
var AllWorkflowsActiveWorkflowActivationPolicy = class {
|
|
1050
|
-
isActive(_workflowId) {
|
|
1051
|
-
return true;
|
|
1052
|
-
}
|
|
1053
|
-
};
|
|
1054
|
-
|
|
1055
1637
|
//#endregion
|
|
1056
1638
|
//#region src/execution/ExecutionTelemetryCostTrackingDecoratorFactory.ts
|
|
1057
1639
|
var ExecutionTelemetryCostTrackingDecoratorFactory = class {
|
|
@@ -1091,6 +1673,13 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
|
|
|
1091
1673
|
telemetry: nodeTelemetry,
|
|
1092
1674
|
costTracking: args.costTracking.forScope(nodeTelemetry)
|
|
1093
1675
|
});
|
|
1676
|
+
},
|
|
1677
|
+
asNodeTelemetry: (rescope) => {
|
|
1678
|
+
const nodeTelemetry = args.telemetry.asNodeTelemetry(rescope);
|
|
1679
|
+
return this.decorateNodeExecutionTelemetry({
|
|
1680
|
+
telemetry: nodeTelemetry,
|
|
1681
|
+
costTracking: args.costTracking.forScope(nodeTelemetry)
|
|
1682
|
+
});
|
|
1094
1683
|
}
|
|
1095
1684
|
};
|
|
1096
1685
|
}
|
|
@@ -1102,7 +1691,14 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
|
|
|
1102
1691
|
addSpanEvent: (event) => args.scope.addSpanEvent(event),
|
|
1103
1692
|
recordMetric: (metric) => args.scope.recordMetric(metric),
|
|
1104
1693
|
attachArtifact: (artifact) => args.scope.attachArtifact(artifact),
|
|
1105
|
-
end: (endArgs) => args.scope.end(endArgs)
|
|
1694
|
+
end: (endArgs) => args.scope.end(endArgs),
|
|
1695
|
+
asNodeTelemetry: (rescope) => {
|
|
1696
|
+
const nodeTelemetry = args.scope.asNodeTelemetry(rescope);
|
|
1697
|
+
return this.decorateNodeExecutionTelemetry({
|
|
1698
|
+
telemetry: nodeTelemetry,
|
|
1699
|
+
costTracking: args.costTracking.forScope(nodeTelemetry)
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1106
1702
|
};
|
|
1107
1703
|
}
|
|
1108
1704
|
};
|
|
@@ -1111,11 +1707,12 @@ var ExecutionTelemetryCostTrackingDecoratorFactory = class {
|
|
|
1111
1707
|
//#region src/execution/DefaultExecutionContextFactory.ts
|
|
1112
1708
|
var DefaultExecutionContextFactory = class {
|
|
1113
1709
|
telemetryDecoratorFactory = new ExecutionTelemetryCostTrackingDecoratorFactory();
|
|
1114
|
-
constructor(binaryStorage = new UnavailableBinaryStorage(), telemetryFactory = new NoOpExecutionTelemetryFactory(), costTrackingFactory = new NoOpCostTrackingTelemetryFactory(), currentDate = () => /* @__PURE__ */ new Date()) {
|
|
1710
|
+
constructor(binaryStorage = new UnavailableBinaryStorage(), telemetryFactory = new NoOpExecutionTelemetryFactory(), costTrackingFactory = new NoOpCostTrackingTelemetryFactory(), currentDate = () => /* @__PURE__ */ new Date(), collections) {
|
|
1115
1711
|
this.binaryStorage = binaryStorage;
|
|
1116
1712
|
this.telemetryFactory = telemetryFactory;
|
|
1117
1713
|
this.costTrackingFactory = costTrackingFactory;
|
|
1118
1714
|
this.currentDate = currentDate;
|
|
1715
|
+
this.collections = collections;
|
|
1119
1716
|
}
|
|
1120
1717
|
create(args) {
|
|
1121
1718
|
const baseTelemetry = args.telemetry ?? this.telemetryFactory.create({
|
|
@@ -1140,7 +1737,9 @@ var DefaultExecutionContextFactory = class {
|
|
|
1140
1737
|
nodeState: args.nodeState,
|
|
1141
1738
|
telemetry,
|
|
1142
1739
|
binary: new DefaultExecutionBinaryService(this.binaryStorage, args.workflowId, args.runId, this.currentDate),
|
|
1143
|
-
getCredential: args.getCredential
|
|
1740
|
+
getCredential: args.getCredential,
|
|
1741
|
+
testContext: args.testContext,
|
|
1742
|
+
collections: this.collections
|
|
1144
1743
|
};
|
|
1145
1744
|
}
|
|
1146
1745
|
};
|
|
@@ -1573,13 +2172,17 @@ var NodeExecutor = class {
|
|
|
1573
2172
|
const parsed = inputSchema.parse(item.json);
|
|
1574
2173
|
const runnableCtx = request.ctx;
|
|
1575
2174
|
const resolvedCtx = await this.itemExprResolver.resolveConfigForItem(runnableCtx, item, i, inputBatch);
|
|
1576
|
-
const
|
|
2175
|
+
const iterationCtx = {
|
|
2176
|
+
...this.pickExecutionContext(runnableCtx, resolvedCtx),
|
|
2177
|
+
iterationId: NodeIterationIdFactory.create(),
|
|
2178
|
+
itemIndex: i
|
|
2179
|
+
};
|
|
1577
2180
|
const args = {
|
|
1578
2181
|
input: parsed,
|
|
1579
2182
|
item,
|
|
1580
2183
|
itemIndex: i,
|
|
1581
2184
|
items: inputBatch,
|
|
1582
|
-
ctx
|
|
2185
|
+
ctx: iterationCtx
|
|
1583
2186
|
};
|
|
1584
2187
|
const raw = await Promise.resolve(node$1.execute(args));
|
|
1585
2188
|
const normalized = this.outputNormalizer.normalizeExecuteResult({
|
|
@@ -1973,7 +2576,12 @@ var NodeInstanceFactory = class {
|
|
|
1973
2576
|
}
|
|
1974
2577
|
createNodes(workflow) {
|
|
1975
2578
|
const nodeInstances = /* @__PURE__ */ new Map();
|
|
1976
|
-
for (const definition of workflow.nodes)
|
|
2579
|
+
for (const definition of workflow.nodes) try {
|
|
2580
|
+
nodeInstances.set(definition.id, this.createNode(definition));
|
|
2581
|
+
} catch (err) {
|
|
2582
|
+
if (err instanceof NodeInstantiationError) throw err;
|
|
2583
|
+
throw new NodeInstantiationError(definition.id, typeof definition.type === "function" ? definition.type.name : String(definition.type), err instanceof Error ? err : new Error(String(err)));
|
|
2584
|
+
}
|
|
1977
2585
|
return nodeInstances;
|
|
1978
2586
|
}
|
|
1979
2587
|
createNode(definition) {
|
|
@@ -1998,12 +2606,13 @@ var NodeInstanceFactoryFactory = class {
|
|
|
1998
2606
|
//#region src/execution/NodeRunStateWriter.ts
|
|
1999
2607
|
var NodeRunStateWriter = class {
|
|
2000
2608
|
chain = Promise.resolve();
|
|
2001
|
-
constructor(workflowExecutionRepository, runId, workflowId, parent, publishNodeEvent) {
|
|
2609
|
+
constructor(workflowExecutionRepository, runId, workflowId, parent, publishNodeEvent, publishConnectionInvocationEvent) {
|
|
2002
2610
|
this.workflowExecutionRepository = workflowExecutionRepository;
|
|
2003
2611
|
this.runId = runId;
|
|
2004
2612
|
this.workflowId = workflowId;
|
|
2005
2613
|
this.parent = parent;
|
|
2006
2614
|
this.publishNodeEvent = publishNodeEvent;
|
|
2615
|
+
this.publishConnectionInvocationEvent = publishConnectionInvocationEvent;
|
|
2007
2616
|
}
|
|
2008
2617
|
markQueued(args) {
|
|
2009
2618
|
return this.enqueue(async () => {
|
|
@@ -2100,12 +2709,16 @@ var NodeRunStateWriter = class {
|
|
|
2100
2709
|
queuedAt: args.queuedAt,
|
|
2101
2710
|
startedAt: args.startedAt,
|
|
2102
2711
|
finishedAt: args.finishedAt,
|
|
2103
|
-
updatedAt
|
|
2712
|
+
updatedAt,
|
|
2713
|
+
iterationId: args.iterationId,
|
|
2714
|
+
itemIndex: args.itemIndex,
|
|
2715
|
+
parentInvocationId: args.parentInvocationId
|
|
2104
2716
|
};
|
|
2105
2717
|
await this.workflowExecutionRepository.save({
|
|
2106
2718
|
...state,
|
|
2107
2719
|
connectionInvocations: [...state.connectionInvocations ?? [], record]
|
|
2108
2720
|
});
|
|
2721
|
+
if (this.publishConnectionInvocationEvent) await this.publishConnectionInvocationEvent(record);
|
|
2109
2722
|
});
|
|
2110
2723
|
}
|
|
2111
2724
|
enqueue(work) {
|
|
@@ -2132,13 +2745,17 @@ var NodeRunStateWriter = class {
|
|
|
2132
2745
|
//#endregion
|
|
2133
2746
|
//#region src/execution/NodeRunStateWriterFactory.ts
|
|
2134
2747
|
var NodeRunStateWriterFactory = class {
|
|
2135
|
-
constructor(workflowExecutionRepository, nodeEventPublisher) {
|
|
2748
|
+
constructor(workflowExecutionRepository, nodeEventPublisher, eventBus) {
|
|
2136
2749
|
this.workflowExecutionRepository = workflowExecutionRepository;
|
|
2137
2750
|
this.nodeEventPublisher = nodeEventPublisher;
|
|
2751
|
+
this.eventBus = eventBus;
|
|
2138
2752
|
}
|
|
2139
2753
|
create(runId, workflowId, parent) {
|
|
2754
|
+
const connectionInvocationEventPublisher = new ConnectionInvocationEventPublisher(this.eventBus, parent);
|
|
2140
2755
|
return new NodeRunStateWriter(this.workflowExecutionRepository, runId, workflowId, parent, async (kind, snapshot) => {
|
|
2141
2756
|
await this.nodeEventPublisher.publish(kind, snapshot);
|
|
2757
|
+
}, async (record) => {
|
|
2758
|
+
await connectionInvocationEventPublisher.publish(record);
|
|
2142
2759
|
});
|
|
2143
2760
|
}
|
|
2144
2761
|
};
|
|
@@ -2263,7 +2880,8 @@ var WorkflowRunExecutionContextFactory = class {
|
|
|
2263
2880
|
engineMaxSubworkflowDepth: args.engineMaxSubworkflowDepth,
|
|
2264
2881
|
data: args.data,
|
|
2265
2882
|
nodeState: args.nodeState,
|
|
2266
|
-
getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId)
|
|
2883
|
+
getCredential: this.credentialResolverFactory.create(args.workflowId, args.nodeId),
|
|
2884
|
+
testContext: args.testContext
|
|
2267
2885
|
});
|
|
2268
2886
|
}
|
|
2269
2887
|
};
|
|
@@ -2430,7 +3048,8 @@ var RunContinuationService = class {
|
|
|
2430
3048
|
engineMaxNodeActivations: limits.engineMaxNodeActivations,
|
|
2431
3049
|
engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
|
|
2432
3050
|
data,
|
|
2433
|
-
nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent)
|
|
3051
|
+
nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent),
|
|
3052
|
+
testContext: state.executionOptions?.testContext
|
|
2434
3053
|
});
|
|
2435
3054
|
data.setOutputs(args.nodeId, args.outputs);
|
|
2436
3055
|
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -2951,7 +3570,8 @@ var RunContinuationService = class {
|
|
|
2951
3570
|
engineMaxNodeActivations: webhookLimits.engineMaxNodeActivations,
|
|
2952
3571
|
engineMaxSubworkflowDepth: webhookLimits.engineMaxSubworkflowDepth,
|
|
2953
3572
|
data,
|
|
2954
|
-
nodeState: this.nodeStatePublisherFactory.create(args.state.runId, args.state.workflowId, args.state.parent)
|
|
3573
|
+
nodeState: this.nodeStatePublisherFactory.create(args.state.runId, args.state.workflowId, args.state.parent),
|
|
3574
|
+
testContext: args.state.executionOptions?.testContext
|
|
2955
3575
|
});
|
|
2956
3576
|
const request = this.nodeActivationRequestComposer.createFromPlannedActivation({
|
|
2957
3577
|
next,
|
|
@@ -3042,7 +3662,8 @@ var RunContinuationService = class {
|
|
|
3042
3662
|
engineMaxNodeActivations: limits.engineMaxNodeActivations,
|
|
3043
3663
|
engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
|
|
3044
3664
|
data,
|
|
3045
|
-
nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent)
|
|
3665
|
+
nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, state.parent),
|
|
3666
|
+
testContext: state.executionOptions?.testContext
|
|
3046
3667
|
});
|
|
3047
3668
|
const activationId = pendingExecution.activationId;
|
|
3048
3669
|
return {
|
|
@@ -3434,7 +4055,7 @@ var RunPolicySnapshotFactory = class {
|
|
|
3434
4055
|
//#endregion
|
|
3435
4056
|
//#region src/orchestration/RunStartService.ts
|
|
3436
4057
|
var RunStartService = class {
|
|
3437
|
-
constructor(runIdFactory, workflowExecutionRepository, runDataFactory, workflowSnapshotFactory, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, workflowPolicyRuntimeDefaults, executionLimitsPolicy) {
|
|
4058
|
+
constructor(runIdFactory, workflowExecutionRepository, runDataFactory, workflowSnapshotFactory, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, workflowPolicyRuntimeDefaults, executionLimitsPolicy, nodeEventPublisher, persistedRunStateTerminalBuilder) {
|
|
3438
4059
|
this.runIdFactory = runIdFactory;
|
|
3439
4060
|
this.workflowExecutionRepository = workflowExecutionRepository;
|
|
3440
4061
|
this.runDataFactory = runDataFactory;
|
|
@@ -3448,6 +4069,8 @@ var RunStartService = class {
|
|
|
3448
4069
|
this.waiters = waiters;
|
|
3449
4070
|
this.workflowPolicyRuntimeDefaults = workflowPolicyRuntimeDefaults;
|
|
3450
4071
|
this.executionLimitsPolicy = executionLimitsPolicy;
|
|
4072
|
+
this.nodeEventPublisher = nodeEventPublisher;
|
|
4073
|
+
this.persistedRunStateTerminalBuilder = persistedRunStateTerminalBuilder;
|
|
3451
4074
|
}
|
|
3452
4075
|
async runWorkflow(workflow, startAt, items, parent, executionOptions, persistedStateOverrides) {
|
|
3453
4076
|
const runId = this.runIdFactory.makeRunId();
|
|
@@ -3478,9 +4101,28 @@ var RunStartService = class {
|
|
|
3478
4101
|
engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations,
|
|
3479
4102
|
engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth,
|
|
3480
4103
|
data,
|
|
3481
|
-
nodeState: this.nodeStatePublisherFactory.create(runId, workflow.id, parent)
|
|
4104
|
+
nodeState: this.nodeStatePublisherFactory.create(runId, workflow.id, parent),
|
|
4105
|
+
testContext: mergedExecutionOptions.testContext
|
|
3482
4106
|
});
|
|
3483
|
-
|
|
4107
|
+
let planning;
|
|
4108
|
+
try {
|
|
4109
|
+
planning = this.planningFactory.create(workflow);
|
|
4110
|
+
} catch (err) {
|
|
4111
|
+
if (err instanceof NodeInstantiationError) return await this.failRunDuringPlanning({
|
|
4112
|
+
runId,
|
|
4113
|
+
workflowId: workflow.id,
|
|
4114
|
+
startedAt,
|
|
4115
|
+
parent,
|
|
4116
|
+
executionOptions: mergedExecutionOptions,
|
|
4117
|
+
control: void 0,
|
|
4118
|
+
workflowSnapshot,
|
|
4119
|
+
mutableState,
|
|
4120
|
+
policySnapshot,
|
|
4121
|
+
err
|
|
4122
|
+
});
|
|
4123
|
+
throw err;
|
|
4124
|
+
}
|
|
4125
|
+
const { topology, planner } = planning;
|
|
3484
4126
|
const startDefinition = topology.defsById.get(startAt);
|
|
3485
4127
|
if (!startDefinition) throw new Error(`Unknown start nodeId: ${startAt}`);
|
|
3486
4128
|
const initialNodeSnapshotsByNodeId = {};
|
|
@@ -3559,7 +4201,25 @@ var RunStartService = class {
|
|
|
3559
4201
|
policySnapshot,
|
|
3560
4202
|
engineCounters: { completedNodeActivations: 0 }
|
|
3561
4203
|
});
|
|
3562
|
-
|
|
4204
|
+
let planningFromState;
|
|
4205
|
+
try {
|
|
4206
|
+
planningFromState = this.planningFactory.create(request.workflow);
|
|
4207
|
+
} catch (err) {
|
|
4208
|
+
if (err instanceof NodeInstantiationError) return await this.failRunDuringPlanning({
|
|
4209
|
+
runId,
|
|
4210
|
+
workflowId: request.workflow.id,
|
|
4211
|
+
startedAt,
|
|
4212
|
+
parent: request.parent,
|
|
4213
|
+
executionOptions: mergedExecutionOptions,
|
|
4214
|
+
control,
|
|
4215
|
+
workflowSnapshot,
|
|
4216
|
+
mutableState,
|
|
4217
|
+
policySnapshot,
|
|
4218
|
+
err
|
|
4219
|
+
});
|
|
4220
|
+
throw err;
|
|
4221
|
+
}
|
|
4222
|
+
const { topology, planner } = planningFromState;
|
|
3563
4223
|
const plan = CurrentStateFrontierPlanner.createFromTopology(topology).plan({
|
|
3564
4224
|
currentState: this.createRunCurrentState(request.currentState, mutableState),
|
|
3565
4225
|
stopCondition: control.stopCondition,
|
|
@@ -3577,7 +4237,8 @@ var RunStartService = class {
|
|
|
3577
4237
|
engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations,
|
|
3578
4238
|
engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth,
|
|
3579
4239
|
data,
|
|
3580
|
-
nodeState: this.nodeStatePublisherFactory.create(runId, request.workflow.id, request.parent)
|
|
4240
|
+
nodeState: this.nodeStatePublisherFactory.create(runId, request.workflow.id, request.parent),
|
|
4241
|
+
testContext: mergedExecutionOptions.testContext
|
|
3581
4242
|
});
|
|
3582
4243
|
return await this.scheduleInitialPlan({
|
|
3583
4244
|
runId,
|
|
@@ -3599,7 +4260,7 @@ var RunStartService = class {
|
|
|
3599
4260
|
return {
|
|
3600
4261
|
outputsByNode: { ...currentState?.outputsByNode ?? {} },
|
|
3601
4262
|
nodeSnapshotsByNodeId: { ...currentState?.nodeSnapshotsByNodeId ?? {} },
|
|
3602
|
-
connectionInvocations:
|
|
4263
|
+
connectionInvocations: [],
|
|
3603
4264
|
mutableState: mutableState ?? currentState?.mutableState
|
|
3604
4265
|
};
|
|
3605
4266
|
}
|
|
@@ -3752,6 +4413,57 @@ var RunStartService = class {
|
|
|
3752
4413
|
this.waiters.resolveRunCompletion(result);
|
|
3753
4414
|
return result;
|
|
3754
4415
|
}
|
|
4416
|
+
async failRunDuringPlanning(args) {
|
|
4417
|
+
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4418
|
+
const failedSnapshot = NodeExecutionSnapshotFactory.failed({
|
|
4419
|
+
previous: void 0,
|
|
4420
|
+
runId: args.runId,
|
|
4421
|
+
workflowId: args.workflowId,
|
|
4422
|
+
nodeId: args.err.nodeId,
|
|
4423
|
+
activationId: "planning_failure",
|
|
4424
|
+
parent: args.parent,
|
|
4425
|
+
finishedAt,
|
|
4426
|
+
inputsByPort: {},
|
|
4427
|
+
error: args.err
|
|
4428
|
+
});
|
|
4429
|
+
const failedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
4430
|
+
state: {
|
|
4431
|
+
runId: args.runId,
|
|
4432
|
+
workflowId: args.workflowId,
|
|
4433
|
+
startedAt: args.startedAt,
|
|
4434
|
+
parent: args.parent,
|
|
4435
|
+
executionOptions: args.executionOptions,
|
|
4436
|
+
control: args.control,
|
|
4437
|
+
workflowSnapshot: args.workflowSnapshot,
|
|
4438
|
+
mutableState: args.mutableState,
|
|
4439
|
+
policySnapshot: args.policySnapshot,
|
|
4440
|
+
engineCounters: { completedNodeActivations: 0 },
|
|
4441
|
+
status: "pending",
|
|
4442
|
+
pending: void 0,
|
|
4443
|
+
queue: [],
|
|
4444
|
+
outputsByNode: {},
|
|
4445
|
+
nodeSnapshotsByNodeId: {},
|
|
4446
|
+
connectionInvocations: []
|
|
4447
|
+
},
|
|
4448
|
+
engineCounters: { completedNodeActivations: 0 },
|
|
4449
|
+
status: "failed",
|
|
4450
|
+
queue: [],
|
|
4451
|
+
outputsByNode: {},
|
|
4452
|
+
nodeSnapshotsByNodeId: { [args.err.nodeId]: failedSnapshot },
|
|
4453
|
+
finishedAtIso: finishedAt
|
|
4454
|
+
});
|
|
4455
|
+
await this.workflowExecutionRepository.save(failedState);
|
|
4456
|
+
await this.nodeEventPublisher.publish("nodeFailed", failedSnapshot);
|
|
4457
|
+
const result = {
|
|
4458
|
+
runId: args.runId,
|
|
4459
|
+
workflowId: args.workflowId,
|
|
4460
|
+
startedAt: args.startedAt,
|
|
4461
|
+
status: "failed",
|
|
4462
|
+
error: { message: args.err.message }
|
|
4463
|
+
};
|
|
4464
|
+
this.waiters.resolveRunCompletion(result);
|
|
4465
|
+
return result;
|
|
4466
|
+
}
|
|
3755
4467
|
};
|
|
3756
4468
|
|
|
3757
4469
|
//#endregion
|
|
@@ -4225,6 +4937,128 @@ var InMemoryRunDataFactory = class {
|
|
|
4225
4937
|
}
|
|
4226
4938
|
};
|
|
4227
4939
|
|
|
4940
|
+
//#endregion
|
|
4941
|
+
//#region src/triggers/polling/PollingTriggerDedupWindow.ts
|
|
4942
|
+
/**
|
|
4943
|
+
* Merges processed-ID windows for polling triggers, capping the total to avoid unbounded growth.
|
|
4944
|
+
* Plugin code receives an instance of this class via {@link PollingTriggerHandle.dedup}.
|
|
4945
|
+
*/
|
|
4946
|
+
var PollingTriggerDedupWindow = class PollingTriggerDedupWindow {
|
|
4947
|
+
static defaultCapN = 2e3;
|
|
4948
|
+
merge(previous, incoming, capN = PollingTriggerDedupWindow.defaultCapN) {
|
|
4949
|
+
const merged = new Set(previous);
|
|
4950
|
+
for (const id of incoming) merged.add(id);
|
|
4951
|
+
const result = [...merged];
|
|
4952
|
+
if (result.length <= capN) return result;
|
|
4953
|
+
return result.slice(result.length - capN);
|
|
4954
|
+
}
|
|
4955
|
+
};
|
|
4956
|
+
|
|
4957
|
+
//#endregion
|
|
4958
|
+
//#region src/triggers/polling/PollingTriggerRuntime.ts
|
|
4959
|
+
/**
|
|
4960
|
+
* Generic polling-trigger runtime. Owns the set-interval loop, overlap guard, and persistence.
|
|
4961
|
+
* Constructed by {@link import("../../runtime/EngineFactory").EngineFactory} and exposed to plugin
|
|
4962
|
+
* authors via {@link import("../../contracts/runtimeTypes").TriggerSetupContext}.polling.
|
|
4963
|
+
*/
|
|
4964
|
+
var PollingTriggerRuntime = class {
|
|
4965
|
+
activeTriggers = /* @__PURE__ */ new Set();
|
|
4966
|
+
intervalsByTrigger = /* @__PURE__ */ new Map();
|
|
4967
|
+
busyTriggers = /* @__PURE__ */ new Set();
|
|
4968
|
+
constructor(triggerSetupStateRepository, logger) {
|
|
4969
|
+
this.triggerSetupStateRepository = triggerSetupStateRepository;
|
|
4970
|
+
this.logger = logger;
|
|
4971
|
+
}
|
|
4972
|
+
async start(args) {
|
|
4973
|
+
let first;
|
|
4974
|
+
try {
|
|
4975
|
+
first = await this.runCycle(args, { seedState: args.seedState });
|
|
4976
|
+
} catch (err) {
|
|
4977
|
+
this.logError(`Polling trigger initial cycle failed for ${this.describe(args.trigger)}`, err);
|
|
4978
|
+
}
|
|
4979
|
+
this.ensureLoop(args);
|
|
4980
|
+
return first;
|
|
4981
|
+
}
|
|
4982
|
+
async stop(trigger) {
|
|
4983
|
+
const key = this.toKey(trigger);
|
|
4984
|
+
const interval = this.intervalsByTrigger.get(key);
|
|
4985
|
+
if (interval !== void 0) {
|
|
4986
|
+
clearInterval(interval);
|
|
4987
|
+
this.intervalsByTrigger.delete(key);
|
|
4988
|
+
}
|
|
4989
|
+
this.busyTriggers.delete(key);
|
|
4990
|
+
this.activeTriggers.delete(key);
|
|
4991
|
+
this.logger.debug(`Polling trigger stopped for ${this.describe(trigger)}`);
|
|
4992
|
+
}
|
|
4993
|
+
ensureLoop(args) {
|
|
4994
|
+
const key = this.toKey(args.trigger);
|
|
4995
|
+
if (this.activeTriggers.has(key)) {
|
|
4996
|
+
this.logger.debug(`Polling trigger already active for ${this.describe(args.trigger)}`);
|
|
4997
|
+
return;
|
|
4998
|
+
}
|
|
4999
|
+
this.activeTriggers.add(key);
|
|
5000
|
+
const intervalMs = Math.max(args.intervalMs, 25);
|
|
5001
|
+
const interval = setInterval(() => {
|
|
5002
|
+
this.runCycle(args, { seedState: void 0 }).catch((err) => {
|
|
5003
|
+
this.logError(`Polling trigger cycle failed for ${this.describe(args.trigger)}`, err);
|
|
5004
|
+
});
|
|
5005
|
+
}, intervalMs);
|
|
5006
|
+
this.intervalsByTrigger.set(key, interval);
|
|
5007
|
+
this.logger.info(`Polling trigger started for ${this.describe(args.trigger)} (interval ${intervalMs}ms)`);
|
|
5008
|
+
}
|
|
5009
|
+
async runCycle(args, opts) {
|
|
5010
|
+
const key = this.toKey(args.trigger);
|
|
5011
|
+
if (this.busyTriggers.has(key)) {
|
|
5012
|
+
this.logger.debug(`Polling trigger skipping overlapping tick for ${this.describe(args.trigger)}`);
|
|
5013
|
+
return;
|
|
5014
|
+
}
|
|
5015
|
+
this.busyTriggers.add(key);
|
|
5016
|
+
try {
|
|
5017
|
+
const loaded = await this.triggerSetupStateRepository.load(args.trigger);
|
|
5018
|
+
const previousState = loaded !== void 0 ? loaded.state : opts.seedState;
|
|
5019
|
+
const controller = new AbortController();
|
|
5020
|
+
const { items, nextState } = await args.runCycle({
|
|
5021
|
+
previousState,
|
|
5022
|
+
signal: controller.signal
|
|
5023
|
+
});
|
|
5024
|
+
await this.triggerSetupStateRepository.save({
|
|
5025
|
+
trigger: args.trigger,
|
|
5026
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
5027
|
+
state: nextState
|
|
5028
|
+
});
|
|
5029
|
+
if (items.length > 0) {
|
|
5030
|
+
this.logger.info(`Polling trigger emitting ${items.length} item(s) for ${this.describe(args.trigger)}`);
|
|
5031
|
+
await args.emit(items);
|
|
5032
|
+
}
|
|
5033
|
+
return nextState;
|
|
5034
|
+
} finally {
|
|
5035
|
+
this.busyTriggers.delete(key);
|
|
5036
|
+
}
|
|
5037
|
+
}
|
|
5038
|
+
toKey(trigger) {
|
|
5039
|
+
return `${trigger.workflowId}:${trigger.nodeId}`;
|
|
5040
|
+
}
|
|
5041
|
+
describe(trigger) {
|
|
5042
|
+
return `${trigger.workflowId}.${trigger.nodeId}`;
|
|
5043
|
+
}
|
|
5044
|
+
logError(message, error) {
|
|
5045
|
+
if (error instanceof Error) {
|
|
5046
|
+
this.logger.error(message, error);
|
|
5047
|
+
return;
|
|
5048
|
+
}
|
|
5049
|
+
this.logger.error(`${message}: ${String(error)}`);
|
|
5050
|
+
}
|
|
5051
|
+
};
|
|
5052
|
+
|
|
5053
|
+
//#endregion
|
|
5054
|
+
//#region src/triggers/polling/PollingTriggerLogger.ts
|
|
5055
|
+
var NoOpPollingTriggerLogger = class {
|
|
5056
|
+
info() {}
|
|
5057
|
+
warn() {}
|
|
5058
|
+
error() {}
|
|
5059
|
+
debug() {}
|
|
5060
|
+
};
|
|
5061
|
+
|
|
4228
5062
|
//#endregion
|
|
4229
5063
|
//#region src/orchestration/NodeExecutionRequestHandlerService.ts
|
|
4230
5064
|
var NodeExecutionRequestHandlerService = class {
|
|
@@ -4264,7 +5098,8 @@ var NodeExecutionRequestHandlerService = class {
|
|
|
4264
5098
|
engineMaxNodeActivations: limits.engineMaxNodeActivations,
|
|
4265
5099
|
engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
|
|
4266
5100
|
data,
|
|
4267
|
-
nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, resolvedParent)
|
|
5101
|
+
nodeState: this.nodeStatePublisherFactory.create(state.runId, state.workflowId, resolvedParent),
|
|
5102
|
+
testContext: state.executionOptions?.testContext
|
|
4268
5103
|
});
|
|
4269
5104
|
const inputsByPort = pendingExecution.inputsByPort;
|
|
4270
5105
|
const portKeys = Object.keys(inputsByPort);
|
|
@@ -4654,7 +5489,7 @@ var EngineWorkflowPlanningFactory = class {
|
|
|
4654
5489
|
var TriggerRuntimeService = class {
|
|
4655
5490
|
credentialResolverFactory;
|
|
4656
5491
|
triggerCleanupHandlesByKey = /* @__PURE__ */ new Map();
|
|
4657
|
-
constructor(workflowRepository, workflowActivationPolicy, runIdFactory, runDataFactory, executionContextFactory, credentialResolverFactory, nodeExecutionStatePublisherFactory, nodeResolver, triggerSetupStateRepository, emitHandler, executionLimitsPolicy, diagnostics) {
|
|
5492
|
+
constructor(workflowRepository, workflowActivationPolicy, runIdFactory, runDataFactory, executionContextFactory, credentialResolverFactory, nodeExecutionStatePublisherFactory, nodeResolver, triggerSetupStateRepository, emitHandler, executionLimitsPolicy, diagnostics, pollingTriggerRuntime, pollingTriggerDedupWindow) {
|
|
4658
5493
|
this.workflowRepository = workflowRepository;
|
|
4659
5494
|
this.workflowActivationPolicy = workflowActivationPolicy;
|
|
4660
5495
|
this.runIdFactory = runIdFactory;
|
|
@@ -4666,6 +5501,8 @@ var TriggerRuntimeService = class {
|
|
|
4666
5501
|
this.emitHandler = emitHandler;
|
|
4667
5502
|
this.executionLimitsPolicy = executionLimitsPolicy;
|
|
4668
5503
|
this.diagnostics = diagnostics;
|
|
5504
|
+
this.pollingTriggerRuntime = pollingTriggerRuntime;
|
|
5505
|
+
this.pollingTriggerDedupWindow = pollingTriggerDedupWindow;
|
|
4669
5506
|
this.credentialResolverFactory = credentialResolverFactory;
|
|
4670
5507
|
}
|
|
4671
5508
|
async startTriggers() {
|
|
@@ -4721,6 +5558,7 @@ var TriggerRuntimeService = class {
|
|
|
4721
5558
|
async startTriggersForWorkflow(wf) {
|
|
4722
5559
|
for (const def of wf.nodes) {
|
|
4723
5560
|
if (def.kind !== "trigger") continue;
|
|
5561
|
+
if (def.config.triggerKind === "test") continue;
|
|
4724
5562
|
const node$1 = this.nodeResolver.resolve(def.type);
|
|
4725
5563
|
const data = this.runDataFactory.create();
|
|
4726
5564
|
const triggerRunId = this.runIdFactory.makeRunId();
|
|
@@ -4730,6 +5568,9 @@ var TriggerRuntimeService = class {
|
|
|
4730
5568
|
};
|
|
4731
5569
|
await this.stopTrigger(trigger);
|
|
4732
5570
|
const previousState = await this.triggerSetupStateRepository.load(trigger);
|
|
5571
|
+
const emit = this.emitHandler.emit.bind(this.emitHandler, wf, def.id);
|
|
5572
|
+
const registerCleanup = this.registerTriggerCleanupHandle.bind(this, trigger);
|
|
5573
|
+
const polling = this.buildPollingHandle(trigger, emit);
|
|
4733
5574
|
let nextState;
|
|
4734
5575
|
try {
|
|
4735
5576
|
nextState = await node$1.setup({
|
|
@@ -4742,12 +5583,9 @@ var TriggerRuntimeService = class {
|
|
|
4742
5583
|
trigger,
|
|
4743
5584
|
config: def.config,
|
|
4744
5585
|
previousState: previousState?.state,
|
|
4745
|
-
registerCleanup
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
emit: async (items) => {
|
|
4749
|
-
await this.emitHandler.emit(wf, def.id, items);
|
|
4750
|
-
}
|
|
5586
|
+
registerCleanup,
|
|
5587
|
+
emit,
|
|
5588
|
+
polling
|
|
4751
5589
|
});
|
|
4752
5590
|
} catch (triggerError) {
|
|
4753
5591
|
await this.stopTrigger(trigger);
|
|
@@ -4766,6 +5604,7 @@ var TriggerRuntimeService = class {
|
|
|
4766
5604
|
async stopTriggersForWorkflow(workflow) {
|
|
4767
5605
|
for (const node$1 of workflow.nodes) {
|
|
4768
5606
|
if (node$1.kind !== "trigger") continue;
|
|
5607
|
+
if (node$1.config.triggerKind === "test") continue;
|
|
4769
5608
|
await this.stopTrigger({
|
|
4770
5609
|
workflowId: workflow.id,
|
|
4771
5610
|
nodeId: node$1.id
|
|
@@ -4806,6 +5645,7 @@ var TriggerRuntimeService = class {
|
|
|
4806
5645
|
const out = [];
|
|
4807
5646
|
for (const def of wf.nodes) {
|
|
4808
5647
|
if (def.kind !== "trigger") continue;
|
|
5648
|
+
if (def.config.triggerKind === "test") continue;
|
|
4809
5649
|
out.push(this.describeTriggerNode(def));
|
|
4810
5650
|
}
|
|
4811
5651
|
return out;
|
|
@@ -4823,6 +5663,22 @@ var TriggerRuntimeService = class {
|
|
|
4823
5663
|
if (this.diagnostics) this.diagnostics.warn(message);
|
|
4824
5664
|
else console.warn(`[engine] ${message}`);
|
|
4825
5665
|
}
|
|
5666
|
+
buildPollingHandle(trigger, emit) {
|
|
5667
|
+
const runtime = this.pollingTriggerRuntime;
|
|
5668
|
+
return {
|
|
5669
|
+
dedup: this.pollingTriggerDedupWindow,
|
|
5670
|
+
start: async (args) => {
|
|
5671
|
+
this.registerTriggerCleanupHandle(trigger, { stop: async () => {
|
|
5672
|
+
await runtime.stop(trigger);
|
|
5673
|
+
} });
|
|
5674
|
+
return runtime.start({
|
|
5675
|
+
trigger,
|
|
5676
|
+
emit,
|
|
5677
|
+
...args
|
|
5678
|
+
});
|
|
5679
|
+
}
|
|
5680
|
+
};
|
|
5681
|
+
}
|
|
4826
5682
|
isTestableTriggerNode(node$1) {
|
|
4827
5683
|
return typeof node$1.getTestItems === "function";
|
|
4828
5684
|
}
|
|
@@ -4959,7 +5815,7 @@ var EngineFactory = class {
|
|
|
4959
5815
|
const waiters = new EngineWaiters();
|
|
4960
5816
|
const credentialResolverFactory = new CredentialResolverFactory(deps.credentialSessions);
|
|
4961
5817
|
const nodeEventPublisher = new NodeEventPublisher(deps.eventBus);
|
|
4962
|
-
const nodeStatePublisherFactory = new NodeRunStateWriterFactory(deps.workflowExecutionRepository, nodeEventPublisher);
|
|
5818
|
+
const nodeStatePublisherFactory = new NodeRunStateWriterFactory(deps.workflowExecutionRepository, nodeEventPublisher, deps.eventBus);
|
|
4963
5819
|
const planningFactory = new EngineWorkflowPlanningFactory(deps.workflowNodeInstanceFactory);
|
|
4964
5820
|
const executionLimitsPolicy = deps.executionLimitsPolicy ?? new EngineExecutionLimitsPolicy();
|
|
4965
5821
|
const workflowSnapshotCodec = deps.workflowSnapshotCodec ?? new WorkflowSnapshotCodec(deps.tokenRegistry);
|
|
@@ -4974,12 +5830,15 @@ var EngineFactory = class {
|
|
|
4974
5830
|
const storagePolicyEvaluator = new WorkflowStoragePolicyEvaluator(deps.nodeResolver);
|
|
4975
5831
|
const terminalPersistence = new RunTerminalPersistenceCoordinator(deps.workflowExecutionRepository, storagePolicyEvaluator);
|
|
4976
5832
|
const policyErrorServices = new WorkflowPolicyErrorServices(deps.nodeResolver);
|
|
4977
|
-
const runStartService = new RunStartService(deps.runIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, workflowSnapshotCodec, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, deps.workflowPolicyRuntimeDefaults, executionLimitsPolicy);
|
|
5833
|
+
const runStartService = new RunStartService(deps.runIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, workflowSnapshotCodec, planningFactory, nodeStatePublisherFactory, runExecutionContextFactory, nodeActivationRequestComposer, activationEnqueueService, semantics, waiters, deps.workflowPolicyRuntimeDefaults, executionLimitsPolicy, nodeEventPublisher, persistedRunStateTerminalBuilder);
|
|
4978
5834
|
const runContinuationService = new RunContinuationService(deps.activationIdFactory, deps.workflowExecutionRepository, deps.runDataFactory, runExecutionContextFactory, workflowSnapshotResolver, planningFactory, nodeStatePublisherFactory, credentialResolverFactory, nodeActivationRequestComposer, persistedRunStateTerminalBuilder, activationEnqueueService, nodeEventPublisher, semantics, waiters, policyErrorServices, terminalPersistence, executionLimitsPolicy);
|
|
4979
5835
|
const nodeExecutionRequestHandler = new NodeExecutionRequestHandlerService(deps.workflowExecutionRepository, workflowSnapshotResolver, deps.runDataFactory, runExecutionContextFactory, nodeStatePublisherFactory, nodeActivationRequestComposer, deps.nodeExecutor, runContinuationService, executionLimitsPolicy);
|
|
5836
|
+
const pollingTriggerLogger = deps.pollingTriggerLogger ?? new NoOpPollingTriggerLogger();
|
|
5837
|
+
const pollingTriggerDedupWindow = new PollingTriggerDedupWindow();
|
|
5838
|
+
const pollingTriggerRuntime = new PollingTriggerRuntime(deps.triggerSetupStateRepository, pollingTriggerLogger);
|
|
4980
5839
|
const triggerRuntime = new TriggerRuntimeService(deps.workflowRepository, deps.workflowActivationPolicy, deps.runIdFactory, deps.runDataFactory, deps.executionContextFactory, credentialResolverFactory, nodeStatePublisherFactory, deps.nodeResolver, deps.triggerSetupStateRepository, { emit: async (workflow, triggerNodeId, items) => {
|
|
4981
5840
|
await runStartService.runWorkflow(workflow, triggerNodeId, items, void 0);
|
|
4982
|
-
} }, executionLimitsPolicy, deps.triggerRuntimeDiagnostics);
|
|
5841
|
+
} }, executionLimitsPolicy, deps.triggerRuntimeDiagnostics, pollingTriggerRuntime, pollingTriggerDedupWindow);
|
|
4983
5842
|
const engine = new Engine({
|
|
4984
5843
|
liveWorkflowRepository: deps.liveWorkflowRepository,
|
|
4985
5844
|
tokenRegistry: deps.tokenRegistry,
|
|
@@ -5270,5 +6129,5 @@ var WorkflowRepositoryWebhookTriggerMatcherFactory = class {
|
|
|
5270
6129
|
};
|
|
5271
6130
|
|
|
5272
6131
|
//#endregion
|
|
5273
|
-
export {
|
|
5274
|
-
//# sourceMappingURL=runtime-
|
|
6132
|
+
export { NoOpCostTrackingTelemetryFactory as $, singleton as $t, PersistedWorkflowTokenRegistry as A, AgentConfigInspector as At, DefaultExecutionContextFactory as B, InjectableRuntimeDecoratorComposer as Bt, DefaultDrivingScheduler as C, WorkflowBuilder as Ct, NodeInstanceFactoryFactory as D, WhenBuilder as Dt, StaticCostCatalog as E, ChainCursor as Et, RunnableOutputBehaviorResolver as F, NodeBackedToolConfig as Ft, CodemationTelemetryAttributeNames as G, delay as Gt, nodeRef as H, StackTraceCallSitePathResolver as Ht, NodeOutputNormalizer as I, chatModel as It, NoOpExecutionTelemetryFactory as J, injectable as Jt, AllWorkflowsActiveWorkflowActivationPolicy as K, inject as Kt, ItemExprResolver as L, getPersistedRuntimeTypeMetadata as Lt, NodeExecutorFactory as M, itemExpr as Mt, NodeExecutor as N, resolveItemExprsForExecution as Nt, NodeInstanceFactory as O, AgentConnectionNodeCollector as Ot, InProcessRetryRunnerFactory as P, resolveItemExprsInUnknown as Pt, NoOpTelemetryArtifactReference as Q, registry as Qt, InProcessRetryRunner as R, node as Rt, HintOnlyOffloadPolicy as S, ConnectionInvocationIdFactory as St, RunPolicySnapshotFactory as T, NodeIdSlugifier as Tt, CodemationTelemetryMetricNames as U, PersistedRuntimeTypeNameResolver as Ut, branchRef as V, PersistedRuntimeTypeMetadataStore as Vt, GenAiTelemetryAttributeNames as W, container$1 as Wt, NoOpNodeExecutionTelemetry as X, instancePerContainerCachingFactory as Xt, NoOpExecutionTelemetry as Y, instanceCachingFactory as Yt, NoOpTelemetrySpanScope as Z, predicateAwareClassFactory as Zt, RunTerminalPersistenceCoordinator as _, ConnectionInvocationEventPublisher as _t, InMemoryLiveWorkflowRepository as a, RetryPolicy as at, LocalOnlyScheduler as b, WorkflowExecutableNodeClassifier as bt, EngineFactory as c, isPortsEmission as ct, PollingTriggerRuntime as d, CredentialResolverFactory as dt, CoreTokens as en, NoOpCostTrackingTelemetry as et, PollingTriggerDedupWindow as f, getOriginIndexFromItem as ft, WorkflowPolicyErrorServices as g, NodeEventPublisher as gt, WorkflowStoragePolicyEvaluator as h, UnavailableBinaryStorage as ht, RunIntentService as i, ExpRetryPolicy as it, MissingRuntimeTriggerToken as j, isItemExpr as jt, WorkflowSnapshotCodec as k, ConnectionNodeIdFactory as kt, Engine as l, isUnbrandedPortsEmissionShape as lt, InMemoryBinaryStorage as m, DefaultExecutionBinaryService as mt, WorkflowRepositoryWebhookTriggerMatcher as n, CostTrackingTelemetryMetricNames as nt, EngineWorkflowRunnerServiceFactory as o, NoRetryPolicy as ot, InMemoryRunDataFactory as p, ChildExecutionScopeFactory as pt, RunFinishedAtFactory as q, injectAll as qt, RunIntentServiceFactory as r, CredentialUnboundError as rt, EngineWorkflowRunnerService as s, emitPorts as st, WorkflowRepositoryWebhookTriggerMatcherFactory as t, CostTrackingTelemetryAttributeNames as tt, NoOpPollingTriggerLogger as u, DefaultAsyncSleeper as ut, ENGINE_EXECUTION_LIMITS_DEFAULTS as v, DefaultWorkflowGraphFactory as vt, ConfigDrivenOffloadPolicy as w, WorkflowDefinitionError as wt, InlineDrivingScheduler as x, NodeIterationIdFactory as xt, EngineExecutionLimitsPolicy as y, WorkflowExecutableNodeClassifierFactory as yt, CatalogBackedCostTrackingTelemetryFactory as z, tool as zt };
|
|
6133
|
+
//# sourceMappingURL=runtime-BGNbRnqs.js.map
|