@exaudeus/workrail 1.1.0 → 1.3.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.d.ts +15 -1
- package/dist/application/services/validation-engine.js +81 -51
- package/dist/application/services/workflow-compiler.d.ts +3 -0
- package/dist/application/services/workflow-compiler.js +26 -0
- package/dist/application/services/workflow-interpreter.d.ts +4 -1
- package/dist/application/services/workflow-interpreter.js +85 -24
- package/dist/application/services/workflow-service.js +19 -2
- package/dist/manifest.json +299 -83
- package/dist/mcp/handlers/shared/with-timeout.d.ts +1 -0
- package/dist/mcp/handlers/shared/with-timeout.js +9 -0
- package/dist/mcp/handlers/v2-advance-core.d.ts +45 -0
- package/dist/mcp/handlers/v2-advance-core.js +433 -0
- package/dist/mcp/handlers/v2-context-budget.d.ts +17 -0
- package/dist/mcp/handlers/v2-context-budget.js +169 -0
- package/dist/mcp/handlers/v2-error-mapping.d.ts +34 -0
- package/dist/mcp/handlers/v2-error-mapping.js +125 -0
- package/dist/mcp/handlers/v2-execution-helpers.js +4 -1
- package/dist/mcp/handlers/v2-execution.d.ts +19 -0
- package/dist/mcp/handlers/v2-execution.js +278 -765
- package/dist/mcp/handlers/v2-state-conversion.d.ts +40 -0
- package/dist/mcp/handlers/v2-state-conversion.js +132 -0
- package/dist/mcp/handlers/v2-token-ops.d.ts +33 -0
- package/dist/mcp/handlers/v2-token-ops.js +62 -0
- package/dist/mcp/handlers/v2-workflow.js +3 -8
- package/dist/mcp/handlers/workflow.js +4 -11
- package/dist/mcp/output-schemas.d.ts +272 -20
- package/dist/mcp/output-schemas.js +20 -1
- package/dist/mcp/server.js +2 -0
- package/dist/mcp/tool-descriptions.js +67 -51
- package/dist/mcp/types.d.ts +2 -0
- package/dist/mcp/v2/tools.d.ts +23 -2
- package/dist/mcp/v2/tools.js +35 -4
- package/dist/types/workflow-definition.d.ts +19 -0
- package/dist/v2/durable-core/constants.d.ts +2 -0
- package/dist/v2/durable-core/constants.js +3 -1
- package/dist/v2/durable-core/domain/ack-advance-append-plan.d.ts +1 -0
- package/dist/v2/durable-core/domain/ack-advance-append-plan.js +11 -1
- package/dist/v2/durable-core/domain/artifact-contract-validator.d.ts +31 -0
- package/dist/v2/durable-core/domain/artifact-contract-validator.js +98 -0
- package/dist/v2/durable-core/domain/blocked-node-builder.d.ts +20 -0
- package/dist/v2/durable-core/domain/blocked-node-builder.js +94 -0
- package/dist/v2/durable-core/domain/bundle-builder.d.ts +27 -0
- package/dist/v2/durable-core/domain/bundle-builder.js +93 -0
- package/dist/v2/durable-core/domain/bundle-validator.d.ts +4 -0
- package/dist/v2/durable-core/domain/bundle-validator.js +129 -0
- package/dist/v2/durable-core/domain/decision-trace-builder.d.ts +33 -0
- package/dist/v2/durable-core/domain/decision-trace-builder.js +92 -0
- package/dist/v2/durable-core/domain/function-definition-expander.js +1 -1
- package/dist/v2/durable-core/domain/loop-control-evaluator.d.ts +13 -0
- package/dist/v2/durable-core/domain/loop-control-evaluator.js +24 -0
- package/dist/v2/durable-core/domain/observation-builder.d.ts +16 -0
- package/dist/v2/durable-core/domain/observation-builder.js +42 -0
- package/dist/v2/durable-core/domain/outputs.js +2 -2
- package/dist/v2/durable-core/domain/prompt-renderer.js +37 -4
- package/dist/v2/durable-core/domain/reason-model.d.ts +3 -1
- package/dist/v2/durable-core/domain/reason-model.js +16 -3
- package/dist/v2/durable-core/domain/recommendation-warnings.d.ts +20 -0
- package/dist/v2/durable-core/domain/recommendation-warnings.js +35 -0
- package/dist/v2/durable-core/domain/risk-policy-guardrails.d.ts +15 -0
- package/dist/v2/durable-core/domain/risk-policy-guardrails.js +78 -0
- package/dist/v2/durable-core/domain/validation-criteria-validator.d.ts +8 -0
- package/dist/v2/durable-core/domain/validation-criteria-validator.js +30 -0
- package/dist/v2/durable-core/domain/validation-event-builder.d.ts +26 -0
- package/dist/v2/durable-core/domain/validation-event-builder.js +100 -0
- package/dist/v2/durable-core/domain/validation-loader.d.ts +11 -0
- package/dist/v2/durable-core/domain/validation-loader.js +21 -0
- package/dist/v2/durable-core/projections/snapshot-state.js +1 -1
- package/dist/v2/durable-core/schemas/artifacts/index.d.ts +4 -0
- package/dist/v2/durable-core/schemas/artifacts/index.js +18 -0
- package/dist/v2/durable-core/schemas/artifacts/loop-control.d.ts +66 -0
- package/dist/v2/durable-core/schemas/artifacts/loop-control.js +47 -0
- package/dist/v2/durable-core/schemas/execution-snapshot/blocked-snapshot.d.ts +598 -0
- package/dist/v2/durable-core/schemas/execution-snapshot/blocked-snapshot.js +89 -0
- package/dist/v2/durable-core/schemas/execution-snapshot/execution-snapshot.v1.d.ts +3801 -57
- package/dist/v2/durable-core/schemas/execution-snapshot/execution-snapshot.v1.js +12 -2
- package/dist/v2/durable-core/schemas/execution-snapshot/index.d.ts +2 -0
- package/dist/v2/durable-core/schemas/execution-snapshot/index.js +3 -1
- package/dist/v2/durable-core/schemas/export-bundle/index.d.ts +4682 -758
- package/dist/v2/durable-core/schemas/session/events.d.ts +158 -45
- package/dist/v2/durable-core/schemas/session/events.js +8 -1
- package/dist/v2/durable-core/schemas/session/validation-event.d.ts +68 -0
- package/dist/v2/durable-core/schemas/session/validation-event.js +52 -0
- package/dist/v2/durable-core/tokens/payloads.d.ts +16 -16
- package/dist/v2/infra/local/workspace-anchor/index.d.ts +9 -0
- package/dist/v2/infra/local/workspace-anchor/index.js +44 -0
- package/dist/v2/ports/workspace-anchor.port.d.ts +18 -0
- package/dist/v2/ports/workspace-anchor.port.js +2 -0
- package/dist/v2/projections/artifacts.d.ts +22 -0
- package/dist/v2/projections/artifacts.js +53 -0
- package/dist/v2/projections/projection-timing.d.ts +13 -0
- package/dist/v2/projections/projection-timing.js +23 -0
- package/dist/v2/projections/run-dag.d.ts +1 -1
- package/dist/v2/projections/run-status-signals.js +3 -8
- package/dist/v2/usecases/export-session.d.ts +47 -0
- package/dist/v2/usecases/export-session.js +92 -0
- package/dist/v2/usecases/import-session.d.ts +34 -0
- package/dist/v2/usecases/import-session.js +57 -0
- package/package.json +1 -1
- package/spec/workflow.schema.json +60 -0
- package/spec/workflow.schema.v0.0.1.json +38 -0
- package/workflows/coding-task-workflow-agentic.json +11 -18
- package/workflows/test-artifact-loop-control.json +59 -0
|
@@ -64,48 +64,54 @@ Remember: inspecting is read-only. Call start_workflow when ready to begin.`,
|
|
|
64
64
|
The workflow represents the user's plan for this task. Each step will tell you exactly what to do. Your job is to execute each step's instructions and report back.
|
|
65
65
|
|
|
66
66
|
What you'll receive:
|
|
67
|
-
-
|
|
68
|
-
-
|
|
69
|
-
-
|
|
70
|
-
- nextIntent: What to do next (usually "perform_pending_then_continue")
|
|
67
|
+
- pending.prompt: The first step's instructions — read this and do what it says
|
|
68
|
+
- nextCall: A pre-built template for your next continue_workflow call (copy its params when done)
|
|
69
|
+
- nextIntent: How to approach this step (usually "perform_pending_then_continue")
|
|
71
70
|
- preferences: Execution mode settings (autonomy level, risk policy)
|
|
72
71
|
|
|
73
72
|
What to do:
|
|
74
|
-
1.
|
|
75
|
-
2.
|
|
76
|
-
3.
|
|
73
|
+
1. Read pending.prompt and execute the step exactly as described
|
|
74
|
+
2. When done, call continue_workflow using the params from nextCall (it has intent, stateToken, ackToken pre-filled)
|
|
75
|
+
3. Optionally add output.notesMarkdown summarizing your work
|
|
76
|
+
4. Don't predict what comes next - the workflow will tell you
|
|
77
77
|
|
|
78
78
|
Context auto-loads: If you provide context at start, WorkRail remembers it. On future continue_workflow calls, only pass context if you have NEW information to add.`,
|
|
79
79
|
continue_workflow: `Get the next step in the workflow (WorkRail v2, feature-flagged).
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
- Recovers the current step (when you omit ackToken)
|
|
81
|
+
QUICK START — How to call back after completing a step:
|
|
82
|
+
Copy the params from the "nextCall" field of the previous response. It has intent, stateToken, and ackToken pre-filled. Just add your output if desired.
|
|
84
83
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-
|
|
90
|
-
|
|
84
|
+
Two modes — set intent explicitly:
|
|
85
|
+
|
|
86
|
+
ADVANCE (intent: "advance"):
|
|
87
|
+
- "I completed the current step; give me the next one"
|
|
88
|
+
- Requires: intent + stateToken + ackToken (all provided in nextCall.params)
|
|
89
|
+
- Optional: output (your work summary), context (if facts changed)
|
|
90
|
+
- Result: WorkRail advances to next step and returns it
|
|
91
|
+
|
|
92
|
+
REHYDRATE (intent: "rehydrate"):
|
|
93
|
+
- "Remind me what the current step is" (after rewind or lost context)
|
|
94
|
+
- Requires: intent + stateToken
|
|
95
|
+
- Do NOT include ackToken or output
|
|
96
|
+
- Result: Same pending step returned; no advancement; side-effect-free
|
|
91
97
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
98
|
+
Reading the response:
|
|
99
|
+
- pending.prompt: The step's instructions — what to do
|
|
100
|
+
- nextCall: Pre-built template for your next call — how to proceed when done (null if workflow complete)
|
|
101
|
+
- nextIntent: How to approach this step — execute it, confirm first, or continue working on it
|
|
95
102
|
|
|
96
|
-
nextIntent
|
|
97
|
-
- "perform_pending_then_continue": Execute this step
|
|
103
|
+
nextIntent values:
|
|
104
|
+
- "perform_pending_then_continue": Execute this step, then use nextCall to advance
|
|
98
105
|
- "await_user_confirmation": Auto-confirm and proceed (you don't need to wait for user in agent mode)
|
|
99
|
-
- "rehydrate_only": You just recovered state; continue working on the current step
|
|
100
|
-
- "complete": Workflow finished;
|
|
106
|
+
- "rehydrate_only": You just recovered state; continue working on the current step, then use nextCall
|
|
107
|
+
- "complete": Workflow finished; nextCall is null
|
|
101
108
|
|
|
102
109
|
Parameters:
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
-
|
|
106
|
-
-
|
|
107
|
-
|
|
108
|
-
Example RIGHT: "Implemented user authentication with OAuth2; added 3 endpoints."
|
|
110
|
+
- intent (required): "advance" or "rehydrate"
|
|
111
|
+
- stateToken (required): From nextCall.params or previous response
|
|
112
|
+
- ackToken (required for advance): From nextCall.params or previous response
|
|
113
|
+
- context (optional): NEW facts only. Omit if unchanged - WorkRail auto-loads previous context
|
|
114
|
+
- output.notesMarkdown (optional, advance only): Fresh summary of THIS step only - never accumulated
|
|
109
115
|
|
|
110
116
|
The workflow is the user's structured instructions. Follow each step exactly as described.`,
|
|
111
117
|
},
|
|
@@ -183,17 +189,17 @@ This is read-only. Call start_workflow when ready to commit to following the wor
|
|
|
183
189
|
The workflow is the USER'S VOICE expressing their plan for this task. Each step is a DIRECT INSTRUCTION from the user (or workflow author representing user intent). You MUST execute each step exactly as specified.
|
|
184
190
|
|
|
185
191
|
What you receive:
|
|
186
|
-
-
|
|
187
|
-
-
|
|
188
|
-
-
|
|
189
|
-
- nextIntent: Prescriptive directive for what to do next
|
|
192
|
+
- pending.prompt: The user's first instruction — execute this EXACTLY as described
|
|
193
|
+
- nextCall: Pre-built template for your next continue_workflow call — copy its params when done
|
|
194
|
+
- nextIntent: How to approach this step (execute, confirm, etc.)
|
|
190
195
|
- preferences: User's execution mode preferences (autonomy, risk tolerance)
|
|
191
196
|
|
|
192
197
|
REQUIRED BEHAVIOR:
|
|
193
198
|
1. Execute the pending step EXACTLY as the prompt describes
|
|
194
|
-
2.
|
|
195
|
-
3.
|
|
196
|
-
4.
|
|
199
|
+
2. When done, call continue_workflow using the params from nextCall (intent, stateToken, ackToken are pre-filled)
|
|
200
|
+
3. Optionally add output.notesMarkdown summarizing your work
|
|
201
|
+
4. Round-trip tokens UNCHANGED (don't decode, inspect, or modify them)
|
|
202
|
+
5. Follow the workflow to completion - don't improvise alternative approaches
|
|
197
203
|
|
|
198
204
|
Context handling:
|
|
199
205
|
- Pass context at start to establish baseline facts
|
|
@@ -203,38 +209,48 @@ Context handling:
|
|
|
203
209
|
|
|
204
210
|
The workflow represents the USER'S PLAN. The pending step returned is a DIRECT INSTRUCTION you MUST follow.
|
|
205
211
|
|
|
206
|
-
|
|
212
|
+
HOW TO CALL — Copy nextCall.params from the previous response. It has intent, stateToken, and ackToken pre-filled. Add output if desired.
|
|
207
213
|
|
|
208
|
-
|
|
214
|
+
Two modes — set intent explicitly:
|
|
215
|
+
|
|
216
|
+
ADVANCE (intent: "advance"):
|
|
209
217
|
- Purpose: "I completed the current step; give me the next instruction"
|
|
210
|
-
-
|
|
218
|
+
- Requires: intent + stateToken + ackToken (all in nextCall.params from previous response)
|
|
219
|
+
- Optional: output (your work summary), context (if facts changed)
|
|
211
220
|
- Result: WorkRail advances to next step
|
|
212
221
|
- Idempotent: Safe to retry with same tokens if unsure
|
|
213
222
|
|
|
214
|
-
|
|
223
|
+
REHYDRATE (intent: "rehydrate"):
|
|
215
224
|
- Purpose: "Remind me what the current step is" (after rewind/lost context)
|
|
216
|
-
-
|
|
225
|
+
- Requires: intent + stateToken only
|
|
226
|
+
- Do NOT include ackToken or output
|
|
217
227
|
- Result: Same pending step returned; no advancement
|
|
218
228
|
- Side-effect-free: No durable writes; pure state recovery
|
|
219
229
|
|
|
220
230
|
REQUIRED BEHAVIOR:
|
|
221
231
|
1. Execute the step EXACTLY as specified in pending.prompt
|
|
222
|
-
2.
|
|
223
|
-
3. Do NOT
|
|
224
|
-
4. Do NOT
|
|
232
|
+
2. When done, call continue_workflow using nextCall.params — do NOT construct params manually
|
|
233
|
+
3. Do NOT predict what comes next - call continue_workflow and the workflow will tell you
|
|
234
|
+
4. Do NOT skip steps, combine steps, or improvise your own approach
|
|
235
|
+
|
|
236
|
+
Reading the response:
|
|
237
|
+
- pending.prompt: The step's instructions — WHAT to do
|
|
238
|
+
- nextCall: Pre-built call template — HOW to proceed when done (null if complete)
|
|
239
|
+
- nextIntent: Step disposition — HOW to approach this step
|
|
225
240
|
|
|
226
241
|
nextIntent is PRESCRIPTIVE (not advisory):
|
|
227
|
-
- "perform_pending_then_continue": Execute this step, then
|
|
242
|
+
- "perform_pending_then_continue": Execute this step, then use nextCall to advance
|
|
228
243
|
- "await_user_confirmation": Auto-confirm and proceed (workflow represents user's intent)
|
|
229
|
-
- "rehydrate_only": State recovery occurred; continue working on current step
|
|
230
|
-
- "complete": Workflow finished;
|
|
244
|
+
- "rehydrate_only": State recovery occurred; continue working on current step, then use nextCall
|
|
245
|
+
- "complete": Workflow finished; nextCall is null
|
|
231
246
|
|
|
232
247
|
Parameters:
|
|
233
|
-
-
|
|
234
|
-
-
|
|
248
|
+
- intent (required): "advance" or "rehydrate"
|
|
249
|
+
- stateToken (required): From nextCall.params or previous response
|
|
250
|
+
- ackToken (required for advance): From nextCall.params or previous response
|
|
235
251
|
- context (optional): NEW facts only (auto-merges with previous). Omit if unchanged
|
|
236
|
-
- output.notesMarkdown (optional): Summary of THIS step only (fresh, never accumulated)
|
|
252
|
+
- output.notesMarkdown (optional, advance only): Summary of THIS step only (fresh, never accumulated)
|
|
237
253
|
|
|
238
|
-
The workflow is the user's structured will. Follow it exactly
|
|
254
|
+
The workflow is the user's structured will. Follow it exactly — it may validate, loop, or branch in ways you don't predict.`,
|
|
239
255
|
},
|
|
240
256
|
};
|
package/dist/mcp/types.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type { CryptoPortV2 } from '../v2/durable-core/canonical/hashing.js';
|
|
|
12
12
|
import type { IdFactoryV2 } from '../v2/infra/local/id-factory/index.js';
|
|
13
13
|
import type { JsonValue } from './output-schemas.js';
|
|
14
14
|
import type { TokenCodecPorts } from '../v2/durable-core/tokens/token-codec-ports.js';
|
|
15
|
+
import type { WorkspaceAnchorPortV2 } from '../v2/ports/workspace-anchor.port.js';
|
|
15
16
|
export interface SessionHealthDetails {
|
|
16
17
|
readonly health: SessionHealthV2;
|
|
17
18
|
}
|
|
@@ -51,6 +52,7 @@ export interface V2Dependencies {
|
|
|
51
52
|
readonly crypto: CryptoPortV2;
|
|
52
53
|
readonly idFactory: IdFactoryV2;
|
|
53
54
|
readonly tokenCodecPorts: TokenCodecPorts;
|
|
55
|
+
readonly workspaceAnchor?: WorkspaceAnchorPortV2;
|
|
54
56
|
}
|
|
55
57
|
export interface ToolContext {
|
|
56
58
|
readonly workflowService: WorkflowService;
|
package/dist/mcp/v2/tools.d.ts
CHANGED
|
@@ -24,7 +24,8 @@ export declare const V2StartWorkflowInput: z.ZodObject<{
|
|
|
24
24
|
context?: Record<string, unknown> | undefined;
|
|
25
25
|
}>;
|
|
26
26
|
export type V2StartWorkflowInput = z.infer<typeof V2StartWorkflowInput>;
|
|
27
|
-
export declare const V2ContinueWorkflowInput: z.ZodObject<{
|
|
27
|
+
export declare const V2ContinueWorkflowInput: z.ZodEffects<z.ZodObject<{
|
|
28
|
+
intent: z.ZodEnum<["advance", "rehydrate"]>;
|
|
28
29
|
stateToken: z.ZodString;
|
|
29
30
|
ackToken: z.ZodOptional<z.ZodString>;
|
|
30
31
|
context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
@@ -38,7 +39,26 @@ export declare const V2ContinueWorkflowInput: z.ZodObject<{
|
|
|
38
39
|
notesMarkdown?: string | undefined;
|
|
39
40
|
artifacts?: unknown[] | undefined;
|
|
40
41
|
}>>;
|
|
41
|
-
}, "
|
|
42
|
+
}, "strict", z.ZodTypeAny, {
|
|
43
|
+
intent: "advance" | "rehydrate";
|
|
44
|
+
stateToken: string;
|
|
45
|
+
context?: Record<string, unknown> | undefined;
|
|
46
|
+
output?: {
|
|
47
|
+
notesMarkdown?: string | undefined;
|
|
48
|
+
artifacts?: unknown[] | undefined;
|
|
49
|
+
} | undefined;
|
|
50
|
+
ackToken?: string | undefined;
|
|
51
|
+
}, {
|
|
52
|
+
intent: "advance" | "rehydrate";
|
|
53
|
+
stateToken: string;
|
|
54
|
+
context?: Record<string, unknown> | undefined;
|
|
55
|
+
output?: {
|
|
56
|
+
notesMarkdown?: string | undefined;
|
|
57
|
+
artifacts?: unknown[] | undefined;
|
|
58
|
+
} | undefined;
|
|
59
|
+
ackToken?: string | undefined;
|
|
60
|
+
}>, {
|
|
61
|
+
intent: "advance" | "rehydrate";
|
|
42
62
|
stateToken: string;
|
|
43
63
|
context?: Record<string, unknown> | undefined;
|
|
44
64
|
output?: {
|
|
@@ -47,6 +67,7 @@ export declare const V2ContinueWorkflowInput: z.ZodObject<{
|
|
|
47
67
|
} | undefined;
|
|
48
68
|
ackToken?: string | undefined;
|
|
49
69
|
}, {
|
|
70
|
+
intent: "advance" | "rehydrate";
|
|
50
71
|
stateToken: string;
|
|
51
72
|
context?: Record<string, unknown> | undefined;
|
|
52
73
|
output?: {
|
package/dist/mcp/v2/tools.js
CHANGED
|
@@ -12,16 +12,47 @@ exports.V2StartWorkflowInput = zod_1.z.object({
|
|
|
12
12
|
context: zod_1.z.record(zod_1.z.unknown()).optional().describe('External facts influencing execution (ticketId, branch, constraints). Pass once at start to establish baseline. WorkRail auto-loads context on subsequent continue_workflow calls. Only pass context again if facts have CHANGED (e.g., user provided new information). Do NOT re-pass unchanged values.'),
|
|
13
13
|
});
|
|
14
14
|
exports.V2ContinueWorkflowInput = zod_1.z.object({
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
intent: zod_1.z.enum(['advance', 'rehydrate']).describe('What you want to do. ' +
|
|
16
|
+
'"advance": I completed the current step — requires ackToken. ' +
|
|
17
|
+
'"rehydrate": Remind me what the current step is (state recovery after rewind/lost context) — do NOT include ackToken or output.'),
|
|
18
|
+
stateToken: zod_1.z.string().min(1).describe('Your session handle from start_workflow or previous continue_workflow. Pass this in EVERY continue_workflow call to identify your session. Round-trip exactly as received — never decode, inspect, or modify it.'),
|
|
19
|
+
ackToken: zod_1.z.string().min(1).optional().describe('Your step completion receipt. Required when intent is "advance". Must be omitted when intent is "rehydrate".'),
|
|
17
20
|
context: zod_1.z.record(zod_1.z.unknown()).optional().describe('External facts (only if CHANGED since last call). Omit this entirely if no facts changed. WorkRail auto-merges with previous context. Example: if context={branch:"main"} at start, do NOT re-pass it unless branch changed. Pass only NEW or OVERRIDDEN values.'),
|
|
18
21
|
output: zod_1.z
|
|
19
22
|
.object({
|
|
20
|
-
notesMarkdown: zod_1.z.string().min(1).optional().describe('Summary of work completed in THIS step only
|
|
23
|
+
notesMarkdown: zod_1.z.string().min(1).optional().describe('Summary of work completed in THIS step only — fresh and specific to this step. Do NOT append previous step notes. WorkRail concatenates notes across steps automatically. WRONG: "Phase 0: planning. Phase 1: implemented." RIGHT: "Implemented OAuth2 with 3 endpoints; added token validation middleware." Aim for ≤10 lines.'),
|
|
21
24
|
artifacts: zod_1.z.array(zod_1.z.unknown()).optional().describe('Optional structured artifacts (schema is workflow/contract-defined)'),
|
|
22
25
|
})
|
|
23
26
|
.optional()
|
|
24
|
-
.describe('
|
|
27
|
+
.describe('Durable output to attach to the current node. Only valid when intent is "advance".'),
|
|
28
|
+
}).strict().superRefine((data, ctx) => {
|
|
29
|
+
if (data.intent === 'advance' && !data.ackToken) {
|
|
30
|
+
ctx.addIssue({
|
|
31
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
32
|
+
path: ['ackToken'],
|
|
33
|
+
message: 'intent is "advance" but ackToken is missing. ' +
|
|
34
|
+
'To advance to the next step, include the ackToken from the previous start_workflow or continue_workflow response. ' +
|
|
35
|
+
'If you don\'t have an ackToken, set intent to "rehydrate" to recover the current step.',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
if (data.intent === 'rehydrate' && data.ackToken) {
|
|
39
|
+
ctx.addIssue({
|
|
40
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
41
|
+
path: ['ackToken'],
|
|
42
|
+
message: 'intent is "rehydrate" but ackToken was provided. ' +
|
|
43
|
+
'Rehydration recovers the current step without advancing — it does not accept ackToken. ' +
|
|
44
|
+
'To advance, set intent to "advance". To rehydrate, remove ackToken.',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (data.intent === 'rehydrate' && data.output) {
|
|
48
|
+
ctx.addIssue({
|
|
49
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
50
|
+
path: ['output'],
|
|
51
|
+
message: 'intent is "rehydrate" but output was provided. ' +
|
|
52
|
+
'Rehydration is read-only state recovery — it does not accept output. ' +
|
|
53
|
+
'To submit output and advance, set intent to "advance" and include ackToken.',
|
|
54
|
+
});
|
|
55
|
+
}
|
|
25
56
|
});
|
|
26
57
|
exports.V2_TOOL_TITLES = {
|
|
27
58
|
list_workflows: 'List Workflows (v2)',
|
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import { ValidationCriteria } from './validation';
|
|
2
|
+
export interface OutputContract {
|
|
3
|
+
readonly contractRef: string;
|
|
4
|
+
readonly required?: boolean;
|
|
5
|
+
}
|
|
2
6
|
export interface WorkflowStepDefinition {
|
|
3
7
|
readonly id: string;
|
|
4
8
|
readonly title: string;
|
|
@@ -9,6 +13,7 @@ export interface WorkflowStepDefinition {
|
|
|
9
13
|
readonly requireConfirmation?: boolean;
|
|
10
14
|
readonly runCondition?: Readonly<Record<string, unknown>>;
|
|
11
15
|
readonly validationCriteria?: ValidationCriteria;
|
|
16
|
+
readonly outputContract?: OutputContract;
|
|
12
17
|
readonly functionDefinitions?: readonly FunctionDefinition[];
|
|
13
18
|
readonly functionCalls?: readonly FunctionCall[];
|
|
14
19
|
readonly functionReferences?: readonly string[];
|
|
@@ -18,9 +23,18 @@ export interface LoopStepDefinition extends WorkflowStepDefinition {
|
|
|
18
23
|
readonly loop: LoopConfigDefinition;
|
|
19
24
|
readonly body: string | readonly WorkflowStepDefinition[];
|
|
20
25
|
}
|
|
26
|
+
export type LoopConditionSource = {
|
|
27
|
+
readonly kind: 'artifact_contract';
|
|
28
|
+
readonly contractRef: string;
|
|
29
|
+
readonly loopId: string;
|
|
30
|
+
} | {
|
|
31
|
+
readonly kind: 'context_variable';
|
|
32
|
+
readonly condition: Readonly<Record<string, unknown>>;
|
|
33
|
+
};
|
|
21
34
|
export interface LoopConfigDefinition {
|
|
22
35
|
readonly type: 'while' | 'until' | 'for' | 'forEach';
|
|
23
36
|
readonly condition?: Readonly<Record<string, unknown>>;
|
|
37
|
+
readonly conditionSource?: LoopConditionSource;
|
|
24
38
|
readonly items?: string;
|
|
25
39
|
readonly count?: number | string;
|
|
26
40
|
readonly maxIterations: number;
|
|
@@ -46,6 +60,10 @@ export interface FunctionCall {
|
|
|
46
60
|
readonly name: string;
|
|
47
61
|
readonly args: Readonly<Record<string, unknown>>;
|
|
48
62
|
}
|
|
63
|
+
export interface WorkflowRecommendedPreferences {
|
|
64
|
+
readonly recommendedAutonomy?: 'guided' | 'full_auto_stop_on_user_deps' | 'full_auto_never_stop';
|
|
65
|
+
readonly recommendedRiskPolicy?: 'conservative' | 'balanced' | 'aggressive';
|
|
66
|
+
}
|
|
49
67
|
export interface WorkflowDefinition {
|
|
50
68
|
readonly id: string;
|
|
51
69
|
readonly name: string;
|
|
@@ -56,6 +74,7 @@ export interface WorkflowDefinition {
|
|
|
56
74
|
readonly clarificationPrompts?: readonly string[];
|
|
57
75
|
readonly metaGuidance?: readonly string[];
|
|
58
76
|
readonly functionDefinitions?: readonly FunctionDefinition[];
|
|
77
|
+
readonly recommendedPreferences?: WorkflowRecommendedPreferences;
|
|
59
78
|
}
|
|
60
79
|
export declare function isLoopStepDefinition(step: WorkflowStepDefinition | LoopStepDefinition): step is LoopStepDefinition;
|
|
61
80
|
export declare function isWorkflowStepDefinition(step: WorkflowStepDefinition | LoopStepDefinition): step is WorkflowStepDefinition;
|
|
@@ -5,6 +5,8 @@ export declare const MAX_DECISION_TRACE_ENTRIES = 25;
|
|
|
5
5
|
export declare const MAX_DECISION_TRACE_ENTRY_SUMMARY_BYTES = 512;
|
|
6
6
|
export declare const MAX_DECISION_TRACE_TOTAL_BYTES = 8192;
|
|
7
7
|
export declare const MAX_OUTPUT_NOTES_MARKDOWN_BYTES = 4096;
|
|
8
|
+
export declare const MAX_VALIDATION_ISSUES_BYTES = 4096;
|
|
9
|
+
export declare const MAX_VALIDATION_SUGGESTIONS_BYTES = 4096;
|
|
8
10
|
export declare const MAX_CONTEXT_BYTES: number;
|
|
9
11
|
export declare const MAX_CONTEXT_DEPTH = 64;
|
|
10
12
|
export declare const MAX_OBSERVATION_SHORT_STRING_LENGTH = 80;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.DELIMITER_SAFE_ID_PATTERN = exports.SHA256_DIGEST_PATTERN = exports.RECOVERY_BUDGET_BYTES = exports.TRUNCATION_MARKER = exports.DEFAULT_RETRY_AFTER_MS = exports.SESSION_LOCK_RETRY_AFTER_MS = exports.MAX_OBSERVATION_SHORT_STRING_LENGTH = exports.MAX_CONTEXT_DEPTH = exports.MAX_CONTEXT_BYTES = exports.MAX_OUTPUT_NOTES_MARKDOWN_BYTES = exports.MAX_DECISION_TRACE_TOTAL_BYTES = exports.MAX_DECISION_TRACE_ENTRY_SUMMARY_BYTES = exports.MAX_DECISION_TRACE_ENTRIES = exports.MAX_BLOCKER_SUGGESTED_FIX_BYTES = exports.MAX_BLOCKER_MESSAGE_BYTES = exports.MAX_BLOCKERS = void 0;
|
|
3
|
+
exports.DELIMITER_SAFE_ID_PATTERN = exports.SHA256_DIGEST_PATTERN = exports.RECOVERY_BUDGET_BYTES = exports.TRUNCATION_MARKER = exports.DEFAULT_RETRY_AFTER_MS = exports.SESSION_LOCK_RETRY_AFTER_MS = exports.MAX_OBSERVATION_SHORT_STRING_LENGTH = exports.MAX_CONTEXT_DEPTH = exports.MAX_CONTEXT_BYTES = exports.MAX_VALIDATION_SUGGESTIONS_BYTES = exports.MAX_VALIDATION_ISSUES_BYTES = exports.MAX_OUTPUT_NOTES_MARKDOWN_BYTES = exports.MAX_DECISION_TRACE_TOTAL_BYTES = exports.MAX_DECISION_TRACE_ENTRY_SUMMARY_BYTES = exports.MAX_DECISION_TRACE_ENTRIES = exports.MAX_BLOCKER_SUGGESTED_FIX_BYTES = exports.MAX_BLOCKER_MESSAGE_BYTES = exports.MAX_BLOCKERS = void 0;
|
|
4
4
|
exports.MAX_BLOCKERS = 10;
|
|
5
5
|
exports.MAX_BLOCKER_MESSAGE_BYTES = 512;
|
|
6
6
|
exports.MAX_BLOCKER_SUGGESTED_FIX_BYTES = 1024;
|
|
@@ -8,6 +8,8 @@ exports.MAX_DECISION_TRACE_ENTRIES = 25;
|
|
|
8
8
|
exports.MAX_DECISION_TRACE_ENTRY_SUMMARY_BYTES = 512;
|
|
9
9
|
exports.MAX_DECISION_TRACE_TOTAL_BYTES = 8192;
|
|
10
10
|
exports.MAX_OUTPUT_NOTES_MARKDOWN_BYTES = 4096;
|
|
11
|
+
exports.MAX_VALIDATION_ISSUES_BYTES = 4096;
|
|
12
|
+
exports.MAX_VALIDATION_SUGGESTIONS_BYTES = 4096;
|
|
11
13
|
exports.MAX_CONTEXT_BYTES = 256 * 1024;
|
|
12
14
|
exports.MAX_CONTEXT_DEPTH = 64;
|
|
13
15
|
exports.MAX_OBSERVATION_SHORT_STRING_LENGTH = 80;
|
|
@@ -16,6 +16,7 @@ export declare function buildAckAdvanceAppendPlanV1(args: {
|
|
|
16
16
|
readonly outcome?: AdvanceOutcomeV1;
|
|
17
17
|
readonly extraEventsToAppend?: readonly EventToAppendV1[];
|
|
18
18
|
readonly toNodeId?: string;
|
|
19
|
+
readonly toNodeKind?: 'step' | 'blocked_attempt';
|
|
19
20
|
readonly snapshotRef?: SnapshotRef;
|
|
20
21
|
readonly causeKind?: 'intentional_fork' | 'non_tip_advance';
|
|
21
22
|
readonly minted: {
|
|
@@ -46,6 +46,12 @@ function buildAckAdvanceAppendPlanV1(args) {
|
|
|
46
46
|
}
|
|
47
47
|
const nextIndexAfterExtra = nextEventIndex + 1 + extra.length;
|
|
48
48
|
if (outcome.kind === 'blocked') {
|
|
49
|
+
if (typeof console !== 'undefined' && console.warn) {
|
|
50
|
+
console.warn('[DEPRECATED] Creating advance_recorded with blocked outcome. ' +
|
|
51
|
+
'Use blocked_attempt nodes instead (see ADR 008). ' +
|
|
52
|
+
'This path will be removed in 2 releases. ' +
|
|
53
|
+
'Set USE_BLOCKED_NODES=true to use the new model.');
|
|
54
|
+
}
|
|
49
55
|
if (outputsToAppend && outputsToAppend.length > 0) {
|
|
50
56
|
return (0, neverthrow_1.err)({
|
|
51
57
|
code: 'INVARIANT_VIOLATION',
|
|
@@ -72,8 +78,12 @@ function buildAckAdvanceAppendPlanV1(args) {
|
|
|
72
78
|
const toNodeId = args.toNodeId;
|
|
73
79
|
const snapshotRef = args.snapshotRef;
|
|
74
80
|
const causeKind = args.causeKind;
|
|
81
|
+
const toNodeKind = args.toNodeKind ?? 'step';
|
|
75
82
|
const nodeCreatedEventIndex = nextIndexAfterExtra;
|
|
76
83
|
const edgeCreatedEventIndex = nextIndexAfterExtra + 1;
|
|
84
|
+
if (toNodeKind !== 'step' && toNodeKind !== 'blocked_attempt') {
|
|
85
|
+
return (0, neverthrow_1.err)({ code: 'INVARIANT_VIOLATION', message: 'toNodeKind must be step|blocked_attempt' });
|
|
86
|
+
}
|
|
77
87
|
const advancedEvents = [
|
|
78
88
|
{
|
|
79
89
|
v: 1,
|
|
@@ -84,7 +94,7 @@ function buildAckAdvanceAppendPlanV1(args) {
|
|
|
84
94
|
dedupeKey: `node_created:${sessionId}:${runId}:${toNodeId}`,
|
|
85
95
|
scope: { runId, nodeId: toNodeId },
|
|
86
96
|
data: {
|
|
87
|
-
nodeKind:
|
|
97
|
+
nodeKind: toNodeKind,
|
|
88
98
|
parentNodeId: fromNodeId,
|
|
89
99
|
workflowHash,
|
|
90
100
|
snapshotRef,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Result } from 'neverthrow';
|
|
2
|
+
import type { OutputContract } from '../../../types/workflow-definition.js';
|
|
3
|
+
export type ArtifactContractValidationError = {
|
|
4
|
+
readonly code: 'MISSING_REQUIRED_ARTIFACT';
|
|
5
|
+
readonly contractRef: string;
|
|
6
|
+
readonly message: string;
|
|
7
|
+
} | {
|
|
8
|
+
readonly code: 'INVALID_ARTIFACT_SCHEMA';
|
|
9
|
+
readonly contractRef: string;
|
|
10
|
+
readonly message: string;
|
|
11
|
+
readonly issues: readonly string[];
|
|
12
|
+
} | {
|
|
13
|
+
readonly code: 'UNKNOWN_CONTRACT_REF';
|
|
14
|
+
readonly contractRef: string;
|
|
15
|
+
readonly message: string;
|
|
16
|
+
};
|
|
17
|
+
export type ArtifactContractValidationResult = {
|
|
18
|
+
readonly valid: true;
|
|
19
|
+
readonly artifact: unknown;
|
|
20
|
+
} | {
|
|
21
|
+
readonly valid: false;
|
|
22
|
+
readonly error: ArtifactContractValidationError;
|
|
23
|
+
};
|
|
24
|
+
export declare function validateArtifactContract(artifacts: readonly unknown[], contract: OutputContract): ArtifactContractValidationResult;
|
|
25
|
+
export declare function requiresArtifactValidation(outputContract: OutputContract | undefined): boolean;
|
|
26
|
+
export declare function formatArtifactValidationError(error: ArtifactContractValidationError): {
|
|
27
|
+
readonly code: string;
|
|
28
|
+
readonly message: string;
|
|
29
|
+
readonly suggestedFix?: string;
|
|
30
|
+
};
|
|
31
|
+
export declare function extractValidatedArtifact(artifacts: readonly unknown[], contract: OutputContract): Result<unknown, ArtifactContractValidationError>;
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.validateArtifactContract = validateArtifactContract;
|
|
4
|
+
exports.requiresArtifactValidation = requiresArtifactValidation;
|
|
5
|
+
exports.formatArtifactValidationError = formatArtifactValidationError;
|
|
6
|
+
exports.extractValidatedArtifact = extractValidatedArtifact;
|
|
7
|
+
const neverthrow_1 = require("neverthrow");
|
|
8
|
+
const index_js_1 = require("../schemas/artifacts/index.js");
|
|
9
|
+
function validateArtifactContract(artifacts, contract) {
|
|
10
|
+
const { contractRef, required = true } = contract;
|
|
11
|
+
if (!(0, index_js_1.isValidContractRef)(contractRef)) {
|
|
12
|
+
return {
|
|
13
|
+
valid: false,
|
|
14
|
+
error: {
|
|
15
|
+
code: 'UNKNOWN_CONTRACT_REF',
|
|
16
|
+
contractRef,
|
|
17
|
+
message: `Unknown artifact contract reference: ${contractRef}`,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
switch (contractRef) {
|
|
22
|
+
case index_js_1.LOOP_CONTROL_CONTRACT_REF:
|
|
23
|
+
return validateLoopControlContract(artifacts, contractRef, required);
|
|
24
|
+
default:
|
|
25
|
+
return {
|
|
26
|
+
valid: false,
|
|
27
|
+
error: {
|
|
28
|
+
code: 'UNKNOWN_CONTRACT_REF',
|
|
29
|
+
contractRef,
|
|
30
|
+
message: `No validator implemented for contract: ${contractRef}`,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function validateLoopControlContract(artifacts, contractRef, required) {
|
|
36
|
+
const loopControlArtifacts = artifacts.filter(index_js_1.isLoopControlArtifact);
|
|
37
|
+
if (loopControlArtifacts.length === 0) {
|
|
38
|
+
if (required) {
|
|
39
|
+
return {
|
|
40
|
+
valid: false,
|
|
41
|
+
error: {
|
|
42
|
+
code: 'MISSING_REQUIRED_ARTIFACT',
|
|
43
|
+
contractRef,
|
|
44
|
+
message: `Required artifact missing: ${contractRef}. Agent must provide an artifact with kind='wr.loop_control'.`,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return { valid: true, artifact: null };
|
|
49
|
+
}
|
|
50
|
+
const artifact = loopControlArtifacts[0];
|
|
51
|
+
const parseResult = index_js_1.LoopControlArtifactV1Schema.safeParse(artifact);
|
|
52
|
+
if (!parseResult.success) {
|
|
53
|
+
const issues = parseResult.error.issues.map(issue => `${issue.path.join('.')}: ${issue.message}`);
|
|
54
|
+
return {
|
|
55
|
+
valid: false,
|
|
56
|
+
error: {
|
|
57
|
+
code: 'INVALID_ARTIFACT_SCHEMA',
|
|
58
|
+
contractRef,
|
|
59
|
+
message: `Artifact schema validation failed for ${contractRef}`,
|
|
60
|
+
issues,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return { valid: true, artifact: parseResult.data };
|
|
65
|
+
}
|
|
66
|
+
function requiresArtifactValidation(outputContract) {
|
|
67
|
+
if (!outputContract)
|
|
68
|
+
return false;
|
|
69
|
+
return outputContract.required !== false;
|
|
70
|
+
}
|
|
71
|
+
function formatArtifactValidationError(error) {
|
|
72
|
+
switch (error.code) {
|
|
73
|
+
case 'MISSING_REQUIRED_ARTIFACT':
|
|
74
|
+
return {
|
|
75
|
+
code: 'MISSING_REQUIRED_OUTPUT',
|
|
76
|
+
message: error.message,
|
|
77
|
+
suggestedFix: `Provide an artifact with kind matching the contract: ${error.contractRef}`,
|
|
78
|
+
};
|
|
79
|
+
case 'INVALID_ARTIFACT_SCHEMA':
|
|
80
|
+
return {
|
|
81
|
+
code: 'INVALID_REQUIRED_OUTPUT',
|
|
82
|
+
message: `${error.message}: ${error.issues.join('; ')}`,
|
|
83
|
+
suggestedFix: `Fix the artifact schema errors and retry`,
|
|
84
|
+
};
|
|
85
|
+
case 'UNKNOWN_CONTRACT_REF':
|
|
86
|
+
return {
|
|
87
|
+
code: 'INVARIANT_VIOLATION',
|
|
88
|
+
message: error.message,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
function extractValidatedArtifact(artifacts, contract) {
|
|
93
|
+
const result = validateArtifactContract(artifacts, contract);
|
|
94
|
+
if (result.valid) {
|
|
95
|
+
return (0, neverthrow_1.ok)(result.artifact);
|
|
96
|
+
}
|
|
97
|
+
return (0, neverthrow_1.err)(result.error);
|
|
98
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Result } from 'neverthrow';
|
|
2
|
+
import type { Sha256PortV2 } from '../../ports/sha256.port.js';
|
|
3
|
+
import type { AttemptId } from '../ids/index.js';
|
|
4
|
+
import type { ExecutionSnapshotFileV1 } from '../schemas/execution-snapshot/index.js';
|
|
5
|
+
import type { BlockerReportV1, ReasonV1 } from './reason-model.js';
|
|
6
|
+
export type BlockedNodeBuildError = {
|
|
7
|
+
readonly code: 'BLOCKED_NODE_INVARIANT_VIOLATION';
|
|
8
|
+
readonly message: string;
|
|
9
|
+
} | {
|
|
10
|
+
readonly code: 'BLOCKED_NODE_UNSUPPORTED_STATE';
|
|
11
|
+
readonly message: string;
|
|
12
|
+
};
|
|
13
|
+
export declare function buildBlockedNodeSnapshot(args: {
|
|
14
|
+
readonly priorSnapshot: ExecutionSnapshotFileV1;
|
|
15
|
+
readonly primaryReason: ReasonV1;
|
|
16
|
+
readonly attemptId: AttemptId;
|
|
17
|
+
readonly validationRef: string;
|
|
18
|
+
readonly blockers: BlockerReportV1;
|
|
19
|
+
readonly sha256: Sha256PortV2;
|
|
20
|
+
}): Result<ExecutionSnapshotFileV1, BlockedNodeBuildError>;
|