@exaudeus/workrail 1.5.0 → 1.5.2
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/dist/application/services/workflow-compiler.js +14 -2
- package/dist/infrastructure/session/HttpServer.js +7 -2
- package/dist/infrastructure/session/SessionManager.d.ts +12 -4
- package/dist/infrastructure/session/SessionManager.js +30 -15
- package/dist/manifest.json +417 -217
- package/dist/mcp/error-mapper.d.ts +1 -1
- package/dist/mcp/error-mapper.js +12 -8
- package/dist/mcp/handler-factory.js +8 -1
- package/dist/mcp/handlers/session.js +36 -58
- package/dist/mcp/handlers/v2-advance-core/event-builders.d.ts +37 -0
- package/dist/mcp/handlers/v2-advance-core/event-builders.js +114 -0
- package/dist/mcp/handlers/v2-advance-core/index.d.ts +67 -0
- package/dist/mcp/handlers/v2-advance-core/index.js +119 -0
- package/dist/mcp/handlers/v2-advance-core/input-validation.d.ts +44 -0
- package/dist/mcp/handlers/v2-advance-core/input-validation.js +58 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-blocked.d.ts +16 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-blocked.js +64 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-success.d.ts +15 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-success.js +136 -0
- package/dist/mcp/handlers/v2-advance-core.d.ts +3 -45
- package/dist/mcp/handlers/v2-advance-core.js +3 -431
- package/dist/mcp/handlers/v2-advance-events.d.ts +61 -0
- package/dist/mcp/handlers/v2-advance-events.js +126 -0
- package/dist/mcp/handlers/v2-checkpoint.js +11 -14
- package/dist/mcp/handlers/v2-context-budget.js +2 -2
- package/dist/mcp/handlers/v2-error-mapping.d.ts +3 -3
- package/dist/mcp/handlers/v2-error-mapping.js +31 -27
- package/dist/mcp/handlers/v2-execution/advance.d.ts +32 -0
- package/dist/mcp/handlers/v2-execution/advance.js +50 -0
- package/dist/mcp/handlers/v2-execution/continue-advance.d.ts +29 -0
- package/dist/mcp/handlers/v2-execution/continue-advance.js +167 -0
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +22 -0
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +145 -0
- package/dist/mcp/handlers/v2-execution/index.d.ts +31 -0
- package/dist/mcp/handlers/v2-execution/index.js +102 -0
- package/dist/mcp/handlers/v2-execution/replay.d.ts +55 -0
- package/dist/mcp/handlers/v2-execution/replay.js +225 -0
- package/dist/mcp/handlers/v2-execution/start.d.ts +52 -0
- package/dist/mcp/handlers/v2-execution/start.js +331 -0
- package/dist/mcp/handlers/v2-execution-helpers.d.ts +26 -2
- package/dist/mcp/handlers/v2-execution-helpers.js +76 -60
- package/dist/mcp/handlers/v2-execution.d.ts +1 -23
- package/dist/mcp/handlers/v2-execution.js +5 -898
- package/dist/mcp/handlers/v2-state-conversion.d.ts +0 -5
- package/dist/mcp/handlers/v2-state-conversion.js +2 -21
- package/dist/mcp/handlers/v2-token-ops.d.ts +1 -1
- package/dist/mcp/handlers/v2-workflow.js +85 -78
- package/dist/mcp/output-schemas.d.ts +197 -34
- package/dist/mcp/output-schemas.js +12 -5
- package/dist/mcp/tool-descriptions.js +22 -16
- package/dist/mcp/types.d.ts +10 -0
- package/dist/mcp/types.js +10 -0
- package/dist/mcp/v2/tools.d.ts +45 -7
- package/dist/mcp/v2/tools.js +7 -3
- package/dist/types/workflow-definition.d.ts +3 -2
- package/dist/v2/durable-core/canonical/jcs.js +8 -1
- package/dist/v2/durable-core/constants.d.ts +60 -0
- package/dist/v2/durable-core/constants.js +55 -1
- package/dist/v2/durable-core/domain/ack-advance-append-plan.d.ts +14 -13
- package/dist/v2/durable-core/domain/ack-advance-append-plan.js +143 -116
- package/dist/v2/durable-core/domain/blocked-node-builder.js +9 -3
- package/dist/v2/durable-core/domain/blocking-decision.d.ts +2 -0
- package/dist/v2/durable-core/domain/blocking-decision.js +29 -12
- package/dist/v2/durable-core/domain/bundle-builder.d.ts +1 -0
- package/dist/v2/durable-core/domain/bundle-builder.js +1 -1
- package/dist/v2/durable-core/domain/bundle-validator.js +3 -2
- package/dist/v2/durable-core/domain/decision-trace-builder.js +7 -9
- package/dist/v2/durable-core/domain/function-definition-expander.js +1 -3
- package/dist/v2/durable-core/domain/gap-builder.js +2 -1
- package/dist/v2/durable-core/domain/observation-builder.js +2 -1
- package/dist/v2/durable-core/domain/outputs.d.ts +2 -1
- package/dist/v2/durable-core/domain/outputs.js +3 -2
- package/dist/v2/durable-core/domain/reason-model.d.ts +1 -1
- package/dist/v2/durable-core/domain/reason-model.js +4 -9
- package/dist/v2/durable-core/domain/validation-criteria-validator.js +2 -2
- package/dist/v2/durable-core/domain/validation-event-builder.js +4 -6
- package/dist/v2/durable-core/domain/validation-loader.js +2 -1
- package/dist/v2/durable-core/domain/validation-requirements-extractor.js +12 -18
- package/dist/v2/durable-core/encoding/base32-lower.d.ts +13 -1
- package/dist/v2/durable-core/encoding/base32-lower.js +13 -3
- package/dist/v2/durable-core/encoding/hex-to-bytes.d.ts +6 -0
- package/dist/v2/durable-core/encoding/hex-to-bytes.js +19 -0
- package/dist/v2/durable-core/ids/attempt-id-derivation.d.ts +6 -1
- package/dist/v2/durable-core/ids/attempt-id-derivation.js +9 -19
- package/dist/v2/durable-core/ids/event-ids.d.ts +9 -0
- package/dist/v2/durable-core/ids/event-ids.js +18 -0
- package/dist/v2/durable-core/ids/index.d.ts +13 -33
- package/dist/v2/durable-core/ids/index.js +22 -63
- package/dist/v2/durable-core/ids/session-ids.d.ts +9 -0
- package/dist/v2/durable-core/ids/session-ids.js +18 -0
- package/dist/v2/durable-core/ids/snapshot-ids.d.ts +6 -0
- package/dist/v2/durable-core/ids/snapshot-ids.js +10 -0
- package/dist/v2/durable-core/ids/token-ids.d.ts +3 -0
- package/dist/v2/durable-core/ids/token-ids.js +6 -0
- package/dist/v2/durable-core/ids/workflow-hash-ref.d.ts +3 -0
- package/dist/v2/durable-core/ids/workflow-hash-ref.js +5 -4
- package/dist/v2/durable-core/ids/workflow-ids.d.ts +11 -0
- package/dist/v2/durable-core/ids/workflow-ids.js +21 -0
- package/dist/v2/durable-core/lib/utf8-byte-length.d.ts +1 -0
- package/dist/v2/durable-core/lib/utf8-byte-length.js +6 -0
- package/dist/v2/durable-core/schemas/artifacts/loop-control.d.ts +6 -6
- package/dist/v2/durable-core/schemas/artifacts/loop-control.js +2 -1
- package/dist/v2/durable-core/schemas/execution-snapshot/blocked-snapshot.d.ts +28 -28
- package/dist/v2/durable-core/schemas/execution-snapshot/blocked-snapshot.js +5 -7
- package/dist/v2/durable-core/schemas/execution-snapshot/execution-snapshot.v1.d.ts +296 -296
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +466 -471
- package/dist/v2/durable-core/schemas/export-bundle/index.js +0 -8
- package/dist/v2/durable-core/schemas/lib/dedupe-key.d.ts +9 -1
- package/dist/v2/durable-core/schemas/lib/dedupe-key.js +4 -3
- package/dist/v2/durable-core/schemas/lib/utf8-byte-length.d.ts +1 -0
- package/dist/v2/durable-core/schemas/lib/utf8-byte-length.js +6 -0
- package/dist/v2/durable-core/schemas/session/blockers.d.ts +305 -0
- package/dist/v2/durable-core/schemas/session/blockers.js +80 -0
- package/dist/v2/durable-core/schemas/session/dag-topology.d.ts +77 -0
- package/dist/v2/durable-core/schemas/session/dag-topology.js +45 -0
- package/dist/v2/durable-core/schemas/session/events.d.ts +56 -56
- package/dist/v2/durable-core/schemas/session/events.js +11 -182
- package/dist/v2/durable-core/schemas/session/gaps.d.ts +211 -0
- package/dist/v2/durable-core/schemas/session/gaps.js +37 -0
- package/dist/v2/durable-core/schemas/session/outputs.d.ts +148 -0
- package/dist/v2/durable-core/schemas/session/outputs.js +44 -0
- package/dist/v2/durable-core/schemas/session/validation-event.js +5 -7
- package/dist/v2/durable-core/tokens/token-codec.d.ts +1 -18
- package/dist/v2/durable-core/tokens/token-codec.js +0 -67
- package/dist/v2/durable-core/tokens/token-signer.d.ts +1 -8
- package/dist/v2/durable-core/tokens/token-signer.js +0 -43
- package/dist/v2/infra/local/base32/index.js +1 -23
- package/dist/v2/infra/local/bech32m/index.js +1 -1
- package/dist/v2/infra/local/data-dir/index.d.ts +7 -6
- package/dist/v2/infra/local/data-dir/index.js +3 -3
- package/dist/v2/infra/local/directory-listing/index.d.ts +2 -2
- package/dist/v2/infra/local/session-store/index.js +198 -182
- package/dist/v2/infra/local/session-summary-provider/index.js +5 -2
- package/dist/v2/infra/local/snapshot-store/index.js +2 -2
- package/dist/v2/ports/data-dir.port.d.ts +7 -6
- package/dist/v2/ports/fs.port.d.ts +18 -7
- package/dist/v2/ports/session-event-log-store.port.d.ts +5 -2
- package/dist/v2/projections/advance-outcomes.d.ts +1 -7
- package/dist/v2/projections/advance-outcomes.js +2 -1
- package/dist/v2/projections/artifacts.js +3 -2
- package/dist/v2/projections/capabilities.d.ts +1 -7
- package/dist/v2/projections/capabilities.js +2 -1
- package/dist/v2/projections/gaps.d.ts +1 -7
- package/dist/v2/projections/gaps.js +2 -1
- package/dist/v2/projections/node-outputs.d.ts +1 -7
- package/dist/v2/projections/node-outputs.js +4 -3
- package/dist/v2/projections/preferences.d.ts +1 -7
- package/dist/v2/projections/preferences.js +2 -1
- package/dist/v2/projections/projection-error.d.ts +7 -0
- package/dist/v2/projections/projection-error.js +2 -0
- package/dist/v2/projections/resume-ranking.js +3 -3
- package/dist/v2/projections/run-context.d.ts +1 -7
- package/dist/v2/projections/run-context.js +4 -2
- package/dist/v2/projections/run-dag.d.ts +9 -9
- package/dist/v2/projections/run-dag.js +88 -65
- package/dist/v2/projections/run-status-signals.d.ts +1 -7
- package/dist/v2/projections/run-status-signals.js +3 -2
- package/dist/v2/usecases/execution-session-gate.js +2 -5
- package/dist/v2/usecases/export-session.js +4 -2
- package/dist/v2/usecases/import-session.d.ts +3 -3
- package/package.json +1 -1
- package/workflows/coding-task-workflow-agentic.json +0 -9
- package/workflows/workflow-for-workflows.json +18 -5
|
@@ -8,8 +8,9 @@ const v2_token_ops_js_1 = require("./v2-token-ops.js");
|
|
|
8
8
|
const index_js_1 = require("../../v2/durable-core/ids/index.js");
|
|
9
9
|
const workflow_hash_ref_js_1 = require("../../v2/durable-core/ids/workflow-hash-ref.js");
|
|
10
10
|
const index_js_2 = require("../../v2/durable-core/schemas/session/index.js");
|
|
11
|
+
const constants_js_1 = require("../../v2/durable-core/constants.js");
|
|
11
12
|
function findNodeCreated(events, nodeId) {
|
|
12
|
-
return events.find((e) => e.kind ===
|
|
13
|
+
return events.find((e) => e.kind === constants_js_1.EVENT_KIND.NODE_CREATED && e.scope?.nodeId === String(nodeId));
|
|
13
14
|
}
|
|
14
15
|
function mintStateTokenForNode(originalNode, sessionId, runId, nodeId, tokenCodecPorts) {
|
|
15
16
|
const wfRefRes = (0, workflow_hash_ref_js_1.deriveWorkflowHashRef)(originalNode.data.workflowHash);
|
|
@@ -40,19 +41,13 @@ function isGateError(e) {
|
|
|
40
41
|
return typeof e === 'object' && e !== null && 'code' in e && typeof e.code === 'string' && !('kind' in e);
|
|
41
42
|
}
|
|
42
43
|
async function handleV2CheckpointWorkflow(input, ctx) {
|
|
43
|
-
|
|
44
|
+
const guard = (0, types_js_1.requireV2Context)(ctx);
|
|
45
|
+
if (!guard.ok)
|
|
46
|
+
return guard.error;
|
|
47
|
+
return executeCheckpoint(input, guard.ctx).match((payload) => (0, types_js_1.success)(payload), (e) => mapCheckpointErrorToToolError(e));
|
|
44
48
|
}
|
|
45
49
|
function executeCheckpoint(input, ctx) {
|
|
46
|
-
if (!ctx.v2) {
|
|
47
|
-
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'v2 tools disabled' });
|
|
48
|
-
}
|
|
49
50
|
const { gate, sessionStore, tokenCodecPorts, idFactory } = ctx.v2;
|
|
50
|
-
if (!tokenCodecPorts) {
|
|
51
|
-
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'v2 context missing tokenCodecPorts' });
|
|
52
|
-
}
|
|
53
|
-
if (!idFactory) {
|
|
54
|
-
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'v2 context missing idFactory' });
|
|
55
|
-
}
|
|
56
51
|
const tokenRes = (0, v2_token_ops_js_1.parseCheckpointTokenOrFail)(input.checkpointToken, tokenCodecPorts);
|
|
57
52
|
if (!tokenRes.ok) {
|
|
58
53
|
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: tokenRes.failure });
|
|
@@ -85,7 +80,7 @@ function executeCheckpoint(input, ctx) {
|
|
|
85
80
|
});
|
|
86
81
|
}
|
|
87
82
|
function replayCheckpoint(events, dedupeKey, originalNode, sessionId, runId, nodeId, tokenCodecPorts) {
|
|
88
|
-
const existingCheckpointNode = events.find((e) => e.kind ===
|
|
83
|
+
const existingCheckpointNode = events.find((e) => e.kind === constants_js_1.EVENT_KIND.NODE_CREATED && e.dedupeKey === `checkpoint_node:${dedupeKey}`);
|
|
89
84
|
const checkpointNodeId = existingCheckpointNode
|
|
90
85
|
? String(existingCheckpointNode.scope?.nodeId ?? 'unknown')
|
|
91
86
|
: 'unknown';
|
|
@@ -95,6 +90,7 @@ function replayCheckpoint(events, dedupeKey, originalNode, sessionId, runId, nod
|
|
|
95
90
|
return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2CheckpointWorkflowOutputSchema.parse({
|
|
96
91
|
checkpointNodeId,
|
|
97
92
|
stateToken: tokenResult.value,
|
|
93
|
+
nextCall: { tool: 'continue_workflow', params: { intent: 'rehydrate', stateToken: tokenResult.value } },
|
|
98
94
|
}));
|
|
99
95
|
}
|
|
100
96
|
function writeCheckpoint(truth, dedupeKey, originalNode, sessionId, runId, nodeId, checkpointNodeId, mintEventId, lock, sessionStore, tokenCodecPorts) {
|
|
@@ -106,7 +102,7 @@ function writeCheckpoint(truth, dedupeKey, originalNode, sessionId, runId, nodeI
|
|
|
106
102
|
eventId: nodeCreatedEventId,
|
|
107
103
|
eventIndex: truth.events.length,
|
|
108
104
|
sessionId: String(sessionId),
|
|
109
|
-
kind:
|
|
105
|
+
kind: constants_js_1.EVENT_KIND.NODE_CREATED,
|
|
110
106
|
dedupeKey: `checkpoint_node:${dedupeKey}`,
|
|
111
107
|
scope: { runId: String(runId), nodeId: String(checkpointNodeId) },
|
|
112
108
|
data: {
|
|
@@ -121,7 +117,7 @@ function writeCheckpoint(truth, dedupeKey, originalNode, sessionId, runId, nodeI
|
|
|
121
117
|
eventId: edgeCreatedEventId,
|
|
122
118
|
eventIndex: truth.events.length + 1,
|
|
123
119
|
sessionId: String(sessionId),
|
|
124
|
-
kind:
|
|
120
|
+
kind: constants_js_1.EVENT_KIND.EDGE_CREATED,
|
|
125
121
|
dedupeKey,
|
|
126
122
|
scope: { runId: String(runId) },
|
|
127
123
|
data: {
|
|
@@ -153,6 +149,7 @@ function writeCheckpoint(truth, dedupeKey, originalNode, sessionId, runId, nodeI
|
|
|
153
149
|
return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2CheckpointWorkflowOutputSchema.parse({
|
|
154
150
|
checkpointNodeId: String(checkpointNodeId),
|
|
155
151
|
stateToken: tokenResult.value,
|
|
152
|
+
nextCall: { tool: 'continue_workflow', params: { intent: 'rehydrate', stateToken: tokenResult.value } },
|
|
156
153
|
}));
|
|
157
154
|
});
|
|
158
155
|
}
|
|
@@ -154,9 +154,9 @@ function checkContextBudget(args) {
|
|
|
154
154
|
function collectArtifactsForEvaluation(args) {
|
|
155
155
|
const collected = [];
|
|
156
156
|
for (const e of args.truthEvents) {
|
|
157
|
-
if (e.kind !==
|
|
157
|
+
if (e.kind !== constants_js_1.EVENT_KIND.NODE_OUTPUT_APPENDED)
|
|
158
158
|
continue;
|
|
159
|
-
if (e.data.outputChannel !==
|
|
159
|
+
if (e.data.outputChannel !== constants_js_1.OUTPUT_CHANNEL.ARTIFACT)
|
|
160
160
|
continue;
|
|
161
161
|
if (e.data.payload.payloadKind !== 'artifact_ref')
|
|
162
162
|
continue;
|
|
@@ -2,7 +2,7 @@ import type { SessionEventLogStoreError } from '../../v2/ports/session-event-log
|
|
|
2
2
|
import type { ExecutionSessionGateErrorV2 } from '../../v2/usecases/execution-session-gate.js';
|
|
3
3
|
import type { SnapshotStoreError } from '../../v2/ports/snapshot-store.port.js';
|
|
4
4
|
import type { PinnedWorkflowStoreError } from '../../v2/ports/pinned-workflow-store.port.js';
|
|
5
|
-
import type
|
|
5
|
+
import { type ToolFailure } from './v2-execution-helpers.js';
|
|
6
6
|
export type InternalError = {
|
|
7
7
|
readonly kind: 'invariant_violation';
|
|
8
8
|
readonly message: string;
|
|
@@ -29,6 +29,6 @@ export declare function normalizeTokenErrorMessage(message: string): string;
|
|
|
29
29
|
export declare function internalError(message: string, suggestion?: string): ToolFailure;
|
|
30
30
|
export declare function sessionStoreErrorToToolError(e: SessionEventLogStoreError): ToolFailure;
|
|
31
31
|
export declare function gateErrorToToolError(e: ExecutionSessionGateErrorV2): ToolFailure;
|
|
32
|
-
export declare function snapshotStoreErrorToToolError(
|
|
33
|
-
export declare function pinnedWorkflowStoreErrorToToolError(
|
|
32
|
+
export declare function snapshotStoreErrorToToolError(_e: SnapshotStoreError, _suggestion?: string): ToolFailure;
|
|
33
|
+
export declare function pinnedWorkflowStoreErrorToToolError(_e: PinnedWorkflowStoreError, _suggestion?: string): ToolFailure;
|
|
34
34
|
export declare function mapInternalErrorToToolError(e: InternalError): ToolFailure;
|
|
@@ -42,6 +42,7 @@ exports.snapshotStoreErrorToToolError = snapshotStoreErrorToToolError;
|
|
|
42
42
|
exports.pinnedWorkflowStoreErrorToToolError = pinnedWorkflowStoreErrorToToolError;
|
|
43
43
|
exports.mapInternalErrorToToolError = mapInternalErrorToToolError;
|
|
44
44
|
const types_js_1 = require("../types.js");
|
|
45
|
+
const v2_execution_helpers_js_1 = require("./v2-execution-helpers.js");
|
|
45
46
|
function isInternalError(e) {
|
|
46
47
|
return (typeof e === 'object' &&
|
|
47
48
|
e !== null &&
|
|
@@ -58,68 +59,71 @@ function internalError(message, suggestion) {
|
|
|
58
59
|
function sessionStoreErrorToToolError(e) {
|
|
59
60
|
switch (e.code) {
|
|
60
61
|
case 'SESSION_STORE_LOCK_BUSY':
|
|
61
|
-
return (0, types_js_1.errRetryAfterMs)('INTERNAL_ERROR',
|
|
62
|
-
suggestion: 'Another WorkRail process may be writing to this session; retry.',
|
|
63
|
-
});
|
|
62
|
+
return (0, types_js_1.errRetryAfterMs)('INTERNAL_ERROR', 'The session is temporarily busy (another operation is in progress).', e.retry.afterMs, { suggestion: (0, v2_execution_helpers_js_1.internalSuggestion)('Wait a moment and retry this call.', 'Another WorkRail process may be accessing this session.') });
|
|
64
63
|
case 'SESSION_STORE_CORRUPTION_DETECTED':
|
|
65
|
-
return (0, types_js_1.errNotRetryable)('SESSION_NOT_HEALTHY',
|
|
66
|
-
suggestion: '
|
|
64
|
+
return (0, types_js_1.errNotRetryable)('SESSION_NOT_HEALTHY', 'This session\'s data is corrupted and cannot be used.', {
|
|
65
|
+
suggestion: (0, v2_execution_helpers_js_1.internalSuggestion)('This session cannot be recovered. Call start_workflow to create a new session.', 'The session data was corrupted.'),
|
|
67
66
|
details: (0, types_js_1.detailsSessionHealth)({ kind: e.location === 'head' ? 'corrupt_head' : 'corrupt_tail', reason: e.reason }),
|
|
68
67
|
});
|
|
69
68
|
case 'SESSION_STORE_IO_ERROR':
|
|
70
|
-
return internalError(
|
|
69
|
+
return internalError('WorkRail could not read or write session data to disk.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail cannot access its data files. Check that the ~/.workrail directory exists and is writable.'));
|
|
71
70
|
case 'SESSION_STORE_INVARIANT_VIOLATION':
|
|
72
|
-
return internalError(
|
|
71
|
+
return internalError('WorkRail encountered an unexpected error with session storage. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal storage error.'));
|
|
73
72
|
default:
|
|
74
73
|
const _exhaustive = e;
|
|
75
|
-
return internalError('
|
|
74
|
+
return internalError('WorkRail encountered an unexpected session storage error. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal error.'));
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
77
|
function gateErrorToToolError(e) {
|
|
79
78
|
switch (e.code) {
|
|
80
79
|
case 'SESSION_LOCKED':
|
|
81
|
-
return (0, types_js_1.errRetryAfterMs)('TOKEN_SESSION_LOCKED',
|
|
80
|
+
return (0, types_js_1.errRetryAfterMs)('TOKEN_SESSION_LOCKED', 'This session is currently being modified by another operation.', e.retry.afterMs, { suggestion: (0, v2_execution_helpers_js_1.internalSuggestion)('Wait a moment and retry this call.', 'Another WorkRail process may be accessing this session.') });
|
|
82
81
|
case 'LOCK_RELEASE_FAILED':
|
|
83
|
-
return (0, types_js_1.errRetryAfterMs)('TOKEN_SESSION_LOCKED',
|
|
82
|
+
return (0, types_js_1.errRetryAfterMs)('TOKEN_SESSION_LOCKED', 'A previous operation on this session did not release cleanly.', e.retry.afterMs, { suggestion: 'Wait a moment and retry this call. The lock will auto-expire shortly.' });
|
|
84
83
|
case 'SESSION_NOT_HEALTHY':
|
|
85
|
-
return (0, types_js_1.errNotRetryable)('SESSION_NOT_HEALTHY',
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
suggestion: 'Session is locked by concurrent execution. Retry in 1 second.',
|
|
84
|
+
return (0, types_js_1.errNotRetryable)('SESSION_NOT_HEALTHY', 'This session is in an unhealthy state and cannot accept new operations.', {
|
|
85
|
+
suggestion: (0, v2_execution_helpers_js_1.internalSuggestion)('This session cannot be used. Call start_workflow to create a new session.', 'The session is in an unhealthy state.'),
|
|
86
|
+
details: (0, types_js_1.detailsSessionHealth)(e.health),
|
|
89
87
|
});
|
|
88
|
+
case 'SESSION_LOCK_REENTRANT':
|
|
89
|
+
return (0, types_js_1.errRetryAfterMs)('TOKEN_SESSION_LOCKED', 'This session is already being modified by a concurrent call. Only one operation at a time is allowed per session.', 1000, { suggestion: 'Wait for your other call to complete, then retry this one.' });
|
|
90
90
|
case 'SESSION_LOAD_FAILED':
|
|
91
|
+
return internalError('WorkRail could not load the session data for this operation.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail cannot load session data.'));
|
|
91
92
|
case 'LOCK_ACQUIRE_FAILED':
|
|
93
|
+
return internalError('WorkRail could not acquire a lock on this session.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail is having trouble with session locking — check if another process is running.'));
|
|
92
94
|
case 'GATE_CALLBACK_FAILED':
|
|
93
|
-
return internalError(
|
|
95
|
+
return internalError('WorkRail encountered an error while processing this session operation. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal error.'));
|
|
94
96
|
default:
|
|
95
97
|
const _exhaustive = e;
|
|
96
|
-
return internalError('
|
|
98
|
+
return internalError('WorkRail encountered an unexpected session error. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal error.'));
|
|
97
99
|
}
|
|
98
100
|
}
|
|
99
|
-
function snapshotStoreErrorToToolError(
|
|
100
|
-
return internalError(
|
|
101
|
+
function snapshotStoreErrorToToolError(_e, _suggestion) {
|
|
102
|
+
return internalError('WorkRail could not access its execution state data. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal storage error.'));
|
|
101
103
|
}
|
|
102
|
-
function pinnedWorkflowStoreErrorToToolError(
|
|
103
|
-
return internalError(
|
|
104
|
+
function pinnedWorkflowStoreErrorToToolError(_e, _suggestion) {
|
|
105
|
+
return internalError('WorkRail could not access the stored workflow definition. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal storage error.'));
|
|
104
106
|
}
|
|
105
107
|
function mapInternalErrorToToolError(e) {
|
|
106
108
|
switch (e.kind) {
|
|
107
109
|
case 'missing_node_or_run':
|
|
108
|
-
return (0, types_js_1.errNotRetryable)('PRECONDITION_FAILED', '
|
|
110
|
+
return (0, types_js_1.errNotRetryable)('PRECONDITION_FAILED', 'The stateToken you provided does not match any active workflow session. It may be expired or from a different session.', { suggestion: 'Use the stateToken returned by the most recent start_workflow or continue_workflow call.' });
|
|
109
111
|
case 'workflow_hash_mismatch':
|
|
110
|
-
return (0, types_js_1.errNotRetryable)('TOKEN_WORKFLOW_HASH_MISMATCH', '
|
|
112
|
+
return (0, types_js_1.errNotRetryable)('TOKEN_WORKFLOW_HASH_MISMATCH', 'The stateToken refers to a different version of this workflow than what is currently stored.', { suggestion: 'Call start_workflow to create a new session with the current workflow version.' });
|
|
111
113
|
case 'token_scope_mismatch':
|
|
112
|
-
return (0, types_js_1.errNotRetryable)('TOKEN_SCOPE_MISMATCH',
|
|
114
|
+
return (0, types_js_1.errNotRetryable)('TOKEN_SCOPE_MISMATCH', 'The stateToken and ackToken do not belong to the same session or node. Tokens must come from the same WorkRail response.', { suggestion: 'Use the stateToken and ackToken from the same continue_workflow or start_workflow response. Do not mix tokens from different calls.' });
|
|
113
115
|
case 'missing_snapshot':
|
|
116
|
+
return internalError('WorkRail\'s execution state is incomplete — a required snapshot is missing. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call, or call start_workflow to create a new session.', 'WorkRail has incomplete execution state.'));
|
|
114
117
|
case 'no_pending_step':
|
|
115
|
-
return internalError('
|
|
118
|
+
return internalError('There is no pending step to advance. The workflow may already be complete.', 'Call continue_workflow with only a stateToken (no ackToken) to check the current workflow state.');
|
|
116
119
|
case 'invariant_violation':
|
|
117
|
-
return internalError(
|
|
120
|
+
return internalError('WorkRail encountered an unexpected error during workflow advancement. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal error during workflow advancement.'));
|
|
118
121
|
case 'advance_apply_failed':
|
|
122
|
+
return internalError('WorkRail could not record the workflow advancement. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail could not record the advancement.'));
|
|
119
123
|
case 'advance_next_failed':
|
|
120
|
-
return internalError(
|
|
124
|
+
return internalError('WorkRail could not compute the next workflow step. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail could not compute the next step.'));
|
|
121
125
|
default:
|
|
122
126
|
const _exhaustive = e;
|
|
123
|
-
return internalError('
|
|
127
|
+
return internalError('WorkRail encountered an unexpected error. This is not caused by your input.', (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal error.'));
|
|
124
128
|
}
|
|
125
129
|
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { V2ContinueWorkflowInput } from '../../v2/tools.js';
|
|
2
|
+
import { createWorkflow } from '../../../types/workflow.js';
|
|
3
|
+
import { type AttemptId } from '../../../v2/durable-core/tokens/index.js';
|
|
4
|
+
import { type SessionId, type RunId, type NodeId, type WorkflowHash } from '../../../v2/durable-core/ids/index.js';
|
|
5
|
+
import type { LoadedSessionTruthV2 } from '../../../v2/ports/session-event-log-store.port.js';
|
|
6
|
+
import type { WithHealthySessionLock } from '../../../v2/durable-core/ids/with-healthy-session-lock.js';
|
|
7
|
+
import type { SessionEventLogStoreError } from '../../../v2/ports/session-event-log-store.port.js';
|
|
8
|
+
import type { SnapshotStoreError } from '../../../v2/ports/snapshot-store.port.js';
|
|
9
|
+
import type { Sha256PortV2 } from '../../../v2/ports/sha256.port.js';
|
|
10
|
+
import { ResultAsync as RA } from 'neverthrow';
|
|
11
|
+
import type { JsonValue } from '../../../v2/durable-core/canonical/json-types.js';
|
|
12
|
+
import { type InternalError } from '../v2-error-mapping.js';
|
|
13
|
+
export declare function advanceAndRecord(args: {
|
|
14
|
+
readonly truth: LoadedSessionTruthV2;
|
|
15
|
+
readonly sessionId: SessionId;
|
|
16
|
+
readonly runId: RunId;
|
|
17
|
+
readonly nodeId: NodeId;
|
|
18
|
+
readonly attemptId: AttemptId;
|
|
19
|
+
readonly workflowHash: WorkflowHash;
|
|
20
|
+
readonly dedupeKey: string;
|
|
21
|
+
readonly inputContext: JsonValue | undefined;
|
|
22
|
+
readonly inputOutput: V2ContinueWorkflowInput['output'];
|
|
23
|
+
readonly lock: WithHealthySessionLock;
|
|
24
|
+
readonly pinnedWorkflow: ReturnType<typeof createWorkflow>;
|
|
25
|
+
readonly snapshotStore: import('../../../v2/ports/snapshot-store.port.js').SnapshotStorePortV2;
|
|
26
|
+
readonly sessionStore: import('../../../v2/ports/session-event-log-store.port.js').SessionEventLogAppendStorePortV2 & import('../../../v2/ports/session-event-log-store.port.js').SessionEventLogReadonlyStorePortV2;
|
|
27
|
+
readonly sha256: Sha256PortV2;
|
|
28
|
+
readonly idFactory: {
|
|
29
|
+
readonly mintNodeId: () => NodeId;
|
|
30
|
+
readonly mintEventId: () => string;
|
|
31
|
+
};
|
|
32
|
+
}): RA<void, InternalError | SessionEventLogStoreError | SnapshotStoreError>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.advanceAndRecord = advanceAndRecord;
|
|
4
|
+
const neverthrow_1 = require("neverthrow");
|
|
5
|
+
const v2_advance_core_js_1 = require("../v2-advance-core.js");
|
|
6
|
+
const constants_js_1 = require("../../../v2/durable-core/constants.js");
|
|
7
|
+
function advanceAndRecord(args) {
|
|
8
|
+
const { truth, sessionId, runId, nodeId, attemptId, workflowHash, dedupeKey, inputContext, inputOutput, lock, pinnedWorkflow, snapshotStore, sessionStore, sha256, idFactory } = args;
|
|
9
|
+
const hasRun = truth.events.some((e) => e.kind === constants_js_1.EVENT_KIND.RUN_STARTED && e.scope?.runId === String(runId));
|
|
10
|
+
const hasNode = truth.events.some((e) => e.kind === constants_js_1.EVENT_KIND.NODE_CREATED && e.scope?.runId === String(runId) && e.scope?.nodeId === String(nodeId));
|
|
11
|
+
if (!hasRun || !hasNode) {
|
|
12
|
+
return (0, neverthrow_1.errAsync)({ kind: 'missing_node_or_run' });
|
|
13
|
+
}
|
|
14
|
+
const nodeCreated = truth.events.find((e) => e.kind === constants_js_1.EVENT_KIND.NODE_CREATED && e.scope?.nodeId === String(nodeId));
|
|
15
|
+
if (!nodeCreated) {
|
|
16
|
+
return (0, neverthrow_1.errAsync)({ kind: 'missing_node_or_run' });
|
|
17
|
+
}
|
|
18
|
+
if (String(nodeCreated.data.workflowHash) !== String(workflowHash)) {
|
|
19
|
+
return (0, neverthrow_1.errAsync)({ kind: 'workflow_hash_mismatch' });
|
|
20
|
+
}
|
|
21
|
+
return snapshotStore.getExecutionSnapshotV1(nodeCreated.data.snapshotRef).andThen((snap) => {
|
|
22
|
+
if (!snap)
|
|
23
|
+
return (0, neverthrow_1.errAsync)({ kind: 'missing_snapshot' });
|
|
24
|
+
const engineState = snap.enginePayload.engineState;
|
|
25
|
+
if (nodeCreated.data.nodeKind === 'blocked_attempt') {
|
|
26
|
+
if (engineState.kind !== 'blocked') {
|
|
27
|
+
return (0, neverthrow_1.errAsync)({ kind: 'invariant_violation', message: 'blocked_attempt node requires engineState.kind=blocked' });
|
|
28
|
+
}
|
|
29
|
+
const blocked = engineState.blocked;
|
|
30
|
+
if (blocked.kind !== 'retryable_block') {
|
|
31
|
+
return (0, neverthrow_1.errAsync)({
|
|
32
|
+
kind: 'token_scope_mismatch',
|
|
33
|
+
message: 'Cannot retry a terminal blocked_attempt node (blocked.kind=terminal_block).',
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return (0, v2_advance_core_js_1.executeAdvanceCore)({
|
|
37
|
+
mode: { kind: 'retry', blockedNodeId: nodeId, blockedSnapshot: snap },
|
|
38
|
+
truth, sessionId, runId, attemptId, workflowHash, dedupeKey,
|
|
39
|
+
inputContext, inputOutput, lock, pinnedWorkflow,
|
|
40
|
+
ports: { snapshotStore, sessionStore, sha256, idFactory },
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
return (0, v2_advance_core_js_1.executeAdvanceCore)({
|
|
44
|
+
mode: { kind: 'fresh', sourceNodeId: nodeId, snapshot: snap },
|
|
45
|
+
truth, sessionId, runId, attemptId, workflowHash, dedupeKey,
|
|
46
|
+
inputContext, inputOutput, lock, pinnedWorkflow,
|
|
47
|
+
ports: { snapshotStore, sessionStore, sha256, idFactory },
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { V2ContinueWorkflowInput } from '../../v2/tools.js';
|
|
2
|
+
import { V2ContinueWorkflowOutputSchema } from '../../output-schemas.js';
|
|
3
|
+
import { type AttemptId } from '../../../v2/durable-core/tokens/index.js';
|
|
4
|
+
import { type SessionId, type RunId, type NodeId } from '../../../v2/durable-core/ids/index.js';
|
|
5
|
+
import type { LoadedSessionTruthV2 } from '../../../v2/ports/session-event-log-store.port.js';
|
|
6
|
+
import type { Sha256PortV2 } from '../../../v2/ports/sha256.port.js';
|
|
7
|
+
import type { TokenCodecPorts } from '../../../v2/durable-core/tokens/token-codec-ports.js';
|
|
8
|
+
import { ResultAsync as RA } from 'neverthrow';
|
|
9
|
+
import { type ContinueWorkflowError } from '../v2-execution-helpers.js';
|
|
10
|
+
import * as z from 'zod';
|
|
11
|
+
export declare function handleAdvanceIntent(args: {
|
|
12
|
+
readonly input: V2ContinueWorkflowInput;
|
|
13
|
+
readonly sessionId: SessionId;
|
|
14
|
+
readonly runId: RunId;
|
|
15
|
+
readonly nodeId: NodeId;
|
|
16
|
+
readonly attemptId: AttemptId;
|
|
17
|
+
readonly workflowHashRef: string;
|
|
18
|
+
readonly truth: LoadedSessionTruthV2;
|
|
19
|
+
readonly gate: import('../../../v2/usecases/execution-session-gate.js').ExecutionSessionGateV2;
|
|
20
|
+
readonly sessionStore: import('../../../v2/ports/session-event-log-store.port.js').SessionEventLogAppendStorePortV2 & import('../../../v2/ports/session-event-log-store.port.js').SessionEventLogReadonlyStorePortV2;
|
|
21
|
+
readonly snapshotStore: import('../../../v2/ports/snapshot-store.port.js').SnapshotStorePortV2;
|
|
22
|
+
readonly pinnedStore: import('../../../v2/ports/pinned-workflow-store.port.js').PinnedWorkflowStorePortV2;
|
|
23
|
+
readonly tokenCodecPorts: TokenCodecPorts;
|
|
24
|
+
readonly idFactory: {
|
|
25
|
+
readonly mintNodeId: () => NodeId;
|
|
26
|
+
readonly mintEventId: () => string;
|
|
27
|
+
};
|
|
28
|
+
readonly sha256: Sha256PortV2;
|
|
29
|
+
}): RA<z.infer<typeof V2ContinueWorkflowOutputSchema>, ContinueWorkflowError>;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleAdvanceIntent = handleAdvanceIntent;
|
|
4
|
+
const workflow_js_1 = require("../../../types/workflow.js");
|
|
5
|
+
const workflow_hash_ref_js_1 = require("../../../v2/durable-core/ids/workflow-hash-ref.js");
|
|
6
|
+
const neverthrow_1 = require("neverthrow");
|
|
7
|
+
const workflow_source_js_1 = require("../../../types/workflow-source.js");
|
|
8
|
+
const workflow_definition_js_1 = require("../../../types/workflow-definition.js");
|
|
9
|
+
const v2_error_mapping_js_1 = require("../v2-error-mapping.js");
|
|
10
|
+
const constants_js_1 = require("../../../v2/durable-core/constants.js");
|
|
11
|
+
const replay_js_1 = require("./replay.js");
|
|
12
|
+
const advance_js_1 = require("./advance.js");
|
|
13
|
+
function handleAdvanceIntent(args) {
|
|
14
|
+
const { input, sessionId, runId, nodeId, attemptId, workflowHashRef, truth, gate, sessionStore, snapshotStore, pinnedStore, tokenCodecPorts, idFactory, sha256 } = args;
|
|
15
|
+
const dedupeKey = `advance_recorded:${sessionId}:${nodeId}:${attemptId}`;
|
|
16
|
+
const runStarted = truth.events.find((e) => e.kind === constants_js_1.EVENT_KIND.RUN_STARTED && e.scope.runId === String(runId));
|
|
17
|
+
if (!runStarted) {
|
|
18
|
+
return (0, neverthrow_1.errAsync)({
|
|
19
|
+
kind: 'token_unknown_node',
|
|
20
|
+
message: 'No durable run state was found for this token (missing run_started).',
|
|
21
|
+
suggestion: 'Use start_workflow to mint a new run, or use tokens returned by WorkRail for an existing run.',
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const workflowHash = runStarted.data.workflowHash;
|
|
25
|
+
const refRes = (0, workflow_hash_ref_js_1.deriveWorkflowHashRef)(workflowHash);
|
|
26
|
+
if (refRes.isErr()) {
|
|
27
|
+
return (0, neverthrow_1.errAsync)({
|
|
28
|
+
kind: 'precondition_failed',
|
|
29
|
+
message: refRes.error.message,
|
|
30
|
+
suggestion: 'Re-pin the workflow via start_workflow.',
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (String(refRes.value) !== String(workflowHashRef)) {
|
|
34
|
+
return (0, neverthrow_1.errAsync)({
|
|
35
|
+
kind: 'precondition_failed',
|
|
36
|
+
message: 'workflowHash mismatch for this run.',
|
|
37
|
+
suggestion: 'Use the stateToken returned by WorkRail for this run.',
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const nodeCreated = truth.events.find((e) => e.kind === constants_js_1.EVENT_KIND.NODE_CREATED && e.scope.nodeId === String(nodeId) && e.scope.runId === String(runId));
|
|
41
|
+
if (!nodeCreated) {
|
|
42
|
+
return (0, neverthrow_1.errAsync)({
|
|
43
|
+
kind: 'token_unknown_node',
|
|
44
|
+
message: 'No durable node state was found for this token (missing node_created).',
|
|
45
|
+
suggestion: 'Use tokens returned by WorkRail for an existing node.',
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
const nodeRefRes = (0, workflow_hash_ref_js_1.deriveWorkflowHashRef)(nodeCreated.data.workflowHash);
|
|
49
|
+
if (nodeRefRes.isErr()) {
|
|
50
|
+
return (0, neverthrow_1.errAsync)({
|
|
51
|
+
kind: 'precondition_failed',
|
|
52
|
+
message: nodeRefRes.error.message,
|
|
53
|
+
suggestion: 'Re-pin the workflow via start_workflow.',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
if (String(nodeRefRes.value) !== String(workflowHashRef)) {
|
|
57
|
+
return (0, neverthrow_1.errAsync)({
|
|
58
|
+
kind: 'precondition_failed',
|
|
59
|
+
message: 'workflowHash mismatch for this node.',
|
|
60
|
+
suggestion: 'Use the stateToken returned by WorkRail for this node.',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const existing = truth.events.find((e) => e.kind === constants_js_1.EVENT_KIND.ADVANCE_RECORDED && e.dedupeKey === dedupeKey);
|
|
64
|
+
return pinnedStore.get(workflowHash)
|
|
65
|
+
.mapErr((cause) => ({ kind: 'pinned_workflow_store_failed', cause }))
|
|
66
|
+
.andThen((compiled) => {
|
|
67
|
+
if (!compiled)
|
|
68
|
+
return (0, neverthrow_1.errAsync)({ kind: 'pinned_workflow_missing', workflowHash });
|
|
69
|
+
if (compiled.sourceKind !== 'v1_pinned')
|
|
70
|
+
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'Pinned workflow snapshot is read-only (v1_preview) and cannot be executed.' });
|
|
71
|
+
if (!(0, workflow_definition_js_1.hasWorkflowDefinitionShape)(compiled.definition)) {
|
|
72
|
+
return (0, neverthrow_1.errAsync)({
|
|
73
|
+
kind: 'precondition_failed',
|
|
74
|
+
message: 'Pinned workflow snapshot has an invalid workflow definition shape.',
|
|
75
|
+
suggestion: 'Re-pin the workflow via start_workflow.',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
const pinnedWorkflow = (0, workflow_js_1.createWorkflow)(compiled.definition, (0, workflow_source_js_1.createBundledSource)());
|
|
79
|
+
if (existing) {
|
|
80
|
+
return (0, replay_js_1.replayFromRecordedAdvance)({
|
|
81
|
+
recordedEvent: existing,
|
|
82
|
+
truth,
|
|
83
|
+
sessionId,
|
|
84
|
+
runId,
|
|
85
|
+
nodeId,
|
|
86
|
+
workflowHash,
|
|
87
|
+
attemptId,
|
|
88
|
+
inputStateToken: input.stateToken,
|
|
89
|
+
inputAckToken: input.ackToken,
|
|
90
|
+
pinnedWorkflow,
|
|
91
|
+
snapshotStore,
|
|
92
|
+
sha256,
|
|
93
|
+
tokenCodecPorts,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return gate
|
|
97
|
+
.withHealthySessionLock(sessionId, (lock) => sessionStore.load(sessionId).andThen((truthLocked) => {
|
|
98
|
+
const existingLocked = truthLocked.events.find((e) => e.kind === constants_js_1.EVENT_KIND.ADVANCE_RECORDED && e.dedupeKey === dedupeKey);
|
|
99
|
+
if (existingLocked)
|
|
100
|
+
return (0, neverthrow_1.okAsync)({ kind: 'replay', truth: truthLocked, recordedEvent: existingLocked });
|
|
101
|
+
return (0, advance_js_1.advanceAndRecord)({
|
|
102
|
+
truth: truthLocked,
|
|
103
|
+
sessionId,
|
|
104
|
+
runId,
|
|
105
|
+
nodeId,
|
|
106
|
+
attemptId,
|
|
107
|
+
workflowHash,
|
|
108
|
+
dedupeKey,
|
|
109
|
+
inputContext: input.context,
|
|
110
|
+
inputOutput: input.output,
|
|
111
|
+
lock,
|
|
112
|
+
pinnedWorkflow,
|
|
113
|
+
snapshotStore,
|
|
114
|
+
sessionStore,
|
|
115
|
+
sha256,
|
|
116
|
+
idFactory,
|
|
117
|
+
}).andThen(() => sessionStore
|
|
118
|
+
.load(sessionId)
|
|
119
|
+
.map((truthAfter) => ({ kind: 'replay', truth: truthAfter, recordedEvent: null })));
|
|
120
|
+
}))
|
|
121
|
+
.mapErr((cause) => {
|
|
122
|
+
if ((0, v2_error_mapping_js_1.isInternalError)(cause)) {
|
|
123
|
+
return {
|
|
124
|
+
kind: 'invariant_violation',
|
|
125
|
+
message: `Advance failed due to internal error: ${cause.kind}`,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
if (typeof cause === 'object' && cause !== null && 'code' in cause) {
|
|
129
|
+
const code = cause.code;
|
|
130
|
+
if (code.startsWith('SNAPSHOT_STORE_')) {
|
|
131
|
+
return { kind: 'snapshot_load_failed', cause: cause };
|
|
132
|
+
}
|
|
133
|
+
return { kind: 'advance_execution_failed', cause: cause };
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
kind: 'invariant_violation',
|
|
137
|
+
message: 'Advance failed with an unknown error shape.',
|
|
138
|
+
};
|
|
139
|
+
})
|
|
140
|
+
.andThen((res) => {
|
|
141
|
+
const truth2 = res.truth;
|
|
142
|
+
const recordedEvent = res.recordedEvent ??
|
|
143
|
+
truth2.events.find((e) => e.kind === constants_js_1.EVENT_KIND.ADVANCE_RECORDED && e.dedupeKey === dedupeKey);
|
|
144
|
+
if (!recordedEvent) {
|
|
145
|
+
return (0, neverthrow_1.errAsync)({
|
|
146
|
+
kind: 'invariant_violation',
|
|
147
|
+
message: 'Missing recorded advance outcome after successful append.',
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return (0, replay_js_1.replayFromRecordedAdvance)({
|
|
151
|
+
recordedEvent,
|
|
152
|
+
truth: truth2,
|
|
153
|
+
sessionId,
|
|
154
|
+
runId,
|
|
155
|
+
nodeId,
|
|
156
|
+
workflowHash,
|
|
157
|
+
attemptId,
|
|
158
|
+
inputStateToken: input.stateToken,
|
|
159
|
+
inputAckToken: input.ackToken,
|
|
160
|
+
pinnedWorkflow,
|
|
161
|
+
snapshotStore,
|
|
162
|
+
sha256,
|
|
163
|
+
tokenCodecPorts,
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { V2ContinueWorkflowInput } from '../../v2/tools.js';
|
|
2
|
+
import { V2ContinueWorkflowOutputSchema } from '../../output-schemas.js';
|
|
3
|
+
import { type SessionId, type RunId, type NodeId } from '../../../v2/durable-core/ids/index.js';
|
|
4
|
+
import type { LoadedSessionTruthV2 } from '../../../v2/ports/session-event-log-store.port.js';
|
|
5
|
+
import type { TokenCodecPorts } from '../../../v2/durable-core/tokens/token-codec-ports.js';
|
|
6
|
+
import { ResultAsync as RA } from 'neverthrow';
|
|
7
|
+
import { type ContinueWorkflowError } from '../v2-execution-helpers.js';
|
|
8
|
+
import * as z from 'zod';
|
|
9
|
+
export declare function handleRehydrateIntent(args: {
|
|
10
|
+
readonly input: V2ContinueWorkflowInput;
|
|
11
|
+
readonly sessionId: SessionId;
|
|
12
|
+
readonly runId: RunId;
|
|
13
|
+
readonly nodeId: NodeId;
|
|
14
|
+
readonly workflowHashRef: string;
|
|
15
|
+
readonly truth: LoadedSessionTruthV2;
|
|
16
|
+
readonly tokenCodecPorts: TokenCodecPorts;
|
|
17
|
+
readonly pinnedStore: import('../../../v2/ports/pinned-workflow-store.port.js').PinnedWorkflowStorePortV2;
|
|
18
|
+
readonly snapshotStore: import('../../../v2/ports/snapshot-store.port.js').SnapshotStorePortV2;
|
|
19
|
+
readonly idFactory: {
|
|
20
|
+
readonly mintAttemptId: () => import('../../../v2/durable-core/tokens/index.js').AttemptId;
|
|
21
|
+
};
|
|
22
|
+
}): RA<z.infer<typeof V2ContinueWorkflowOutputSchema>, ContinueWorkflowError>;
|