@codemation/core 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/{EngineRuntimeRegistration.types-BP6tsaNP.d.ts → EngineRuntimeRegistration.types-kxQA5NLt.d.ts} +2 -2
- package/dist/{EngineWorkflowRunnerService-DzOCa1BW.d.cts → EngineWorkflowRunnerService-Ba2AvBnL.d.cts} +2 -2
- package/dist/{InMemoryRunDataFactory-1iz7_SnO.d.cts → InMemoryRunDataFactory-Ou4tQUOS.d.cts} +2 -2
- package/dist/{RunIntentService-S-1lW-gS.d.cts → RunIntentService-Dyh_dH0k.d.cts} +528 -467
- package/dist/{RunIntentService-BqhmdoA1.d.ts → RunIntentService-dteLjNiT.d.ts} +568 -462
- package/dist/bootstrap/index.cjs +2 -2
- package/dist/bootstrap/index.d.cts +3 -3
- package/dist/bootstrap/index.d.ts +3 -3
- package/dist/bootstrap/index.js +2 -2
- package/dist/{bootstrap-jqh1kCNI.js → bootstrap-CL68rqWg.js} +3 -2
- package/dist/bootstrap-CL68rqWg.js.map +1 -0
- package/dist/{bootstrap-BfZE19lK.cjs → bootstrap-Cko6udwL.cjs} +3 -2
- package/dist/bootstrap-Cko6udwL.cjs.map +1 -0
- package/dist/{index-CGs3Hnoz.d.ts → index-CyfGTfU1.d.ts} +51 -3
- package/dist/index.cjs +10 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +96 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +2 -11
- package/dist/index.js.map +1 -1
- package/dist/{runtime-u6O644ST.js → runtime-284ok0cm.js} +200 -30
- package/dist/runtime-284ok0cm.js.map +1 -0
- package/dist/{runtime-DWKfb0BI.cjs → runtime-B3Og-_St.cjs} +222 -28
- package/dist/runtime-B3Og-_St.cjs.map +1 -0
- package/dist/testing.cjs +2 -2
- package/dist/testing.d.cts +2 -2
- package/dist/testing.d.ts +2 -2
- package/dist/testing.js +2 -2
- package/package.json +1 -1
- package/src/ai/AiHost.ts +9 -0
- package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +4 -0
- 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/executionPersistenceContracts.ts +30 -0
- package/src/contracts/runTypes.ts +10 -0
- package/src/contracts/runtimeTypes.ts +8 -0
- package/src/contracts/telemetryTypes.ts +8 -0
- package/src/contracts/workflowTypes.ts +6 -0
- package/src/events/ConnectionInvocationEventPublisher.ts +46 -0
- package/src/events/index.ts +1 -0
- package/src/events/runEvents.ts +25 -0
- package/src/execution/ChildExecutionScopeFactory.ts +58 -0
- package/src/execution/ExecutionTelemetryCostTrackingDecoratorFactory.ts +18 -0
- package/src/execution/NodeExecutor.ts +10 -2
- package/src/execution/NodeRunStateWriter.ts +7 -0
- package/src/execution/NodeRunStateWriterFactory.ts +7 -0
- package/src/execution/index.ts +1 -0
- package/src/index.ts +1 -0
- package/src/runtime/EngineFactory.ts +1 -0
- package/src/workflow/definition/NodeIterationIdFactory.ts +26 -0
- package/src/workflow/index.ts +1 -0
- package/dist/bootstrap-BfZE19lK.cjs.map +0 -1
- package/dist/bootstrap-jqh1kCNI.js.map +0 -1
- package/dist/runtime-DWKfb0BI.cjs.map +0 -1
- package/dist/runtime-u6O644ST.js.map +0 -1
package/dist/testing.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const require_runtime = require('./runtime-
|
|
1
|
+
const require_runtime = require('./runtime-B3Og-_St.cjs');
|
|
2
2
|
const require_InMemoryRunEventBusRegistry = require('./InMemoryRunEventBusRegistry-B0_C4OnP.cjs');
|
|
3
|
-
const require_bootstrap = require('./bootstrap-
|
|
3
|
+
const require_bootstrap = require('./bootstrap-Cko6udwL.cjs');
|
|
4
4
|
let tsyringe = require("tsyringe");
|
|
5
5
|
tsyringe = require_runtime.__toESM(tsyringe);
|
|
6
6
|
|
package/dist/testing.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { a as WorkflowSnapshotCodec, n as EngineRuntimeRegistrationOptions, t as EngineWorkflowRunnerService } from "./EngineWorkflowRunnerService-
|
|
1
|
+
import { A as NodeOffloadPolicy, E as NodeId, Ei as WorkflowExecutionRepository, Gt as NodeExecutionScheduler, Ht as NodeExecutionContext, I as ParentExecutionRef, K as TriggerNodeConfig, Mt as ExecutionContextFactory, Or as TypeToken, Qt as RunnableNodeExecuteArgs, Sr as Container, U as RunnableNodeConfig, Ut as NodeExecutionRequest, Vr as EngineExecutionLimitsPolicy, Wr as RunEventBus, X as WorkflowDefinition, Zt as RunnableNode, an as TriggerSetupStateRepository, f as Items, j as NodeOutputs, mr as CredentialSessionService, n as InMemoryLiveWorkflowRepository, nt as WorkflowId, r as Engine, rn as TriggerSetupContext, t as RunIntentService, tn as TriggerNode, u as Item, un as WorkflowRunnerService, vi as RunResult, z as RunDataFactory } from "./RunIntentService-Dyh_dH0k.cjs";
|
|
2
|
+
import { a as WorkflowSnapshotCodec, n as EngineRuntimeRegistrationOptions, t as EngineWorkflowRunnerService } from "./EngineWorkflowRunnerService-Ba2AvBnL.cjs";
|
|
3
3
|
import { DependencyContainer, InjectionToken } from "tsyringe";
|
|
4
4
|
import { ZodType } from "zod";
|
|
5
5
|
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $
|
|
2
|
-
import { t as EngineRuntimeRegistrationOptions } from "./EngineRuntimeRegistration.types-
|
|
1
|
+
import { $t as RunDataFactory, Ba as WorkflowExecutionRepository, Bt as NodeId, Et as Items, Gt as NodeOutputs, Hi as TypeToken, Ii as Container, Kn as ExecutionContextFactory, Ma as RunResult, Oi as CredentialSessionService, Wt as NodeOffloadPolicy, Xt as ParentExecutionRef, _r as TriggerSetupContext, ar as NodeExecutionScheduler, dr as RunnableNode, fr as RunnableNodeExecuteArgs, gn as WorkflowId, hr as TriggerNode, ia as RunEventBus, l as WorkflowSnapshotCodec, n as InMemoryLiveWorkflowRepository, nr as NodeExecutionContext, on as TriggerNodeConfig, r as EngineWorkflowRunnerService, rn as RunnableNodeConfig, rr as NodeExecutionRequest, t as RunIntentService, ta as EngineExecutionLimitsPolicy, u as Engine, un as WorkflowDefinition, wr as WorkflowRunnerService, wt as Item, yr as TriggerSetupStateRepository } from "./RunIntentService-dteLjNiT.js";
|
|
2
|
+
import { t as EngineRuntimeRegistrationOptions } from "./EngineRuntimeRegistration.types-kxQA5NLt.js";
|
|
3
3
|
import { DependencyContainer, InjectionToken } from "tsyringe";
|
|
4
4
|
import { ZodType } from "zod";
|
|
5
5
|
|
package/dist/testing.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { A as NodeExecutor, D as PersistedWorkflowTokenRegistry, E as WorkflowSnapshotCodec, F as InProcessRetryRunner,
|
|
1
|
+
import { A as NodeExecutor, D as PersistedWorkflowTokenRegistry, E as WorkflowSnapshotCodec, F as InProcessRetryRunner, Ht as CoreTokens, L as DefaultExecutionContextFactory, R as AllWorkflowsActiveWorkflowActivationPolicy, T as NodeInstanceFactory, a as InMemoryLiveWorkflowRepository, b as DefaultDrivingScheduler, i as RunIntentService, it as emitPorts, l as Engine, st as DefaultAsyncSleeper, u as InMemoryRunDataFactory, v as InlineDrivingScheduler, y as HintOnlyOffloadPolicy } from "./runtime-284ok0cm.js";
|
|
2
2
|
import { n as WorkflowBuilder, t as InMemoryRunEventBus } from "./InMemoryRunEventBusRegistry-C2U83Hmv.js";
|
|
3
|
-
import { n as InMemoryWorkflowExecutionRepository, t as EngineRuntimeRegistrar } from "./bootstrap-
|
|
3
|
+
import { n as InMemoryWorkflowExecutionRepository, t as EngineRuntimeRegistrar } from "./bootstrap-CL68rqWg.js";
|
|
4
4
|
import { container } from "tsyringe";
|
|
5
5
|
|
|
6
6
|
//#region src/testing/RejectingCredentialSessionService.ts
|
package/package.json
CHANGED
package/src/ai/AiHost.ts
CHANGED
|
@@ -37,6 +37,15 @@ export type ToolExecuteArgs<TConfig extends ToolConfig = ToolConfig, TInput = un
|
|
|
37
37
|
item: Item;
|
|
38
38
|
itemIndex: number;
|
|
39
39
|
items: Items;
|
|
40
|
+
/**
|
|
41
|
+
* Optional sub-agent boundary hooks: when present, the live `agent.tool.call` span and the
|
|
42
|
+
* planned tool-call invocationId are forwarded so node-backed runtimes can re-root their child
|
|
43
|
+
* execution scope. Plain function tools may safely ignore these hooks.
|
|
44
|
+
*/
|
|
45
|
+
hooks?: Readonly<{
|
|
46
|
+
parentSpan?: import("../contracts/telemetryTypes").TelemetrySpanScope;
|
|
47
|
+
parentInvocationId?: import("../contracts/runTypes").ConnectionInvocationId;
|
|
48
|
+
}>;
|
|
40
49
|
}>;
|
|
41
50
|
|
|
42
51
|
export interface Tool<
|
|
@@ -2,6 +2,7 @@ import { instanceCachingFactory, type DependencyContainer } from "../../di";
|
|
|
2
2
|
import { CoreTokens } from "../../di";
|
|
3
3
|
import { EngineExecutionLimitsPolicyFactory } from "../../policies/executionLimits/EngineExecutionLimitsPolicyFactory";
|
|
4
4
|
import {
|
|
5
|
+
ChildExecutionScopeFactory,
|
|
5
6
|
DefaultAsyncSleeper,
|
|
6
7
|
InProcessRetryRunnerFactory,
|
|
7
8
|
ItemExprResolver,
|
|
@@ -50,6 +51,9 @@ export class EngineRuntimeRegistrar {
|
|
|
50
51
|
if (!container.isRegistered(RunnableOutputBehaviorResolver, true)) {
|
|
51
52
|
container.registerSingleton(RunnableOutputBehaviorResolver, RunnableOutputBehaviorResolver);
|
|
52
53
|
}
|
|
54
|
+
if (!container.isRegistered(ChildExecutionScopeFactory, true)) {
|
|
55
|
+
container.registerSingleton(ChildExecutionScopeFactory, ChildExecutionScopeFactory);
|
|
56
|
+
}
|
|
53
57
|
container.registerSingleton(EngineExecutionLimitsPolicyFactory, EngineExecutionLimitsPolicyFactory);
|
|
54
58
|
container.registerSingleton(NodeInstanceFactoryFactory, NodeInstanceFactoryFactory);
|
|
55
59
|
container.registerSingleton(DefaultAsyncSleeper, DefaultAsyncSleeper);
|
package/src/browser.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type {
|
|
|
9
9
|
} from "./ai/AgentConnectionNodeCollector";
|
|
10
10
|
export type { AgentNodeConfig } from "./ai/AiHost";
|
|
11
11
|
export { ConnectionNodeIdFactory } from "./workflow/definition/ConnectionNodeIdFactory";
|
|
12
|
+
export { NodeIterationIdFactory } from "./workflow/definition/NodeIterationIdFactory";
|
|
12
13
|
export * from "./contracts/credentialTypes";
|
|
13
14
|
export * from "./contracts/runtimeTypes";
|
|
14
15
|
export * from "./contracts/runFinishedAtFactory";
|
|
@@ -9,4 +9,10 @@ export class CodemationTelemetryAttributeNames {
|
|
|
9
9
|
static readonly connectionInvocationId = "codemation.connection.invocation_id";
|
|
10
10
|
static readonly toolName = "codemation.tool.name";
|
|
11
11
|
static readonly traceParentRunId = "codemation.parent.run.id";
|
|
12
|
+
/** Per-item iteration that emitted this span/metric. Set on spans recorded inside a runnable per-item loop. */
|
|
13
|
+
static readonly iterationId = "codemation.iteration.id";
|
|
14
|
+
/** Item index (0-based) of the iteration. */
|
|
15
|
+
static readonly iterationIndex = "codemation.iteration.index";
|
|
16
|
+
/** Set when this span/metric was recorded under a sub-agent triggered by an outer LLM/tool call. */
|
|
17
|
+
static readonly parentInvocationId = "codemation.parent.invocation_id";
|
|
12
18
|
}
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type { NodeExecutionTelemetry, TelemetryChildSpanStart, TelemetrySpanScope } from "./telemetryTypes";
|
|
1
|
+
import type { NodeExecutionTelemetry } from "./telemetryTypes";
|
|
3
2
|
import { NoOpTelemetrySpanScope } from "./NoOpTelemetrySpanScope";
|
|
4
3
|
|
|
5
4
|
export class NoOpNodeExecutionTelemetry {
|
|
6
|
-
static readonly value: NodeExecutionTelemetry =
|
|
7
|
-
...NoOpTelemetrySpanScope.value,
|
|
8
|
-
forNode(_: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>): NodeExecutionTelemetry {
|
|
9
|
-
return NoOpNodeExecutionTelemetry.value;
|
|
10
|
-
},
|
|
11
|
-
startChildSpan(_: TelemetryChildSpanStart): TelemetrySpanScope {
|
|
12
|
-
return NoOpTelemetrySpanScope.value;
|
|
13
|
-
},
|
|
14
|
-
};
|
|
5
|
+
static readonly value: NodeExecutionTelemetry = NoOpTelemetrySpanScope.nodeExecutionTelemetryValue;
|
|
15
6
|
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import type { NodeActivationId, NodeId } from "./workflowTypes";
|
|
1
2
|
import type {
|
|
3
|
+
NodeExecutionTelemetry,
|
|
2
4
|
TelemetryArtifactAttachment,
|
|
3
5
|
TelemetryArtifactReference,
|
|
6
|
+
TelemetryChildSpanStart,
|
|
4
7
|
TelemetryMetricRecord,
|
|
5
8
|
TelemetrySpanEnd,
|
|
6
9
|
TelemetrySpanEventRecord,
|
|
@@ -8,15 +11,48 @@ import type {
|
|
|
8
11
|
} from "./telemetryTypes";
|
|
9
12
|
import { NoOpTelemetryArtifactReference } from "./NoOpTelemetryArtifactReference";
|
|
10
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Standalone no-op {@link NodeExecutionTelemetry} value used as the return for `asNodeTelemetry`.
|
|
16
|
+
*
|
|
17
|
+
* Defined here (instead of in `NoOpNodeExecutionTelemetry.ts`) so that {@link NoOpTelemetrySpanScope}
|
|
18
|
+
* can return it without importing the other module — both no-ops share this leaf.
|
|
19
|
+
*/
|
|
20
|
+
const noOpNodeExecutionTelemetry: NodeExecutionTelemetry = {
|
|
21
|
+
traceId: "00000000000000000000000000000000",
|
|
22
|
+
spanId: "0000000000000000",
|
|
23
|
+
addSpanEvent(_: TelemetrySpanEventRecord): void {},
|
|
24
|
+
recordMetric(_: TelemetryMetricRecord): void {},
|
|
25
|
+
attachArtifact(_: TelemetryArtifactAttachment): TelemetryArtifactReference {
|
|
26
|
+
return NoOpTelemetryArtifactReference.value;
|
|
27
|
+
},
|
|
28
|
+
end(_: TelemetrySpanEnd = {}): void {},
|
|
29
|
+
asNodeTelemetry(_: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>): NodeExecutionTelemetry {
|
|
30
|
+
return noOpNodeExecutionTelemetry;
|
|
31
|
+
},
|
|
32
|
+
forNode(_: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>): NodeExecutionTelemetry {
|
|
33
|
+
return noOpNodeExecutionTelemetry;
|
|
34
|
+
},
|
|
35
|
+
startChildSpan(_: TelemetryChildSpanStart): TelemetrySpanScope {
|
|
36
|
+
return noOpTelemetrySpanScope;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const noOpTelemetrySpanScope: TelemetrySpanScope = {
|
|
41
|
+
traceId: "00000000000000000000000000000000",
|
|
42
|
+
spanId: "0000000000000000",
|
|
43
|
+
addSpanEvent(_: TelemetrySpanEventRecord): void {},
|
|
44
|
+
recordMetric(_: TelemetryMetricRecord): void {},
|
|
45
|
+
attachArtifact(_: TelemetryArtifactAttachment): TelemetryArtifactReference {
|
|
46
|
+
return NoOpTelemetryArtifactReference.value;
|
|
47
|
+
},
|
|
48
|
+
end(_: TelemetrySpanEnd = {}): void {},
|
|
49
|
+
asNodeTelemetry(_: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>): NodeExecutionTelemetry {
|
|
50
|
+
return noOpNodeExecutionTelemetry;
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
11
54
|
export class NoOpTelemetrySpanScope {
|
|
12
|
-
static readonly value: TelemetrySpanScope =
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
addSpanEvent(_: TelemetrySpanEventRecord): void {},
|
|
16
|
-
recordMetric(_: TelemetryMetricRecord): void {},
|
|
17
|
-
attachArtifact(_: TelemetryArtifactAttachment): TelemetryArtifactReference {
|
|
18
|
-
return NoOpTelemetryArtifactReference.value;
|
|
19
|
-
},
|
|
20
|
-
end(_: TelemetrySpanEnd = {}): void {},
|
|
21
|
-
};
|
|
55
|
+
static readonly value: TelemetrySpanScope = noOpTelemetrySpanScope;
|
|
56
|
+
/** Internal: the shared no-op {@link NodeExecutionTelemetry} that {@link NoOpNodeExecutionTelemetry} re-exposes. */
|
|
57
|
+
static readonly nodeExecutionTelemetryValue: NodeExecutionTelemetry = noOpNodeExecutionTelemetry;
|
|
22
58
|
}
|
|
@@ -148,6 +148,30 @@ export interface WorkflowRunDetailDto {
|
|
|
148
148
|
readonly mutableState?: PersistedMutableRunState;
|
|
149
149
|
readonly slotStates: ReadonlyArray<SlotExecutionStateDto>;
|
|
150
150
|
readonly executionInstances: ReadonlyArray<ExecutionInstanceDto>;
|
|
151
|
+
readonly iterations?: ReadonlyArray<RunIterationDto>;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Per-item iteration projected from connection invocations and node activations.
|
|
156
|
+
*
|
|
157
|
+
* One iteration = one item processed by an agent within an activation. Multiple invocations
|
|
158
|
+
* (LLM rounds, tool calls) belonging to the same iteration share the iterationId.
|
|
159
|
+
*/
|
|
160
|
+
export interface RunIterationDto {
|
|
161
|
+
readonly iterationId: string;
|
|
162
|
+
readonly agentNodeId: NodeId;
|
|
163
|
+
readonly activationId: NodeActivationId;
|
|
164
|
+
readonly itemIndex: number;
|
|
165
|
+
readonly itemSummary?: string;
|
|
166
|
+
readonly status: NodeExecutionStatus;
|
|
167
|
+
readonly startedAt?: string;
|
|
168
|
+
readonly finishedAt?: string;
|
|
169
|
+
readonly invocationIds: ReadonlyArray<string>;
|
|
170
|
+
readonly parentInvocationId?: string;
|
|
171
|
+
/** Estimated cost rolled up from telemetry cost metric points, keyed by ISO currency code (e.g. "USD"). Values are minor units (cents-of-cents per the metric's `cost.currency_scale`). */
|
|
172
|
+
readonly estimatedCostMinorByCurrency?: Readonly<Record<string, number>>;
|
|
173
|
+
/** Currency scale (denominator) per currency, when present on the metric points. Joined with `estimatedCostMinorByCurrency` to format human-readable amounts. */
|
|
174
|
+
readonly estimatedCostCurrencyScaleByCurrency?: Readonly<Record<string, number>>;
|
|
151
175
|
}
|
|
152
176
|
|
|
153
177
|
export interface SlotExecutionStateDto {
|
|
@@ -178,6 +202,12 @@ export interface ExecutionInstanceDto {
|
|
|
178
202
|
readonly inputJson?: JsonValue;
|
|
179
203
|
readonly outputJson?: JsonValue;
|
|
180
204
|
readonly error?: Readonly<NodeExecutionError>;
|
|
205
|
+
/** Per-item iteration that produced this instance. Set on connectionInvocation rows produced inside per-item runnable loops. */
|
|
206
|
+
readonly iterationId?: string;
|
|
207
|
+
/** Item index (0-based) of the iteration. */
|
|
208
|
+
readonly itemIndex?: number;
|
|
209
|
+
/** Parent invocation id when this instance was emitted by a sub-agent triggered by an outer LLM/tool call. */
|
|
210
|
+
readonly parentInvocationId?: string;
|
|
181
211
|
}
|
|
182
212
|
|
|
183
213
|
export interface WorkflowDetailSelectionState {
|
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
JsonValue,
|
|
8
8
|
NodeActivationId,
|
|
9
9
|
NodeId,
|
|
10
|
+
NodeIterationId,
|
|
10
11
|
NodeKind,
|
|
11
12
|
NodeOutputs,
|
|
12
13
|
OutputPortKey,
|
|
@@ -154,6 +155,12 @@ export interface ConnectionInvocationRecord {
|
|
|
154
155
|
readonly startedAt?: string;
|
|
155
156
|
readonly finishedAt?: string;
|
|
156
157
|
readonly updatedAt: string;
|
|
158
|
+
/** Per-item iteration id minted by the engine when this invocation occurred inside a runnable node's per-item loop. */
|
|
159
|
+
readonly iterationId?: NodeIterationId;
|
|
160
|
+
/** Item index (0-based) of the iteration that produced this invocation. */
|
|
161
|
+
readonly itemIndex?: number;
|
|
162
|
+
/** When set, this invocation was produced inside a sub-agent triggered by the named parent invocation. */
|
|
163
|
+
readonly parentInvocationId?: ConnectionInvocationId;
|
|
157
164
|
}
|
|
158
165
|
|
|
159
166
|
/** Arguments for appending a {@link ConnectionInvocationRecord} (engine fills run/workflow ids and timestamps). */
|
|
@@ -169,6 +176,9 @@ export type ConnectionInvocationAppendArgs = Readonly<{
|
|
|
169
176
|
queuedAt?: string;
|
|
170
177
|
startedAt?: string;
|
|
171
178
|
finishedAt?: string;
|
|
179
|
+
iterationId?: NodeIterationId;
|
|
180
|
+
itemIndex?: number;
|
|
181
|
+
parentInvocationId?: ConnectionInvocationId;
|
|
172
182
|
}>;
|
|
173
183
|
|
|
174
184
|
export interface RunCurrentState {
|
|
@@ -5,6 +5,7 @@ import type { CredentialSessionService } from "./credentialTypes";
|
|
|
5
5
|
import type { ExecutionTelemetry, ExecutionTelemetryFactory, NodeExecutionTelemetry } from "./telemetryTypes";
|
|
6
6
|
import type {
|
|
7
7
|
ConnectionInvocationAppendArgs,
|
|
8
|
+
ConnectionInvocationId,
|
|
8
9
|
NodeInputsByPort,
|
|
9
10
|
PersistedWorkflowSnapshot,
|
|
10
11
|
PersistedWorkflowTokenRegistryLike,
|
|
@@ -25,6 +26,7 @@ import type {
|
|
|
25
26
|
NodeActivationId,
|
|
26
27
|
NodeConfigBase,
|
|
27
28
|
NodeId,
|
|
29
|
+
NodeIterationId,
|
|
28
30
|
NodeOutputs,
|
|
29
31
|
RunnableNodeConfig,
|
|
30
32
|
OutputPortKey,
|
|
@@ -154,6 +156,12 @@ export interface ExecutionContext {
|
|
|
154
156
|
telemetry: ExecutionTelemetry;
|
|
155
157
|
binary: ExecutionBinaryService;
|
|
156
158
|
getCredential<TSession = unknown>(slotKey: string): Promise<TSession>;
|
|
159
|
+
/** Per-item iteration id, set by {@link NodeExecutor} on the ctx passed into runnable `execute`. */
|
|
160
|
+
iterationId?: NodeIterationId;
|
|
161
|
+
/** Item index (0-based) within the current activation's batch; set alongside {@link iterationId}. */
|
|
162
|
+
itemIndex?: number;
|
|
163
|
+
/** When set, this ctx is executing inside a sub-agent triggered by the named parent invocation. */
|
|
164
|
+
parentInvocationId?: ConnectionInvocationId;
|
|
157
165
|
}
|
|
158
166
|
|
|
159
167
|
export interface ExecutionContextFactory {
|
|
@@ -73,6 +73,14 @@ export interface TelemetrySpanScope extends TelemetryScope {
|
|
|
73
73
|
readonly traceId: string;
|
|
74
74
|
readonly spanId: string;
|
|
75
75
|
end(args?: TelemetrySpanEnd): Promise<void> | void;
|
|
76
|
+
/**
|
|
77
|
+
* Lift this span into a {@link NodeExecutionTelemetry} scoped to a different (nodeId, activationId).
|
|
78
|
+
* Children created via the returned telemetry's `startChildSpan` get this span as their parent.
|
|
79
|
+
*
|
|
80
|
+
* Used at the sub-agent boundary so that nested runtime telemetry parents under the agent.tool.call
|
|
81
|
+
* span instead of the orchestrator's node-level span.
|
|
82
|
+
*/
|
|
83
|
+
asNodeTelemetry(args: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>): NodeExecutionTelemetry;
|
|
76
84
|
}
|
|
77
85
|
|
|
78
86
|
export interface NodeExecutionTelemetry extends ExecutionTelemetry, TelemetrySpanScope {
|
|
@@ -194,6 +194,12 @@ export type NodeOutputs = Partial<Record<OutputPortKey, Items>>;
|
|
|
194
194
|
|
|
195
195
|
export type RunId = string;
|
|
196
196
|
export type NodeActivationId = string;
|
|
197
|
+
/**
|
|
198
|
+
* One per-item iteration of a runnable node's execute loop. Refines `NodeActivationId` for
|
|
199
|
+
* per-item connection invocations and telemetry. Undefined when the executing node is a batch
|
|
200
|
+
* node or trigger that does not iterate items.
|
|
201
|
+
*/
|
|
202
|
+
export type NodeIterationId = string;
|
|
197
203
|
|
|
198
204
|
export interface ParentExecutionRef {
|
|
199
205
|
runId: RunId;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ConnectionInvocationRecord } from "../contracts/runTypes";
|
|
2
|
+
import type { ParentExecutionRef } from "../types";
|
|
3
|
+
import type { RunEventBus } from "./runEvents";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Publishes per-invocation lifecycle records onto the run {@link RunEventBus}.
|
|
7
|
+
*
|
|
8
|
+
* Surgical, per-invocation events let the UI update the right-side inspector
|
|
9
|
+
* timeline as each LLM round / tool call transitions through `running` → `completed`
|
|
10
|
+
* (or `failed`) without depending on a coarse `runSaved` poll.
|
|
11
|
+
*/
|
|
12
|
+
export class ConnectionInvocationEventPublisher {
|
|
13
|
+
constructor(
|
|
14
|
+
private readonly eventBus: RunEventBus | undefined,
|
|
15
|
+
private readonly parent: ParentExecutionRef | undefined,
|
|
16
|
+
) {}
|
|
17
|
+
|
|
18
|
+
async publish(record: ConnectionInvocationRecord): Promise<void> {
|
|
19
|
+
if (!this.eventBus) return;
|
|
20
|
+
const kind = this.kindFor(record);
|
|
21
|
+
if (!kind) return;
|
|
22
|
+
await this.eventBus.publish({
|
|
23
|
+
kind,
|
|
24
|
+
runId: record.runId,
|
|
25
|
+
workflowId: record.workflowId,
|
|
26
|
+
parent: this.parent,
|
|
27
|
+
at: record.updatedAt,
|
|
28
|
+
record,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private kindFor(
|
|
33
|
+
record: ConnectionInvocationRecord,
|
|
34
|
+
): "connectionInvocationStarted" | "connectionInvocationCompleted" | "connectionInvocationFailed" | undefined {
|
|
35
|
+
if (record.status === "running" || record.status === "queued") {
|
|
36
|
+
return "connectionInvocationStarted";
|
|
37
|
+
}
|
|
38
|
+
if (record.status === "completed") {
|
|
39
|
+
return "connectionInvocationCompleted";
|
|
40
|
+
}
|
|
41
|
+
if (record.status === "failed") {
|
|
42
|
+
return "connectionInvocationFailed";
|
|
43
|
+
}
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/events/index.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export { ConnectionInvocationEventPublisher } from "./ConnectionInvocationEventPublisher";
|
|
1
2
|
export { NodeEventPublisher } from "./NodeEventPublisher";
|
|
2
3
|
export { InMemoryRunEventBus } from "./InMemoryRunEventBusRegistry";
|
|
3
4
|
export { EventPublishingWorkflowExecutionRepository } from "./EventPublishingWorkflowExecutionRepository";
|
package/src/events/runEvents.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ConnectionInvocationRecord } from "../contracts/runTypes";
|
|
1
2
|
import type { NodeExecutionSnapshot, ParentExecutionRef, PersistedRunState, RunId, WorkflowId } from "../types";
|
|
2
3
|
|
|
3
4
|
export type RunEvent =
|
|
@@ -41,6 +42,30 @@ export type RunEvent =
|
|
|
41
42
|
parent?: ParentExecutionRef;
|
|
42
43
|
at: string;
|
|
43
44
|
snapshot: NodeExecutionSnapshot;
|
|
45
|
+
}>
|
|
46
|
+
| Readonly<{
|
|
47
|
+
kind: "connectionInvocationStarted";
|
|
48
|
+
runId: RunId;
|
|
49
|
+
workflowId: WorkflowId;
|
|
50
|
+
parent?: ParentExecutionRef;
|
|
51
|
+
at: string;
|
|
52
|
+
record: ConnectionInvocationRecord;
|
|
53
|
+
}>
|
|
54
|
+
| Readonly<{
|
|
55
|
+
kind: "connectionInvocationCompleted";
|
|
56
|
+
runId: RunId;
|
|
57
|
+
workflowId: WorkflowId;
|
|
58
|
+
parent?: ParentExecutionRef;
|
|
59
|
+
at: string;
|
|
60
|
+
record: ConnectionInvocationRecord;
|
|
61
|
+
}>
|
|
62
|
+
| Readonly<{
|
|
63
|
+
kind: "connectionInvocationFailed";
|
|
64
|
+
runId: RunId;
|
|
65
|
+
workflowId: WorkflowId;
|
|
66
|
+
parent?: ParentExecutionRef;
|
|
67
|
+
at: string;
|
|
68
|
+
record: ConnectionInvocationRecord;
|
|
44
69
|
}>;
|
|
45
70
|
|
|
46
71
|
export interface RunEventSubscription {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { CoreTokens } from "../di/CoreTokens";
|
|
2
|
+
import { inject, injectable } from "../di";
|
|
3
|
+
import type {
|
|
4
|
+
ActivationIdFactory,
|
|
5
|
+
ConnectionInvocationId,
|
|
6
|
+
NodeExecutionContext,
|
|
7
|
+
NodeId,
|
|
8
|
+
RunnableNodeConfig,
|
|
9
|
+
TelemetrySpanScope,
|
|
10
|
+
} from "../types";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Builds a re-rooted child execution context for sub-agent (and other deeply-nested) invocations.
|
|
14
|
+
*
|
|
15
|
+
* At the orchestrator's `agent.tool.call` boundary the inner runtime needs a ctx whose:
|
|
16
|
+
* - `nodeId` is the tool's connection node id (so inner LLM/tool connection ids derive correctly),
|
|
17
|
+
* - `activationId` is fresh (so its connection-invocation rows are uniquely identifiable),
|
|
18
|
+
* - `telemetry` parents children under the tool-call span (not the orchestrator's node span),
|
|
19
|
+
* - `binary` is scoped to the new (nodeId, activationId),
|
|
20
|
+
* - `parentInvocationId` points back to the tool-call invocation for downstream lineage.
|
|
21
|
+
*/
|
|
22
|
+
@injectable()
|
|
23
|
+
export class ChildExecutionScopeFactory {
|
|
24
|
+
constructor(
|
|
25
|
+
@inject(CoreTokens.ActivationIdFactory)
|
|
26
|
+
private readonly activationIdFactory: ActivationIdFactory,
|
|
27
|
+
) {}
|
|
28
|
+
|
|
29
|
+
forSubAgent<TConfig extends RunnableNodeConfig<any, any>>(
|
|
30
|
+
args: Readonly<{
|
|
31
|
+
parentCtx: NodeExecutionContext<TConfig>;
|
|
32
|
+
childNodeId: NodeId;
|
|
33
|
+
childConfig: TConfig;
|
|
34
|
+
parentInvocationId: ConnectionInvocationId;
|
|
35
|
+
parentSpan: TelemetrySpanScope;
|
|
36
|
+
}>,
|
|
37
|
+
): NodeExecutionContext<TConfig> {
|
|
38
|
+
const childActivationId = this.activationIdFactory.makeActivationId();
|
|
39
|
+
const childTelemetry = args.parentSpan.asNodeTelemetry({
|
|
40
|
+
nodeId: args.childNodeId,
|
|
41
|
+
activationId: childActivationId,
|
|
42
|
+
});
|
|
43
|
+
const childBinary = args.parentCtx.binary.forNode({
|
|
44
|
+
nodeId: args.childNodeId,
|
|
45
|
+
activationId: childActivationId,
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
...args.parentCtx,
|
|
49
|
+
nodeId: args.childNodeId,
|
|
50
|
+
activationId: childActivationId,
|
|
51
|
+
config: args.childConfig,
|
|
52
|
+
telemetry: childTelemetry,
|
|
53
|
+
binary: childBinary,
|
|
54
|
+
parentInvocationId: args.parentInvocationId,
|
|
55
|
+
iterationId: undefined,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -62,6 +62,15 @@ export class ExecutionTelemetryCostTrackingDecoratorFactory {
|
|
|
62
62
|
costTracking: args.costTracking.forScope(nodeTelemetry),
|
|
63
63
|
});
|
|
64
64
|
},
|
|
65
|
+
asNodeTelemetry: (
|
|
66
|
+
rescope: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>,
|
|
67
|
+
): NodeExecutionTelemetry => {
|
|
68
|
+
const nodeTelemetry = args.telemetry.asNodeTelemetry(rescope);
|
|
69
|
+
return this.decorateNodeExecutionTelemetry({
|
|
70
|
+
telemetry: nodeTelemetry,
|
|
71
|
+
costTracking: args.costTracking.forScope(nodeTelemetry),
|
|
72
|
+
});
|
|
73
|
+
},
|
|
65
74
|
};
|
|
66
75
|
}
|
|
67
76
|
|
|
@@ -79,6 +88,15 @@ export class ExecutionTelemetryCostTrackingDecoratorFactory {
|
|
|
79
88
|
artifact: TelemetryArtifactAttachment,
|
|
80
89
|
): Promise<TelemetryArtifactReference> | TelemetryArtifactReference => args.scope.attachArtifact(artifact),
|
|
81
90
|
end: (endArgs?: TelemetrySpanEnd) => args.scope.end(endArgs),
|
|
91
|
+
asNodeTelemetry: (
|
|
92
|
+
rescope: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>,
|
|
93
|
+
): NodeExecutionTelemetry => {
|
|
94
|
+
const nodeTelemetry = args.scope.asNodeTelemetry(rescope);
|
|
95
|
+
return this.decorateNodeExecutionTelemetry({
|
|
96
|
+
telemetry: nodeTelemetry,
|
|
97
|
+
costTracking: args.costTracking.forScope(nodeTelemetry),
|
|
98
|
+
});
|
|
99
|
+
},
|
|
82
100
|
};
|
|
83
101
|
}
|
|
84
102
|
}
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
TriggerNode,
|
|
14
14
|
WorkflowNodeInstanceFactory,
|
|
15
15
|
} from "../types";
|
|
16
|
+
import { NodeIterationIdFactory } from "../workflow/definition/NodeIterationIdFactory";
|
|
16
17
|
|
|
17
18
|
import { FanInMergeByOriginMerger } from "./FanInMergeByOriginMerger";
|
|
18
19
|
import { ItemExprResolver } from "./ItemExprResolver";
|
|
@@ -158,13 +159,20 @@ export class NodeExecutor {
|
|
|
158
159
|
const parsed = inputSchema.parse(item.json);
|
|
159
160
|
const runnableCtx = request.ctx as NodeExecutionContext<RunnableNodeConfig>;
|
|
160
161
|
const resolvedCtx = await this.itemExprResolver.resolveConfigForItem(runnableCtx, item, i, inputBatch);
|
|
161
|
-
const
|
|
162
|
+
const baseCtx = this.pickExecutionContext(runnableCtx, resolvedCtx);
|
|
163
|
+
// Mint a per-item iteration id and stamp it (with the item index) onto the ctx so connection
|
|
164
|
+
// invocations and telemetry written from inside `node.execute` carry the per-item identity.
|
|
165
|
+
const iterationCtx = {
|
|
166
|
+
...baseCtx,
|
|
167
|
+
iterationId: NodeIterationIdFactory.create(),
|
|
168
|
+
itemIndex: i,
|
|
169
|
+
} as NodeExecutionContext<RunnableNodeConfig>;
|
|
162
170
|
const args: RunnableNodeExecuteArgs = {
|
|
163
171
|
input: parsed,
|
|
164
172
|
item,
|
|
165
173
|
itemIndex: i,
|
|
166
174
|
items: inputBatch,
|
|
167
|
-
ctx,
|
|
175
|
+
ctx: iterationCtx,
|
|
168
176
|
};
|
|
169
177
|
const raw = await Promise.resolve(node.execute(args));
|
|
170
178
|
const normalized = this.outputNormalizer.normalizeExecuteResult({
|
|
@@ -28,6 +28,7 @@ export class NodeRunStateWriter implements NodeExecutionStatePublisher {
|
|
|
28
28
|
kind: "nodeQueued" | "nodeStarted" | "nodeCompleted" | "nodeFailed",
|
|
29
29
|
snapshot: NodeExecutionSnapshot,
|
|
30
30
|
) => Promise<void>,
|
|
31
|
+
private readonly publishConnectionInvocationEvent?: (record: ConnectionInvocationRecord) => Promise<void>,
|
|
31
32
|
) {}
|
|
32
33
|
|
|
33
34
|
markQueued(args: {
|
|
@@ -148,11 +149,17 @@ export class NodeRunStateWriter implements NodeExecutionStatePublisher {
|
|
|
148
149
|
startedAt: args.startedAt,
|
|
149
150
|
finishedAt: args.finishedAt,
|
|
150
151
|
updatedAt,
|
|
152
|
+
iterationId: args.iterationId,
|
|
153
|
+
itemIndex: args.itemIndex,
|
|
154
|
+
parentInvocationId: args.parentInvocationId,
|
|
151
155
|
};
|
|
152
156
|
await this.workflowExecutionRepository.save({
|
|
153
157
|
...state,
|
|
154
158
|
connectionInvocations: [...(state.connectionInvocations ?? []), record],
|
|
155
159
|
});
|
|
160
|
+
if (this.publishConnectionInvocationEvent) {
|
|
161
|
+
await this.publishConnectionInvocationEvent(record);
|
|
162
|
+
}
|
|
156
163
|
});
|
|
157
164
|
}
|
|
158
165
|
|
|
@@ -6,16 +6,20 @@ import type {
|
|
|
6
6
|
WorkflowId,
|
|
7
7
|
} from "../types";
|
|
8
8
|
|
|
9
|
+
import { ConnectionInvocationEventPublisher } from "../events/ConnectionInvocationEventPublisher";
|
|
9
10
|
import { NodeEventPublisher } from "../events/NodeEventPublisher";
|
|
11
|
+
import type { RunEventBus } from "../events/runEvents";
|
|
10
12
|
import { NodeRunStateWriter } from "./NodeRunStateWriter";
|
|
11
13
|
|
|
12
14
|
export class NodeRunStateWriterFactory {
|
|
13
15
|
constructor(
|
|
14
16
|
private readonly workflowExecutionRepository: WorkflowExecutionRepository,
|
|
15
17
|
private readonly nodeEventPublisher: NodeEventPublisher,
|
|
18
|
+
private readonly eventBus?: RunEventBus,
|
|
16
19
|
) {}
|
|
17
20
|
|
|
18
21
|
create(runId: RunId, workflowId: WorkflowId, parent: ParentExecutionRef | undefined): NodeExecutionStatePublisher {
|
|
22
|
+
const connectionInvocationEventPublisher = new ConnectionInvocationEventPublisher(this.eventBus, parent);
|
|
19
23
|
return new NodeRunStateWriter(
|
|
20
24
|
this.workflowExecutionRepository,
|
|
21
25
|
runId,
|
|
@@ -24,6 +28,9 @@ export class NodeRunStateWriterFactory {
|
|
|
24
28
|
async (kind, snapshot) => {
|
|
25
29
|
await this.nodeEventPublisher.publish(kind, snapshot);
|
|
26
30
|
},
|
|
31
|
+
async (record) => {
|
|
32
|
+
await connectionInvocationEventPublisher.publish(record);
|
|
33
|
+
},
|
|
27
34
|
);
|
|
28
35
|
}
|
|
29
36
|
}
|
package/src/execution/index.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { ActivationEnqueueService } from "./ActivationEnqueueService";
|
|
2
|
+
export { ChildExecutionScopeFactory } from "./ChildExecutionScopeFactory";
|
|
2
3
|
export { NodeActivationRequestInputPreparer } from "./NodeActivationRequestInputPreparer";
|
|
3
4
|
export { NodeInputContractError } from "./NodeInputContractError";
|
|
4
5
|
export { CredentialResolverFactory } from "./CredentialResolverFactory";
|
package/src/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from "./runtime-types/runtimeTypeDecorators.types";
|
|
|
14
14
|
export * from "./serialization/ItemsInputNormalizer";
|
|
15
15
|
export { DefaultExecutionBinaryService, UnavailableBinaryStorage } from "./binaries";
|
|
16
16
|
export {
|
|
17
|
+
ChildExecutionScopeFactory,
|
|
17
18
|
CredentialResolverFactory,
|
|
18
19
|
DefaultAsyncSleeper,
|
|
19
20
|
DefaultExecutionContextFactory,
|
|
@@ -49,6 +49,7 @@ export class EngineFactory {
|
|
|
49
49
|
const nodeStatePublisherFactory = new NodeRunStateWriterFactory(
|
|
50
50
|
deps.workflowExecutionRepository,
|
|
51
51
|
nodeEventPublisher,
|
|
52
|
+
deps.eventBus,
|
|
52
53
|
);
|
|
53
54
|
const planningFactory = new EngineWorkflowPlanningFactory(deps.workflowNodeInstanceFactory);
|
|
54
55
|
const executionLimitsPolicy = deps.executionLimitsPolicy ?? new EngineExecutionLimitsPolicy();
|