@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,81 +1,26 @@
|
|
|
1
1
|
import type { TypeToken } from "../di";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Metadata returned for a workspace file object.
|
|
5
|
-
* Filename and contentType come from the S3 object's custom metadata
|
|
6
|
-
* (stamped by the control plane at upload time — story 03).
|
|
7
|
-
* The local-fs driver reads them from a companion .meta.json sidecar.
|
|
8
|
-
*/
|
|
9
3
|
export interface WorkspaceFileMetadata {
|
|
10
|
-
/** Storage key: `<workspaceId>/files/<fileId>` */
|
|
11
4
|
readonly key: string;
|
|
12
|
-
/** Last path segment of the storage key. */
|
|
13
5
|
readonly fileId: string;
|
|
14
|
-
/** Original filename as stamped by the CP at upload time. Empty string if not yet stamped (pre-story-03). */
|
|
15
6
|
readonly filename: string;
|
|
16
7
|
readonly contentType: string;
|
|
17
8
|
readonly size: number;
|
|
18
9
|
readonly lastModified: Date;
|
|
19
10
|
}
|
|
20
11
|
|
|
21
|
-
/**
|
|
22
|
-
* Workspace-scoped port for accessing the shared workspace file pool.
|
|
23
|
-
* Implemented in `@codemation/host`; nodes reach it via `ctx.resolve(WorkspaceFileStorageToken)`.
|
|
24
|
-
*
|
|
25
|
-
* Key scheme: `<workspaceId>/files/<fileId>` — but nodes never construct raw keys.
|
|
26
|
-
* Use the workspace-level helpers (`listFiles`, `getFileByName`, `getFileById`, `writeFile`) instead.
|
|
27
|
-
*
|
|
28
|
-
* This adapter is SEPARATE from the run-scoped BinaryStorage — do not confuse the two.
|
|
29
|
-
*/
|
|
30
12
|
export interface IWorkspaceFileStorage {
|
|
31
|
-
/**
|
|
32
|
-
* Lists all files in this workspace, sorted newest-first by lastModified.
|
|
33
|
-
* Optional case-insensitive substring filter on filename.
|
|
34
|
-
*/
|
|
35
13
|
listFiles(filenameFilter?: string): Promise<ReadonlyArray<WorkspaceFileMetadata>>;
|
|
36
14
|
|
|
37
|
-
/**
|
|
38
|
-
* Returns metadata for the newest file with the given filename in this workspace.
|
|
39
|
-
* @throws WorkspaceFileNotFoundError when no file with that name exists.
|
|
40
|
-
*/
|
|
41
15
|
getFileByName(filename: string): Promise<WorkspaceFileMetadata>;
|
|
42
16
|
|
|
43
|
-
/**
|
|
44
|
-
* Returns metadata for the file with the given fileId in this workspace.
|
|
45
|
-
* @throws WorkspaceFileNotFoundError when no file with that id exists.
|
|
46
|
-
*/
|
|
47
17
|
getFileById(fileId: string): Promise<WorkspaceFileMetadata>;
|
|
48
18
|
|
|
49
|
-
/**
|
|
50
|
-
* Returns a non-buffered stream of the stored object's bytes.
|
|
51
|
-
* Accepts a full storage key or a fileId (prefixes as needed).
|
|
52
|
-
* @throws WorkspaceFileNotFoundError when the key does not exist.
|
|
53
|
-
*/
|
|
54
19
|
getStream(key: string): Promise<ReadableStream<Uint8Array>>;
|
|
55
20
|
|
|
56
|
-
/**
|
|
57
|
-
* Writes a file into the workspace's shared file pool.
|
|
58
|
-
*
|
|
59
|
-
* Generates a new fileId internally; the caller never constructs a raw key.
|
|
60
|
-
* Stamps the filename into object metadata so read-side adapters can resolve
|
|
61
|
-
* files by name without querying a registry.
|
|
62
|
-
*
|
|
63
|
-
* Returns the stored file's metadata (fileId, key, filename, contentType, size,
|
|
64
|
-
* lastModified). Callers that need concierge visibility must also register a
|
|
65
|
-
* WorkspaceFile row on the CP side via the HMAC-paired
|
|
66
|
-
* `POST /internal/workspace-files/register` endpoint — see the host-side
|
|
67
|
-
* `WorkspaceFileRegistrarClient`.
|
|
68
|
-
*
|
|
69
|
-
* @param filename Original filename; stored in object metadata.
|
|
70
|
-
* @param body Bytes to write (contiguous — required for presigned PUT Content-Length).
|
|
71
|
-
* @param contentType MIME type.
|
|
72
|
-
*/
|
|
73
21
|
writeFile(filename: string, body: Uint8Array, contentType: string): Promise<WorkspaceFileMetadata>;
|
|
74
22
|
}
|
|
75
23
|
|
|
76
|
-
/**
|
|
77
|
-
* Error thrown when a requested workspace file key does not exist.
|
|
78
|
-
*/
|
|
79
24
|
export class WorkspaceFileNotFoundError extends Error {
|
|
80
25
|
constructor(readonly key: string) {
|
|
81
26
|
super(`Workspace file not found: ${key}`);
|
|
@@ -83,31 +28,14 @@ export class WorkspaceFileNotFoundError extends Error {
|
|
|
83
28
|
}
|
|
84
29
|
}
|
|
85
30
|
|
|
86
|
-
/**
|
|
87
|
-
* Port for registering a workflow-written file in the CP's WorkspaceFile table.
|
|
88
|
-
* Optional: only wired when the host is paired with a control plane.
|
|
89
|
-
* Implemented by `WorkspaceFileRegistrarClient` in `@codemation/host`.
|
|
90
|
-
* Nodes call this after `writeFile` so the concierge can see the file via
|
|
91
|
-
* `list_files` / `get_file`.
|
|
92
|
-
*/
|
|
93
31
|
export interface IWorkspaceFileRegistrar {
|
|
94
32
|
register(meta: WorkspaceFileMetadata): Promise<void>;
|
|
95
33
|
}
|
|
96
34
|
|
|
97
|
-
/**
|
|
98
|
-
* DI token for the workspace-scoped file storage adapter.
|
|
99
|
-
* Registered by `@codemation/host`; resolved by workspace-file nodes via `ctx.resolve(...)`.
|
|
100
|
-
*/
|
|
101
35
|
export const WorkspaceFileStorageToken = Symbol.for("codemation.core.WorkspaceFileStorage") as TypeToken<
|
|
102
36
|
IWorkspaceFileStorage | undefined
|
|
103
37
|
>;
|
|
104
38
|
|
|
105
|
-
/**
|
|
106
|
-
* DI token for the optional CP registry hook.
|
|
107
|
-
* Present only when the host is paired (managed mode). Standalone / local-fs
|
|
108
|
-
* deployments leave this undefined — workflow-written files will be in S3/local
|
|
109
|
-
* but will not appear in the concierge's list_files.
|
|
110
|
-
*/
|
|
111
39
|
export const WorkspaceFileRegistrarToken = Symbol.for("codemation.core.WorkspaceFileRegistrar") as TypeToken<
|
|
112
40
|
IWorkspaceFileRegistrar | undefined
|
|
113
41
|
>;
|
package/src/contracts.ts
CHANGED
|
@@ -1,28 +1,23 @@
|
|
|
1
|
-
// Pure-type-only re-exports. Use this for type-only consumers that should not drag in runtime DSL or factory code.
|
|
2
|
-
// This subpath prevents unnecessary compile-graph bloat for packages that only need types like NodeId, Items, etc.
|
|
3
|
-
|
|
4
1
|
export type * from "./contracts/agentMcpTypes";
|
|
2
|
+
export type { WorkspaceId, DispatchItemMeta, WorkflowDispatch } from "./contracts/dispatchTypes";
|
|
3
|
+
export { serializeDispatch, deserializeDispatch } from "./contracts/dispatchTypes";
|
|
5
4
|
export * from "./contracts/AgentBindError";
|
|
6
5
|
export * from "./contracts/NoOpAgentMcpIntegration";
|
|
7
6
|
export type * from "./contracts/baseTypes";
|
|
8
7
|
export type * from "./contracts/assertionTypes";
|
|
9
|
-
// assertionTypes also exports a runtime helper for deriving pass/fail from a score+threshold.
|
|
10
|
-
// We keep the type-only re-export above and surface the helper explicitly here so UI consumers
|
|
11
|
-
// (next-host) don't need to re-implement the comparison.
|
|
12
8
|
export { deriveAssertionPassed, DEFAULT_ASSERTION_PASS_THRESHOLD } from "./contracts/assertionTypes";
|
|
13
9
|
export type * from "./contracts/params";
|
|
14
10
|
export type * from "./contracts/retryPolicySpec.types";
|
|
15
11
|
export type * from "./contracts/CostCatalogContract";
|
|
16
12
|
export type * from "./contracts/executionPersistenceContracts";
|
|
17
13
|
export type * from "./contracts/runtimeTypes";
|
|
14
|
+
export type * from "./contracts/triggerInvokerTypes";
|
|
18
15
|
export type * from "./contracts/telemetryTypes";
|
|
19
16
|
export type * from "./contracts/testTriggerTypes";
|
|
20
17
|
export type * from "./contracts/runTypes";
|
|
21
18
|
export type * from "./contracts/webhookTypes";
|
|
22
19
|
export type * from "./contracts/workflowTypes";
|
|
23
20
|
|
|
24
|
-
// credentialTypes mixes types (Credential* interfaces) with runtime (CredentialUnboundError class).
|
|
25
|
-
// Export type-only subset for pure type consumers.
|
|
26
21
|
export type {
|
|
27
22
|
CredentialTypeId,
|
|
28
23
|
CredentialInstanceId,
|
|
@@ -44,6 +39,8 @@ export type {
|
|
|
44
39
|
CredentialInstanceRecord,
|
|
45
40
|
CredentialSessionFactoryArgs,
|
|
46
41
|
CredentialSessionFactory,
|
|
42
|
+
CredentialAccessTokenSessionArgs,
|
|
43
|
+
CredentialAccessTokenSessionFactory,
|
|
47
44
|
CredentialHealthTester,
|
|
48
45
|
CredentialType,
|
|
49
46
|
AnyCredentialType,
|
|
@@ -51,8 +48,6 @@ export type {
|
|
|
51
48
|
CredentialTypeRegistry,
|
|
52
49
|
} from "./contracts/credentialTypes";
|
|
53
50
|
|
|
54
|
-
// CostTrackingTelemetryContract mixes types with const runtime values (metric/attribute names).
|
|
55
|
-
// Export type-only subset for pure type consumers.
|
|
56
51
|
export type {
|
|
57
52
|
CostTrackingComponent,
|
|
58
53
|
CostTrackingUsageRecord,
|
|
@@ -60,3 +55,16 @@ export type {
|
|
|
60
55
|
CostTrackingTelemetry,
|
|
61
56
|
CostTrackingTelemetryFactory,
|
|
62
57
|
} from "./contracts/CostTrackingTelemetryContract";
|
|
58
|
+
|
|
59
|
+
export type {
|
|
60
|
+
DeploymentManifestSchemaVersion,
|
|
61
|
+
ManifestTriggerConfig,
|
|
62
|
+
ManifestNodeCredentialShape,
|
|
63
|
+
WorkflowDeploymentManifest,
|
|
64
|
+
} from "./contracts/deploymentManifestTypes";
|
|
65
|
+
export {
|
|
66
|
+
DEPLOYMENT_MANIFEST_SCHEMA_VERSION,
|
|
67
|
+
serializeManifest,
|
|
68
|
+
deserializeManifest,
|
|
69
|
+
emitWorkflowManifest,
|
|
70
|
+
} from "./contracts/deploymentManifestTypes";
|
|
@@ -1,35 +1,12 @@
|
|
|
1
1
|
import type { OAuthMaterial } from "./OAuthFlowExecutor.types";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Material provider seam — see `docs/design/credentials-oauth-unification.md`,
|
|
5
|
-
* "Material provider seam" section. Sits beside the workspace's
|
|
6
|
-
* `CredentialStore`; persistence of the row stays at the store, persistence of
|
|
7
|
-
* the bytes goes through this provider so they can live at the control plane
|
|
8
|
-
* in managed mode.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Pointer to material bytes. For local rows `ref` is the workspace instance id
|
|
13
|
-
* and the bytes co-locate with the row (existing `CredentialOAuth2Material` /
|
|
14
|
-
* `CredentialSecretMaterial` tables). For control-plane rows `ref` is the
|
|
15
|
-
* CP-side credential id; the workspace stores only the pointer.
|
|
16
|
-
*/
|
|
17
3
|
export type CredentialMaterialRef = Readonly<{
|
|
18
4
|
source: "local" | "control-plane";
|
|
19
5
|
id: string;
|
|
20
6
|
}>;
|
|
21
7
|
|
|
22
|
-
/**
|
|
23
|
-
* Decrypted material bytes returned by a provider. Shape matches
|
|
24
|
-
* `OAuthMaterial` — every supported credential type today is OAuth-shaped.
|
|
25
|
-
*/
|
|
26
8
|
export type MaterialBundle = OAuthMaterial;
|
|
27
9
|
|
|
28
|
-
/**
|
|
29
|
-
* Caller context recorded by the CP material endpoint per fetch (D5 in the
|
|
30
|
-
* `credentials-vault` sprint README). The local provider accepts but ignores
|
|
31
|
-
* it; standalone mode has no audit log.
|
|
32
|
-
*/
|
|
33
10
|
export type CallerContext = Readonly<{
|
|
34
11
|
workspaceId: string;
|
|
35
12
|
caller:
|
|
@@ -45,11 +22,6 @@ export interface CredentialMaterialProvider {
|
|
|
45
22
|
setMaterial(ref: CredentialMaterialRef, material: MaterialBundle): Promise<void>;
|
|
46
23
|
}
|
|
47
24
|
|
|
48
|
-
/**
|
|
49
|
-
* Thrown by a provider when asked to operate on a `ref.source` it does not
|
|
50
|
-
* handle (e.g. the local provider being asked to read `control-plane` bytes).
|
|
51
|
-
* Exported so `instanceof`-checks work across the workspace boundary.
|
|
52
|
-
*/
|
|
53
25
|
export class IllegalMaterialSourceError extends Error {
|
|
54
26
|
constructor(
|
|
55
27
|
public readonly source: CredentialMaterialRef["source"],
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thrown by managed-mode providers when `setMaterial` is called. Managed
|
|
3
|
-
* credential bytes are owned by the control plane; the workspace must not
|
|
4
|
-
* mutate them. See `docs/design/credentials-oauth-unification.md` and
|
|
5
|
-
* `planning/sprints/credentials-vault/02-controlplane-material-provider.md`.
|
|
6
|
-
*/
|
|
7
1
|
export class ManagedCredentialMaterialWriteError extends Error {
|
|
8
2
|
constructor(
|
|
9
3
|
message: string = "managed credentials are owned by the control plane; use the Connected apps page to create or modify them.",
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Thrown by `ControlPlaneCredentialMaterialProvider` when the control-plane
|
|
3
|
-
* material endpoint returns a non-2xx response or a malformed body. Exposes
|
|
4
|
-
* the HTTP status and the raw error body so call sites can surface actionable
|
|
5
|
-
* detail without parsing strings.
|
|
6
|
-
*/
|
|
7
1
|
export class ManagedMaterialFetchError extends Error {
|
|
8
2
|
constructor(
|
|
9
3
|
public readonly status: number,
|
|
@@ -1,13 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Four-concept model for credentials (see docs/design/credentials-oauth-unification.md):
|
|
3
|
-
* 1. CredentialType — schema for stored material (e.g. "oauth.google.gmail").
|
|
4
|
-
* 2. Credential slot requirement — which types a node or MCP server accepts.
|
|
5
|
-
* 3. CredentialInstance — a stored, usable token row in the host's credential store.
|
|
6
|
-
* 4. OAuthFlowExecutor (this file) — the only concept that differs between deployment
|
|
7
|
-
* modes. DI selects one implementation at boot; the rest of the system programs
|
|
8
|
-
* against this interface alone.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
1
|
export interface OAuthFlowStartArgs {
|
|
12
2
|
readonly typeId: string;
|
|
13
3
|
readonly scopes: ReadonlyArray<string>;
|
|
@@ -34,11 +24,6 @@ export interface OAuthMaterial {
|
|
|
34
24
|
|
|
35
25
|
export interface OAuthFlowExecutor {
|
|
36
26
|
start(args: OAuthFlowStartArgs): Promise<OAuthFlowStartResult>;
|
|
37
|
-
/**
|
|
38
|
-
* Returns the instanceId associated with a pending stateToken without consuming it.
|
|
39
|
-
* Used by callback routes to identify the target instance before calling completeCallback.
|
|
40
|
-
* Returns undefined when the stateToken is unknown or already consumed.
|
|
41
|
-
*/
|
|
42
27
|
lookupInstanceId(stateToken: string): string | undefined;
|
|
43
28
|
completeCallback(args: OAuthFlowCallbackArgs): Promise<OAuthMaterial>;
|
|
44
29
|
refresh(args: { typeId: string; instanceId: string; material: OAuthMaterial }): Promise<OAuthMaterial>;
|
package/src/di/CoreTokens.ts
CHANGED
|
@@ -21,6 +21,7 @@ import type {
|
|
|
21
21
|
WorkflowRepository,
|
|
22
22
|
WorkflowRunnerService,
|
|
23
23
|
} from "../types";
|
|
24
|
+
import type { TriggerInvoker } from "../contracts/triggerInvokerTypes";
|
|
24
25
|
|
|
25
26
|
export const CoreTokens = {
|
|
26
27
|
PersistedWorkflowTokenRegistry: Symbol.for(
|
|
@@ -51,17 +52,12 @@ export const CoreTokens = {
|
|
|
51
52
|
RunEventBus: Symbol.for("codemation.core.RunEventBus") as TypeToken<RunEventBus>,
|
|
52
53
|
BinaryStorage: Symbol.for("codemation.core.BinaryStorage") as TypeToken<BinaryStorage>,
|
|
53
54
|
WebhookBasePath: Symbol.for("codemation.core.WebhookBasePath") as TypeToken<string>,
|
|
54
|
-
/** Engine execution limits (defaults + optional host overrides). Consumers may bind a custom instance to override. */
|
|
55
55
|
EngineExecutionLimitsPolicy: Symbol.for(
|
|
56
56
|
"codemation.core.EngineExecutionLimitsPolicy",
|
|
57
57
|
) as TypeToken<EngineExecutionLimitsPolicy>,
|
|
58
58
|
WorkflowActivationPolicy: Symbol.for(
|
|
59
59
|
"codemation.core.WorkflowActivationPolicy",
|
|
60
60
|
) as TypeToken<WorkflowActivationPolicy>,
|
|
61
|
-
/**
|
|
62
|
-
* Optional. When registered, AIAgentNode uses it to resolve mcpServers bindings,
|
|
63
|
-
* validate scopes, open pool connections, and prepare the MCP ToolSet map.
|
|
64
|
-
* Not registered in the default core bootstrap — the host provides the implementation.
|
|
65
|
-
*/
|
|
66
61
|
AgentMcpIntegration: Symbol.for("codemation.core.AgentMcpIntegration") as TypeToken<AgentMcpIntegration>,
|
|
62
|
+
TriggerInvoker: Symbol.for("codemation.core.TriggerInvoker") as TypeToken<TriggerInvoker>,
|
|
67
63
|
} as const;
|
|
@@ -2,13 +2,6 @@ import type { ConnectionInvocationRecord } from "../contracts/runTypes";
|
|
|
2
2
|
import type { ParentExecutionRef } from "../types";
|
|
3
3
|
import type { RunEventBus } from "./runEvents";
|
|
4
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
5
|
export class ConnectionInvocationEventPublisher {
|
|
13
6
|
constructor(
|
|
14
7
|
private readonly eventBus: RunEventBus | undefined,
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { RunEventBus } from "./runEvents";
|
|
2
2
|
import type { NodeExecutionSnapshot } from "../types";
|
|
3
3
|
|
|
4
|
-
/** Publishes node lifecycle snapshots onto the run {@link RunEventBus}. */
|
|
5
4
|
export class NodeEventPublisher {
|
|
6
5
|
constructor(private readonly eventBus: RunEventBus | undefined) {}
|
|
7
6
|
|
package/src/events/runEvents.ts
CHANGED
|
@@ -2,15 +2,7 @@ import type { TestSuiteRunId } from "../contracts/testTriggerTypes";
|
|
|
2
2
|
import type { ConnectionInvocationRecord } from "../contracts/runTypes";
|
|
3
3
|
import type { NodeExecutionSnapshot, ParentExecutionRef, PersistedRunState, RunId, WorkflowId } from "../types";
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Outcome of a single test case (one workflow run dispatched by the test-suite orchestrator).
|
|
7
|
-
* - `running`: workflow still in flight
|
|
8
|
-
* - `succeeded`: workflow completed AND all assertions passed (or no assertions)
|
|
9
|
-
* - `failed`: workflow failed OR (workflow completed but ≥1 assertion failed)
|
|
10
|
-
* - `errored` / `cancelled`: workflow itself errored or was cancelled
|
|
11
|
-
*/
|
|
12
5
|
export type TestCaseRunStatus = "running" | "succeeded" | "failed" | "errored" | "cancelled";
|
|
13
|
-
/** Aggregate outcome of a TestSuiteRun. */
|
|
14
6
|
export type TestSuiteRunStatus = "succeeded" | "failed" | "partial" | "errored" | "cancelled";
|
|
15
7
|
|
|
16
8
|
export type RunEvent =
|
|
@@ -47,15 +47,7 @@ export type ActivationEnqueueRequest = {
|
|
|
47
47
|
planner: RunQueuePlanner;
|
|
48
48
|
engineCounters?: EngineRunCounters;
|
|
49
49
|
connectionInvocations?: ReadonlyArray<ConnectionInvocationRecord>;
|
|
50
|
-
/**
|
|
51
|
-
* Remaining suspension entries after consuming one for a HITL resume.
|
|
52
|
-
* When provided, saved alongside the new pending state so they survive the enqueue.
|
|
53
|
-
*/
|
|
54
50
|
suspension?: ReadonlyArray<PersistedSuspensionEntry>;
|
|
55
|
-
/**
|
|
56
|
-
* Resume context to attach to the re-activated node's execution context.
|
|
57
|
-
* Written here and consumed by `NodeExecutionRequestHandlerService` when building ctx.
|
|
58
|
-
*/
|
|
59
51
|
pendingResume?: PendingResumeEntry;
|
|
60
52
|
};
|
|
61
53
|
|
|
@@ -126,8 +118,6 @@ export class ActivationEnqueueService {
|
|
|
126
118
|
...args.previousNodeSnapshotsByNodeId,
|
|
127
119
|
[args.request.nodeId]: queuedSnapshot,
|
|
128
120
|
},
|
|
129
|
-
// HITL: preserve suspension entries and resume context when re-activating a
|
|
130
|
-
// suspended node. Omit fields when not provided (avoids polluting normal enqueue).
|
|
131
121
|
...(args.suspension !== undefined ? { suspension: args.suspension } : {}),
|
|
132
122
|
...(args.pendingResume !== undefined ? { pendingResume: args.pendingResume } : {}),
|
|
133
123
|
});
|
|
@@ -7,19 +7,6 @@ import type {
|
|
|
7
7
|
TelemetrySpanScope,
|
|
8
8
|
} from "../types";
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
* Builds a re-rooted child execution context for sub-agent (and other deeply-nested) invocations.
|
|
12
|
-
*
|
|
13
|
-
* At the orchestrator's `agent.tool.call` boundary the inner runtime needs a ctx whose:
|
|
14
|
-
* - `nodeId` is the tool's connection node id (so inner LLM/tool connection ids derive correctly),
|
|
15
|
-
* - `activationId` is fresh (so its connection-invocation rows are uniquely identifiable),
|
|
16
|
-
* - `telemetry` parents children under the tool-call span (not the orchestrator's node span),
|
|
17
|
-
* - `binary` is scoped to the new (nodeId, activationId),
|
|
18
|
-
* - `parentInvocationId` points back to the tool-call invocation for downstream lineage.
|
|
19
|
-
*
|
|
20
|
-
* Registered via factory in {@link EngineRuntimeRegistrar} so constructors stay free of parameter
|
|
21
|
-
* decorators (Next/SWC and coverage tooling cannot parse them on in-repo sources).
|
|
22
|
-
*/
|
|
23
10
|
export class ChildExecutionScopeFactory {
|
|
24
11
|
constructor(private readonly activationIdFactory: ActivationIdFactory) {}
|
|
25
12
|
|
|
@@ -2,17 +2,6 @@ import type { InputPortKey, Item, Items, NodeInputsByPort } from "../types";
|
|
|
2
2
|
|
|
3
3
|
import { getOriginIndexFromItem } from "../contracts/itemMeta";
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* Default fan-in: combine multi-port {@link NodeInputsByPort} into one {@link Items} batch for per-item nodes.
|
|
7
|
-
*
|
|
8
|
-
* This is used when a single-input per-item node has multiple inbound edges (for example, branch reconverge
|
|
9
|
-
* after an `If` / `Switch`). The default behavior is **append / union** (preserving item payloads) with a
|
|
10
|
-
* deterministic order:
|
|
11
|
-
*
|
|
12
|
-
* - When router origin metadata exists (`meta._cm.originIndex`), items are sorted by origin index so the
|
|
13
|
-
* downstream batch preserves original ordering across branches.
|
|
14
|
-
* - Otherwise, items are appended by port-key order, preserving each port's local order.
|
|
15
|
-
*/
|
|
16
5
|
export class FanInMergeByOriginMerger {
|
|
17
6
|
merge(inputsByPort: NodeInputsByPort): Items {
|
|
18
7
|
const portKeys = Object.keys(inputsByPort).sort();
|
|
@@ -7,7 +7,6 @@ import type { AsyncSleeper } from "./asyncSleeper.types";
|
|
|
7
7
|
|
|
8
8
|
export type { AsyncSleeper } from "./asyncSleeper.types";
|
|
9
9
|
|
|
10
|
-
/** Maximum permitted retry attempts — workflow-declared values above this are clamped. */
|
|
11
10
|
const HARD_MAX_RETRY_ATTEMPTS = 10;
|
|
12
11
|
|
|
13
12
|
type NormalizedPolicy =
|
|
@@ -1,9 +1,6 @@
|
|
|
1
1
|
import { resolveItemExprsForExecution } from "../contracts/itemExpr";
|
|
2
2
|
import type { Item, NodeExecutionContext, RunnableNodeConfig } from "../types";
|
|
3
3
|
|
|
4
|
-
/**
|
|
5
|
-
* Resolves {@link import("../contracts/itemExpr").ItemExpr} leaves on runnable config before {@link RunnableNode.execute}.
|
|
6
|
-
*/
|
|
7
4
|
export class ItemExprResolver {
|
|
8
5
|
async resolveConfigForItem<TConfig extends RunnableNodeConfig<any, any>>(
|
|
9
6
|
ctx: NodeExecutionContext<TConfig>,
|
|
@@ -46,9 +46,6 @@ export type PlannedNodeActivationRequest = NodeActivationContextArgs & {
|
|
|
46
46
|
nodeDefinition: NodeExecutionDefinition;
|
|
47
47
|
};
|
|
48
48
|
|
|
49
|
-
/**
|
|
50
|
-
* Builds {@link NodeActivationRequest} values shared by workflow starters and continuation.
|
|
51
|
-
*/
|
|
52
49
|
export class NodeActivationRequestComposer {
|
|
53
50
|
constructor(
|
|
54
51
|
private readonly activationIdFactory: ActivationIdFactory,
|
|
@@ -5,11 +5,6 @@ import type { Item, NodeActivationRequest, RunnableNodeConfig, WorkflowNodeInsta
|
|
|
5
5
|
import { FanInMergeByOriginMerger } from "./FanInMergeByOriginMerger";
|
|
6
6
|
import { NodeInputContractError } from "./NodeInputContractError";
|
|
7
7
|
|
|
8
|
-
/**
|
|
9
|
-
* Validates per-item inputs for {@link RunnableNode} before enqueue persistence (Zod on `item.json`).
|
|
10
|
-
* Does not rewrite `item.json` (wire stays as emitted upstream; engine passes parsed input via `execute` args).
|
|
11
|
-
* Converts multi-input activations into a single-input batch when the node is per-item only (engine fan-in).
|
|
12
|
-
*/
|
|
13
8
|
export class NodeActivationRequestInputPreparer {
|
|
14
9
|
private readonly fanInMerger = new FanInMergeByOriginMerger();
|
|
15
10
|
|
|
@@ -71,7 +71,6 @@ export class NodeExecutionSnapshotFactory {
|
|
|
71
71
|
inputsByPort: NodeInputsByPort;
|
|
72
72
|
outputs: NodeOutputs;
|
|
73
73
|
fromPinnedOutput?: boolean;
|
|
74
|
-
/** Override the terminal status for HITL outcomes (defaults to `"completed"`). */
|
|
75
74
|
hitlStatus?: Extract<
|
|
76
75
|
NodeExecutionStatus,
|
|
77
76
|
"hitl-approved" | "hitl-rejected" | "hitl-timeout" | "hitl-auto-accepted" | "hitl-cancelled"
|
|
@@ -38,9 +38,7 @@ export class NodeExecutor {
|
|
|
38
38
|
private readonly retryRunner: InProcessRetryRunner,
|
|
39
39
|
itemExprResolver?: ItemExprResolver,
|
|
40
40
|
outputBehaviorResolver?: RunnableOutputBehaviorResolver,
|
|
41
|
-
/** Required for HITL suspension support. When omitted, `SuspensionRequest` throws upward. */
|
|
42
41
|
private readonly suspensionHandler?: NodeSuspensionHandler,
|
|
43
|
-
/** Required alongside `suspensionHandler`. */
|
|
44
42
|
private readonly loadRunState?: (runId: RunId) => Promise<PersistedRunState | undefined>,
|
|
45
43
|
) {
|
|
46
44
|
this.itemExprResolver = itemExprResolver ?? new ItemExprResolver();
|
|
@@ -190,8 +188,6 @@ export class NodeExecutor {
|
|
|
190
188
|
const runnableCtx = request.ctx as NodeExecutionContext<RunnableNodeConfig>;
|
|
191
189
|
const resolvedCtx = await this.itemExprResolver.resolveConfigForItem(runnableCtx, item, i, inputBatch);
|
|
192
190
|
const baseCtx = this.pickExecutionContext(runnableCtx, resolvedCtx);
|
|
193
|
-
// Mint a per-item iteration id and stamp it (with the item index) onto the ctx so connection
|
|
194
|
-
// invocations and telemetry written from inside `node.execute` carry the per-item identity.
|
|
195
191
|
const iterationCtx = {
|
|
196
192
|
...baseCtx,
|
|
197
193
|
iterationId: NodeIterationIdFactory.create(),
|
|
@@ -208,9 +204,6 @@ export class NodeExecutor {
|
|
|
208
204
|
try {
|
|
209
205
|
raw = await Promise.resolve(node.execute(args));
|
|
210
206
|
} catch (e) {
|
|
211
|
-
// Use both instanceof AND name check: under tsx/dev with mixed source/dist resolution,
|
|
212
|
-
// SuspensionRequest may load as two distinct class objects and instanceof fails. The
|
|
213
|
-
// name brand survives the duality because both copies set name="SuspensionRequest".
|
|
214
207
|
const isSuspension =
|
|
215
208
|
e instanceof SuspensionRequest ||
|
|
216
209
|
(e instanceof Error &&
|
|
@@ -218,23 +211,17 @@ export class NodeExecutor {
|
|
|
218
211
|
typeof (e as { request?: unknown }).request === "object");
|
|
219
212
|
if (isSuspension) {
|
|
220
213
|
if (!this.suspensionHandler || !this.loadRunState) {
|
|
221
|
-
// Suspension not supported in this executor configuration — propagate as a regular error.
|
|
222
214
|
throw new Error(
|
|
223
215
|
`Node ${request.nodeId} threw SuspensionRequest but this NodeExecutor has no suspensionHandler configured.`,
|
|
224
216
|
{ cause: e },
|
|
225
217
|
);
|
|
226
218
|
}
|
|
227
|
-
// Per-item suspension: load current state, persist the suspension entry, and
|
|
228
|
-
// continue processing remaining items. If deliver throws it propagates upward.
|
|
229
219
|
const state = await this.loadRunState(request.runId);
|
|
230
220
|
if (!state) {
|
|
231
221
|
throw new Error(`NodeExecutor: run state not found for runId ${request.runId} during suspension`, {
|
|
232
222
|
cause: e,
|
|
233
223
|
});
|
|
234
224
|
}
|
|
235
|
-
// handleSuspension throws RunSuspendedError after persisting — we re-throw it
|
|
236
|
-
// to exit the loop immediately. Partial byPort outputs are intentionally dropped
|
|
237
|
-
// (TODO: consider stashing outputs of non-suspended items alongside the suspension).
|
|
238
225
|
await this.suspensionHandler.handle({
|
|
239
226
|
runId: request.runId,
|
|
240
227
|
nodeId: request.nodeId,
|
|
@@ -244,7 +231,7 @@ export class NodeExecutor {
|
|
|
244
231
|
state,
|
|
245
232
|
telemetry: iterationCtx.telemetry,
|
|
246
233
|
});
|
|
247
|
-
hasSuspension = true;
|
|
234
|
+
hasSuspension = true;
|
|
248
235
|
continue;
|
|
249
236
|
}
|
|
250
237
|
throw e;
|
|
@@ -264,14 +251,11 @@ export class NodeExecutor {
|
|
|
264
251
|
}
|
|
265
252
|
}
|
|
266
253
|
if (hasSuspension) {
|
|
267
|
-
// Unreachable in practice (suspensionHandler always throws RunSuspendedError) but
|
|
268
|
-
// guards against future refactors that might change handler behaviour.
|
|
269
254
|
throw new RunSuspendedError(request.runId, "unknown");
|
|
270
255
|
}
|
|
271
256
|
return byPort as NodeOutputs;
|
|
272
257
|
}
|
|
273
258
|
|
|
274
|
-
/** Use resolver ctx only when {@link NodeExecutionContext.config} is non-nullish. */
|
|
275
259
|
private pickExecutionContext<TConfig extends RunnableNodeConfig<any, any>>(
|
|
276
260
|
runnableCtx: NodeExecutionContext<TConfig>,
|
|
277
261
|
resolvedCtx: NodeExecutionContext<TConfig> | null | undefined,
|
|
@@ -19,33 +19,12 @@ import { CodemationTelemetryAttributeNames } from "../contracts/CodemationTeleme
|
|
|
19
19
|
import { RunSuspendedError } from "./RunSuspendedError";
|
|
20
20
|
export { RunSuspendedError };
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
* Handles per-item `SuspensionRequest` catches in the engine's item execution loop.
|
|
24
|
-
*
|
|
25
|
-
* Responsibilities:
|
|
26
|
-
* 1. Generate a `taskId` (UUID v4).
|
|
27
|
-
* 2. Persist a `HumanTask` row via `HumanTaskStore.create`.
|
|
28
|
-
* 3. Sign a resume URL via `HitlResumeTokenSigner.sign`.
|
|
29
|
-
* 4. Enqueue a delayed BullMQ timeout job via `HitlTimeoutJobScheduler.enqueue`.
|
|
30
|
-
* 5. Build a `HumanTaskHandle` and call `deliver`.
|
|
31
|
-
* 6. Append a `PersistedSuspensionEntry` to the run state and flip status to `"suspended"`.
|
|
32
|
-
* 7. Persist via `WorkflowExecutionRepository.save`.
|
|
33
|
-
* 8. Throw `RunSuspendedError` so the caller can exit cleanly.
|
|
34
|
-
*
|
|
35
|
-
* If `deliver` throws, the error propagates up to `NodeExecutionRequestHandlerService`
|
|
36
|
-
* which routes it through `resumeFromNodeError` → run status becomes `"failed"`.
|
|
37
|
-
*
|
|
38
|
-
* `humanTaskStore`, `tokenSigner`, and `timeoutScheduler` are optional —
|
|
39
|
-
* when not registered (e.g. in unit tests), the handler still suspends the run but
|
|
40
|
-
* skips persistence, token signing, and job scheduling.
|
|
41
|
-
*/
|
|
42
22
|
export class NodeSuspensionHandler {
|
|
43
23
|
constructor(
|
|
44
24
|
private readonly workflowExecutionRepository: WorkflowExecutionRepository,
|
|
45
25
|
private readonly humanTaskStore?: HumanTaskStore,
|
|
46
26
|
private readonly tokenSigner?: HitlResumeTokenSignerSeam,
|
|
47
27
|
private readonly timeoutScheduler?: HitlTimeoutJobSchedulerSeam,
|
|
48
|
-
/** Workspace ID to stamp on HumanTaskRecord in managed mode (T7 security fix). Null in non-managed mode. */
|
|
49
28
|
private readonly workspaceId?: string,
|
|
50
29
|
) {}
|
|
51
30
|
|
|
@@ -56,7 +35,6 @@ export class NodeSuspensionHandler {
|
|
|
56
35
|
itemIndex: number;
|
|
57
36
|
suspensionRequest: SuspensionRequest;
|
|
58
37
|
state: PersistedRunState;
|
|
59
|
-
/** Telemetry scope of the node's per-item span. Used to emit `hitl.task.*` span events. */
|
|
60
38
|
telemetry?: TelemetryScope;
|
|
61
39
|
}): Promise<never> {
|
|
62
40
|
const taskId = `htask_${globalThis.crypto.randomUUID()}`;
|
|
@@ -68,12 +46,11 @@ export class NodeSuspensionHandler {
|
|
|
68
46
|
const decisionSchemaHash = this.hashSchema(decisionSchema);
|
|
69
47
|
const decisionSchemaJson = this.schemaToJson(decisionSchema);
|
|
70
48
|
|
|
71
|
-
// Build resume token (when signer is available)
|
|
72
49
|
let resumeUrl = "";
|
|
73
50
|
let resumeTokenHash = "";
|
|
74
51
|
if (this.tokenSigner) {
|
|
75
52
|
const token = this.tokenSigner.sign({ taskId, expiresAt, schemaHash: decisionSchemaHash });
|
|
76
|
-
resumeUrl = token;
|
|
53
|
+
resumeUrl = token;
|
|
77
54
|
resumeTokenHash = this.tokenSigner.hashToken(token);
|
|
78
55
|
}
|
|
79
56
|
|
|
@@ -86,7 +63,6 @@ export class NodeSuspensionHandler {
|
|
|
86
63
|
...(metadata !== undefined ? { metadata } : {}),
|
|
87
64
|
};
|
|
88
65
|
|
|
89
|
-
// Emit hitl.task.created before calling deliver.
|
|
90
66
|
const channel = (metadata as Record<string, unknown> | undefined)?.["channel"];
|
|
91
67
|
await args.telemetry?.addSpanEvent?.({
|
|
92
68
|
name: "hitl.task.created",
|
|
@@ -99,8 +75,6 @@ export class NodeSuspensionHandler {
|
|
|
99
75
|
},
|
|
100
76
|
});
|
|
101
77
|
|
|
102
|
-
// D5: deliver throws → emit hitl.task.delivery_failed, then propagate upward;
|
|
103
|
-
// caller routes to resumeFromNodeError → "failed"
|
|
104
78
|
let deliveryRef: Awaited<ReturnType<typeof deliver>>;
|
|
105
79
|
try {
|
|
106
80
|
deliveryRef = await deliver(handle);
|
|
@@ -116,15 +90,11 @@ export class NodeSuspensionHandler {
|
|
|
116
90
|
throw deliverError;
|
|
117
91
|
}
|
|
118
92
|
|
|
119
|
-
// Persist HumanTask row
|
|
120
93
|
if (this.humanTaskStore) {
|
|
121
94
|
const record: HumanTaskRecord = {
|
|
122
95
|
id: taskId,
|
|
123
96
|
runId: args.runId,
|
|
124
97
|
workflowId: args.state.workflowId,
|
|
125
|
-
// T7: stamp workspaceId in managed mode so HitlCallbackHandler can assert workspace identity.
|
|
126
|
-
// Non-managed mode leaves this undefined (null in DB) — the check in HitlCallbackHandler
|
|
127
|
-
// is guarded by `task.workspaceId !== undefined` and is a no-op when null.
|
|
128
98
|
workspaceId: this.workspaceId ?? undefined,
|
|
129
99
|
nodeId: args.nodeId,
|
|
130
100
|
activationId: args.activationId,
|
|
@@ -144,7 +114,6 @@ export class NodeSuspensionHandler {
|
|
|
144
114
|
await this.humanTaskStore.create(record);
|
|
145
115
|
}
|
|
146
116
|
|
|
147
|
-
// Enqueue timeout job
|
|
148
117
|
if (this.timeoutScheduler) {
|
|
149
118
|
await this.timeoutScheduler.enqueueTimeoutJob({ taskId, expiresAt });
|
|
150
119
|
}
|
|
@@ -172,13 +141,7 @@ export class NodeSuspensionHandler {
|
|
|
172
141
|
throw new RunSuspendedError(args.runId, taskId);
|
|
173
142
|
}
|
|
174
143
|
|
|
175
|
-
/**
|
|
176
|
-
* Parse a duration string into milliseconds.
|
|
177
|
-
* Accepts ISO 8601 durations ("PT24H", "PT30M") and shorthand ("24h", "30m", "1d").
|
|
178
|
-
* Throws for unrecognised formats.
|
|
179
|
-
*/
|
|
180
144
|
private parseDurationMs(duration: string): number {
|
|
181
|
-
// Shorthand: "24h", "30m", "7d", "3600s"
|
|
182
145
|
const shorthand = /^(\d+(?:\.\d+)?)(s|m|h|d)$/i.exec(duration);
|
|
183
146
|
if (shorthand) {
|
|
184
147
|
const value = parseFloat(shorthand[1]!);
|
|
@@ -191,7 +154,6 @@ export class NodeSuspensionHandler {
|
|
|
191
154
|
};
|
|
192
155
|
return value * multipliers[unit]!;
|
|
193
156
|
}
|
|
194
|
-
// ISO 8601 duration subset: PTnHnMnS (days handled via P1D)
|
|
195
157
|
const iso = /^P(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/.exec(duration);
|
|
196
158
|
if (iso) {
|
|
197
159
|
const days = parseFloat(iso[1] ?? "0");
|