@osolmaz/pi-workflows 0.12.0 → 0.13.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 +56 -31
- package/dist/builtins/autodoc.workflow.d.ts +4 -4
- package/dist/builtins/autoimplement.workflow.d.ts +797 -142
- package/dist/builtins/autoimplement.workflow.js +17 -105
- package/dist/builtins/autoimplement.workflow.js.map +1 -1
- package/dist/builtins/autoplan.workflow.d.ts +126 -13
- package/dist/builtins/autoplan.workflow.js +200 -29
- package/dist/builtins/autoplan.workflow.js.map +1 -1
- package/dist/builtins/catalog.js +7 -5
- package/dist/builtins/catalog.js.map +1 -1
- package/dist/builtins/index.d.ts +4 -2
- package/dist/builtins/index.js +3 -1
- package/dist/builtins/index.js.map +1 -1
- package/dist/builtins/monitor.workflow.d.ts +56 -23
- package/dist/builtins/monitor.workflow.js +508 -329
- package/dist/builtins/monitor.workflow.js.map +1 -1
- package/dist/builtins/pi-agent-group.d.ts +72 -0
- package/dist/builtins/pi-agent-group.js +1087 -0
- package/dist/builtins/pi-agent-group.js.map +1 -0
- package/dist/builtins/plain-summary.workflow.d.ts +32 -0
- package/dist/builtins/plain-summary.workflow.js +134 -0
- package/dist/builtins/plain-summary.workflow.js.map +1 -0
- package/dist/builtins/plan-approval.workflow.d.ts +39 -5
- package/dist/builtins/plan-approval.workflow.js +92 -14
- package/dist/builtins/plan-approval.workflow.js.map +1 -1
- package/dist/builtins/plan-change.workflow.d.ts +449 -0
- package/dist/builtins/plan-change.workflow.js +256 -0
- package/dist/builtins/plan-change.workflow.js.map +1 -0
- package/dist/builtins/plan-presentation.js +2 -2
- package/dist/builtins/plan-presentation.js.map +1 -1
- package/dist/builtins/sanity-check.workflow.d.ts +50 -6
- package/dist/builtins/sanity-check.workflow.js +150 -28
- package/dist/builtins/sanity-check.workflow.js.map +1 -1
- package/dist/controllers/effects.d.ts +3 -2
- package/dist/controllers/effects.js +8 -1
- package/dist/controllers/effects.js.map +1 -1
- package/dist/controllers/index.d.ts +1 -1
- package/dist/controllers/index.js +1 -1
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/manager.d.ts +1 -0
- package/dist/controllers/manager.js +41 -17
- package/dist/controllers/manager.js.map +1 -1
- package/dist/controllers/sqlite.d.ts +107 -85
- package/dist/controllers/sqlite.js +1611 -1486
- package/dist/controllers/sqlite.js.map +1 -1
- package/dist/controllers/store.d.ts +9 -8
- package/dist/controllers/store.js +1 -31
- package/dist/controllers/store.js.map +1 -1
- package/dist/controllers/types.d.ts +3 -0
- package/dist/controllers/workflow-engine-scheduler.d.ts +1 -1
- package/dist/controllers/workflow-engine-scheduler.js +3 -5
- package/dist/controllers/workflow-engine-scheduler.js.map +1 -1
- package/dist/controllers/workflows.d.ts +2 -2
- package/dist/controllers/workflows.js +11 -10
- package/dist/controllers/workflows.js.map +1 -1
- package/dist/extension/controller-host.js +2 -2
- package/dist/extension/controller-host.js.map +1 -1
- package/dist/extension/decision-channels.d.ts +4 -2
- package/dist/extension/decision-channels.js +333 -146
- package/dist/extension/decision-channels.js.map +1 -1
- package/dist/extension/executor.d.ts +9 -2
- package/dist/extension/executor.js +89 -2
- package/dist/extension/executor.js.map +1 -1
- package/dist/extension/herdr-viewer.d.ts +0 -1
- package/dist/extension/herdr-viewer.js +0 -4
- package/dist/extension/herdr-viewer.js.map +1 -1
- package/dist/extension/index.js +209 -127
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/recorder.d.ts +3 -10
- package/dist/extension/recorder.js +13 -22
- package/dist/extension/recorder.js.map +1 -1
- package/dist/extension/session-events.d.ts +2 -2
- package/dist/extension/step-message.d.ts +7 -2
- package/dist/extension/step-message.js +94 -2
- package/dist/extension/step-message.js.map +1 -1
- package/dist/extension/widget.js +29 -3
- package/dist/extension/widget.js.map +1 -1
- package/dist/host/rpc-executor.d.ts +3 -0
- package/dist/host/rpc-executor.js +2 -0
- package/dist/host/rpc-executor.js.map +1 -1
- package/dist/host/runner.d.ts +3 -6
- package/dist/host/runner.js +83 -32
- package/dist/host/runner.js.map +1 -1
- package/dist/render/graph-render.js +15 -10
- package/dist/render/graph-render.js.map +1 -1
- package/dist/state/database.d.ts +35 -0
- package/dist/state/database.js +287 -0
- package/dist/state/database.js.map +1 -0
- package/dist/state/index.d.ts +4 -0
- package/dist/state/index.js +5 -0
- package/dist/state/index.js.map +1 -0
- package/dist/state/json.d.ts +6 -0
- package/dist/state/json.js +38 -0
- package/dist/state/json.js.map +1 -0
- package/dist/state/mutation.d.ts +57 -0
- package/dist/state/mutation.js +255 -0
- package/dist/state/mutation.js.map +1 -0
- package/dist/state/schema.d.ts +6 -0
- package/dist/state/schema.js +473 -0
- package/dist/state/schema.js.map +1 -0
- package/dist/viewer/cli.d.ts +2 -2
- package/dist/viewer/cli.js +142 -122
- package/dist/viewer/cli.js.map +1 -1
- package/dist/viewer/render.d.ts +4 -4
- package/dist/viewer/render.js +9 -23
- package/dist/viewer/render.js.map +1 -1
- package/dist/viewer/session-reducer.d.ts +1 -1
- package/dist/viewer/session-reducer.js +1 -1
- package/dist/viewer/tui.d.ts +3 -3
- package/dist/viewer/tui.js +15 -13
- package/dist/viewer/tui.js.map +1 -1
- package/dist/viewer/watch.d.ts +2 -5
- package/dist/viewer/watch.js +13 -13
- package/dist/viewer/watch.js.map +1 -1
- package/dist/workflows/catalog.js +7 -2
- package/dist/workflows/catalog.js.map +1 -1
- package/dist/workflows/composition.js +20 -2
- package/dist/workflows/composition.js.map +1 -1
- package/dist/workflows/decision-presentation.d.ts +1 -1
- package/dist/workflows/decision-presentation.js +51 -38
- package/dist/workflows/decision-presentation.js.map +1 -1
- package/dist/workflows/definition.d.ts +6 -2
- package/dist/workflows/definition.js +17 -0
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/engine.d.ts +7 -7
- package/dist/workflows/engine.js +196 -115
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/errors.d.ts +16 -3
- package/dist/workflows/errors.js +18 -3
- package/dist/workflows/errors.js.map +1 -1
- package/dist/workflows/human-decision.d.ts +45 -8
- package/dist/workflows/human-decision.js +641 -274
- package/dist/workflows/human-decision.js.map +1 -1
- package/dist/workflows/index.d.ts +5 -6
- package/dist/workflows/index.js +4 -5
- package/dist/workflows/index.js.map +1 -1
- package/dist/workflows/progress.d.ts +1 -0
- package/dist/workflows/progress.js +15 -3
- package/dist/workflows/progress.js.map +1 -1
- package/dist/workflows/schema.js +27 -1
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/store.d.ts +83 -103
- package/dist/workflows/store.js +907 -951
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/types.d.ts +88 -126
- package/docs/CONTROLLERS.md +10 -8
- package/docs/DEFERRED_TURNS.md +2 -2
- package/docs/DESIGN_PHILOSOPHY.md +4 -2
- package/docs/HUMAN_DECISIONS.md +36 -47
- package/docs/HUMAN_DECISION_PRESENTATIONS.md +14 -24
- package/docs/MONITOR.md +179 -237
- package/docs/SQLITE_STATE.md +219 -0
- package/docs/WORKFLOW_COMPOSITION.md +27 -26
- package/docs/WORKFLOW_STEP_MESSAGES.md +20 -18
- package/docs/WORKFLOW_UPDATES.md +10 -9
- package/docs/development.md +9 -9
- package/docs/live-replay-protocol.md +28 -37
- package/docs/plans/2026-08-16-workflow-updates-plan.md +1 -1
- package/docs/plans/2026-08-19-human-decision-gates-plan.md +1 -1
- package/docs/plans/2026-08-21-autoimplement-timeout-fallback-plan.md +1 -1
- package/docs/plans/2026-08-21-plan-change-approval-policy-plan.md +322 -0
- package/docs/plans/2026-08-21-sanity-check-plan.md +217 -95
- package/docs/plans/2026-08-22-goal-finishing-monitor-plan.md +200 -0
- package/docs/plans/2026-08-23-assistant-agent-completion-plan.md +701 -0
- package/docs/plans/2026-08-23-sqlite-state-plan.md +970 -0
- package/docs/plans/replayable-run-bundles-implementation-plan.md +2 -2
- package/docs/plans/session-event-replay-implementation-plan.md +1 -1
- package/docs/plans/tui-viewer-implementation-plan.md +1 -1
- package/docs/session-event-journal.md +63 -434
- package/docs/tui-viewer.md +13 -15
- package/docs/workflows.md +127 -53
- package/examples/workflows/approved-plan.workflow.ts +19 -46
- package/examples/workflows/plain-summary.workflow.ts +1 -0
- package/herdr-plugin.toml +1 -1
- package/package.json +7 -7
- package/plugins/herdr/viewer.mjs +1 -11
- package/schemas/human-decision-accepted-v1.schema.json +15 -3
- package/schemas/human-decision-continuation-v1.schema.json +10 -1
- package/schemas/human-decision-delivery-v1.schema.json +8 -0
- package/schemas/human-decision-receipt-v1.schema.json +8 -0
- package/schemas/human-decision-request-v1.schema.json +24 -4
- package/skills/autoimplement/SKILL.md +27 -0
- package/skills/autoplan/SKILL.md +5 -4
- package/skills/monitor/SKILL.md +91 -135
- package/skills/pi-workflows/SKILL.md +9 -8
- package/skills/sanity-check/SKILL.md +44 -0
- package/src/builtins/autoimplement.workflow.ts +19 -118
- package/src/builtins/autoplan.workflow.ts +290 -40
- package/src/builtins/catalog.ts +7 -5
- package/src/builtins/index.ts +18 -1
- package/src/builtins/monitor.workflow.ts +673 -382
- package/src/builtins/pi-agent-group.ts +1407 -0
- package/src/builtins/plain-summary.workflow.ts +185 -0
- package/src/builtins/plan-approval.workflow.ts +157 -24
- package/src/builtins/plan-change.workflow.ts +321 -0
- package/src/builtins/plan-presentation.ts +2 -2
- package/src/builtins/sanity-check.workflow.ts +248 -48
- package/src/controllers/effects.ts +7 -0
- package/src/controllers/index.ts +0 -6
- package/src/controllers/manager.ts +72 -32
- package/src/controllers/sqlite.ts +2420 -1948
- package/src/controllers/store.ts +17 -38
- package/src/controllers/types.ts +3 -0
- package/src/controllers/workflow-engine-scheduler.ts +4 -8
- package/src/controllers/workflows.ts +45 -21
- package/src/extension/controller-host.ts +1 -2
- package/src/extension/decision-channels.ts +456 -203
- package/src/extension/executor.ts +105 -2
- package/src/extension/herdr-viewer.ts +0 -5
- package/src/extension/index.ts +251 -151
- package/src/extension/recorder.ts +13 -22
- package/src/extension/session-events.ts +2 -2
- package/src/extension/step-message.ts +106 -4
- package/src/extension/widget.ts +32 -5
- package/src/host/rpc-executor.ts +4 -0
- package/src/host/runner.ts +93 -41
- package/src/render/graph-render.ts +12 -6
- package/src/state/database.ts +375 -0
- package/src/state/index.ts +29 -0
- package/src/state/json.ts +42 -0
- package/src/state/mutation.ts +435 -0
- package/src/state/schema.ts +475 -0
- package/src/viewer/cli.ts +151 -144
- package/src/viewer/render.ts +19 -30
- package/src/viewer/session-reducer.ts +1 -1
- package/src/viewer/tui.ts +18 -17
- package/src/viewer/watch.ts +13 -17
- package/src/workflows/catalog.ts +7 -2
- package/src/workflows/composition.ts +21 -3
- package/src/workflows/decision-presentation.ts +56 -43
- package/src/workflows/definition.ts +36 -3
- package/src/workflows/engine.ts +228 -130
- package/src/workflows/errors.ts +27 -3
- package/src/workflows/human-decision.ts +921 -349
- package/src/workflows/index.ts +20 -30
- package/src/workflows/progress.ts +18 -3
- package/src/workflows/schema.ts +36 -1
- package/src/workflows/store.ts +1300 -1163
- package/src/workflows/types.ts +100 -137
- package/dist/builtins/sanity-check-session.d.ts +0 -17
- package/dist/builtins/sanity-check-session.js +0 -168
- package/dist/builtins/sanity-check-session.js.map +0 -1
- package/dist/workflows/artifacts.d.ts +0 -40
- package/dist/workflows/artifacts.js +0 -155
- package/dist/workflows/artifacts.js.map +0 -1
- package/dist/workflows/migrate-sources.d.ts +0 -42
- package/dist/workflows/migrate-sources.js +0 -133
- package/dist/workflows/migrate-sources.js.map +0 -1
- package/docs/run-bundles.md +0 -481
- package/schemas/human-decision-accepted-v2.schema.json +0 -50
- package/schemas/human-decision-delivery-v2.schema.json +0 -36
- package/schemas/human-decision-receipt-v2.schema.json +0 -39
- package/schemas/human-decision-request-v2.schema.json +0 -69
- package/schemas/human-decision-resolution-v2.schema.json +0 -27
- package/src/builtins/sanity-check-session.ts +0 -205
- package/src/workflows/artifacts.ts +0 -188
- package/src/workflows/migrate-sources.ts +0 -178
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { agent, compute, defineWorkflow } from "../workflows/definition.js";
|
|
2
|
+
import { agent, compute, defineWorkflow, includeWorkflow } from "../workflows/definition.js";
|
|
3
|
+
import plainSummaryWorkflow, {
|
|
4
|
+
type PlainSummaryInput,
|
|
5
|
+
type PlainSummaryResult,
|
|
6
|
+
} from "./plain-summary.workflow.js";
|
|
3
7
|
|
|
4
8
|
export type AutoplanInput = {
|
|
5
9
|
problem: string;
|
|
@@ -9,13 +13,47 @@ export type AutoplanInput = {
|
|
|
9
13
|
newEvidence?: unknown;
|
|
10
14
|
};
|
|
11
15
|
|
|
16
|
+
export type AutoplanCandidate = {
|
|
17
|
+
id: string;
|
|
18
|
+
title: string;
|
|
19
|
+
gist: string;
|
|
20
|
+
solution: string;
|
|
21
|
+
rationale: string;
|
|
22
|
+
parts: string[];
|
|
23
|
+
tradeoffs: string[];
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export type AutoplanProposal = {
|
|
27
|
+
candidates: AutoplanCandidate[];
|
|
28
|
+
previousPlan?:
|
|
29
|
+
| { status: "candidate"; candidateId: string }
|
|
30
|
+
| { status: "rejected"; reason: string };
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type AutoplanIdeal = {
|
|
34
|
+
ideal: string;
|
|
35
|
+
outsideDependencies: string[];
|
|
36
|
+
additionalValue: string[];
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type AutoplanSelection = {
|
|
40
|
+
status: "ready" | "blocked";
|
|
41
|
+
selectedId: string;
|
|
42
|
+
why: string;
|
|
43
|
+
relationshipToIdeal: string;
|
|
44
|
+
rejected: Array<{ id: string; reason: string }>;
|
|
45
|
+
compromises: string[];
|
|
46
|
+
blocker?: string;
|
|
47
|
+
};
|
|
48
|
+
|
|
12
49
|
export type AutoplanReady = {
|
|
13
50
|
status: "ready";
|
|
14
51
|
frame: unknown;
|
|
15
|
-
proposal:
|
|
16
|
-
ideal:
|
|
17
|
-
selection:
|
|
52
|
+
proposal: AutoplanProposal;
|
|
53
|
+
ideal: AutoplanIdeal;
|
|
54
|
+
selection: AutoplanSelection;
|
|
18
55
|
plan: unknown;
|
|
56
|
+
plainSummary: PlainSummaryResult;
|
|
19
57
|
planDigest: string;
|
|
20
58
|
previousPlanDigest?: string;
|
|
21
59
|
changed: boolean;
|
|
@@ -24,9 +62,10 @@ export type AutoplanReady = {
|
|
|
24
62
|
export type AutoplanBlocked = {
|
|
25
63
|
status: "blocked";
|
|
26
64
|
frame: unknown;
|
|
27
|
-
proposal:
|
|
28
|
-
ideal:
|
|
29
|
-
selection:
|
|
65
|
+
proposal: AutoplanProposal;
|
|
66
|
+
ideal: AutoplanIdeal;
|
|
67
|
+
selection: AutoplanSelection;
|
|
68
|
+
plainSummary: PlainSummaryResult;
|
|
30
69
|
reason: string;
|
|
31
70
|
};
|
|
32
71
|
|
|
@@ -44,6 +83,24 @@ function requireString(value: unknown, label: string): string {
|
|
|
44
83
|
return value.trim();
|
|
45
84
|
}
|
|
46
85
|
|
|
86
|
+
function requireBoundedString(value: unknown, label: string, maxChars: number): string {
|
|
87
|
+
const text = requireString(value, label);
|
|
88
|
+
if (text.length > maxChars) throw new Error(`${label} exceeds ${maxChars} characters`);
|
|
89
|
+
return text;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function requireStringArray(
|
|
93
|
+
value: unknown,
|
|
94
|
+
label: string,
|
|
95
|
+
maxItems = 32,
|
|
96
|
+
maxChars = 2_000,
|
|
97
|
+
): string[] {
|
|
98
|
+
if (!Array.isArray(value) || value.length > maxItems) {
|
|
99
|
+
throw new Error(`${label} must be an array with at most ${maxItems} strings`);
|
|
100
|
+
}
|
|
101
|
+
return value.map((item, index) => requireBoundedString(item, `${label}[${index}]`, maxChars));
|
|
102
|
+
}
|
|
103
|
+
|
|
47
104
|
function parseInput(value: unknown): AutoplanInput {
|
|
48
105
|
const input = requireRecord(value, "autoplan input");
|
|
49
106
|
const constraints = input.constraints;
|
|
@@ -62,34 +119,216 @@ function parseInput(value: unknown): AutoplanInput {
|
|
|
62
119
|
};
|
|
63
120
|
}
|
|
64
121
|
|
|
65
|
-
function
|
|
122
|
+
function parseProposal(value: unknown, previousPlanSupplied: boolean): AutoplanProposal {
|
|
123
|
+
const proposal = requireRecord(value, "autoplan proposal");
|
|
124
|
+
if (
|
|
125
|
+
!Array.isArray(proposal.candidates) ||
|
|
126
|
+
proposal.candidates.length < 2 ||
|
|
127
|
+
proposal.candidates.length > 4
|
|
128
|
+
) {
|
|
129
|
+
throw new Error("autoplan proposal must contain two through four candidates");
|
|
130
|
+
}
|
|
131
|
+
const ids = new Set<string>();
|
|
132
|
+
const candidates = proposal.candidates.map((value, index): AutoplanCandidate => {
|
|
133
|
+
const candidate = requireRecord(value, `autoplan candidate ${index + 1}`);
|
|
134
|
+
const id = requireString(candidate.id, `autoplan candidate ${index + 1} id`);
|
|
135
|
+
if (!/^[a-z][a-z0-9-]{0,63}$/.test(id)) {
|
|
136
|
+
throw new Error(`autoplan candidate id ${JSON.stringify(id)} is invalid`);
|
|
137
|
+
}
|
|
138
|
+
if (id === "ideal" || ids.has(id)) {
|
|
139
|
+
throw new Error(`autoplan candidate id ${JSON.stringify(id)} is reserved or duplicated`);
|
|
140
|
+
}
|
|
141
|
+
ids.add(id);
|
|
142
|
+
return {
|
|
143
|
+
id,
|
|
144
|
+
title: requireBoundedString(candidate.title, `autoplan candidate ${id} title`, 200),
|
|
145
|
+
gist: requireBoundedString(candidate.gist, `autoplan candidate ${id} gist`, 1_000),
|
|
146
|
+
solution: requireBoundedString(
|
|
147
|
+
candidate.solution,
|
|
148
|
+
`autoplan candidate ${id} solution`,
|
|
149
|
+
20_000,
|
|
150
|
+
),
|
|
151
|
+
rationale: requireBoundedString(
|
|
152
|
+
candidate.rationale,
|
|
153
|
+
`autoplan candidate ${id} rationale`,
|
|
154
|
+
5_000,
|
|
155
|
+
),
|
|
156
|
+
parts: requireStringArray(candidate.parts, `autoplan candidate ${id} parts`),
|
|
157
|
+
tradeoffs: requireStringArray(candidate.tradeoffs, `autoplan candidate ${id} tradeoffs`),
|
|
158
|
+
};
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
let previousPlan: AutoplanProposal["previousPlan"];
|
|
162
|
+
if (proposal.previousPlan !== undefined) {
|
|
163
|
+
const account = requireRecord(proposal.previousPlan, "autoplan previousPlan account");
|
|
164
|
+
if (account.status === "candidate") {
|
|
165
|
+
const candidateId = requireString(account.candidateId, "autoplan previousPlan candidateId");
|
|
166
|
+
if (!ids.has(candidateId)) {
|
|
167
|
+
throw new Error("autoplan previousPlan candidateId must name a candidate");
|
|
168
|
+
}
|
|
169
|
+
previousPlan = { status: "candidate", candidateId };
|
|
170
|
+
} else if (account.status === "rejected") {
|
|
171
|
+
previousPlan = {
|
|
172
|
+
status: "rejected",
|
|
173
|
+
reason: requireBoundedString(
|
|
174
|
+
account.reason,
|
|
175
|
+
"autoplan previousPlan rejection reason",
|
|
176
|
+
5_000,
|
|
177
|
+
),
|
|
178
|
+
};
|
|
179
|
+
} else {
|
|
180
|
+
throw new Error("autoplan previousPlan status must be candidate or rejected");
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (previousPlanSupplied && previousPlan === undefined) {
|
|
184
|
+
throw new Error("autoplan proposal must account for the supplied previous plan");
|
|
185
|
+
}
|
|
186
|
+
return { candidates, ...(previousPlan !== undefined ? { previousPlan } : {}) };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function parseIdeal(value: unknown): AutoplanIdeal {
|
|
190
|
+
const ideal = requireRecord(value, "autoplan ideal");
|
|
191
|
+
return {
|
|
192
|
+
ideal: requireBoundedString(ideal.ideal, "autoplan ideal end state", 20_000),
|
|
193
|
+
outsideDependencies: requireStringArray(
|
|
194
|
+
ideal.outsideDependencies,
|
|
195
|
+
"autoplan ideal outsideDependencies",
|
|
196
|
+
),
|
|
197
|
+
additionalValue: requireStringArray(ideal.additionalValue, "autoplan ideal additionalValue"),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function parseSelection(value: unknown, proposal: AutoplanProposal): AutoplanSelection {
|
|
66
202
|
const selection = requireRecord(value, "autoplan selection");
|
|
67
203
|
if (selection.status !== "ready" && selection.status !== "blocked") {
|
|
68
204
|
throw new Error("autoplan selection status must be ready or blocked");
|
|
69
205
|
}
|
|
70
|
-
|
|
71
|
-
requireString(selection.
|
|
72
|
-
if (
|
|
73
|
-
|
|
206
|
+
const validIds = new Set([...proposal.candidates.map((candidate) => candidate.id), "ideal"]);
|
|
207
|
+
const selectedId = requireString(selection.selectedId, "autoplan selectedId");
|
|
208
|
+
if (!validIds.has(selectedId)) throw new Error("autoplan selectedId must name a candidate");
|
|
209
|
+
if (!Array.isArray(selection.rejected)) {
|
|
210
|
+
throw new Error("autoplan rejected plans must be an array");
|
|
211
|
+
}
|
|
212
|
+
const rejectedIds = new Set<string>();
|
|
213
|
+
const rejected = selection.rejected.map((value, index) => {
|
|
214
|
+
const rejection = requireRecord(value, `autoplan rejection ${index + 1}`);
|
|
215
|
+
const id = requireString(rejection.id, `autoplan rejection ${index + 1} id`);
|
|
216
|
+
if (!validIds.has(id) || id === selectedId || rejectedIds.has(id)) {
|
|
217
|
+
throw new Error(`autoplan rejected id ${JSON.stringify(id)} is invalid or duplicated`);
|
|
218
|
+
}
|
|
219
|
+
rejectedIds.add(id);
|
|
220
|
+
return {
|
|
221
|
+
id,
|
|
222
|
+
reason: requireBoundedString(rejection.reason, `autoplan rejection ${id} reason`, 5_000),
|
|
223
|
+
};
|
|
224
|
+
});
|
|
225
|
+
const expectedRejected = [...validIds].filter((id) => id !== selectedId).sort();
|
|
226
|
+
if (JSON.stringify([...rejectedIds].sort()) !== JSON.stringify(expectedRejected)) {
|
|
227
|
+
throw new Error("autoplan selection must reject every non-selected candidate exactly once");
|
|
228
|
+
}
|
|
229
|
+
const blocker =
|
|
230
|
+
selection.status === "blocked"
|
|
231
|
+
? requireString(selection.blocker, "autoplan blocker")
|
|
232
|
+
: undefined;
|
|
233
|
+
return {
|
|
234
|
+
status: selection.status,
|
|
235
|
+
selectedId,
|
|
236
|
+
why: requireBoundedString(selection.why, "autoplan selection reason", 5_000),
|
|
237
|
+
relationshipToIdeal: requireBoundedString(
|
|
238
|
+
selection.relationshipToIdeal,
|
|
239
|
+
"autoplan relationshipToIdeal",
|
|
240
|
+
5_000,
|
|
241
|
+
),
|
|
242
|
+
rejected,
|
|
243
|
+
compromises: requireStringArray(selection.compromises, "autoplan compromises"),
|
|
244
|
+
...(blocker !== undefined ? { blocker } : {}),
|
|
245
|
+
};
|
|
74
246
|
}
|
|
75
247
|
|
|
76
248
|
function digest(value: unknown): string {
|
|
77
249
|
return `sha256:${createHash("sha256").update(JSON.stringify(value)).digest("hex")}`;
|
|
78
250
|
}
|
|
79
251
|
|
|
252
|
+
function plainSummaryResult(value: unknown, label: string): PlainSummaryResult {
|
|
253
|
+
const included = requireRecord(value, label);
|
|
254
|
+
if (included.exit !== "completed") throw new Error(`${label} must use the completed exit`);
|
|
255
|
+
const result = requireRecord(included.output, `${label} output`);
|
|
256
|
+
return { text: requireString(result.text, `${label} text`) };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function candidateSummary(
|
|
260
|
+
proposal: AutoplanProposal,
|
|
261
|
+
ideal: AutoplanIdeal,
|
|
262
|
+
id: string,
|
|
263
|
+
): { id: string; title: string; gist: string } {
|
|
264
|
+
if (id === "ideal") return { id, title: "Ideal end state", gist: ideal.ideal };
|
|
265
|
+
const candidate = proposal.candidates.find((item) => item.id === id);
|
|
266
|
+
if (candidate === undefined)
|
|
267
|
+
throw new Error(`autoplan candidate ${JSON.stringify(id)} is missing`);
|
|
268
|
+
return { id, title: candidate.title, gist: candidate.gist };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function summaryInput(
|
|
272
|
+
outputs: Record<string, unknown>,
|
|
273
|
+
blocked: boolean,
|
|
274
|
+
input: AutoplanInput,
|
|
275
|
+
): PlainSummaryInput {
|
|
276
|
+
const proposal = outputs.propose as AutoplanProposal;
|
|
277
|
+
const selection = outputs.choose as AutoplanSelection;
|
|
278
|
+
const ideal = outputs.ideal as AutoplanIdeal;
|
|
279
|
+
const selected = candidateSummary(proposal, ideal, selection.selectedId);
|
|
280
|
+
return {
|
|
281
|
+
source: {
|
|
282
|
+
status: selection.status,
|
|
283
|
+
selected,
|
|
284
|
+
why: selection.why,
|
|
285
|
+
implementationPlan: blocked ? null : outputs.plan,
|
|
286
|
+
rejected: selection.rejected.map((rejection) => ({
|
|
287
|
+
...candidateSummary(proposal, ideal, rejection.id),
|
|
288
|
+
reason: rejection.reason,
|
|
289
|
+
})),
|
|
290
|
+
relationshipToIdeal: selection.relationshipToIdeal,
|
|
291
|
+
compromises: selection.compromises,
|
|
292
|
+
...(proposal.previousPlan !== undefined && input.previousPlan !== undefined
|
|
293
|
+
? { previousPlan: { plan: input.previousPlan, account: proposal.previousPlan } }
|
|
294
|
+
: {}),
|
|
295
|
+
...(selection.blocker !== undefined ? { blocker: selection.blocker } : {}),
|
|
296
|
+
},
|
|
297
|
+
purpose: blocked
|
|
298
|
+
? "Explain plainly why planning is blocked and summarize every considered plan."
|
|
299
|
+
: "Explain the recommended plan plainly, summarize its main implementation steps, and give one-line reasons for rejecting every other plan.",
|
|
300
|
+
mustInclude: [
|
|
301
|
+
selected.title,
|
|
302
|
+
...selection.rejected.map(
|
|
303
|
+
(rejection) => candidateSummary(proposal, ideal, rejection.id).title,
|
|
304
|
+
),
|
|
305
|
+
...(proposal.previousPlan !== undefined && input.previousPlan !== undefined
|
|
306
|
+
? ["Previous plan"]
|
|
307
|
+
: []),
|
|
308
|
+
...(blocked ? [selection.blocker as string] : ["The plan is selected for approval"]),
|
|
309
|
+
],
|
|
310
|
+
maxChars: 2_500,
|
|
311
|
+
maxSentences: 12,
|
|
312
|
+
format: "mixed",
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
80
316
|
export const autoplanWorkflow = defineWorkflow({
|
|
81
317
|
source: import.meta.url,
|
|
82
318
|
contractId: "pi-workflows.autoplan.v1",
|
|
83
319
|
name: "autoplan",
|
|
84
320
|
input: parseInput,
|
|
85
321
|
title: ({ input }) => `autoplan: ${input.problem.slice(0, 60)}`,
|
|
86
|
-
presentationPrompt: [
|
|
87
|
-
"Present the selected practical solution and its implementation plan.",
|
|
88
|
-
"Briefly state how the ideal informed the choice and what was excluded as outside scope.",
|
|
89
|
-
"Do not ask the user to choose between the options.",
|
|
90
|
-
].join("\n"),
|
|
91
322
|
startAt: "frame",
|
|
92
|
-
maxSteps:
|
|
323
|
+
maxSteps: 16,
|
|
324
|
+
includes: {
|
|
325
|
+
readySummary: includeWorkflow(plainSummaryWorkflow, {
|
|
326
|
+
input: ({ outputs, input }) => summaryInput(outputs, false, input as AutoplanInput),
|
|
327
|
+
}),
|
|
328
|
+
blockedSummary: includeWorkflow(plainSummaryWorkflow, {
|
|
329
|
+
input: ({ outputs, input }) => summaryInput(outputs, true, input as AutoplanInput),
|
|
330
|
+
}),
|
|
331
|
+
},
|
|
93
332
|
exits: {
|
|
94
333
|
ready: {
|
|
95
334
|
from: "finalize",
|
|
@@ -119,32 +358,36 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
119
358
|
validate: (value) => requireRecord(value, "autoplan frame"),
|
|
120
359
|
}),
|
|
121
360
|
propose: agent({
|
|
122
|
-
statusDetail: "devising
|
|
123
|
-
prompt: ({ outputs }) =>
|
|
361
|
+
statusDetail: "devising candidate solutions",
|
|
362
|
+
prompt: ({ outputs, input }) =>
|
|
124
363
|
[
|
|
125
|
-
"Devise
|
|
364
|
+
"Devise two through four distinct practical solutions within the framed scope.",
|
|
365
|
+
"Each candidate needs a stable lowercase id, short title, plain gist, full solution, rationale, parts, and trade-offs.",
|
|
126
366
|
"Prefer a small number of general parts, clear ownership boundaries, and existing public interfaces.",
|
|
127
367
|
"Avoid one-off mechanisms and unnecessary infrastructure.",
|
|
368
|
+
"When a previous plan exists, mark it as a candidate or reject it with a reason.",
|
|
128
369
|
"Do not implement anything.",
|
|
129
370
|
`Problem frame: ${JSON.stringify(outputs.frame)}`,
|
|
371
|
+
`Previous plan: ${JSON.stringify((input as AutoplanInput).previousPlan ?? null)}`,
|
|
130
372
|
].join("\n"),
|
|
131
|
-
expectedOutput: `{ "solution": "proposal", "rationale": "why", "parts": ["part"], "tradeoffs": ["trade-off"] }`,
|
|
132
|
-
validate: (value
|
|
373
|
+
expectedOutput: `{ "candidates": [{ "id": "stable-id", "title": "short title", "gist": "plain gist", "solution": "full proposal", "rationale": "why", "parts": ["part"], "tradeoffs": ["trade-off"] }], "previousPlan": { "status": "candidate", "candidateId": "id" } | { "status": "rejected", "reason": "reason" } }`,
|
|
374
|
+
validate: (value, { input }) =>
|
|
375
|
+
parseProposal(value, (input as AutoplanInput).previousPlan !== undefined),
|
|
133
376
|
}),
|
|
134
377
|
ideal: agent({
|
|
135
378
|
statusDetail: "describing the ideal end state",
|
|
136
379
|
prompt: ({ outputs, input }) =>
|
|
137
380
|
[
|
|
138
|
-
"Set the
|
|
139
|
-
"The holy grail can match
|
|
381
|
+
"Set the practical candidates aside and describe the holy grail for this problem.",
|
|
382
|
+
"The holy grail can match a candidate or exceed the current scope.",
|
|
140
383
|
"Name dependencies outside our authority instead of assuming they can change.",
|
|
141
|
-
"Explain the practical value beyond the
|
|
384
|
+
"Explain the practical value beyond the candidates.",
|
|
142
385
|
`Problem frame: ${JSON.stringify(outputs.frame)}`,
|
|
143
|
-
`
|
|
386
|
+
`Candidates: ${JSON.stringify(outputs.propose)}`,
|
|
144
387
|
`New evidence: ${JSON.stringify((input as AutoplanInput).newEvidence ?? null)}`,
|
|
145
388
|
].join("\n"),
|
|
146
389
|
expectedOutput: `{ "ideal": "ideal end state", "outsideDependencies": ["dependency"], "additionalValue": ["benefit"] }`,
|
|
147
|
-
validate:
|
|
390
|
+
validate: parseIdeal,
|
|
148
391
|
}),
|
|
149
392
|
choose: agent({
|
|
150
393
|
statusDetail: "choosing the practical solution",
|
|
@@ -152,17 +395,19 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
152
395
|
[
|
|
153
396
|
"Choose the right solution without asking the user to decide.",
|
|
154
397
|
"Choose the ideal when it is production-ready, proportionate, in scope, and implementable through interfaces we control.",
|
|
155
|
-
"Otherwise choose the strongest practical in-scope
|
|
398
|
+
"Otherwise choose the strongest practical in-scope candidate with a clear path toward the ideal.",
|
|
156
399
|
"Do not block only because the ideal depends on work outside our authority.",
|
|
157
400
|
"Do not make an upstream change, unrelated repository, new service, or unapproved resource a requirement.",
|
|
158
401
|
"Prefer the simpler choice when options give materially equivalent results.",
|
|
402
|
+
"Return one rejection reason for every non-selected candidate, including the ideal when it is not selected.",
|
|
159
403
|
"Return blocked only when no truthful in-scope solution can meet the success criteria.",
|
|
160
404
|
`Frame: ${JSON.stringify(outputs.frame)}`,
|
|
161
|
-
`
|
|
405
|
+
`Candidates: ${JSON.stringify(outputs.propose)}`,
|
|
406
|
+
`Ideal candidate id: ideal`,
|
|
162
407
|
`Ideal: ${JSON.stringify(outputs.ideal)}`,
|
|
163
408
|
].join("\n"),
|
|
164
|
-
expectedOutput: `{ "status": "ready" | "blocked", "
|
|
165
|
-
validate: parseSelection,
|
|
409
|
+
expectedOutput: `{ "status": "ready" | "blocked", "selectedId": "candidate-id-or-ideal", "why": "reason", "relationshipToIdeal": "relationship", "rejected": [{ "id": "other-id", "reason": "why it lost" }], "compromises": ["compromise"], "blocker": "required only when blocked" }`,
|
|
410
|
+
validate: (value, { outputs }) => parseSelection(value, outputs.propose as AutoplanProposal),
|
|
166
411
|
}),
|
|
167
412
|
plan: agent({
|
|
168
413
|
timeoutMs: 30 * 60_000,
|
|
@@ -177,6 +422,7 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
177
422
|
"Do not implement the plan.",
|
|
178
423
|
`Frame: ${JSON.stringify(outputs.frame)}`,
|
|
179
424
|
`Selection: ${JSON.stringify(outputs.choose)}`,
|
|
425
|
+
`Candidates: ${JSON.stringify(outputs.propose)}`,
|
|
180
426
|
`Previous plan: ${JSON.stringify((input as AutoplanInput).previousPlan ?? null)}`,
|
|
181
427
|
`New evidence: ${JSON.stringify((input as AutoplanInput).newEvidence ?? null)}`,
|
|
182
428
|
].join("\n"),
|
|
@@ -185,13 +431,14 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
185
431
|
}),
|
|
186
432
|
blocked: compute({
|
|
187
433
|
run: ({ outputs }) => {
|
|
188
|
-
const selection = outputs.choose as
|
|
434
|
+
const selection = outputs.choose as AutoplanSelection;
|
|
189
435
|
return {
|
|
190
436
|
status: "blocked",
|
|
191
437
|
frame: outputs.frame,
|
|
192
|
-
proposal: outputs.propose,
|
|
193
|
-
ideal: outputs.ideal,
|
|
438
|
+
proposal: outputs.propose as AutoplanProposal,
|
|
439
|
+
ideal: outputs.ideal as AutoplanIdeal,
|
|
194
440
|
selection,
|
|
441
|
+
plainSummary: plainSummaryResult(outputs.blockedSummary, "autoplan blocked summary"),
|
|
195
442
|
reason: requireString(selection.blocker, "autoplan blocker"),
|
|
196
443
|
} satisfies AutoplanBlocked;
|
|
197
444
|
},
|
|
@@ -205,10 +452,11 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
205
452
|
return {
|
|
206
453
|
status: "ready",
|
|
207
454
|
frame: outputs.frame,
|
|
208
|
-
proposal: outputs.propose,
|
|
209
|
-
ideal: outputs.ideal,
|
|
210
|
-
selection: outputs.choose,
|
|
455
|
+
proposal: outputs.propose as AutoplanProposal,
|
|
456
|
+
ideal: outputs.ideal as AutoplanIdeal,
|
|
457
|
+
selection: outputs.choose as AutoplanSelection,
|
|
211
458
|
plan: outputs.plan,
|
|
459
|
+
plainSummary: plainSummaryResult(outputs.readySummary, "autoplan ready summary"),
|
|
212
460
|
planDigest,
|
|
213
461
|
...(previousPlanDigest !== undefined ? { previousPlanDigest } : {}),
|
|
214
462
|
changed: previousPlanDigest === undefined || previousPlanDigest !== planDigest,
|
|
@@ -222,9 +470,11 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
222
470
|
{ from: "ideal", to: "choose" },
|
|
223
471
|
{
|
|
224
472
|
from: "choose",
|
|
225
|
-
switch: { on: "$.status", cases: { ready: "plan", blocked: "
|
|
473
|
+
switch: { on: "$.status", cases: { ready: "plan", blocked: "blockedSummary" } },
|
|
226
474
|
},
|
|
227
|
-
{ from: "plan", to: "
|
|
475
|
+
{ from: "plan", to: "readySummary" },
|
|
476
|
+
{ from: "readySummary.completed", to: "finalize" },
|
|
477
|
+
{ from: "blockedSummary.completed", to: "blocked" },
|
|
228
478
|
],
|
|
229
479
|
});
|
|
230
480
|
|
package/src/builtins/catalog.ts
CHANGED
|
@@ -3,18 +3,20 @@ import autodocWorkflow from "./autodoc.workflow.js";
|
|
|
3
3
|
import autoimplementWorkflow from "./autoimplement.workflow.js";
|
|
4
4
|
import autoplanWorkflow from "./autoplan.workflow.js";
|
|
5
5
|
import monitorWorkflow from "./monitor.workflow.js";
|
|
6
|
+
import plainSummaryWorkflow from "./plain-summary.workflow.js";
|
|
6
7
|
import planApprovalWorkflow from "./plan-approval.workflow.js";
|
|
7
8
|
import sanityCheckWorkflow from "./sanity-check.workflow.js";
|
|
8
9
|
|
|
9
10
|
export const builtinWorkflowCatalog = new BuiltinWorkflowCatalog([
|
|
10
|
-
{ id: "
|
|
11
|
+
{ id: "plain-summary", revision: "1", definition: plainSummaryWorkflow },
|
|
12
|
+
{ id: "autoplan", revision: "2", definition: autoplanWorkflow },
|
|
11
13
|
{ id: "autodoc", revision: "1", definition: autodocWorkflow },
|
|
12
|
-
{ id: "autoimplement", revision: "
|
|
13
|
-
{ id: "plan-approval", revision: "
|
|
14
|
-
{ id: "sanity-check", revision: "
|
|
14
|
+
{ id: "autoimplement", revision: "9", definition: autoimplementWorkflow },
|
|
15
|
+
{ id: "plan-approval", revision: "4", definition: planApprovalWorkflow },
|
|
16
|
+
{ id: "sanity-check", revision: "4", definition: sanityCheckWorkflow },
|
|
15
17
|
{
|
|
16
18
|
id: "monitor",
|
|
17
|
-
revision: "
|
|
19
|
+
revision: "11",
|
|
18
20
|
definition: monitorWorkflow,
|
|
19
21
|
legacySources: [
|
|
20
22
|
{
|
package/src/builtins/index.ts
CHANGED
|
@@ -21,8 +21,20 @@ export type { AutoimplementConcurrency } from "./autoimplement-command-batches.j
|
|
|
21
21
|
export {
|
|
22
22
|
default as monitorWorkflow,
|
|
23
23
|
type MonitorInput,
|
|
24
|
-
type
|
|
24
|
+
type MonitorObservation,
|
|
25
25
|
} from "./monitor.workflow.js";
|
|
26
|
+
export {
|
|
27
|
+
plainSummaryWorkflow,
|
|
28
|
+
type PlainSummaryFormat,
|
|
29
|
+
type PlainSummaryInput,
|
|
30
|
+
type PlainSummaryResult,
|
|
31
|
+
} from "./plain-summary.workflow.js";
|
|
32
|
+
export {
|
|
33
|
+
planChangeWorkflow,
|
|
34
|
+
type PlanChangeBlocked,
|
|
35
|
+
type PlanChangeInput,
|
|
36
|
+
type PlanChangeReady,
|
|
37
|
+
} from "./plan-change.workflow.js";
|
|
26
38
|
export { presentPlan } from "./plan-presentation.js";
|
|
27
39
|
export {
|
|
28
40
|
sanityCheckWorkflow,
|
|
@@ -38,8 +50,13 @@ export {
|
|
|
38
50
|
} from "./sanity-check.workflow.js";
|
|
39
51
|
export {
|
|
40
52
|
planApprovalWorkflow,
|
|
53
|
+
parsePlanApprovalPolicy,
|
|
41
54
|
type PlanApprovalContinue,
|
|
42
55
|
type PlanApprovalInput,
|
|
56
|
+
type PlanApprovalMode,
|
|
57
|
+
type PlanApprovalPolicy,
|
|
43
58
|
type PlanApprovalReplan,
|
|
59
|
+
type PlanApprovalResolution,
|
|
44
60
|
type PlanApprovalStop,
|
|
61
|
+
type ResolvedPlanApprovalPolicy,
|
|
45
62
|
} from "./plan-approval.workflow.js";
|