-
Notifications
You must be signed in to change notification settings - Fork 0
Implement Plan Code feature for AI Coding Assistant #21
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
Conversation
Co-authored-by: anikitenko <12380460+anikitenko@users.noreply.github.com>
Co-authored-by: anikitenko <12380460+anikitenko@users.noreply.github.com>
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.
Pull Request Overview
This PR adds a new "Plan Code (Plugin Scaffold)" feature to the AI Coding Agent that enables generation of complete multi-file plugin projects. The feature leverages vision-capable AI models to analyze UI mockups and generate matching code structures, automatically creating files and folders in the editor's VirtualFS.
Key changes:
- New
handlePlanCodeIPC handler with vision/image support for analyzing UI mockups - Plan parsing and execution logic that extracts file paths and content from AI-generated markdown
- Comprehensive documentation covering the feature's workflow, format, and troubleshooting
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
src/ipc/ai_coding_agent.js |
Adds handlePlanCode handler that generates structured plugin plans with vision model support for UI mockup analysis |
src/components/editor/AiCodingAgentPanel.jsx |
Implements plan execution workflow including parsing AI responses, creating folder structures, and generating Monaco models with snapshot protection |
docs/AI_CODING_AGENT.md |
Documents the Plan Code feature including format specifications, usage examples, troubleshooting guidance, and vision model integration |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Clear response and image after a delay | ||
| setTimeout(() => { | ||
| setResponse(''); | ||
| responseRef.current = ''; | ||
| handleRemoveImage(); | ||
| }, 3000); |
Copilot
AI
Nov 10, 2025
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.
[nitpick] After successfully creating files from the plan, the response and image are automatically cleared after 3 seconds (lines 434-438). However, if the user wants to copy the plan or review the response, they have only 3 seconds to do so. Consider either:
- Not auto-clearing on success (let the user manually clear)
- Increasing the timeout to give users more time (e.g., 10 seconds)
- Only clearing if the user manually dismisses, or providing a "dismiss" button
The current 3-second auto-clear might be too aggressive and could frustrate users who want to review the plan after execution.
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.
@copilot apply changes based on this feedback
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.
Increased timeout from 3s to 10s in commit a256c98 to give users more time to review the plan after execution.
| const files = []; | ||
|
|
||
| // Match file sections: ### File: /path/to/file followed by code block | ||
| const filePattern = /###\s+File:\s+(\/[^\n]+)\s*\n\s*```(\w+)?\s*\n([\s\S]*?)```/g; |
Copilot
AI
Nov 10, 2025
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.
[nitpick] The regex uses the global flag (/g) with a greedy quantifier [\s\S]*? which can lead to catastrophic backtracking on malformed input (e.g., if there's a file section without a closing code fence). While *? is lazy, the regex engine may still need to backtrack significantly on large responses. Consider:
- Adding a reasonable maximum length limit to the content capture group
- Using a more specific pattern instead of
[\s\S]*?, such as[^]+` if backticks aren't expected in code - Implementing a timeout or length limit for the parsing operation
For typical AI responses this should be fine, but it's worth considering edge cases where the AI generates malformed output.
| const filePattern = /###\s+File:\s+(\/[^\n]+)\s*\n\s*```(\w+)?\s*\n([\s\S]*?)```/g; | |
| // Limit code block content to 10,000 characters to avoid catastrophic backtracking on malformed input | |
| const filePattern = /###\s+File:\s+(\/[^\n]+)\s*\n\s*```(\w+)?\s*\n([^]{0,10000}?)```/g; |
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.
Added 50,000 character limit to the regex capture group in commit a256c98 to prevent catastrophic backtracking on malformed AI responses.
| for (const file of files) { | ||
| try { | ||
| const monaco = await import('monaco-editor'); |
Copilot
AI
Nov 10, 2025
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 dynamic import of monaco-editor happens inside a loop for each file. This is inefficient because:
- The import statement will be executed multiple times (once per file)
- While the module is cached after the first import, the
await import()overhead still occurs on each iteration
Move the await import('monaco-editor') outside the loop (before line 392) to import it once and reuse the reference for all files. This will improve performance when creating multiple files.
| for (const file of files) { | |
| try { | |
| const monaco = await import('monaco-editor'); | |
| const monaco = await import('monaco-editor'); | |
| for (const file of files) { | |
| try { |
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.
@copilot this loop is completely incorrect. Consider checking FileDialogComponent.js file about file creation
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.
Fixed in commit a256c98. Replaced the incorrect loop with proper file creation using createVirtualFile utility, following the pattern from FileDialogComponent.js. This eliminates the monaco import inside the loop and ensures proper language detection and VirtualFS registration.
src/ipc/ai_coding_agent.js
Outdated
| const messages = []; | ||
| if (image) { | ||
| messages.push({ | ||
| role: 'user', | ||
| content: [ | ||
| { type: 'text', text: fullPrompt }, | ||
| { | ||
| type: 'image_url', | ||
| image_url: { url: image } | ||
| } | ||
| ] | ||
| }); | ||
| } else { | ||
| llm.user(fullPrompt); | ||
| } |
Copilot
AI
Nov 10, 2025
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 llm.user() call is only made in the else branch, but when image is provided, the LLM instance doesn't have the prompt added through the usual API. The messages array is created locally but the LLM's internal conversation state may not be set up correctly. This inconsistency in how messages are prepared could lead to unexpected behavior. Consider using a consistent pattern for both cases.
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.
Fixed in commit a256c98. Refactored to use consistent message handling - when image is provided, messages are prepared before the chat call, otherwise llm.user() is called before chat. Both paths now properly set up the LLM conversation state.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Qodana for JS111 new problems were found
☁️ View the detailed Qodana report Contact Qodana teamContact us at qodana-support@jetbrains.com
|
Co-authored-by: anikitenko <12380460+anikitenko@users.noreply.github.com>
|
@copilot and now there are 2 bugs:
|
…opment Co-authored-by: anikitenko <12380460+anikitenko@users.noreply.github.com>
Fixed both bugs in commit c040749:
|
Complete implementation of Plan Code in Coding Assistant
Summary
Successfully implemented the Plan Code (Plugin Scaffold) feature for the AI Coding Assistant in the FDO editor. This feature allows users to generate complete plugin project structures with multiple files from a single AI prompt, optionally including UI mockup analysis.
Latest Changes (Bug Fixes)
Bug #1: handleRefine Not Being Used
handleRefinefunction instead of inline handlerBug #2: Plan Code Prompt Incorrectly Suggesting React
.tsxfile examples, replaced with SDK DOM class examplesPrevious Changes
Critical Fix: File Creation Loop
createVirtualFileutility (as used in FileDialogComponent)Backend LLM Message Consistency
Performance & UX Improvements
getLanguageFromPathhelper (handled bycreateVirtualFile)Completed Tasks
handlePlanCode) insrc/ipc/ai_coding_agent.jsAiCodingAgentPanel.jsxImplementation Details
Backend Handler (
handlePlanCode)requestId,prompt,image(base64),assistantIdFrontend Execution (
handleExecutePlan)createVirtualFileutility for proper file creation (follows FDO patterns)Plan Format
Test Results
Original prompt
💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.