@exaudeus/workrail 3.27.0 → 3.29.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/console/assets/{index-FtTaDku8.js → index-BZ6HkxGf.js} +1 -1
- package/dist/console/index.html +1 -1
- package/dist/manifest.json +3 -3
- package/docs/README.md +57 -0
- package/docs/adrs/001-hybrid-storage-backend.md +38 -0
- package/docs/adrs/002-four-layer-context-classification.md +38 -0
- package/docs/adrs/003-checkpoint-trigger-strategy.md +35 -0
- package/docs/adrs/004-opt-in-encryption-strategy.md +36 -0
- package/docs/adrs/005-agent-first-workflow-execution-tokens.md +105 -0
- package/docs/adrs/006-append-only-session-run-event-log.md +76 -0
- package/docs/adrs/007-resume-and-checkpoint-only-sessions.md +51 -0
- package/docs/adrs/008-blocked-nodes-architectural-upgrade.md +178 -0
- package/docs/adrs/009-bridge-mode-single-instance-mcp.md +195 -0
- package/docs/adrs/010-release-pipeline.md +89 -0
- package/docs/architecture/README.md +7 -0
- package/docs/architecture/refactor-audit.md +364 -0
- package/docs/authoring-v2.md +527 -0
- package/docs/authoring.md +873 -0
- package/docs/changelog-recent.md +201 -0
- package/docs/configuration.md +505 -0
- package/docs/ctc-mcp-proposal.md +518 -0
- package/docs/design/README.md +22 -0
- package/docs/design/agent-cascade-protocol.md +96 -0
- package/docs/design/autonomous-console-design-candidates.md +253 -0
- package/docs/design/autonomous-console-design-review.md +111 -0
- package/docs/design/autonomous-platform-mvp-discovery.md +525 -0
- package/docs/design/claude-code-source-deep-dive.md +713 -0
- package/docs/design/console-cyberpunk-ui-discovery.md +504 -0
- package/docs/design/console-execution-trace-candidates-final.md +160 -0
- package/docs/design/console-execution-trace-candidates.md +211 -0
- package/docs/design/console-execution-trace-design-candidates-v2.md +113 -0
- package/docs/design/console-execution-trace-design-review.md +74 -0
- package/docs/design/console-execution-trace-discovery.md +394 -0
- package/docs/design/console-execution-trace-final-review.md +77 -0
- package/docs/design/console-execution-trace-review.md +92 -0
- package/docs/design/console-performance-discovery.md +415 -0
- package/docs/design/console-ui-backlog.md +280 -0
- package/docs/design/daemon-architecture-discovery.md +853 -0
- package/docs/design/daemon-design-candidates.md +318 -0
- package/docs/design/daemon-design-review-findings.md +119 -0
- package/docs/design/daemon-engine-design-candidates.md +210 -0
- package/docs/design/daemon-engine-design-review.md +131 -0
- package/docs/design/daemon-execution-engine-discovery.md +280 -0
- package/docs/design/daemon-gap-analysis.md +554 -0
- package/docs/design/daemon-owns-console-plan.md +168 -0
- package/docs/design/daemon-owns-console-review.md +91 -0
- package/docs/design/daemon-owns-console.md +195 -0
- package/docs/design/data-model-erd.md +11 -0
- package/docs/design/design-candidates-consolidate-dev-staleness.md +98 -0
- package/docs/design/design-candidates-walk-cache-depth-limit.md +80 -0
- package/docs/design/design-review-consolidate-dev-staleness.md +54 -0
- package/docs/design/design-review-walk-cache-depth-limit.md +48 -0
- package/docs/design/implementation-plan-consolidate-dev-staleness.md +142 -0
- package/docs/design/implementation-plan-walk-cache-depth-limit.md +141 -0
- package/docs/design/layer3b-ghost-nodes-design-candidates.md +229 -0
- package/docs/design/layer3b-ghost-nodes-design-review.md +93 -0
- package/docs/design/layer3b-ghost-nodes-implementation-plan.md +219 -0
- package/docs/design/list-workflows-latency-fix-plan.md +128 -0
- package/docs/design/list-workflows-latency-fix-review.md +55 -0
- package/docs/design/list-workflows-latency-fix.md +109 -0
- package/docs/design/native-context-management-api.md +11 -0
- package/docs/design/performance-sweep-2026-04.md +96 -0
- package/docs/design/routines-guide.md +219 -0
- package/docs/design/sequence-diagrams.md +11 -0
- package/docs/design/subagent-design-principles.md +220 -0
- package/docs/design/temporal-patterns-design-candidates.md +312 -0
- package/docs/design/temporal-patterns-design-review-findings.md +163 -0
- package/docs/design/test-isolation-from-config-file.md +335 -0
- package/docs/design/v2-core-design-locks.md +2746 -0
- package/docs/design/v2-lock-registry.json +734 -0
- package/docs/design/workflow-authoring-v2.md +1044 -0
- package/docs/design/workflow-docs-spec.md +218 -0
- package/docs/design/workflow-extension-points.md +687 -0
- package/docs/design/workrail-auto-trigger-system.md +359 -0
- package/docs/design/workrail-config-file-discovery.md +513 -0
- package/docs/docker.md +110 -0
- package/docs/generated/v2-lock-closure-plan.md +26 -0
- package/docs/generated/v2-lock-coverage.json +797 -0
- package/docs/generated/v2-lock-coverage.md +177 -0
- package/docs/ideas/backlog.md +3927 -0
- package/docs/ideas/design-candidates-mcp-resilience.md +208 -0
- package/docs/ideas/design-review-findings-mcp-resilience.md +119 -0
- package/docs/ideas/implementation_plan.md +249 -0
- package/docs/ideas/third-party-workflow-setup-design-thinking.md +1948 -0
- package/docs/implementation/02-architecture.md +316 -0
- package/docs/implementation/04-testing-strategy.md +124 -0
- package/docs/implementation/09-simple-workflow-guide.md +835 -0
- package/docs/implementation/13-advanced-validation-guide.md +874 -0
- package/docs/implementation/README.md +21 -0
- package/docs/integrations/claude-code.md +300 -0
- package/docs/integrations/firebender.md +315 -0
- package/docs/migration/v0.1.0.md +147 -0
- package/docs/naming-conventions.md +45 -0
- package/docs/planning/README.md +104 -0
- package/docs/planning/github-ticketing-playbook.md +195 -0
- package/docs/plans/README.md +24 -0
- package/docs/plans/agent-managed-ticketing-design.md +605 -0
- package/docs/plans/agentic-orchestration-roadmap.md +112 -0
- package/docs/plans/assessment-gates-engine-handoff.md +536 -0
- package/docs/plans/content-coherence-and-references.md +151 -0
- package/docs/plans/library-extraction-plan.md +340 -0
- package/docs/plans/mr-review-workflow-redesign.md +1451 -0
- package/docs/plans/native-context-management-epic.md +11 -0
- package/docs/plans/perf-fixes-design-candidates.md +225 -0
- package/docs/plans/perf-fixes-design-review-findings.md +61 -0
- package/docs/plans/perf-fixes-new-issues-candidates.md +264 -0
- package/docs/plans/perf-fixes-new-issues-review.md +110 -0
- package/docs/plans/prompt-fragments.md +53 -0
- package/docs/plans/ui-ux-workflow-design-candidates.md +120 -0
- package/docs/plans/ui-ux-workflow-discovery.md +100 -0
- package/docs/plans/ui-ux-workflow-review.md +48 -0
- package/docs/plans/v2-followup-enhancements.md +587 -0
- package/docs/plans/workflow-categories-candidates.md +105 -0
- package/docs/plans/workflow-categories-discovery.md +110 -0
- package/docs/plans/workflow-categories-review.md +51 -0
- package/docs/plans/workflow-discovery-model-candidates.md +94 -0
- package/docs/plans/workflow-discovery-model-discovery.md +74 -0
- package/docs/plans/workflow-discovery-model-review.md +48 -0
- package/docs/plans/workflow-source-setup-phase-1.md +245 -0
- package/docs/plans/workflow-source-setup-phase-2.md +361 -0
- package/docs/plans/workflow-staleness-detection-candidates.md +104 -0
- package/docs/plans/workflow-staleness-detection-review.md +58 -0
- package/docs/plans/workflow-staleness-detection.md +80 -0
- package/docs/plans/workflow-v2-design.md +69 -0
- package/docs/plans/workflow-v2-roadmap.md +74 -0
- package/docs/plans/workflow-validation-design.md +98 -0
- package/docs/plans/workflow-validation-roadmap.md +108 -0
- package/docs/plans/workrail-platform-vision.md +420 -0
- package/docs/reference/agent-context-cleaner-snippet.md +94 -0
- package/docs/reference/agent-context-guidance.md +140 -0
- package/docs/reference/context-optimization.md +284 -0
- package/docs/reference/example-workflow-repository-template/.github/workflows/validate.yml +125 -0
- package/docs/reference/example-workflow-repository-template/README.md +268 -0
- package/docs/reference/example-workflow-repository-template/workflows/example-workflow.json +80 -0
- package/docs/reference/external-workflow-repositories.md +916 -0
- package/docs/reference/feature-flags-architecture.md +472 -0
- package/docs/reference/feature-flags.md +349 -0
- package/docs/reference/god-tier-workflow-validation.md +272 -0
- package/docs/reference/loop-optimization.md +209 -0
- package/docs/reference/loop-validation.md +176 -0
- package/docs/reference/loops.md +465 -0
- package/docs/reference/mcp-platform-constraints.md +59 -0
- package/docs/reference/recovery.md +88 -0
- package/docs/reference/releases.md +177 -0
- package/docs/reference/troubleshooting.md +105 -0
- package/docs/reference/workflow-execution-contract.md +998 -0
- package/docs/roadmap/README.md +22 -0
- package/docs/roadmap/legacy-planning-status.md +103 -0
- package/docs/roadmap/now-next-later.md +70 -0
- package/docs/roadmap/open-work-inventory.md +389 -0
- package/docs/tickets/README.md +39 -0
- package/docs/tickets/next-up.md +76 -0
- package/docs/workflow-management.md +317 -0
- package/docs/workflow-templates.md +423 -0
- package/docs/workflow-validation.md +184 -0
- package/docs/workflows.md +254 -0
- package/package.json +3 -1
- package/spec/authoring-spec.json +61 -16
- package/workflows/workflow-for-workflows.json +252 -93
- package/workflows/workflow-for-workflows.v2.json +188 -77
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
# WorkRail Library Extraction Plan
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
|
|
5
|
+
Expose WorkRail's v2 workflow engine as an in-process library callable without MCP, transport, or tool abstractions. The first consumer is etienne-clone (MR review bot), but the API should be generic enough for any system that embeds workflow execution.
|
|
6
|
+
|
|
7
|
+
## Non-goals
|
|
8
|
+
|
|
9
|
+
- No workflow redesign
|
|
10
|
+
- No context injection / prompt templating
|
|
11
|
+
- No parallel steps
|
|
12
|
+
- No new workflow schema features
|
|
13
|
+
- No removal of the existing MCP surface (it stays, built on top of the same engine)
|
|
14
|
+
|
|
15
|
+
## Current architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
MCP client (agent)
|
|
19
|
+
|
|
|
20
|
+
v
|
|
21
|
+
MCP JSON-RPC transport (stdio / HTTP)
|
|
22
|
+
|
|
|
23
|
+
v
|
|
24
|
+
Tool registry (tool-registry.ts) — routes tool calls
|
|
25
|
+
|
|
|
26
|
+
v
|
|
27
|
+
MCP handler layer (v2-execution/index.ts)
|
|
28
|
+
- handleV2StartWorkflow(input, ctx: ToolContext) → ToolResult
|
|
29
|
+
- handleV2ContinueWorkflow(input, ctx: ToolContext) → ToolResult
|
|
30
|
+
- handleV2CheckpointWorkflow(input, ctx: ToolContext) → ToolResult
|
|
31
|
+
- handleV2ResumeSession(input, ctx: ToolContext) → ToolResult
|
|
32
|
+
|
|
|
33
|
+
v
|
|
34
|
+
Execution functions (pure logic, returns ResultAsync)
|
|
35
|
+
- executeStartWorkflow(input, ctx: V2ToolContext) → ResultAsync<Output, Error>
|
|
36
|
+
- executeContinueWorkflow(input, ctx: V2ToolContext) → ResultAsync<Output, Error>
|
|
37
|
+
- executeCheckpoint(input, ctx: V2ToolContext) → ResultAsync<Output, Error>
|
|
38
|
+
|
|
|
39
|
+
v
|
|
40
|
+
Engine internals (prompt-renderer, blocking-decision, durable-core, tokens, etc.)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Key observation
|
|
44
|
+
|
|
45
|
+
The execution functions (`executeStartWorkflow`, etc.) are already decoupled from MCP. They take typed inputs and a `V2ToolContext`, return `ResultAsync`. The MCP handler layer is a thin adapter that:
|
|
46
|
+
1. Calls `requireV2Context(ctx)` to narrow the type
|
|
47
|
+
2. Calls the execution function
|
|
48
|
+
3. Maps the result to `ToolResult` (success/error)
|
|
49
|
+
|
|
50
|
+
The library extraction targets the execution function layer, bypassing the MCP handler and tool registry entirely.
|
|
51
|
+
|
|
52
|
+
## What a library consumer calls today (via MCP)
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
bot → HTTP → MCP JSON-RPC → tool handler → executeStartWorkflow(input, V2ToolContext)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## What a library consumer would call
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
bot → engine.startWorkflow(workflowId) → typed result
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
No HTTP. No JSON-RPC. No tool routing. No ToolResult wrapping.
|
|
65
|
+
|
|
66
|
+
## Integration points verified
|
|
67
|
+
|
|
68
|
+
### Inputs to execution functions
|
|
69
|
+
|
|
70
|
+
| Function | Input type | Fields |
|
|
71
|
+
|----------|-----------|--------|
|
|
72
|
+
| `executeStartWorkflow` | `V2StartWorkflowInput` | `workflowId: string`, `workspacePath?: string` |
|
|
73
|
+
| `executeContinueWorkflow` | `V2ContinueWorkflowInput` | `stateToken`, `ackToken?`, `intent`, `context?`, `output?` |
|
|
74
|
+
| `handleV2CheckpointWorkflow` | `V2CheckpointWorkflowInput` | `checkpointToken: string` |
|
|
75
|
+
| `handleV2ResumeSession` | `V2ResumeSessionInput` | `query?`, `gitBranch?`, `gitHeadSha?`, `workspacePath?` |
|
|
76
|
+
|
|
77
|
+
### Dependencies (V2ToolContext)
|
|
78
|
+
|
|
79
|
+
`V2ToolContext` = `ToolContext` narrowed to guarantee `v2: V2Dependencies` is non-null.
|
|
80
|
+
|
|
81
|
+
**ToolContext fields:**
|
|
82
|
+
- `workflowService: WorkflowService` — used by `executeStartWorkflow` to load workflows
|
|
83
|
+
- `featureFlags: IFeatureFlagProvider` — checked at boundary (not in execution functions)
|
|
84
|
+
- `sessionManager` / `httpServer` — not used by v2 execution functions
|
|
85
|
+
- `v2: V2Dependencies` — the core engine dependency bag
|
|
86
|
+
|
|
87
|
+
**V2Dependencies fields (all required for execution):**
|
|
88
|
+
- `gate: ExecutionSessionGateV2` — session locking
|
|
89
|
+
- `sessionStore` — append-only event log (read + write)
|
|
90
|
+
- `snapshotStore` — execution snapshots
|
|
91
|
+
- `pinnedStore` — content-addressed workflow snapshots
|
|
92
|
+
- `sha256` / `crypto` — hashing
|
|
93
|
+
- `idFactory` — ID generation (session, run, node, event IDs)
|
|
94
|
+
- `tokenCodecPorts` — token encode/decode/sign/verify (grouped: keyring, hmac, base64url, base32, bech32m)
|
|
95
|
+
- `validationPipelineDeps` — Phase 1a validation (schema, structural, compilation, normalization)
|
|
96
|
+
|
|
97
|
+
**V2Dependencies fields (optional, used by resume/workspace):**
|
|
98
|
+
- `resolvedRootUris?` — MCP client roots (not needed for library)
|
|
99
|
+
- `workspaceResolver?` — workspace identity (git branch/SHA detection)
|
|
100
|
+
- `dataDir?` / `directoryListing?` — session enumeration for resume
|
|
101
|
+
- `sessionSummaryProvider?` — resume session ranking
|
|
102
|
+
|
|
103
|
+
### DI construction graph
|
|
104
|
+
|
|
105
|
+
The V2Dependencies bag is constructed in `server.ts:createToolContext()` using the DI container. The container registers ~20 services across 3 levels:
|
|
106
|
+
|
|
107
|
+
**Level 1 (primitives, no deps):**
|
|
108
|
+
- `LocalDataDirV2(process.env)` — resolves `~/.workrail/v2`
|
|
109
|
+
- `NodeFileSystemV2()` — fs read/write
|
|
110
|
+
- `NodeSha256V2()`, `NodeCryptoV2()`, `NodeHmacSha256V2()` — crypto
|
|
111
|
+
- `NodeBase64UrlV2()`, `Base32AdapterV2()`, `Bech32mAdapterV2()` — encoding
|
|
112
|
+
- `NodeRandomEntropyV2()`, `NodeTimeClockV2()` — randomness, time
|
|
113
|
+
- `IdFactoryV2(entropy)` — ID minting
|
|
114
|
+
|
|
115
|
+
**Level 2 (stores, depend on Level 1):**
|
|
116
|
+
- `LocalKeyringV2(dataDir, fs, base64url, entropy)` — HMAC key management
|
|
117
|
+
- `LocalSessionEventLogStoreV2(dataDir, fs, sha256)` — session event log
|
|
118
|
+
- `LocalSnapshotStoreV2(dataDir, fs, crypto)` — execution snapshots
|
|
119
|
+
- `LocalPinnedWorkflowStoreV2(dataDir, fs)` — pinned workflow definitions
|
|
120
|
+
- `LocalSessionLockV2(dataDir, fs, clock)` — session locking
|
|
121
|
+
|
|
122
|
+
**Level 3 (orchestration):**
|
|
123
|
+
- `ExecutionSessionGateV2(lock, store)` — health-checked session access
|
|
124
|
+
|
|
125
|
+
**WorkflowService deps (separate from V2):**
|
|
126
|
+
- `WorkflowService` depends on storage (Primary), `ValidationEngine`, `WorkflowCompiler`, `WorkflowInterpreter`
|
|
127
|
+
- Storage is a 3-layer chain: `EnhancedMultiSourceWorkflowStorage` → `SchemaValidatingWorkflowStorage` → `CachingWorkflowStorage`
|
|
128
|
+
|
|
129
|
+
**Validation pipeline deps (subset used by start_workflow):**
|
|
130
|
+
- `schemaValidate` — AJV schema validator
|
|
131
|
+
- `structuralValidate` — `ValidationEngine.validateWorkflowStructureOnly()`
|
|
132
|
+
- `compiler` — `WorkflowCompiler` instance
|
|
133
|
+
- `normalizeToExecutable` — `normalizeV1WorkflowToPinnedSnapshot` function
|
|
134
|
+
|
|
135
|
+
### Token codec construction
|
|
136
|
+
|
|
137
|
+
Tokens require a loaded keyring. The keyring is loaded once at startup (`keyringPort.loadOrCreate()`), then the `unsafeTokenCodecPorts()` factory groups all encoding ports:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
const tokenCodecPorts = unsafeTokenCodecPorts({
|
|
141
|
+
keyring: keyringResult.value, // loaded HMAC keys
|
|
142
|
+
hmac, // NodeHmacSha256V2
|
|
143
|
+
base64url, // NodeBase64UrlV2
|
|
144
|
+
base32, // Base32AdapterV2
|
|
145
|
+
bech32m, // Bech32mAdapterV2
|
|
146
|
+
});
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## agentRole enhancement
|
|
150
|
+
|
|
151
|
+
`agentRole` is defined on `WorkflowStepDefinition` and available in `prompt-renderer.ts` via `getStepById()`. Currently not returned in the response.
|
|
152
|
+
|
|
153
|
+
### Changes needed
|
|
154
|
+
|
|
155
|
+
1. `StepMetadata` in `prompt-renderer.ts` (line 319): add `readonly agentRole?: string`
|
|
156
|
+
2. `renderPendingPrompt()` (line 451, 457, 481, 489): include `agentRole: step.agentRole` in return value
|
|
157
|
+
3. `V2PendingStepSchema` in `output-schemas.ts` (line 102): add `agentRole: z.string().optional()`
|
|
158
|
+
4. Response construction — 5 sites that build `pending` from `meta`:
|
|
159
|
+
- `start.ts:448` — `const pending = { stepId: meta.stepId, title: meta.title, prompt: meta.prompt }`
|
|
160
|
+
- `continue-rehydrate.ts:185` — same pattern
|
|
161
|
+
- `replay.ts:91, 213, 253` — same pattern (3 sites)
|
|
162
|
+
5. Contract tests — update schema expectations for `agentRole` optional field
|
|
163
|
+
|
|
164
|
+
This is a ~15 line change across 4 files + contract tests. Note: `continue-advance.ts` delegates to `replay.ts`, so it doesn't need direct changes.
|
|
165
|
+
|
|
166
|
+
## etienne-clone compatibility (verified)
|
|
167
|
+
|
|
168
|
+
etienne-clone already has a `WorkRailClient` interface in `src/clients/workrail.ts` that matches almost exactly what the library API should expose:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
// etienne-clone's existing interface (clients/workrail.ts)
|
|
172
|
+
interface WorkRailClient {
|
|
173
|
+
readonly startWorkflow: (workflowId: string) => Promise<Result<WorkflowStepResponse, WorkRailError>>;
|
|
174
|
+
readonly continueWorkflow: (stateToken, ackToken, output) => Promise<Result<WorkflowStepResponse, WorkRailError>>;
|
|
175
|
+
readonly listWorkflows: () => Promise<Result<WorkflowListResponse, WorkRailError>>;
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The library API should match this shape so etienne-clone can swap `createWorkRailClient(config)` (HTTP) for `createWorkRailEngine(config)` (in-process) with minimal changes. The main difference: `WorkRailError` becomes `EngineError` (no `connection_failed`, `timeout`, `session_expired` — those are transport errors).
|
|
180
|
+
|
|
181
|
+
The `PendingStep` type in etienne-clone is `{ stepId, title, prompt }` — once `agentRole` ships, the bot can use it as the LLM's system prompt per step, rather than using a static system prompt for the whole review.
|
|
182
|
+
|
|
183
|
+
## Library API design
|
|
184
|
+
|
|
185
|
+
### Entry point
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
// src/engine/index.ts (new file, library entry point)
|
|
189
|
+
export { createWorkRailEngine } from './engine-factory.js';
|
|
190
|
+
export type { WorkRailEngine, EngineConfig } from './types.js';
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Config
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
interface EngineConfig {
|
|
197
|
+
// Where to store durable state (sessions, snapshots, keyring)
|
|
198
|
+
// Default: ~/.workrail/v2
|
|
199
|
+
readonly dataDir?: string;
|
|
200
|
+
|
|
201
|
+
// Workflow sources (bundled, filesystem, git, etc.)
|
|
202
|
+
// Default: bundled workflows only
|
|
203
|
+
readonly workflowSources?: readonly WorkflowSource[];
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Engine interface
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
interface WorkRailEngine {
|
|
211
|
+
// Start a workflow, get the first step
|
|
212
|
+
readonly startWorkflow: (workflowId: string) => Promise<EngineResult<StepResponse>>;
|
|
213
|
+
|
|
214
|
+
// Advance to next step (ackToken present) or rehydrate (ackToken absent)
|
|
215
|
+
readonly continueWorkflow: (
|
|
216
|
+
stateToken: string,
|
|
217
|
+
ackToken: string | null,
|
|
218
|
+
output?: { notesMarkdown?: string; artifacts?: unknown[] },
|
|
219
|
+
) => Promise<EngineResult<StepResponse>>;
|
|
220
|
+
|
|
221
|
+
// Checkpoint without advancing
|
|
222
|
+
readonly checkpointWorkflow: (checkpointToken: string) => Promise<EngineResult<CheckpointResponse>>;
|
|
223
|
+
|
|
224
|
+
// List available workflows
|
|
225
|
+
readonly listWorkflows: () => Promise<EngineResult<WorkflowListResponse>>;
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Response types
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// Branded token types — compile-time safety against token misuse
|
|
233
|
+
type StateToken = string & { readonly [StateTokenBrand]: never };
|
|
234
|
+
type AckToken = string & { readonly [AckTokenBrand]: never };
|
|
235
|
+
type CheckpointToken = string & { readonly [CheckpointTokenBrand]: never };
|
|
236
|
+
|
|
237
|
+
// Discriminated union: ok | blocked (illegal states unrepresentable)
|
|
238
|
+
type StepResponse = StepResponseOk | StepResponseBlocked;
|
|
239
|
+
|
|
240
|
+
interface StepResponseOk extends StepResponseBase {
|
|
241
|
+
readonly kind: 'ok';
|
|
242
|
+
readonly pending: PendingStep | null;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
interface StepResponseBlocked extends StepResponseBase {
|
|
246
|
+
readonly kind: 'blocked';
|
|
247
|
+
readonly pending: PendingStep | null;
|
|
248
|
+
readonly blockers: readonly Blocker[];
|
|
249
|
+
readonly retryable: boolean;
|
|
250
|
+
readonly retryAckToken: AckToken | null;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// Typed error variants with domain-specific payloads (errors as data)
|
|
254
|
+
type EngineError =
|
|
255
|
+
| { readonly kind: 'workflow_not_found'; readonly workflowId: string }
|
|
256
|
+
| { readonly kind: 'workflow_has_no_steps'; readonly workflowId: string }
|
|
257
|
+
| { readonly kind: 'workflow_compile_failed'; readonly message: string }
|
|
258
|
+
| { readonly kind: 'validation_failed'; readonly message: string }
|
|
259
|
+
| { readonly kind: 'token_invalid'; readonly message: string }
|
|
260
|
+
| { readonly kind: 'token_signing_failed'; readonly message: string }
|
|
261
|
+
| { readonly kind: 'session_error'; readonly message: string }
|
|
262
|
+
| { readonly kind: 'storage_error'; readonly message: string }
|
|
263
|
+
| { readonly kind: 'prompt_render_failed'; readonly message: string }
|
|
264
|
+
| { readonly kind: 'precondition_failed'; readonly message: string }
|
|
265
|
+
| { readonly kind: 'internal_error'; readonly message: string };
|
|
266
|
+
|
|
267
|
+
type EngineResult<T> =
|
|
268
|
+
| { readonly ok: true; readonly value: T }
|
|
269
|
+
| { readonly ok: false; readonly error: EngineError };
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### Factory implementation strategy — DECIDED
|
|
273
|
+
|
|
274
|
+
**Chosen: DI container with library runtime mode.** The services used by execution functions use `@singleton()` and `@inject()` decorators from `tsyringe`, which require `reflect-metadata` and the global container. Manual wiring is not viable without decoupling the services from decorators first.
|
|
275
|
+
|
|
276
|
+
The factory calls `initializeContainer({ runtimeMode: { kind: 'library' } })` which:
|
|
277
|
+
- Skips signal handlers and process lifecycle management
|
|
278
|
+
- Uses `ThrowingProcessTerminator` (same as test mode)
|
|
279
|
+
- Registers all storage, services, and v2 primitives identically to production
|
|
280
|
+
- Does NOT start HTTP server, MCP transport, or session tools
|
|
281
|
+
|
|
282
|
+
Long-term: DI-free service wrappers remain the ideal (no global state, no reflect-metadata) but require a larger refactor that shouldn't block library v1.
|
|
283
|
+
|
|
284
|
+
## Implementation slices
|
|
285
|
+
|
|
286
|
+
### Slice 1: agentRole in step responses (smallest, immediate value) — DONE
|
|
287
|
+
|
|
288
|
+
**Files changed:**
|
|
289
|
+
- `src/v2/durable-core/domain/prompt-renderer.ts` — added `agentRole` to `StepMetadata`, threaded through all 4 return sites
|
|
290
|
+
- `src/mcp/output-schemas.ts` — added `agentRole` to `V2PendingStepSchema`, extracted `toPendingStep()` helper
|
|
291
|
+
- `src/mcp/handlers/v2-execution/start.ts` — uses `toPendingStep(meta)` instead of inline construction
|
|
292
|
+
- `src/mcp/handlers/v2-execution/continue-rehydrate.ts` — same
|
|
293
|
+
- `src/mcp/handlers/v2-execution/replay.ts` — same (3 sites)
|
|
294
|
+
- Note: `continue-advance.ts` delegates to `replay.ts`, no direct changes needed
|
|
295
|
+
|
|
296
|
+
**Risk:** Low. Additive, backward-compatible (optional field). All 62 contract tests pass.
|
|
297
|
+
|
|
298
|
+
### Slice 2+3: Engine types + factory — DONE
|
|
299
|
+
|
|
300
|
+
**New files:**
|
|
301
|
+
- `src/engine/types.ts` — branded tokens, discriminated union `StepResponse`, typed `EngineError` variants, `WorkRailEngine` interface with `close()`
|
|
302
|
+
- `src/engine/engine-factory.ts` — `createWorkRailEngine(config)` returns `EngineResult<WorkRailEngine>`, uses DI container in `library` runtime mode
|
|
303
|
+
- `src/engine/index.ts` — public exports
|
|
304
|
+
|
|
305
|
+
**Also changed:**
|
|
306
|
+
- `src/runtime/runtime-mode.ts` — added `library` variant
|
|
307
|
+
- `src/di/container.ts` — `library` mode uses no signal handlers, ThrowingProcessTerminator
|
|
308
|
+
- `src/mcp/handlers/v2-execution/index.ts` — exported `executeContinueWorkflow`
|
|
309
|
+
- `src/mcp/handlers/v2-checkpoint.ts` — exported `executeCheckpoint` and `CheckpointError`
|
|
310
|
+
|
|
311
|
+
### Slice 4: Package export — DONE
|
|
312
|
+
|
|
313
|
+
- `package.json` — added `exports` field with `./engine` sub-path for `@exaudeus/workrail/engine`
|
|
314
|
+
|
|
315
|
+
### Slice 5: Integration test — DONE
|
|
316
|
+
|
|
317
|
+
- `tests/integration/engine-library.test.ts` — 7 tests: factory init, list, start, rehydrate, advance, typed error (not found), typed error (invalid token)
|
|
318
|
+
|
|
319
|
+
## What the factory does NOT include
|
|
320
|
+
|
|
321
|
+
- MCP transport or tool registry
|
|
322
|
+
- Feature flag checking (v2 is always on)
|
|
323
|
+
- Session tools (create/update/read session)
|
|
324
|
+
- HTTP server or dashboard
|
|
325
|
+
- Signal handling or process lifecycle
|
|
326
|
+
- `resolvedRootUris` (MCP-specific)
|
|
327
|
+
- `workspaceResolver` (can be added later if needed)
|
|
328
|
+
|
|
329
|
+
## Testing strategy
|
|
330
|
+
|
|
331
|
+
1. **Existing tests pass** — the agentRole change must not break any existing tests
|
|
332
|
+
2. **Engine integration test** — start + advance + complete a workflow via library API
|
|
333
|
+
3. **Output parity** — verify that `engine.startWorkflow(id)` returns equivalent data to `executeStartWorkflow(input, ctx)` (minus MCP wrapping)
|
|
334
|
+
4. **Keyring lifecycle** — verify the engine creates/loads keyring correctly on first run and subsequent runs
|
|
335
|
+
|
|
336
|
+
## Design decisions (resolved)
|
|
337
|
+
|
|
338
|
+
1. **Engine has `close()` method** — required for resource lifecycle. Currently a no-op since keyring is in-memory and locks are per-operation, but the contract exists for future resource management.
|
|
339
|
+
2. **Custom storage adapters** — deferred. The port interfaces exist but the factory doesn't expose them yet. Add when a consumer needs in-memory stores for testing.
|
|
340
|
+
3. **`nextCall` excluded from library responses** — it's an MCP agent concept (`{ tool: 'continue_workflow', params: {...} }`). Library consumers call engine methods directly; they don't need tool call templates.
|