From 0f4829376ffff1663f8c847b39c9877971ecff8f Mon Sep 17 00:00:00 2001 From: can1357 Date: Tue, 27 Jan 2026 04:14:16 +0100 Subject: [PATCH] refactor(coding-agent/tools): removed enter-plan-mode tool - Removed the enter-plan-mode tool, associated prompt, and all event handling code. --- packages/coding-agent/CHANGELOG.md | 2 + .../src/modes/controllers/event-controller.ts | 6 -- .../src/modes/interactive-mode.ts | 21 +--- packages/coding-agent/src/modes/types.ts | 1 - .../src/prompts/tools/enter-plan-mode.md | 98 ------------------- .../coding-agent/src/tools/enter-plan-mode.ts | 81 --------------- packages/coding-agent/src/tools/index.ts | 3 - .../coding-agent/test/tools/index.test.ts | 1 - .../test/tools/schema-validation.test.ts | 1 - 9 files changed, 3 insertions(+), 211 deletions(-) delete mode 100644 packages/coding-agent/src/prompts/tools/enter-plan-mode.md delete mode 100644 packages/coding-agent/src/tools/enter-plan-mode.ts diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index d3b42a2f5..34230fa70 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -5,6 +5,8 @@ ### Fixed - Reduced Task tool progress update overhead to keep the UI responsive during high-volume streaming output +### Removed +- Removed enter-plan-mode tool ## [8.4.5] - 2026-01-26 ### Added diff --git a/packages/coding-agent/src/modes/controllers/event-controller.ts b/packages/coding-agent/src/modes/controllers/event-controller.ts index 07ce43181..06ef36ea4 100644 --- a/packages/coding-agent/src/modes/controllers/event-controller.ts +++ b/packages/coding-agent/src/modes/controllers/event-controller.ts @@ -247,12 +247,6 @@ export class EventController { this.ctx.setTodos(details.todos); } } - if (event.toolName === "enter_plan_mode" && !event.isError) { - const details = event.result.details as import("../../tools").EnterPlanModeDetails | undefined; - if (details) { - await this.ctx.handleEnterPlanModeTool(details); - } - } if (event.toolName === "exit_plan_mode" && !event.isError) { const details = event.result.details as ExitPlanModeDetails | undefined; if (details) { diff --git a/packages/coding-agent/src/modes/interactive-mode.ts b/packages/coding-agent/src/modes/interactive-mode.ts index 556d2e057..721e21141 100644 --- a/packages/coding-agent/src/modes/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive-mode.ts @@ -29,7 +29,7 @@ import type { AgentSession, AgentSessionEvent } from "../session/agent-session"; import { HistoryStorage } from "../session/history-storage"; import type { SessionContext, SessionManager } from "../session/session-manager"; import { getRecentSessions } from "../session/session-manager"; -import type { EnterPlanModeDetails, ExitPlanModeDetails } from "../tools"; +import type { ExitPlanModeDetails } from "../tools"; import { setTerminalTitle } from "../utils/title-generator"; import type { AssistantMessageComponent } from "./components/assistant-message"; import type { BashExecutionComponent } from "./components/bash-execution"; @@ -631,25 +631,6 @@ export class InteractiveMode implements InteractiveModeContext { await this.enterPlanMode(); } - async handleEnterPlanModeTool(details: EnterPlanModeDetails): Promise { - if (this.planModeEnabled) { - this.showWarning("Plan mode is already active."); - return; - } - - const confirmed = await this.showHookConfirm( - "Enter plan mode?", - "This enables read-only planning and creates a plan file for approval.", - ); - if (!confirmed) { - return; - } - - const planFilePath = details.planFilePath || this.getPlanFilePath(); - this.planModePlanFilePath = planFilePath; - await this.enterPlanMode({ planFilePath, workflow: details.workflow }); - } - async handleExitPlanModeTool(details: ExitPlanModeDetails): Promise { if (!this.planModeEnabled) { this.showWarning("Plan mode is not active."); diff --git a/packages/coding-agent/src/modes/types.ts b/packages/coding-agent/src/modes/types.ts index 2f6371d82..92974d392 100644 --- a/packages/coding-agent/src/modes/types.ts +++ b/packages/coding-agent/src/modes/types.ts @@ -178,7 +178,6 @@ export interface InteractiveModeContext { openExternalEditor(): void; registerExtensionShortcuts(): void; handlePlanModeCommand(): Promise; - handleEnterPlanModeTool(details: import("../tools").EnterPlanModeDetails): Promise; handleExitPlanModeTool(details: ExitPlanModeDetails): Promise; // Hook UI methods diff --git a/packages/coding-agent/src/prompts/tools/enter-plan-mode.md b/packages/coding-agent/src/prompts/tools/enter-plan-mode.md deleted file mode 100644 index 9afba6b8b..000000000 --- a/packages/coding-agent/src/prompts/tools/enter-plan-mode.md +++ /dev/null @@ -1,98 +0,0 @@ -Transitions to plan mode for designing implementation approaches before writing code. - - -Prefer using EnterPlanMode for implementation tasks unless they're simple. Use it when ANY of these conditions apply: -1. **New Feature Implementation**: Adding meaningful new functionality - - Example: "Add a logout button" — where should it go? What should happen on click? - - Example: "Add form validation" — what rules? What error messages? -2. **Multiple Valid Approaches**: The task can be solved in several different ways - - Example: "Add caching to the API" — could use Redis, in-memory, file-based, etc. - - Example: "Improve performance" — many optimization strategies possible -3. **Code Modifications**: Changes that affect existing behavior or structure - - Example: "Update the login flow" — what exactly should change? - - Example: "Refactor this component" — what's the target architecture? -4. **Architectural Decisions**: The task requires choosing between patterns or technologies - - Example: "Add real-time updates" — WebSockets vs SSE vs polling - - Example: "Implement state management" — Redux vs Context vs custom solution -5. **Multi-File Changes**: The task will likely touch more than 2-3 files - - Example: "Refactor the authentication system" - - Example: "Add a new API endpoint with tests" -6. **Unclear Requirements**: You need to explore before understanding the full scope - - Example: "Make the app faster" — need to profile and identify bottlenecks - - Example: "Fix the bug in checkout" — need to investigate root cause -7. **User Preferences Matter**: The implementation could reasonably go multiple ways - - If you would use `ask` to clarify the approach, use EnterPlanMode instead - - Plan mode lets you explore first, then present options with context - - - -In plan mode: -1. Explore codebase with `find`, `grep`, `read`, `ls` -2. Understand existing patterns and architecture -3. Design implementation approach -4. Use `ask` if clarification needed -5. Call `exit_plan_mode` when ready - - - -Requires user approval to enter. Once approved, you enter read-only exploration mode with restricted tool access. - - - -Optional parameters: - - `parallel`: Explore independent threads in parallel before synthesizing. - - `iterative`: One thread at a time with checkpoints between steps. - - - -User: "Add user authentication to the app" -→ Use plan mode: architectural decisions (session vs JWT, where to store tokens, middleware structure) - - - -User: "Optimize the database queries" -→ Use plan mode: multiple approaches possible, need to profile first, significant impact - - - -User: "Implement dark mode" -→ Use plan mode: architectural decision on theme system, affects many components - - - -User: "Add a delete button to the user profile" -→ Use plan mode: seems simple but involves placement, confirmation dialog, API call, error handling, state updates - - - -User: "Update the error handling in the API" -→ Use plan mode: affects multiple files, user should approve the approach - - - -User: "Fix the typo in the README" -→ Skip plan mode: straightforward, no planning needed - - - -User: "Add a console.log to debug this function" -→ Skip plan mode: simple, obvious implementation - - - -User: "What files handle routing?" -→ Skip plan mode: research task, not implementation planning - - - -- Single-line or few-line fixes (typos, obvious bugs) -- Adding a single function with clear requirements -- Tasks with very specific, detailed instructions -- Pure research/exploration tasks - - - -- This tool REQUIRES user approval — they must consent to entering plan mode -- If unsure whether to use it, err on the side of planning — alignment upfront beats rework -- Users appreciate being consulted before significant changes are made to their codebase - \ No newline at end of file diff --git a/packages/coding-agent/src/tools/enter-plan-mode.ts b/packages/coding-agent/src/tools/enter-plan-mode.ts deleted file mode 100644 index dbfaddf2e..000000000 --- a/packages/coding-agent/src/tools/enter-plan-mode.ts +++ /dev/null @@ -1,81 +0,0 @@ -import * as fs from "node:fs/promises"; -import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core"; -import { StringEnum } from "@oh-my-pi/pi-ai"; -import { isEnoent } from "@oh-my-pi/pi-utils"; -import { Type } from "@sinclair/typebox"; -import { renderPromptTemplate } from "../config/prompt-templates"; -import { resolvePlanUrlToPath } from "../internal-urls"; -import enterPlanModeDescription from "../prompts/tools/enter-plan-mode.md" with { type: "text" }; -import type { ToolSession } from "."; -import { ToolError } from "./tool-errors"; - -const enterPlanModeSchema = Type.Object({ - workflow: Type.Optional( - StringEnum(["parallel", "iterative"], { - description: "Planning workflow to use", - }), - ), -}); - -export interface EnterPlanModeDetails { - planFilePath: string; - planExists: boolean; - workflow?: "parallel" | "iterative"; -} - -export class EnterPlanModeTool implements AgentTool { - public readonly name = "enter_plan_mode"; - public readonly label = "EnterPlanMode"; - public readonly description: string; - public readonly parameters = enterPlanModeSchema; - - private readonly session: ToolSession; - - constructor(session: ToolSession) { - this.session = session; - this.description = renderPromptTemplate(enterPlanModeDescription); - } - - public async execute( - _toolCallId: string, - params: { workflow?: "parallel" | "iterative" }, - _signal?: AbortSignal, - _onUpdate?: AgentToolUpdateCallback, - _context?: AgentToolContext, - ): Promise> { - const state = this.session.getPlanModeState?.(); - if (state?.enabled) { - throw new ToolError("Plan mode is already active."); - } - - const sessionId = this.session.getSessionId?.(); - if (!sessionId) { - throw new ToolError("Plan mode requires an active session."); - } - - const settingsManager = this.session.settingsManager; - if (!settingsManager) { - throw new ToolError("Settings manager unavailable for plan mode."); - } - - const planFilePath = `plan://${sessionId}/plan.md`; - const resolvedPlanPath = resolvePlanUrlToPath(planFilePath, { - getPlansDirectory: settingsManager.getPlansDirectory.bind(settingsManager), - cwd: this.session.cwd, - }); - let planExists = false; - try { - const stat = await fs.stat(resolvedPlanPath); - planExists = stat.isFile(); - } catch (error) { - if (!isEnoent(error)) { - throw error; - } - } - - return { - content: [{ type: "text", text: "Plan mode requested." }], - details: { planFilePath, planExists, workflow: params.workflow }, - }; - } -} diff --git a/packages/coding-agent/src/tools/index.ts b/packages/coding-agent/src/tools/index.ts index 85cac66a3..616d12630 100644 --- a/packages/coding-agent/src/tools/index.ts +++ b/packages/coding-agent/src/tools/index.ts @@ -19,7 +19,6 @@ import { AskTool } from "./ask"; import { BashTool } from "./bash"; import { CalculatorTool } from "./calculator"; import { CompleteTool } from "./complete"; -import { EnterPlanModeTool } from "./enter-plan-mode"; import { ExitPlanModeTool } from "./exit-plan-mode"; import { FetchTool } from "./fetch"; import { FindTool } from "./find"; @@ -73,7 +72,6 @@ export { AskTool, type AskToolDetails } from "./ask"; export { BashTool, type BashToolDetails, type BashToolOptions } from "./bash"; export { CalculatorTool, type CalculatorToolDetails } from "./calculator"; export { CompleteTool } from "./complete"; -export { type EnterPlanModeDetails, EnterPlanModeTool } from "./enter-plan-mode"; export { type ExitPlanModeDetails, ExitPlanModeTool } from "./exit-plan-mode"; export { FetchTool, type FetchToolDetails } from "./fetch"; export { type FindOperations, FindTool, type FindToolDetails, type FindToolOptions } from "./find"; @@ -199,7 +197,6 @@ export const BUILTIN_TOOLS: Record = { fetch: s => new FetchTool(s), web_search: s => new WebSearchTool(s), write: s => new WriteTool(s), - enter_plan_mode: s => new EnterPlanModeTool(s), }; export const HIDDEN_TOOLS: Record = { diff --git a/packages/coding-agent/test/tools/index.test.ts b/packages/coding-agent/test/tools/index.test.ts index ae1a14c4a..d6b10c684 100644 --- a/packages/coding-agent/test/tools/index.test.ts +++ b/packages/coding-agent/test/tools/index.test.ts @@ -155,7 +155,6 @@ describe("createTools", () => { "fetch", "web_search", "write", - "enter_plan_mode", ]; for (const tool of expectedTools) { diff --git a/packages/coding-agent/test/tools/schema-validation.test.ts b/packages/coding-agent/test/tools/schema-validation.test.ts index 935b37a65..317899642 100644 --- a/packages/coding-agent/test/tools/schema-validation.test.ts +++ b/packages/coding-agent/test/tools/schema-validation.test.ts @@ -383,7 +383,6 @@ describe("tool schema validation (post-sanitization)", () => { "fetch", "web_search", "write", - "enter_plan_mode", ]; expect(Object.keys(BUILTIN_TOOLS).sort()).toEqual(expectedTools.sort());