@exaudeus/workrail 3.14.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/validation-engine.js +4 -9
- package/dist/application/services/workflow-compiler.js +4 -6
- 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/engine/engine-factory.js +2 -2
- package/dist/engine/types.d.ts +1 -1
- 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 +283 -219
- 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/shared/request-workflow-reader.d.ts +5 -0
- package/dist/mcp/handlers/shared/request-workflow-reader.js +47 -2
- package/dist/mcp/handlers/v2-advance-core/assessment-consequences.d.ts +1 -1
- package/dist/mcp/handlers/v2-advance-core/assessment-consequences.js +4 -5
- 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 +5 -4
- 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 +2 -2
- 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 +3 -3
- package/dist/mcp/handlers/v2-execution/start.js +31 -12
- 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 +100 -0
- package/dist/mcp/handlers/v2-workflow.js +155 -31
- package/dist/mcp/handlers/workflow.d.ts +2 -5
- package/dist/mcp/handlers/workflow.js +15 -12
- package/dist/mcp/output-schemas.d.ts +123 -29
- package/dist/mcp/output-schemas.js +36 -18
- package/dist/mcp/server.js +70 -5
- package/dist/mcp/tool-call-timing.d.ts +24 -0
- package/dist/mcp/tool-call-timing.js +85 -0
- package/dist/mcp/tool-descriptions.js +17 -9
- 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/tools.d.ts +6 -0
- package/dist/mcp/v2/tools.js +2 -0
- 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/mcp/workflow-protocol-contracts.js +5 -1
- 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 +3 -2
- 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/infra/local/workspace-anchor/index.js +4 -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 +149 -3
- package/dist/v2/usecases/console-service.d.ts +2 -0
- package/dist/v2/usecases/console-service.js +87 -26
- package/dist/v2/usecases/console-types.d.ts +65 -0
- package/dist/v2/usecases/worktree-service.js +87 -8
- package/package.json +7 -6
- package/spec/authoring-spec.json +82 -1
- package/spec/workflow-tags.json +132 -0
- package/spec/workflow.schema.json +21 -11
- package/workflows/adaptive-ticket-creation.json +33 -8
- package/workflows/architecture-scalability-audit.json +50 -9
- package/workflows/bug-investigation.agentic.v2.json +43 -14
- package/workflows/coding-task-workflow-agentic.json +57 -38
- package/workflows/coding-task-workflow-agentic.lean.v2.json +129 -34
- package/workflows/coding-task-workflow-agentic.v2.json +97 -30
- package/workflows/cross-platform-code-conversion.v2.json +175 -48
- package/workflows/document-creation-workflow.json +49 -12
- package/workflows/documentation-update-workflow.json +9 -2
- package/workflows/intelligent-test-case-generation.json +9 -2
- package/workflows/learner-centered-course-workflow.json +273 -266
- package/workflows/mr-review-workflow.agentic.v2.json +88 -14
- package/workflows/personal-learning-materials-creation-branched.json +181 -174
- package/workflows/presentation-creation.json +167 -160
- package/workflows/production-readiness-audit.json +61 -15
- package/workflows/relocation-workflow-us.json +21 -5
- package/workflows/routines/tension-driven-design.json +1 -1
- package/workflows/scoped-documentation-workflow.json +9 -2
- package/workflows/test-artifact-loop-control.json +1 -2
- package/workflows/ui-ux-design-workflow.json +334 -0
- package/workflows/workflow-diagnose-environment.json +7 -1
- package/workflows/workflow-for-workflows.json +514 -484
- package/workflows/workflow-for-workflows.v2.json +55 -11
- package/workflows/wr.discovery.json +118 -29
- package/dist/console/assets/index-DW78t31j.css +0 -1
- package/dist/console/assets/index-EsSXrC_a.js +0 -28
|
@@ -23,8 +23,7 @@ export interface AssessmentDefinition {
|
|
|
23
23
|
readonly dimensions: readonly AssessmentDimensionDefinition[];
|
|
24
24
|
}
|
|
25
25
|
export interface AssessmentConsequenceTriggerDefinition {
|
|
26
|
-
readonly
|
|
27
|
-
readonly equalsLevel: string;
|
|
26
|
+
readonly anyEqualsLevel: string;
|
|
28
27
|
}
|
|
29
28
|
export interface AssessmentFollowupRequiredEffectDefinition {
|
|
30
29
|
readonly kind: 'require_followup';
|
|
@@ -135,6 +134,8 @@ export interface WorkflowDefinition {
|
|
|
135
134
|
readonly extensionPoints?: readonly ExtensionPoint[];
|
|
136
135
|
readonly references?: readonly WorkflowReference[];
|
|
137
136
|
readonly validatedAgainstSpecVersion?: number;
|
|
137
|
+
readonly about?: string;
|
|
138
|
+
readonly examples?: readonly string[];
|
|
138
139
|
}
|
|
139
140
|
export declare function isLoopStepDefinition(step: WorkflowStepDefinition | LoopStepDefinition): step is LoopStepDefinition;
|
|
140
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
|
}
|
|
@@ -6,18 +6,21 @@ exports.buildChildSummary = buildChildSummary;
|
|
|
6
6
|
const neverthrow_1 = require("neverthrow");
|
|
7
7
|
const constants_js_1 = require("../constants.js");
|
|
8
8
|
function collectAncestryRecap(args) {
|
|
9
|
-
const buildChain = (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
9
|
+
const buildChain = (start) => {
|
|
10
|
+
const result = [];
|
|
11
|
+
const visited = new Set();
|
|
12
|
+
let cur = start;
|
|
13
|
+
while (cur !== null && !visited.has(cur)) {
|
|
14
|
+
visited.add(cur);
|
|
15
|
+
result.push(cur);
|
|
16
|
+
cur = args.dag.nodesById[cur]?.parentNodeId ?? null;
|
|
17
|
+
}
|
|
18
|
+
return result;
|
|
16
19
|
};
|
|
17
20
|
const startNode = args.includeCurrentNode
|
|
18
21
|
? String(args.nodeId)
|
|
19
22
|
: args.dag.nodesById[String(args.nodeId)]?.parentNodeId ?? null;
|
|
20
|
-
const chain = buildChain(startNode
|
|
23
|
+
const chain = buildChain(startNode);
|
|
21
24
|
const recaps = chain.flatMap((nodeId) => {
|
|
22
25
|
const nodeOutputs = args.outputs.nodesById[nodeId];
|
|
23
26
|
if (!nodeOutputs)
|
|
@@ -35,15 +38,19 @@ function collectAncestryRecap(args) {
|
|
|
35
38
|
return (0, neverthrow_1.ok)([...recaps].reverse());
|
|
36
39
|
}
|
|
37
40
|
function collectDownstreamRecap(args) {
|
|
38
|
-
const buildPathBackward = (
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
const buildPathBackward = (start) => {
|
|
42
|
+
const result = [];
|
|
43
|
+
const visited = new Set();
|
|
44
|
+
const fromId = String(args.fromNodeId);
|
|
45
|
+
let cur = start;
|
|
46
|
+
while (cur !== null && cur !== fromId && !visited.has(cur)) {
|
|
47
|
+
visited.add(cur);
|
|
48
|
+
result.push(cur);
|
|
49
|
+
cur = args.dag.nodesById[cur]?.parentNodeId ?? null;
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
45
52
|
};
|
|
46
|
-
const pathBackward = buildPathBackward(String(args.toNodeId)
|
|
53
|
+
const pathBackward = buildPathBackward(String(args.toNodeId));
|
|
47
54
|
const recaps = [...pathBackward].reverse().flatMap((nodeId) => {
|
|
48
55
|
const nodeOutputs = args.outputs.nodesById[nodeId];
|
|
49
56
|
if (!nodeOutputs)
|
|
@@ -63,17 +63,21 @@ exports.RESUME_PREVIEW_CONTRACT = {
|
|
|
63
63
|
};
|
|
64
64
|
const encoder = new TextEncoder();
|
|
65
65
|
const decoder = new TextDecoder('utf-8');
|
|
66
|
+
const TIER_PRIORITY = Object.fromEntries(exports.REHYDRATE_RETRIEVAL_CONTRACT.tiers.map((t) => [t.tier, t.priority]));
|
|
67
|
+
const TIER_RETENTION = Object.fromEntries(exports.REHYDRATE_RETRIEVAL_CONTRACT.tiers.map((t) => [t.tier, t.retention]));
|
|
68
|
+
const RESUME_PREVIEW_TIER_PRIORITY = Object.fromEntries(exports.RESUME_PREVIEW_CONTRACT.tiers.map((t) => [t.tier, t.priority]));
|
|
69
|
+
const RESUME_PREVIEW_TIER_MAX_BYTES = Object.fromEntries(exports.RESUME_PREVIEW_CONTRACT.tiers.map((t) => [t.tier, t.maxBytes]));
|
|
66
70
|
function getTierPriority(tier) {
|
|
67
|
-
return
|
|
71
|
+
return TIER_PRIORITY[tier] ?? Number.MAX_SAFE_INTEGER;
|
|
68
72
|
}
|
|
69
73
|
function getTierRetention(tier) {
|
|
70
|
-
return
|
|
74
|
+
return TIER_RETENTION[tier] ?? 'tail';
|
|
71
75
|
}
|
|
72
76
|
function getResumePreviewTierPriority(tier) {
|
|
73
|
-
return
|
|
77
|
+
return RESUME_PREVIEW_TIER_PRIORITY[tier] ?? Number.MAX_SAFE_INTEGER;
|
|
74
78
|
}
|
|
75
79
|
function getResumePreviewTierMaxBytes(tier) {
|
|
76
|
-
return
|
|
80
|
+
return RESUME_PREVIEW_TIER_MAX_BYTES[tier] ?? exports.RESUME_PREVIEW_CONTRACT.budgetBytes;
|
|
77
81
|
}
|
|
78
82
|
function compareAscii(a, b) {
|
|
79
83
|
return a < b ? -1 : a > b ? 1 : 0;
|
|
@@ -283,7 +287,8 @@ function renderBudgetedRehydrateRecovery(args) {
|
|
|
283
287
|
const initiallyIncludedTiers = tiersInOrder.filter((tier) => (sectionsByTier.get(tier) ?? []).length > 0);
|
|
284
288
|
let includedTiers = initiallyIncludedTiers;
|
|
285
289
|
let recoveryText = renderFromTiers(includedTiers);
|
|
286
|
-
|
|
290
|
+
let recoveryBytes = encoder.encode(recoveryText).length;
|
|
291
|
+
while (recoveryBytes > constants_js_1.RECOVERY_BUDGET_BYTES) {
|
|
287
292
|
const droppableTierIndex = [...includedTiers]
|
|
288
293
|
.reverse()
|
|
289
294
|
.findIndex((tier) => getTierRetention(tier) === 'tail');
|
|
@@ -293,9 +298,10 @@ function renderBudgetedRehydrateRecovery(args) {
|
|
|
293
298
|
const actualIndex = includedTiers.length - 1 - droppableTierIndex;
|
|
294
299
|
includedTiers = includedTiers.filter((_, index) => index !== actualIndex);
|
|
295
300
|
recoveryText = renderFromTiers(includedTiers);
|
|
301
|
+
recoveryBytes = encoder.encode(recoveryText).length;
|
|
296
302
|
}
|
|
297
303
|
const omittedTierCount = initiallyIncludedTiers.length - includedTiers.length;
|
|
298
|
-
const needsSuffix = omittedTierCount > 0 ||
|
|
304
|
+
const needsSuffix = omittedTierCount > 0 || recoveryBytes > constants_js_1.RECOVERY_BUDGET_BYTES || includedTiers.length === 0;
|
|
299
305
|
const finalText = recoveryText.length === 0
|
|
300
306
|
? trimFinalRecoveryText(args.header, initiallyIncludedTiers.length)
|
|
301
307
|
: !needsSuffix
|
|
@@ -305,6 +311,6 @@ function renderBudgetedRehydrateRecovery(args) {
|
|
|
305
311
|
text: finalText,
|
|
306
312
|
includedTiers,
|
|
307
313
|
omittedTierCount,
|
|
308
|
-
truncatedWithinTier:
|
|
314
|
+
truncatedWithinTier: recoveryBytes > constants_js_1.RECOVERY_BUDGET_BYTES || includedTiers.length === 0,
|
|
309
315
|
};
|
|
310
316
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Brand } from '../../runtime/brand.js';
|
|
2
|
+
import type { SortedEventLog } from './sorted-event-log.js';
|
|
3
|
+
import type { DomainEventV1 } from './schemas/session/index.js';
|
|
4
|
+
import type { JsonObject } from './canonical/json-types.js';
|
|
5
|
+
export interface SessionIndexData {
|
|
6
|
+
readonly sortedEvents: SortedEventLog;
|
|
7
|
+
readonly runStartedByRunId: ReadonlyMap<string, Extract<DomainEventV1, {
|
|
8
|
+
kind: 'run_started';
|
|
9
|
+
}>>;
|
|
10
|
+
readonly nodeCreatedByNodeId: ReadonlyMap<string, Extract<DomainEventV1, {
|
|
11
|
+
kind: 'node_created';
|
|
12
|
+
}>>;
|
|
13
|
+
readonly hasChildEdgeByFromNodeId: ReadonlySet<string>;
|
|
14
|
+
readonly advanceRecordedByDedupeKey: ReadonlyMap<string, Extract<DomainEventV1, {
|
|
15
|
+
kind: 'advance_recorded';
|
|
16
|
+
}>>;
|
|
17
|
+
readonly nextEventIndex: number;
|
|
18
|
+
readonly hasPriorNotesByRunId: ReadonlySet<string>;
|
|
19
|
+
readonly runContextByRunId: ReadonlyMap<string, JsonObject>;
|
|
20
|
+
}
|
|
21
|
+
export type SessionIndex = Brand<SessionIndexData, 'v2.SessionIndex'>;
|
|
22
|
+
export declare function buildSessionIndex(events: SortedEventLog): SessionIndex;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSessionIndex = buildSessionIndex;
|
|
4
|
+
const constants_js_1 = require("./constants.js");
|
|
5
|
+
function buildSessionIndex(events) {
|
|
6
|
+
const runStartedByRunId = new Map();
|
|
7
|
+
const nodeCreatedByNodeId = new Map();
|
|
8
|
+
const hasChildEdgeByFromNodeId = new Set();
|
|
9
|
+
const advanceRecordedByDedupeKey = new Map();
|
|
10
|
+
const hasPriorNotesByRunId = new Set();
|
|
11
|
+
const runContextByRunId = new Map();
|
|
12
|
+
for (const event of events) {
|
|
13
|
+
switch (event.kind) {
|
|
14
|
+
case 'run_started':
|
|
15
|
+
runStartedByRunId.set(event.scope.runId, event);
|
|
16
|
+
break;
|
|
17
|
+
case 'node_created':
|
|
18
|
+
nodeCreatedByNodeId.set(event.scope.nodeId, event);
|
|
19
|
+
break;
|
|
20
|
+
case 'edge_created':
|
|
21
|
+
hasChildEdgeByFromNodeId.add(event.data.fromNodeId);
|
|
22
|
+
break;
|
|
23
|
+
case 'advance_recorded':
|
|
24
|
+
advanceRecordedByDedupeKey.set(event.dedupeKey, event);
|
|
25
|
+
break;
|
|
26
|
+
case 'node_output_appended': {
|
|
27
|
+
const outputEvt = event;
|
|
28
|
+
if (outputEvt.data.outputChannel === constants_js_1.OUTPUT_CHANNEL.RECAP &&
|
|
29
|
+
outputEvt.data.payload.payloadKind === constants_js_1.PAYLOAD_KIND.NOTES) {
|
|
30
|
+
hasPriorNotesByRunId.add(event.scope.runId);
|
|
31
|
+
}
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
case 'context_set': {
|
|
35
|
+
const ctx = event.data.context;
|
|
36
|
+
if (ctx && typeof ctx === 'object' && !Array.isArray(ctx)) {
|
|
37
|
+
runContextByRunId.set(event.scope.runId, ctx);
|
|
38
|
+
}
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
default:
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const lastEvent = events[events.length - 1];
|
|
46
|
+
const nextEventIndex = lastEvent !== undefined ? lastEvent.eventIndex + 1 : 0;
|
|
47
|
+
const data = {
|
|
48
|
+
sortedEvents: events,
|
|
49
|
+
runStartedByRunId,
|
|
50
|
+
nodeCreatedByNodeId,
|
|
51
|
+
hasChildEdgeByFromNodeId,
|
|
52
|
+
advanceRecordedByDedupeKey,
|
|
53
|
+
nextEventIndex,
|
|
54
|
+
hasPriorNotesByRunId,
|
|
55
|
+
runContextByRunId,
|
|
56
|
+
};
|
|
57
|
+
return data;
|
|
58
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Result } from 'neverthrow';
|
|
2
|
+
import type { Brand } from '../../runtime/brand.js';
|
|
3
|
+
import type { DomainEventV1 } from './schemas/session/index.js';
|
|
4
|
+
import type { ProjectionError } from '../projections/projection-error.js';
|
|
5
|
+
export type SortedEventLog = Brand<readonly DomainEventV1[], 'v2.SortedEventLog'>;
|
|
6
|
+
export declare function asSortedEventLog(events: readonly DomainEventV1[]): Result<SortedEventLog, ProjectionError>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.asSortedEventLog = asSortedEventLog;
|
|
4
|
+
const neverthrow_1 = require("neverthrow");
|
|
5
|
+
function asSortedEventLog(events) {
|
|
6
|
+
for (let i = 1; i < events.length; i++) {
|
|
7
|
+
if (events[i].eventIndex <= events[i - 1].eventIndex) {
|
|
8
|
+
return (0, neverthrow_1.err)({
|
|
9
|
+
code: 'PROJECTION_INVARIANT_VIOLATION',
|
|
10
|
+
message: 'Events must be sorted by eventIndex strictly ascending (no duplicates)',
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return (0, neverthrow_1.ok)(events);
|
|
15
|
+
}
|
|
@@ -166,18 +166,18 @@ class NodeFileSystemV2 {
|
|
|
166
166
|
readdirWithMtime(dirPath) {
|
|
167
167
|
return neverthrow_1.ResultAsync.fromPromise((async () => {
|
|
168
168
|
const entries = await fs.readdir(dirPath);
|
|
169
|
+
const results = await Promise.allSettled(entries.map((name) => fs.stat(path.join(dirPath, name)).then((s) => ({ name, mtimeMs: s.mtimeMs }))));
|
|
169
170
|
const withMtime = [];
|
|
170
171
|
let skipped = 0;
|
|
171
|
-
for (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
withMtime.push(
|
|
172
|
+
for (let i = 0; i < results.length; i++) {
|
|
173
|
+
const result = results[i];
|
|
174
|
+
if (result.status === 'fulfilled') {
|
|
175
|
+
withMtime.push(result.value);
|
|
175
176
|
}
|
|
176
|
-
|
|
177
|
-
const code = nodeErrorCode(
|
|
177
|
+
else {
|
|
178
|
+
const code = nodeErrorCode(result.reason);
|
|
178
179
|
skipped++;
|
|
179
|
-
console.error(`[workrail:session-enum] Skipping ${
|
|
180
|
-
continue;
|
|
180
|
+
console.error(`[workrail:session-enum] Skipping ${entries[i]}: stat failed (${code ?? 'unknown'}: ${result.reason instanceof Error ? result.reason.message : String(result.reason)})`);
|
|
181
181
|
}
|
|
182
182
|
}
|
|
183
183
|
if (skipped > 0) {
|
|
@@ -10,7 +10,7 @@ export declare class LocalSessionEventLogStoreV2 implements SessionEventLogReado
|
|
|
10
10
|
private readonly fs;
|
|
11
11
|
private readonly sha256;
|
|
12
12
|
constructor(dataDir: DataDirPortV2, fs: FileSystemPortV2, sha256: Sha256PortV2);
|
|
13
|
-
append(lock: WithHealthySessionLock, plan: AppendPlanV2): ResultAsync<void, SessionEventLogStoreError>;
|
|
13
|
+
append(lock: WithHealthySessionLock, plan: AppendPlanV2, preloadedTruth?: LoadedSessionTruthV2): ResultAsync<void, SessionEventLogStoreError>;
|
|
14
14
|
load(sessionId: SessionId): ResultAsync<LoadedSessionTruthV2, SessionEventLogStoreError>;
|
|
15
15
|
loadValidatedPrefix(sessionId: SessionId): ResultAsync<LoadedValidatedPrefixV2, SessionEventLogStoreError>;
|
|
16
16
|
private appendImpl;
|