Files
oh-my-pi/packages/coding-agent/test/plan-mode/reentry-prompt.test.ts
T
Slava Zavadsky b6a3862ebc fix(coding-agent): gate prompt tool mentions on session tool availability
System and mode prompts referenced tools that may be absent from the
session catalog, forcing the model to satisfy requirements it cannot
execute (generalizes #8139's browser-verification mismatch):

- system-prompt.md: browser verification now keys on the actual UI
  surface and available tools (browser/computer/TUI/CLI), with an
  explicit behavioral/smoke-test fallback when no runtime tool exists;
  todo workflow guidance and the AST-section grep hint are gated on
  tool presence; the auto-QA report_issue block additionally requires
  the write tool.
- project-prompt.md: workspace-tree drill-in and additional-roots tool
  hints only name tools present in the session.
- plan-mode-active.md: ask-tool directives get a prose fallback and
  scout-via-task dispatch is gated on the task tool (render site now
  passes askAvailable/taskAvailable).
- orchestrate-notice.md: the tool budget, verify gates, todo tracking,
  and inline-edit guidance are gated on tool presence; the notice is
  skipped entirely when the task tool is inactive (render fn takes the
  active tool list).

Adds regression tests for each gate; changelog entry.
2026-08-10 20:24:34 -04:00

53 lines
2.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { describe, expect, it } from "bun:test";
import { prompt } from "@oh-my-pi/pi-utils";
import planModeActivePrompt from "../../src/prompts/system/plan-mode-active.md" with { type: "text" };
const BASE = {
planFilePath: "local://old-feature-plan.md",
askToolName: "ask",
writeToolName: "write",
editToolName: "edit",
isHashlineEditMode: false,
iterative: false,
askAvailable: true,
taskAvailable: true,
scoutAvailable: true,
} as const;
function render(overrides: Partial<Record<string, unknown>>): string {
return prompt.render(planModeActivePrompt, { ...BASE, ...overrides });
}
describe("plan-mode re-entry prompt", () => {
it("only emits the Re-entry section when re-entering", () => {
expect(render({ reentry: false, planExists: true })).not.toContain("## Re-entry");
expect(render({ reentry: true, planExists: true })).toContain("## Re-entry");
});
});
describe("plan-mode-active tool availability", () => {
it("omits ask-tool directives when ask is unavailable", () => {
const withoutAsk = render({ askAvailable: false });
expect(withoutAsk).not.toContain("`ask` with 2–4 mutually exclusive options");
expect(withoutAsk).not.toContain("use `ask` for preferences and tradeoffs");
expect(withoutAsk).not.toContain("Using `ask` to gather requirements");
const withAsk = render({ askAvailable: true });
expect(withAsk).toContain("`ask` with 2–4 mutually exclusive options");
});
it("provides a prose fallback for preference collection when ask is unavailable", () => {
const withoutAsk = render({ askAvailable: false });
expect(withoutAsk).toContain("present the candidates with a recommendation in prose");
expect(withoutAsk).toContain("surface any remaining preference questions with a recommendation in prose");
});
it("omits scout-via-task dispatch when the task tool is unavailable", () => {
const withoutTask = render({ taskAvailable: false, scoutAvailable: true });
expect(withoutTask).not.toContain("(via `task`)");
const withTask = render({ taskAvailable: true, scoutAvailable: true });
expect(withTask).toContain("(via `task`)");
});
});