@codemation/core 0.14.0 → 0.15.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 +68 -0
- package/dist/{CostCatalogContract-B9aYIqJu.d.cts → CostCatalogContract-Dwo-ZamG.d.cts} +2 -2
- package/dist/EngineRuntimeRegistration.types-BiNasx3G.d.cts +54 -0
- package/dist/EngineRuntimeRegistration.types-Dq4ucrdo.d.ts +21 -0
- package/dist/{InMemoryRunDataFactory-C3rIszrW.d.cts → InMemoryRunDataFactory-D2U9azmZ.d.cts} +2 -20
- package/dist/{InMemoryRunEventBusRegistry-Sa86VxuV.cjs → InMemoryRunEventBusRegistry-DO0WM9Lw.cjs} +1 -1
- package/dist/{InMemoryRunEventBusRegistry-Sa86VxuV.cjs.map → InMemoryRunEventBusRegistry-DO0WM9Lw.cjs.map} +1 -1
- package/dist/{InMemoryRunEventBusRegistry-Bwunvt1T.js → InMemoryRunEventBusRegistry-Layt2xgm.js} +1 -1
- package/dist/{InMemoryRunEventBusRegistry-Bwunvt1T.js.map → InMemoryRunEventBusRegistry-Layt2xgm.js.map} +1 -1
- package/dist/{ItemsInputNormalizer-UCpn7luX.d.cts → ItemsInputNormalizer-A5txcOWX.d.cts} +3 -98
- package/dist/{ItemsInputNormalizer-B9SdLG24.cjs → ItemsInputNormalizer-C1fv3sMW.cjs} +2 -2
- package/dist/ItemsInputNormalizer-C1fv3sMW.cjs.map +1 -0
- package/dist/{ItemsInputNormalizer-DoOawd9R.d.ts → ItemsInputNormalizer-D2vrMrX1.d.ts} +2 -62
- package/dist/{ItemsInputNormalizer-CZEODg94.js → ItemsInputNormalizer-fUYo4GLV.js} +2 -2
- package/dist/ItemsInputNormalizer-fUYo4GLV.js.map +1 -0
- package/dist/{RunIntentService-0f3ICjAz.d.cts → RunIntentService-DKxuHTUz.d.cts} +2 -15
- package/dist/{RunIntentService-Dx_HHxDX.d.ts → RunIntentService-DrpKli2k.d.ts} +2 -22
- package/dist/{agentMcpTypes-B11B3Hd-.d.cts → agentMcpTypes-BHX4RQCC.d.cts} +24 -524
- package/dist/bootstrap/index.cjs +9 -5
- package/dist/bootstrap/index.d.cts +32 -106
- package/dist/bootstrap/index.d.ts +18 -17
- package/dist/bootstrap/index.js +6 -5
- package/dist/{bootstrap-Be0LB0nh.cjs → bootstrap-CTB53rEF.cjs} +9 -60
- package/dist/bootstrap-CTB53rEF.cjs.map +1 -0
- package/dist/{bootstrap-pSQdsMfa.js → bootstrap-DmqKheCI.js} +6 -57
- package/dist/bootstrap-DmqKheCI.js.map +1 -0
- package/dist/browser.cjs +12 -11
- package/dist/browser.d.cts +4 -4
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +3 -2
- package/dist/contracts-7L1wJHdk.cjs +569 -0
- package/dist/contracts-7L1wJHdk.cjs.map +1 -0
- package/dist/contracts-CjJ5CZ7N.js +447 -0
- package/dist/contracts-CjJ5CZ7N.js.map +1 -0
- package/dist/contracts.cjs +9 -2
- package/dist/contracts.d.cts +5 -5
- package/dist/contracts.d.ts +2 -2
- package/dist/contracts.js +3 -2
- package/dist/{executionPersistenceContracts-CX9Ql8N1.d.cts → deploymentManifestTypes-B8CDmZZK.d.cts} +65 -81
- package/dist/di-C6Ubf9o5.cjs +179 -0
- package/dist/di-C6Ubf9o5.cjs.map +1 -0
- package/dist/di-Cjiil7U-.js +114 -0
- package/dist/di-Cjiil7U-.js.map +1 -0
- package/dist/{index-CbJdbIHe.d.ts → index-CRv3_pY3.d.ts} +87 -870
- package/dist/{index-uPnD9EE6.d.ts → index-mnLS0iQl.d.ts} +27 -400
- package/dist/index.cjs +44 -115
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -524
- package/dist/index.d.ts +5 -5
- package/dist/index.js +21 -98
- package/dist/index.js.map +1 -1
- package/dist/{params-Dwl10Ws9.d.cts → params-CrK4iuG1.d.cts} +2 -11
- package/dist/{runtime-CSunvf7A.js → runtime-CBFDpmiz.js} +46 -679
- package/dist/runtime-CBFDpmiz.js.map +1 -0
- package/dist/{runtime-n2tqRwaf.cjs → runtime-Due-FOZ2.cjs} +69 -752
- package/dist/runtime-Due-FOZ2.cjs.map +1 -0
- package/dist/testing.cjs +8 -40
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +3 -32
- package/dist/testing.d.ts +3 -32
- package/dist/testing.js +6 -38
- package/dist/testing.js.map +1 -1
- package/dist/{di-DhwtDRgs.cjs → workflowTypes-BW6Hhee7.cjs} +4 -229
- package/dist/workflowTypes-BW6Hhee7.cjs.map +1 -0
- package/dist/{di-CEV6wTc4.js → workflowTypes-DZtBTmKf.js} +3 -162
- package/dist/workflowTypes-DZtBTmKf.js.map +1 -0
- package/package.json +1 -1
- package/src/ai/AgentConnectionNodeCollector.ts +0 -4
- package/src/ai/AgentMessageConfigNormalizerFactory.ts +0 -4
- package/src/ai/AiHost.ts +0 -38
- package/src/ai/CallableToolConfig.ts +0 -9
- package/src/ai/CallableToolKindToken.ts +0 -4
- package/src/authoring/callableTool.types.ts +0 -3
- package/src/authoring/defineCollection.types.ts +0 -11
- package/src/authoring/defineHumanApprovalNode.types.ts +0 -116
- package/src/authoring/defineNode.types.ts +0 -25
- package/src/authoring/definePollingTrigger.types.ts +18 -152
- package/src/authoring/definePollingTriggerInternals.ts +0 -4
- package/src/authoring/nodeBaseOptions.types.ts +0 -14
- package/src/binaries/boundedReadBinary.types.ts +0 -16
- package/src/bootstrap/index.ts +8 -2
- package/src/bootstrap/runtime/EngineRuntimeRegistrar.ts +0 -5
- package/src/bootstrap/runtime/EngineRuntimeRegistration.types.ts +0 -23
- package/src/browser.ts +0 -3
- package/src/contracts/AgentBindError.ts +0 -5
- package/src/contracts/Clock.ts +0 -1
- package/src/contracts/CodemationTelemetryAttributeNames.ts +0 -10
- package/src/contracts/NoOpAgentMcpIntegration.ts +0 -6
- package/src/contracts/NoOpTelemetrySpanScope.ts +0 -7
- package/src/contracts/RetryPolicy.ts +0 -2
- package/src/contracts/agentMcpTypes.ts +0 -34
- package/src/contracts/assertionTypes.ts +0 -33
- package/src/contracts/baseTypes.ts +0 -6
- package/src/contracts/collectionTypes.ts +0 -25
- package/src/contracts/credentialTypes.ts +13 -60
- package/src/contracts/deploymentManifestTypes.ts +158 -0
- package/src/contracts/dispatchTypes.ts +29 -0
- package/src/contracts/executionPersistenceContracts.ts +0 -33
- package/src/contracts/hitlSeamTypes.ts +0 -14
- package/src/contracts/humanTaskStoreTypes.ts +0 -2
- package/src/contracts/inboxChannelTypes.ts +0 -9
- package/src/contracts/index.ts +3 -0
- package/src/contracts/itemExpr.ts +0 -18
- package/src/contracts/itemMeta.ts +0 -3
- package/src/contracts/mcpTypes.ts +0 -16
- package/src/contracts/retryPolicySpec.types.ts +0 -10
- package/src/contracts/runFinishedAtFactory.ts +0 -1
- package/src/contracts/runTypes.ts +0 -74
- package/src/contracts/runtimeTypes.ts +4 -131
- package/src/contracts/telemetryTypes.ts +0 -7
- package/src/contracts/testTriggerTypes.ts +0 -43
- package/src/contracts/triggerInvokerTypes.ts +6 -0
- package/src/contracts/webhookTypes.ts +0 -8
- package/src/contracts/workflowActivationPolicy.ts +0 -5
- package/src/contracts/workflowTypes.ts +4 -86
- package/src/contracts/workspaceFileTypes.ts +0 -72
- package/src/contracts.ts +18 -10
- package/src/credentials/CredentialMaterialProvider.types.ts +0 -28
- package/src/credentials/ManagedCredentialMaterialWriteError.ts +0 -6
- package/src/credentials/ManagedMaterialFetchError.ts +0 -6
- package/src/credentials/OAuthFlowExecutor.types.ts +0 -15
- package/src/di/CoreTokens.ts +2 -6
- package/src/events/ConnectionInvocationEventPublisher.ts +0 -7
- package/src/events/NodeEventPublisher.ts +0 -1
- package/src/events/runEvents.ts +0 -8
- package/src/execution/ActivationEnqueueService.ts +0 -10
- package/src/execution/ChildExecutionScopeFactory.ts +0 -13
- package/src/execution/FanInMergeByOriginMerger.ts +0 -11
- package/src/execution/InProcessRetryRunner.ts +0 -1
- package/src/execution/ItemExprResolver.ts +0 -3
- package/src/execution/NodeActivationRequestComposer.ts +0 -3
- package/src/execution/NodeActivationRequestInputPreparer.ts +0 -5
- package/src/execution/NodeExecutionSnapshotFactory.ts +0 -1
- package/src/execution/NodeExecutor.ts +1 -17
- package/src/execution/NodeSuspensionHandler.ts +1 -39
- package/src/execution/PersistedRunStateTerminalBuilder.ts +0 -5
- package/src/execution/RunSuspendedError.ts +0 -10
- package/src/execution/WorkflowRunExecutionContextFactory.ts +0 -3
- package/src/orchestration/AbortControllerFactory.ts +0 -4
- package/src/orchestration/Engine.ts +0 -9
- package/src/orchestration/NodeExecutionRequestHandlerService.ts +3 -4
- package/src/orchestration/RunContinuationService.ts +7 -39
- package/src/orchestration/RunStartService.ts +0 -7
- package/src/orchestration/TestSuiteOrchestrator.ts +0 -18
- package/src/orchestration/TestSuiteRunIdFactory.ts +0 -4
- package/src/orchestration/TriggerRuntimeService.ts +3 -2
- package/src/planning/CurrentStateFrontierPlanner.ts +0 -1
- package/src/planning/RunQueuePlanner.ts +0 -6
- package/src/policies/executionLimits/EngineExecutionLimitsPolicy.ts +0 -8
- package/src/policies/executionLimits/EngineExecutionLimitsPolicyFactory.ts +0 -3
- package/src/runStorage/RunSummaryMapper.ts +0 -1
- package/src/runtime/EngineFactory.ts +6 -11
- package/src/runtime/RunIntentService.ts +0 -4
- package/src/runtime/WorkflowRepositoryWebhookTriggerMatcher.ts +0 -4
- package/src/runtime-types/InjectableRuntimeDecoratorComposerRegistry.ts +0 -4
- package/src/runtime-types/PersistedRuntimeTypeMetadataStoreRegistry.ts +0 -4
- package/src/runtime-types/PersistedRuntimeTypeNameResolver.ts +0 -1
- package/src/runtime-types/persistedRuntimeTypeModelRegistry.ts +0 -4
- package/src/runtime-types/runtimeTypeDecorators.types.ts +0 -12
- package/src/scheduler/ConfigDrivenOffloadPolicy.ts +0 -1
- package/src/scheduler/DefaultDrivingScheduler.ts +0 -6
- package/src/scheduler/InlineDrivingScheduler.ts +0 -13
- package/src/serialization/ItemsInputNormalizer.ts +0 -5
- package/src/testing/CapturingScheduler.ts +0 -3
- package/src/testing/EngineTestKitRunIdFactory.ts +0 -3
- package/src/testing/ItemHarnessNode.ts +0 -3
- package/src/testing/ItemHarnessNodeConfig.ts +0 -4
- package/src/testing/PrefixedSequentialIdGenerator.ts +0 -3
- package/src/testing/RegistrarEngineTestKit.types.ts +0 -2
- package/src/testing/RejectingCredentialSessionService.ts +0 -4
- package/src/testing/SubWorkflowRunnerTestNode.ts +0 -3
- package/src/testing/WorkflowTestHarnessManualTrigger.ts +0 -3
- package/src/testing/WorkflowTestKitBuilder.ts +0 -4
- package/src/testing/WorkflowTestKitRunNodeWorkflowFactory.ts +0 -3
- package/src/testing.ts +0 -3
- package/src/triggers/polling/PollingTriggerDedupWindow.ts +0 -4
- package/src/triggers/polling/PollingTriggerLogger.ts +0 -5
- package/src/triggers/polling/PollingTriggerRuntime.ts +0 -5
- package/src/types/index.ts +0 -6
- package/src/validation/WorkflowEdgePortValidator.ts +0 -5
- package/src/workflow/definition/ConnectionInvocationIdFactory.ts +0 -7
- package/src/workflow/definition/ConnectionNodeIdFactory.ts +0 -6
- package/src/workflow/definition/NodeIterationIdFactory.ts +0 -13
- package/src/workflow/definition/WorkflowExecutableNodeClassifier.ts +0 -6
- package/src/workflow/dsl/ChainCursorResolver.ts +0 -20
- package/src/workflow/dsl/NodeIdSlugifier.ts +0 -9
- package/src/workflow/dsl/WhenBuilder.ts +0 -17
- package/src/workflow/dsl/WorkflowDefinitionError.ts +0 -9
- package/src/workflow/dsl/workflowBuilderTypes.ts +0 -24
- package/src/workflowSnapshots/MissingRuntimeParityGuard.ts +24 -0
- package/src/workflowSnapshots/PersistedWorkflowTokenRegistry.ts +0 -6
- package/src/workflowSnapshots/WorkflowParityMismatchError.ts +18 -0
- package/src/workflowSnapshots/WorkflowSnapshotCodec.ts +0 -5
- package/src/workflowSnapshots/index.ts +3 -0
- package/dist/EngineRuntimeRegistration.types-BYAmGMdS.d.cts +0 -81
- package/dist/EngineRuntimeRegistration.types-CVLI8DsJ.d.ts +0 -44
- package/dist/ItemsInputNormalizer-B9SdLG24.cjs.map +0 -1
- package/dist/ItemsInputNormalizer-CZEODg94.js.map +0 -1
- package/dist/bootstrap-Be0LB0nh.cjs.map +0 -1
- package/dist/bootstrap-pSQdsMfa.js.map +0 -1
- package/dist/contracts-CK0x6w_G.cjs +0 -74
- package/dist/contracts-CK0x6w_G.cjs.map +0 -1
- package/dist/contracts-DXdfTdpW.js +0 -50
- package/dist/contracts-DXdfTdpW.js.map +0 -1
- package/dist/di-CEV6wTc4.js.map +0 -1
- package/dist/di-DhwtDRgs.cjs.map +0 -1
- package/dist/runtime-CSunvf7A.js.map +0 -1
- package/dist/runtime-n2tqRwaf.cjs.map +0 -1
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
import type { EngineRunCounters, PersistedRunState, RunHaltReason, RunQueueEntry } from "../types";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Merges common terminal-run fields onto a loaded {@link PersistedRunState} without repeating object literals.
|
|
5
|
-
*/
|
|
6
3
|
export class PersistedRunStateTerminalBuilder {
|
|
7
4
|
mergeTerminal(args: {
|
|
8
5
|
state: PersistedRunState;
|
|
9
6
|
engineCounters: EngineRunCounters;
|
|
10
7
|
status: "completed" | "failed" | "halted";
|
|
11
|
-
/** Populated when `status === "halted"`. */
|
|
12
8
|
reason?: RunHaltReason;
|
|
13
9
|
queue: RunQueueEntry[];
|
|
14
10
|
outputsByNode: PersistedRunState["outputsByNode"];
|
|
15
11
|
nodeSnapshotsByNodeId: NonNullable<PersistedRunState["nodeSnapshotsByNodeId"]>;
|
|
16
|
-
/** When set, persisted on the run root for listings and retention pruning. */
|
|
17
12
|
finishedAtIso?: string;
|
|
18
13
|
}): PersistedRunState {
|
|
19
14
|
return {
|
|
@@ -1,15 +1,5 @@
|
|
|
1
1
|
import type { RunId } from "../types";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Internal sentinel thrown by {@link NodeSuspensionHandler} after persisting a suspension
|
|
5
|
-
* entry. `NodeExecutionRequestHandlerService` catches this specifically and returns cleanly —
|
|
6
|
-
* no continuation call, preventing `resumeFromNodeResult` / `resumeFromNodeError` from
|
|
7
|
-
* overwriting the `"suspended"` run status.
|
|
8
|
-
*
|
|
9
|
-
* The `Error` suffix satisfies the ESLint `no-manual-di-new` allowlist. This is NOT a
|
|
10
|
-
* user-facing error — it is an engine-internal control-flow primitive and should NOT be
|
|
11
|
-
* exported from the public barrel.
|
|
12
|
-
*/
|
|
13
3
|
export class RunSuspendedError extends Error {
|
|
14
4
|
constructor(
|
|
15
5
|
readonly runId: RunId,
|
|
@@ -11,9 +11,6 @@ import type {
|
|
|
11
11
|
|
|
12
12
|
import { CredentialResolverFactory } from "./CredentialResolverFactory";
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
* Shared {@link ExecutionContextFactory#create} wiring for workflow runners (base context before node-specific fields).
|
|
16
|
-
*/
|
|
17
14
|
export class WorkflowRunExecutionContextFactory {
|
|
18
15
|
constructor(
|
|
19
16
|
private readonly executionContextFactory: ExecutionContextFactory,
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mints fresh {@link AbortController}s. Injected (rather than direct `new`) to honor the
|
|
3
|
-
* codebase's no-direct-construction rule and to give tests a seam for substituting a fake.
|
|
4
|
-
*/
|
|
5
1
|
export class AbortControllerFactory {
|
|
6
2
|
create(): AbortController {
|
|
7
3
|
return new AbortController();
|
|
@@ -98,11 +98,6 @@ export interface EngineFacadeDeps {
|
|
|
98
98
|
nodeExecutionRequestHandler: EngineNodeExecutionRequestHandler;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
/**
|
|
102
|
-
* Runtime facade for orchestration, continuation, triggers, and webhook routing.
|
|
103
|
-
* Prefer {@link import("../intents/RunIntentService").RunIntentService} for host/HTTP invocation boundaries.
|
|
104
|
-
* The class token is exported from `@codemation/core/bootstrap` (not the main `@codemation/core` barrel).
|
|
105
|
-
*/
|
|
106
101
|
export class Engine implements NodeActivationContinuation, NodeExecutionRequestHandler {
|
|
107
102
|
constructor(private readonly deps: EngineFacadeDeps) {}
|
|
108
103
|
|
|
@@ -236,10 +231,6 @@ export class Engine implements NodeActivationContinuation, NodeExecutionRequestH
|
|
|
236
231
|
return await this.deps.runContinuationService.waitForWebhookResponse(runId);
|
|
237
232
|
}
|
|
238
233
|
|
|
239
|
-
/**
|
|
240
|
-
* Re-activate a suspended run item with a human decision (HITL).
|
|
241
|
-
* The HTTP resume endpoint calls this; this method exposes the engine primitive.
|
|
242
|
-
*/
|
|
243
234
|
async resumeRun(args: { runId: RunId; taskId: string; resumeContext: ResumeContext }): Promise<RunResult> {
|
|
244
235
|
return await this.deps.runContinuationService.resumeRun(args);
|
|
245
236
|
}
|
|
@@ -15,6 +15,7 @@ import { RunSuspendedError } from "../execution/RunSuspendedError";
|
|
|
15
15
|
import { NodeActivationRequestComposer } from "../execution/NodeActivationRequestComposer";
|
|
16
16
|
import { NodeRunStateWriterFactory } from "../execution/NodeRunStateWriterFactory";
|
|
17
17
|
import { WorkflowRunExecutionContextFactory } from "../execution/WorkflowRunExecutionContextFactory";
|
|
18
|
+
import { MissingRuntimeParityGuard } from "../workflowSnapshots/MissingRuntimeParityGuard";
|
|
18
19
|
|
|
19
20
|
type PersistedWorkflowLike = Readonly<{
|
|
20
21
|
workflowId: PersistedRunState["workflowId"];
|
|
@@ -32,6 +33,7 @@ export class NodeExecutionRequestHandlerService implements NodeExecutionRequestH
|
|
|
32
33
|
private readonly nodeExecutor: NodeExecutor,
|
|
33
34
|
private readonly continuation: NodeActivationContinuation,
|
|
34
35
|
private readonly executionLimitsPolicy: EngineExecutionLimitsPolicy,
|
|
36
|
+
private readonly parityGuard: MissingRuntimeParityGuard,
|
|
35
37
|
) {}
|
|
36
38
|
|
|
37
39
|
async handleNodeExecutionRequest(request: NodeExecutionRequest): Promise<void> {
|
|
@@ -86,7 +88,6 @@ export class NodeExecutionRequestHandlerService implements NodeExecutionRequestH
|
|
|
86
88
|
const portKeys = Object.keys(inputsByPort);
|
|
87
89
|
const kind = portKeys.length === 1 && portKeys[0] === "in" ? ("single" as const) : ("multi" as const);
|
|
88
90
|
const batchId = pendingExecution.batchId ?? "batch_1";
|
|
89
|
-
// Splice resumeContext from pendingResume if this activation is a HITL resume.
|
|
90
91
|
const pendingResume = state.pendingResume;
|
|
91
92
|
const resumeContext: ResumeContext | undefined =
|
|
92
93
|
pendingResume?.activationId === request.activationId && pendingResume?.nodeId === request.nodeId
|
|
@@ -127,7 +128,6 @@ export class NodeExecutionRequestHandlerService implements NodeExecutionRequestH
|
|
|
127
128
|
input: inputsByPort.in ?? request.input ?? [],
|
|
128
129
|
});
|
|
129
130
|
|
|
130
|
-
// Clear pendingResume from state now that we have consumed it.
|
|
131
131
|
if (resumeContext != null) {
|
|
132
132
|
const clearedState = await this.workflowExecutionRepository.load(request.runId);
|
|
133
133
|
if (clearedState?.pendingResume?.activationId === request.activationId) {
|
|
@@ -144,11 +144,10 @@ export class NodeExecutionRequestHandlerService implements NodeExecutionRequestH
|
|
|
144
144
|
|
|
145
145
|
let outputs;
|
|
146
146
|
try {
|
|
147
|
+
this.parityGuard.assertNone(workflow, [request.nodeId]);
|
|
147
148
|
outputs = await this.nodeExecutor.execute(activationRequest);
|
|
148
149
|
} catch (error) {
|
|
149
150
|
if (error instanceof RunSuspendedError) {
|
|
150
|
-
// The node threw SuspensionRequest; NodeSuspensionHandler already persisted the
|
|
151
|
-
// suspension entry and flipped status to "suspended". Nothing more to do here.
|
|
152
151
|
return;
|
|
153
152
|
}
|
|
154
153
|
await this.resumeAfterExecutionError(activationRequest, this.asError(error));
|
|
@@ -46,6 +46,7 @@ import { NodeActivationRequestComposer } from "../execution/NodeActivationReques
|
|
|
46
46
|
import { PersistedRunStateTerminalBuilder } from "../execution/PersistedRunStateTerminalBuilder";
|
|
47
47
|
import { RunStateSemantics } from "../execution/RunStateSemantics";
|
|
48
48
|
import { WorkflowRunExecutionContextFactory } from "../execution/WorkflowRunExecutionContextFactory";
|
|
49
|
+
import { MissingRuntimeParityGuard } from "../workflowSnapshots/MissingRuntimeParityGuard";
|
|
49
50
|
|
|
50
51
|
export class RunContinuationService {
|
|
51
52
|
constructor(
|
|
@@ -66,6 +67,7 @@ export class RunContinuationService {
|
|
|
66
67
|
private readonly policyErrorServices: WorkflowPolicyErrorServices,
|
|
67
68
|
private readonly terminalPersistence: RunTerminalPersistenceCoordinator,
|
|
68
69
|
private readonly executionLimitsPolicy: EngineExecutionLimitsPolicy,
|
|
70
|
+
private readonly parityGuard: MissingRuntimeParityGuard,
|
|
69
71
|
) {}
|
|
70
72
|
|
|
71
73
|
async markNodeRunning(args: {
|
|
@@ -151,9 +153,6 @@ export class RunContinuationService {
|
|
|
151
153
|
data.setOutputs(args.nodeId, args.outputs);
|
|
152
154
|
const completedAt = new Date().toISOString();
|
|
153
155
|
|
|
154
|
-
// Resolve HITL status from the node's decision output.
|
|
155
|
-
// Only fires when the output carries `item.json.decision.status` written by a
|
|
156
|
-
// defineHumanApprovalNode-based node. Non-HITL nodes never have this field.
|
|
157
156
|
const hitlResolution = this.resolveHitlStatus(args.outputs);
|
|
158
157
|
|
|
159
158
|
const completedSnapshot = this.semantics.createFinishedSnapshot({
|
|
@@ -170,7 +169,6 @@ export class RunContinuationService {
|
|
|
170
169
|
hitlStatus: hitlResolution?.nodeStatus,
|
|
171
170
|
});
|
|
172
171
|
|
|
173
|
-
// Halt the run for HITL rejection / timeout outcomes.
|
|
174
172
|
if (hitlResolution?.halt) {
|
|
175
173
|
const haltedState = this.persistedRunStateTerminalBuilder.mergeTerminal({
|
|
176
174
|
state,
|
|
@@ -355,6 +353,7 @@ export class RunContinuationService {
|
|
|
355
353
|
});
|
|
356
354
|
|
|
357
355
|
try {
|
|
356
|
+
this.parityGuard.assertNone(wf, [next.nodeId]);
|
|
358
357
|
const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
|
|
359
358
|
runId: state.runId,
|
|
360
359
|
workflowId: state.workflowId,
|
|
@@ -461,9 +460,7 @@ export class RunContinuationService {
|
|
|
461
460
|
nodeId: args.nodeId,
|
|
462
461
|
outputs: recovered,
|
|
463
462
|
});
|
|
464
|
-
} catch {
|
|
465
|
-
// fall through to workflow-level failure
|
|
466
|
-
}
|
|
463
|
+
} catch {}
|
|
467
464
|
}
|
|
468
465
|
}
|
|
469
466
|
|
|
@@ -591,20 +588,6 @@ export class RunContinuationService {
|
|
|
591
588
|
return await this.waiters.waitForWebhookResponse(runId);
|
|
592
589
|
}
|
|
593
590
|
|
|
594
|
-
/**
|
|
595
|
-
* Re-activate a previously suspended run item with a human decision.
|
|
596
|
-
*
|
|
597
|
-
* Called by the HITL resume endpoint. This method:
|
|
598
|
-
* 1. Loads `PersistedRunState` and locates the suspension entry by `taskId`.
|
|
599
|
-
* 2. Removes the entry from the `suspension` array; if empty, run stays `"suspended"` until
|
|
600
|
-
* enqueue flips it to `"pending"`.
|
|
601
|
-
* 3. Writes `pendingResume` onto the state so `NodeExecutionRequestHandlerService` can
|
|
602
|
-
* splice `resumeContext` into the node's execution context.
|
|
603
|
-
* 4. Reconstructs the original input from `outputsByNode` of the upstream node and
|
|
604
|
-
* enqueues a new activation via `activationEnqueueService`.
|
|
605
|
-
*
|
|
606
|
-
* @throws if the run is not found, not suspended, or the `taskId` is unknown.
|
|
607
|
-
*/
|
|
608
591
|
async resumeRun(args: { runId: RunId; taskId: string; resumeContext: ResumeContext }): Promise<RunResult> {
|
|
609
592
|
const state = await this.workflowExecutionRepository.load(args.runId);
|
|
610
593
|
if (!state) throw new Error(`Unknown runId: ${args.runId}`);
|
|
@@ -626,8 +609,6 @@ export class RunContinuationService {
|
|
|
626
609
|
throw new Error(`Node ${suspensionEntry.nodeId} is not a runnable node`);
|
|
627
610
|
}
|
|
628
611
|
|
|
629
|
-
// Reconstruct input: find the parent node that fed this node and use its main output.
|
|
630
|
-
// The single-item input corresponds to `itemIndex` in the original activation batch.
|
|
631
612
|
const data = this.runDataFactory.create(state.outputsByNode);
|
|
632
613
|
const limits = this.resolveEngineLimitsFromState(state);
|
|
633
614
|
const base = this.runExecutionContextFactory.create({
|
|
@@ -644,13 +625,10 @@ export class RunContinuationService {
|
|
|
644
625
|
testContext: state.executionOptions?.testContext,
|
|
645
626
|
});
|
|
646
627
|
|
|
647
|
-
// Find the original input items for this node from upstream outputs.
|
|
648
|
-
// Use the workflow edges to resolve the parent node. If no parent found, fall back to empty.
|
|
649
628
|
const parentEdges = wf.edges.filter((e) => e.to.nodeId === suspensionEntry.nodeId);
|
|
650
629
|
const parentNodeId = parentEdges[0]?.from.nodeId;
|
|
651
630
|
const parentOutputPort = parentEdges[0]?.from.output ?? "main";
|
|
652
631
|
const allParentItems = parentNodeId ? (data.getOutputItems(parentNodeId, parentOutputPort) ?? []) : [];
|
|
653
|
-
// Each suspended item gets its own resume; pass the single item at itemIndex.
|
|
654
632
|
const resumeInput =
|
|
655
633
|
allParentItems.length > suspensionEntry.itemIndex ? [allParentItems[suspensionEntry.itemIndex]!] : allParentItems;
|
|
656
634
|
|
|
@@ -663,10 +641,6 @@ export class RunContinuationService {
|
|
|
663
641
|
|
|
664
642
|
const remainingSuspensions = (state.suspension ?? []).filter((s) => s.taskId !== args.taskId);
|
|
665
643
|
|
|
666
|
-
// Thread resumeContext into the execution context so the inline scheduler path
|
|
667
|
-
// (InlineDrivingScheduler) delivers it directly to the node's ctx.resumeContext.
|
|
668
|
-
// On the worker path (BullMQ), NodeExecutionRequestHandlerService re-derives it
|
|
669
|
-
// from state.pendingResume — passing it here is additive and harmless.
|
|
670
644
|
const baseWithResume = { ...base, resumeContext: args.resumeContext };
|
|
671
645
|
|
|
672
646
|
const batchId = `resume_${newActivationId}`;
|
|
@@ -683,6 +657,8 @@ export class RunContinuationService {
|
|
|
683
657
|
input: resumeInput,
|
|
684
658
|
});
|
|
685
659
|
|
|
660
|
+
this.parityGuard.assertNone(wf, [suspensionEntry.nodeId]);
|
|
661
|
+
|
|
686
662
|
const { result, queuedSnapshot } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
|
|
687
663
|
runId: state.runId,
|
|
688
664
|
workflowId: state.workflowId,
|
|
@@ -944,6 +920,7 @@ export class RunContinuationService {
|
|
|
944
920
|
});
|
|
945
921
|
|
|
946
922
|
try {
|
|
923
|
+
this.parityGuard.assertNone(args.workflow, [next.nodeId]);
|
|
947
924
|
const { queuedSnapshot, result } = await this.activationEnqueueService.enqueueActivationWithSnapshot({
|
|
948
925
|
runId: args.state.runId,
|
|
949
926
|
workflowId: args.state.workflowId,
|
|
@@ -1084,10 +1061,6 @@ export class RunContinuationService {
|
|
|
1084
1061
|
};
|
|
1085
1062
|
}
|
|
1086
1063
|
|
|
1087
|
-
/**
|
|
1088
|
-
* Next activation could not be enqueued (e.g. input contract / mapping failed in the preparer).
|
|
1089
|
-
* Marks the target node failed and terminates the run.
|
|
1090
|
-
*/
|
|
1091
1064
|
private async terminateRunAfterActivationEnqueueRejected(
|
|
1092
1065
|
args: Readonly<{
|
|
1093
1066
|
wf: WorkflowDefinition;
|
|
@@ -1166,11 +1139,6 @@ export class RunContinuationService {
|
|
|
1166
1139
|
return result;
|
|
1167
1140
|
}
|
|
1168
1141
|
|
|
1169
|
-
/**
|
|
1170
|
-
* Inspects node outputs for a `decision.status` written by `defineHumanApprovalNode`.
|
|
1171
|
-
* Returns the first-class HITL node status and halt classification, or `undefined`
|
|
1172
|
-
* when the node is not a HITL approval node.
|
|
1173
|
-
*/
|
|
1174
1142
|
private resolveHitlStatus(outputs: NodeOutputs):
|
|
1175
1143
|
| {
|
|
1176
1144
|
nodeStatus: Extract<
|
|
@@ -277,13 +277,6 @@ export class RunStartService {
|
|
|
277
277
|
currentState: RunCurrentState | undefined,
|
|
278
278
|
mutableState: NonNullable<Awaited<ReturnType<WorkflowExecutionRepository["load"]>>>["mutableState"],
|
|
279
279
|
): RunCurrentState {
|
|
280
|
-
// Each `ConnectionInvocationRecord` represents a single, auditable LLM/tool call
|
|
281
|
-
// that must belong to exactly one run. Reruns start from a fresh invocation
|
|
282
|
-
// ledger so the new run only records what it actually invokes. The prior run's
|
|
283
|
-
// invocations remain queryable on that run's persisted state (their true owner).
|
|
284
|
-
// Carrying them over here would write duplicate `ExecutionInstance` rows whose
|
|
285
|
-
// primary key (`invocationId`) already exists under the previous run, causing a
|
|
286
|
-
// `Unique constraint failed on the fields: (instance_id)` violation on first save.
|
|
287
280
|
return {
|
|
288
281
|
outputsByNode: { ...(currentState?.outputsByNode ?? {}) },
|
|
289
282
|
nodeSnapshotsByNodeId: { ...(currentState?.nodeSnapshotsByNodeId ?? {}) },
|
|
@@ -21,10 +21,6 @@ import { TestSuiteRunIdFactory } from "./TestSuiteRunIdFactory";
|
|
|
21
21
|
|
|
22
22
|
const DEFAULT_CONCURRENCY = 4;
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
* Engine-facade subset the orchestrator needs. Kept narrow on purpose so unit tests can
|
|
26
|
-
* substitute a fake without depending on the full Engine wiring.
|
|
27
|
-
*/
|
|
28
24
|
export interface TestSuiteOrchestratorEngine {
|
|
29
25
|
runWorkflow(
|
|
30
26
|
wf: WorkflowDefinition,
|
|
@@ -61,15 +57,6 @@ export interface RunTestSuiteArgs {
|
|
|
61
57
|
readonly signal?: AbortSignal;
|
|
62
58
|
}
|
|
63
59
|
|
|
64
|
-
/**
|
|
65
|
-
* Drives a {@link TestTriggerNodeConfig.generateItems} iterable into one workflow run per item,
|
|
66
|
-
* with bounded concurrency. Pure engine logic — no persistence, no HTTP, no UI. Hosts adapt by
|
|
67
|
-
* subscribing to {@link RunEventBus} and writing rows on `testSuite*` / `testCase*` / `nodeCompleted`.
|
|
68
|
-
*
|
|
69
|
-
* Cancellation: the supplied `AbortSignal` aborts the source iterable (so credentialed pulls bail)
|
|
70
|
-
* and stops scheduling further cases. In-flight cases are awaited; engine-level cancellation of
|
|
71
|
-
* an already-dispatched run is not yet wired (Phase 2).
|
|
72
|
-
*/
|
|
73
60
|
export class TestSuiteOrchestrator {
|
|
74
61
|
constructor(
|
|
75
62
|
private readonly engine: TestSuiteOrchestratorEngine,
|
|
@@ -282,10 +269,6 @@ export class TestSuiteOrchestrator {
|
|
|
282
269
|
terminal = await this.engine.waitForCompletion(runId);
|
|
283
270
|
}
|
|
284
271
|
|
|
285
|
-
// RunResult.status from the engine narrows to "completed" | "failed" | "halted" here; widening to
|
|
286
|
-
// "errored" / "cancelled" happens outside this code path (tracker downgrade for assertion
|
|
287
|
-
// failures; outer abort handling for cancelled). Halted runs are treated as "failed" for
|
|
288
|
-
// test case status purposes.
|
|
289
272
|
const status: TestCaseRunStatus = terminal.status === "completed" ? "succeeded" : "failed";
|
|
290
273
|
await this.publish({
|
|
291
274
|
kind: "testCaseCompleted",
|
|
@@ -331,7 +314,6 @@ export class TestSuiteOrchestrator {
|
|
|
331
314
|
return this.currentDate().toISOString();
|
|
332
315
|
}
|
|
333
316
|
|
|
334
|
-
/** Defensive label resolver — author-supplied callbacks throw / return non-strings; we tolerate both. */
|
|
335
317
|
private resolveCaseLabel(config: TestTriggerNodeConfig<unknown>, item: Item<unknown>): string | undefined {
|
|
336
318
|
if (typeof config.caseLabel !== "function") return undefined;
|
|
337
319
|
try {
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import type { TestSuiteRunId } from "../contracts/testTriggerTypes";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Mints unique TestSuiteRun identifiers. Separated from {@link import("../types").RunIdFactory}
|
|
5
|
-
* so suite ids and per-case workflow run ids never alias.
|
|
6
|
-
*/
|
|
7
3
|
export class TestSuiteRunIdFactory {
|
|
8
4
|
makeTestSuiteRunId(): TestSuiteRunId {
|
|
9
5
|
return `tsr_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
@@ -26,7 +26,7 @@ import type { NodeRunStateWriterFactory } from "../execution/NodeRunStateWriterF
|
|
|
26
26
|
import type { EngineExecutionLimitsPolicy } from "../policies/executionLimits/EngineExecutionLimitsPolicy";
|
|
27
27
|
import type { PollingTriggerRuntime } from "../triggers/polling/PollingTriggerRuntime";
|
|
28
28
|
import type { PollingTriggerDedupWindow } from "../triggers/polling/PollingTriggerDedupWindow";
|
|
29
|
-
import type { PollingTriggerHandle } from "../contracts/runtimeTypes";
|
|
29
|
+
import type { PollingTriggerHandle, TriggerPollingPort } from "../contracts/runtimeTypes";
|
|
30
30
|
|
|
31
31
|
export interface TriggerEmitHandler {
|
|
32
32
|
emit(workflow: WorkflowDefinition, triggerNodeId: NodeId, items: Items): Promise<void>;
|
|
@@ -268,7 +268,7 @@ export class TriggerRuntimeService {
|
|
|
268
268
|
|
|
269
269
|
private buildPollingHandle(trigger: TriggerInstanceId, emit: (items: Items) => Promise<void>): PollingTriggerHandle {
|
|
270
270
|
const runtime = this.pollingTriggerRuntime;
|
|
271
|
-
|
|
271
|
+
const handle: PollingTriggerHandle = {
|
|
272
272
|
dedup: this.pollingTriggerDedupWindow,
|
|
273
273
|
start: async (args) => {
|
|
274
274
|
this.registerTriggerCleanupHandle(trigger, {
|
|
@@ -279,6 +279,7 @@ export class TriggerRuntimeService {
|
|
|
279
279
|
return runtime.start({ trigger, emit, ...args });
|
|
280
280
|
},
|
|
281
281
|
};
|
|
282
|
+
return handle satisfies TriggerPollingPort;
|
|
282
283
|
}
|
|
283
284
|
|
|
284
285
|
private isTestableTriggerNode(node: TriggerNode): node is TestableTriggerNode<TriggerNodeConfig> {
|
|
@@ -19,7 +19,6 @@ import { WorkflowTopology } from "./WorkflowTopologyPlanner";
|
|
|
19
19
|
export class CurrentStateFrontierPlanner {
|
|
20
20
|
constructor(private readonly topology: WorkflowTopology) {}
|
|
21
21
|
|
|
22
|
-
/** Composition-root-friendly factory (avoids `new` at orchestration call sites under ESLint manual-DI rules). */
|
|
23
22
|
static createFromTopology(topology: WorkflowTopology): CurrentStateFrontierPlanner {
|
|
24
23
|
return new CurrentStateFrontierPlanner(topology);
|
|
25
24
|
}
|
|
@@ -150,12 +150,6 @@ export class RunQueuePlanner {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
/**
|
|
154
|
-
* Matches `CurrentStateFrontierPlanner.buildFrontierQueue`: anything that is not exactly one input
|
|
155
|
-
* port named `in` participates in multi-port collect (Merge after `If` branches, etc.). Routing must
|
|
156
|
-
* not depend solely on `nodeInstances.get(toNodeId)?.executeMulti`, or a Merge can be enqueued as a
|
|
157
|
-
* single-input job and `NodeExecutor` will call `execute` on a multi-input-only implementation.
|
|
158
|
-
*/
|
|
159
153
|
private usesTopologyCollectMerge(toNodeId: NodeId): boolean {
|
|
160
154
|
const expectedInputs = this.topology.expectedInputsByNode.get(toNodeId) ?? [];
|
|
161
155
|
if (expectedInputs.length !== 1 || expectedInputs[0] !== "in") {
|
|
@@ -7,7 +7,6 @@ export interface EngineExecutionLimitsPolicyConfig {
|
|
|
7
7
|
readonly hardMaxSubworkflowDepth: number;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
/** Framework defaults for {@link EngineExecutionLimitsPolicy} (merged with host `runtime.engineExecutionLimits`). */
|
|
11
10
|
export const ENGINE_EXECUTION_LIMITS_DEFAULTS: EngineExecutionLimitsPolicyConfig = {
|
|
12
11
|
defaultMaxNodeActivations: 100_000,
|
|
13
12
|
hardMaxNodeActivations: 100_000,
|
|
@@ -15,16 +14,9 @@ export const ENGINE_EXECUTION_LIMITS_DEFAULTS: EngineExecutionLimitsPolicyConfig
|
|
|
15
14
|
hardMaxSubworkflowDepth: 32,
|
|
16
15
|
};
|
|
17
16
|
|
|
18
|
-
/**
|
|
19
|
-
* Resolves per-run execution limits: defaults, hard ceilings, and subworkflow depth for new runs.
|
|
20
|
-
*/
|
|
21
17
|
export class EngineExecutionLimitsPolicy {
|
|
22
18
|
constructor(private readonly config: EngineExecutionLimitsPolicyConfig = ENGINE_EXECUTION_LIMITS_DEFAULTS) {}
|
|
23
19
|
|
|
24
|
-
/**
|
|
25
|
-
* Effective options for a new root run (depth 0): defaults merged with engine ceilings.
|
|
26
|
-
* Replaces a separate one-method factory for root-run bootstrap.
|
|
27
|
-
*/
|
|
28
20
|
createRootExecutionOptions(): RunExecutionOptions {
|
|
29
21
|
return this.mergeExecutionOptionsForNewRun(undefined, undefined);
|
|
30
22
|
}
|
|
@@ -4,9 +4,6 @@ import {
|
|
|
4
4
|
type EngineExecutionLimitsPolicyConfig,
|
|
5
5
|
} from "./EngineExecutionLimitsPolicy";
|
|
6
6
|
|
|
7
|
-
/**
|
|
8
|
-
* Builds {@link EngineExecutionLimitsPolicy} by merging {@link ENGINE_EXECUTION_LIMITS_DEFAULTS} with optional `overrides` (e.g. host `runtime.engineExecutionLimits`).
|
|
9
|
-
*/
|
|
10
7
|
export class EngineExecutionLimitsPolicyFactory {
|
|
11
8
|
create(overrides?: Partial<EngineExecutionLimitsPolicyConfig>): EngineExecutionLimitsPolicy {
|
|
12
9
|
return new EngineExecutionLimitsPolicy({ ...ENGINE_EXECUTION_LIMITS_DEFAULTS, ...overrides });
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { RunFinishedAtFactory } from "../contracts/runFinishedAtFactory";
|
|
2
2
|
import type { PersistedRunState, RunSummary } from "../types";
|
|
3
3
|
|
|
4
|
-
/** Maps persisted run state to API run summaries for listings. */
|
|
5
4
|
export class RunSummaryMapper {
|
|
6
5
|
static fromPersistedState(state: PersistedRunState): RunSummary {
|
|
7
6
|
return {
|
|
@@ -5,6 +5,7 @@ import { PollingTriggerRuntime } from "../triggers/polling/PollingTriggerRuntime
|
|
|
5
5
|
import { NoOpPollingTriggerLogger } from "../triggers/polling/PollingTriggerLogger";
|
|
6
6
|
import { MissingRuntimeFallbacks } from "../workflowSnapshots/MissingRuntimeFallbacksFactory";
|
|
7
7
|
import { MissingRuntimeExecutionMarker } from "../workflowSnapshots/MissingRuntimeExecutionMarker";
|
|
8
|
+
import { MissingRuntimeParityGuard } from "../workflowSnapshots/MissingRuntimeParityGuard";
|
|
8
9
|
import { WorkflowSnapshotCodec } from "../workflowSnapshots/WorkflowSnapshotCodec";
|
|
9
10
|
import { WorkflowSnapshotResolver } from "../workflowSnapshots/WorkflowSnapshotResolver";
|
|
10
11
|
import { ActivationEnqueueService } from "../execution/ActivationEnqueueService";
|
|
@@ -28,22 +29,12 @@ import { Engine } from "../orchestration/Engine";
|
|
|
28
29
|
import { CredentialResolverFactory } from "../execution/CredentialResolverFactory";
|
|
29
30
|
import { NodeRunStateWriterFactory } from "../execution/NodeRunStateWriterFactory";
|
|
30
31
|
|
|
31
|
-
/**
|
|
32
|
-
* {@link EngineDeps} plus optional overrides for workflow-snapshot materialization.
|
|
33
|
-
* Overrides keep default construction in this factory while allowing tests or advanced wiring to inject instances.
|
|
34
|
-
*/
|
|
35
32
|
export type EngineCompositionDeps = EngineDeps & {
|
|
36
33
|
workflowSnapshotCodec?: WorkflowSnapshotCodec;
|
|
37
34
|
missingRuntimeFallbacks?: MissingRuntimeFallbacks;
|
|
38
|
-
/** When set, used for run-start, trigger, and continuation limit defaults. */
|
|
39
35
|
executionLimitsPolicy?: EngineExecutionLimitsPolicy;
|
|
40
36
|
};
|
|
41
37
|
|
|
42
|
-
/**
|
|
43
|
-
* Composes the {@link Engine} graph from {@link EngineCompositionDeps}. Production wiring usually goes through
|
|
44
|
-
* {@link import("../bootstrap/runtime/EngineRuntimeRegistrar").EngineRuntimeRegistrar}; this factory remains for tests and custom composition.
|
|
45
|
-
* Exported from `@codemation/core/bootstrap` (not the main `@codemation/core` barrel).
|
|
46
|
-
*/
|
|
47
38
|
export class EngineFactory {
|
|
48
39
|
create(deps: EngineCompositionDeps): Engine {
|
|
49
40
|
const waiters = new EngineWaiters();
|
|
@@ -65,7 +56,9 @@ export class EngineFactory {
|
|
|
65
56
|
missingRuntimeFallbacks,
|
|
66
57
|
);
|
|
67
58
|
|
|
68
|
-
const
|
|
59
|
+
const missingRuntimeExecutionMarker = new MissingRuntimeExecutionMarker();
|
|
60
|
+
const semantics = new RunStateSemantics(missingRuntimeExecutionMarker);
|
|
61
|
+
const parityGuard = new MissingRuntimeParityGuard(missingRuntimeExecutionMarker);
|
|
69
62
|
const nodeActivationRequestInputPreparer = new NodeActivationRequestInputPreparer(deps.workflowNodeInstanceFactory);
|
|
70
63
|
const activationEnqueueService = new ActivationEnqueueService(
|
|
71
64
|
deps.activationScheduler,
|
|
@@ -124,6 +117,7 @@ export class EngineFactory {
|
|
|
124
117
|
policyErrorServices,
|
|
125
118
|
terminalPersistence,
|
|
126
119
|
executionLimitsPolicy,
|
|
120
|
+
parityGuard,
|
|
127
121
|
);
|
|
128
122
|
const nodeExecutionRequestHandler = new NodeExecutionRequestHandlerService(
|
|
129
123
|
deps.workflowExecutionRepository,
|
|
@@ -135,6 +129,7 @@ export class EngineFactory {
|
|
|
135
129
|
deps.nodeExecutor,
|
|
136
130
|
runContinuationService,
|
|
137
131
|
executionLimitsPolicy,
|
|
132
|
+
parityGuard,
|
|
138
133
|
);
|
|
139
134
|
|
|
140
135
|
const pollingTriggerLogger = deps.pollingTriggerLogger ?? new NoOpPollingTriggerLogger();
|
|
@@ -219,10 +219,6 @@ export class RunIntentService {
|
|
|
219
219
|
]);
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
/**
|
|
223
|
-
* Webhook-triggered runs always force inline execution first.
|
|
224
|
-
* This is the highest-precedence scheduler override: it wins over node hints and container defaults.
|
|
225
|
-
*/
|
|
226
222
|
private createWebhookExecutionOptions(): RunExecutionOptions {
|
|
227
223
|
return {
|
|
228
224
|
localOnly: true,
|
|
@@ -12,10 +12,6 @@ import type {
|
|
|
12
12
|
WorkflowRepository,
|
|
13
13
|
} from "../types";
|
|
14
14
|
|
|
15
|
-
/**
|
|
16
|
-
* Resolves webhook HTTP routes from the live workflow repository (no trigger setup / registration).
|
|
17
|
-
* Maintains an in-memory index keyed by user-defined endpoint path for O(1) lookups after reload.
|
|
18
|
-
*/
|
|
19
15
|
export class WorkflowRepositoryWebhookTriggerMatcher implements WebhookTriggerMatcher {
|
|
20
16
|
private readonly routeByPath = new Map<string, WebhookInvocationMatch>();
|
|
21
17
|
private engineRoutesActive = false;
|
|
@@ -7,10 +7,6 @@ import type {
|
|
|
7
7
|
PersistedRuntimeTypeKind,
|
|
8
8
|
} from "./persistedRuntimeTypeModelRegistry";
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* Applies both tsyringe injectability and persisted runtime metadata in one decorator.
|
|
12
|
-
* This keeps runtime-type decorators thin while still recording enough data for snapshot hydration.
|
|
13
|
-
*/
|
|
14
10
|
export class InjectableRuntimeDecoratorComposer {
|
|
15
11
|
static compose(
|
|
16
12
|
kind: PersistedRuntimeTypeKind,
|
|
@@ -9,10 +9,6 @@ import {
|
|
|
9
9
|
import { PersistedRuntimeTypeNameResolver } from "./PersistedRuntimeTypeNameResolver";
|
|
10
10
|
import { StackTraceCallSitePathResolver } from "./StackTraceCallSitePathResolver";
|
|
11
11
|
|
|
12
|
-
/**
|
|
13
|
-
* Defines and retrieves persisted runtime metadata on decorated classes.
|
|
14
|
-
* The metadata is attached as a non-enumerable property so runtime objects stay serializable.
|
|
15
|
-
*/
|
|
16
12
|
export class PersistedRuntimeTypeMetadataStore {
|
|
17
13
|
static define(
|
|
18
14
|
target: DecoratedRuntimeType,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { DecoratedRuntimeType } from "./persistedRuntimeTypeModelRegistry";
|
|
2
2
|
|
|
3
|
-
/** Resolves the persisted type name from either an explicit override or the class name itself. */
|
|
4
3
|
export class PersistedRuntimeTypeNameResolver {
|
|
5
4
|
static resolve(target: DecoratedRuntimeType, override: string | undefined): string {
|
|
6
5
|
const resolved = override ?? target.name;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
-
/** Shared metadata key used to attach persisted runtime-type information to decorated classes. */
|
|
2
1
|
export const persistedRuntimeTypeMetadataKey = Symbol.for("codemation.core.persistedRuntimeTypeMetadata");
|
|
3
2
|
|
|
4
3
|
export type DecoratedRuntimeType = Readonly<{ name?: string }> & object;
|
|
5
4
|
|
|
6
|
-
/** Categories of runtime classes that can be discovered and rehydrated from persisted snapshots. */
|
|
7
5
|
export type PersistedRuntimeTypeKind = "node" | "tool" | "chatModel";
|
|
8
6
|
|
|
9
7
|
export interface PersistedRuntimeTypeDecoratorOptions {
|
|
@@ -12,7 +10,6 @@ export interface PersistedRuntimeTypeDecoratorOptions {
|
|
|
12
10
|
readonly moduleUrl?: string;
|
|
13
11
|
}
|
|
14
12
|
|
|
15
|
-
/** Serialized metadata attached to a decorated runtime type. */
|
|
16
13
|
export interface PersistedRuntimeTypeMetadata {
|
|
17
14
|
readonly persistedName: string;
|
|
18
15
|
readonly kind: PersistedRuntimeTypeKind;
|
|
@@ -20,7 +17,6 @@ export interface PersistedRuntimeTypeMetadata {
|
|
|
20
17
|
readonly sourceHint?: string;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
|
-
/** Normalizes decorator options so persistence metadata has stable defaults. */
|
|
24
20
|
export class PersistedRuntimeTypeDecoratorDefaults {
|
|
25
21
|
static readonly appPackageName = "app";
|
|
26
22
|
|
|
@@ -6,36 +6,24 @@ import type {
|
|
|
6
6
|
import { InjectableRuntimeDecoratorComposer } from "./InjectableRuntimeDecoratorComposerRegistry";
|
|
7
7
|
import { PersistedRuntimeTypeMetadataStore } from "./PersistedRuntimeTypeMetadataStoreRegistry";
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* Public decorator entry points for runtime-discoverable classes.
|
|
11
|
-
*
|
|
12
|
-
* These exports intentionally stay as plain decorator factory functions because TypeScript's
|
|
13
|
-
* `@decorator()` syntax expects callable values rather than instance methods. The helpers below
|
|
14
|
-
* attach DI metadata and persisted-name metadata in one step so hosts can discover nodes, tools,
|
|
15
|
-
* and chat models without duplicating registration boilerplate.
|
|
16
|
-
*/
|
|
17
9
|
export type {
|
|
18
10
|
PersistedRuntimeTypeDecoratorOptions,
|
|
19
11
|
PersistedRuntimeTypeKind,
|
|
20
12
|
PersistedRuntimeTypeMetadata,
|
|
21
13
|
} from "./persistedRuntimeTypeModelRegistry";
|
|
22
14
|
|
|
23
|
-
/** Reads persisted runtime metadata from a decorated class or object. */
|
|
24
15
|
export function getPersistedRuntimeTypeMetadata(target: unknown): PersistedRuntimeTypeMetadata | undefined {
|
|
25
16
|
return PersistedRuntimeTypeMetadataStore.get(target);
|
|
26
17
|
}
|
|
27
18
|
|
|
28
|
-
/** Marks a class as a persisted node runtime type and an injectable tsyringe service. */
|
|
29
19
|
export function node(options: PersistedRuntimeTypeDecoratorOptions = {}): ClassDecorator {
|
|
30
20
|
return InjectableRuntimeDecoratorComposer.compose("node", options, import.meta.url);
|
|
31
21
|
}
|
|
32
22
|
|
|
33
|
-
/** Marks a class as a persisted tool runtime type and an injectable tsyringe service. */
|
|
34
23
|
export function tool(options: PersistedRuntimeTypeDecoratorOptions = {}): ClassDecorator {
|
|
35
24
|
return InjectableRuntimeDecoratorComposer.compose("tool", options, import.meta.url);
|
|
36
25
|
}
|
|
37
26
|
|
|
38
|
-
/** Marks a class as a persisted chat-model runtime type and an injectable tsyringe service. */
|
|
39
27
|
export function chatModel(options: PersistedRuntimeTypeDecoratorOptions = {}): ClassDecorator {
|
|
40
28
|
return InjectableRuntimeDecoratorComposer.compose("chatModel", options, import.meta.url);
|
|
41
29
|
}
|
|
@@ -20,7 +20,6 @@ export class ConfigDrivenOffloadPolicy implements NodeOffloadPolicy {
|
|
|
20
20
|
if (hint === "local") return { mode: "local" };
|
|
21
21
|
if (hint === "worker") return { mode: "worker", queue };
|
|
22
22
|
|
|
23
|
-
// If a queue is specified, treat it as an implicit worker hint.
|
|
24
23
|
if (queue) return { mode: "worker", queue };
|
|
25
24
|
|
|
26
25
|
return { mode: this.defaultMode };
|
|
@@ -60,12 +60,6 @@ export class DefaultDrivingScheduler implements NodeActivationScheduler {
|
|
|
60
60
|
return await this.prepareInlineDispatch(request);
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
/**
|
|
64
|
-
* Scheduler precedence is explicit:
|
|
65
|
-
* 1. run-intent override (`executionOptions.localOnly`)
|
|
66
|
-
* 2. node-level execution hint / queue policy
|
|
67
|
-
* 3. container-default scheduler policy fallback
|
|
68
|
-
*/
|
|
69
63
|
private async selectScheduler(request: NodeActivationRequest): Promise<SchedulerSelection> {
|
|
70
64
|
if (request.executionOptions?.localOnly) {
|
|
71
65
|
return {
|