Refactor pi plan mode
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
let
|
let
|
||||||
cfg = config.dot.pi;
|
cfg = config.dot.pi;
|
||||||
piPath = "${config.dot.dotfilesPath}/modules/pi/agent";
|
piPath = "${config.dot.dotfilesPath}/modules/pi/agent";
|
||||||
|
piWorkMode = config.dot.llm.pi.workMode or false;
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
options.dot.pi = {
|
options.dot.pi = {
|
||||||
@@ -12,14 +13,15 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
# Out-of-store symlinks so the files stay editable without a nix rebuild.
|
|
||||||
# Only the managed files are linked; pi's runtime files (auth.json,
|
|
||||||
# sessions/, models-store.json) are left untouched in ~/.pi/agent.
|
|
||||||
home.file = {
|
home.file = {
|
||||||
".pi/agent/settings.json".source =
|
".pi/agent/settings.json".source =
|
||||||
config.lib.file.mkOutOfStoreSymlink "${piPath}/settings.json";
|
config.lib.file.mkOutOfStoreSymlink
|
||||||
|
"${piPath}/${if piWorkMode then "settings.work" else "settings.home"}.json";
|
||||||
".pi/agent/extensions".source =
|
".pi/agent/extensions".source =
|
||||||
config.lib.file.mkOutOfStoreSymlink "${piPath}/extensions";
|
config.lib.file.mkOutOfStoreSymlink "${piPath}/extensions-common";
|
||||||
|
} // lib.optionalAttrs piWorkMode {
|
||||||
|
".pi/agent/extensions-work".source =
|
||||||
|
config.lib.file.mkOutOfStoreSymlink "${piPath}/extensions-work";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -316,10 +316,9 @@ Do just this one step. Do NOT start any other step. Stop when this step is done.
|
|||||||
phase = undefined;
|
phase = undefined;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const where = planFilePath ? `\nSaved to: ${planFilePath}` : "";
|
|
||||||
const choice = await ctx.ui.select(
|
const choice = await ctx.ui.select(
|
||||||
`Plan "${plan.title}" — ${plan.steps.length} steps.${where}\nWhat next?`,
|
`Plan "${plan.title}" — ${plan.steps.length} steps.\nWhat next?`,
|
||||||
["Execute step-by-step", "Stay in plan mode", "Refine the plan"],
|
["Execute step-by-step", "Stay in plan mode", "Refine the plan", "Save plan to file"],
|
||||||
);
|
);
|
||||||
|
|
||||||
if (choice?.startsWith("Execute")) {
|
if (choice?.startsWith("Execute")) {
|
||||||
@@ -339,6 +338,14 @@ Do just this one step. Do NOT start any other step. Stop when this step is done.
|
|||||||
if (refinement?.trim()) {
|
if (refinement?.trim()) {
|
||||||
pi.sendUserMessage(refinement.trim(), { deliverAs: "followUp" });
|
pi.sendUserMessage(refinement.trim(), { deliverAs: "followUp" });
|
||||||
}
|
}
|
||||||
|
} else if (choice === "Save plan to file") {
|
||||||
|
try {
|
||||||
|
planFilePath = await savePlanFile(ctx, plan);
|
||||||
|
ctx.ui.notify(`Plan saved to ${planFilePath}`, "info");
|
||||||
|
persistState();
|
||||||
|
} catch {
|
||||||
|
ctx.ui.notify("Failed to save plan.", "error");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
phase = "planning";
|
phase = "planning";
|
||||||
updateStatus(ctx);
|
updateStatus(ctx);
|
||||||
@@ -382,6 +389,23 @@ Do just this one step. Do NOT start any other step. Stop when this step is done.
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pi.registerCommand("plan-save", {
|
||||||
|
description: "Save the current plan to a file in .pi/plans/",
|
||||||
|
handler: async (_args, ctx) => {
|
||||||
|
if (!plan) {
|
||||||
|
ctx.ui.notify("No plan to save. Submit a plan first.", "info");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
planFilePath = await savePlanFile(ctx, plan);
|
||||||
|
ctx.ui.notify(`Plan saved to ${planFilePath}`, "info");
|
||||||
|
persistState();
|
||||||
|
} catch {
|
||||||
|
ctx.ui.notify("Failed to save plan.", "error");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
pi.registerShortcut(Key.ctrlAlt("p"), {
|
pi.registerShortcut(Key.ctrlAlt("p"), {
|
||||||
description: "Toggle plan mode",
|
description: "Toggle plan mode",
|
||||||
handler: async (ctx) => togglePlanMode(ctx),
|
handler: async (ctx) => togglePlanMode(ctx),
|
||||||
@@ -424,23 +448,17 @@ Do just this one step. Do NOT start any other step. Stop when this step is done.
|
|||||||
awaitingStep = false;
|
awaitingStep = false;
|
||||||
phase = "awaiting-approval";
|
phase = "awaiting-approval";
|
||||||
|
|
||||||
try {
|
|
||||||
planFilePath = await savePlanFile(ctx, plan);
|
|
||||||
} catch {
|
|
||||||
planFilePath = undefined;
|
|
||||||
}
|
|
||||||
persistState();
|
persistState();
|
||||||
updateStatus(ctx);
|
updateStatus(ctx);
|
||||||
|
|
||||||
const loc = planFilePath ? ` and saved to ${planFilePath}` : "";
|
|
||||||
return {
|
return {
|
||||||
content: [
|
content: [
|
||||||
{
|
{
|
||||||
type: "text",
|
type: "text",
|
||||||
text: `Plan "${plan.title}" with ${plan.steps.length} step(s) submitted${loc}. Stop here and wait for the user to approve, refine, or execute.`,
|
text: `Plan "${plan.title}" with ${plan.steps.length} step(s) submitted. Stop here and wait for the user to approve, refine, or execute. Use /plan-save to save the plan to a file.`,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
details: { title: plan.title, steps: plan.steps.length, path: planFilePath ?? null },
|
details: { title: plan.title, steps: plan.steps.length },
|
||||||
terminate: true,
|
terminate: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -141,13 +141,10 @@ export default function (pi: ExtensionAPI) {
|
|||||||
|
|
||||||
// ── Hide unwanted built-in providers ────────────────────────────────────
|
// ── Hide unwanted built-in providers ────────────────────────────────────
|
||||||
const keep = new Set([
|
const keep = new Set([
|
||||||
"anthropic",
|
"openrouter",
|
||||||
"openai",
|
|
||||||
// "openrouter",
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const hide = [
|
const hide = [
|
||||||
"openrouter",
|
|
||||||
"ant-ling",
|
"ant-ling",
|
||||||
"azure-openai",
|
"azure-openai",
|
||||||
"azure-openai-responses",
|
"azure-openai-responses",
|
||||||
11
modules/pi/agent/settings.home.json
Normal file
11
modules/pi/agent/settings.home.json
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"lastChangelogVersion": "0.81.1",
|
||||||
|
"theme": "light",
|
||||||
|
"defaultProvider": "openrouter",
|
||||||
|
"defaultModel": "deepseek/deepseek-v4-pro",
|
||||||
|
"defaultThinkingLevel": "high",
|
||||||
|
"hideThinkingBlock": false,
|
||||||
|
"enableInstallTelemetry": false,
|
||||||
|
"doubleEscapeAction": "tree",
|
||||||
|
"treeFilterMode": "all"
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"lastChangelogVersion": "0.81.1",
|
"lastChangelogVersion": "0.81.1",
|
||||||
"theme": "light",
|
"theme": "light",
|
||||||
"defaultProvider": "anthropic",
|
"defaultProvider": "openrouter",
|
||||||
"defaultModel": "claude-opus-4-8-default",
|
"defaultModel": "deepseek/deepseek-v4-flash",
|
||||||
"defaultThinkingLevel": "high",
|
"defaultThinkingLevel": "high",
|
||||||
"hideThinkingBlock": false,
|
"hideThinkingBlock": false,
|
||||||
"retry": {
|
"retry": {
|
||||||
|
|||||||
19
modules/pi/agent/settings.work.json
Normal file
19
modules/pi/agent/settings.work.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"lastChangelogVersion": "0.81.1",
|
||||||
|
"theme": "light",
|
||||||
|
"defaultProvider": "anthropic",
|
||||||
|
"defaultModel": "claude-opus-4-8-default",
|
||||||
|
"defaultThinkingLevel": "high",
|
||||||
|
"hideThinkingBlock": false,
|
||||||
|
"retry": {
|
||||||
|
"enabled": true,
|
||||||
|
"maxRetries": 4,
|
||||||
|
"baseDelayMs": 10000
|
||||||
|
},
|
||||||
|
"enableInstallTelemetry": false,
|
||||||
|
"doubleEscapeAction": "tree",
|
||||||
|
"treeFilterMode": "all",
|
||||||
|
"extensions": [
|
||||||
|
"~/.pi/agent/extensions-work"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user