@osolmaz/pi-workflows 0.10.0 → 0.11.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/README.md +23 -12
- package/dist/builtins/autodoc.workflow.d.ts +58 -0
- package/dist/builtins/autodoc.workflow.js +266 -0
- package/dist/builtins/autodoc.workflow.js.map +1 -0
- package/dist/builtins/autoimplement.workflow.d.ts +210 -11
- package/dist/builtins/autoimplement.workflow.js +245 -13
- package/dist/builtins/autoimplement.workflow.js.map +1 -1
- package/dist/builtins/{autodevise.workflow.d.ts → autoplan.workflow.d.ts} +9 -9
- package/dist/builtins/{autodevise.workflow.js → autoplan.workflow.js} +20 -20
- package/dist/builtins/autoplan.workflow.js.map +1 -0
- package/dist/builtins/catalog.js +8 -4
- package/dist/builtins/catalog.js.map +1 -1
- package/dist/builtins/index.d.ts +6 -3
- package/dist/builtins/index.js +5 -2
- package/dist/builtins/index.js.map +1 -1
- package/dist/builtins/monitor.workflow.d.ts +4 -0
- package/dist/builtins/monitor.workflow.js +134 -9
- package/dist/builtins/monitor.workflow.js.map +1 -1
- package/dist/builtins/plan-approval.workflow.d.ts +83 -0
- package/dist/builtins/plan-approval.workflow.js +148 -0
- package/dist/builtins/plan-approval.workflow.js.map +1 -0
- package/dist/builtins/plan-presentation.d.ts +7 -0
- package/dist/builtins/plan-presentation.js +44 -0
- package/dist/builtins/plan-presentation.js.map +1 -0
- package/dist/extension/decision-channels.d.ts +132 -0
- package/dist/extension/decision-channels.js +1082 -0
- package/dist/extension/decision-channels.js.map +1 -0
- package/dist/extension/index.d.ts +1 -0
- package/dist/extension/index.js +426 -11
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/widget.js +26 -2
- package/dist/extension/widget.js.map +1 -1
- package/dist/extension/workflow-tool.d.ts +1 -37
- package/dist/extension/workflow-tool.js +1 -42
- package/dist/extension/workflow-tool.js.map +1 -1
- package/dist/host/rpc-bridge.js +4 -21
- package/dist/host/rpc-bridge.js.map +1 -1
- package/dist/render/graph-render.js +33 -8
- package/dist/render/graph-render.js.map +1 -1
- package/dist/viewer/render.js +36 -2
- package/dist/viewer/render.js.map +1 -1
- package/dist/workflows/composition.js +15 -1
- package/dist/workflows/composition.js.map +1 -1
- package/dist/workflows/decision-presentation.d.ts +18 -0
- package/dist/workflows/decision-presentation.js +417 -0
- package/dist/workflows/decision-presentation.js.map +1 -0
- package/dist/workflows/engine.d.ts +2 -1
- package/dist/workflows/engine.js +86 -4
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/human-decision.d.ts +87 -0
- package/dist/workflows/human-decision.js +583 -0
- package/dist/workflows/human-decision.js.map +1 -0
- package/dist/workflows/index.d.ts +3 -1
- package/dist/workflows/index.js +2 -0
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/schema.js +15 -0
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/store.js +7 -0
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/tool-input.d.ts +72 -0
- package/dist/workflows/tool-input.js +141 -0
- package/dist/workflows/tool-input.js.map +1 -0
- package/dist/workflows/types.d.ts +223 -0
- package/docs/HUMAN_DECISIONS.md +371 -0
- package/docs/HUMAN_DECISION_PRESENTATIONS.md +323 -0
- package/docs/MONITOR.md +17 -6
- package/docs/WORKFLOW_COMPOSITION.md +13 -6
- package/docs/plans/2026-08-19-human-decision-gates-plan.md +296 -0
- package/docs/plans/2026-08-19-human-decision-presentations-plan.md +172 -0
- package/docs/plans/2026-08-19-provider-compatible-workflow-tool-schema-plan.md +45 -0
- package/docs/plans/2026-08-19-workflow-composition-plan.md +25 -17
- package/docs/run-bundles.md +23 -2
- package/docs/workflows.md +43 -5
- package/examples/workflows/approved-plan.workflow.ts +58 -0
- package/examples/workflows/autoplan.workflow.ts +1 -0
- package/examples/workflows/human-decision.workflow.ts +62 -0
- package/herdr-plugin.toml +1 -1
- package/package.json +2 -1
- package/schemas/decision-presentation-v1.schema.json +83 -0
- package/schemas/human-decision-accepted-v1.schema.json +44 -0
- package/schemas/human-decision-accepted-v2.schema.json +50 -0
- package/schemas/human-decision-answer-attempt-v1.schema.json +37 -0
- package/schemas/human-decision-cancellation-v1.schema.json +15 -0
- package/schemas/human-decision-continuation-v1.schema.json +16 -0
- package/schemas/human-decision-delivery-v1.schema.json +28 -0
- package/schemas/human-decision-delivery-v2.schema.json +36 -0
- package/schemas/human-decision-receipt-v1.schema.json +33 -0
- package/schemas/human-decision-receipt-v2.schema.json +39 -0
- package/schemas/human-decision-request-v1.schema.json +59 -0
- package/schemas/human-decision-request-v2.schema.json +69 -0
- package/schemas/human-decision-resolution-v1.schema.json +27 -0
- package/schemas/human-decision-resolution-v2.schema.json +27 -0
- package/schemas/human-decision-settlement-v1.schema.json +28 -0
- package/skills/autodoc/SKILL.md +43 -0
- package/skills/autoimplement/SKILL.md +58 -0
- package/skills/autoimplement/agents/openai.yaml +4 -0
- package/skills/autoplan/SKILL.md +25 -0
- package/skills/monitor/SKILL.md +3 -1
- package/skills/pi-workflows/SKILL.md +3 -3
- package/src/builtins/autodoc.workflow.ts +325 -0
- package/src/builtins/autoimplement.workflow.ts +281 -14
- package/src/builtins/{autodevise.workflow.ts → autoplan.workflow.ts} +32 -32
- package/src/builtins/catalog.ts +8 -4
- package/src/builtins/index.ts +25 -6
- package/src/builtins/monitor.workflow.ts +162 -8
- package/src/builtins/plan-approval.workflow.ts +190 -0
- package/src/builtins/plan-presentation.ts +57 -0
- package/src/extension/decision-channels.ts +1533 -0
- package/src/extension/index.ts +499 -9
- package/src/extension/widget.ts +39 -2
- package/src/extension/workflow-tool.ts +5 -81
- package/src/host/rpc-bridge.ts +7 -30
- package/src/render/graph-render.ts +40 -3
- package/src/viewer/render.ts +56 -3
- package/src/workflows/composition.ts +16 -1
- package/src/workflows/decision-presentation.ts +501 -0
- package/src/workflows/engine.ts +108 -4
- package/src/workflows/human-decision.ts +819 -0
- package/src/workflows/index.ts +69 -0
- package/src/workflows/schema.ts +17 -0
- package/src/workflows/store.ts +8 -0
- package/src/workflows/tool-input.ts +202 -0
- package/src/workflows/types.ts +265 -0
- package/dist/builtins/autodevise.workflow.js.map +0 -1
- package/examples/workflows/autodevise.workflow.ts +0 -1
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { WorkflowNodeContext } from "../workflows/types.js";
|
|
2
|
+
import { type AutodocInput } from "./autodoc.workflow.js";
|
|
3
|
+
import { type AutoplanInput } from "./autoplan.workflow.js";
|
|
4
|
+
import { type PlanApprovalInput } from "./plan-approval.workflow.js";
|
|
2
5
|
export type AutoimplementInput = {
|
|
3
6
|
task: string;
|
|
4
7
|
plan?: unknown;
|
|
@@ -7,6 +10,24 @@ export type AutoimplementInput = {
|
|
|
7
10
|
repository?: string;
|
|
8
11
|
baseBranch?: string;
|
|
9
12
|
merge?: boolean;
|
|
13
|
+
documents?: string[];
|
|
14
|
+
documentation?: {
|
|
15
|
+
status: "current";
|
|
16
|
+
planDigest: string;
|
|
17
|
+
documents: string[];
|
|
18
|
+
};
|
|
19
|
+
approval?: {
|
|
20
|
+
audience: string;
|
|
21
|
+
maxReplans: number;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export type ExistingPlanDiscovery = {
|
|
25
|
+
route: "found" | "blocked";
|
|
26
|
+
plan?: unknown;
|
|
27
|
+
documentation?: "current" | "missing" | "stale";
|
|
28
|
+
documents: string[];
|
|
29
|
+
reason: string;
|
|
30
|
+
evidence: unknown;
|
|
10
31
|
};
|
|
11
32
|
type ReviewFinding = {
|
|
12
33
|
severity: "P0" | "P1" | "P2" | "lower";
|
|
@@ -48,14 +69,101 @@ export declare const autoimplementWorkflow: import("../workflows/types.js").Work
|
|
|
48
69
|
readonly validate: (value: unknown) => AutoimplementBlocked;
|
|
49
70
|
};
|
|
50
71
|
}, {
|
|
51
|
-
readonly
|
|
72
|
+
readonly documentation: import("../workflows/types.js").WorkflowIncludeDefinition<import("../workflows/types.js").WorkflowDefinition<AutodocInput, {
|
|
52
73
|
readonly ready: {
|
|
53
74
|
readonly from: "finalize";
|
|
54
|
-
readonly validate: (value: unknown) => import("./
|
|
75
|
+
readonly validate: (value: unknown) => import("./autodoc.workflow.js").DocumentedPlan;
|
|
55
76
|
};
|
|
56
77
|
readonly blocked: {
|
|
57
78
|
readonly from: "blocked";
|
|
58
|
-
readonly validate: (value: unknown) => import("./
|
|
79
|
+
readonly validate: (value: unknown) => import("./autodoc.workflow.js").AutodocBlocked;
|
|
80
|
+
};
|
|
81
|
+
}, import("../workflows/types.js").WorkflowIncludeMap> & {
|
|
82
|
+
nodes: {
|
|
83
|
+
readonly prepare: import("../workflows/types.js").ComputeNodeDefinition;
|
|
84
|
+
readonly locatePlan: import("../workflows/types.js").AgentNodeDefinition;
|
|
85
|
+
readonly inspectDocumentation: import("../workflows/types.js").AgentNodeDefinition;
|
|
86
|
+
readonly updateDocumentation: import("../workflows/types.js").AgentNodeDefinition;
|
|
87
|
+
readonly verifyDocumentation: import("../workflows/types.js").AgentNodeDefinition;
|
|
88
|
+
readonly finalize: import("../workflows/types.js").ComputeNodeDefinition;
|
|
89
|
+
readonly blocked: import("../workflows/types.js").ComputeNodeDefinition;
|
|
90
|
+
};
|
|
91
|
+
includes?: import("../workflows/types.js").WorkflowIncludeMap;
|
|
92
|
+
exits?: {
|
|
93
|
+
readonly ready: {
|
|
94
|
+
readonly from: "finalize";
|
|
95
|
+
readonly validate: (value: unknown) => import("./autodoc.workflow.js").DocumentedPlan;
|
|
96
|
+
};
|
|
97
|
+
readonly blocked: {
|
|
98
|
+
readonly from: "blocked";
|
|
99
|
+
readonly validate: (value: unknown) => import("./autodoc.workflow.js").AutodocBlocked;
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
}>;
|
|
103
|
+
readonly approval: import("../workflows/types.js").WorkflowIncludeDefinition<import("../workflows/types.js").WorkflowDefinition<PlanApprovalInput, {
|
|
104
|
+
readonly continue: {
|
|
105
|
+
readonly from: "continued";
|
|
106
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalContinue;
|
|
107
|
+
};
|
|
108
|
+
readonly stop: {
|
|
109
|
+
readonly from: "stopped";
|
|
110
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalStop;
|
|
111
|
+
};
|
|
112
|
+
readonly replan: {
|
|
113
|
+
readonly from: "replan";
|
|
114
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalReplan;
|
|
115
|
+
};
|
|
116
|
+
}, import("../workflows/types.js").WorkflowIncludeMap> & {
|
|
117
|
+
nodes: {
|
|
118
|
+
readonly approve: import("../workflows/types.js").WorkflowNodeCommon & {
|
|
119
|
+
nodeType: "checkpoint";
|
|
120
|
+
summary?: string;
|
|
121
|
+
run?: (context: WorkflowNodeContext) => import("../workflows/types.js").MaybePromise<unknown>;
|
|
122
|
+
humanDecision?: import("../workflows/types.js").HumanDecisionNodeContract;
|
|
123
|
+
} & {
|
|
124
|
+
readonly __humanChoices?: {
|
|
125
|
+
readonly continue: {
|
|
126
|
+
readonly label: "Yes, continue";
|
|
127
|
+
};
|
|
128
|
+
readonly stop: {
|
|
129
|
+
readonly label: "No, stop";
|
|
130
|
+
};
|
|
131
|
+
readonly replan: {
|
|
132
|
+
readonly label: "Replan";
|
|
133
|
+
readonly input: import("../workflows/types.js").HumanDecisionTextInput & {
|
|
134
|
+
name: "instructions";
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
readonly continued: import("../workflows/types.js").ComputeNodeDefinition;
|
|
140
|
+
readonly stopped: import("../workflows/types.js").ComputeNodeDefinition;
|
|
141
|
+
readonly replan: import("../workflows/types.js").ComputeNodeDefinition;
|
|
142
|
+
};
|
|
143
|
+
includes?: import("../workflows/types.js").WorkflowIncludeMap;
|
|
144
|
+
exits?: {
|
|
145
|
+
readonly continue: {
|
|
146
|
+
readonly from: "continued";
|
|
147
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalContinue;
|
|
148
|
+
};
|
|
149
|
+
readonly stop: {
|
|
150
|
+
readonly from: "stopped";
|
|
151
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalStop;
|
|
152
|
+
};
|
|
153
|
+
readonly replan: {
|
|
154
|
+
readonly from: "replan";
|
|
155
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalReplan;
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
}>;
|
|
159
|
+
readonly redesign: import("../workflows/types.js").WorkflowIncludeDefinition<import("../workflows/types.js").WorkflowDefinition<AutoplanInput, {
|
|
160
|
+
readonly ready: {
|
|
161
|
+
readonly from: "finalize";
|
|
162
|
+
readonly validate: (value: unknown) => import("./autoplan.workflow.js").AutoplanReady;
|
|
163
|
+
};
|
|
164
|
+
readonly blocked: {
|
|
165
|
+
readonly from: "blocked";
|
|
166
|
+
readonly validate: (value: unknown) => import("./autoplan.workflow.js").AutoplanBlocked;
|
|
59
167
|
};
|
|
60
168
|
}, import("../workflows/types.js").WorkflowIncludeMap> & {
|
|
61
169
|
nodes: {
|
|
@@ -71,18 +179,22 @@ export declare const autoimplementWorkflow: import("../workflows/types.js").Work
|
|
|
71
179
|
exits?: {
|
|
72
180
|
readonly ready: {
|
|
73
181
|
readonly from: "finalize";
|
|
74
|
-
readonly validate: (value: unknown) => import("./
|
|
182
|
+
readonly validate: (value: unknown) => import("./autoplan.workflow.js").AutoplanReady;
|
|
75
183
|
};
|
|
76
184
|
readonly blocked: {
|
|
77
185
|
readonly from: "blocked";
|
|
78
|
-
readonly validate: (value: unknown) => import("./
|
|
186
|
+
readonly validate: (value: unknown) => import("./autoplan.workflow.js").AutoplanBlocked;
|
|
79
187
|
};
|
|
80
188
|
};
|
|
81
189
|
}>;
|
|
82
190
|
}> & {
|
|
83
191
|
nodes: {
|
|
84
192
|
readonly prepare: import("../workflows/types.js").ComputeNodeDefinition;
|
|
193
|
+
readonly findPlan: import("../workflows/types.js").AgentNodeDefinition;
|
|
194
|
+
readonly routeFoundPlan: import("../workflows/types.js").ComputeNodeDefinition;
|
|
85
195
|
readonly adoptPlan: import("../workflows/types.js").ComputeNodeDefinition;
|
|
196
|
+
readonly maybeApproval: import("../workflows/types.js").ComputeNodeDefinition;
|
|
197
|
+
readonly replanGuard: import("../workflows/types.js").ComputeNodeDefinition;
|
|
86
198
|
readonly implement: import("../workflows/types.js").AgentNodeDefinition;
|
|
87
199
|
readonly classifyImplementation: import("../workflows/types.js").AgentNodeDefinition;
|
|
88
200
|
readonly verify: import("../workflows/types.js").AgentNodeDefinition;
|
|
@@ -108,14 +220,101 @@ export declare const autoimplementWorkflow: import("../workflows/types.js").Work
|
|
|
108
220
|
readonly finalize: import("../workflows/types.js").ComputeNodeDefinition;
|
|
109
221
|
};
|
|
110
222
|
includes?: {
|
|
111
|
-
readonly
|
|
223
|
+
readonly documentation: import("../workflows/types.js").WorkflowIncludeDefinition<import("../workflows/types.js").WorkflowDefinition<AutodocInput, {
|
|
224
|
+
readonly ready: {
|
|
225
|
+
readonly from: "finalize";
|
|
226
|
+
readonly validate: (value: unknown) => import("./autodoc.workflow.js").DocumentedPlan;
|
|
227
|
+
};
|
|
228
|
+
readonly blocked: {
|
|
229
|
+
readonly from: "blocked";
|
|
230
|
+
readonly validate: (value: unknown) => import("./autodoc.workflow.js").AutodocBlocked;
|
|
231
|
+
};
|
|
232
|
+
}, import("../workflows/types.js").WorkflowIncludeMap> & {
|
|
233
|
+
nodes: {
|
|
234
|
+
readonly prepare: import("../workflows/types.js").ComputeNodeDefinition;
|
|
235
|
+
readonly locatePlan: import("../workflows/types.js").AgentNodeDefinition;
|
|
236
|
+
readonly inspectDocumentation: import("../workflows/types.js").AgentNodeDefinition;
|
|
237
|
+
readonly updateDocumentation: import("../workflows/types.js").AgentNodeDefinition;
|
|
238
|
+
readonly verifyDocumentation: import("../workflows/types.js").AgentNodeDefinition;
|
|
239
|
+
readonly finalize: import("../workflows/types.js").ComputeNodeDefinition;
|
|
240
|
+
readonly blocked: import("../workflows/types.js").ComputeNodeDefinition;
|
|
241
|
+
};
|
|
242
|
+
includes?: import("../workflows/types.js").WorkflowIncludeMap;
|
|
243
|
+
exits?: {
|
|
244
|
+
readonly ready: {
|
|
245
|
+
readonly from: "finalize";
|
|
246
|
+
readonly validate: (value: unknown) => import("./autodoc.workflow.js").DocumentedPlan;
|
|
247
|
+
};
|
|
248
|
+
readonly blocked: {
|
|
249
|
+
readonly from: "blocked";
|
|
250
|
+
readonly validate: (value: unknown) => import("./autodoc.workflow.js").AutodocBlocked;
|
|
251
|
+
};
|
|
252
|
+
};
|
|
253
|
+
}>;
|
|
254
|
+
readonly approval: import("../workflows/types.js").WorkflowIncludeDefinition<import("../workflows/types.js").WorkflowDefinition<PlanApprovalInput, {
|
|
255
|
+
readonly continue: {
|
|
256
|
+
readonly from: "continued";
|
|
257
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalContinue;
|
|
258
|
+
};
|
|
259
|
+
readonly stop: {
|
|
260
|
+
readonly from: "stopped";
|
|
261
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalStop;
|
|
262
|
+
};
|
|
263
|
+
readonly replan: {
|
|
264
|
+
readonly from: "replan";
|
|
265
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalReplan;
|
|
266
|
+
};
|
|
267
|
+
}, import("../workflows/types.js").WorkflowIncludeMap> & {
|
|
268
|
+
nodes: {
|
|
269
|
+
readonly approve: import("../workflows/types.js").WorkflowNodeCommon & {
|
|
270
|
+
nodeType: "checkpoint";
|
|
271
|
+
summary?: string;
|
|
272
|
+
run?: (context: WorkflowNodeContext) => import("../workflows/types.js").MaybePromise<unknown>;
|
|
273
|
+
humanDecision?: import("../workflows/types.js").HumanDecisionNodeContract;
|
|
274
|
+
} & {
|
|
275
|
+
readonly __humanChoices?: {
|
|
276
|
+
readonly continue: {
|
|
277
|
+
readonly label: "Yes, continue";
|
|
278
|
+
};
|
|
279
|
+
readonly stop: {
|
|
280
|
+
readonly label: "No, stop";
|
|
281
|
+
};
|
|
282
|
+
readonly replan: {
|
|
283
|
+
readonly label: "Replan";
|
|
284
|
+
readonly input: import("../workflows/types.js").HumanDecisionTextInput & {
|
|
285
|
+
name: "instructions";
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
};
|
|
289
|
+
};
|
|
290
|
+
readonly continued: import("../workflows/types.js").ComputeNodeDefinition;
|
|
291
|
+
readonly stopped: import("../workflows/types.js").ComputeNodeDefinition;
|
|
292
|
+
readonly replan: import("../workflows/types.js").ComputeNodeDefinition;
|
|
293
|
+
};
|
|
294
|
+
includes?: import("../workflows/types.js").WorkflowIncludeMap;
|
|
295
|
+
exits?: {
|
|
296
|
+
readonly continue: {
|
|
297
|
+
readonly from: "continued";
|
|
298
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalContinue;
|
|
299
|
+
};
|
|
300
|
+
readonly stop: {
|
|
301
|
+
readonly from: "stopped";
|
|
302
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalStop;
|
|
303
|
+
};
|
|
304
|
+
readonly replan: {
|
|
305
|
+
readonly from: "replan";
|
|
306
|
+
readonly validate: (value: unknown) => import("./plan-approval.workflow.js").PlanApprovalReplan;
|
|
307
|
+
};
|
|
308
|
+
};
|
|
309
|
+
}>;
|
|
310
|
+
readonly redesign: import("../workflows/types.js").WorkflowIncludeDefinition<import("../workflows/types.js").WorkflowDefinition<AutoplanInput, {
|
|
112
311
|
readonly ready: {
|
|
113
312
|
readonly from: "finalize";
|
|
114
|
-
readonly validate: (value: unknown) => import("./
|
|
313
|
+
readonly validate: (value: unknown) => import("./autoplan.workflow.js").AutoplanReady;
|
|
115
314
|
};
|
|
116
315
|
readonly blocked: {
|
|
117
316
|
readonly from: "blocked";
|
|
118
|
-
readonly validate: (value: unknown) => import("./
|
|
317
|
+
readonly validate: (value: unknown) => import("./autoplan.workflow.js").AutoplanBlocked;
|
|
119
318
|
};
|
|
120
319
|
}, import("../workflows/types.js").WorkflowIncludeMap> & {
|
|
121
320
|
nodes: {
|
|
@@ -131,11 +330,11 @@ export declare const autoimplementWorkflow: import("../workflows/types.js").Work
|
|
|
131
330
|
exits?: {
|
|
132
331
|
readonly ready: {
|
|
133
332
|
readonly from: "finalize";
|
|
134
|
-
readonly validate: (value: unknown) => import("./
|
|
333
|
+
readonly validate: (value: unknown) => import("./autoplan.workflow.js").AutoplanReady;
|
|
135
334
|
};
|
|
136
335
|
readonly blocked: {
|
|
137
336
|
readonly from: "blocked";
|
|
138
|
-
readonly validate: (value: unknown) => import("./
|
|
337
|
+
readonly validate: (value: unknown) => import("./autoplan.workflow.js").AutoplanBlocked;
|
|
139
338
|
};
|
|
140
339
|
};
|
|
141
340
|
}>;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { agent, compute, defineWorkflow, includeWorkflow, includedResult, shell, } from "../workflows/definition.js";
|
|
3
|
-
import
|
|
3
|
+
import { digest } from "../workflows/human-decision.js";
|
|
4
|
+
import autodocWorkflow, {} from "./autodoc.workflow.js";
|
|
5
|
+
import autoplanWorkflow, {} from "./autoplan.workflow.js";
|
|
6
|
+
import planApprovalWorkflow, {} from "./plan-approval.workflow.js";
|
|
4
7
|
const FIVE_MINUTES_MS = 5 * 60_000;
|
|
5
8
|
const TEN_MINUTES_MS = 10 * 60_000;
|
|
6
9
|
function requireRecord(value, label) {
|
|
@@ -25,6 +28,47 @@ function parseInput(value) {
|
|
|
25
28
|
if (input.merge !== undefined && typeof input.merge !== "boolean") {
|
|
26
29
|
throw new Error("autoimplement merge must be a boolean");
|
|
27
30
|
}
|
|
31
|
+
const documents = input.documents;
|
|
32
|
+
if (documents !== undefined &&
|
|
33
|
+
(!Array.isArray(documents) || documents.some((item) => typeof item !== "string"))) {
|
|
34
|
+
throw new Error("autoimplement documents must be an array of strings");
|
|
35
|
+
}
|
|
36
|
+
let documentation;
|
|
37
|
+
if (input.documentation !== undefined) {
|
|
38
|
+
if (input.plan === undefined) {
|
|
39
|
+
throw new Error("autoimplement documentation requires an explicit plan");
|
|
40
|
+
}
|
|
41
|
+
const raw = requireRecord(input.documentation, "autoimplement documentation");
|
|
42
|
+
if (raw.status !== "current") {
|
|
43
|
+
throw new Error("autoimplement documentation status must be current");
|
|
44
|
+
}
|
|
45
|
+
const planDigest = requireString(raw.planDigest, "autoimplement documentation planDigest");
|
|
46
|
+
if (planDigest !== digest(input.plan)) {
|
|
47
|
+
throw new Error("autoimplement documentation planDigest does not match the explicit plan");
|
|
48
|
+
}
|
|
49
|
+
if (!Array.isArray(raw.documents) || raw.documents.some((item) => typeof item !== "string")) {
|
|
50
|
+
throw new Error("autoimplement documentation documents must be an array of strings");
|
|
51
|
+
}
|
|
52
|
+
documentation = {
|
|
53
|
+
status: "current",
|
|
54
|
+
planDigest,
|
|
55
|
+
documents: [...raw.documents],
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
let approval;
|
|
59
|
+
if (input.approval !== undefined) {
|
|
60
|
+
const raw = requireRecord(input.approval, "autoimplement approval");
|
|
61
|
+
const maxReplans = raw.maxReplans ?? 3;
|
|
62
|
+
if (!Number.isInteger(maxReplans) ||
|
|
63
|
+
maxReplans < 1 ||
|
|
64
|
+
maxReplans > 20) {
|
|
65
|
+
throw new Error("autoimplement approval maxReplans must be from 1 through 20");
|
|
66
|
+
}
|
|
67
|
+
approval = {
|
|
68
|
+
audience: requireString(raw.audience, "autoimplement approval audience"),
|
|
69
|
+
maxReplans: maxReplans,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
28
72
|
return {
|
|
29
73
|
task: requireString(input.task, "autoimplement task"),
|
|
30
74
|
...(input.plan !== undefined ? { plan: input.plan } : {}),
|
|
@@ -37,6 +81,38 @@ function parseInput(value) {
|
|
|
37
81
|
? { baseBranch: requireString(input.baseBranch, "baseBranch") }
|
|
38
82
|
: {}),
|
|
39
83
|
merge: input.merge === true,
|
|
84
|
+
...(documents !== undefined ? { documents: [...documents] } : {}),
|
|
85
|
+
...(documentation !== undefined ? { documentation } : {}),
|
|
86
|
+
...(approval !== undefined ? { approval } : {}),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function parseExistingPlan(value) {
|
|
90
|
+
const result = requireRecord(value, "existing plan discovery");
|
|
91
|
+
if (result.route !== "found" && result.route !== "blocked") {
|
|
92
|
+
throw new Error("existing plan discovery route must be found or blocked");
|
|
93
|
+
}
|
|
94
|
+
if (result.route === "found") {
|
|
95
|
+
if (result.plan === undefined)
|
|
96
|
+
throw new Error("found plan must include plan");
|
|
97
|
+
if (result.documentation !== "current" &&
|
|
98
|
+
result.documentation !== "missing" &&
|
|
99
|
+
result.documentation !== "stale") {
|
|
100
|
+
throw new Error("found plan documentation must be current, missing, or stale");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (!Array.isArray(result.documents) ||
|
|
104
|
+
result.documents.some((item) => typeof item !== "string")) {
|
|
105
|
+
throw new Error("existing plan documents must be an array of strings");
|
|
106
|
+
}
|
|
107
|
+
return {
|
|
108
|
+
route: result.route,
|
|
109
|
+
...(result.plan !== undefined ? { plan: result.plan } : {}),
|
|
110
|
+
...(result.documentation !== undefined
|
|
111
|
+
? { documentation: result.documentation }
|
|
112
|
+
: {}),
|
|
113
|
+
documents: [...result.documents],
|
|
114
|
+
reason: requireString(result.reason, "existing plan discovery reason"),
|
|
115
|
+
evidence: result.evidence ?? null,
|
|
40
116
|
};
|
|
41
117
|
}
|
|
42
118
|
function parseRoute(value, routes, label) {
|
|
@@ -124,9 +200,39 @@ function latestCiCommand(context) {
|
|
|
124
200
|
}
|
|
125
201
|
function currentPlan(context) {
|
|
126
202
|
const adopted = context.outputs.adoptPlan;
|
|
127
|
-
|
|
203
|
+
if (adopted?.plan !== undefined)
|
|
204
|
+
return adopted.plan;
|
|
205
|
+
const documented = context.outputs.documentation;
|
|
206
|
+
if (documented?.exit === "ready" && documented.output?.plan !== undefined) {
|
|
207
|
+
return documented.output.plan;
|
|
208
|
+
}
|
|
209
|
+
const discovered = context.outputs.findPlan;
|
|
210
|
+
if (discovered?.route === "found" && discovered.plan !== undefined)
|
|
211
|
+
return discovered.plan;
|
|
212
|
+
return context.input.plan;
|
|
213
|
+
}
|
|
214
|
+
function currentPlanDigest(context) {
|
|
215
|
+
const adopted = context.outputs.adoptPlan;
|
|
216
|
+
if (typeof adopted?.planDigest === "string")
|
|
217
|
+
return adopted.planDigest;
|
|
218
|
+
const documented = context.outputs.documentation;
|
|
219
|
+
if (documented?.exit === "ready" && typeof documented.output?.planDigest === "string") {
|
|
220
|
+
return documented.output.planDigest;
|
|
221
|
+
}
|
|
222
|
+
const plan = currentPlan(context);
|
|
223
|
+
if (plan === undefined)
|
|
224
|
+
throw new Error("autoimplement does not have a selected plan");
|
|
225
|
+
return digest(plan);
|
|
128
226
|
}
|
|
129
227
|
function latestIssue(context) {
|
|
228
|
+
const approval = context.outputs.approval;
|
|
229
|
+
if (approval?.exit === "replan" && typeof approval.output?.instructions === "string") {
|
|
230
|
+
return {
|
|
231
|
+
source: "human-replan",
|
|
232
|
+
instructions: approval.output.instructions,
|
|
233
|
+
priorPlanDigest: currentPlanDigest(context),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
130
236
|
const ids = [
|
|
131
237
|
"classifyImplementation",
|
|
132
238
|
"classifyVerification",
|
|
@@ -198,7 +304,11 @@ function latestBlockedReason(context) {
|
|
|
198
304
|
"classifyImplementation",
|
|
199
305
|
"classifyVerification",
|
|
200
306
|
"triageReview",
|
|
307
|
+
"replanGuard",
|
|
201
308
|
"adoptPlan",
|
|
309
|
+
"findPlan",
|
|
310
|
+
"documentation",
|
|
311
|
+
"approval",
|
|
202
312
|
];
|
|
203
313
|
for (let index = context.state.steps.length - 1; index >= 0; index -= 1) {
|
|
204
314
|
const step = context.state.steps[index];
|
|
@@ -222,11 +332,46 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
222
332
|
title: ({ input }) => `autoimplement: ${input.task.slice(0, 60)}`,
|
|
223
333
|
presentationPrompt: "Summarize what was implemented, the review rounds by severity, the CI result, the PR or merge result, and any remaining limitation. Include exact validation commands.",
|
|
224
334
|
startAt: "prepare",
|
|
225
|
-
maxSteps:
|
|
335
|
+
maxSteps: 240,
|
|
226
336
|
includes: {
|
|
337
|
+
documentation: includeWorkflow(autodocWorkflow, {
|
|
338
|
+
input: (context) => {
|
|
339
|
+
const request = context.input;
|
|
340
|
+
const discovery = context.outputs.findPlan;
|
|
341
|
+
const plan = currentPlan(context);
|
|
342
|
+
if (plan === undefined)
|
|
343
|
+
throw new Error("autoimplement documentation is missing a plan");
|
|
344
|
+
return {
|
|
345
|
+
task: request.task,
|
|
346
|
+
plan,
|
|
347
|
+
...(request.repository !== undefined ? { repository: request.repository } : {}),
|
|
348
|
+
documents: request.documents ?? request.documentation?.documents ?? discovery?.documents ?? [],
|
|
349
|
+
evidence: latestIssue(context),
|
|
350
|
+
};
|
|
351
|
+
},
|
|
352
|
+
}),
|
|
353
|
+
approval: includeWorkflow(planApprovalWorkflow, {
|
|
354
|
+
input: (context) => {
|
|
355
|
+
const request = context.input;
|
|
356
|
+
if (request.approval === undefined) {
|
|
357
|
+
throw new Error("autoimplement approval was entered without an approval policy");
|
|
358
|
+
}
|
|
359
|
+
const plan = currentPlan(context);
|
|
360
|
+
if (plan === undefined)
|
|
361
|
+
throw new Error("autoimplement approval is missing a plan");
|
|
362
|
+
const revisions = context.state.steps.filter((step) => step.nodeId === "approval/approve").length;
|
|
363
|
+
return {
|
|
364
|
+
task: request.task,
|
|
365
|
+
plan,
|
|
366
|
+
planDigest: currentPlanDigest(context),
|
|
367
|
+
audience: request.approval.audience,
|
|
368
|
+
revision: revisions + 1,
|
|
369
|
+
};
|
|
370
|
+
},
|
|
371
|
+
}),
|
|
227
372
|
redesign: includeWorkflow({
|
|
228
|
-
workflow: "
|
|
229
|
-
contract:
|
|
373
|
+
workflow: "autoplan",
|
|
374
|
+
contract: autoplanWorkflow,
|
|
230
375
|
input: (context) => {
|
|
231
376
|
const request = context.input;
|
|
232
377
|
return {
|
|
@@ -251,26 +396,84 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
251
396
|
},
|
|
252
397
|
nodes: {
|
|
253
398
|
prepare: compute({
|
|
254
|
-
run: ({ input }) =>
|
|
255
|
-
|
|
256
|
-
|
|
399
|
+
run: ({ input }) => {
|
|
400
|
+
const request = input;
|
|
401
|
+
return {
|
|
402
|
+
route: request.plan === undefined
|
|
403
|
+
? "find"
|
|
404
|
+
: request.documentation?.status === "current"
|
|
405
|
+
? "ready"
|
|
406
|
+
: "document",
|
|
407
|
+
};
|
|
408
|
+
},
|
|
409
|
+
}),
|
|
410
|
+
findPlan: agent({
|
|
411
|
+
statusDetail: "finding existing plan",
|
|
412
|
+
prompt: ({ input }) => {
|
|
413
|
+
const request = input;
|
|
414
|
+
return [
|
|
415
|
+
"Find the clear plan that has already been selected for this task.",
|
|
416
|
+
"Use the current conversation context and referenced canonical documents.",
|
|
417
|
+
"Do not devise, improve, replace, document, or implement a plan.",
|
|
418
|
+
"Return blocked when no single clear existing plan can be found.",
|
|
419
|
+
"Report whether its canonical documentation is current, missing, or stale.",
|
|
420
|
+
`Task: ${request.task}`,
|
|
421
|
+
`Repository: ${request.repository ?? "current repository"}`,
|
|
422
|
+
`Referenced documents: ${JSON.stringify(request.documents ?? [])}`,
|
|
423
|
+
].join("\n");
|
|
424
|
+
},
|
|
425
|
+
expectedOutput: '{ "route": "found" | "blocked", "plan": {} (required when found), "documentation": "current" | "missing" | "stale" (required when found), "documents": ["canonical file"], "reason": "reason", "evidence": "evidence" }',
|
|
426
|
+
validate: parseExistingPlan,
|
|
427
|
+
}),
|
|
428
|
+
routeFoundPlan: compute({
|
|
429
|
+
run: ({ outputs }) => {
|
|
430
|
+
const discovered = outputs.findPlan;
|
|
431
|
+
if (discovered.route !== "found" || discovered.plan === undefined) {
|
|
432
|
+
return { route: "blocked", reason: discovered.reason, evidence: discovered.evidence };
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
route: discovered.documentation === "current" ? "ready" : "document",
|
|
436
|
+
plan: discovered.plan,
|
|
437
|
+
reason: discovered.reason,
|
|
438
|
+
evidence: discovered.evidence,
|
|
439
|
+
};
|
|
440
|
+
},
|
|
257
441
|
}),
|
|
258
442
|
adoptPlan: compute({
|
|
259
443
|
run: ({ outputs }) => {
|
|
260
|
-
const result = includedResult(
|
|
444
|
+
const result = includedResult(autoplanWorkflow, outputs.redesign);
|
|
261
445
|
if (result.exit !== "ready")
|
|
262
446
|
throw new Error("redesign did not return a ready plan");
|
|
263
447
|
return {
|
|
264
|
-
route: result.output.changed ? "
|
|
448
|
+
route: result.output.changed ? "document" : "blocked",
|
|
265
449
|
plan: result.output.plan,
|
|
266
450
|
planDigest: result.output.planDigest,
|
|
267
451
|
changed: result.output.changed,
|
|
268
452
|
reason: result.output.changed
|
|
269
|
-
? "The plan changed in response to new evidence."
|
|
453
|
+
? "The plan changed in response to new evidence and must be documented."
|
|
270
454
|
: "Redesign returned the same plan for the same unresolved evidence.",
|
|
271
455
|
};
|
|
272
456
|
},
|
|
273
457
|
}),
|
|
458
|
+
maybeApproval: compute({
|
|
459
|
+
run: ({ input }) => ({
|
|
460
|
+
route: input.approval === undefined ? "implement" : "approve",
|
|
461
|
+
}),
|
|
462
|
+
}),
|
|
463
|
+
replanGuard: compute({
|
|
464
|
+
run: (context) => {
|
|
465
|
+
const request = context.input;
|
|
466
|
+
const limit = request.approval?.maxReplans ?? 3;
|
|
467
|
+
const replans = context.state.steps.filter((step) => step.nodeId === "approval/replan").length;
|
|
468
|
+
return replans > limit
|
|
469
|
+
? {
|
|
470
|
+
route: "blocked",
|
|
471
|
+
reason: `Plan approval reached the ${limit}-replan safety limit.`,
|
|
472
|
+
evidence: context.outputs.approval,
|
|
473
|
+
}
|
|
474
|
+
: { route: "redesign", replans, limit };
|
|
475
|
+
},
|
|
476
|
+
}),
|
|
274
477
|
implement: agent({
|
|
275
478
|
timeoutMs: 60 * 60_000,
|
|
276
479
|
statusDetail: "implementing",
|
|
@@ -279,6 +482,8 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
279
482
|
return [
|
|
280
483
|
`Implement this task end-to-end: ${request.task}`,
|
|
281
484
|
`Plan: ${JSON.stringify(currentPlan(context))}`,
|
|
485
|
+
`Authorized scope: ${request.scope ?? request.repository ?? "the current repository and task"}`,
|
|
486
|
+
`Constraints: ${JSON.stringify(request.constraints ?? [])}`,
|
|
282
487
|
"Follow repository instructions and use the most elegant long-term production-ready implementation without unnecessary work.",
|
|
283
488
|
"If implementation exposes a new design or scope problem, report it precisely instead of forcing the old plan.",
|
|
284
489
|
"Do not merge yet.",
|
|
@@ -601,13 +806,40 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
601
806
|
edges: [
|
|
602
807
|
{
|
|
603
808
|
from: "prepare",
|
|
604
|
-
switch: {
|
|
809
|
+
switch: {
|
|
810
|
+
on: "$.route",
|
|
811
|
+
cases: { find: "findPlan", document: "documentation", ready: "maybeApproval" },
|
|
812
|
+
},
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
from: "findPlan",
|
|
816
|
+
switch: { on: "$.route", cases: { found: "routeFoundPlan", blocked: "blocked" } },
|
|
817
|
+
},
|
|
818
|
+
{
|
|
819
|
+
from: "routeFoundPlan",
|
|
820
|
+
switch: {
|
|
821
|
+
on: "$.route",
|
|
822
|
+
cases: { ready: "maybeApproval", document: "documentation", blocked: "blocked" },
|
|
823
|
+
},
|
|
605
824
|
},
|
|
606
825
|
{ from: "redesign.ready", to: "adoptPlan" },
|
|
607
826
|
{ from: "redesign.blocked", to: "blocked" },
|
|
608
827
|
{
|
|
609
828
|
from: "adoptPlan",
|
|
610
|
-
switch: { on: "$.route", cases: {
|
|
829
|
+
switch: { on: "$.route", cases: { document: "documentation", blocked: "blocked" } },
|
|
830
|
+
},
|
|
831
|
+
{ from: "documentation.ready", to: "maybeApproval" },
|
|
832
|
+
{ from: "documentation.blocked", to: "blocked" },
|
|
833
|
+
{
|
|
834
|
+
from: "maybeApproval",
|
|
835
|
+
switch: { on: "$.route", cases: { approve: "approval", implement: "implement" } },
|
|
836
|
+
},
|
|
837
|
+
{ from: "approval.continue", to: "implement" },
|
|
838
|
+
{ from: "approval.stop", to: "blocked" },
|
|
839
|
+
{ from: "approval.replan", to: "replanGuard" },
|
|
840
|
+
{
|
|
841
|
+
from: "replanGuard",
|
|
842
|
+
switch: { on: "$.route", cases: { redesign: "redesign", blocked: "blocked" } },
|
|
611
843
|
},
|
|
612
844
|
{ from: "implement", to: "classifyImplementation" },
|
|
613
845
|
{
|