refactor(coding-agent/tools): removed enter-plan-mode tool
- Removed the enter-plan-mode tool, associated prompt, and all event handling code.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<void> {
|
||||
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<void> {
|
||||
if (!this.planModeEnabled) {
|
||||
this.showWarning("Plan mode is not active.");
|
||||
|
||||
@@ -178,7 +178,6 @@ export interface InteractiveModeContext {
|
||||
openExternalEditor(): void;
|
||||
registerExtensionShortcuts(): void;
|
||||
handlePlanModeCommand(): Promise<void>;
|
||||
handleEnterPlanModeTool(details: import("../tools").EnterPlanModeDetails): Promise<void>;
|
||||
handleExitPlanModeTool(details: ExitPlanModeDetails): Promise<void>;
|
||||
|
||||
// Hook UI methods
|
||||
|
||||
@@ -1,98 +0,0 @@
|
||||
Transitions to plan mode for designing implementation approaches before writing code.
|
||||
|
||||
<conditions>
|
||||
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
|
||||
</conditions>
|
||||
|
||||
<instruction>
|
||||
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
|
||||
</instruction>
|
||||
|
||||
<output>
|
||||
Requires user approval to enter. Once approved, you enter read-only exploration mode with restricted tool access.
|
||||
</output>
|
||||
|
||||
<parameters>
|
||||
Optional parameters:
|
||||
- `parallel`: Explore independent threads in parallel before synthesizing.
|
||||
- `iterative`: One thread at a time with checkpoints between steps.
|
||||
</parameters>
|
||||
|
||||
<example name="auth">
|
||||
User: "Add user authentication to the app"
|
||||
→ Use plan mode: architectural decisions (session vs JWT, where to store tokens, middleware structure)
|
||||
</example>
|
||||
|
||||
<example name="optimization">
|
||||
User: "Optimize the database queries"
|
||||
→ Use plan mode: multiple approaches possible, need to profile first, significant impact
|
||||
</example>
|
||||
|
||||
<example name="dark-mode">
|
||||
User: "Implement dark mode"
|
||||
→ Use plan mode: architectural decision on theme system, affects many components
|
||||
</example>
|
||||
|
||||
<example name="delete-button">
|
||||
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
|
||||
</example>
|
||||
|
||||
<example name="error-handling">
|
||||
User: "Update the error handling in the API"
|
||||
→ Use plan mode: affects multiple files, user should approve the approach
|
||||
</example>
|
||||
|
||||
<example name="typo-skip">
|
||||
User: "Fix the typo in the README"
|
||||
→ Skip plan mode: straightforward, no planning needed
|
||||
</example>
|
||||
|
||||
<example name="debug-skip">
|
||||
User: "Add a console.log to debug this function"
|
||||
→ Skip plan mode: simple, obvious implementation
|
||||
</example>
|
||||
|
||||
<example name="research-skip">
|
||||
User: "What files handle routing?"
|
||||
→ Skip plan mode: research task, not implementation planning
|
||||
</example>
|
||||
|
||||
<avoid>
|
||||
- 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
|
||||
</avoid>
|
||||
|
||||
<critical>
|
||||
- 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
|
||||
</critical>
|
||||
@@ -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<typeof enterPlanModeSchema, EnterPlanModeDetails> {
|
||||
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<EnterPlanModeDetails>,
|
||||
_context?: AgentToolContext,
|
||||
): Promise<AgentToolResult<EnterPlanModeDetails>> {
|
||||
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 },
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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<string, ToolFactory> = {
|
||||
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<string, ToolFactory> = {
|
||||
|
||||
@@ -155,7 +155,6 @@ describe("createTools", () => {
|
||||
"fetch",
|
||||
"web_search",
|
||||
"write",
|
||||
"enter_plan_mode",
|
||||
];
|
||||
|
||||
for (const tool of expectedTools) {
|
||||
|
||||
@@ -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());
|
||||
|
||||
Reference in New Issue
Block a user