@codemation/core 0.7.0 → 0.8.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 +22 -0
- package/dist/{EngineRuntimeRegistration.types-_M7KFD3D.d.ts → EngineRuntimeRegistration.types-BP6tsaNP.d.ts} +4 -2
- package/dist/{EngineWorkflowRunnerService-D0Cwngv7.d.cts → EngineWorkflowRunnerService-DzOCa1BW.d.cts} +4 -2
- package/dist/{InMemoryRunDataFactory-BIWx6e02.d.cts → InMemoryRunDataFactory-1iz7_SnO.d.cts} +24 -4
- package/dist/{workflowActivationPolicy-6V3OJD3N.cjs → InMemoryRunEventBusRegistry-B0_C4OnP.cjs} +1 -16
- package/dist/InMemoryRunEventBusRegistry-B0_C4OnP.cjs.map +1 -0
- package/dist/{workflowActivationPolicy-Td9HTOuD.js → InMemoryRunEventBusRegistry-C2U83Hmv.js} +2 -11
- package/dist/InMemoryRunEventBusRegistry-C2U83Hmv.js.map +1 -0
- package/dist/{RunIntentService-CuXAIO6_.d.ts → RunIntentService-BqhmdoA1.d.ts} +231 -3
- package/dist/{RunIntentService-5k0p-J67.d.cts → RunIntentService-S-1lW-gS.d.cts} +203 -3
- package/dist/bootstrap/index.cjs +4 -2
- package/dist/bootstrap/index.d.cts +24 -5
- package/dist/bootstrap/index.d.ts +4 -4
- package/dist/bootstrap/index.js +3 -3
- package/dist/{bootstrap-D-TDU9Lu.cjs → bootstrap-BaN6hZ5I.cjs} +6 -3
- package/dist/bootstrap-BaN6hZ5I.cjs.map +1 -0
- package/dist/{bootstrap-BhYxSivA.js → bootstrap-d_BMaDT4.js} +6 -3
- package/dist/bootstrap-d_BMaDT4.js.map +1 -0
- package/dist/{index-BnJ7_IrO.d.ts → index-CVs9rVhl.d.ts} +36 -6
- package/dist/index.cjs +48 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -4
- package/dist/index.d.ts +3 -3
- package/dist/index.js +27 -74
- package/dist/index.js.map +1 -1
- package/dist/{runtime-CJnObwsU.js → runtime-DUW6tIJ1.js} +423 -33
- package/dist/runtime-DUW6tIJ1.js.map +1 -0
- package/dist/{runtime-3YVDd2vY.cjs → runtime-Dvo2ru5A.cjs} +548 -32
- package/dist/runtime-Dvo2ru5A.cjs.map +1 -0
- package/dist/testing.cjs +6 -6
- 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 +3 -3
- package/package.json +1 -1
- package/src/ai/AiHost.ts +2 -0
- package/src/ai/CallableToolConfig.ts +28 -3
- package/src/bootstrap/index.ts +6 -1
- package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +1 -0
- package/src/bootstrap/runtime/EngineRuntimeRegistration.types.ts +3 -0
- package/src/contracts/CodemationTelemetryAttributeNames.ts +12 -0
- package/src/contracts/CodemationTelemetryMetricNames.ts +7 -0
- package/src/contracts/CostCatalogContract.ts +16 -0
- package/src/contracts/CostTrackingTelemetryContract.ts +47 -0
- package/src/contracts/GenAiTelemetryAttributeNames.ts +10 -0
- package/src/contracts/NoOpCostTrackingTelemetry.ts +16 -0
- package/src/contracts/NoOpCostTrackingTelemetryFactory.ts +9 -0
- package/src/contracts/NoOpExecutionTelemetry.ts +26 -0
- package/src/contracts/NoOpExecutionTelemetryFactory.ts +16 -0
- package/src/contracts/NoOpNodeExecutionTelemetry.ts +15 -0
- package/src/contracts/NoOpTelemetryArtifactReference.ts +9 -0
- package/src/contracts/NoOpTelemetrySpanScope.ts +22 -0
- package/src/contracts/index.ts +1 -0
- package/src/contracts/runTypes.ts +4 -1
- package/src/contracts/runtimeTypes.ts +7 -0
- package/src/contracts/telemetryTypes.ts +105 -0
- package/src/contracts/workflowTypes.ts +9 -0
- package/src/events/EventPublishingWorkflowExecutionRepository.ts +1 -1
- package/src/execution/CatalogBackedCostTrackingTelemetry.ts +81 -0
- package/src/execution/CatalogBackedCostTrackingTelemetryFactory.ts +12 -0
- package/src/execution/DefaultExecutionContextFactory.ts +23 -0
- package/src/execution/ExecutionTelemetryCostTrackingDecoratorFactory.ts +84 -0
- package/src/execution/NodeActivationRequestComposer.ts +1 -0
- package/src/execution/NodeExecutionSnapshotFactory.ts +2 -0
- package/src/execution/StaticCostCatalog.ts +22 -0
- package/src/execution/WorkflowRunExecutionContextFactory.ts +2 -0
- package/src/execution/index.ts +4 -0
- package/src/orchestration/NodeExecutionRequestHandlerService.ts +1 -0
- package/src/orchestration/RunContinuationService.ts +4 -0
- package/src/orchestration/RunStartService.ts +2 -0
- package/src/policies/storage/RunPolicySnapshotFactory.ts +9 -0
- package/src/runStorage/InMemoryWorkflowExecutionRepository.ts +4 -2
- package/src/types/index.ts +5 -0
- package/dist/bootstrap-BhYxSivA.js.map +0 -1
- package/dist/bootstrap-D-TDU9Lu.cjs.map +0 -1
- package/dist/runtime-3YVDd2vY.cjs.map +0 -1
- package/dist/runtime-CJnObwsU.js.map +0 -1
- package/dist/workflowActivationPolicy-6V3OJD3N.cjs.map +0 -1
- package/dist/workflowActivationPolicy-Td9HTOuD.js.map +0 -1
|
@@ -2,6 +2,7 @@ import type { ReadableStream as BinaryReadableStream } from "node:stream/web";
|
|
|
2
2
|
import type { TypeToken } from "../di";
|
|
3
3
|
import type { RunEventBus } from "../events/runEvents";
|
|
4
4
|
import type { CredentialSessionService } from "./credentialTypes";
|
|
5
|
+
import type { ExecutionTelemetry, ExecutionTelemetryFactory, NodeExecutionTelemetry } from "./telemetryTypes";
|
|
5
6
|
import type {
|
|
6
7
|
ConnectionInvocationAppendArgs,
|
|
7
8
|
NodeInputsByPort,
|
|
@@ -28,6 +29,7 @@ import type {
|
|
|
28
29
|
RunnableNodeConfig,
|
|
29
30
|
OutputPortKey,
|
|
30
31
|
ParentExecutionRef,
|
|
32
|
+
PersistedRunPolicySnapshot,
|
|
31
33
|
RunDataFactory,
|
|
32
34
|
RunDataSnapshot,
|
|
33
35
|
RunId,
|
|
@@ -149,6 +151,7 @@ export interface ExecutionContext {
|
|
|
149
151
|
now: () => Date;
|
|
150
152
|
data: RunDataSnapshot;
|
|
151
153
|
nodeState?: NodeExecutionStatePublisher;
|
|
154
|
+
telemetry: ExecutionTelemetry;
|
|
152
155
|
binary: ExecutionBinaryService;
|
|
153
156
|
getCredential<TSession = unknown>(slotKey: string): Promise<TSession>;
|
|
154
157
|
}
|
|
@@ -158,11 +161,13 @@ export interface ExecutionContextFactory {
|
|
|
158
161
|
runId: RunId;
|
|
159
162
|
workflowId: WorkflowId;
|
|
160
163
|
parent?: ParentExecutionRef;
|
|
164
|
+
policySnapshot?: PersistedRunPolicySnapshot;
|
|
161
165
|
subworkflowDepth: number;
|
|
162
166
|
engineMaxNodeActivations: number;
|
|
163
167
|
engineMaxSubworkflowDepth: number;
|
|
164
168
|
data: RunDataSnapshot;
|
|
165
169
|
nodeState?: NodeExecutionStatePublisher;
|
|
170
|
+
telemetry?: ExecutionTelemetry;
|
|
166
171
|
getCredential<TSession = unknown>(slotKey: string): Promise<TSession>;
|
|
167
172
|
}): ExecutionContext;
|
|
168
173
|
}
|
|
@@ -171,6 +176,7 @@ export interface NodeExecutionContext<TConfig extends NodeConfigBase = NodeConfi
|
|
|
171
176
|
nodeId: NodeId;
|
|
172
177
|
activationId: NodeActivationId;
|
|
173
178
|
config: TConfig;
|
|
179
|
+
telemetry: NodeExecutionTelemetry;
|
|
174
180
|
binary: NodeBinaryAttachmentService;
|
|
175
181
|
}
|
|
176
182
|
|
|
@@ -416,6 +422,7 @@ export interface EngineDeps {
|
|
|
416
422
|
activationScheduler: NodeActivationScheduler;
|
|
417
423
|
runDataFactory: RunDataFactory;
|
|
418
424
|
executionContextFactory: ExecutionContextFactory;
|
|
425
|
+
executionTelemetryFactory?: ExecutionTelemetryFactory;
|
|
419
426
|
nodeExecutor: NodeExecutor;
|
|
420
427
|
eventBus?: RunEventBus;
|
|
421
428
|
tokenRegistry: PersistedWorkflowTokenRegistryLike;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
JsonValue,
|
|
3
|
+
NodeActivationId,
|
|
4
|
+
NodeId,
|
|
5
|
+
ParentExecutionRef,
|
|
6
|
+
PersistedRunPolicySnapshot,
|
|
7
|
+
RunId,
|
|
8
|
+
WorkflowId,
|
|
9
|
+
} from "./workflowTypes";
|
|
10
|
+
import type { CostTrackingTelemetry } from "./CostTrackingTelemetryContract";
|
|
11
|
+
|
|
12
|
+
export type TelemetryAttributePrimitive = string | number | boolean | null;
|
|
13
|
+
|
|
14
|
+
export interface TelemetryAttributes {
|
|
15
|
+
readonly [key: string]: TelemetryAttributePrimitive | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface TelemetryMetricRecord {
|
|
19
|
+
readonly name: string;
|
|
20
|
+
readonly value: number;
|
|
21
|
+
readonly unit?: string;
|
|
22
|
+
readonly attributes?: TelemetryAttributes;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface TelemetrySpanEventRecord {
|
|
26
|
+
readonly name: string;
|
|
27
|
+
readonly occurredAt?: Date;
|
|
28
|
+
readonly attributes?: TelemetryAttributes;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface TelemetryArtifactAttachment {
|
|
32
|
+
readonly kind: string;
|
|
33
|
+
readonly contentType: string;
|
|
34
|
+
readonly previewText?: string;
|
|
35
|
+
readonly previewJson?: JsonValue;
|
|
36
|
+
readonly payloadText?: string;
|
|
37
|
+
readonly payloadJson?: JsonValue;
|
|
38
|
+
readonly bytes?: number;
|
|
39
|
+
readonly truncated?: boolean;
|
|
40
|
+
readonly expiresAt?: Date;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface TelemetryArtifactReference {
|
|
44
|
+
readonly artifactId: string;
|
|
45
|
+
readonly traceId?: string;
|
|
46
|
+
readonly spanId?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface TelemetrySpanEnd {
|
|
50
|
+
readonly status?: "ok" | "error";
|
|
51
|
+
readonly statusMessage?: string;
|
|
52
|
+
readonly endedAt?: Date;
|
|
53
|
+
readonly attributes?: TelemetryAttributes;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface TelemetryChildSpanStart {
|
|
57
|
+
readonly name: string;
|
|
58
|
+
readonly kind?: "internal" | "client";
|
|
59
|
+
readonly startedAt?: Date;
|
|
60
|
+
readonly attributes?: TelemetryAttributes;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export interface TelemetryScope {
|
|
64
|
+
readonly traceId?: string;
|
|
65
|
+
readonly spanId?: string;
|
|
66
|
+
readonly costTracking?: CostTrackingTelemetry;
|
|
67
|
+
addSpanEvent(args: TelemetrySpanEventRecord): Promise<void> | void;
|
|
68
|
+
recordMetric(args: TelemetryMetricRecord): Promise<void> | void;
|
|
69
|
+
attachArtifact(args: TelemetryArtifactAttachment): Promise<TelemetryArtifactReference> | TelemetryArtifactReference;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface TelemetrySpanScope extends TelemetryScope {
|
|
73
|
+
readonly traceId: string;
|
|
74
|
+
readonly spanId: string;
|
|
75
|
+
end(args?: TelemetrySpanEnd): Promise<void> | void;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface NodeExecutionTelemetry extends ExecutionTelemetry, TelemetrySpanScope {
|
|
79
|
+
startChildSpan(args: TelemetryChildSpanStart): TelemetrySpanScope;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface ExecutionTelemetry extends TelemetryScope {
|
|
83
|
+
readonly traceId: string;
|
|
84
|
+
readonly spanId: string;
|
|
85
|
+
forNode(args: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>): NodeExecutionTelemetry;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface ExecutionTelemetryFactory {
|
|
89
|
+
create(
|
|
90
|
+
args: Readonly<{
|
|
91
|
+
runId: RunId;
|
|
92
|
+
workflowId: WorkflowId;
|
|
93
|
+
parent?: ParentExecutionRef;
|
|
94
|
+
policySnapshot?: PersistedRunPolicySnapshot;
|
|
95
|
+
}>,
|
|
96
|
+
): ExecutionTelemetry;
|
|
97
|
+
}
|
|
98
|
+
export { NoOpTelemetryArtifactReference } from "./NoOpTelemetryArtifactReference";
|
|
99
|
+
export { NoOpTelemetrySpanScope } from "./NoOpTelemetrySpanScope";
|
|
100
|
+
export { NoOpNodeExecutionTelemetry } from "./NoOpNodeExecutionTelemetry";
|
|
101
|
+
export { NoOpExecutionTelemetry } from "./NoOpExecutionTelemetry";
|
|
102
|
+
export { NoOpExecutionTelemetryFactory } from "./NoOpExecutionTelemetryFactory";
|
|
103
|
+
export { CodemationTelemetryAttributeNames } from "./CodemationTelemetryAttributeNames";
|
|
104
|
+
export { GenAiTelemetryAttributeNames } from "./GenAiTelemetryAttributeNames";
|
|
105
|
+
export { CodemationTelemetryMetricNames } from "./CodemationTelemetryMetricNames";
|
|
@@ -269,11 +269,17 @@ export interface WorkflowStoragePolicyDecisionArgs {
|
|
|
269
269
|
export interface WorkflowPrunePolicySpec {
|
|
270
270
|
readonly runDataRetentionSeconds?: number;
|
|
271
271
|
readonly binaryRetentionSeconds?: number;
|
|
272
|
+
readonly telemetrySpanRetentionSeconds?: number;
|
|
273
|
+
readonly telemetryArtifactRetentionSeconds?: number;
|
|
274
|
+
readonly telemetryMetricRetentionSeconds?: number;
|
|
272
275
|
}
|
|
273
276
|
|
|
274
277
|
export interface PersistedRunPolicySnapshot {
|
|
275
278
|
readonly retentionSeconds?: number;
|
|
276
279
|
readonly binaryRetentionSeconds?: number;
|
|
280
|
+
readonly telemetrySpanRetentionSeconds?: number;
|
|
281
|
+
readonly telemetryArtifactRetentionSeconds?: number;
|
|
282
|
+
readonly telemetryMetricRetentionSeconds?: number;
|
|
277
283
|
readonly storagePolicy: WorkflowStoragePolicyMode;
|
|
278
284
|
}
|
|
279
285
|
|
|
@@ -311,5 +317,8 @@ export type NodeErrorHandlerSpec = TypeToken<NodeErrorHandler> | NodeErrorHandle
|
|
|
311
317
|
export interface WorkflowPolicyRuntimeDefaults {
|
|
312
318
|
readonly retentionSeconds?: number;
|
|
313
319
|
readonly binaryRetentionSeconds?: number;
|
|
320
|
+
readonly telemetrySpanRetentionSeconds?: number;
|
|
321
|
+
readonly telemetryArtifactRetentionSeconds?: number;
|
|
322
|
+
readonly telemetryMetricRetentionSeconds?: number;
|
|
314
323
|
readonly storagePolicy?: WorkflowStoragePolicyMode;
|
|
315
324
|
}
|
|
@@ -63,7 +63,7 @@ export class EventPublishingWorkflowExecutionRepository
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
async listRunsOlderThan(
|
|
66
|
-
args: Readonly<{
|
|
66
|
+
args: Readonly<{ nowIso: string; defaultRetentionSeconds: number; limit?: number }>,
|
|
67
67
|
): Promise<ReadonlyArray<RunPruneCandidate>> {
|
|
68
68
|
const pruneRepository = this.inner as unknown as Partial<WorkflowExecutionPruneRepository>;
|
|
69
69
|
if (!pruneRepository.listRunsOlderThan) return [];
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { CostCatalog } from "../contracts/CostCatalogContract";
|
|
2
|
+
import {
|
|
3
|
+
CostTrackingTelemetryAttributeNames,
|
|
4
|
+
CostTrackingTelemetryMetricNames,
|
|
5
|
+
type CostTrackingPriceQuote,
|
|
6
|
+
type CostTrackingTelemetry,
|
|
7
|
+
type CostTrackingUsageRecord,
|
|
8
|
+
} from "../contracts/CostTrackingTelemetryContract";
|
|
9
|
+
import type { TelemetryAttributes, TelemetryScope } from "../types";
|
|
10
|
+
|
|
11
|
+
export class CatalogBackedCostTrackingTelemetry implements CostTrackingTelemetry {
|
|
12
|
+
constructor(
|
|
13
|
+
private readonly currentScope: TelemetryScope,
|
|
14
|
+
private readonly costCatalog: CostCatalog,
|
|
15
|
+
) {}
|
|
16
|
+
|
|
17
|
+
async captureUsage(args: CostTrackingUsageRecord): Promise<CostTrackingPriceQuote | undefined> {
|
|
18
|
+
const usageAttributes = this.createUsageAttributes(args);
|
|
19
|
+
await this.currentScope.recordMetric({
|
|
20
|
+
name: CostTrackingTelemetryMetricNames.usage,
|
|
21
|
+
value: args.quantity,
|
|
22
|
+
unit: args.usageUnit,
|
|
23
|
+
attributes: usageAttributes,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const catalogEntry = this.costCatalog.findEntry(args);
|
|
27
|
+
if (!catalogEntry) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const estimatedAmountMinor = Math.round(args.quantity * catalogEntry.pricePerUnitMinor);
|
|
32
|
+
const costAttributes = this.createCostAttributes(args, catalogEntry.currency, catalogEntry.currencyScale);
|
|
33
|
+
await this.currentScope.recordMetric({
|
|
34
|
+
name: CostTrackingTelemetryMetricNames.estimatedCost,
|
|
35
|
+
value: estimatedAmountMinor,
|
|
36
|
+
unit: catalogEntry.currency,
|
|
37
|
+
attributes: costAttributes,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
currency: catalogEntry.currency,
|
|
42
|
+
currencyScale: catalogEntry.currencyScale,
|
|
43
|
+
estimatedAmountMinor,
|
|
44
|
+
estimateKind: "catalog",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
forScope(scope: TelemetryScope): CostTrackingTelemetry {
|
|
49
|
+
// eslint-disable-next-line codemation/no-manual-di-new
|
|
50
|
+
return new CatalogBackedCostTrackingTelemetry(scope, this.costCatalog);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private createUsageAttributes(args: CostTrackingUsageRecord): TelemetryAttributes {
|
|
54
|
+
return {
|
|
55
|
+
...args.attributes,
|
|
56
|
+
[CostTrackingTelemetryAttributeNames.component]: args.component,
|
|
57
|
+
[CostTrackingTelemetryAttributeNames.provider]: args.provider,
|
|
58
|
+
[CostTrackingTelemetryAttributeNames.operation]: args.operation,
|
|
59
|
+
[CostTrackingTelemetryAttributeNames.pricingKey]: args.pricingKey,
|
|
60
|
+
[CostTrackingTelemetryAttributeNames.usageUnit]: args.usageUnit,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private createCostAttributes(
|
|
65
|
+
args: CostTrackingUsageRecord,
|
|
66
|
+
currency: string,
|
|
67
|
+
currencyScale: number,
|
|
68
|
+
): TelemetryAttributes {
|
|
69
|
+
return {
|
|
70
|
+
...args.attributes,
|
|
71
|
+
[CostTrackingTelemetryAttributeNames.component]: args.component,
|
|
72
|
+
[CostTrackingTelemetryAttributeNames.provider]: args.provider,
|
|
73
|
+
[CostTrackingTelemetryAttributeNames.operation]: args.operation,
|
|
74
|
+
[CostTrackingTelemetryAttributeNames.pricingKey]: args.pricingKey,
|
|
75
|
+
[CostTrackingTelemetryAttributeNames.usageUnit]: args.usageUnit,
|
|
76
|
+
[CostTrackingTelemetryAttributeNames.currency]: currency,
|
|
77
|
+
[CostTrackingTelemetryAttributeNames.currencyScale]: currencyScale,
|
|
78
|
+
[CostTrackingTelemetryAttributeNames.estimateKind]: "catalog",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CostCatalog } from "../contracts/CostCatalogContract";
|
|
2
|
+
import type { CostTrackingTelemetry, CostTrackingTelemetryFactory } from "../contracts/CostTrackingTelemetryContract";
|
|
3
|
+
import type { ExecutionTelemetry } from "../contracts/telemetryTypes";
|
|
4
|
+
import { CatalogBackedCostTrackingTelemetry } from "./CatalogBackedCostTrackingTelemetry";
|
|
5
|
+
|
|
6
|
+
export class CatalogBackedCostTrackingTelemetryFactory implements CostTrackingTelemetryFactory {
|
|
7
|
+
constructor(private readonly costCatalog: CostCatalog) {}
|
|
8
|
+
|
|
9
|
+
create(args: Readonly<{ telemetry: ExecutionTelemetry }>): CostTrackingTelemetry {
|
|
10
|
+
return new CatalogBackedCostTrackingTelemetry(args.telemetry, this.costCatalog);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
BinaryStorage,
|
|
3
|
+
CostTrackingTelemetryFactory,
|
|
3
4
|
ExecutionContext,
|
|
4
5
|
ExecutionContextFactory,
|
|
6
|
+
ExecutionTelemetryFactory,
|
|
5
7
|
NodeExecutionStatePublisher,
|
|
6
8
|
ParentExecutionRef,
|
|
7
9
|
RunDataSnapshot,
|
|
8
10
|
RunId,
|
|
9
11
|
WorkflowId,
|
|
10
12
|
} from "../types";
|
|
13
|
+
import { NoOpCostTrackingTelemetryFactory, NoOpExecutionTelemetryFactory } from "../types";
|
|
11
14
|
|
|
12
15
|
import {
|
|
13
16
|
DefaultExecutionBinaryService,
|
|
14
17
|
UnavailableBinaryStorage,
|
|
15
18
|
} from "../binaries/DefaultExecutionBinaryServiceFactory";
|
|
19
|
+
import { ExecutionTelemetryCostTrackingDecoratorFactory } from "./ExecutionTelemetryCostTrackingDecoratorFactory";
|
|
16
20
|
|
|
17
21
|
export class DefaultExecutionContextFactory implements ExecutionContextFactory {
|
|
22
|
+
private readonly telemetryDecoratorFactory = new ExecutionTelemetryCostTrackingDecoratorFactory();
|
|
23
|
+
|
|
18
24
|
constructor(
|
|
19
25
|
private readonly binaryStorage: BinaryStorage = new UnavailableBinaryStorage(),
|
|
26
|
+
private readonly telemetryFactory: ExecutionTelemetryFactory = new NoOpExecutionTelemetryFactory(),
|
|
27
|
+
private readonly costTrackingFactory: CostTrackingTelemetryFactory = new NoOpCostTrackingTelemetryFactory(),
|
|
20
28
|
private readonly currentDate: () => Date = () => new Date(),
|
|
21
29
|
) {}
|
|
22
30
|
|
|
@@ -24,13 +32,27 @@ export class DefaultExecutionContextFactory implements ExecutionContextFactory {
|
|
|
24
32
|
runId: RunId;
|
|
25
33
|
workflowId: WorkflowId;
|
|
26
34
|
parent?: ParentExecutionRef;
|
|
35
|
+
policySnapshot?: import("../types").PersistedRunPolicySnapshot;
|
|
27
36
|
subworkflowDepth: number;
|
|
28
37
|
engineMaxNodeActivations: number;
|
|
29
38
|
engineMaxSubworkflowDepth: number;
|
|
30
39
|
data: RunDataSnapshot;
|
|
31
40
|
nodeState?: NodeExecutionStatePublisher;
|
|
41
|
+
telemetry?: ExecutionContext["telemetry"];
|
|
32
42
|
getCredential<TSession = unknown>(slotKey: string): Promise<TSession>;
|
|
33
43
|
}): ExecutionContext {
|
|
44
|
+
const baseTelemetry =
|
|
45
|
+
args.telemetry ??
|
|
46
|
+
this.telemetryFactory.create({
|
|
47
|
+
runId: args.runId,
|
|
48
|
+
workflowId: args.workflowId,
|
|
49
|
+
parent: args.parent,
|
|
50
|
+
policySnapshot: args.policySnapshot,
|
|
51
|
+
});
|
|
52
|
+
const telemetry = this.telemetryDecoratorFactory.decorateExecutionTelemetry({
|
|
53
|
+
telemetry: baseTelemetry,
|
|
54
|
+
costTracking: baseTelemetry.costTracking ?? this.costTrackingFactory.create({ telemetry: baseTelemetry }),
|
|
55
|
+
});
|
|
34
56
|
return {
|
|
35
57
|
runId: args.runId,
|
|
36
58
|
workflowId: args.workflowId,
|
|
@@ -41,6 +63,7 @@ export class DefaultExecutionContextFactory implements ExecutionContextFactory {
|
|
|
41
63
|
now: this.currentDate,
|
|
42
64
|
data: args.data,
|
|
43
65
|
nodeState: args.nodeState,
|
|
66
|
+
telemetry,
|
|
44
67
|
binary: new DefaultExecutionBinaryService(this.binaryStorage, args.workflowId, args.runId, this.currentDate),
|
|
45
68
|
getCredential: args.getCredential,
|
|
46
69
|
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { CostTrackingTelemetry } from "../contracts/CostTrackingTelemetryContract";
|
|
2
|
+
import type {
|
|
3
|
+
ExecutionTelemetry,
|
|
4
|
+
NodeExecutionTelemetry,
|
|
5
|
+
TelemetryArtifactAttachment,
|
|
6
|
+
TelemetryArtifactReference,
|
|
7
|
+
TelemetryChildSpanStart,
|
|
8
|
+
TelemetryMetricRecord,
|
|
9
|
+
TelemetrySpanEnd,
|
|
10
|
+
TelemetrySpanEventRecord,
|
|
11
|
+
TelemetrySpanScope,
|
|
12
|
+
} from "../contracts/telemetryTypes";
|
|
13
|
+
import type { NodeActivationId, NodeId } from "../contracts/workflowTypes";
|
|
14
|
+
|
|
15
|
+
export class ExecutionTelemetryCostTrackingDecoratorFactory {
|
|
16
|
+
decorateExecutionTelemetry(args: {
|
|
17
|
+
telemetry: ExecutionTelemetry;
|
|
18
|
+
costTracking: CostTrackingTelemetry;
|
|
19
|
+
}): ExecutionTelemetry {
|
|
20
|
+
return {
|
|
21
|
+
traceId: args.telemetry.traceId,
|
|
22
|
+
spanId: args.telemetry.spanId,
|
|
23
|
+
costTracking: args.costTracking,
|
|
24
|
+
addSpanEvent: (event: TelemetrySpanEventRecord) => args.telemetry.addSpanEvent(event),
|
|
25
|
+
recordMetric: (metric: TelemetryMetricRecord) => args.telemetry.recordMetric(metric),
|
|
26
|
+
attachArtifact: (
|
|
27
|
+
artifact: TelemetryArtifactAttachment,
|
|
28
|
+
): Promise<TelemetryArtifactReference> | TelemetryArtifactReference => args.telemetry.attachArtifact(artifact),
|
|
29
|
+
forNode: (nodeArgs: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>): NodeExecutionTelemetry => {
|
|
30
|
+
const nodeTelemetry = args.telemetry.forNode(nodeArgs);
|
|
31
|
+
return this.decorateNodeExecutionTelemetry({
|
|
32
|
+
telemetry: nodeTelemetry,
|
|
33
|
+
costTracking: args.costTracking.forScope(nodeTelemetry),
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
private decorateNodeExecutionTelemetry(args: {
|
|
40
|
+
telemetry: NodeExecutionTelemetry;
|
|
41
|
+
costTracking: CostTrackingTelemetry;
|
|
42
|
+
}): NodeExecutionTelemetry {
|
|
43
|
+
return {
|
|
44
|
+
traceId: args.telemetry.traceId,
|
|
45
|
+
spanId: args.telemetry.spanId,
|
|
46
|
+
costTracking: args.costTracking,
|
|
47
|
+
addSpanEvent: (event: TelemetrySpanEventRecord) => args.telemetry.addSpanEvent(event),
|
|
48
|
+
recordMetric: (metric: TelemetryMetricRecord) => args.telemetry.recordMetric(metric),
|
|
49
|
+
attachArtifact: (
|
|
50
|
+
artifact: TelemetryArtifactAttachment,
|
|
51
|
+
): Promise<TelemetryArtifactReference> | TelemetryArtifactReference => args.telemetry.attachArtifact(artifact),
|
|
52
|
+
end: (endArgs?: TelemetrySpanEnd) => args.telemetry.end(endArgs),
|
|
53
|
+
startChildSpan: (spanArgs: TelemetryChildSpanStart): TelemetrySpanScope =>
|
|
54
|
+
this.decorateTelemetrySpanScope({
|
|
55
|
+
scope: args.telemetry.startChildSpan(spanArgs),
|
|
56
|
+
costTracking: args.costTracking,
|
|
57
|
+
}),
|
|
58
|
+
forNode: (nodeArgs: Readonly<{ nodeId: NodeId; activationId: NodeActivationId }>): NodeExecutionTelemetry => {
|
|
59
|
+
const nodeTelemetry = args.telemetry.forNode(nodeArgs);
|
|
60
|
+
return this.decorateNodeExecutionTelemetry({
|
|
61
|
+
telemetry: nodeTelemetry,
|
|
62
|
+
costTracking: args.costTracking.forScope(nodeTelemetry),
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private decorateTelemetrySpanScope(args: {
|
|
69
|
+
scope: TelemetrySpanScope;
|
|
70
|
+
costTracking: CostTrackingTelemetry;
|
|
71
|
+
}): TelemetrySpanScope {
|
|
72
|
+
return {
|
|
73
|
+
traceId: args.scope.traceId,
|
|
74
|
+
spanId: args.scope.spanId,
|
|
75
|
+
costTracking: args.costTracking.forScope(args.scope),
|
|
76
|
+
addSpanEvent: (event: TelemetrySpanEventRecord) => args.scope.addSpanEvent(event),
|
|
77
|
+
recordMetric: (metric: TelemetryMetricRecord) => args.scope.recordMetric(metric),
|
|
78
|
+
attachArtifact: (
|
|
79
|
+
artifact: TelemetryArtifactAttachment,
|
|
80
|
+
): Promise<TelemetryArtifactReference> | TelemetryArtifactReference => args.scope.attachArtifact(artifact),
|
|
81
|
+
end: (endArgs?: TelemetrySpanEnd) => args.scope.end(endArgs),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -142,6 +142,7 @@ export class NodeActivationRequestComposer {
|
|
|
142
142
|
nodeId: definition.id,
|
|
143
143
|
activationId,
|
|
144
144
|
config: definition.config,
|
|
145
|
+
telemetry: args.base.telemetry.forNode({ nodeId: definition.id, activationId }),
|
|
145
146
|
binary: args.base.binary.forNode({ nodeId: definition.id, activationId }),
|
|
146
147
|
getCredential: this.credentialResolverFactory.create(args.workflowId, definition.id, definition.config),
|
|
147
148
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
JsonValue,
|
|
2
3
|
NodeActivationId,
|
|
3
4
|
NodeExecutionSnapshot,
|
|
4
5
|
NodeId,
|
|
@@ -146,6 +147,7 @@ export class NodeExecutionSnapshotFactory {
|
|
|
146
147
|
message: args.error.message,
|
|
147
148
|
name: args.error.name,
|
|
148
149
|
stack: args.error.stack,
|
|
150
|
+
details: (args.error as Error & { details?: JsonValue }).details,
|
|
149
151
|
},
|
|
150
152
|
};
|
|
151
153
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CostCatalog, CostCatalogEntry } from "../contracts/CostCatalogContract";
|
|
2
|
+
import type { CostTrackingUsageRecord } from "../contracts/CostTrackingTelemetryContract";
|
|
3
|
+
|
|
4
|
+
export class StaticCostCatalog implements CostCatalog {
|
|
5
|
+
private readonly entriesByKey: ReadonlyMap<string, CostCatalogEntry>;
|
|
6
|
+
|
|
7
|
+
constructor(entries: ReadonlyArray<CostCatalogEntry>) {
|
|
8
|
+
this.entriesByKey = new Map(entries.map((entry) => [this.createKeyFromEntry(entry), entry]));
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
findEntry(args: CostTrackingUsageRecord): CostCatalogEntry | undefined {
|
|
12
|
+
return this.entriesByKey.get(this.createKeyFromUsage(args));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
private createKeyFromEntry(entry: CostCatalogEntry): string {
|
|
16
|
+
return `${entry.component}::${entry.provider}::${entry.operation}::${entry.pricingKey}::${entry.usageUnit}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private createKeyFromUsage(args: CostTrackingUsageRecord): string {
|
|
20
|
+
return `${args.component}::${args.provider}::${args.operation}::${args.pricingKey}::${args.usageUnit}`;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
@@ -24,6 +24,7 @@ export class WorkflowRunExecutionContextFactory {
|
|
|
24
24
|
workflowId: WorkflowId;
|
|
25
25
|
nodeId: NodeId;
|
|
26
26
|
parent?: ParentExecutionRef;
|
|
27
|
+
policySnapshot?: import("../types").PersistedRunPolicySnapshot;
|
|
27
28
|
subworkflowDepth: number;
|
|
28
29
|
engineMaxNodeActivations: number;
|
|
29
30
|
engineMaxSubworkflowDepth: number;
|
|
@@ -34,6 +35,7 @@ export class WorkflowRunExecutionContextFactory {
|
|
|
34
35
|
runId: args.runId,
|
|
35
36
|
workflowId: args.workflowId,
|
|
36
37
|
parent: args.parent,
|
|
38
|
+
policySnapshot: args.policySnapshot,
|
|
37
39
|
subworkflowDepth: args.subworkflowDepth,
|
|
38
40
|
engineMaxNodeActivations: args.engineMaxNodeActivations,
|
|
39
41
|
engineMaxSubworkflowDepth: args.engineMaxSubworkflowDepth,
|
package/src/execution/index.ts
CHANGED
|
@@ -4,6 +4,9 @@ export { NodeInputContractError } from "./NodeInputContractError";
|
|
|
4
4
|
export { CredentialResolverFactory } from "./CredentialResolverFactory";
|
|
5
5
|
export { DefaultAsyncSleeper } from "./DefaultAsyncSleeper";
|
|
6
6
|
export { DefaultExecutionContextFactory } from "./DefaultExecutionContextFactory";
|
|
7
|
+
export { CatalogBackedCostTrackingTelemetry } from "./CatalogBackedCostTrackingTelemetry";
|
|
8
|
+
export { CatalogBackedCostTrackingTelemetryFactory } from "./CatalogBackedCostTrackingTelemetryFactory";
|
|
9
|
+
export { ExecutionTelemetryCostTrackingDecoratorFactory } from "./ExecutionTelemetryCostTrackingDecoratorFactory";
|
|
7
10
|
export { InProcessRetryRunner } from "./InProcessRetryRunner";
|
|
8
11
|
export { ItemExprResolver } from "./ItemExprResolver";
|
|
9
12
|
export { NodeOutputNormalizer } from "./NodeOutputNormalizer";
|
|
@@ -21,6 +24,7 @@ export { NodeRunStateWriterFactory } from "./NodeRunStateWriterFactory";
|
|
|
21
24
|
export { PersistedRunStateTerminalBuilder } from "./PersistedRunStateTerminalBuilder";
|
|
22
25
|
export { RunStateSemantics } from "./RunStateSemantics";
|
|
23
26
|
export { WorkflowRunExecutionContextFactory } from "./WorkflowRunExecutionContextFactory";
|
|
27
|
+
export { StaticCostCatalog } from "./StaticCostCatalog";
|
|
24
28
|
export type { AsyncSleeper } from "./asyncSleeper.types";
|
|
25
29
|
export { RunContinuationService } from "../orchestration/RunContinuationService";
|
|
26
30
|
export { RunStartService } from "../orchestration/RunStartService";
|
|
@@ -71,6 +71,7 @@ export class NodeExecutionRequestHandlerService implements NodeExecutionRequestH
|
|
|
71
71
|
workflowId: state.workflowId,
|
|
72
72
|
nodeId: request.nodeId,
|
|
73
73
|
parent: resolvedParent,
|
|
74
|
+
policySnapshot: state.policySnapshot,
|
|
74
75
|
subworkflowDepth: state.executionOptions?.subworkflowDepth ?? 0,
|
|
75
76
|
engineMaxNodeActivations: limits.engineMaxNodeActivations,
|
|
76
77
|
engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
|
|
@@ -135,6 +135,7 @@ export class RunContinuationService {
|
|
|
135
135
|
workflowId: state.workflowId,
|
|
136
136
|
nodeId: args.nodeId,
|
|
137
137
|
parent: state.parent,
|
|
138
|
+
policySnapshot: state.policySnapshot,
|
|
138
139
|
subworkflowDepth: state.executionOptions?.subworkflowDepth ?? 0,
|
|
139
140
|
engineMaxNodeActivations: limits.engineMaxNodeActivations,
|
|
140
141
|
engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
|
|
@@ -748,6 +749,7 @@ export class RunContinuationService {
|
|
|
748
749
|
workflowId: args.state.workflowId,
|
|
749
750
|
nodeId: nextDefinition.id,
|
|
750
751
|
parent: args.state.parent,
|
|
752
|
+
policySnapshot: args.state.policySnapshot,
|
|
751
753
|
subworkflowDepth: args.state.executionOptions?.subworkflowDepth ?? 0,
|
|
752
754
|
engineMaxNodeActivations: webhookLimits.engineMaxNodeActivations,
|
|
753
755
|
engineMaxSubworkflowDepth: webhookLimits.engineMaxSubworkflowDepth,
|
|
@@ -851,6 +853,7 @@ export class RunContinuationService {
|
|
|
851
853
|
workflowId: state.workflowId,
|
|
852
854
|
nodeId,
|
|
853
855
|
parent: state.parent,
|
|
856
|
+
policySnapshot: state.policySnapshot,
|
|
854
857
|
subworkflowDepth: state.executionOptions?.subworkflowDepth ?? 0,
|
|
855
858
|
engineMaxNodeActivations: limits.engineMaxNodeActivations,
|
|
856
859
|
engineMaxSubworkflowDepth: limits.engineMaxSubworkflowDepth,
|
|
@@ -864,6 +867,7 @@ export class RunContinuationService {
|
|
|
864
867
|
nodeId,
|
|
865
868
|
activationId,
|
|
866
869
|
config: def.config,
|
|
870
|
+
telemetry: base.telemetry.forNode({ nodeId, activationId }),
|
|
867
871
|
binary: base.binary.forNode({ nodeId, activationId }),
|
|
868
872
|
getCredential: this.credentialResolverFactory.create(wf.id, nodeId, def.config),
|
|
869
873
|
};
|
|
@@ -90,6 +90,7 @@ export class RunStartService {
|
|
|
90
90
|
workflowId: workflow.id,
|
|
91
91
|
nodeId: startAt,
|
|
92
92
|
parent,
|
|
93
|
+
policySnapshot,
|
|
93
94
|
subworkflowDepth: mergedExecutionOptions.subworkflowDepth ?? 0,
|
|
94
95
|
engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations!,
|
|
95
96
|
engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth!,
|
|
@@ -199,6 +200,7 @@ export class RunStartService {
|
|
|
199
200
|
request.workflow,
|
|
200
201
|
) ?? "unknown_node",
|
|
201
202
|
parent: request.parent,
|
|
203
|
+
policySnapshot,
|
|
202
204
|
subworkflowDepth: mergedExecutionOptions.subworkflowDepth ?? 0,
|
|
203
205
|
engineMaxNodeActivations: mergedExecutionOptions.maxNodeActivations!,
|
|
204
206
|
engineMaxSubworkflowDepth: mergedExecutionOptions.maxSubworkflowDepth!,
|
|
@@ -10,6 +10,12 @@ export class RunPolicySnapshotFactory {
|
|
|
10
10
|
const prune = workflow.prunePolicy;
|
|
11
11
|
const retentionSeconds = prune?.runDataRetentionSeconds ?? defaults?.retentionSeconds;
|
|
12
12
|
const binaryRetentionSeconds = prune?.binaryRetentionSeconds ?? defaults?.binaryRetentionSeconds;
|
|
13
|
+
const telemetrySpanRetentionSeconds =
|
|
14
|
+
prune?.telemetrySpanRetentionSeconds ?? defaults?.telemetrySpanRetentionSeconds;
|
|
15
|
+
const telemetryArtifactRetentionSeconds =
|
|
16
|
+
prune?.telemetryArtifactRetentionSeconds ?? defaults?.telemetryArtifactRetentionSeconds;
|
|
17
|
+
const telemetryMetricRetentionSeconds =
|
|
18
|
+
prune?.telemetryMetricRetentionSeconds ?? defaults?.telemetryMetricRetentionSeconds;
|
|
13
19
|
const storagePolicy: WorkflowStoragePolicyMode =
|
|
14
20
|
typeof workflow.storagePolicy === "string"
|
|
15
21
|
? (workflow.storagePolicy as WorkflowStoragePolicyMode)
|
|
@@ -17,6 +23,9 @@ export class RunPolicySnapshotFactory {
|
|
|
17
23
|
return {
|
|
18
24
|
retentionSeconds,
|
|
19
25
|
binaryRetentionSeconds,
|
|
26
|
+
telemetrySpanRetentionSeconds,
|
|
27
|
+
telemetryArtifactRetentionSeconds,
|
|
28
|
+
telemetryMetricRetentionSeconds,
|
|
20
29
|
storagePolicy,
|
|
21
30
|
};
|
|
22
31
|
}
|
|
@@ -87,14 +87,16 @@ export class InMemoryWorkflowExecutionRepository
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
async listRunsOlderThan(
|
|
90
|
-
args: Readonly<{
|
|
90
|
+
args: Readonly<{ nowIso: string; defaultRetentionSeconds: number; limit?: number }>,
|
|
91
91
|
): Promise<ReadonlyArray<RunPruneCandidate>> {
|
|
92
92
|
const limit = args.limit ?? 100;
|
|
93
93
|
const out: RunPruneCandidate[] = [];
|
|
94
94
|
for (const s of this.runs.values()) {
|
|
95
95
|
if (s.status !== "completed" && s.status !== "failed") continue;
|
|
96
96
|
const finishedAt = RunFinishedAtFactory.resolveIso(s);
|
|
97
|
-
|
|
97
|
+
const retentionSeconds = s.policySnapshot?.retentionSeconds ?? args.defaultRetentionSeconds;
|
|
98
|
+
const cutoffIso = new Date(new Date(args.nowIso).getTime() - retentionSeconds * 1000).toISOString();
|
|
99
|
+
if (!finishedAt || finishedAt >= cutoffIso) continue;
|
|
98
100
|
out.push({
|
|
99
101
|
runId: s.runId,
|
|
100
102
|
workflowId: s.workflowId,
|
package/src/types/index.ts
CHANGED
|
@@ -7,8 +7,13 @@ export * from "../contracts/NoRetryPolicy";
|
|
|
7
7
|
export * from "../contracts/RetryPolicy";
|
|
8
8
|
export * from "../contracts/ExpRetryPolicy";
|
|
9
9
|
export * from "../contracts/credentialTypes";
|
|
10
|
+
export * from "../contracts/CostCatalogContract";
|
|
11
|
+
export * from "../contracts/CostTrackingTelemetryContract";
|
|
12
|
+
export * from "../contracts/NoOpCostTrackingTelemetry";
|
|
13
|
+
export * from "../contracts/NoOpCostTrackingTelemetryFactory";
|
|
10
14
|
export * from "../contracts/executionPersistenceContracts";
|
|
11
15
|
export * from "../contracts/runtimeTypes";
|
|
16
|
+
export * from "../contracts/telemetryTypes";
|
|
12
17
|
export * from "../contracts/runFinishedAtFactory";
|
|
13
18
|
export * from "../contracts/runTypes";
|
|
14
19
|
export * from "../contracts/webhookTypes";
|