@exaudeus/workrail 1.4.0 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/manifest.json +464 -200
- 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 +100 -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 +5 -4
- package/dist/mcp/handlers/v2-context-budget.js +2 -2
- 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 +170 -0
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +22 -0
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +146 -0
- package/dist/mcp/handlers/v2-execution/index.d.ts +23 -0
- package/dist/mcp/handlers/v2-execution/index.js +113 -0
- package/dist/mcp/handlers/v2-execution/replay.d.ts +55 -0
- package/dist/mcp/handlers/v2-execution/replay.js +227 -0
- package/dist/mcp/handlers/v2-execution/start.d.ts +52 -0
- package/dist/mcp/handlers/v2-execution/start.js +350 -0
- package/dist/mcp/handlers/v2-execution-helpers.d.ts +23 -0
- package/dist/mcp/handlers/v2-execution-helpers.js +42 -1
- package/dist/mcp/handlers/v2-execution.d.ts +1 -23
- package/dist/mcp/handlers/v2-execution.js +5 -898
- package/dist/mcp/handlers/v2-resume.d.ts +8 -0
- package/dist/mcp/handlers/v2-resume.js +70 -0
- 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 +76 -64
- package/dist/mcp/output-schemas.d.ts +40 -0
- package/dist/mcp/output-schemas.js +17 -1
- package/dist/mcp/server.js +12 -0
- package/dist/mcp/tool-descriptions.js +22 -0
- package/dist/mcp/tools.js +6 -0
- package/dist/mcp/types/tool-description-types.d.ts +1 -1
- package/dist/mcp/types/tool-description-types.js +1 -0
- package/dist/mcp/types/workflow-tool-edition.d.ts +1 -1
- package/dist/mcp/types.d.ts +6 -0
- package/dist/mcp/v2/tool-registry.js +8 -0
- package/dist/mcp/v2/tools.d.ts +15 -0
- package/dist/mcp/v2/tools.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 +23 -13
- package/dist/v2/durable-core/domain/ack-advance-append-plan.js +160 -113
- package/dist/v2/durable-core/domain/blocked-node-builder.js +8 -2
- 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.js +2 -1
- package/dist/v2/durable-core/schemas/execution-snapshot/blocked-snapshot.d.ts +24 -24
- 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 +180 -180
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +282 -287
- 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 +36 -36
- 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 +8 -0
- package/dist/v2/infra/local/directory-listing/index.js +18 -0
- package/dist/v2/infra/local/fs/index.d.ts +1 -0
- package/dist/v2/infra/local/fs/index.js +3 -0
- package/dist/v2/infra/local/session-store/index.js +198 -182
- package/dist/v2/infra/local/session-summary-provider/index.d.ts +18 -0
- package/dist/v2/infra/local/session-summary-provider/index.js +144 -0
- 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/directory-listing.port.d.ts +5 -0
- package/dist/v2/ports/directory-listing.port.js +2 -0
- package/dist/v2/ports/fs.port.d.ts +19 -7
- package/dist/v2/ports/session-event-log-store.port.d.ts +5 -2
- package/dist/v2/ports/session-summary-provider.port.d.ts +9 -0
- package/dist/v2/ports/session-summary-provider.port.js +2 -0
- 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.d.ts +62 -0
- package/dist/v2/projections/resume-ranking.js +105 -0
- 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/enumerate-sessions.d.ts +9 -0
- package/dist/v2/usecases/enumerate-sessions.js +13 -0
- 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/dist/v2/usecases/resume-session.d.ts +4 -0
- package/dist/v2/usecases/resume-session.js +9 -0
- package/package.json +1 -1
|
@@ -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);
|
|
@@ -85,7 +86,7 @@ function executeCheckpoint(input, ctx) {
|
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
88
|
function replayCheckpoint(events, dedupeKey, originalNode, sessionId, runId, nodeId, tokenCodecPorts) {
|
|
88
|
-
const existingCheckpointNode = events.find((e) => e.kind ===
|
|
89
|
+
const existingCheckpointNode = events.find((e) => e.kind === constants_js_1.EVENT_KIND.NODE_CREATED && e.dedupeKey === `checkpoint_node:${dedupeKey}`);
|
|
89
90
|
const checkpointNodeId = existingCheckpointNode
|
|
90
91
|
? String(existingCheckpointNode.scope?.nodeId ?? 'unknown')
|
|
91
92
|
: 'unknown';
|
|
@@ -106,7 +107,7 @@ function writeCheckpoint(truth, dedupeKey, originalNode, sessionId, runId, nodeI
|
|
|
106
107
|
eventId: nodeCreatedEventId,
|
|
107
108
|
eventIndex: truth.events.length,
|
|
108
109
|
sessionId: String(sessionId),
|
|
109
|
-
kind:
|
|
110
|
+
kind: constants_js_1.EVENT_KIND.NODE_CREATED,
|
|
110
111
|
dedupeKey: `checkpoint_node:${dedupeKey}`,
|
|
111
112
|
scope: { runId: String(runId), nodeId: String(checkpointNodeId) },
|
|
112
113
|
data: {
|
|
@@ -121,7 +122,7 @@ function writeCheckpoint(truth, dedupeKey, originalNode, sessionId, runId, nodeI
|
|
|
121
122
|
eventId: edgeCreatedEventId,
|
|
122
123
|
eventIndex: truth.events.length + 1,
|
|
123
124
|
sessionId: String(sessionId),
|
|
124
|
-
kind:
|
|
125
|
+
kind: constants_js_1.EVENT_KIND.EDGE_CREATED,
|
|
125
126
|
dedupeKey,
|
|
126
127
|
scope: { runId: String(runId) },
|
|
127
128
|
data: {
|
|
@@ -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;
|
|
@@ -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,170 @@
|
|
|
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 invariant violation: ${cause.kind}`,
|
|
126
|
+
suggestion: 'Retry; if this persists, treat as invariant violation.',
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
if (typeof cause === 'object' && cause !== null && 'code' in cause) {
|
|
130
|
+
const code = cause.code;
|
|
131
|
+
if (code.startsWith('SNAPSHOT_STORE_')) {
|
|
132
|
+
return { kind: 'snapshot_load_failed', cause: cause };
|
|
133
|
+
}
|
|
134
|
+
return { kind: 'advance_execution_failed', cause: cause };
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
kind: 'invariant_violation',
|
|
138
|
+
message: 'Advance failed with an unknown error shape (invariant violation).',
|
|
139
|
+
suggestion: 'Retry; if this persists, treat as invariant violation.',
|
|
140
|
+
};
|
|
141
|
+
})
|
|
142
|
+
.andThen((res) => {
|
|
143
|
+
const truth2 = res.truth;
|
|
144
|
+
const recordedEvent = res.recordedEvent ??
|
|
145
|
+
truth2.events.find((e) => e.kind === constants_js_1.EVENT_KIND.ADVANCE_RECORDED && e.dedupeKey === dedupeKey);
|
|
146
|
+
if (!recordedEvent) {
|
|
147
|
+
return (0, neverthrow_1.errAsync)({
|
|
148
|
+
kind: 'invariant_violation',
|
|
149
|
+
message: 'Missing recorded advance outcome after successful append (invariant violation).',
|
|
150
|
+
suggestion: 'Retry; if this persists, treat as invariant violation.',
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return (0, replay_js_1.replayFromRecordedAdvance)({
|
|
154
|
+
recordedEvent,
|
|
155
|
+
truth: truth2,
|
|
156
|
+
sessionId,
|
|
157
|
+
runId,
|
|
158
|
+
nodeId,
|
|
159
|
+
workflowHash,
|
|
160
|
+
attemptId,
|
|
161
|
+
inputStateToken: input.stateToken,
|
|
162
|
+
inputAckToken: input.ackToken,
|
|
163
|
+
pinnedWorkflow,
|
|
164
|
+
snapshotStore,
|
|
165
|
+
sha256,
|
|
166
|
+
tokenCodecPorts,
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
}
|
|
@@ -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>;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleRehydrateIntent = handleRehydrateIntent;
|
|
4
|
+
const output_schemas_js_1 = require("../../output-schemas.js");
|
|
5
|
+
const snapshot_state_js_1 = require("../../../v2/durable-core/projections/snapshot-state.js");
|
|
6
|
+
const workflow_js_1 = require("../../../types/workflow.js");
|
|
7
|
+
const index_js_1 = require("../../../v2/durable-core/ids/index.js");
|
|
8
|
+
const workflow_hash_ref_js_1 = require("../../../v2/durable-core/ids/workflow-hash-ref.js");
|
|
9
|
+
const neverthrow_1 = require("neverthrow");
|
|
10
|
+
const workflow_source_js_1 = require("../../../types/workflow-source.js");
|
|
11
|
+
const workflow_definition_js_1 = require("../../../types/workflow-definition.js");
|
|
12
|
+
const v2_execution_helpers_js_1 = require("../v2-execution-helpers.js");
|
|
13
|
+
const prompt_renderer_js_1 = require("../../../v2/durable-core/domain/prompt-renderer.js");
|
|
14
|
+
const v2_token_ops_js_1 = require("../v2-token-ops.js");
|
|
15
|
+
const v2_state_conversion_js_1 = require("../v2-state-conversion.js");
|
|
16
|
+
const constants_js_1 = require("../../../v2/durable-core/constants.js");
|
|
17
|
+
const index_js_2 = require("./index.js");
|
|
18
|
+
function handleRehydrateIntent(args) {
|
|
19
|
+
const { input, sessionId, runId, nodeId, workflowHashRef, truth, tokenCodecPorts, pinnedStore, snapshotStore, idFactory } = args;
|
|
20
|
+
const runStarted = truth.events.find((e) => e.kind === constants_js_1.EVENT_KIND.RUN_STARTED && e.scope.runId === String(runId));
|
|
21
|
+
const workflowId = runStarted?.data.workflowId;
|
|
22
|
+
if (!runStarted || typeof workflowId !== 'string' || workflowId.trim() === '') {
|
|
23
|
+
return (0, neverthrow_1.errAsync)({
|
|
24
|
+
kind: 'token_unknown_node',
|
|
25
|
+
message: 'No durable run state was found for this stateToken (missing run_started).',
|
|
26
|
+
suggestion: 'Use start_workflow to mint a new run, or use a stateToken returned by WorkRail for an existing run.',
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
const workflowHash = runStarted.data.workflowHash;
|
|
30
|
+
const expectedRefRes = (0, workflow_hash_ref_js_1.deriveWorkflowHashRef)(workflowHash);
|
|
31
|
+
if (expectedRefRes.isErr()) {
|
|
32
|
+
return (0, neverthrow_1.errAsync)({
|
|
33
|
+
kind: 'precondition_failed',
|
|
34
|
+
message: expectedRefRes.error.message,
|
|
35
|
+
suggestion: 'Re-pin the workflow via start_workflow.',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (String(expectedRefRes.value) !== String(workflowHashRef)) {
|
|
39
|
+
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'workflowHash mismatch for this run.', suggestion: 'Use the stateToken returned by WorkRail for this run.' });
|
|
40
|
+
}
|
|
41
|
+
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));
|
|
42
|
+
if (!nodeCreated) {
|
|
43
|
+
return (0, neverthrow_1.errAsync)({
|
|
44
|
+
kind: 'token_unknown_node',
|
|
45
|
+
message: 'No durable node state was found for this stateToken (missing node_created).',
|
|
46
|
+
suggestion: 'Use a stateToken returned by WorkRail for an existing node.',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
const expectedNodeRefRes = (0, workflow_hash_ref_js_1.deriveWorkflowHashRef)(nodeCreated.data.workflowHash);
|
|
50
|
+
if (expectedNodeRefRes.isErr()) {
|
|
51
|
+
return (0, neverthrow_1.errAsync)({
|
|
52
|
+
kind: 'precondition_failed',
|
|
53
|
+
message: expectedNodeRefRes.error.message,
|
|
54
|
+
suggestion: 'Re-pin the workflow via start_workflow.',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (String(expectedNodeRefRes.value) !== String(workflowHashRef)) {
|
|
58
|
+
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'workflowHash mismatch for this node.', suggestion: 'Use the stateToken returned by WorkRail for this node.' });
|
|
59
|
+
}
|
|
60
|
+
return snapshotStore.getExecutionSnapshotV1(nodeCreated.data.snapshotRef)
|
|
61
|
+
.mapErr((cause) => ({ kind: 'snapshot_load_failed', cause }))
|
|
62
|
+
.andThen((snapshot) => {
|
|
63
|
+
if (!snapshot) {
|
|
64
|
+
return (0, neverthrow_1.errAsync)({
|
|
65
|
+
kind: 'token_unknown_node',
|
|
66
|
+
message: 'No execution snapshot was found for this node.',
|
|
67
|
+
suggestion: 'Use a stateToken returned by WorkRail for an existing node.',
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
const engineState = snapshot.enginePayload.engineState;
|
|
71
|
+
const pending = (0, snapshot_state_js_1.derivePendingStep)(engineState);
|
|
72
|
+
const isComplete = (0, snapshot_state_js_1.deriveIsComplete)(engineState);
|
|
73
|
+
if (!pending) {
|
|
74
|
+
const preferences = (0, v2_execution_helpers_js_1.derivePreferencesOrDefault)({ truth, runId, nodeId });
|
|
75
|
+
const nextIntent = (0, v2_state_conversion_js_1.deriveNextIntent)({ rehydrateOnly: true, isComplete, pending: null });
|
|
76
|
+
return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2ContinueWorkflowOutputSchema.parse({
|
|
77
|
+
kind: 'ok',
|
|
78
|
+
stateToken: input.stateToken,
|
|
79
|
+
isComplete,
|
|
80
|
+
pending: null,
|
|
81
|
+
preferences,
|
|
82
|
+
nextIntent,
|
|
83
|
+
nextCall: (0, index_js_2.buildNextCall)({ stateToken: input.stateToken, ackToken: undefined, isComplete, pending: null }),
|
|
84
|
+
}));
|
|
85
|
+
}
|
|
86
|
+
const attemptId = (0, v2_token_ops_js_1.newAttemptId)(idFactory);
|
|
87
|
+
const ackTokenRes = (0, v2_token_ops_js_1.signTokenOrErr)({
|
|
88
|
+
payload: { tokenVersion: 1, tokenKind: 'ack', sessionId, runId, nodeId, attemptId },
|
|
89
|
+
ports: tokenCodecPorts,
|
|
90
|
+
});
|
|
91
|
+
if (ackTokenRes.isErr())
|
|
92
|
+
return (0, neverthrow_1.errAsync)({ kind: 'token_signing_failed', cause: ackTokenRes.error });
|
|
93
|
+
const checkpointTokenRes = (0, v2_token_ops_js_1.signTokenOrErr)({
|
|
94
|
+
payload: { tokenVersion: 1, tokenKind: 'checkpoint', sessionId, runId, nodeId, attemptId },
|
|
95
|
+
ports: tokenCodecPorts,
|
|
96
|
+
});
|
|
97
|
+
if (checkpointTokenRes.isErr())
|
|
98
|
+
return (0, neverthrow_1.errAsync)({ kind: 'token_signing_failed', cause: checkpointTokenRes.error });
|
|
99
|
+
return pinnedStore.get(workflowHash)
|
|
100
|
+
.mapErr((cause) => ({ kind: 'pinned_workflow_store_failed', cause }))
|
|
101
|
+
.andThen((pinned) => {
|
|
102
|
+
if (!pinned)
|
|
103
|
+
return (0, neverthrow_1.errAsync)({ kind: 'pinned_workflow_missing', workflowHash });
|
|
104
|
+
if (pinned.sourceKind !== 'v1_pinned')
|
|
105
|
+
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'Pinned workflow snapshot is read-only (v1_preview) and cannot be executed.' });
|
|
106
|
+
if (!(0, workflow_definition_js_1.hasWorkflowDefinitionShape)(pinned.definition)) {
|
|
107
|
+
return (0, neverthrow_1.errAsync)({
|
|
108
|
+
kind: 'precondition_failed',
|
|
109
|
+
message: 'Pinned workflow snapshot has an invalid workflow definition shape.',
|
|
110
|
+
suggestion: 'Re-pin the workflow via start_workflow.',
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
const wf = (0, workflow_js_1.createWorkflow)(pinned.definition, (0, workflow_source_js_1.createBundledSource)());
|
|
114
|
+
const metaRes = (0, prompt_renderer_js_1.renderPendingPrompt)({
|
|
115
|
+
workflow: wf,
|
|
116
|
+
stepId: String(pending.stepId),
|
|
117
|
+
loopPath: pending.loopPath,
|
|
118
|
+
truth,
|
|
119
|
+
runId: (0, index_js_1.asRunId)(String(runId)),
|
|
120
|
+
nodeId: (0, index_js_1.asNodeId)(String(nodeId)),
|
|
121
|
+
rehydrateOnly: true,
|
|
122
|
+
});
|
|
123
|
+
if (metaRes.isErr()) {
|
|
124
|
+
return (0, neverthrow_1.errAsync)({
|
|
125
|
+
kind: 'invariant_violation',
|
|
126
|
+
message: `Prompt rendering failed: ${metaRes.error.message}`,
|
|
127
|
+
suggestion: 'Retry; if this persists, treat as invariant violation.',
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
const meta = metaRes.value;
|
|
131
|
+
const preferences = (0, v2_execution_helpers_js_1.derivePreferencesOrDefault)({ truth, runId, nodeId });
|
|
132
|
+
const nextIntent = (0, v2_state_conversion_js_1.deriveNextIntent)({ rehydrateOnly: true, isComplete, pending: meta });
|
|
133
|
+
return (0, neverthrow_1.okAsync)(output_schemas_js_1.V2ContinueWorkflowOutputSchema.parse({
|
|
134
|
+
kind: 'ok',
|
|
135
|
+
stateToken: input.stateToken,
|
|
136
|
+
ackToken: ackTokenRes.value,
|
|
137
|
+
checkpointToken: checkpointTokenRes.value,
|
|
138
|
+
isComplete,
|
|
139
|
+
pending: { stepId: meta.stepId, title: meta.title, prompt: meta.prompt },
|
|
140
|
+
preferences,
|
|
141
|
+
nextIntent,
|
|
142
|
+
nextCall: (0, index_js_2.buildNextCall)({ stateToken: input.stateToken, ackToken: ackTokenRes.value, isComplete, pending: meta }),
|
|
143
|
+
}));
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ToolContext, ToolResult } from '../../types.js';
|
|
2
|
+
import type { V2ContinueWorkflowInput, V2StartWorkflowInput } from '../../v2/tools.js';
|
|
3
|
+
type NextCallTemplate = {
|
|
4
|
+
readonly tool: 'continue_workflow';
|
|
5
|
+
readonly params: {
|
|
6
|
+
readonly intent: 'advance';
|
|
7
|
+
readonly stateToken: string;
|
|
8
|
+
readonly ackToken: string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
export declare function buildNextCall(args: {
|
|
12
|
+
readonly stateToken: string;
|
|
13
|
+
readonly ackToken: string | undefined;
|
|
14
|
+
readonly isComplete: boolean;
|
|
15
|
+
readonly pending: {
|
|
16
|
+
readonly stepId: string;
|
|
17
|
+
} | null;
|
|
18
|
+
readonly retryable?: boolean;
|
|
19
|
+
readonly retryAckToken?: string;
|
|
20
|
+
}): NextCallTemplate | null;
|
|
21
|
+
export declare function handleV2StartWorkflow(input: V2StartWorkflowInput, ctx: ToolContext): Promise<ToolResult<unknown>>;
|
|
22
|
+
export declare function handleV2ContinueWorkflow(input: V2ContinueWorkflowInput, ctx: ToolContext): Promise<ToolResult<unknown>>;
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildNextCall = buildNextCall;
|
|
4
|
+
exports.handleV2StartWorkflow = handleV2StartWorkflow;
|
|
5
|
+
exports.handleV2ContinueWorkflow = handleV2ContinueWorkflow;
|
|
6
|
+
const types_js_1 = require("../../types.js");
|
|
7
|
+
const index_js_1 = require("../../../v2/durable-core/tokens/index.js");
|
|
8
|
+
const index_js_2 = require("../../../v2/durable-core/ids/index.js");
|
|
9
|
+
const neverthrow_1 = require("neverthrow");
|
|
10
|
+
const v2_execution_helpers_js_1 = require("../v2-execution-helpers.js");
|
|
11
|
+
const v2_token_ops_js_1 = require("../v2-token-ops.js");
|
|
12
|
+
const v2_context_budget_js_1 = require("../v2-context-budget.js");
|
|
13
|
+
const start_js_1 = require("./start.js");
|
|
14
|
+
const continue_rehydrate_js_1 = require("./continue-rehydrate.js");
|
|
15
|
+
const continue_advance_js_1 = require("./continue-advance.js");
|
|
16
|
+
function buildNextCall(args) {
|
|
17
|
+
if (args.isComplete && !args.pending)
|
|
18
|
+
return null;
|
|
19
|
+
if (args.retryable && args.retryAckToken) {
|
|
20
|
+
return {
|
|
21
|
+
tool: 'continue_workflow',
|
|
22
|
+
params: { intent: 'advance', stateToken: args.stateToken, ackToken: args.retryAckToken },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
if (!args.ackToken)
|
|
26
|
+
return null;
|
|
27
|
+
return {
|
|
28
|
+
tool: 'continue_workflow',
|
|
29
|
+
params: { intent: 'advance', stateToken: args.stateToken, ackToken: args.ackToken },
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async function handleV2StartWorkflow(input, ctx) {
|
|
33
|
+
return (0, start_js_1.executeStartWorkflow)(input, ctx).match((payload) => (0, types_js_1.success)(payload), (e) => (0, v2_execution_helpers_js_1.mapStartWorkflowErrorToToolError)(e));
|
|
34
|
+
}
|
|
35
|
+
async function handleV2ContinueWorkflow(input, ctx) {
|
|
36
|
+
return executeContinueWorkflow(input, ctx).match((payload) => (0, types_js_1.success)(payload), (e) => (0, v2_execution_helpers_js_1.mapContinueWorkflowErrorToToolError)(e));
|
|
37
|
+
}
|
|
38
|
+
function executeContinueWorkflow(input, ctx) {
|
|
39
|
+
if (!ctx.v2) {
|
|
40
|
+
return (0, neverthrow_1.errAsync)({ kind: 'precondition_failed', message: 'v2 tools disabled', suggestion: 'Enable v2Tools flag' });
|
|
41
|
+
}
|
|
42
|
+
const { gate, sessionStore, snapshotStore, pinnedStore, sha256, tokenCodecPorts, idFactory } = ctx.v2;
|
|
43
|
+
if (!sha256 || !idFactory) {
|
|
44
|
+
return (0, neverthrow_1.errAsync)({
|
|
45
|
+
kind: 'precondition_failed',
|
|
46
|
+
message: 'v2 context missing required dependencies',
|
|
47
|
+
suggestion: 'Reinitialize v2 tool context (sha256 and idFactory must be provided when v2Tools are enabled).',
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (!tokenCodecPorts) {
|
|
51
|
+
return (0, neverthrow_1.errAsync)({
|
|
52
|
+
kind: 'precondition_failed',
|
|
53
|
+
message: 'v2 context missing tokenCodecPorts dependency',
|
|
54
|
+
suggestion: 'Reinitialize v2 tool context (tokenCodecPorts must be provided when v2Tools are enabled).',
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const stateRes = (0, v2_token_ops_js_1.parseStateTokenOrFail)(input.stateToken, tokenCodecPorts);
|
|
58
|
+
if (!stateRes.ok)
|
|
59
|
+
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: stateRes.failure });
|
|
60
|
+
const state = stateRes.token;
|
|
61
|
+
const ctxCheck = (0, v2_context_budget_js_1.checkContextBudget)({ tool: 'continue_workflow', context: input.context });
|
|
62
|
+
if (!ctxCheck.ok)
|
|
63
|
+
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: ctxCheck.error });
|
|
64
|
+
const sessionId = (0, index_js_2.asSessionId)(state.payload.sessionId);
|
|
65
|
+
const runId = (0, index_js_2.asRunId)(state.payload.runId);
|
|
66
|
+
const nodeId = (0, index_js_2.asNodeId)(state.payload.nodeId);
|
|
67
|
+
const workflowHashRef = state.payload.workflowHashRef;
|
|
68
|
+
if (input.intent === 'rehydrate') {
|
|
69
|
+
return sessionStore.load(sessionId)
|
|
70
|
+
.mapErr((cause) => ({ kind: 'session_load_failed', cause }))
|
|
71
|
+
.andThen((truth) => (0, continue_rehydrate_js_1.handleRehydrateIntent)({
|
|
72
|
+
input,
|
|
73
|
+
sessionId,
|
|
74
|
+
runId,
|
|
75
|
+
nodeId,
|
|
76
|
+
workflowHashRef,
|
|
77
|
+
truth,
|
|
78
|
+
tokenCodecPorts,
|
|
79
|
+
pinnedStore,
|
|
80
|
+
snapshotStore,
|
|
81
|
+
idFactory,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
if (!input.ackToken) {
|
|
85
|
+
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: (0, types_js_1.error)('VALIDATION_ERROR', 'ackToken is required for advance intent') });
|
|
86
|
+
}
|
|
87
|
+
const ackRes = (0, v2_token_ops_js_1.parseAckTokenOrFail)(input.ackToken, tokenCodecPorts);
|
|
88
|
+
if (!ackRes.ok)
|
|
89
|
+
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: ackRes.failure });
|
|
90
|
+
const ack = ackRes.token;
|
|
91
|
+
const scopeRes = (0, index_js_1.assertTokenScopeMatchesStateBinary)(state, ack);
|
|
92
|
+
if (scopeRes.isErr())
|
|
93
|
+
return (0, neverthrow_1.errAsync)({ kind: 'validation_failed', failure: (0, v2_execution_helpers_js_1.mapTokenDecodeErrorToToolError)(scopeRes.error) });
|
|
94
|
+
const attemptId = (0, index_js_1.asAttemptId)(ack.payload.attemptId);
|
|
95
|
+
return sessionStore.load(sessionId)
|
|
96
|
+
.mapErr((cause) => ({ kind: 'session_load_failed', cause }))
|
|
97
|
+
.andThen((truth) => (0, continue_advance_js_1.handleAdvanceIntent)({
|
|
98
|
+
input,
|
|
99
|
+
sessionId,
|
|
100
|
+
runId,
|
|
101
|
+
nodeId,
|
|
102
|
+
attemptId,
|
|
103
|
+
workflowHashRef,
|
|
104
|
+
truth,
|
|
105
|
+
gate,
|
|
106
|
+
sessionStore,
|
|
107
|
+
snapshotStore,
|
|
108
|
+
pinnedStore,
|
|
109
|
+
tokenCodecPorts,
|
|
110
|
+
idFactory,
|
|
111
|
+
sha256,
|
|
112
|
+
}));
|
|
113
|
+
}
|