@miller-tech/uap 2.36.4 → 2.39.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/config/model-profiles/qwen38.json +3 -3
- package/config/model-registry.json +96 -6
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +57 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/cli/deliver.d.ts +46 -0
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +155 -36
- package/dist/cli/deliver.js.map +1 -1
- package/dist/cli/models.d.ts +11 -1
- package/dist/cli/models.d.ts.map +1 -1
- package/dist/cli/models.js +164 -3
- package/dist/cli/models.js.map +1 -1
- package/dist/cli/workflow.d.ts +36 -0
- package/dist/cli/workflow.d.ts.map +1 -0
- package/dist/cli/workflow.js +246 -0
- package/dist/cli/workflow.js.map +1 -0
- package/dist/delivery/run-state.d.ts +1 -1
- package/dist/delivery/run-state.d.ts.map +1 -1
- package/dist/delivery/run-state.js +1 -1
- package/dist/delivery/run-state.js.map +1 -1
- package/dist/delivery/team-solve-deliver.d.ts +83 -0
- package/dist/delivery/team-solve-deliver.d.ts.map +1 -0
- package/dist/delivery/team-solve-deliver.js +191 -0
- package/dist/delivery/team-solve-deliver.js.map +1 -0
- package/dist/inference/model-files.d.ts +111 -0
- package/dist/inference/model-files.d.ts.map +1 -0
- package/dist/inference/model-files.js +172 -0
- package/dist/inference/model-files.js.map +1 -0
- package/dist/placement/registry.d.ts +650 -0
- package/dist/placement/registry.d.ts.map +1 -1
- package/dist/placement/registry.js +21 -0
- package/dist/placement/registry.js.map +1 -1
- package/dist/workflow/loader.d.ts +34 -0
- package/dist/workflow/loader.d.ts.map +1 -0
- package/dist/workflow/loader.js +232 -0
- package/dist/workflow/loader.js.map +1 -0
- package/dist/workflow/runner.d.ts +90 -0
- package/dist/workflow/runner.d.ts.map +1 -0
- package/dist/workflow/runner.js +416 -0
- package/dist/workflow/runner.js.map +1 -0
- package/dist/workflow/types.d.ts +400 -0
- package/dist/workflow/types.d.ts.map +1 -0
- package/dist/workflow/types.js +147 -0
- package/dist/workflow/types.js.map +1 -0
- package/docs/INDEX.md +1 -0
- package/docs/architecture/adr/0013-declarative-workflow-layer.md +99 -0
- package/docs/architecture/adr/0014-loop-steps-and-team-solve-deliver.md +142 -0
- package/docs/benchmarks/LCB_DROID_SMOKE.md +111 -0
- package/docs/guides/DELIVER.md +3 -1
- package/docs/guides/WORKFLOWS.md +179 -0
- package/docs/plans/model-performance-proof-options.md +39 -0
- package/docs/reference/CLI.md +33 -0
- package/docs/reference/CONFIGURATION.md +1 -0
- package/docs/reference/FEATURES.md +18 -0
- package/examples/auto-coordinator-example.js +127 -0
- package/examples/demo-order-solid.ts +19 -0
- package/examples/order-processing-strategy-pattern.ts +186 -0
- package/examples/order-processor-refactored.ts +473 -0
- package/examples/order-solid-refactor.ts +830 -0
- package/examples/refactored-order-processing.ts +106 -0
- package/examples/run-order-processing.ts +48 -0
- package/examples/solid-order-processing.ts +324 -0
- package/examples/strategy-pattern-example.ts +100 -0
- package/examples/workflows/team-solve/README.md +85 -0
- package/examples/workflows/team-solve/check-samples.sh +50 -0
- package/examples/workflows/team-solve/sample/task.md +22 -0
- package/examples/workflows/team-solve/sample/tests/1.in +2 -0
- package/examples/workflows/team-solve/sample/tests/1.out +1 -0
- package/examples/workflows/team-solve/sample/tests/2.in +2 -0
- package/examples/workflows/team-solve/sample/tests/2.out +1 -0
- package/examples/workflows/team-solve/sample/tests/3.in +2 -0
- package/examples/workflows/team-solve/sample/tests/3.out +1 -0
- package/examples/workflows/team-solve/sample/tests/4.in +2 -0
- package/examples/workflows/team-solve/sample/tests/4.out +1 -0
- package/examples/workflows/team-solve/sample/tests/5.in +1 -0
- package/examples/workflows/team-solve/sample/tests/5.out +1 -0
- package/examples/workflows/team-solve/steps/ideate-a.md +26 -0
- package/examples/workflows/team-solve/steps/ideate-b.md +28 -0
- package/examples/workflows/team-solve/steps/plan.md +20 -0
- package/examples/workflows/team-solve/steps/repair.md +25 -0
- package/examples/workflows/team-solve/steps/review.md +29 -0
- package/examples/workflows/team-solve/steps/solve.md +26 -0
- package/examples/workflows/team-solve/workflow.yaml +78 -0
- package/examples/workflows/team-solve-deliver/README.md +84 -0
- package/examples/workflows/team-solve-deliver/steps/ideate-a.md +25 -0
- package/examples/workflows/team-solve-deliver/steps/ideate-b.md +28 -0
- package/examples/workflows/team-solve-deliver/steps/plan.md +25 -0
- package/examples/workflows/team-solve-deliver/steps/repair.md +20 -0
- package/examples/workflows/team-solve-deliver/steps/review.md +31 -0
- package/examples/workflows/team-solve-deliver/steps/solve.md +28 -0
- package/examples/workflows/team-solve-deliver/steps/verify.md +9 -0
- package/examples/workflows/team-solve-deliver/workflow.yaml +74 -0
- package/package.json +2 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-311.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-311.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-311.pyc +0 -0
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-311.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-311.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +147 -14
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative workflow types — the static layer over the blackboard
|
|
3
|
+
* orchestrator.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS. The orchestrator (src/delivery/task-orchestrator.ts)
|
|
6
|
+
* executes a task DAG with fresh minimal contexts, bounded repair, and
|
|
7
|
+
* resume-at-the-boundary — but the DAG it runs is MODEL-AUTHORED at runtime
|
|
8
|
+
* (decompose.ts), so every mission re-plans itself and nothing is a durable,
|
|
9
|
+
* inspectable, reusable asset. The measured alternative (Memdoor's
|
|
10
|
+
* team-solve, GVS5H's method: five Qwen3.8-27B roles beating a frontier
|
|
11
|
+
* single-call on LiveCodeBench Hard at 9.8 vs 8.0) is a workflow authored
|
|
12
|
+
* ONCE as data — fixed role prompts, `requires:` edges, deterministic
|
|
13
|
+
* command steps — pointed at whatever model is serving.
|
|
14
|
+
*
|
|
15
|
+
* This module is the file format: a `workflow.yaml` plus role-prompt files.
|
|
16
|
+
* The runner (runner.ts) maps these steps onto `orchestrate()` unchanged, so
|
|
17
|
+
* the graph semantics (dependency-triggered dispatch, skip cascade, minimal
|
|
18
|
+
* repair, resume) are the validated delivery semantics, not a reimplementation.
|
|
19
|
+
*/
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
/** Step kinds. Each maps to one execution seam in the runner. */
|
|
22
|
+
export declare const STEP_KINDS: readonly ["agent", "command", "gate", "loop"];
|
|
23
|
+
export type StepKind = (typeof STEP_KINDS)[number];
|
|
24
|
+
declare const WorkflowStepSchema: z.ZodObject<{
|
|
25
|
+
id: z.ZodString;
|
|
26
|
+
kind: z.ZodEnum<["agent", "command", "gate", "loop"]>;
|
|
27
|
+
/** Human label for logs; defaults to the id. */
|
|
28
|
+
title: z.ZodOptional<z.ZodString>;
|
|
29
|
+
/**
|
|
30
|
+
* Per-step model pin — a ModelPresets id (e.g. `qwen38-27b`, the local
|
|
31
|
+
* strata arm through the proxy). Absent = the workflow default, then the
|
|
32
|
+
* CLI pin, then the local fleet default. Mirrors the decompose C2 per-leaf
|
|
33
|
+
* model dial: the plan (here: the author) decides which rung each step pays.
|
|
34
|
+
*/
|
|
35
|
+
model: z.ZodOptional<z.ZodString>;
|
|
36
|
+
/**
|
|
37
|
+
* Path to the role-prompt file, relative to the workflow directory.
|
|
38
|
+
* Agent steps take `prompt` XOR `goal` — a file keeps the workflow.yaml
|
|
39
|
+
* reviewable while the role prompt stays a first-class artifact (the
|
|
40
|
+
* Memdoor layout: one file per step). Loop steps take the same pair:
|
|
41
|
+
* the role instruction the convergence loop executes against.
|
|
42
|
+
*/
|
|
43
|
+
prompt: z.ZodOptional<z.ZodString>;
|
|
44
|
+
/** Inline role prompt (alternative to `prompt:`). */
|
|
45
|
+
goal: z.ZodOptional<z.ZodString>;
|
|
46
|
+
/** Run-directory files whose CONTENTS are inlined into the agent prompt. */
|
|
47
|
+
reads: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
48
|
+
/**
|
|
49
|
+
* Run-directory files this step produces. The first entry receives the
|
|
50
|
+
* agent reply (or the command's captured output); the rest are declared
|
|
51
|
+
* for the graph's write-collision check. Overwrite semantics — the file
|
|
52
|
+
* ledger is authoritative, chat is not. NOT for loop steps: a loop works
|
|
53
|
+
* the project tree (its DeliveryResult is the blackboard entry), not the
|
|
54
|
+
* run directory.
|
|
55
|
+
*/
|
|
56
|
+
writes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
57
|
+
/** DAG edges: step ids that must SUCCEED before this one runs. */
|
|
58
|
+
requires: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
59
|
+
/** Acceptance criteria lines — assembled into the agent prompt. */
|
|
60
|
+
criteria: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
61
|
+
/** command kind: shell line, run with cwd = the run directory. */
|
|
62
|
+
command: z.ZodOptional<z.ZodString>;
|
|
63
|
+
/**
|
|
64
|
+
* command kind: capture the output but never fail the run — Memdoor's
|
|
65
|
+
* `test` step ("test-output.log (never fails the run)"). The verdict step
|
|
66
|
+
* is simply a command WITHOUT this flag: a nonzero exit fails the run.
|
|
67
|
+
*/
|
|
68
|
+
neverFails: z.ZodOptional<z.ZodBoolean>;
|
|
69
|
+
/** command kind: kill the command after this many ms (default 120000). */
|
|
70
|
+
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
71
|
+
/** gate kind: prompt shown when the run pauses for approval. */
|
|
72
|
+
approvalPrompt: z.ZodOptional<z.ZodString>;
|
|
73
|
+
/**
|
|
74
|
+
* gate kind: maximum ms to WAIT for `uap workflow approve` before
|
|
75
|
+
* reporting the run as blocked (exit 2, resumable). 0 = never wait:
|
|
76
|
+
* pause immediately. Default 0 — approval is an operator act, not
|
|
77
|
+
* something a headless run should block a terminal on.
|
|
78
|
+
*/
|
|
79
|
+
waitMs: z.ZodOptional<z.ZodNumber>;
|
|
80
|
+
/**
|
|
81
|
+
* loop kind: max executor turns for the convergence loop this step runs
|
|
82
|
+
* (the caller's default applies when absent). The loop's exit condition
|
|
83
|
+
* is the project's real completion gates — this bounds the attempt
|
|
84
|
+
* budget, it does not replace verification.
|
|
85
|
+
*/
|
|
86
|
+
turns: z.ZodOptional<z.ZodNumber>;
|
|
87
|
+
/**
|
|
88
|
+
* loop kind: run the gates ONLY — no executor turns. The independent
|
|
89
|
+
* final verdict after repair steps: a green repair is not "delivered"
|
|
90
|
+
* until a verify-only pass says so.
|
|
91
|
+
*/
|
|
92
|
+
verifyOnly: z.ZodOptional<z.ZodBoolean>;
|
|
93
|
+
}, "strip", z.ZodTypeAny, {
|
|
94
|
+
id: string;
|
|
95
|
+
kind: "command" | "agent" | "loop" | "gate";
|
|
96
|
+
model?: string | undefined;
|
|
97
|
+
goal?: string | undefined;
|
|
98
|
+
command?: string | undefined;
|
|
99
|
+
title?: string | undefined;
|
|
100
|
+
turns?: number | undefined;
|
|
101
|
+
prompt?: string | undefined;
|
|
102
|
+
timeoutMs?: number | undefined;
|
|
103
|
+
criteria?: string[] | undefined;
|
|
104
|
+
writes?: string[] | undefined;
|
|
105
|
+
reads?: string[] | undefined;
|
|
106
|
+
requires?: string[] | undefined;
|
|
107
|
+
neverFails?: boolean | undefined;
|
|
108
|
+
approvalPrompt?: string | undefined;
|
|
109
|
+
waitMs?: number | undefined;
|
|
110
|
+
verifyOnly?: boolean | undefined;
|
|
111
|
+
}, {
|
|
112
|
+
id: string;
|
|
113
|
+
kind: "command" | "agent" | "loop" | "gate";
|
|
114
|
+
model?: string | undefined;
|
|
115
|
+
goal?: string | undefined;
|
|
116
|
+
command?: string | undefined;
|
|
117
|
+
title?: string | undefined;
|
|
118
|
+
turns?: number | undefined;
|
|
119
|
+
prompt?: string | undefined;
|
|
120
|
+
timeoutMs?: number | undefined;
|
|
121
|
+
criteria?: string[] | undefined;
|
|
122
|
+
writes?: string[] | undefined;
|
|
123
|
+
reads?: string[] | undefined;
|
|
124
|
+
requires?: string[] | undefined;
|
|
125
|
+
neverFails?: boolean | undefined;
|
|
126
|
+
approvalPrompt?: string | undefined;
|
|
127
|
+
waitMs?: number | undefined;
|
|
128
|
+
verifyOnly?: boolean | undefined;
|
|
129
|
+
}>;
|
|
130
|
+
declare const WorkflowDefSchema: z.ZodObject<{
|
|
131
|
+
name: z.ZodString;
|
|
132
|
+
description: z.ZodOptional<z.ZodString>;
|
|
133
|
+
/**
|
|
134
|
+
* Default model pin for steps that do not name one. The full resolution
|
|
135
|
+
* order is step.model → defaultModel → CLI --model → the local fleet
|
|
136
|
+
* default (see cli/workflow.ts) — the workflow names no model and stays
|
|
137
|
+
* portable across whatever arm is serving.
|
|
138
|
+
*/
|
|
139
|
+
defaultModel: z.ZodOptional<z.ZodString>;
|
|
140
|
+
/**
|
|
141
|
+
* Max concurrent INDEPENDENT steps (clamped to [1,16] by the
|
|
142
|
+
* orchestrator). Agent steps are stateless completions writing distinct
|
|
143
|
+
* files, so >1 is safe for the steps that declare disjoint `writes`; the
|
|
144
|
+
* loader rejects shared write targets across PARALLEL siblings.
|
|
145
|
+
* Default 1 — one local rail serves one completion at a time.
|
|
146
|
+
*/
|
|
147
|
+
parallel: z.ZodOptional<z.ZodNumber>;
|
|
148
|
+
/**
|
|
149
|
+
* Bounded fresh re-execution of a failed step before its dependents are
|
|
150
|
+
* blocked (orchestrator maxRepairsPerTask). Env hard-ceiling 5 applies.
|
|
151
|
+
* Default: the orchestrator's (1).
|
|
152
|
+
*/
|
|
153
|
+
maxRepairsPerStep: z.ZodOptional<z.ZodNumber>;
|
|
154
|
+
/** Assembled-prompt budget in chars (orchestrator contextBudgetChars). */
|
|
155
|
+
contextBudgetChars: z.ZodOptional<z.ZodNumber>;
|
|
156
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
157
|
+
id: z.ZodString;
|
|
158
|
+
kind: z.ZodEnum<["agent", "command", "gate", "loop"]>;
|
|
159
|
+
/** Human label for logs; defaults to the id. */
|
|
160
|
+
title: z.ZodOptional<z.ZodString>;
|
|
161
|
+
/**
|
|
162
|
+
* Per-step model pin — a ModelPresets id (e.g. `qwen38-27b`, the local
|
|
163
|
+
* strata arm through the proxy). Absent = the workflow default, then the
|
|
164
|
+
* CLI pin, then the local fleet default. Mirrors the decompose C2 per-leaf
|
|
165
|
+
* model dial: the plan (here: the author) decides which rung each step pays.
|
|
166
|
+
*/
|
|
167
|
+
model: z.ZodOptional<z.ZodString>;
|
|
168
|
+
/**
|
|
169
|
+
* Path to the role-prompt file, relative to the workflow directory.
|
|
170
|
+
* Agent steps take `prompt` XOR `goal` — a file keeps the workflow.yaml
|
|
171
|
+
* reviewable while the role prompt stays a first-class artifact (the
|
|
172
|
+
* Memdoor layout: one file per step). Loop steps take the same pair:
|
|
173
|
+
* the role instruction the convergence loop executes against.
|
|
174
|
+
*/
|
|
175
|
+
prompt: z.ZodOptional<z.ZodString>;
|
|
176
|
+
/** Inline role prompt (alternative to `prompt:`). */
|
|
177
|
+
goal: z.ZodOptional<z.ZodString>;
|
|
178
|
+
/** Run-directory files whose CONTENTS are inlined into the agent prompt. */
|
|
179
|
+
reads: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
180
|
+
/**
|
|
181
|
+
* Run-directory files this step produces. The first entry receives the
|
|
182
|
+
* agent reply (or the command's captured output); the rest are declared
|
|
183
|
+
* for the graph's write-collision check. Overwrite semantics — the file
|
|
184
|
+
* ledger is authoritative, chat is not. NOT for loop steps: a loop works
|
|
185
|
+
* the project tree (its DeliveryResult is the blackboard entry), not the
|
|
186
|
+
* run directory.
|
|
187
|
+
*/
|
|
188
|
+
writes: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
189
|
+
/** DAG edges: step ids that must SUCCEED before this one runs. */
|
|
190
|
+
requires: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
191
|
+
/** Acceptance criteria lines — assembled into the agent prompt. */
|
|
192
|
+
criteria: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
193
|
+
/** command kind: shell line, run with cwd = the run directory. */
|
|
194
|
+
command: z.ZodOptional<z.ZodString>;
|
|
195
|
+
/**
|
|
196
|
+
* command kind: capture the output but never fail the run — Memdoor's
|
|
197
|
+
* `test` step ("test-output.log (never fails the run)"). The verdict step
|
|
198
|
+
* is simply a command WITHOUT this flag: a nonzero exit fails the run.
|
|
199
|
+
*/
|
|
200
|
+
neverFails: z.ZodOptional<z.ZodBoolean>;
|
|
201
|
+
/** command kind: kill the command after this many ms (default 120000). */
|
|
202
|
+
timeoutMs: z.ZodOptional<z.ZodNumber>;
|
|
203
|
+
/** gate kind: prompt shown when the run pauses for approval. */
|
|
204
|
+
approvalPrompt: z.ZodOptional<z.ZodString>;
|
|
205
|
+
/**
|
|
206
|
+
* gate kind: maximum ms to WAIT for `uap workflow approve` before
|
|
207
|
+
* reporting the run as blocked (exit 2, resumable). 0 = never wait:
|
|
208
|
+
* pause immediately. Default 0 — approval is an operator act, not
|
|
209
|
+
* something a headless run should block a terminal on.
|
|
210
|
+
*/
|
|
211
|
+
waitMs: z.ZodOptional<z.ZodNumber>;
|
|
212
|
+
/**
|
|
213
|
+
* loop kind: max executor turns for the convergence loop this step runs
|
|
214
|
+
* (the caller's default applies when absent). The loop's exit condition
|
|
215
|
+
* is the project's real completion gates — this bounds the attempt
|
|
216
|
+
* budget, it does not replace verification.
|
|
217
|
+
*/
|
|
218
|
+
turns: z.ZodOptional<z.ZodNumber>;
|
|
219
|
+
/**
|
|
220
|
+
* loop kind: run the gates ONLY — no executor turns. The independent
|
|
221
|
+
* final verdict after repair steps: a green repair is not "delivered"
|
|
222
|
+
* until a verify-only pass says so.
|
|
223
|
+
*/
|
|
224
|
+
verifyOnly: z.ZodOptional<z.ZodBoolean>;
|
|
225
|
+
}, "strip", z.ZodTypeAny, {
|
|
226
|
+
id: string;
|
|
227
|
+
kind: "command" | "agent" | "loop" | "gate";
|
|
228
|
+
model?: string | undefined;
|
|
229
|
+
goal?: string | undefined;
|
|
230
|
+
command?: string | undefined;
|
|
231
|
+
title?: string | undefined;
|
|
232
|
+
turns?: number | undefined;
|
|
233
|
+
prompt?: string | undefined;
|
|
234
|
+
timeoutMs?: number | undefined;
|
|
235
|
+
criteria?: string[] | undefined;
|
|
236
|
+
writes?: string[] | undefined;
|
|
237
|
+
reads?: string[] | undefined;
|
|
238
|
+
requires?: string[] | undefined;
|
|
239
|
+
neverFails?: boolean | undefined;
|
|
240
|
+
approvalPrompt?: string | undefined;
|
|
241
|
+
waitMs?: number | undefined;
|
|
242
|
+
verifyOnly?: boolean | undefined;
|
|
243
|
+
}, {
|
|
244
|
+
id: string;
|
|
245
|
+
kind: "command" | "agent" | "loop" | "gate";
|
|
246
|
+
model?: string | undefined;
|
|
247
|
+
goal?: string | undefined;
|
|
248
|
+
command?: string | undefined;
|
|
249
|
+
title?: string | undefined;
|
|
250
|
+
turns?: number | undefined;
|
|
251
|
+
prompt?: string | undefined;
|
|
252
|
+
timeoutMs?: number | undefined;
|
|
253
|
+
criteria?: string[] | undefined;
|
|
254
|
+
writes?: string[] | undefined;
|
|
255
|
+
reads?: string[] | undefined;
|
|
256
|
+
requires?: string[] | undefined;
|
|
257
|
+
neverFails?: boolean | undefined;
|
|
258
|
+
approvalPrompt?: string | undefined;
|
|
259
|
+
waitMs?: number | undefined;
|
|
260
|
+
verifyOnly?: boolean | undefined;
|
|
261
|
+
}>, "many">;
|
|
262
|
+
}, "strip", z.ZodTypeAny, {
|
|
263
|
+
name: string;
|
|
264
|
+
steps: {
|
|
265
|
+
id: string;
|
|
266
|
+
kind: "command" | "agent" | "loop" | "gate";
|
|
267
|
+
model?: string | undefined;
|
|
268
|
+
goal?: string | undefined;
|
|
269
|
+
command?: string | undefined;
|
|
270
|
+
title?: string | undefined;
|
|
271
|
+
turns?: number | undefined;
|
|
272
|
+
prompt?: string | undefined;
|
|
273
|
+
timeoutMs?: number | undefined;
|
|
274
|
+
criteria?: string[] | undefined;
|
|
275
|
+
writes?: string[] | undefined;
|
|
276
|
+
reads?: string[] | undefined;
|
|
277
|
+
requires?: string[] | undefined;
|
|
278
|
+
neverFails?: boolean | undefined;
|
|
279
|
+
approvalPrompt?: string | undefined;
|
|
280
|
+
waitMs?: number | undefined;
|
|
281
|
+
verifyOnly?: boolean | undefined;
|
|
282
|
+
}[];
|
|
283
|
+
description?: string | undefined;
|
|
284
|
+
parallel?: number | undefined;
|
|
285
|
+
defaultModel?: string | undefined;
|
|
286
|
+
maxRepairsPerStep?: number | undefined;
|
|
287
|
+
contextBudgetChars?: number | undefined;
|
|
288
|
+
}, {
|
|
289
|
+
name: string;
|
|
290
|
+
steps: {
|
|
291
|
+
id: string;
|
|
292
|
+
kind: "command" | "agent" | "loop" | "gate";
|
|
293
|
+
model?: string | undefined;
|
|
294
|
+
goal?: string | undefined;
|
|
295
|
+
command?: string | undefined;
|
|
296
|
+
title?: string | undefined;
|
|
297
|
+
turns?: number | undefined;
|
|
298
|
+
prompt?: string | undefined;
|
|
299
|
+
timeoutMs?: number | undefined;
|
|
300
|
+
criteria?: string[] | undefined;
|
|
301
|
+
writes?: string[] | undefined;
|
|
302
|
+
reads?: string[] | undefined;
|
|
303
|
+
requires?: string[] | undefined;
|
|
304
|
+
neverFails?: boolean | undefined;
|
|
305
|
+
approvalPrompt?: string | undefined;
|
|
306
|
+
waitMs?: number | undefined;
|
|
307
|
+
verifyOnly?: boolean | undefined;
|
|
308
|
+
}[];
|
|
309
|
+
description?: string | undefined;
|
|
310
|
+
parallel?: number | undefined;
|
|
311
|
+
defaultModel?: string | undefined;
|
|
312
|
+
maxRepairsPerStep?: number | undefined;
|
|
313
|
+
contextBudgetChars?: number | undefined;
|
|
314
|
+
}>;
|
|
315
|
+
export type WorkflowStep = z.infer<typeof WorkflowStepSchema>;
|
|
316
|
+
export type WorkflowDef = z.infer<typeof WorkflowDefSchema>;
|
|
317
|
+
/** The parsed + validated workflow, ready for the runner. */
|
|
318
|
+
export interface LoadedWorkflow {
|
|
319
|
+
/** Absolute path of the workflow directory (workflow.yaml's dir). */
|
|
320
|
+
dir: string;
|
|
321
|
+
def: WorkflowDef;
|
|
322
|
+
/**
|
|
323
|
+
* Role-prompt text per agent step id, resolved from `prompt:` files at
|
|
324
|
+
* load time — fail-closed: a missing prompt file is a load error, never a
|
|
325
|
+
* silent empty role.
|
|
326
|
+
*/
|
|
327
|
+
rolePrompts: Map<string, string>;
|
|
328
|
+
}
|
|
329
|
+
export declare const WORKFLOW_FILE = "workflow.yaml";
|
|
330
|
+
/** Run lifecycle status, persisted to run-state.json after every change. */
|
|
331
|
+
export type WorkflowRunStatus = 'running' | 'succeeded' | 'failed' | 'blocked';
|
|
332
|
+
/**
|
|
333
|
+
* The persisted run state. `done` carries exactly what the orchestrator's
|
|
334
|
+
* onProgress emits — id + summary (+ contract) — so a resume seeds
|
|
335
|
+
* orchestrate.initialDone and finished work is never redone.
|
|
336
|
+
*/
|
|
337
|
+
export interface WorkflowRunState {
|
|
338
|
+
runId: string;
|
|
339
|
+
workflow: string;
|
|
340
|
+
status: WorkflowRunStatus;
|
|
341
|
+
startedAt: string;
|
|
342
|
+
updatedAt: string;
|
|
343
|
+
endedAt?: string;
|
|
344
|
+
/** One-line mission text (orientation for every step context). */
|
|
345
|
+
mission: string;
|
|
346
|
+
/** Cumulative accepted steps (orchestrator onProgress payload). */
|
|
347
|
+
done: Array<{
|
|
348
|
+
id: string;
|
|
349
|
+
summary: string;
|
|
350
|
+
contract?: string;
|
|
351
|
+
}>;
|
|
352
|
+
/** Failed step ids from the last attempt (informational on resume). */
|
|
353
|
+
failed: string[];
|
|
354
|
+
}
|
|
355
|
+
/** Exit-code contract — CI/cron can branch without parsing output. */
|
|
356
|
+
export declare const WORKFLOW_EXIT: {
|
|
357
|
+
readonly ok: 0;
|
|
358
|
+
/** A step failed (and its repairs); dependents were skipped. */
|
|
359
|
+
readonly stepFailed: 1;
|
|
360
|
+
/** The run paused at a gate awaiting approval — resumable. */
|
|
361
|
+
readonly blocked: 2;
|
|
362
|
+
/** The workflow file itself is invalid — never retriable as-is. */
|
|
363
|
+
readonly invalid: 3;
|
|
364
|
+
};
|
|
365
|
+
/**
|
|
366
|
+
* The convergence-loop seam for `kind: loop` steps — the composition point
|
|
367
|
+
* where a workflow DIRECTS delivery machinery. The caller owns loop
|
|
368
|
+
* construction (deliver wires its ConvergenceLoop / mission dispatch);
|
|
369
|
+
* the engine owns assembly (role instruction + dependency outputs + reads)
|
|
370
|
+
* and the graph semantics around it. `stepId` lets one seam serve several
|
|
371
|
+
* roles (solve vs repair vs a verify-only verdict).
|
|
372
|
+
*/
|
|
373
|
+
export type LoopStepExecutor = (args: {
|
|
374
|
+
stepId: string;
|
|
375
|
+
/** Assembled instruction: role prompt + direct-dependency outputs + reads. */
|
|
376
|
+
prompt: string;
|
|
377
|
+
/** The step's model pin, when the workflow names one. */
|
|
378
|
+
model?: string;
|
|
379
|
+
/** A verify-only step: gates, no executor turns. */
|
|
380
|
+
verifyOnly?: boolean;
|
|
381
|
+
/** The step's turns bound, when the workflow names one. */
|
|
382
|
+
turns?: number;
|
|
383
|
+
}) => Promise<{
|
|
384
|
+
success: boolean;
|
|
385
|
+
summary: string;
|
|
386
|
+
turns?: number;
|
|
387
|
+
}>;
|
|
388
|
+
/**
|
|
389
|
+
* Per-step role-call seam for agent steps — lets a caller with its own
|
|
390
|
+
* executor rails (deliver's generator/judge plan) drive role steps through
|
|
391
|
+
* them instead of a raw model client, preserving its discipline.
|
|
392
|
+
*/
|
|
393
|
+
export type StepCallExecutor = (step: {
|
|
394
|
+
id: string;
|
|
395
|
+
kind: StepKind;
|
|
396
|
+
}, prompt: string) => Promise<string>;
|
|
397
|
+
/** Narrow the raw parsed YAML into the typed def, with a flat error list. */
|
|
398
|
+
export declare function parseWorkflowDef(raw: unknown): WorkflowDef;
|
|
399
|
+
export {};
|
|
400
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/workflow/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,iEAAiE;AACjE,eAAO,MAAM,UAAU,+CAAgD,CAAC;AACxE,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AASnD,QAAA,MAAM,kBAAkB;;;IAGtB,gDAAgD;;IAEhD;;;;;OAKG;;IAEH;;;;;;OAMG;;IAEH,qDAAqD;;IAErD,4EAA4E;;IAE5E;;;;;;;OAOG;;IAEH,kEAAkE;;IAElE,mEAAmE;;IAEnE,kEAAkE;;IAElE;;;;OAIG;;IAEH,0EAA0E;;IAE1E,gEAAgE;;IAEhE;;;;;OAKG;;IAEH;;;;;OAKG;;IAEH;;;;OAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAEH,CAAC;AAEH,QAAA,MAAM,iBAAiB;;;IAGrB;;;;;OAKG;;IAEH;;;;;;OAMG;;IAEH;;;;OAIG;;IAEH,0EAA0E;;;;;QA5F1E,gDAAgD;;QAEhD;;;;;WAKG;;QAEH;;;;;;WAMG;;QAEH,qDAAqD;;QAErD,4EAA4E;;QAE5E;;;;;;;WAOG;;QAEH,kEAAkE;;QAElE,mEAAmE;;QAEnE,kEAAkE;;QAElE;;;;WAIG;;QAEH,0EAA0E;;QAE1E,gEAAgE;;QAEhE;;;;;WAKG;;QAEH;;;;;WAKG;;QAEH;;;;WAIG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA+BH,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC9D,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,WAAW,CAAC;IACjB;;;;OAIG;IACH,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,eAAO,MAAM,aAAa,kBAAkB,CAAC;AAE7C,4EAA4E;AAC5E,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE/E;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,IAAI,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAChE,uEAAuE;IACvE,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,sEAAsE;AACtE,eAAO,MAAM,aAAa;;IAExB,gEAAgE;;IAEhE,8DAA8D;;IAE9D,mEAAmE;;CAE3D,CAAC;AAEX;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,KAAK,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAErE;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAEzG,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,CAO1D"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative workflow types — the static layer over the blackboard
|
|
3
|
+
* orchestrator.
|
|
4
|
+
*
|
|
5
|
+
* WHY THIS EXISTS. The orchestrator (src/delivery/task-orchestrator.ts)
|
|
6
|
+
* executes a task DAG with fresh minimal contexts, bounded repair, and
|
|
7
|
+
* resume-at-the-boundary — but the DAG it runs is MODEL-AUTHORED at runtime
|
|
8
|
+
* (decompose.ts), so every mission re-plans itself and nothing is a durable,
|
|
9
|
+
* inspectable, reusable asset. The measured alternative (Memdoor's
|
|
10
|
+
* team-solve, GVS5H's method: five Qwen3.8-27B roles beating a frontier
|
|
11
|
+
* single-call on LiveCodeBench Hard at 9.8 vs 8.0) is a workflow authored
|
|
12
|
+
* ONCE as data — fixed role prompts, `requires:` edges, deterministic
|
|
13
|
+
* command steps — pointed at whatever model is serving.
|
|
14
|
+
*
|
|
15
|
+
* This module is the file format: a `workflow.yaml` plus role-prompt files.
|
|
16
|
+
* The runner (runner.ts) maps these steps onto `orchestrate()` unchanged, so
|
|
17
|
+
* the graph semantics (dependency-triggered dispatch, skip cascade, minimal
|
|
18
|
+
* repair, resume) are the validated delivery semantics, not a reimplementation.
|
|
19
|
+
*/
|
|
20
|
+
import { z } from 'zod';
|
|
21
|
+
/** Step kinds. Each maps to one execution seam in the runner. */
|
|
22
|
+
export const STEP_KINDS = ['agent', 'command', 'gate', 'loop'];
|
|
23
|
+
/**
|
|
24
|
+
* File-system discipline for step ids: lowercase slug, no dots — a repair
|
|
25
|
+
* chain namespaces links as `<id>.r0-…` (task-orchestrator.ts) and a dot in
|
|
26
|
+
* the base id would blur that boundary in run-state.json.
|
|
27
|
+
*/
|
|
28
|
+
const STEP_ID_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
29
|
+
const WorkflowStepSchema = z.object({
|
|
30
|
+
id: z.string().regex(STEP_ID_RE, 'step id must be a lowercase slug (a-z, 0-9, -)'),
|
|
31
|
+
kind: z.enum(STEP_KINDS),
|
|
32
|
+
/** Human label for logs; defaults to the id. */
|
|
33
|
+
title: z.string().min(1).optional(),
|
|
34
|
+
/**
|
|
35
|
+
* Per-step model pin — a ModelPresets id (e.g. `qwen38-27b`, the local
|
|
36
|
+
* strata arm through the proxy). Absent = the workflow default, then the
|
|
37
|
+
* CLI pin, then the local fleet default. Mirrors the decompose C2 per-leaf
|
|
38
|
+
* model dial: the plan (here: the author) decides which rung each step pays.
|
|
39
|
+
*/
|
|
40
|
+
model: z.string().min(1).optional(),
|
|
41
|
+
/**
|
|
42
|
+
* Path to the role-prompt file, relative to the workflow directory.
|
|
43
|
+
* Agent steps take `prompt` XOR `goal` — a file keeps the workflow.yaml
|
|
44
|
+
* reviewable while the role prompt stays a first-class artifact (the
|
|
45
|
+
* Memdoor layout: one file per step). Loop steps take the same pair:
|
|
46
|
+
* the role instruction the convergence loop executes against.
|
|
47
|
+
*/
|
|
48
|
+
prompt: z.string().min(1).optional(),
|
|
49
|
+
/** Inline role prompt (alternative to `prompt:`). */
|
|
50
|
+
goal: z.string().min(1).optional(),
|
|
51
|
+
/** Run-directory files whose CONTENTS are inlined into the agent prompt. */
|
|
52
|
+
reads: z.array(z.string().min(1)).optional(),
|
|
53
|
+
/**
|
|
54
|
+
* Run-directory files this step produces. The first entry receives the
|
|
55
|
+
* agent reply (or the command's captured output); the rest are declared
|
|
56
|
+
* for the graph's write-collision check. Overwrite semantics — the file
|
|
57
|
+
* ledger is authoritative, chat is not. NOT for loop steps: a loop works
|
|
58
|
+
* the project tree (its DeliveryResult is the blackboard entry), not the
|
|
59
|
+
* run directory.
|
|
60
|
+
*/
|
|
61
|
+
writes: z.array(z.string().min(1)).optional(),
|
|
62
|
+
/** DAG edges: step ids that must SUCCEED before this one runs. */
|
|
63
|
+
requires: z.array(z.string().min(1)).optional(),
|
|
64
|
+
/** Acceptance criteria lines — assembled into the agent prompt. */
|
|
65
|
+
criteria: z.array(z.string().min(1)).optional(),
|
|
66
|
+
/** command kind: shell line, run with cwd = the run directory. */
|
|
67
|
+
command: z.string().min(1).optional(),
|
|
68
|
+
/**
|
|
69
|
+
* command kind: capture the output but never fail the run — Memdoor's
|
|
70
|
+
* `test` step ("test-output.log (never fails the run)"). The verdict step
|
|
71
|
+
* is simply a command WITHOUT this flag: a nonzero exit fails the run.
|
|
72
|
+
*/
|
|
73
|
+
neverFails: z.boolean().optional(),
|
|
74
|
+
/** command kind: kill the command after this many ms (default 120000). */
|
|
75
|
+
timeoutMs: z.number().int().positive().optional(),
|
|
76
|
+
/** gate kind: prompt shown when the run pauses for approval. */
|
|
77
|
+
approvalPrompt: z.string().min(1).optional(),
|
|
78
|
+
/**
|
|
79
|
+
* gate kind: maximum ms to WAIT for `uap workflow approve` before
|
|
80
|
+
* reporting the run as blocked (exit 2, resumable). 0 = never wait:
|
|
81
|
+
* pause immediately. Default 0 — approval is an operator act, not
|
|
82
|
+
* something a headless run should block a terminal on.
|
|
83
|
+
*/
|
|
84
|
+
waitMs: z.number().int().nonnegative().optional(),
|
|
85
|
+
/**
|
|
86
|
+
* loop kind: max executor turns for the convergence loop this step runs
|
|
87
|
+
* (the caller's default applies when absent). The loop's exit condition
|
|
88
|
+
* is the project's real completion gates — this bounds the attempt
|
|
89
|
+
* budget, it does not replace verification.
|
|
90
|
+
*/
|
|
91
|
+
turns: z.number().int().positive().optional(),
|
|
92
|
+
/**
|
|
93
|
+
* loop kind: run the gates ONLY — no executor turns. The independent
|
|
94
|
+
* final verdict after repair steps: a green repair is not "delivered"
|
|
95
|
+
* until a verify-only pass says so.
|
|
96
|
+
*/
|
|
97
|
+
verifyOnly: z.boolean().optional(),
|
|
98
|
+
});
|
|
99
|
+
const WorkflowDefSchema = z.object({
|
|
100
|
+
name: z.string().regex(STEP_ID_RE, 'workflow name must be a lowercase slug'),
|
|
101
|
+
description: z.string().min(1).optional(),
|
|
102
|
+
/**
|
|
103
|
+
* Default model pin for steps that do not name one. The full resolution
|
|
104
|
+
* order is step.model → defaultModel → CLI --model → the local fleet
|
|
105
|
+
* default (see cli/workflow.ts) — the workflow names no model and stays
|
|
106
|
+
* portable across whatever arm is serving.
|
|
107
|
+
*/
|
|
108
|
+
defaultModel: z.string().min(1).optional(),
|
|
109
|
+
/**
|
|
110
|
+
* Max concurrent INDEPENDENT steps (clamped to [1,16] by the
|
|
111
|
+
* orchestrator). Agent steps are stateless completions writing distinct
|
|
112
|
+
* files, so >1 is safe for the steps that declare disjoint `writes`; the
|
|
113
|
+
* loader rejects shared write targets across PARALLEL siblings.
|
|
114
|
+
* Default 1 — one local rail serves one completion at a time.
|
|
115
|
+
*/
|
|
116
|
+
parallel: z.number().int().min(1).max(16).optional(),
|
|
117
|
+
/**
|
|
118
|
+
* Bounded fresh re-execution of a failed step before its dependents are
|
|
119
|
+
* blocked (orchestrator maxRepairsPerTask). Env hard-ceiling 5 applies.
|
|
120
|
+
* Default: the orchestrator's (1).
|
|
121
|
+
*/
|
|
122
|
+
maxRepairsPerStep: z.number().int().min(0).max(5).optional(),
|
|
123
|
+
/** Assembled-prompt budget in chars (orchestrator contextBudgetChars). */
|
|
124
|
+
contextBudgetChars: z.number().int().positive().optional(),
|
|
125
|
+
steps: z.array(WorkflowStepSchema).min(1, 'a workflow needs at least one step'),
|
|
126
|
+
});
|
|
127
|
+
export const WORKFLOW_FILE = 'workflow.yaml';
|
|
128
|
+
/** Exit-code contract — CI/cron can branch without parsing output. */
|
|
129
|
+
export const WORKFLOW_EXIT = {
|
|
130
|
+
ok: 0,
|
|
131
|
+
/** A step failed (and its repairs); dependents were skipped. */
|
|
132
|
+
stepFailed: 1,
|
|
133
|
+
/** The run paused at a gate awaiting approval — resumable. */
|
|
134
|
+
blocked: 2,
|
|
135
|
+
/** The workflow file itself is invalid — never retriable as-is. */
|
|
136
|
+
invalid: 3,
|
|
137
|
+
};
|
|
138
|
+
/** Narrow the raw parsed YAML into the typed def, with a flat error list. */
|
|
139
|
+
export function parseWorkflowDef(raw) {
|
|
140
|
+
const parsed = WorkflowDefSchema.safeParse(raw);
|
|
141
|
+
if (!parsed.success) {
|
|
142
|
+
const lines = parsed.error.issues.map((i) => ` - ${i.path.join('.')}: ${i.message}`);
|
|
143
|
+
throw new Error(`invalid workflow definition:\n${lines.join('\n')}`);
|
|
144
|
+
}
|
|
145
|
+
return parsed.data;
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/workflow/types.ts"],"names":[],"mappings":"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"}
|
package/docs/INDEX.md
CHANGED
|
@@ -50,6 +50,7 @@ Full map: **[The UAP Delivery Pipeline](guides/DELIVERY_PIPELINE.md)**.
|
|
|
50
50
|
| [What UAP Does Automatically (compact)](guides/AUTOMATIC.md) | A shorter, trigger-by-trigger telling of the same ground as AUTOMATIC_FEATURES |
|
|
51
51
|
| [**`uap deliver`**](guides/DELIVER.md) | The Build+QC harness — convergence loop to verified completion, tiered gates, CI/deploy feedback loop ⭐ |
|
|
52
52
|
| [**Orchestrator & Hands-Free**](guides/ORCHESTRATOR.md) | The long-task autonomy layer — blackboard orchestrator, epic controller, completion ledger, auto-seed/resume; any model runs a huge build to 100% hands-free ⭐ |
|
|
53
|
+
| [Workflows](guides/WORKFLOWS.md) | Static `workflow.yaml` step DAGs (agent/command/gate/loop) over the orchestrator — role relays with cross-correction, deterministic verdicts, resumable runs; bundled team-solve + the deliver-driven team-solve-deliver (`uap deliver --team-solve`, auto on high/critical) |
|
|
53
54
|
| [**UAP Across Two Agents & Uplift**](guides/TWO_AGENTS_AND_UPLIFT.md) | The whole line applied seam-by-seam to opencode+Qwen3.6 (local) and Claude Code+Opus 4.8 (cloud), plus the benchmark that measures UAP uplift — diagrams + `benchmarks/suites/swe-bench-pro/` config |
|
|
54
55
|
| [Memory](guides/MEMORY.md) | The 4-tier memory system, write-gates, semantic recall |
|
|
55
56
|
| [MCP Router](guides/MCP_ROUTER.md) | Token-optimizing tool proxy + FTS5 output compression |
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# ADR 0013: Declarative workflow layer — static step DAGs over the orchestrator
|
|
2
|
+
|
|
3
|
+
- Status: Accepted (amended by ADR 0014: a fourth step kind `loop`, the
|
|
4
|
+
caller-injected convergence-loop seam, and the team-solve-deliver
|
|
5
|
+
posture that `uap deliver` auto-engages on high/critical missions)
|
|
6
|
+
- Date: 2026-11-03
|
|
7
|
+
- Spec: `uap workflow` (src/workflow/, src/cli/workflow.ts,
|
|
8
|
+
examples/workflows/team-solve/, docs/guides/WORKFLOWS.md).
|
|
9
|
+
- Supersedes: none — additive layer; `orchestrate()` and every existing
|
|
10
|
+
delivery surface are untouched.
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
UAP's task DAG machinery (ADR 0009's blackboard orchestrator) executes a
|
|
15
|
+
graph of fresh-context tasks with bounded repair and resume — but the DAG it
|
|
16
|
+
runs is model-authored at runtime (decompose.ts). Every mission re-plans
|
|
17
|
+
itself; nothing about the plan is a durable, reviewable, reusable asset.
|
|
18
|
+
|
|
19
|
+
The measured external counterpoint is GVS5H (Lee, 2026; reproduced by
|
|
20
|
+
Memdoor's team-solve): five Qwen3.8-27B roles on a STATIC graph — planner,
|
|
21
|
+
two parallel ideators from different algorithm families, solver, reviewer,
|
|
22
|
+
repairer — talking only through files, judged only by a deterministic
|
|
23
|
+
harness, matched the authors' own harness on LiveCodeBench Hard (9.8/10 vs
|
|
24
|
+
9.6; a frontier single-call at 8.0). The claim is structure, not model
|
|
25
|
+
class: the graph and the ledger discipline carried the result.
|
|
26
|
+
|
|
27
|
+
UAP had the engine but not the declarative layer: no way to author the graph
|
|
28
|
+
as data, pin models per step, run deterministic command steps as first-class
|
|
29
|
+
nodes, or resume a blocked run — nothing a CI or a cron could execute as a
|
|
30
|
+
file.
|
|
31
|
+
|
|
32
|
+
## Decision
|
|
33
|
+
|
|
34
|
+
1. **A workflow is data.** `.uap/workflows/<name>/workflow.yaml` (zod-
|
|
35
|
+
validated) + role-prompt files; search roots project → home → bundled
|
|
36
|
+
`examples/` (first hit wins). The loader is fail-closed: unique ids, known
|
|
37
|
+
`requires:`, cycle rejection (Kahn — topoOrder's fail-soft is right for
|
|
38
|
+
model-authored plans, wrong for a static file), kind/field confusion,
|
|
39
|
+
parallel write collision (graph-safety FALSE INDEPENDENCE, checked at
|
|
40
|
+
authoring time), run-dir path escapes, load-time model-pin validation,
|
|
41
|
+
reserved-path rejection.
|
|
42
|
+
2. **`orchestrate()` is the engine, unchanged.** The runner maps three step
|
|
43
|
+
kinds onto its existing seams: `agent` (fresh single completion; role
|
|
44
|
+
prompt + direct-dependency summaries + inlined `reads:` files; the reply
|
|
45
|
+
IS `writes[0]`), `command` (spawnSync exit-code verdict; `neverFails`
|
|
46
|
+
evidence mode), `gate` (approval file → BLOCKED exit 2, resumable). No
|
|
47
|
+
graph logic is reimplemented; dependency-triggered dispatch, skip
|
|
48
|
+
cascade, bounded repair, and resume-at-the-boundary are inherited and
|
|
49
|
+
already tested by the orchestrator suite.
|
|
50
|
+
3. **Files, not chat.** Steps communicate only through the run directory
|
|
51
|
+
(`.uap/workflow-runs/<runId>/`); each agent step starts from a fresh
|
|
52
|
+
context assembled from the file ledger. One deliberate divergence from
|
|
53
|
+
Memdoor: one reply → one file (overwrite semantics), not append-to-notes;
|
|
54
|
+
per-step files keep the ledger unambiguous.
|
|
55
|
+
4. **Steps name no model.** Pin ladder: step → workflow `defaultModel` →
|
|
56
|
+
`--model` → the local fleet default (`qwen38-27b`, the strata arm through
|
|
57
|
+
the proxy). A workflow is portable across arms and endpoints without
|
|
58
|
+
edits; `--endpoint` covers non-local OpenAI-compatible servers.
|
|
59
|
+
5. **Exit contract for CI/cron:** 0 ok · 1 step failed · 2 gate blocked
|
|
60
|
+
(resumable) · 3 invalid workflow. A real step defect never hides behind a
|
|
61
|
+
blocked gate (failed > blocked precedence).
|
|
62
|
+
6. **Trust boundary is the npm-scripts class.** `command:` lines run a shell
|
|
63
|
+
as the invoking user; `--input` bundles are dereferenced on copy (no
|
|
64
|
+
symlink escapes) and cannot plant run-state.json; model replies are data
|
|
65
|
+
(prompts and files, never a shell); model-written code executes only via
|
|
66
|
+
authored commands, exactly like `deliver` gate scripts. Untrusted input
|
|
67
|
+
composes with `uap sandbox --net off` externally — no sandbox stub inside
|
|
68
|
+
the layer.
|
|
69
|
+
7. **Validation is a gated option, not a claim.** O7 in
|
|
70
|
+
docs/plans/model-performance-proof-options.md: paired three-arm (single-
|
|
71
|
+
shot / deliver gate loop / team-solve workflow) on the same local model;
|
|
72
|
+
starts only on an explicit go, with the house rules (paired rates,
|
|
73
|
+
bootstrap CI, McNemar, discrimination status).
|
|
74
|
+
|
|
75
|
+
## Alternatives considered
|
|
76
|
+
|
|
77
|
+
- **Extend decompose.ts with static plan files** — rejected: couples the
|
|
78
|
+
declarative format to the model-planning path; a static workflow needs
|
|
79
|
+
different validation (fail-closed, not fail-soft) and different authoring
|
|
80
|
+
ergonomics than a runtime plan.
|
|
81
|
+
- **Byte-port Memdoor's mario engine** — rejected: UAP already owns a
|
|
82
|
+
validated orchestrator with repair/resume semantics; a second engine would
|
|
83
|
+
duplicate them. The port keeps the METHOD (roles, ledger discipline,
|
|
84
|
+
deterministic verdict), not the bytes.
|
|
85
|
+
- **Build workflows on droids/Task** — rejected: droid delegation is runtime
|
|
86
|
+
ad-hoc (the orchestrating model decides); a workflow must be executable
|
|
87
|
+
headless from a file, by CI, without any model in the driver's seat.
|
|
88
|
+
|
|
89
|
+
## Consequences
|
|
90
|
+
|
|
91
|
+
- `uap workflow list|show|run|status|resume|approve` joins the command
|
|
92
|
+
surface (additive; registration is one lazy-map entry + one block).
|
|
93
|
+
- team-solve ships as the bundled flagship example and the O7 subject; its
|
|
94
|
+
published numbers belong to the authors (their harness, their host).
|
|
95
|
+
- Known follow-ups (tracked, deliberate): a shared preset resolver for
|
|
96
|
+
deliver + workflow (the pin ladder's resolution discipline is currently
|
|
97
|
+
expressed twice); dashboard integration over run-state.json's stable JSON
|
|
98
|
+
seam; gate repair-attempt accounting (an unapproved gate consumes its
|
|
99
|
+
step's repair budget while waiting).
|