@exaudeus/workrail 3.15.0 → 3.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/application/services/workflow-service.d.ts +2 -0
- package/dist/application/services/workflow-service.js +3 -0
- package/dist/console/assets/index-BE5PAgPO.js +28 -0
- package/dist/console/assets/index-BZNM03t1.css +1 -0
- package/dist/console/index.html +2 -2
- package/dist/env-flags.d.ts +1 -0
- package/dist/env-flags.js +4 -0
- package/dist/infrastructure/session/HttpServer.d.ts +3 -3
- package/dist/infrastructure/session/HttpServer.js +68 -74
- package/dist/infrastructure/storage/caching-workflow-storage.d.ts +2 -0
- package/dist/infrastructure/storage/caching-workflow-storage.js +15 -6
- package/dist/infrastructure/storage/file-workflow-storage.js +3 -4
- package/dist/infrastructure/storage/schema-validating-workflow-storage.js +9 -8
- package/dist/manifest.json +257 -193
- package/dist/mcp/assert-output.d.ts +37 -0
- package/dist/mcp/assert-output.js +52 -0
- package/dist/mcp/boundary-coercion.d.ts +1 -0
- package/dist/mcp/boundary-coercion.js +44 -0
- package/dist/mcp/dev-mode.d.ts +1 -0
- package/dist/mcp/dev-mode.js +4 -0
- package/dist/mcp/handler-factory.js +12 -9
- package/dist/mcp/handlers/session.js +8 -9
- package/dist/mcp/handlers/v2-advance-core/event-builders.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/event-builders.js +6 -6
- package/dist/mcp/handlers/v2-advance-core/index.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/index.js +4 -3
- package/dist/mcp/handlers/v2-advance-core/input-validation.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/input-validation.js +32 -9
- package/dist/mcp/handlers/v2-advance-core/outcome-blocked.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-blocked.js +1 -1
- package/dist/mcp/handlers/v2-advance-core/outcome-success.d.ts +2 -0
- package/dist/mcp/handlers/v2-advance-core/outcome-success.js +1 -1
- package/dist/mcp/handlers/v2-checkpoint.d.ts +1 -1
- package/dist/mcp/handlers/v2-checkpoint.js +5 -6
- package/dist/mcp/handlers/v2-execution/advance.d.ts +4 -2
- package/dist/mcp/handlers/v2-execution/advance.js +5 -7
- package/dist/mcp/handlers/v2-execution/continue-advance.js +56 -26
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.d.ts +1 -1
- package/dist/mcp/handlers/v2-execution/continue-rehydrate.js +9 -9
- package/dist/mcp/handlers/v2-execution/replay.d.ts +6 -4
- package/dist/mcp/handlers/v2-execution/replay.js +47 -30
- package/dist/mcp/handlers/v2-execution/start.d.ts +2 -3
- package/dist/mcp/handlers/v2-execution/start.js +11 -11
- package/dist/mcp/handlers/v2-execution/workflow-object-cache.d.ts +5 -0
- package/dist/mcp/handlers/v2-execution/workflow-object-cache.js +19 -0
- package/dist/mcp/handlers/v2-execution-helpers.d.ts +1 -0
- package/dist/mcp/handlers/v2-execution-helpers.js +23 -7
- package/dist/mcp/handlers/v2-resume.d.ts +1 -1
- package/dist/mcp/handlers/v2-resume.js +3 -4
- package/dist/mcp/handlers/v2-state-conversion.js +5 -1
- package/dist/mcp/handlers/v2-workflow.d.ts +80 -0
- package/dist/mcp/handlers/v2-workflow.js +36 -21
- package/dist/mcp/handlers/workflow.d.ts +2 -5
- package/dist/mcp/handlers/workflow.js +15 -12
- package/dist/mcp/output-schemas.d.ts +20 -27
- package/dist/mcp/output-schemas.js +5 -7
- package/dist/mcp/server.js +22 -4
- package/dist/mcp/tool-call-timing.d.ts +24 -0
- package/dist/mcp/tool-call-timing.js +85 -0
- package/dist/mcp/transports/http-entry.js +3 -2
- package/dist/mcp/transports/http-listener.d.ts +1 -0
- package/dist/mcp/transports/http-listener.js +25 -0
- package/dist/mcp/transports/shutdown-hooks.d.ts +4 -1
- package/dist/mcp/transports/shutdown-hooks.js +3 -2
- package/dist/mcp/transports/stdio-entry.js +6 -28
- package/dist/mcp/v2-response-formatter.js +2 -4
- package/dist/mcp/validation/schema-introspection.d.ts +1 -0
- package/dist/mcp/validation/schema-introspection.js +15 -5
- package/dist/mcp/validation/suggestion-generator.js +2 -2
- package/dist/runtime/adapters/node-process-signals.d.ts +1 -0
- package/dist/runtime/adapters/node-process-signals.js +5 -0
- package/dist/runtime/adapters/noop-process-signals.d.ts +1 -0
- package/dist/runtime/adapters/noop-process-signals.js +2 -0
- package/dist/runtime/ports/process-signals.d.ts +1 -0
- package/dist/types/workflow-definition.d.ts +2 -0
- package/dist/types/workflow.d.ts +3 -0
- package/dist/types/workflow.js +35 -26
- package/dist/v2/durable-core/domain/context-template-resolver.js +2 -2
- package/dist/v2/durable-core/domain/function-definition-expander.js +2 -17
- package/dist/v2/durable-core/domain/prompt-renderer.d.ts +1 -0
- package/dist/v2/durable-core/domain/prompt-renderer.js +23 -18
- package/dist/v2/durable-core/domain/recap-recovery.js +23 -16
- package/dist/v2/durable-core/domain/retrieval-contract.js +13 -7
- package/dist/v2/durable-core/session-index.d.ts +22 -0
- package/dist/v2/durable-core/session-index.js +58 -0
- package/dist/v2/durable-core/sorted-event-log.d.ts +6 -0
- package/dist/v2/durable-core/sorted-event-log.js +15 -0
- package/dist/v2/infra/local/fs/index.js +8 -8
- package/dist/v2/infra/local/session-store/index.d.ts +1 -1
- package/dist/v2/infra/local/session-store/index.js +71 -61
- package/dist/v2/infra/local/session-summary-provider/index.js +9 -4
- package/dist/v2/infra/local/snapshot-store/index.js +2 -1
- package/dist/v2/ports/session-event-log-store.port.d.ts +1 -1
- package/dist/v2/projections/assessment-consequences.d.ts +2 -1
- package/dist/v2/projections/assessment-consequences.js +0 -5
- package/dist/v2/projections/assessments.d.ts +2 -1
- package/dist/v2/projections/assessments.js +2 -4
- package/dist/v2/projections/gaps.d.ts +2 -1
- package/dist/v2/projections/gaps.js +0 -5
- package/dist/v2/projections/preferences.d.ts +2 -1
- package/dist/v2/projections/preferences.js +0 -5
- package/dist/v2/projections/run-context.d.ts +2 -2
- package/dist/v2/projections/run-context.js +0 -5
- package/dist/v2/projections/run-dag.js +7 -1
- package/dist/v2/projections/run-execution-trace.d.ts +8 -0
- package/dist/v2/projections/run-execution-trace.js +124 -0
- package/dist/v2/projections/run-status-signals.d.ts +2 -2
- package/dist/v2/usecases/console-routes.d.ts +3 -1
- package/dist/v2/usecases/console-routes.js +123 -25
- package/dist/v2/usecases/console-service.d.ts +1 -0
- package/dist/v2/usecases/console-service.js +83 -25
- package/dist/v2/usecases/console-types.d.ts +53 -0
- package/dist/v2/usecases/worktree-service.js +32 -1
- package/package.json +6 -5
- package/spec/workflow.schema.json +18 -0
- package/workflows/adaptive-ticket-creation.json +23 -16
- package/workflows/architecture-scalability-audit.json +29 -22
- package/workflows/bug-investigation.agentic.v2.json +7 -0
- package/workflows/coding-task-workflow-agentic.json +7 -0
- package/workflows/coding-task-workflow-agentic.lean.v2.json +16 -8
- package/workflows/coding-task-workflow-agentic.v2.json +7 -0
- package/workflows/cross-platform-code-conversion.v2.json +7 -0
- package/workflows/document-creation-workflow.json +15 -8
- package/workflows/documentation-update-workflow.json +15 -8
- package/workflows/intelligent-test-case-generation.json +7 -0
- package/workflows/learner-centered-course-workflow.json +9 -2
- package/workflows/mr-review-workflow.agentic.v2.json +7 -0
- package/workflows/personal-learning-materials-creation-branched.json +15 -8
- package/workflows/presentation-creation.json +12 -5
- package/workflows/production-readiness-audit.json +7 -0
- package/workflows/relocation-workflow-us.json +39 -32
- package/workflows/scoped-documentation-workflow.json +33 -26
- package/workflows/ui-ux-design-workflow.json +7 -0
- package/workflows/workflow-diagnose-environment.json +6 -0
- package/workflows/workflow-for-workflows.json +7 -0
- package/workflows/workflow-for-workflows.v2.json +23 -11
- package/workflows/wr.discovery.json +8 -1
- package/dist/console/assets/index-BZYIjrzJ.js +0 -28
- package/dist/console/assets/index-OLCKbDdm.css +0 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DEFAULT_RING_BUFFER_CAPACITY = exports.ToolCallTimingRingBuffer = exports.noopToolCallTimingSink = void 0;
|
|
4
|
+
exports.createRingBufferSink = createRingBufferSink;
|
|
5
|
+
exports.createDevPerfSink = createDevPerfSink;
|
|
6
|
+
exports.composeSinks = composeSinks;
|
|
7
|
+
exports.withToolCallTiming = withToolCallTiming;
|
|
8
|
+
const noopToolCallTimingSink = () => { };
|
|
9
|
+
exports.noopToolCallTimingSink = noopToolCallTimingSink;
|
|
10
|
+
class ToolCallTimingRingBuffer {
|
|
11
|
+
constructor(capacity) {
|
|
12
|
+
this.capacity = capacity;
|
|
13
|
+
this.head = 0;
|
|
14
|
+
this.count = 0;
|
|
15
|
+
if (capacity < 1)
|
|
16
|
+
throw new Error('Ring buffer capacity must be >= 1');
|
|
17
|
+
this.buffer = new Array(capacity).fill(undefined);
|
|
18
|
+
}
|
|
19
|
+
push(timing) {
|
|
20
|
+
this.buffer[this.head] = timing;
|
|
21
|
+
this.head = (this.head + 1) % this.capacity;
|
|
22
|
+
if (this.count < this.capacity)
|
|
23
|
+
this.count++;
|
|
24
|
+
}
|
|
25
|
+
recent(limit) {
|
|
26
|
+
const n = limit !== undefined ? Math.min(limit, this.count) : this.count;
|
|
27
|
+
const results = [];
|
|
28
|
+
for (let i = 1; i <= n; i++) {
|
|
29
|
+
const idx = (this.head - i + this.capacity) % this.capacity;
|
|
30
|
+
const entry = this.buffer[idx];
|
|
31
|
+
if (entry !== undefined)
|
|
32
|
+
results.push(entry);
|
|
33
|
+
}
|
|
34
|
+
return results;
|
|
35
|
+
}
|
|
36
|
+
get size() {
|
|
37
|
+
return this.count;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
exports.ToolCallTimingRingBuffer = ToolCallTimingRingBuffer;
|
|
41
|
+
exports.DEFAULT_RING_BUFFER_CAPACITY = 100;
|
|
42
|
+
function createRingBufferSink(buffer) {
|
|
43
|
+
return (timing) => {
|
|
44
|
+
buffer.push(timing);
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function createDevPerfSink() {
|
|
48
|
+
return (timing) => {
|
|
49
|
+
const outcomeLabel = timing.outcome === 'success' ? 'OK' : timing.outcome.toUpperCase();
|
|
50
|
+
const line = `[PerfTrace] ${timing.toolName} ${timing.durationMs.toFixed(1)}ms [${outcomeLabel}]`;
|
|
51
|
+
console.error(line);
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function composeSinks(...sinks) {
|
|
55
|
+
return (timing) => {
|
|
56
|
+
for (const sink of sinks) {
|
|
57
|
+
try {
|
|
58
|
+
sink(timing);
|
|
59
|
+
}
|
|
60
|
+
catch { }
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async function withToolCallTiming(toolName, handler, sink) {
|
|
65
|
+
const startedAtMs = Date.now();
|
|
66
|
+
const startHr = performance.now();
|
|
67
|
+
let outcome = 'error';
|
|
68
|
+
try {
|
|
69
|
+
const result = await handler();
|
|
70
|
+
outcome = result?.isError === true ? 'error' : 'success';
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
outcome = 'error';
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
const durationMs = Math.round((performance.now() - startHr) * 100) / 100;
|
|
79
|
+
try {
|
|
80
|
+
sink({ toolName, startedAtMs, durationMs, outcome });
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -42,9 +42,11 @@ const http_listener_js_1 = require("./http-listener.js");
|
|
|
42
42
|
const shutdown_hooks_js_1 = require("./shutdown-hooks.js");
|
|
43
43
|
const crypto = __importStar(require("crypto"));
|
|
44
44
|
const express_1 = __importDefault(require("express"));
|
|
45
|
+
const HTTP_PORT_SCAN_END = 3199;
|
|
45
46
|
async function startHttpServer(port) {
|
|
46
47
|
const { server, ctx } = await (0, server_js_1.composeServer)();
|
|
47
|
-
const
|
|
48
|
+
const scanEnd = Math.max(port, HTTP_PORT_SCAN_END);
|
|
49
|
+
const listener = await (0, http_listener_js_1.bindWithPortFallback)(port, scanEnd);
|
|
48
50
|
const { StreamableHTTPServerTransport } = await Promise.resolve().then(() => __importStar(require('@modelcontextprotocol/sdk/server/streamableHttp.js')));
|
|
49
51
|
const transport = new StreamableHTTPServerTransport({
|
|
50
52
|
sessionIdGenerator: () => crypto.randomUUID(),
|
|
@@ -54,7 +56,6 @@ async function startHttpServer(port) {
|
|
|
54
56
|
listener.app.post('/mcp', (req, res) => transport.handleRequest(req, res, req.body));
|
|
55
57
|
listener.app.get('/mcp', (req, res) => transport.handleRequest(req, res));
|
|
56
58
|
listener.app.delete('/mcp', (req, res) => transport.handleRequest(req, res));
|
|
57
|
-
await listener.start();
|
|
58
59
|
await server.connect(transport);
|
|
59
60
|
const boundPort = listener.getBoundPort();
|
|
60
61
|
console.error('[Transport] WorkRail MCP Server running on HTTP');
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.createHttpListener = createHttpListener;
|
|
7
|
+
exports.bindWithPortFallback = bindWithPortFallback;
|
|
7
8
|
const express_1 = __importDefault(require("express"));
|
|
8
9
|
const http_1 = require("http");
|
|
9
10
|
function createHttpListener(requestedPort) {
|
|
@@ -62,3 +63,27 @@ function createHttpListener(requestedPort) {
|
|
|
62
63
|
},
|
|
63
64
|
};
|
|
64
65
|
}
|
|
66
|
+
async function bindWithPortFallback(startPort, endPort) {
|
|
67
|
+
let lastError;
|
|
68
|
+
for (let port = startPort; port <= endPort; port++) {
|
|
69
|
+
const listener = createHttpListener(port);
|
|
70
|
+
try {
|
|
71
|
+
await listener.start();
|
|
72
|
+
if (port !== startPort) {
|
|
73
|
+
console.error(`[HttpListener] Port ${startPort} unavailable; bound to fallback port ${port}`);
|
|
74
|
+
}
|
|
75
|
+
return listener;
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const nodeErr = err;
|
|
79
|
+
if (nodeErr.code === 'EADDRINUSE' ||
|
|
80
|
+
(err instanceof Error && err.message.includes('already in use'))) {
|
|
81
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
throw err;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
throw new Error(`[HttpListener] No available port in range ${startPort}-${endPort}. ` +
|
|
88
|
+
`Last error: ${lastError?.message}`);
|
|
89
|
+
}
|
|
@@ -2,4 +2,7 @@ export interface ShutdownHookOptions {
|
|
|
2
2
|
readonly onBeforeTerminate: () => Promise<void>;
|
|
3
3
|
}
|
|
4
4
|
export declare function wireShutdownHooks(opts: ShutdownHookOptions): void;
|
|
5
|
-
export
|
|
5
|
+
export interface StdinShutdownOptions {
|
|
6
|
+
readonly stdin?: NodeJS.ReadableStream;
|
|
7
|
+
}
|
|
8
|
+
export declare function wireStdinShutdown(opts?: StdinShutdownOptions): void;
|
|
@@ -29,9 +29,10 @@ function wireShutdownHooks(opts) {
|
|
|
29
29
|
})();
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
|
-
function wireStdinShutdown() {
|
|
32
|
+
function wireStdinShutdown(opts) {
|
|
33
33
|
const shutdownEvents = container_js_1.container.resolve(tokens_js_1.DI.Runtime.ShutdownEvents);
|
|
34
|
-
|
|
34
|
+
const stdin = opts?.stdin ?? process.stdin;
|
|
35
|
+
stdin.once('end', () => {
|
|
35
36
|
console.error('[MCP] stdin closed, initiating shutdown');
|
|
36
37
|
shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGHUP' });
|
|
37
38
|
});
|
|
@@ -35,8 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.startStdioServer = startStdioServer;
|
|
37
37
|
const server_js_1 = require("../server.js");
|
|
38
|
-
const
|
|
39
|
-
const tokens_js_1 = require("../../di/tokens.js");
|
|
38
|
+
const shutdown_hooks_js_1 = require("./shutdown-hooks.js");
|
|
40
39
|
const INITIAL_ROOTS_TIMEOUT_MS = 1000;
|
|
41
40
|
async function fetchInitialRootsWithTimeout(server) {
|
|
42
41
|
return Promise.race([
|
|
@@ -75,31 +74,10 @@ async function startStdioServer() {
|
|
|
75
74
|
.catch(() => {
|
|
76
75
|
console.error('[Roots] Client does not support roots/list; workspace context will use server CWD fallback');
|
|
77
76
|
});
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
processSignals.on('SIGHUP', () => shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGHUP' }));
|
|
84
|
-
process.stdin.on('end', () => {
|
|
85
|
-
console.error('[MCP] stdin closed, initiating shutdown');
|
|
86
|
-
shutdownEvents.emit({ kind: 'shutdown_requested', signal: 'SIGHUP' });
|
|
87
|
-
});
|
|
88
|
-
let shutdownStarted = false;
|
|
89
|
-
shutdownEvents.onShutdown((event) => {
|
|
90
|
-
if (shutdownStarted)
|
|
91
|
-
return;
|
|
92
|
-
shutdownStarted = true;
|
|
93
|
-
void (async () => {
|
|
94
|
-
try {
|
|
95
|
-
console.error(`[Shutdown] Requested by ${event.signal}. Stopping services...`);
|
|
96
|
-
await ctx.httpServer?.stop();
|
|
97
|
-
terminator.terminate({ kind: 'success' });
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
console.error('[Shutdown] Error while stopping services:', err);
|
|
101
|
-
terminator.terminate({ kind: 'failure' });
|
|
102
|
-
}
|
|
103
|
-
})();
|
|
77
|
+
(0, shutdown_hooks_js_1.wireStdinShutdown)();
|
|
78
|
+
(0, shutdown_hooks_js_1.wireShutdownHooks)({
|
|
79
|
+
onBeforeTerminate: async () => {
|
|
80
|
+
await ctx.httpServer?.stop();
|
|
81
|
+
},
|
|
104
82
|
});
|
|
105
83
|
}
|
|
@@ -4,6 +4,7 @@ exports.formatV2ExecutionResponse = formatV2ExecutionResponse;
|
|
|
4
4
|
exports.formatV2ResumeResponse = formatV2ResumeResponse;
|
|
5
5
|
const render_envelope_js_1 = require("./render-envelope.js");
|
|
6
6
|
const response_supplements_js_1 = require("./response-supplements.js");
|
|
7
|
+
const env_flags_js_1 = require("../env-flags.js");
|
|
7
8
|
function isV2ExecutionResponse(data) {
|
|
8
9
|
if (typeof data !== 'object' || data === null)
|
|
9
10
|
return false;
|
|
@@ -216,9 +217,6 @@ function formatSuccess(data) {
|
|
|
216
217
|
}
|
|
217
218
|
return lines.join('\n');
|
|
218
219
|
}
|
|
219
|
-
function isCleanResponseFormat() {
|
|
220
|
-
return process.env.WORKRAIL_CLEAN_RESPONSE_FORMAT === 'true';
|
|
221
|
-
}
|
|
222
220
|
const CLEAN_ADVANCE_FOOTERS = [
|
|
223
221
|
'WorkRail: when done, call continue_workflow with your notes. Token:',
|
|
224
222
|
'WorkRail: advance with continue_workflow when ready. Include your notes. Token:',
|
|
@@ -354,7 +352,7 @@ function formatV2ExecutionResponse(data) {
|
|
|
354
352
|
const renderInput = deriveRenderInput(data);
|
|
355
353
|
if (!renderInput)
|
|
356
354
|
return null;
|
|
357
|
-
const cleanFormat =
|
|
355
|
+
const cleanFormat = env_flags_js_1.CLEAN_RESPONSE_FORMAT;
|
|
358
356
|
const { response, lifecycle, contentEnvelope } = renderInput;
|
|
359
357
|
const references = renderReferencesSection(contentEnvelope, lifecycle);
|
|
360
358
|
if (cleanFormat) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
export declare function getCachedShape(schema: z.ZodObject<z.ZodRawShape>): z.ZodRawShape;
|
|
2
3
|
export declare function extractExpectedKeys(schema: z.ZodType): readonly string[];
|
|
3
4
|
export declare function extractRequiredKeys(schema: z.ZodType): readonly string[];
|
|
4
5
|
export declare function findUnknownKeys(args: unknown, schema: z.ZodType): readonly string[];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getCachedShape = getCachedShape;
|
|
3
4
|
exports.extractExpectedKeys = extractExpectedKeys;
|
|
4
5
|
exports.extractRequiredKeys = extractRequiredKeys;
|
|
5
6
|
exports.findUnknownKeys = findUnknownKeys;
|
|
@@ -8,9 +9,18 @@ exports.generateExampleValue = generateExampleValue;
|
|
|
8
9
|
exports.generateTemplate = generateTemplate;
|
|
9
10
|
exports.extractEnumValues = extractEnumValues;
|
|
10
11
|
const zod_1 = require("zod");
|
|
12
|
+
const shapeCache = new WeakMap();
|
|
13
|
+
function getCachedShape(schema) {
|
|
14
|
+
const cached = shapeCache.get(schema);
|
|
15
|
+
if (cached !== undefined)
|
|
16
|
+
return cached;
|
|
17
|
+
const shape = schema._def.shape();
|
|
18
|
+
shapeCache.set(schema, shape);
|
|
19
|
+
return shape;
|
|
20
|
+
}
|
|
11
21
|
function extractExpectedKeys(schema) {
|
|
12
22
|
if (schema instanceof zod_1.z.ZodObject) {
|
|
13
|
-
return Object.keys(schema
|
|
23
|
+
return Object.keys(getCachedShape(schema));
|
|
14
24
|
}
|
|
15
25
|
return [];
|
|
16
26
|
}
|
|
@@ -18,7 +28,7 @@ function extractRequiredKeys(schema) {
|
|
|
18
28
|
if (!(schema instanceof zod_1.z.ZodObject)) {
|
|
19
29
|
return [];
|
|
20
30
|
}
|
|
21
|
-
const shape = schema
|
|
31
|
+
const shape = getCachedShape(schema);
|
|
22
32
|
const required = [];
|
|
23
33
|
for (const [key, value] of Object.entries(shape)) {
|
|
24
34
|
const field = value;
|
|
@@ -55,7 +65,7 @@ function generateExampleValue(schema, depth = 0, maxDepth = 3, includeOptional =
|
|
|
55
65
|
return generateExampleValue(schema._def.innerType, depth, maxDepth, includeOptional);
|
|
56
66
|
}
|
|
57
67
|
if (schema instanceof zod_1.z.ZodObject) {
|
|
58
|
-
const shape = schema
|
|
68
|
+
const shape = getCachedShape(schema);
|
|
59
69
|
const result = {};
|
|
60
70
|
for (const [key, value] of Object.entries(shape)) {
|
|
61
71
|
const field = value;
|
|
@@ -124,7 +134,7 @@ function extractEnumValues(schema, path) {
|
|
|
124
134
|
let current = schema;
|
|
125
135
|
for (const part of parts) {
|
|
126
136
|
if (current instanceof zod_1.z.ZodObject) {
|
|
127
|
-
const shape = current
|
|
137
|
+
const shape = getCachedShape(current);
|
|
128
138
|
const field = shape[part];
|
|
129
139
|
if (!field)
|
|
130
140
|
return [];
|
|
@@ -133,7 +143,7 @@ function extractEnumValues(schema, path) {
|
|
|
133
143
|
else if (current instanceof zod_1.z.ZodOptional) {
|
|
134
144
|
current = current._def.innerType;
|
|
135
145
|
if (current instanceof zod_1.z.ZodObject) {
|
|
136
|
-
const shape = current
|
|
146
|
+
const shape = getCachedShape(current);
|
|
137
147
|
const field = shape[part];
|
|
138
148
|
if (!field)
|
|
139
149
|
return [];
|
|
@@ -38,7 +38,7 @@ function generateMissingRequiredSuggestions(missingKeys, schema, config) {
|
|
|
38
38
|
if (!(schema instanceof zod_1.z.ZodObject)) {
|
|
39
39
|
return [];
|
|
40
40
|
}
|
|
41
|
-
const shape =
|
|
41
|
+
const shape = (0, schema_introspection_js_1.getCachedShape)(schema);
|
|
42
42
|
const suggestions = [];
|
|
43
43
|
for (const key of missingKeys) {
|
|
44
44
|
const field = shape[key];
|
|
@@ -118,7 +118,7 @@ function patchTemplateForFailedOptionals(correctTemplate, args, zodErrors, schem
|
|
|
118
118
|
if (args === null || typeof args !== 'object' || Array.isArray(args))
|
|
119
119
|
return correctTemplate;
|
|
120
120
|
const argsObj = args;
|
|
121
|
-
const shape =
|
|
121
|
+
const shape = (0, schema_introspection_js_1.getCachedShape)(schema);
|
|
122
122
|
const patched = { ...correctTemplate };
|
|
123
123
|
let changed = false;
|
|
124
124
|
for (const error of zodErrors) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ProcessSignal, ProcessSignals } from '../ports/process-signals.js';
|
|
2
2
|
export declare class NodeProcessSignals implements ProcessSignals {
|
|
3
3
|
on(signal: ProcessSignal, handler: () => void | Promise<void>): void;
|
|
4
|
+
once(signal: ProcessSignal, handler: () => void | Promise<void>): void;
|
|
4
5
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ProcessSignal, ProcessSignals } from '../ports/process-signals.js';
|
|
2
2
|
export declare class NoopProcessSignals implements ProcessSignals {
|
|
3
3
|
on(_signal: ProcessSignal, _handler: () => void | Promise<void>): void;
|
|
4
|
+
once(_signal: ProcessSignal, _handler: () => void | Promise<void>): void;
|
|
4
5
|
}
|
|
@@ -134,6 +134,8 @@ export interface WorkflowDefinition {
|
|
|
134
134
|
readonly extensionPoints?: readonly ExtensionPoint[];
|
|
135
135
|
readonly references?: readonly WorkflowReference[];
|
|
136
136
|
readonly validatedAgainstSpecVersion?: number;
|
|
137
|
+
readonly about?: string;
|
|
138
|
+
readonly examples?: readonly string[];
|
|
137
139
|
}
|
|
138
140
|
export declare function isLoopStepDefinition(step: WorkflowStepDefinition | LoopStepDefinition): step is LoopStepDefinition;
|
|
139
141
|
export declare function isWorkflowStepDefinition(step: WorkflowStepDefinition | LoopStepDefinition): step is WorkflowStepDefinition;
|
package/dist/types/workflow.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ import { WorkflowSource } from './workflow-source';
|
|
|
3
3
|
export interface Workflow {
|
|
4
4
|
readonly definition: WorkflowDefinition;
|
|
5
5
|
readonly source: WorkflowSource;
|
|
6
|
+
readonly stepById: ReadonlyMap<string, WorkflowStepDefinition | LoopStepDefinition>;
|
|
7
|
+
readonly parentLoopByStepId: ReadonlyMap<string, LoopStepDefinition>;
|
|
8
|
+
readonly loopById: ReadonlyMap<string, LoopStepDefinition>;
|
|
6
9
|
}
|
|
7
10
|
export interface WorkflowSummary {
|
|
8
11
|
readonly id: string;
|
package/dist/types/workflow.js
CHANGED
|
@@ -9,10 +9,35 @@ exports.getAllStepIds = getAllStepIds;
|
|
|
9
9
|
exports.isWorkflow = isWorkflow;
|
|
10
10
|
exports.isWorkflowDefinition = isWorkflowDefinition;
|
|
11
11
|
const workflow_source_1 = require("./workflow-source");
|
|
12
|
+
function buildWorkflowIndices(definition) {
|
|
13
|
+
const stepById = new Map();
|
|
14
|
+
const parentLoopByStepId = new Map();
|
|
15
|
+
const loopById = new Map();
|
|
16
|
+
function indexSteps(steps, parentLoop) {
|
|
17
|
+
for (const step of steps) {
|
|
18
|
+
stepById.set(step.id, step);
|
|
19
|
+
if (parentLoop !== null) {
|
|
20
|
+
parentLoopByStepId.set(step.id, parentLoop);
|
|
21
|
+
}
|
|
22
|
+
if ('type' in step && step.type === 'loop') {
|
|
23
|
+
loopById.set(step.id, step);
|
|
24
|
+
if (Array.isArray(step.body)) {
|
|
25
|
+
indexSteps(step.body, step);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
indexSteps(definition.steps ?? [], null);
|
|
31
|
+
return { stepById, parentLoopByStepId, loopById };
|
|
32
|
+
}
|
|
12
33
|
function createWorkflow(definition, source) {
|
|
34
|
+
const { stepById, parentLoopByStepId, loopById } = buildWorkflowIndices(definition);
|
|
13
35
|
return Object.freeze({
|
|
14
36
|
definition,
|
|
15
|
-
source
|
|
37
|
+
source,
|
|
38
|
+
stepById,
|
|
39
|
+
parentLoopByStepId,
|
|
40
|
+
loopById,
|
|
16
41
|
});
|
|
17
42
|
}
|
|
18
43
|
function toWorkflowSummary(workflow) {
|
|
@@ -31,32 +56,10 @@ function toWorkflowSourceInfo(source) {
|
|
|
31
56
|
});
|
|
32
57
|
}
|
|
33
58
|
function getStepById(workflow, stepId) {
|
|
34
|
-
|
|
35
|
-
for (const step of steps) {
|
|
36
|
-
if (step.id === stepId) {
|
|
37
|
-
return step;
|
|
38
|
-
}
|
|
39
|
-
if ('type' in step && step.type === 'loop' && Array.isArray(step.body)) {
|
|
40
|
-
for (const bodyStep of step.body) {
|
|
41
|
-
if (bodyStep.id === stepId) {
|
|
42
|
-
return bodyStep;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return null;
|
|
59
|
+
return workflow.stepById.get(stepId) ?? null;
|
|
48
60
|
}
|
|
49
61
|
function getAllStepIds(workflow) {
|
|
50
|
-
|
|
51
|
-
for (const step of workflow.definition.steps) {
|
|
52
|
-
ids.push(step.id);
|
|
53
|
-
if ('type' in step && step.type === 'loop' && Array.isArray(step.body)) {
|
|
54
|
-
for (const bodyStep of step.body) {
|
|
55
|
-
ids.push(bodyStep.id);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return Object.freeze(ids);
|
|
62
|
+
return Object.freeze([...workflow.stepById.keys()]);
|
|
60
63
|
}
|
|
61
64
|
function isWorkflow(obj) {
|
|
62
65
|
if (!obj || typeof obj !== 'object')
|
|
@@ -64,10 +67,16 @@ function isWorkflow(obj) {
|
|
|
64
67
|
const candidate = obj;
|
|
65
68
|
return ('definition' in candidate &&
|
|
66
69
|
'source' in candidate &&
|
|
70
|
+
'stepById' in candidate &&
|
|
71
|
+
'parentLoopByStepId' in candidate &&
|
|
72
|
+
'loopById' in candidate &&
|
|
67
73
|
candidate['definition'] !== null &&
|
|
68
74
|
typeof candidate['definition'] === 'object' &&
|
|
69
75
|
candidate['source'] !== null &&
|
|
70
|
-
typeof candidate['source'] === 'object'
|
|
76
|
+
typeof candidate['source'] === 'object' &&
|
|
77
|
+
candidate['stepById'] instanceof Map &&
|
|
78
|
+
candidate['parentLoopByStepId'] instanceof Map &&
|
|
79
|
+
candidate['loopById'] instanceof Map);
|
|
71
80
|
}
|
|
72
81
|
function isWorkflowDefinition(obj) {
|
|
73
82
|
if (!obj || typeof obj !== 'object')
|
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.CONTEXT_TOKEN_PATTERN = void 0;
|
|
4
4
|
exports.resolveContextTemplates = resolveContextTemplates;
|
|
5
5
|
exports.CONTEXT_TOKEN_PATTERN = /\{\{(?!wr\.)([a-zA-Z_]\w*(?:\.[a-zA-Z_]\w*)*)\}\}/;
|
|
6
|
-
const CONTEXT_TOKEN_RE_G = new RegExp(exports.CONTEXT_TOKEN_PATTERN.source, 'g');
|
|
7
6
|
function resolveDotPath(base, path) {
|
|
8
7
|
let current = base;
|
|
9
8
|
for (const segment of path) {
|
|
@@ -16,7 +15,8 @@ function resolveDotPath(base, path) {
|
|
|
16
15
|
function resolveContextTemplates(template, context) {
|
|
17
16
|
if (!template.includes('{{'))
|
|
18
17
|
return template;
|
|
19
|
-
|
|
18
|
+
const re = new RegExp(exports.CONTEXT_TOKEN_PATTERN.source, 'g');
|
|
19
|
+
return template.replace(re, (_match, dotPath) => {
|
|
20
20
|
const value = resolveDotPath(context, dotPath.split('.'));
|
|
21
21
|
if (value === undefined || value === null) {
|
|
22
22
|
return `[unset: ${dotPath}]`;
|
|
@@ -3,23 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.expandFunctionDefinitions = expandFunctionDefinitions;
|
|
4
4
|
exports.formatFunctionDef = formatFunctionDef;
|
|
5
5
|
const neverthrow_1 = require("neverthrow");
|
|
6
|
-
const workflow_js_1 = require("../../../types/workflow.js");
|
|
7
6
|
function findLoopById(workflow, loopId) {
|
|
8
|
-
|
|
9
|
-
for (const step of steps) {
|
|
10
|
-
if (!(0, workflow_js_1.isLoopStepDefinition)(step))
|
|
11
|
-
continue;
|
|
12
|
-
if (step.id === loopId)
|
|
13
|
-
return step;
|
|
14
|
-
if (Array.isArray(step.body)) {
|
|
15
|
-
const found = searchSteps(step.body);
|
|
16
|
-
if (found)
|
|
17
|
-
return found;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
return null;
|
|
21
|
-
}
|
|
22
|
-
return searchSteps(workflow.definition.steps);
|
|
7
|
+
return workflow.loopById.get(loopId) ?? null;
|
|
23
8
|
}
|
|
24
9
|
function getWorkflowScopeDefs(workflow) {
|
|
25
10
|
return workflow.definition.functionDefinitions?.filter(f => !f.scope || f.scope === 'workflow') ?? [];
|
|
@@ -31,7 +16,7 @@ function getLoopScopeDefs(args) {
|
|
|
31
16
|
});
|
|
32
17
|
}
|
|
33
18
|
function getStepScopeDefs(args) {
|
|
34
|
-
const step = args.workflow.
|
|
19
|
+
const step = args.workflow.stepById.get(args.stepId);
|
|
35
20
|
return step?.functionDefinitions?.filter(f => !f.scope || f.scope === 'step') ?? [];
|
|
36
21
|
}
|
|
37
22
|
function expandFunctionDefinitions(args) {
|
|
@@ -13,9 +13,11 @@ const constants_js_1 = require("../constants.js");
|
|
|
13
13
|
const validation_requirements_extractor_js_1 = require("./validation-requirements-extractor.js");
|
|
14
14
|
const index_js_2 = require("../schemas/artifacts/index.js");
|
|
15
15
|
const run_context_js_1 = require("../../projections/run-context.js");
|
|
16
|
+
const sorted_event_log_js_1 = require("../sorted-event-log.js");
|
|
16
17
|
const condition_evaluator_js_1 = require("../../../utils/condition-evaluator.js");
|
|
17
18
|
const context_template_resolver_js_1 = require("./context-template-resolver.js");
|
|
18
19
|
const retrieval_contract_js_1 = require("./retrieval-contract.js");
|
|
20
|
+
const env_flags_js_1 = require("../../../env-flags.js");
|
|
19
21
|
function buildNonTipSegments(args) {
|
|
20
22
|
const segments = [];
|
|
21
23
|
const childSummary = (0, recap_recovery_js_1.buildChildSummary)({ nodeId: args.nodeId, dag: args.run });
|
|
@@ -86,15 +88,7 @@ function buildRecoverySegments(args) {
|
|
|
86
88
|
];
|
|
87
89
|
}
|
|
88
90
|
function resolveParentLoopStep(workflow, stepId) {
|
|
89
|
-
|
|
90
|
-
if ((0, workflow_js_1.isLoopStepDefinition)(step) && Array.isArray(step.body)) {
|
|
91
|
-
for (const bodyStep of step.body) {
|
|
92
|
-
if (bodyStep.id === stepId)
|
|
93
|
-
return step;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return undefined;
|
|
91
|
+
return workflow.parentLoopByStepId.get(stepId);
|
|
98
92
|
}
|
|
99
93
|
function buildLoopRenderContext(loopStep, iteration, sessionContext) {
|
|
100
94
|
const iterationVar = loopStep.loop.iterationVar || 'currentIteration';
|
|
@@ -238,11 +232,13 @@ function renderPendingPrompt(args) {
|
|
|
238
232
|
const isExitStep = outputContract?.contractRef === index_js_2.LOOP_CONTROL_CONTRACT_REF;
|
|
239
233
|
const loopStep = resolveParentLoopStep(args.workflow, args.stepId);
|
|
240
234
|
const maxIterations = loopStep?.loop.maxIterations;
|
|
241
|
-
const sessionContext =
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
235
|
+
const sessionContext = args.precomputedIndex
|
|
236
|
+
? (args.precomputedIndex.runContextByRunId.get(String(args.runId)) ?? {})
|
|
237
|
+
: (0, sorted_event_log_js_1.asSortedEventLog)(args.truth.events).andThen((sorted) => (0, run_context_js_1.projectRunContextV2)(sorted)).match((ok) => (ok.byRunId[String(args.runId)]?.context ?? {}), (e) => {
|
|
238
|
+
console.warn(`[prompt-renderer] Context projection failed for step '${args.stepId}' — ` +
|
|
239
|
+
`{{varName}} tokens will render as [unset:...]: ${e.message}`);
|
|
240
|
+
return {};
|
|
241
|
+
});
|
|
246
242
|
const loopIterationFrame = args.loopPath.at(-1);
|
|
247
243
|
const loopRenderContext = loopStep && loopIterationFrame
|
|
248
244
|
? buildLoopRenderContext(loopStep, loopIterationFrame.iteration, sessionContext)
|
|
@@ -250,7 +246,7 @@ function renderPendingPrompt(args) {
|
|
|
250
246
|
const renderContext = { ...sessionContext, ...loopRenderContext };
|
|
251
247
|
const basePrompt = (0, context_template_resolver_js_1.resolveContextTemplates)(step.prompt ?? '', renderContext);
|
|
252
248
|
const baseTitle = (0, context_template_resolver_js_1.resolveContextTemplates)(step.title, renderContext);
|
|
253
|
-
const cleanResponseFormat =
|
|
249
|
+
const cleanResponseFormat = env_flags_js_1.CLEAN_RESPONSE_FORMAT;
|
|
254
250
|
const loopBanner = buildLoopContextBanner({ loopPath: args.loopPath, isExitStep, maxIterations, cleanFormat: cleanResponseFormat });
|
|
255
251
|
const validationCriteria = step.validationCriteria;
|
|
256
252
|
const requirements = (0, validation_requirements_extractor_js_1.extractValidationRequirements)(validationCriteria);
|
|
@@ -279,7 +275,9 @@ function renderPendingPrompt(args) {
|
|
|
279
275
|
if (cleanResponseFormat) {
|
|
280
276
|
return '';
|
|
281
277
|
}
|
|
282
|
-
const hasPriorNotes =
|
|
278
|
+
const hasPriorNotes = args.precomputedIndex
|
|
279
|
+
? args.precomputedIndex.hasPriorNotesByRunId.has(String(args.runId))
|
|
280
|
+
: hasPriorNotesInRun({ truth: args.truth, runId: args.runId });
|
|
283
281
|
if (hasPriorNotes && !args.rehydrateOnly) {
|
|
284
282
|
return '\n\n**NOTES REQUIRED (System):** Include `output.notesMarkdown` when advancing.\n\n' +
|
|
285
283
|
'Scope: this step only — WorkRail concatenates notes automatically.\n' +
|
|
@@ -321,8 +319,15 @@ function renderPendingPrompt(args) {
|
|
|
321
319
|
const fragmentSuffix = promptFragments && promptFragments.length > 0
|
|
322
320
|
? assembleFragmentedPrompt(promptFragments, renderContext)
|
|
323
321
|
: '';
|
|
324
|
-
const enhancedPrompt =
|
|
325
|
-
|
|
322
|
+
const enhancedPrompt = [
|
|
323
|
+
loopBanner,
|
|
324
|
+
basePrompt,
|
|
325
|
+
requirementsSection,
|
|
326
|
+
contractSection,
|
|
327
|
+
assessmentSection,
|
|
328
|
+
notesSection,
|
|
329
|
+
fragmentSuffix ? '\n\n' + fragmentSuffix : '',
|
|
330
|
+
].join('');
|
|
326
331
|
if (!args.rehydrateOnly) {
|
|
327
332
|
return (0, neverthrow_1.ok)({ stepId: args.stepId, title: baseTitle, prompt: enhancedPrompt, agentRole, requireConfirmation });
|
|
328
333
|
}
|