-
Notifications
You must be signed in to change notification settings - Fork 10.4k
feat: Introduce Plan Mode & Parallel Tool Execution #15901
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
1. New PlanCompletionRequest Type (packages/cli/src/ui/types.ts) Added interface for the plan completion dialog with title, content, affected files, dependencies, original prompt, plan ID, and onChoice callback. 2. New PlanCompletionDialog Component (packages/cli/src/ui/components/PlanCompletionDialog.tsx) Created a dialog with four options: - Execute - Switch to Auto Edit mode and start implementation - Save - Keep the plan for later execution - Refine - Provide feedback to improve the plan - Cancel - Discard the plan 3. Updated UIStateContext (packages/cli/src/ui/contexts/UIStateContext.tsx) Added planCompletionRequest to the UIState interface. 4. Updated DialogManager (packages/cli/src/ui/components/DialogManager.tsx) Added rendering for the PlanCompletionDialog when a plan is presented. 5. Updated useGeminiStream Hook (packages/cli/src/ui/hooks/useGeminiStream.ts) - Detects when present_plan tool completes successfully - Auto-saves the plan as a draft using PlanService - Triggers the plan completion dialog - Stores original prompt for context 6. Updated AppContainer (packages/cli/src/ui/AppContainer.tsx) Wired up planCompletionRequest to the UI state. 7. Updated Documentation (docs/cli/plan-mode.md) Documented the new automatic plan completion dialog and auto-save feature. Key Features Implemented - Auto-save as draft: Plans are automatically saved as drafts when presented, preventing data loss on crash - Interactive dialog: After present_plan executes, users see a dialog with Execute/Save/Refine/Cancel options - Seamless mode switching: Execute option switches to Auto Edit mode automatically
…le in your active project easier
Bug Fixes 1. Plan dialog showing after execution - Fixed: present_plan results are now ignored when not in Plan Mode. Previously, if the model called present_plan after executing (in AUTO_EDIT mode), it would show the dialog again. 2. Refine not working - Fixed: Selecting "Refine" now shows an inline text input, and submitting feedback re-runs the planning cycle with the original prompt + plan + feedback. 3. Refine creating duplicate plans - Fixed: When refining, the old draft is deleted before creating the revised version. Only the latest plan exists. 4. Duplicate title in output - Fixed: Removed redundant # Implementation Plan: <title> header from the tool output since the tool description and model content already show it. New Features 1. /plan export <title> <filename> - Export plan content to a file in your working directory. 2. [last viewed] indicator - Shows which plan was most recently viewed in /plan list. 3. Inline refine input - "Refine" option now shows a text box directly in the dialog instead of exiting to main input. Documentation - Expanded Plan Storage docs with file format, status lifecycle (draft→saved→executed), and auto-save behavior transparency.
packages/core/src/core/coreToolScheduler.ts - Implemented safe parallel execution for tool batches based on tool Kind - Read-only tools (Kind.Read, Kind.Search, Kind.Fetch, Kind.Think) now execute in parallel via Promise.all() - Mutating tools (Kind.Edit, Kind.Delete, Kind.Move, Kind.Execute) execute sequentially to prevent race conditions - MCP tools (Kind.Other) are treated as mutating for safety by default - Extracted executeSingleToolCall() helper method to support both execution modes Core: Strengthened Parallel Exploration Prompts packages/core/src/core/prompts.ts - Enhanced Plan Mode system prompt to emphasize parallel tool usage - Added explicit examples showing correct (batched) vs incorrect (sequential) tool calls - Clearer instructions for batching glob, grep, and read_file operations CLI: Parallel Execution UI Visualization packages/cli/src/ui/components/messages/ToolGroupMessage.tsx - Added header showing "Running X tools in parallel..." / "Ran X tools in parallel" - Added bullet (•) prefix for each tool in parallel batches packages/cli/src/ui/components/messages/ToolMessage.tsx packages/cli/src/ui/components/messages/ShellToolMessage.tsx - Added treeConnector prop to display bullet prefix for parallel tools Documentation docs/core/tools-api.md - Added new "Parallel tool execution" section documenting Kind-based execution strategy - Documented all Tool Kinds and their execution behavior docs/core/index.md - Added mention of parallel execution in tool orchestration section with link to detailed docs
…m blocklist (exclude mutating kinds) to allowlist (only include read-only kinds) for parallel execution. Prevents race conditions when tool.kind is undefined or unexpected - now defaults to sequential execution for safety.
Summary of ChangesHello @LyalinDotCom, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly enhances the agent's workflow by introducing a dedicated planning phase and optimizing tool execution. The new Plan Mode guides the agent through a structured research and planning process using only read-only tools, ensuring no accidental modifications. Concurrently, the system now intelligently executes multiple read-only tools in parallel, drastically improving efficiency during information gathering. This combination provides a more controlled, efficient, and user-friendly experience for complex development tasks, allowing users to review and approve detailed plans before any code changes are made. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a significant new feature, Plan Mode, along with parallel tool execution for performance improvements. The implementation is extensive, covering core logic, UI components, and documentation. Overall, the changes are well-structured. I've identified a few high-severity issues related to argument parsing, error handling, and data serialization that could impact the user experience and robustness of the new features. Addressing these will ensure the Plan Mode is reliable and intuitive for users.
| action: async (context, args): Promise<SlashCommandActionReturn | void> => { | ||
| const parts = args.trim().split(/\s+/); | ||
| if (parts.length < 2) { | ||
| return { | ||
| type: 'message', | ||
| messageType: 'error', | ||
| content: | ||
| 'Missing arguments. Usage: /plan export <title> <filename>\nTip: Use /plan view <title> first, then export will use the last viewed plan if no title is provided.', | ||
| }; | ||
| } | ||
|
|
||
| // Last part is the filename, everything else is the title search | ||
| const filename = parts[parts.length - 1]; | ||
| const searchTerm = parts.slice(0, -1).join(' '); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The argument parsing logic for the export subcommand is brittle and can lead to incorrect behavior when plan titles contain spaces. It assumes the last word of the input is always the filename. For example, if a user runs /plan export my awesome plan, the command will incorrectly search for a plan titled "my awesome" and attempt to export it to a file named "plan". This is inconsistent with other subcommands like view and resume, which correctly handle multi-word arguments, and could cause user confusion and data handling errors.
| onChoice: async (choice, feedback) => { | ||
| setPlanCompletionRequest(null); | ||
| if (choice === 'execute') { | ||
| config.setApprovalMode(ApprovalMode.AUTO_EDIT); | ||
| addItem( | ||
| { | ||
| type: MessageType.INFO, | ||
| text: `Executing plan "${args.title}"... Mode switched to Auto Edit.`, | ||
| }, | ||
| Date.now(), | ||
| ); | ||
| // Use isContinuation: true to bypass the streamingState check | ||
| const executeInstruction = `Please implement the plan above. Start with the first step and work through each step systematically.`; | ||
| // eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
| submitQuery([{ text: executeInstruction }], { | ||
| isContinuation: true, | ||
| }); | ||
| } else if (choice === 'refine' && feedback) { | ||
| // Refine the plan with user feedback - stay in Plan Mode | ||
| addItem( | ||
| { | ||
| type: MessageType.INFO, | ||
| text: `Refining plan with feedback: "${feedback}"`, | ||
| }, | ||
| Date.now(), | ||
| ); | ||
| // Construct refinement prompt with context | ||
| const refinePrompt = `I previously asked you to plan: "${originalPrompt}" | ||
| You created this plan titled "${args.title}": | ||
| ${args.content} | ||
| Please revise the plan based on this feedback: | ||
| ${feedback} | ||
| Create an updated implementation plan addressing the feedback. Use present_plan to show me the revised plan.`; | ||
| // eslint-disable-next-line @typescript-eslint/no-floating-promises | ||
| submitQuery([{ text: refinePrompt }], { | ||
| isContinuation: true, | ||
| }); | ||
| } else { | ||
| addItem( | ||
| { | ||
| type: MessageType.INFO, | ||
| text: 'Plan discarded.', | ||
| }, | ||
| Date.now(), | ||
| ); | ||
| setIsResponding(false); | ||
| } | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the error handling path for a failed planService.savePlan, the onChoice callback is missing a case to handle the 'save' action. If the initial auto-save of a plan fails and the user explicitly selects "Save" from the dialog, nothing happens. This could lead to the user believing the plan was saved when it was not, potentially causing data loss. The error handler should either re-attempt the save operation or clearly inform the user that the save failed.
| private parsePlan(fileContent: string, filePath: string): PlanData | null { | ||
| const frontmatterMatch = fileContent.match( | ||
| /^---\n([\s\S]*?)\n---\n([\s\S]*)$/, | ||
| ); | ||
|
|
||
| if (!frontmatterMatch) { | ||
| debugLogger.warn(`Invalid plan file format: ${filePath}`); | ||
| return null; | ||
| } | ||
|
|
||
| const [, frontmatter, content] = frontmatterMatch; | ||
|
|
||
| // Parse YAML frontmatter manually (simple key: value parsing) | ||
| const metadata: Record<string, string> = {}; | ||
| for (const line of frontmatter.split('\n')) { | ||
| const match = line.match(/^(\w+):\s*"(.*)"\s*$/); | ||
| if (match) { | ||
| const [, key, value] = match; | ||
| // Unescape the value | ||
| metadata[key] = value.replace(/\\"/g, '"').replace(/\\n/g, '\n'); | ||
| } | ||
| } | ||
|
|
||
| if (!metadata['id'] || !metadata['title']) { | ||
| debugLogger.warn(`Missing required metadata in plan file: ${filePath}`); | ||
| return null; | ||
| } | ||
|
|
||
| return { | ||
| content: content.trim(), | ||
| metadata: { | ||
| id: metadata['id'], | ||
| title: metadata['title'], | ||
| createdAt: metadata['createdAt'] || new Date().toISOString(), | ||
| updatedAt: metadata['updatedAt'] || new Date().toISOString(), | ||
| status: (metadata['status'] as PlanMetadata['status']) || 'saved', | ||
| originalPrompt: metadata['originalPrompt'] || '', | ||
| lastViewed: metadata['lastViewed'] || undefined, | ||
| }, | ||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The manual YAML parsing logic in parsePlan is not robust and is inconsistent with the feature's documentation. The parser requires all metadata values to be double-quoted, but the example in docs/cli/plan-mode.md shows unquoted values (e.g., status: draft). This discrepancy will cause parsing to fail for plan files that are manually created or edited according to the documentation, leading to a frustrating user experience. Using a lightweight, standard YAML parsing library for the frontmatter would make this implementation more resilient and align it with the documented format.
- Enforce .md extension on exported plans - Add parallel execution documentation to tools-api.md
| - Summary of what will be implemented | ||
| - Specific files that need to be created or modified | ||
| - Step-by-step implementation sequence | ||
| - Testing strategy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about having a clear success criterion that explicitly signals successful delivery of a plan?
I’ve noticed this issue with a few other popular agentic tools: they implement a plan and run tests, but when I re-run the final feature or application, it often does not actually satisfy the original goal.
For example, performance improvements may be assumed once the original plan is delivered. The proposed strategies are implemented, the agent exits the plan after tests pass, but when I rerun the application, the goal is not achieved. In other cases, I discover bugs that stem from gaps in the requirement definitions.
Please don’t feel obligated to reply or blocked by this comment—just curious about your point of view.
Gemini-CLI upstream PR google-gemini#15901
|
Looks really promising! Can we make it auto summarize too that is not so aggressive when using plan mode since there will be a lot of context generated? With 3 pro if it hits more than 30% of max context it gets confused and tool calls are not so reliable anymore... |
|
@LyalinDotCom Can we make plan mode be a different color border? Right now having plan mode be the same blue as the default border is not as clear as it could be... maybe we use the accent purple as the border. |
Summary
This PR introduces Plan Mode, a specialized workflow state that enforces a "Think, Research, Plan" approach. In Plan Mode, the agent is restricted to read-only tools, enabling it to safely research the codebase and generate detailed implementation plans without making accidental modifications.
Additionally, this PR implements Kind-Based Parallel Tool Execution in the core scheduler. Read-only tools (like
read_file,glob,grep) now execute in parallel, significantly speeding up the research and planning phases.Details
New Feature: Plan Mode
Shift+Tab(cycles Default → Auto Edit → Plan Mode) or--approval-mode plan.write_file,run_shell_command, etc.) while auto-approving read-only tools.present_plantool..gemini/plans/).Core Enhancements
CoreToolSchedulernow categorizes tools byKind(Read, Search, Edit, Execute).Promise.all./plancommand suite:/plan list: View saved plans./plan view <title>: Read a specific plan./plan resume <title>: Load a plan into context and switch to Auto Edit mode./plan export: Export a plan to a standalone Markdown file.UI Changes
present_plantool support with a dedicated completion dialog.ToolGroupMessageto indicate parallel execution (e.g., "Ran 3 tools in parallel").Related Issues
How to Validate
geminiand pressShift+Tabuntil the status bar shows "planning mode".glob,grep,read_file) in a single turn.present_plan./plan listto see it./plan resume <title>and verify the mode switches to "Auto Edit" and implementation begins.Pre-Merge Checklist
docs/cli/plan-mode.md, updatedcommands.md,core/tools-api.md)ToolGroupMessagesnapshot tests,prompts.test.ts)