@osolmaz/pi-workflows 0.13.2 → 0.13.4
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 +5 -3
- package/dist/builtins/autodoc.workflow.d.ts +5 -5
- package/dist/builtins/autoimplement.workflow.d.ts +77 -73
- package/dist/builtins/autoimplement.workflow.js +47 -8
- package/dist/builtins/autoimplement.workflow.js.map +1 -1
- package/dist/builtins/autoplan.workflow.d.ts +8 -8
- package/dist/builtins/autoplan.workflow.js +44 -35
- package/dist/builtins/autoplan.workflow.js.map +1 -1
- package/dist/builtins/catalog.js +2 -2
- package/dist/builtins/change-verification.workflow.d.ts +1 -1
- package/dist/builtins/plain-summary.workflow.d.ts +1 -1
- package/dist/builtins/plan-approval.workflow.d.ts +1 -1
- package/dist/builtins/plan-change.workflow.d.ts +29 -29
- package/dist/builtins/sanity-check.workflow.d.ts +3 -3
- package/dist/builtins/workspace-preparation.workflow.d.ts +1 -1
- package/dist/controllers/index.d.ts +2 -2
- package/dist/controllers/index.js.map +1 -1
- package/dist/controllers/sqlite.js +85 -23
- package/dist/controllers/sqlite.js.map +1 -1
- package/dist/controllers/types.d.ts +34 -0
- package/dist/controllers/workflow-engine-scheduler.d.ts +5 -1
- package/dist/controllers/workflow-engine-scheduler.js +83 -1
- package/dist/controllers/workflow-engine-scheduler.js.map +1 -1
- package/dist/controllers/workflows.d.ts +8 -1
- package/dist/controllers/workflows.js +36 -0
- package/dist/controllers/workflows.js.map +1 -1
- package/dist/extension/controller-host.d.ts +2 -1
- package/dist/extension/controller-host.js +1 -1
- package/dist/extension/controller-host.js.map +1 -1
- package/dist/extension/follow-up-coordinator.d.ts +27 -0
- package/dist/extension/follow-up-coordinator.js +131 -0
- package/dist/extension/follow-up-coordinator.js.map +1 -0
- package/dist/extension/index.d.ts +9 -0
- package/dist/extension/index.js +460 -75
- package/dist/extension/index.js.map +1 -1
- package/dist/extension/session-events.d.ts +2 -3
- package/dist/extension/session-events.js +11 -10
- package/dist/extension/session-events.js.map +1 -1
- package/dist/extension/widget.js +9 -0
- package/dist/extension/widget.js.map +1 -1
- package/dist/state/database.d.ts +2 -1
- package/dist/state/database.js +11 -13
- package/dist/state/database.js.map +1 -1
- package/dist/state/json.js +6 -1
- package/dist/state/json.js.map +1 -1
- package/dist/state/mutation.d.ts +1 -1
- package/dist/state/mutation.js.map +1 -1
- package/dist/state/prune.d.ts +18 -0
- package/dist/state/prune.js +373 -0
- package/dist/state/prune.js.map +1 -0
- package/dist/state/schema.d.ts +1 -1
- package/dist/state/schema.js +116 -18
- package/dist/state/schema.js.map +1 -1
- package/dist/viewer/cli.d.ts +3 -1
- package/dist/viewer/cli.js +55 -4
- package/dist/viewer/cli.js.map +1 -1
- package/dist/viewer/render.js +19 -1
- package/dist/viewer/render.js.map +1 -1
- package/dist/workflows/composition.d.ts +2 -0
- package/dist/workflows/composition.js +15 -0
- package/dist/workflows/composition.js.map +1 -1
- package/dist/workflows/definition.d.ts +6 -3
- package/dist/workflows/definition.js +3 -0
- package/dist/workflows/definition.js.map +1 -1
- package/dist/workflows/engine.d.ts +6 -1
- package/dist/workflows/engine.js +301 -35
- package/dist/workflows/engine.js.map +1 -1
- package/dist/workflows/human-decision.d.ts +1 -0
- package/dist/workflows/human-decision.js +25 -9
- package/dist/workflows/human-decision.js.map +1 -1
- 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/json-patch.d.ts +47 -0
- package/dist/workflows/json-patch.js +298 -0
- package/dist/workflows/json-patch.js.map +1 -0
- package/dist/workflows/schema.js +29 -1
- package/dist/workflows/schema.js.map +1 -1
- package/dist/workflows/settings.d.ts +128 -0
- package/dist/workflows/settings.js +199 -0
- package/dist/workflows/settings.js.map +1 -0
- package/dist/workflows/store.d.ts +75 -2
- package/dist/workflows/store.js +1349 -89
- package/dist/workflows/store.js.map +1 -1
- package/dist/workflows/tool-input.d.ts +22 -0
- package/dist/workflows/tool-input.js +43 -0
- package/dist/workflows/tool-input.js.map +1 -1
- package/dist/workflows/types.d.ts +40 -5
- package/docs/2026-08-25-workflow-follow-ups.md +132 -0
- package/docs/2026-08-25-workflow-settings.md +169 -0
- package/docs/DEFERRED_TURNS.md +6 -0
- package/docs/DESIGN_PHILOSOPHY.md +2 -0
- package/docs/SQLITE_STATE.md +31 -18
- package/docs/WORKFLOW_COMPOSITION.md +16 -1
- package/docs/WORKFLOW_STEP_MESSAGES.md +4 -2
- package/docs/plans/2026-08-25-live-workflow-settings-plan.md +532 -0
- package/docs/plans/2026-08-25-workflow-run-storage-plan.md +67 -0
- package/docs/tui-viewer.md +7 -6
- package/docs/workflows.md +22 -1
- package/examples/workflows/live-settings.workflow.ts +93 -0
- package/herdr-plugin.toml +1 -1
- package/package.json +1 -1
- package/skills/autoplan/SKILL.md +6 -6
- package/src/builtins/autoimplement.workflow.ts +56 -8
- package/src/builtins/autoplan.workflow.ts +45 -37
- package/src/builtins/catalog.ts +2 -2
- package/src/controllers/index.ts +6 -0
- package/src/controllers/sqlite.ts +129 -35
- package/src/controllers/types.ts +40 -0
- package/src/controllers/workflow-engine-scheduler.ts +103 -1
- package/src/controllers/workflows.ts +68 -0
- package/src/extension/controller-host.ts +6 -1
- package/src/extension/follow-up-coordinator.ts +151 -0
- package/src/extension/index.ts +538 -88
- package/src/extension/session-events.ts +15 -13
- package/src/extension/widget.ts +8 -0
- package/src/state/database.ts +12 -12
- package/src/state/json.ts +6 -1
- package/src/state/mutation.ts +4 -1
- package/src/state/prune.ts +502 -0
- package/src/state/schema.ts +116 -18
- package/src/viewer/cli.ts +52 -5
- package/src/viewer/render.ts +43 -1
- package/src/workflows/composition.ts +19 -0
- package/src/workflows/definition.ts +19 -5
- package/src/workflows/engine.ts +363 -35
- package/src/workflows/human-decision.ts +41 -11
- package/src/workflows/index.ts +43 -0
- package/src/workflows/json-patch.ts +375 -0
- package/src/workflows/schema.ts +31 -1
- package/src/workflows/settings.ts +430 -0
- package/src/workflows/store.ts +1977 -184
- package/src/workflows/tool-input.ts +58 -0
- package/src/workflows/types.ts +43 -4
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
agent,
|
|
3
|
+
allowSettingsPath,
|
|
4
|
+
compute,
|
|
5
|
+
defineWorkflow,
|
|
6
|
+
settingsRoute,
|
|
7
|
+
workflowSettings,
|
|
8
|
+
} from "@osolmaz/pi-workflows";
|
|
9
|
+
|
|
10
|
+
type Settings = {
|
|
11
|
+
instructions: string[];
|
|
12
|
+
route: "normal" | "careful";
|
|
13
|
+
variables: Record<string, unknown>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
function parseSettings(value: unknown): Settings {
|
|
17
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
18
|
+
throw new Error("settings must be an object");
|
|
19
|
+
}
|
|
20
|
+
const settings = value as Partial<Settings>;
|
|
21
|
+
if (
|
|
22
|
+
!Array.isArray(settings.instructions) ||
|
|
23
|
+
!settings.instructions.every((item) => typeof item === "string") ||
|
|
24
|
+
(settings.route !== "normal" && settings.route !== "careful") ||
|
|
25
|
+
settings.variables === null ||
|
|
26
|
+
typeof settings.variables !== "object" ||
|
|
27
|
+
Array.isArray(settings.variables)
|
|
28
|
+
) {
|
|
29
|
+
throw new Error("settings are invalid");
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
instructions: [...settings.instructions],
|
|
33
|
+
route: settings.route,
|
|
34
|
+
variables: { ...settings.variables },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default defineWorkflow({
|
|
39
|
+
name: "live-settings",
|
|
40
|
+
settings: workflowSettings<Settings>({
|
|
41
|
+
initial: { instructions: [], route: "normal", variables: {} },
|
|
42
|
+
parse: parseSettings,
|
|
43
|
+
description: "Instructions, variables, and the future route for this example.",
|
|
44
|
+
paths: [
|
|
45
|
+
allowSettingsPath("/instructions", {
|
|
46
|
+
read: ["session", "human"],
|
|
47
|
+
add: ["session", "human"],
|
|
48
|
+
remove: ["session", "human"],
|
|
49
|
+
replace: ["session", "human"],
|
|
50
|
+
}),
|
|
51
|
+
allowSettingsPath("/route", {
|
|
52
|
+
read: ["session", "human"],
|
|
53
|
+
replace: ["session", "human"],
|
|
54
|
+
}),
|
|
55
|
+
allowSettingsPath("/variables", {
|
|
56
|
+
read: ["session", "human"],
|
|
57
|
+
add: ["session", "human"],
|
|
58
|
+
remove: ["session", "human"],
|
|
59
|
+
replace: ["session", "human"],
|
|
60
|
+
}),
|
|
61
|
+
],
|
|
62
|
+
}),
|
|
63
|
+
startAt: "prepare",
|
|
64
|
+
nodes: {
|
|
65
|
+
prepare: agent({
|
|
66
|
+
prompt: ({ settings }) =>
|
|
67
|
+
[
|
|
68
|
+
"Prepare the requested work.",
|
|
69
|
+
`Current instructions and variables: ${JSON.stringify(settings)}`,
|
|
70
|
+
"The user can change future settings or queue several post-completion prompts while this step runs.",
|
|
71
|
+
].join("\n"),
|
|
72
|
+
expectedOutput: `{ "prepared": "summary" }`,
|
|
73
|
+
}),
|
|
74
|
+
choose: settingsRoute({
|
|
75
|
+
run: ({ settings }) => ({ route: (settings as Settings).route }),
|
|
76
|
+
}),
|
|
77
|
+
normal: compute({
|
|
78
|
+
run: ({ settings }) => ({ mode: "normal", settings }),
|
|
79
|
+
}),
|
|
80
|
+
careful: compute({
|
|
81
|
+
run: ({ settings }) => ({ mode: "careful", settings }),
|
|
82
|
+
}),
|
|
83
|
+
},
|
|
84
|
+
edges: [
|
|
85
|
+
{ from: "prepare", to: "choose" },
|
|
86
|
+
{
|
|
87
|
+
from: "choose",
|
|
88
|
+
switch: { on: "$.route", cases: { normal: "normal", careful: "careful" } },
|
|
89
|
+
},
|
|
90
|
+
],
|
|
91
|
+
presentationPrompt:
|
|
92
|
+
"Explain which route and settings were used. Any queued follow-up prompts run only after this response settles.",
|
|
93
|
+
});
|
package/herdr-plugin.toml
CHANGED
package/package.json
CHANGED
package/skills/autoplan/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: autoplan
|
|
3
|
-
description: Use when the user asks to devise, choose, or plan the most
|
|
3
|
+
description: Use when the user asks to devise, choose, or plan the most Long term elegant and production ready solution, compare it with the Holy grail, and produce the best practical in-scope implementation plan without asking the user to resolve the gap.
|
|
4
4
|
compatibility: Requires pi-workflows and the built-in autoplan workflow.
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -37,12 +37,12 @@ When this skill is loaded inside an active workflow step, do not start another w
|
|
|
37
37
|
Outside Pi, or when the workflow is unavailable:
|
|
38
38
|
|
|
39
39
|
1. Frame the problem, observable success criteria, scope, constraints, and interfaces under our control.
|
|
40
|
-
2. Record two through four distinct practical candidates. Give each one a stable id, short title, plain gist, full solution, rationale, parts, and trade-offs.
|
|
41
|
-
3. Describe the
|
|
40
|
+
2. Record two through four distinct practical candidates. Ask whether each is a Long term elegant and production ready solution. Give each one a stable id, short title, plain gist, full solution, rationale, parts, and trade-offs.
|
|
41
|
+
3. Describe the Holy grail separately. Ask whether it is the Holy grail for the problem. Name every dependency outside our authority.
|
|
42
42
|
4. Choose the right option without asking the user to decide between them. Record one rejection reason for every other explicit candidate.
|
|
43
|
-
- Choose the
|
|
44
|
-
- Otherwise choose the strongest practical in-scope solution with a clear path toward the
|
|
45
|
-
- Do not block only because the
|
|
43
|
+
- Choose the Holy grail when it is proportionate, production-ready, in scope, and implementable through interfaces we control.
|
|
44
|
+
- Otherwise choose the strongest practical in-scope solution with a clear path toward the Holy grail.
|
|
45
|
+
- Do not block only because the Holy grail requires an upstream or external change.
|
|
46
46
|
5. Write a detailed implementation plan. For each step, state what changes, where it changes, and how to verify it.
|
|
47
47
|
6. Present one short plain assistant message with the chosen plan, its main steps, and a one-line gist and rejection reason for every other candidate. Call it selected for approval when a later human decision still applies.
|
|
48
48
|
7. Stop as blocked only when no truthful in-scope solution can meet the success criteria.
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
includedResult,
|
|
14
14
|
} from "../workflows/definition.js";
|
|
15
15
|
import { digest } from "../workflows/human-decision.js";
|
|
16
|
+
import { allowSettingsPath, workflowSettings } from "../workflows/settings.js";
|
|
16
17
|
import type { WorkflowActionContext, WorkflowNodeContext } from "../workflows/types.js";
|
|
17
18
|
import autodocWorkflow, { type AutodocInput } from "./autodoc.workflow.js";
|
|
18
19
|
import {
|
|
@@ -40,6 +41,11 @@ import workspacePreparationWorkflow, {
|
|
|
40
41
|
type WorkspacePreparationInput,
|
|
41
42
|
} from "./workspace-preparation.workflow.js";
|
|
42
43
|
|
|
44
|
+
export type AutoimplementSettings = {
|
|
45
|
+
merge: boolean;
|
|
46
|
+
addedInstructions: string[];
|
|
47
|
+
};
|
|
48
|
+
|
|
43
49
|
export type AutoimplementInput = {
|
|
44
50
|
task: string;
|
|
45
51
|
plan?: unknown;
|
|
@@ -577,6 +583,27 @@ function parseInput(value: unknown): AutoimplementInput {
|
|
|
577
583
|
};
|
|
578
584
|
}
|
|
579
585
|
|
|
586
|
+
function parseAutoimplementSettings(value: unknown): AutoimplementSettings {
|
|
587
|
+
const settings = requireRecord(value, "autoimplement settings");
|
|
588
|
+
if (typeof settings.merge !== "boolean") {
|
|
589
|
+
throw new Error("autoimplement settings merge must be a boolean");
|
|
590
|
+
}
|
|
591
|
+
if (
|
|
592
|
+
!Array.isArray(settings.addedInstructions) ||
|
|
593
|
+
settings.addedInstructions.some((item) => typeof item !== "string")
|
|
594
|
+
) {
|
|
595
|
+
throw new Error("autoimplement settings addedInstructions must be an array of strings");
|
|
596
|
+
}
|
|
597
|
+
return {
|
|
598
|
+
merge: settings.merge,
|
|
599
|
+
addedInstructions: [...settings.addedInstructions] as string[],
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function autoimplementSettings(context: WorkflowNodeContext): AutoimplementSettings {
|
|
604
|
+
return parseAutoimplementSettings(context.settings);
|
|
605
|
+
}
|
|
606
|
+
|
|
580
607
|
function parseExistingPlan(value: unknown): ExistingPlanDiscovery {
|
|
581
608
|
const result = requireRecord(value, "existing plan discovery");
|
|
582
609
|
if (result.route !== "found" && result.route !== "blocked") {
|
|
@@ -790,7 +817,7 @@ function createBlockerClaim(context: WorkflowNodeContext): BlockerClaim {
|
|
|
790
817
|
unrelatedFailures: Array.isArray(result.unrelatedFailures) ? result.unrelatedFailures : [],
|
|
791
818
|
recoveryAttempts: Array.isArray(result.repairAttempts) ? result.repairAttempts : [],
|
|
792
819
|
alternativesChecked: [],
|
|
793
|
-
authorityFact: `scope=${(context.input as AutoimplementInput).scope ?? "unspecified"}; merge=${(context
|
|
820
|
+
authorityFact: `scope=${(context.input as AutoimplementInput).scope ?? "unspecified"}; merge=${autoimplementSettings(context).merge}`,
|
|
794
821
|
};
|
|
795
822
|
}
|
|
796
823
|
|
|
@@ -919,8 +946,8 @@ function parseDeliveryResult(
|
|
|
919
946
|
if (result.status !== "completed" && result.status !== "blocked") {
|
|
920
947
|
throw new Error("delivery status must be completed or blocked");
|
|
921
948
|
}
|
|
922
|
-
const
|
|
923
|
-
if (
|
|
949
|
+
const settings = autoimplementSettings(context);
|
|
950
|
+
if (settings.merge !== true && result.merged === true) {
|
|
924
951
|
throw new Error("delivery cannot merge without explicit merge: true");
|
|
925
952
|
}
|
|
926
953
|
if (result.status === "blocked") return result;
|
|
@@ -960,7 +987,7 @@ function parseDeliveryResult(
|
|
|
960
987
|
}
|
|
961
988
|
actual.set(repository.repository, repository);
|
|
962
989
|
}
|
|
963
|
-
const mergeExpected =
|
|
990
|
+
const mergeExpected = settings.merge === true;
|
|
964
991
|
for (const expected of published) {
|
|
965
992
|
const repository = actual.get(path.resolve(expected.repository));
|
|
966
993
|
if (repository === undefined || repository.pr !== expected.pr) {
|
|
@@ -1298,6 +1325,28 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1298
1325
|
contractId: "pi-workflows.autoimplement.v1",
|
|
1299
1326
|
name: "autoimplement",
|
|
1300
1327
|
input: parseInput,
|
|
1328
|
+
settings: workflowSettings<AutoimplementSettings, AutoimplementInput>({
|
|
1329
|
+
initial: (input) => ({ merge: input.merge === true, addedInstructions: [] }),
|
|
1330
|
+
parse: parseAutoimplementSettings,
|
|
1331
|
+
description: "Future merge behavior and instructions added during this run.",
|
|
1332
|
+
paths: [
|
|
1333
|
+
allowSettingsPath("/merge", {
|
|
1334
|
+
read: ["session", "human"],
|
|
1335
|
+
replace: ["session", "human"],
|
|
1336
|
+
}),
|
|
1337
|
+
allowSettingsPath("/addedInstructions", {
|
|
1338
|
+
read: ["session", "human"],
|
|
1339
|
+
add: ["session", "human"],
|
|
1340
|
+
remove: ["session", "human"],
|
|
1341
|
+
replace: ["session", "human"],
|
|
1342
|
+
}),
|
|
1343
|
+
],
|
|
1344
|
+
validateChange: ({ before, after, actor }) => {
|
|
1345
|
+
if (actor.type === "session" && before.merge === false && after.merge === true) {
|
|
1346
|
+
throw new Error("A model workflow step cannot grant merge authority");
|
|
1347
|
+
}
|
|
1348
|
+
},
|
|
1349
|
+
}),
|
|
1301
1350
|
title: ({ input }) => `autoimplement: ${input.task.slice(0, 60)}`,
|
|
1302
1351
|
presentationPrompt:
|
|
1303
1352
|
"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.",
|
|
@@ -1616,7 +1665,7 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1616
1665
|
`Current result and claimed blocker: ${JSON.stringify(latestBlockerClaim(context))}`,
|
|
1617
1666
|
`Authorized scope: ${request.scope ?? request.repository ?? "the current repository and task"}`,
|
|
1618
1667
|
`Constraints and authority: ${JSON.stringify(request.constraints ?? [])}`,
|
|
1619
|
-
`Merge
|
|
1668
|
+
`Merge currently allowed: ${autoimplementSettings(context).merge === true}`,
|
|
1620
1669
|
`Previous blocker challenges: ${JSON.stringify(blockerChallenges(context))}`,
|
|
1621
1670
|
`Recent workflow attempts: ${JSON.stringify(recentWorkflowAttempts(context))}`,
|
|
1622
1671
|
].join("\n");
|
|
@@ -1925,10 +1974,9 @@ export const autoimplementWorkflow = defineWorkflow({
|
|
|
1925
1974
|
timeoutMs: 30 * 60_000,
|
|
1926
1975
|
statusDetail: "finalizing PRs",
|
|
1927
1976
|
prompt: (context) => {
|
|
1928
|
-
const request = context.input as AutoimplementInput;
|
|
1929
1977
|
return [
|
|
1930
|
-
|
|
1931
|
-
? "Leave every verified PR ready without merging because
|
|
1978
|
+
autoimplementSettings(context).merge === false
|
|
1979
|
+
? "Leave every verified PR ready without merging because current workflow settings disable merge."
|
|
1932
1980
|
: "Handle verified PRs one at a time and merge each unless repository policy or explicit user instructions prohibit it.",
|
|
1933
1981
|
"Before each mutation, inspect the current PR head, merge state, and existing final report. Do not merge an already merged expected head or post a duplicate report.",
|
|
1934
1982
|
"Use each repository's required merge method.",
|
|
@@ -96,9 +96,11 @@ function originalUserInstructions(outputs: Record<string, unknown>): string {
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
function originalInstructionsPrompt(outputs: Record<string, unknown>): string {
|
|
99
|
-
return [
|
|
100
|
-
"
|
|
101
|
-
|
|
99
|
+
return [
|
|
100
|
+
"Continue in this Pi session. Do not delegate this workflow step or start another session.",
|
|
101
|
+
"Original user instructions (authoritative):",
|
|
102
|
+
originalUserInstructions(outputs),
|
|
103
|
+
].join("\n");
|
|
102
104
|
}
|
|
103
105
|
|
|
104
106
|
function requireString(value: unknown, label: string): string {
|
|
@@ -286,7 +288,7 @@ function candidateSummary(
|
|
|
286
288
|
ideal: AutoplanIdeal,
|
|
287
289
|
id: string,
|
|
288
290
|
): { id: string; title: string; gist: string } {
|
|
289
|
-
if (id === "ideal") return { id, title: "
|
|
291
|
+
if (id === "ideal") return { id, title: "Holy grail", gist: ideal.ideal };
|
|
290
292
|
const candidate = proposal.candidates.find((item) => item.id === id);
|
|
291
293
|
if (candidate === undefined)
|
|
292
294
|
throw new Error(`autoplan candidate ${JSON.stringify(id)} is missing`);
|
|
@@ -298,9 +300,9 @@ function summaryInput(
|
|
|
298
300
|
blocked: boolean,
|
|
299
301
|
input: AutoplanInput,
|
|
300
302
|
): PlainSummaryInput {
|
|
301
|
-
const proposal = outputs.
|
|
302
|
-
const selection = outputs.
|
|
303
|
-
const ideal = outputs.
|
|
303
|
+
const proposal = outputs.solutions as AutoplanProposal;
|
|
304
|
+
const selection = outputs.select as AutoplanSelection;
|
|
305
|
+
const ideal = outputs.holyGrail as AutoplanIdeal;
|
|
304
306
|
const selected = candidateSummary(proposal, ideal, selection.selectedId);
|
|
305
307
|
return {
|
|
306
308
|
source: {
|
|
@@ -368,6 +370,7 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
368
370
|
statusDetail: "capturing the user's instructions",
|
|
369
371
|
prompt: () =>
|
|
370
372
|
[
|
|
373
|
+
"Continue in this Pi session. Do not delegate this workflow step or start another session.",
|
|
371
374
|
"Read the conversation that came before this workflow step.",
|
|
372
375
|
"Return one text string named originalUserInstructions.",
|
|
373
376
|
"Include everything that the user has instructed for the intended purpose in the given context.",
|
|
@@ -398,12 +401,13 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
398
401
|
expectedOutput: `{ "problem": "concise statement", "success": ["criterion"], "inScope": ["change"], "outOfScope": ["change"], "constraints": ["constraint"], "controlBoundary": "what can change" }`,
|
|
399
402
|
validate: (value) => requireRecord(value, "autoplan frame"),
|
|
400
403
|
}),
|
|
401
|
-
|
|
402
|
-
statusDetail: "devising
|
|
404
|
+
solutions: agent({
|
|
405
|
+
statusDetail: "devising long-term solutions",
|
|
403
406
|
prompt: ({ outputs, input }) =>
|
|
404
407
|
[
|
|
405
408
|
originalInstructionsPrompt(outputs),
|
|
406
409
|
"Give two to four practical options that fit the allowed scope.",
|
|
410
|
+
"For each option, ask: Is this a Long term elegant and production ready solution?",
|
|
407
411
|
"For each option return a stable lowercase id and a short title. Add a plain gist and full solution, explain the reason and trade-offs, and list the parts.",
|
|
408
412
|
"Favor a few reusable parts with clear owners and use interfaces that already exist.",
|
|
409
413
|
"Reject one-off machinery and infrastructure that the task does not need.",
|
|
@@ -416,42 +420,46 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
416
420
|
validate: (value, { input }) =>
|
|
417
421
|
parseProposal(value, (input as AutoplanInput).previousPlan !== undefined),
|
|
418
422
|
}),
|
|
419
|
-
|
|
420
|
-
statusDetail: "describing the
|
|
423
|
+
holyGrail: agent({
|
|
424
|
+
statusDetail: "describing the Holy grail",
|
|
421
425
|
prompt: ({ outputs, input }) =>
|
|
422
426
|
[
|
|
423
427
|
originalInstructionsPrompt(outputs),
|
|
424
|
-
"Describe the
|
|
425
|
-
"
|
|
428
|
+
"Describe the Holy grail separately from the practical options.",
|
|
429
|
+
"Ask: Is this the Holy grail for the problem?",
|
|
430
|
+
"The Holy grail may match one option or go beyond the current scope.",
|
|
431
|
+
"Explain what makes it more Long term elegant and production ready than the practical options.",
|
|
426
432
|
"List each dependency we do not control. Do not assume that it can change.",
|
|
427
|
-
"State what
|
|
433
|
+
"State what the Holy grail would improve beyond the practical options.",
|
|
428
434
|
`Problem frame: ${JSON.stringify(outputs.frame)}`,
|
|
429
|
-
`Candidates: ${JSON.stringify(outputs.
|
|
435
|
+
`Candidates: ${JSON.stringify(outputs.solutions)}`,
|
|
430
436
|
`New evidence: ${JSON.stringify((input as AutoplanInput).newEvidence ?? null)}`,
|
|
431
437
|
].join("\n"),
|
|
432
|
-
expectedOutput: `{ "ideal": "
|
|
438
|
+
expectedOutput: `{ "ideal": "Holy grail end state", "outsideDependencies": ["dependency"], "additionalValue": ["benefit"] }`,
|
|
433
439
|
validate: parseIdeal,
|
|
434
440
|
}),
|
|
435
|
-
|
|
436
|
-
statusDetail: "
|
|
441
|
+
select: agent({
|
|
442
|
+
statusDetail: "selecting the solution",
|
|
437
443
|
prompt: ({ outputs }) =>
|
|
438
444
|
[
|
|
439
445
|
originalInstructionsPrompt(outputs),
|
|
440
446
|
"Select one option. Do not ask the user to choose.",
|
|
441
|
-
"Select the
|
|
442
|
-
"
|
|
447
|
+
"Select the most Long term elegant and production ready option that is proportionate, in scope, and implementable through interfaces we control.",
|
|
448
|
+
"Select the Holy grail when it meets those conditions and its value justifies the added complexity.",
|
|
449
|
+
"Otherwise select the strongest practical option we can build now with a clear path toward the Holy grail.",
|
|
443
450
|
"Work outside our control does not by itself make the plan blocked.",
|
|
444
451
|
"Do not require changes to an upstream project or an unrelated repository. Do not require a new service or resource without approval.",
|
|
445
452
|
"When two options solve the problem equally well, choose the simpler one.",
|
|
446
|
-
"Give one specific rejection reason for every option you do not select, including the
|
|
453
|
+
"Give one specific rejection reason for every option you do not select, including the Holy grail.",
|
|
447
454
|
"Return blocked only if no option inside the allowed scope can meet the success criteria.",
|
|
448
455
|
`Frame: ${JSON.stringify(outputs.frame)}`,
|
|
449
|
-
`Candidates: ${JSON.stringify(outputs.
|
|
450
|
-
`
|
|
451
|
-
`
|
|
456
|
+
`Candidates: ${JSON.stringify(outputs.solutions)}`,
|
|
457
|
+
`Holy grail candidate id: ideal`,
|
|
458
|
+
`Holy grail: ${JSON.stringify(outputs.holyGrail)}`,
|
|
452
459
|
].join("\n"),
|
|
453
460
|
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" }`,
|
|
454
|
-
validate: (value, { outputs }) =>
|
|
461
|
+
validate: (value, { outputs }) =>
|
|
462
|
+
parseSelection(value, outputs.solutions as AutoplanProposal),
|
|
455
463
|
}),
|
|
456
464
|
plan: agent({
|
|
457
465
|
timeoutMs: 30 * 60_000,
|
|
@@ -466,8 +474,8 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
466
474
|
"Correct the earlier plan when the new evidence proves it wrong.",
|
|
467
475
|
"Do not change files.",
|
|
468
476
|
`Frame: ${JSON.stringify(outputs.frame)}`,
|
|
469
|
-
`Selection: ${JSON.stringify(outputs.
|
|
470
|
-
`Candidates: ${JSON.stringify(outputs.
|
|
477
|
+
`Selection: ${JSON.stringify(outputs.select)}`,
|
|
478
|
+
`Candidates: ${JSON.stringify(outputs.solutions)}`,
|
|
471
479
|
`Previous plan: ${JSON.stringify((input as AutoplanInput).previousPlan ?? null)}`,
|
|
472
480
|
`New evidence: ${JSON.stringify((input as AutoplanInput).newEvidence ?? null)}`,
|
|
473
481
|
].join("\n"),
|
|
@@ -476,13 +484,13 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
476
484
|
}),
|
|
477
485
|
blocked: compute({
|
|
478
486
|
run: ({ outputs }) => {
|
|
479
|
-
const selection = outputs.
|
|
487
|
+
const selection = outputs.select as AutoplanSelection;
|
|
480
488
|
return {
|
|
481
489
|
status: "blocked",
|
|
482
490
|
originalUserInstructions: originalUserInstructions(outputs),
|
|
483
491
|
frame: outputs.frame,
|
|
484
|
-
proposal: outputs.
|
|
485
|
-
ideal: outputs.
|
|
492
|
+
proposal: outputs.solutions as AutoplanProposal,
|
|
493
|
+
ideal: outputs.holyGrail as AutoplanIdeal,
|
|
486
494
|
selection,
|
|
487
495
|
plainSummary: plainSummaryResult(outputs.blockedSummary, "autoplan blocked summary"),
|
|
488
496
|
reason: requireString(selection.blocker, "autoplan blocker"),
|
|
@@ -499,9 +507,9 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
499
507
|
status: "ready",
|
|
500
508
|
originalUserInstructions: originalUserInstructions(outputs),
|
|
501
509
|
frame: outputs.frame,
|
|
502
|
-
proposal: outputs.
|
|
503
|
-
ideal: outputs.
|
|
504
|
-
selection: outputs.
|
|
510
|
+
proposal: outputs.solutions as AutoplanProposal,
|
|
511
|
+
ideal: outputs.holyGrail as AutoplanIdeal,
|
|
512
|
+
selection: outputs.select as AutoplanSelection,
|
|
505
513
|
plan: outputs.plan,
|
|
506
514
|
plainSummary: plainSummaryResult(outputs.readySummary, "autoplan ready summary"),
|
|
507
515
|
planDigest,
|
|
@@ -513,11 +521,11 @@ export const autoplanWorkflow = defineWorkflow({
|
|
|
513
521
|
},
|
|
514
522
|
edges: [
|
|
515
523
|
{ from: "captureIntent", to: "frame" },
|
|
516
|
-
{ from: "frame", to: "
|
|
517
|
-
{ from: "
|
|
518
|
-
{ from: "
|
|
524
|
+
{ from: "frame", to: "solutions" },
|
|
525
|
+
{ from: "solutions", to: "holyGrail" },
|
|
526
|
+
{ from: "holyGrail", to: "select" },
|
|
519
527
|
{
|
|
520
|
-
from: "
|
|
528
|
+
from: "select",
|
|
521
529
|
switch: { on: "$.status", cases: { ready: "plan", blocked: "blockedSummary" } },
|
|
522
530
|
},
|
|
523
531
|
{ from: "plan", to: "readySummary" },
|
package/src/builtins/catalog.ts
CHANGED
|
@@ -9,9 +9,9 @@ import sanityCheckWorkflow from "./sanity-check.workflow.js";
|
|
|
9
9
|
|
|
10
10
|
export const builtinWorkflowCatalog = new BuiltinWorkflowCatalog([
|
|
11
11
|
{ id: "plain-summary", revision: "3", definition: plainSummaryWorkflow },
|
|
12
|
-
{ id: "autoplan", revision: "
|
|
12
|
+
{ id: "autoplan", revision: "6", definition: autoplanWorkflow },
|
|
13
13
|
{ id: "autodoc", revision: "2", definition: autodocWorkflow },
|
|
14
|
-
{ id: "autoimplement", revision: "
|
|
14
|
+
{ id: "autoimplement", revision: "11", definition: autoimplementWorkflow },
|
|
15
15
|
{ id: "plan-approval", revision: "4", definition: planApprovalWorkflow },
|
|
16
16
|
{ id: "sanity-check", revision: "6", definition: sanityCheckWorkflow },
|
|
17
17
|
{
|
package/src/controllers/index.ts
CHANGED
|
@@ -49,6 +49,7 @@ export {
|
|
|
49
49
|
} from "./workflow-engine-scheduler.js";
|
|
50
50
|
export {
|
|
51
51
|
ControllerWorkflowCoordinator,
|
|
52
|
+
type ControllerWorkflowControlRequest,
|
|
52
53
|
type ControllerWorkflowScheduler,
|
|
53
54
|
type WorkflowSchedulerRequest,
|
|
54
55
|
type WorkflowSchedulerResult,
|
|
@@ -64,6 +65,11 @@ export type {
|
|
|
64
65
|
ControllerConditionStatus,
|
|
65
66
|
ControllerDefinition,
|
|
66
67
|
ControllerEffects,
|
|
68
|
+
ControllerFollowUpResult,
|
|
69
|
+
ControllerQueueFollowUpRequest,
|
|
70
|
+
ControllerRemoveFollowUpRequest,
|
|
71
|
+
ControllerSettingsChangeRequest,
|
|
72
|
+
ControllerSettingsChangeResult,
|
|
67
73
|
ControllerEvent,
|
|
68
74
|
ControllerQueueClaim,
|
|
69
75
|
ControllerResource,
|