Merge PR #4166: fix(agent): preserve approved plan path (@roboomp)
This commit is contained in:
@@ -50,6 +50,9 @@
|
||||
### Fixed
|
||||
|
||||
- Fixed the multi-select (checkbox) `ask` picker showing no visible cursor on themes where `accent` fg is close to the terminal foreground; the focused option now renders as a full-width `selectedBg` highlight band spanning label and wrapped description rows, matching the Ctrl+R history overlay ([#4157](https://github.com/can1357/oh-my-pi/issues/4157)).
|
||||
### Fixed
|
||||
|
||||
- Fixed approved plan execution prompts embedding the full plan instead of requiring the executor to read the durable `local://<slug>-plan.md` file. ([#4164](https://github.com/can1357/oh-my-pi/issues/4164))
|
||||
|
||||
## [16.2.12] - 2026-07-01
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { describe, expect, it } from "bun:test";
|
||||
import { prompt } from "@oh-my-pi/pi-utils";
|
||||
import planModeApprovedPrompt from "../prompts/system/plan-mode-approved.md" with { type: "text" };
|
||||
import planModeCompactInstructionsPrompt from "../prompts/system/plan-mode-compact-instructions.md" with {
|
||||
type: "text",
|
||||
};
|
||||
import planModeReferencePrompt from "../prompts/system/plan-mode-reference.md" with { type: "text" };
|
||||
|
||||
const PLAN_FILE_PATH = "local://durable-plan.md";
|
||||
const PLAN_SENTINEL = "SENTINEL_HEADROOM_COMPRESSED_PLAN_CONTENT";
|
||||
|
||||
describe("approved plan execution prompts", () => {
|
||||
it("loads the approved plan from the durable local file instead of embedding content", () => {
|
||||
const approved = prompt.render(planModeApprovedPrompt, {
|
||||
planContent: PLAN_SENTINEL,
|
||||
planFilePath: PLAN_FILE_PATH,
|
||||
contextPreserved: false,
|
||||
});
|
||||
const reference = prompt.render(planModeReferencePrompt, {
|
||||
planContent: PLAN_SENTINEL,
|
||||
planFilePath: PLAN_FILE_PATH,
|
||||
});
|
||||
const compact = prompt.render(planModeCompactInstructionsPrompt, {
|
||||
planFilePath: PLAN_FILE_PATH,
|
||||
});
|
||||
|
||||
for (const rendered of [approved, reference, compact]) {
|
||||
expect(rendered).toContain(PLAN_FILE_PATH);
|
||||
expect(rendered).not.toContain(PLAN_SENTINEL);
|
||||
}
|
||||
expect(approved).toContain("MUST read `local://durable-plan.md`");
|
||||
expect(reference).toContain("MUST read `local://durable-plan.md`");
|
||||
});
|
||||
});
|
||||
@@ -1,25 +1,22 @@
|
||||
Plan approved.
|
||||
{{#if contextPreserved}}
|
||||
- Context preserved. Use conversation history when useful; this plan is the source of truth if it conflicts with earlier exploration.
|
||||
- Context preserved. Use conversation history when useful; the plan file is the source of truth if it conflicts with earlier exploration.
|
||||
{{/if}}
|
||||
|
||||
<instruction>
|
||||
You MUST execute this plan step by step. You have full tool access.
|
||||
You MUST read `{{planFilePath}}` before executing.
|
||||
The file content is the authoritative plan; visible/compressed context is secondary.
|
||||
Read failure? Report the exact path and error instead of guessing.
|
||||
After reading, you MUST execute the plan step by step with full tool access.
|
||||
You MUST verify each step before proceeding to the next.
|
||||
{{#has tools "todo"}}
|
||||
Before execution, initialize todo tracking with `todo`.
|
||||
After reading the plan, initialize todo tracking with `todo`.
|
||||
After each completed step, immediately update `todo`.
|
||||
If `todo` fails, fix the payload and retry before continuing.
|
||||
{{/has}}
|
||||
The plan path is for subagent handoff only. You already have the plan; NEVER read it.
|
||||
</instruction>
|
||||
|
||||
The full plan is injected below. You MUST execute it now:
|
||||
|
||||
<plan path="{{planFilePath}}">
|
||||
{{planContent}}
|
||||
</plan>
|
||||
|
||||
<critical>
|
||||
NEVER stop because inline plan content is compressed, expired, or unrecoverable. Read `{{planFilePath}}`.
|
||||
You MUST keep going until complete. This matters.
|
||||
</critical>
|
||||
|
||||
@@ -12,5 +12,6 @@ You MUST drop:
|
||||
- Restated context already present in the plan file.
|
||||
|
||||
{{#if planFilePath}}
|
||||
The approved plan file is at `{{planFilePath}}`; it is the authoritative source of truth and need not be re-summarized in detail.
|
||||
The approved plan file is at `{{planFilePath}}`; it is the authoritative source of truth.
|
||||
You MUST preserve this durable path and the fact that the executor must read it directly after compaction.
|
||||
{{/if}}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
## Existing Plan
|
||||
|
||||
<plan path="{{planFilePath}}">
|
||||
{{planContent}}
|
||||
</plan>
|
||||
The approved plan file is at `{{planFilePath}}`.
|
||||
|
||||
<instruction>
|
||||
If this plan is relevant to current work and not complete, you MUST continue executing it.
|
||||
If you do not have the current plan content in visible context, you MUST read `{{planFilePath}}`.
|
||||
If the plan is stale or unrelated, you MUST ignore it.
|
||||
The plan path is for subagent handoff only. You already have the plan; NEVER read it.
|
||||
NEVER stop because inline plan content is compressed, expired, or unrecoverable. Read the file.
|
||||
</instruction>
|
||||
|
||||
@@ -6666,9 +6666,8 @@ export class AgentSession {
|
||||
|
||||
const planFilePath = this.#planReferencePath;
|
||||
const resolvedPlanPath = resolveLocalUrlToPath(planFilePath, this.#localProtocolOptions());
|
||||
let planContent: string;
|
||||
try {
|
||||
planContent = await Bun.file(resolvedPlanPath).text();
|
||||
await fs.promises.access(resolvedPlanPath, fs.constants.R_OK);
|
||||
} catch (error) {
|
||||
if (isEnoent(error)) {
|
||||
return null;
|
||||
@@ -6678,7 +6677,6 @@ export class AgentSession {
|
||||
|
||||
const content = prompt.render(planModeReferencePrompt, {
|
||||
planFilePath,
|
||||
planContent,
|
||||
});
|
||||
|
||||
this.#planReferenceSent = true;
|
||||
|
||||
Reference in New Issue
Block a user