@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
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { DomainError } from '../domain/execution/error.js';
|
|
2
2
|
import type { ToolError } from './types.js';
|
|
3
3
|
export declare function mapDomainErrorToToolError(err: DomainError): ToolError;
|
|
4
|
-
export declare function mapUnknownErrorToToolError(
|
|
4
|
+
export declare function mapUnknownErrorToToolError(_err: unknown): ToolError;
|
package/dist/mcp/error-mapper.js
CHANGED
|
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.mapDomainErrorToToolError = mapDomainErrorToToolError;
|
|
4
4
|
exports.mapUnknownErrorToToolError = mapUnknownErrorToToolError;
|
|
5
5
|
const bounded_json_js_1 = require("./validation/bounded-json.js");
|
|
6
|
-
|
|
6
|
+
const v2_execution_helpers_js_1 = require("./handlers/v2-execution-helpers.js");
|
|
7
|
+
function assertNever(_x) {
|
|
7
8
|
return {
|
|
8
9
|
type: 'error',
|
|
9
10
|
code: 'INTERNAL_ERROR',
|
|
10
|
-
message:
|
|
11
|
+
message: 'WorkRail encountered an unexpected error. This is not caused by your input.',
|
|
11
12
|
retry: { kind: 'not_retryable' },
|
|
12
|
-
details: {
|
|
13
|
+
details: { suggestion: (0, v2_execution_helpers_js_1.internalSuggestion)('', 'WorkRail has an internal error.') },
|
|
13
14
|
};
|
|
14
15
|
}
|
|
15
16
|
function mapDomainErrorToToolError(err) {
|
|
@@ -80,9 +81,12 @@ function mapDomainErrorToToolError(err) {
|
|
|
80
81
|
return assertNever(err);
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
|
-
function mapUnknownErrorToToolError(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
function mapUnknownErrorToToolError(_err) {
|
|
85
|
+
return {
|
|
86
|
+
type: 'error',
|
|
87
|
+
code: 'INTERNAL_ERROR',
|
|
88
|
+
message: 'WorkRail encountered an unexpected error. This is not caused by your input.',
|
|
89
|
+
retry: { kind: 'not_retryable' },
|
|
90
|
+
details: { suggestion: (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal error.') },
|
|
91
|
+
};
|
|
88
92
|
}
|
|
@@ -6,6 +6,7 @@ exports.createValidatingHandler = createValidatingHandler;
|
|
|
6
6
|
const types_js_1 = require("./types.js");
|
|
7
7
|
const index_js_1 = require("./validation/index.js");
|
|
8
8
|
const bounded_json_js_1 = require("./validation/bounded-json.js");
|
|
9
|
+
const v2_execution_helpers_js_1 = require("./handlers/v2-execution-helpers.js");
|
|
9
10
|
function toMcpResult(result) {
|
|
10
11
|
switch (result.type) {
|
|
11
12
|
case 'success':
|
|
@@ -41,7 +42,13 @@ function createHandler(schema, handler) {
|
|
|
41
42
|
...suggestionDetails,
|
|
42
43
|
}));
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
+
try {
|
|
46
|
+
return toMcpResult(await handler(parseResult.data, ctx));
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
console.error('[WorkRail] Unhandled exception in tool handler:', err);
|
|
50
|
+
return toMcpResult((0, types_js_1.errNotRetryable)('INTERNAL_ERROR', 'WorkRail encountered an unexpected error. This is not caused by your input.', { suggestion: (0, v2_execution_helpers_js_1.internalSuggestion)('Retry the call.', 'WorkRail has an internal error.') }));
|
|
51
|
+
}
|
|
45
52
|
};
|
|
46
53
|
}
|
|
47
54
|
function createValidatingHandler(schema, preValidate, handler) {
|
|
@@ -6,7 +6,6 @@ exports.handleReadSession = handleReadSession;
|
|
|
6
6
|
exports.handleOpenDashboard = handleOpenDashboard;
|
|
7
7
|
const types_js_1 = require("../types.js");
|
|
8
8
|
const output_schemas_js_1 = require("../output-schemas.js");
|
|
9
|
-
const error_mapper_js_1 = require("../error-mapper.js");
|
|
10
9
|
const SESSION_SCHEMA_OVERVIEW = {
|
|
11
10
|
description: 'Bug Investigation Session Data Structure',
|
|
12
11
|
mainSections: {
|
|
@@ -52,49 +51,38 @@ async function handleCreateSession(input, ctx) {
|
|
|
52
51
|
return guardError;
|
|
53
52
|
const sessionManager = ctx.sessionManager;
|
|
54
53
|
const httpServer = ctx.httpServer;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const dashboardUrl = baseUrl ? `${baseUrl}?session=${input.sessionId}` : null;
|
|
59
|
-
const payload = output_schemas_js_1.CreateSessionOutputSchema.parse({
|
|
60
|
-
sessionId: session.id,
|
|
61
|
-
workflowId: session.workflowId,
|
|
62
|
-
path: sessionManager.getSessionPath(input.workflowId, input.sessionId),
|
|
63
|
-
dashboardUrl,
|
|
64
|
-
createdAt: session.createdAt,
|
|
65
|
-
});
|
|
66
|
-
return (0, types_js_1.success)(payload);
|
|
67
|
-
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
const mapped = (0, error_mapper_js_1.mapUnknownErrorToToolError)(err);
|
|
70
|
-
return mapped;
|
|
54
|
+
const res = await sessionManager.createSession(input.workflowId, input.sessionId, input.initialData);
|
|
55
|
+
if (res.isErr()) {
|
|
56
|
+
return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', res.error.message);
|
|
71
57
|
}
|
|
58
|
+
const session = res.value;
|
|
59
|
+
const baseUrl = httpServer.getBaseUrl();
|
|
60
|
+
const dashboardUrl = baseUrl ? `${baseUrl}?session=${input.sessionId}` : null;
|
|
61
|
+
const payload = output_schemas_js_1.CreateSessionOutputSchema.parse({
|
|
62
|
+
sessionId: session.id,
|
|
63
|
+
workflowId: session.workflowId,
|
|
64
|
+
path: sessionManager.getSessionPath(input.workflowId, input.sessionId),
|
|
65
|
+
dashboardUrl,
|
|
66
|
+
createdAt: session.createdAt,
|
|
67
|
+
});
|
|
68
|
+
return (0, types_js_1.success)(payload);
|
|
72
69
|
}
|
|
73
70
|
async function handleUpdateSession(input, ctx) {
|
|
74
71
|
const guardError = requireSessionTools(ctx);
|
|
75
72
|
if (guardError)
|
|
76
73
|
return guardError;
|
|
77
74
|
const sessionManager = ctx.sessionManager;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
if (err instanceof Error && (err.name === 'SessionNotFoundError' ||
|
|
85
|
-
err.message.toLowerCase().includes('not found') ||
|
|
86
|
-
err.message.toLowerCase().includes('does not exist'))) {
|
|
87
|
-
return {
|
|
88
|
-
type: 'error',
|
|
89
|
-
code: 'NOT_FOUND',
|
|
90
|
-
message: err.message,
|
|
91
|
-
retry: { kind: 'not_retryable' },
|
|
92
|
-
details: { suggestion: 'Make sure the session exists. Use workrail_create_session() first.' },
|
|
93
|
-
};
|
|
75
|
+
const res = await sessionManager.updateSession(input.workflowId, input.sessionId, input.updates);
|
|
76
|
+
if (res.isErr()) {
|
|
77
|
+
if (res.error.code === 'SESSION_NOT_FOUND') {
|
|
78
|
+
return (0, types_js_1.errNotRetryable)('NOT_FOUND', res.error.message, {
|
|
79
|
+
suggestion: 'Make sure the session exists. Use workrail_create_session() first.',
|
|
80
|
+
});
|
|
94
81
|
}
|
|
95
|
-
|
|
96
|
-
return mapped;
|
|
82
|
+
return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', res.error.message);
|
|
97
83
|
}
|
|
84
|
+
const payload = output_schemas_js_1.UpdateSessionOutputSchema.parse({ updatedAt: new Date().toISOString() });
|
|
85
|
+
return (0, types_js_1.success)(payload);
|
|
98
86
|
}
|
|
99
87
|
async function handleReadSession(input, ctx) {
|
|
100
88
|
const guardError = requireSessionTools(ctx);
|
|
@@ -108,29 +96,20 @@ async function handleReadSession(input, ctx) {
|
|
|
108
96
|
});
|
|
109
97
|
return (0, types_js_1.success)(payload);
|
|
110
98
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
return (0, types_js_1.success)(payload);
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
if (err instanceof Error && (err.name === 'SessionNotFoundError' ||
|
|
121
|
-
err.message.toLowerCase().includes('not found') ||
|
|
122
|
-
err.message.toLowerCase().includes('does not exist'))) {
|
|
123
|
-
return {
|
|
124
|
-
type: 'error',
|
|
125
|
-
code: 'NOT_FOUND',
|
|
126
|
-
message: err.message,
|
|
127
|
-
retry: { kind: 'not_retryable' },
|
|
128
|
-
details: { suggestion: 'Make sure the session exists. Use workrail_create_session() first.' },
|
|
129
|
-
};
|
|
99
|
+
const res = await sessionManager.readSession(input.workflowId, input.sessionId, input.path);
|
|
100
|
+
if (res.isErr()) {
|
|
101
|
+
if (res.error.code === 'SESSION_NOT_FOUND') {
|
|
102
|
+
return (0, types_js_1.errNotRetryable)('NOT_FOUND', res.error.message, {
|
|
103
|
+
suggestion: 'Make sure the session exists. Use workrail_create_session() first.',
|
|
104
|
+
});
|
|
130
105
|
}
|
|
131
|
-
|
|
132
|
-
return mapped;
|
|
106
|
+
return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', res.error.message);
|
|
133
107
|
}
|
|
108
|
+
const payload = output_schemas_js_1.ReadSessionOutputSchema.parse({
|
|
109
|
+
query: input.path ?? '(full session)',
|
|
110
|
+
data: res.value,
|
|
111
|
+
});
|
|
112
|
+
return (0, types_js_1.success)(payload);
|
|
134
113
|
}
|
|
135
114
|
async function handleOpenDashboard(input, ctx) {
|
|
136
115
|
const guardError = requireSessionTools(ctx);
|
|
@@ -143,7 +122,6 @@ async function handleOpenDashboard(input, ctx) {
|
|
|
143
122
|
return (0, types_js_1.success)(payload);
|
|
144
123
|
}
|
|
145
124
|
catch (err) {
|
|
146
|
-
|
|
147
|
-
return mapped;
|
|
125
|
+
return (0, types_js_1.errNotRetryable)('INTERNAL_ERROR', err instanceof Error ? err.message : 'Failed to open dashboard');
|
|
148
126
|
}
|
|
149
127
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ResultAsync as RA, type Result } from 'neverthrow';
|
|
2
|
+
import type { DomainEventV1 } from '../../../v2/durable-core/schemas/session/index.js';
|
|
3
|
+
import type { SessionId, RunId, NodeId, WorkflowHash } from '../../../v2/durable-core/ids/index.js';
|
|
4
|
+
import type { AttemptId } from '../../../v2/durable-core/tokens/index.js';
|
|
5
|
+
import type { LoadedSessionTruthV2 } from '../../../v2/ports/session-event-log-store.port.js';
|
|
6
|
+
import type { SessionEventLogStoreError } from '../../../v2/ports/session-event-log-store.port.js';
|
|
7
|
+
import type { WithHealthySessionLock } from '../../../v2/durable-core/ids/with-healthy-session-lock.js';
|
|
8
|
+
import type { Sha256PortV2 } from '../../../v2/ports/sha256.port.js';
|
|
9
|
+
import type { V2ContinueWorkflowInput } from '../../v2/tools.js';
|
|
10
|
+
import { type OutputToAppend } from '../../../v2/durable-core/domain/outputs.js';
|
|
11
|
+
import type { InternalError } from '../v2-error-mapping.js';
|
|
12
|
+
import type { AdvanceCorePorts } from './index.js';
|
|
13
|
+
type BuildAppendPlanArgs = {
|
|
14
|
+
readonly truth: LoadedSessionTruthV2;
|
|
15
|
+
readonly sessionId: SessionId;
|
|
16
|
+
readonly runId: RunId;
|
|
17
|
+
readonly currentNodeId: NodeId;
|
|
18
|
+
readonly attemptId: AttemptId;
|
|
19
|
+
readonly workflowHash: WorkflowHash;
|
|
20
|
+
readonly extraEventsToAppend: readonly Omit<DomainEventV1, 'eventIndex' | 'sessionId'>[];
|
|
21
|
+
readonly sessionStore: import('../../../v2/ports/session-event-log-store.port.js').SessionEventLogAppendStorePortV2;
|
|
22
|
+
readonly idFactory: AdvanceCorePorts['idFactory'];
|
|
23
|
+
readonly lock: WithHealthySessionLock;
|
|
24
|
+
} & ({
|
|
25
|
+
readonly kind: 'blocked';
|
|
26
|
+
readonly blockers: import('../../../v2/durable-core/domain/reason-model.js').BlockerReportV1;
|
|
27
|
+
readonly snapshotRef: import('../../../v2/durable-core/ids/index.js').SnapshotRef;
|
|
28
|
+
} | {
|
|
29
|
+
readonly kind: 'advanced';
|
|
30
|
+
readonly toNodeKind: 'step' | 'blocked_attempt' | undefined;
|
|
31
|
+
readonly snapshotRef: import('../../../v2/durable-core/ids/index.js').SnapshotRef;
|
|
32
|
+
readonly outputsToAppend: readonly OutputToAppend[];
|
|
33
|
+
});
|
|
34
|
+
export declare function buildAndAppendPlan(args: BuildAppendPlanArgs): RA<void, InternalError | SessionEventLogStoreError>;
|
|
35
|
+
export declare function buildNotesOutputs(allowNotesAppend: boolean, attemptId: AttemptId, inputOutput: V2ContinueWorkflowInput['output']): readonly OutputToAppend[];
|
|
36
|
+
export declare function buildArtifactOutputs(inputArtifacts: readonly unknown[], attemptId: AttemptId, sha256: Sha256PortV2): Result<readonly OutputToAppend[], InternalError>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildAndAppendPlan = buildAndAppendPlan;
|
|
4
|
+
exports.buildNotesOutputs = buildNotesOutputs;
|
|
5
|
+
exports.buildArtifactOutputs = buildArtifactOutputs;
|
|
6
|
+
const neverthrow_1 = require("neverthrow");
|
|
7
|
+
const index_js_1 = require("../../../v2/durable-core/tokens/index.js");
|
|
8
|
+
const jcs_js_1 = require("../../../v2/durable-core/canonical/jcs.js");
|
|
9
|
+
const notes_markdown_js_1 = require("../../../v2/durable-core/domain/notes-markdown.js");
|
|
10
|
+
const outputs_js_1 = require("../../../v2/durable-core/domain/outputs.js");
|
|
11
|
+
const ack_advance_append_plan_js_1 = require("../../../v2/durable-core/domain/ack-advance-append-plan.js");
|
|
12
|
+
const constants_js_1 = require("../../../v2/durable-core/constants.js");
|
|
13
|
+
function buildAndAppendPlan(args) {
|
|
14
|
+
const { truth, sessionId, runId, currentNodeId, attemptId, workflowHash, extraEventsToAppend, sessionStore, idFactory, lock } = args;
|
|
15
|
+
const nextEventIndex = truth.events.length === 0 ? 0 : truth.events[truth.events.length - 1].eventIndex + 1;
|
|
16
|
+
const evtAdvanceRecorded = idFactory.mintEventId();
|
|
17
|
+
if (args.kind === 'blocked') {
|
|
18
|
+
const toNodeId = String(idFactory.mintNodeId());
|
|
19
|
+
const evtNodeCreated = idFactory.mintEventId();
|
|
20
|
+
const evtEdgeCreated = idFactory.mintEventId();
|
|
21
|
+
const hasChildren = truth.events.some((e) => e.kind === constants_js_1.EVENT_KIND.EDGE_CREATED && e.data.fromNodeId === String(currentNodeId));
|
|
22
|
+
const causeKind = hasChildren ? constants_js_1.EDGE_CAUSE.NON_TIP_ADVANCE : constants_js_1.EDGE_CAUSE.INTENTIONAL_FORK;
|
|
23
|
+
const planRes = (0, ack_advance_append_plan_js_1.buildAckAdvanceAppendPlanV1)({
|
|
24
|
+
sessionId: String(sessionId),
|
|
25
|
+
runId: String(runId),
|
|
26
|
+
fromNodeId: String(currentNodeId),
|
|
27
|
+
workflowHash,
|
|
28
|
+
attemptId: String(attemptId),
|
|
29
|
+
nextEventIndex,
|
|
30
|
+
extraEventsToAppend,
|
|
31
|
+
outcome: { kind: 'advanced', toNodeId },
|
|
32
|
+
toNodeKind: 'blocked_attempt',
|
|
33
|
+
toNodeId,
|
|
34
|
+
snapshotRef: args.snapshotRef,
|
|
35
|
+
causeKind,
|
|
36
|
+
minted: {
|
|
37
|
+
advanceRecordedEventId: evtAdvanceRecorded,
|
|
38
|
+
nodeCreatedEventId: evtNodeCreated,
|
|
39
|
+
edgeCreatedEventId: evtEdgeCreated,
|
|
40
|
+
outputEventIds: [],
|
|
41
|
+
},
|
|
42
|
+
outputsToAppend: [],
|
|
43
|
+
});
|
|
44
|
+
if (planRes.isErr())
|
|
45
|
+
return (0, neverthrow_1.errAsync)({ kind: 'invariant_violation', message: planRes.error.message });
|
|
46
|
+
return sessionStore.append(lock, planRes.value);
|
|
47
|
+
}
|
|
48
|
+
const toNodeId = String(idFactory.mintNodeId());
|
|
49
|
+
const evtNodeCreated = idFactory.mintEventId();
|
|
50
|
+
const evtEdgeCreated = idFactory.mintEventId();
|
|
51
|
+
const hasChildren = truth.events.some((e) => e.kind === constants_js_1.EVENT_KIND.EDGE_CREATED && e.data.fromNodeId === String(currentNodeId));
|
|
52
|
+
const causeKind = hasChildren ? constants_js_1.EDGE_CAUSE.NON_TIP_ADVANCE : constants_js_1.EDGE_CAUSE.INTENTIONAL_FORK;
|
|
53
|
+
const normalizedOutputs = (0, outputs_js_1.normalizeOutputsForAppend)(args.outputsToAppend);
|
|
54
|
+
const outputEventIds = normalizedOutputs.map(() => idFactory.mintEventId());
|
|
55
|
+
const planRes = (0, ack_advance_append_plan_js_1.buildAckAdvanceAppendPlanV1)({
|
|
56
|
+
sessionId: String(sessionId),
|
|
57
|
+
runId: String(runId),
|
|
58
|
+
fromNodeId: String(currentNodeId),
|
|
59
|
+
workflowHash,
|
|
60
|
+
attemptId: String(attemptId),
|
|
61
|
+
nextEventIndex,
|
|
62
|
+
extraEventsToAppend,
|
|
63
|
+
outcome: { kind: 'advanced', toNodeId },
|
|
64
|
+
toNodeKind: args.toNodeKind ?? 'step',
|
|
65
|
+
toNodeId,
|
|
66
|
+
snapshotRef: args.snapshotRef,
|
|
67
|
+
causeKind,
|
|
68
|
+
minted: {
|
|
69
|
+
advanceRecordedEventId: evtAdvanceRecorded,
|
|
70
|
+
nodeCreatedEventId: evtNodeCreated,
|
|
71
|
+
edgeCreatedEventId: evtEdgeCreated,
|
|
72
|
+
outputEventIds,
|
|
73
|
+
},
|
|
74
|
+
outputsToAppend: [...args.outputsToAppend],
|
|
75
|
+
});
|
|
76
|
+
if (planRes.isErr())
|
|
77
|
+
return (0, neverthrow_1.errAsync)({ kind: 'invariant_violation', message: planRes.error.message });
|
|
78
|
+
return sessionStore.append(lock, planRes.value);
|
|
79
|
+
}
|
|
80
|
+
function buildNotesOutputs(allowNotesAppend, attemptId, inputOutput) {
|
|
81
|
+
if (!allowNotesAppend || !inputOutput?.notesMarkdown)
|
|
82
|
+
return [];
|
|
83
|
+
return [{
|
|
84
|
+
outputId: String((0, index_js_1.asOutputId)(`out_recap_${String(attemptId)}`)),
|
|
85
|
+
outputChannel: constants_js_1.OUTPUT_CHANNEL.RECAP,
|
|
86
|
+
payload: {
|
|
87
|
+
payloadKind: 'notes',
|
|
88
|
+
notesMarkdown: (0, notes_markdown_js_1.toNotesMarkdownV1)(inputOutput.notesMarkdown),
|
|
89
|
+
},
|
|
90
|
+
}];
|
|
91
|
+
}
|
|
92
|
+
function buildArtifactOutputs(inputArtifacts, attemptId, sha256) {
|
|
93
|
+
const outputs = [];
|
|
94
|
+
for (let idx = 0; idx < inputArtifacts.length; idx++) {
|
|
95
|
+
const artifact = inputArtifacts[idx];
|
|
96
|
+
const canonicalBytesRes = (0, jcs_js_1.toCanonicalBytes)(artifact);
|
|
97
|
+
if (canonicalBytesRes.isErr()) {
|
|
98
|
+
return (0, neverthrow_1.err)({ kind: 'invariant_violation', message: `Artifact canonicalization failed at index ${idx}: ${canonicalBytesRes.error.message}` });
|
|
99
|
+
}
|
|
100
|
+
const canonicalBytes = canonicalBytesRes.value;
|
|
101
|
+
outputs.push({
|
|
102
|
+
outputId: (0, index_js_1.asOutputId)(`out_artifact_${String(attemptId)}_${idx}`),
|
|
103
|
+
outputChannel: constants_js_1.OUTPUT_CHANNEL.ARTIFACT,
|
|
104
|
+
payload: {
|
|
105
|
+
payloadKind: 'artifact_ref',
|
|
106
|
+
sha256: sha256.sha256(canonicalBytes),
|
|
107
|
+
contentType: 'application/json',
|
|
108
|
+
byteLength: canonicalBytes.length,
|
|
109
|
+
content: artifact,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
return (0, neverthrow_1.ok)(outputs);
|
|
114
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ResultAsync as RA } from 'neverthrow';
|
|
2
|
+
import type { ExecutionSnapshotFileV1, EngineStateV1 } from '../../../v2/durable-core/schemas/execution-snapshot/index.js';
|
|
3
|
+
import type { SessionId, RunId, NodeId, WorkflowHash } from '../../../v2/durable-core/ids/index.js';
|
|
4
|
+
import type { AttemptId } from '../../../v2/durable-core/tokens/index.js';
|
|
5
|
+
import type { LoadedSessionTruthV2 } from '../../../v2/ports/session-event-log-store.port.js';
|
|
6
|
+
import type { SessionEventLogStoreError } from '../../../v2/ports/session-event-log-store.port.js';
|
|
7
|
+
import type { SnapshotStoreError } from '../../../v2/ports/snapshot-store.port.js';
|
|
8
|
+
import type { WithHealthySessionLock } from '../../../v2/durable-core/ids/with-healthy-session-lock.js';
|
|
9
|
+
import type { Sha256PortV2 } from '../../../v2/ports/sha256.port.js';
|
|
10
|
+
import type { JsonValue } from '../../../v2/durable-core/canonical/json-types.js';
|
|
11
|
+
import type { V2ContinueWorkflowInput } from '../../v2/tools.js';
|
|
12
|
+
import type { ValidationResult } from '../../../types/validation.js';
|
|
13
|
+
import { createWorkflow } from '../../../types/workflow.js';
|
|
14
|
+
import { type ReasonV1 } from '../../../v2/durable-core/domain/reason-model.js';
|
|
15
|
+
import { getOutputRequirementStatusWithArtifactsV1 } from '../../../v2/durable-core/domain/validation-criteria-validator.js';
|
|
16
|
+
import type { InternalError } from '../v2-error-mapping.js';
|
|
17
|
+
import { type ValidatedAdvanceInputs } from './input-validation.js';
|
|
18
|
+
export type AdvanceMode = {
|
|
19
|
+
readonly kind: 'fresh';
|
|
20
|
+
readonly sourceNodeId: NodeId;
|
|
21
|
+
readonly snapshot: ExecutionSnapshotFileV1;
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: 'retry';
|
|
24
|
+
readonly blockedNodeId: NodeId;
|
|
25
|
+
readonly blockedSnapshot: ExecutionSnapshotFileV1;
|
|
26
|
+
};
|
|
27
|
+
export interface AdvanceCorePorts {
|
|
28
|
+
readonly snapshotStore: import('../../../v2/ports/snapshot-store.port.js').SnapshotStorePortV2;
|
|
29
|
+
readonly sessionStore: import('../../../v2/ports/session-event-log-store.port.js').SessionEventLogAppendStorePortV2;
|
|
30
|
+
readonly sha256: Sha256PortV2;
|
|
31
|
+
readonly idFactory: {
|
|
32
|
+
readonly mintNodeId: () => NodeId;
|
|
33
|
+
readonly mintEventId: () => string;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export interface AdvanceContext {
|
|
37
|
+
readonly truth: LoadedSessionTruthV2;
|
|
38
|
+
readonly sessionId: SessionId;
|
|
39
|
+
readonly runId: RunId;
|
|
40
|
+
readonly currentNodeId: NodeId;
|
|
41
|
+
readonly attemptId: AttemptId;
|
|
42
|
+
readonly workflowHash: WorkflowHash;
|
|
43
|
+
readonly inputOutput: V2ContinueWorkflowInput['output'];
|
|
44
|
+
readonly pinnedWorkflow: ReturnType<typeof createWorkflow>;
|
|
45
|
+
readonly engineState: EngineStateV1;
|
|
46
|
+
readonly pendingStep: ValidatedAdvanceInputs['pendingStep'];
|
|
47
|
+
}
|
|
48
|
+
export interface ComputedAdvanceResults {
|
|
49
|
+
readonly reasons: readonly ReasonV1[];
|
|
50
|
+
readonly effectiveReasons: readonly ReasonV1[];
|
|
51
|
+
readonly outputRequirement: ReturnType<typeof getOutputRequirementStatusWithArtifactsV1>;
|
|
52
|
+
readonly validation: ValidationResult | undefined;
|
|
53
|
+
}
|
|
54
|
+
export declare function executeAdvanceCore(args: {
|
|
55
|
+
readonly mode: AdvanceMode;
|
|
56
|
+
readonly truth: LoadedSessionTruthV2;
|
|
57
|
+
readonly sessionId: SessionId;
|
|
58
|
+
readonly runId: RunId;
|
|
59
|
+
readonly attemptId: AttemptId;
|
|
60
|
+
readonly workflowHash: WorkflowHash;
|
|
61
|
+
readonly dedupeKey: string;
|
|
62
|
+
readonly inputContext: JsonValue | undefined;
|
|
63
|
+
readonly inputOutput: V2ContinueWorkflowInput['output'];
|
|
64
|
+
readonly lock: WithHealthySessionLock;
|
|
65
|
+
readonly pinnedWorkflow: ReturnType<typeof createWorkflow>;
|
|
66
|
+
readonly ports: AdvanceCorePorts;
|
|
67
|
+
}): RA<void, InternalError | SessionEventLogStoreError | SnapshotStoreError>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.executeAdvanceCore = executeAdvanceCore;
|
|
4
|
+
const neverthrow_1 = require("neverthrow");
|
|
5
|
+
const snapshot_state_js_1 = require("../../../v2/durable-core/projections/snapshot-state.js");
|
|
6
|
+
const reason_model_js_1 = require("../../../v2/durable-core/domain/reason-model.js");
|
|
7
|
+
const risk_policy_guardrails_js_1 = require("../../../v2/durable-core/domain/risk-policy-guardrails.js");
|
|
8
|
+
const blocking_decision_js_1 = require("../../../v2/durable-core/domain/blocking-decision.js");
|
|
9
|
+
const validation_criteria_validator_js_1 = require("../../../v2/durable-core/domain/validation-criteria-validator.js");
|
|
10
|
+
const validation_engine_js_1 = require("../../../application/services/validation-engine.js");
|
|
11
|
+
const enhanced_loop_validator_js_1 = require("../../../application/services/enhanced-loop-validator.js");
|
|
12
|
+
const v2_state_conversion_js_1 = require("../v2-state-conversion.js");
|
|
13
|
+
const v2_execution_helpers_js_1 = require("../v2-execution-helpers.js");
|
|
14
|
+
const with_timeout_js_1 = require("../shared/with-timeout.js");
|
|
15
|
+
const input_validation_js_1 = require("./input-validation.js");
|
|
16
|
+
const outcome_blocked_js_1 = require("./outcome-blocked.js");
|
|
17
|
+
const outcome_success_js_1 = require("./outcome-success.js");
|
|
18
|
+
function nodeIdOf(mode) {
|
|
19
|
+
switch (mode.kind) {
|
|
20
|
+
case 'fresh': return mode.sourceNodeId;
|
|
21
|
+
case 'retry': return mode.blockedNodeId;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function snapshotOf(mode) {
|
|
25
|
+
switch (mode.kind) {
|
|
26
|
+
case 'fresh': return mode.snapshot;
|
|
27
|
+
case 'retry': return mode.blockedSnapshot;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function executeAdvanceCore(args) {
|
|
31
|
+
const { mode, truth, sessionId, runId, attemptId, workflowHash, inputContext, inputOutput, lock, pinnedWorkflow, ports } = args;
|
|
32
|
+
const { snapshotStore, sessionStore, sha256, idFactory } = ports;
|
|
33
|
+
const currentNodeId = nodeIdOf(mode);
|
|
34
|
+
const snap = snapshotOf(mode);
|
|
35
|
+
const engineState = snap.enginePayload.engineState;
|
|
36
|
+
const pendingStep = derivePendingStepForMode(mode, engineState);
|
|
37
|
+
if (!pendingStep) {
|
|
38
|
+
return errAsync({ kind: 'no_pending_step' });
|
|
39
|
+
}
|
|
40
|
+
const validatedRes = (0, input_validation_js_1.validateAdvanceInputs)({
|
|
41
|
+
truth, runId, currentNodeId, inputContext, inputOutput, pinnedWorkflow, pendingStep,
|
|
42
|
+
});
|
|
43
|
+
if (validatedRes.isErr())
|
|
44
|
+
return errAsync(validatedRes.error);
|
|
45
|
+
const v = validatedRes.value;
|
|
46
|
+
const validator = v.validationCriteria ? new validation_engine_js_1.ValidationEngine(new enhanced_loop_validator_js_1.EnhancedLoopValidator()) : null;
|
|
47
|
+
const validationPhase = validator && v.notesMarkdown
|
|
48
|
+
? neverthrow_1.ResultAsync.fromPromise((0, with_timeout_js_1.withTimeout)(validator.validate(v.notesMarkdown, v.validationCriteria, v.mergedContext), 30000, 'ValidationEngine.validate'), (cause) => ({ kind: 'advance_apply_failed', message: String(cause) })).andThen((res) => {
|
|
49
|
+
if (res.isErr()) {
|
|
50
|
+
return (0, neverthrow_1.okAsync)({ kind: 'evaluation_error', message: `${res.error.kind}: ${res.error.message}` });
|
|
51
|
+
}
|
|
52
|
+
return (0, neverthrow_1.okAsync)({ kind: 'completed', validation: res.value });
|
|
53
|
+
}).orElse((e) => {
|
|
54
|
+
if (e.kind === 'advance_apply_failed') {
|
|
55
|
+
return (0, neverthrow_1.okAsync)({ kind: 'evaluation_error', message: e.message });
|
|
56
|
+
}
|
|
57
|
+
return (0, neverthrow_1.errAsync)(e);
|
|
58
|
+
})
|
|
59
|
+
: (0, neverthrow_1.okAsync)({ kind: 'completed', validation: undefined });
|
|
60
|
+
return validationPhase.andThen((phase) => {
|
|
61
|
+
if (phase.kind === 'evaluation_error') {
|
|
62
|
+
const evalReason = { kind: 'evaluation_error' };
|
|
63
|
+
const reasons = [evalReason];
|
|
64
|
+
const effectiveReasons = [evalReason];
|
|
65
|
+
const outputRequirement = { kind: 'not_required' };
|
|
66
|
+
const evalValidation = {
|
|
67
|
+
valid: false,
|
|
68
|
+
issues: ['WorkRail could not evaluate the validation criteria for this step. This is not caused by your output.'],
|
|
69
|
+
suggestions: [(0, v2_execution_helpers_js_1.internalSuggestion)('Retry your submission with the same output.', 'The validation criteria for this step may be misconfigured.')],
|
|
70
|
+
};
|
|
71
|
+
const ctx = { truth, sessionId, runId, currentNodeId, attemptId, workflowHash, inputOutput, pinnedWorkflow, engineState, pendingStep };
|
|
72
|
+
const computed = { reasons, effectiveReasons, outputRequirement, validation: evalValidation };
|
|
73
|
+
const portsLocal = { snapshotStore, sessionStore, sha256, idFactory };
|
|
74
|
+
return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, lock, ports: portsLocal });
|
|
75
|
+
}
|
|
76
|
+
const validation = phase.validation;
|
|
77
|
+
const outputRequirement = (0, validation_criteria_validator_js_1.getOutputRequirementStatusWithArtifactsV1)({
|
|
78
|
+
outputContract: v.outputContract,
|
|
79
|
+
artifacts: v.artifacts,
|
|
80
|
+
validationCriteria: v.validationCriteria,
|
|
81
|
+
notesMarkdown: v.notesMarkdown,
|
|
82
|
+
validation,
|
|
83
|
+
});
|
|
84
|
+
const reasonsRes = (0, blocking_decision_js_1.detectBlockingReasonsV1)({ outputRequirement });
|
|
85
|
+
if (reasonsRes.isErr()) {
|
|
86
|
+
return errAsync({ kind: 'invariant_violation', message: reasonsRes.error.message });
|
|
87
|
+
}
|
|
88
|
+
const reasons = reasonsRes.value;
|
|
89
|
+
const { blocking: effectiveReasons } = (0, risk_policy_guardrails_js_1.applyGuardrails)(v.riskPolicy, reasons);
|
|
90
|
+
const shouldBlockNow = effectiveReasons.length > 0 && (0, reason_model_js_1.shouldBlock)(v.autonomy, effectiveReasons);
|
|
91
|
+
const ctx = { truth, sessionId, runId, currentNodeId, attemptId, workflowHash, inputOutput, pinnedWorkflow, engineState, pendingStep };
|
|
92
|
+
const computed = { reasons, effectiveReasons, outputRequirement, validation };
|
|
93
|
+
const ports = { snapshotStore, sessionStore, sha256, idFactory };
|
|
94
|
+
if (shouldBlockNow) {
|
|
95
|
+
return (0, outcome_blocked_js_1.buildBlockedOutcome)({ mode, snap, ctx, computed, lock, ports });
|
|
96
|
+
}
|
|
97
|
+
return (0, outcome_success_js_1.buildSuccessOutcome)({ mode, ctx, computed, v, lock, ports });
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function derivePendingStepForMode(mode, engineState) {
|
|
101
|
+
switch (mode.kind) {
|
|
102
|
+
case 'fresh': {
|
|
103
|
+
const currentState = (0, v2_state_conversion_js_1.toV1ExecutionState)(engineState);
|
|
104
|
+
return (currentState.kind === 'running' && currentState.pendingStep) ? currentState.pendingStep : null;
|
|
105
|
+
}
|
|
106
|
+
case 'retry': {
|
|
107
|
+
if (engineState.kind !== 'blocked')
|
|
108
|
+
return null;
|
|
109
|
+
const pending = (0, snapshot_state_js_1.derivePendingStep)(engineState);
|
|
110
|
+
return pending ? {
|
|
111
|
+
stepId: String(pending.stepId),
|
|
112
|
+
loopPath: pending.loopPath.map(f => ({ loopId: String(f.loopId), iteration: f.iteration })),
|
|
113
|
+
} : null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function errAsync(e) {
|
|
118
|
+
return (0, neverthrow_1.errAsync)(e);
|
|
119
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type Result } from 'neverthrow';
|
|
2
|
+
import type { RunId, NodeId } from '../../../v2/durable-core/ids/index.js';
|
|
3
|
+
import type { LoadedSessionTruthV2 } from '../../../v2/ports/session-event-log-store.port.js';
|
|
4
|
+
import type { JsonValue, JsonObject } from '../../../v2/durable-core/canonical/json-types.js';
|
|
5
|
+
import type { V2ContinueWorkflowInput } from '../../v2/tools.js';
|
|
6
|
+
import type { OutputContract } from '../../../types/workflow-definition.js';
|
|
7
|
+
import type { ValidationCriteria } from '../../../types/validation.js';
|
|
8
|
+
import type { InternalError } from '../v2-error-mapping.js';
|
|
9
|
+
export interface ValidatedAdvanceInputs {
|
|
10
|
+
readonly pendingStep: {
|
|
11
|
+
readonly stepId: string;
|
|
12
|
+
readonly loopPath: readonly {
|
|
13
|
+
readonly loopId: string;
|
|
14
|
+
readonly iteration: number;
|
|
15
|
+
}[];
|
|
16
|
+
};
|
|
17
|
+
readonly mergedContext: Record<string, unknown>;
|
|
18
|
+
readonly inputContextObj: JsonObject | undefined;
|
|
19
|
+
readonly validationCriteria: ValidationCriteria | undefined;
|
|
20
|
+
readonly outputContract: OutputContract | undefined;
|
|
21
|
+
readonly notesMarkdown: string | undefined;
|
|
22
|
+
readonly artifacts: readonly unknown[];
|
|
23
|
+
readonly autonomy: 'guided' | 'full_auto_stop_on_user_deps' | 'full_auto_never_stop';
|
|
24
|
+
readonly riskPolicy: 'conservative' | 'balanced' | 'aggressive';
|
|
25
|
+
readonly effectivePrefs: {
|
|
26
|
+
readonly autonomy: string;
|
|
27
|
+
readonly riskPolicy: string;
|
|
28
|
+
} | undefined;
|
|
29
|
+
}
|
|
30
|
+
export declare function validateAdvanceInputs(args: {
|
|
31
|
+
readonly truth: LoadedSessionTruthV2;
|
|
32
|
+
readonly runId: RunId;
|
|
33
|
+
readonly currentNodeId: NodeId;
|
|
34
|
+
readonly inputContext: JsonValue | undefined;
|
|
35
|
+
readonly inputOutput: V2ContinueWorkflowInput['output'];
|
|
36
|
+
readonly pinnedWorkflow: ReturnType<typeof import('../../../types/workflow.js').createWorkflow>;
|
|
37
|
+
readonly pendingStep: {
|
|
38
|
+
readonly stepId: string;
|
|
39
|
+
readonly loopPath: readonly {
|
|
40
|
+
readonly loopId: string;
|
|
41
|
+
readonly iteration: number;
|
|
42
|
+
}[];
|
|
43
|
+
};
|
|
44
|
+
}): Result<ValidatedAdvanceInputs, InternalError>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateAdvanceInputs = validateAdvanceInputs;
|
|
4
|
+
const neverthrow_1 = require("neverthrow");
|
|
5
|
+
const workflow_js_1 = require("../../../types/workflow.js");
|
|
6
|
+
const run_context_js_1 = require("../../../v2/projections/run-context.js");
|
|
7
|
+
const preferences_js_1 = require("../../../v2/projections/preferences.js");
|
|
8
|
+
const context_merge_js_1 = require("../../../v2/durable-core/domain/context-merge.js");
|
|
9
|
+
const constants_js_1 = require("../../../v2/durable-core/constants.js");
|
|
10
|
+
function validateAdvanceInputs(args) {
|
|
11
|
+
const { truth, runId, currentNodeId, inputContext, inputOutput, pinnedWorkflow, pendingStep } = args;
|
|
12
|
+
const storedContextRes = (0, run_context_js_1.projectRunContextV2)(truth.events);
|
|
13
|
+
const storedContext = storedContextRes.isOk() ? storedContextRes.value.byRunId[String(runId)]?.context : undefined;
|
|
14
|
+
const inputContextObj = inputContext && typeof inputContext === 'object' && inputContext !== null && !Array.isArray(inputContext)
|
|
15
|
+
? inputContext
|
|
16
|
+
: undefined;
|
|
17
|
+
const mergedContextRes = (0, context_merge_js_1.mergeContext)(storedContext, inputContextObj);
|
|
18
|
+
if (mergedContextRes.isErr()) {
|
|
19
|
+
return (0, neverthrow_1.err)({ kind: 'invariant_violation', message: `Context merge failed: ${mergedContextRes.error.message}` });
|
|
20
|
+
}
|
|
21
|
+
const step = (0, workflow_js_1.getStepById)(pinnedWorkflow, pendingStep.stepId);
|
|
22
|
+
const validationCriteria = step?.validationCriteria;
|
|
23
|
+
const outputContract = step?.outputContract;
|
|
24
|
+
const parentByNodeId = {};
|
|
25
|
+
for (const e of truth.events) {
|
|
26
|
+
if (e.kind !== constants_js_1.EVENT_KIND.NODE_CREATED)
|
|
27
|
+
continue;
|
|
28
|
+
if (e.scope?.runId !== String(runId))
|
|
29
|
+
continue;
|
|
30
|
+
parentByNodeId[String(e.scope.nodeId)] = e.data.parentNodeId;
|
|
31
|
+
}
|
|
32
|
+
const prefs = (0, preferences_js_1.projectPreferencesV2)(truth.events, parentByNodeId);
|
|
33
|
+
const effectivePrefs = prefs.isOk() ? prefs.value.byNodeId[String(currentNodeId)]?.effective : undefined;
|
|
34
|
+
const rawAutonomy = effectivePrefs?.autonomy ?? 'guided';
|
|
35
|
+
const rawRiskPolicy = effectivePrefs?.riskPolicy ?? 'conservative';
|
|
36
|
+
const VALID_AUTONOMY = ['guided', 'full_auto_stop_on_user_deps', 'full_auto_never_stop'];
|
|
37
|
+
const VALID_RISK_POLICY = ['conservative', 'balanced', 'aggressive'];
|
|
38
|
+
if (!VALID_AUTONOMY.includes(rawAutonomy)) {
|
|
39
|
+
return (0, neverthrow_1.err)({ kind: 'invariant_violation', message: `Unknown autonomy mode: ${rawAutonomy}` });
|
|
40
|
+
}
|
|
41
|
+
if (!VALID_RISK_POLICY.includes(rawRiskPolicy)) {
|
|
42
|
+
return (0, neverthrow_1.err)({ kind: 'invariant_violation', message: `Unknown risk policy: ${rawRiskPolicy}` });
|
|
43
|
+
}
|
|
44
|
+
const autonomy = rawAutonomy;
|
|
45
|
+
const riskPolicy = rawRiskPolicy;
|
|
46
|
+
return (0, neverthrow_1.ok)({
|
|
47
|
+
pendingStep,
|
|
48
|
+
mergedContext: mergedContextRes.value,
|
|
49
|
+
inputContextObj,
|
|
50
|
+
validationCriteria,
|
|
51
|
+
outputContract,
|
|
52
|
+
notesMarkdown: inputOutput?.notesMarkdown,
|
|
53
|
+
artifacts: inputOutput?.artifacts ?? [],
|
|
54
|
+
autonomy,
|
|
55
|
+
riskPolicy,
|
|
56
|
+
effectivePrefs,
|
|
57
|
+
});
|
|
58
|
+
}
|