From b2cb4ada353a645b92f4960955ec227a7509604a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Nov 2025 12:11:43 +0000 Subject: [PATCH 1/8] Initial plan From 62ac21170c95a05d838ef576491451af2fe8d321 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Nov 2025 12:24:29 +0000 Subject: [PATCH 2/8] Implement Plan Code backend handler and frontend execution logic Co-authored-by: anikitenko <12380460+anikitenko@users.noreply.github.com> --- src/components/editor/AiCodingAgentPanel.jsx | 143 ++++++++++++++++++- src/ipc/ai_coding_agent.js | 134 +++++++++++++++++ 2 files changed, 275 insertions(+), 2 deletions(-) diff --git a/src/components/editor/AiCodingAgentPanel.jsx b/src/components/editor/AiCodingAgentPanel.jsx index e60470a..1b3c273 100644 --- a/src/components/editor/AiCodingAgentPanel.jsx +++ b/src/components/editor/AiCodingAgentPanel.jsx @@ -338,9 +338,148 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } const handleExecutePlan = async () => { if (!response) return; - // TODO: Parse plan and generate files in VirtualFS + console.log('[AI Coding Agent] Executing plan...'); - setError('Plan execution coming soon!'); + setIsLoading(true); + setError(null); + + try { + // Create snapshot before making changes + const snapshot = createSnapshotBeforeApply(); + if (!snapshot) { + setError('Failed to create snapshot before applying plan'); + setIsLoading(false); + return; + } + + // Parse the plan and extract files + const files = parsePlanResponse(response); + + if (files.length === 0) { + setError('No files found in the plan. Please ensure the AI response contains file sections with code blocks.'); + setIsLoading(false); + return; + } + + console.log('[AI Coding Agent] Creating files from plan', { fileCount: files.length }); + + // Create folders first (extract unique folder paths) + const folders = new Set(); + files.forEach(file => { + const parts = file.path.split('/').filter(Boolean); + for (let i = 1; i < parts.length; i++) { + const folderPath = '/' + parts.slice(0, i).join('/'); + folders.add(folderPath); + } + }); + + // Create folders in order + const sortedFolders = Array.from(folders).sort(); + for (const folder of sortedFolders) { + try { + virtualFS.createFolder(folder); + console.log('[AI Coding Agent] Created folder:', folder); + } catch (err) { + console.warn('[AI Coding Agent] Folder may already exist:', folder, err); + } + } + + // Create files + let successCount = 0; + let errorCount = 0; + + for (const file of files) { + try { + const monaco = await import('monaco-editor'); + const uri = monaco.Uri.file(file.path); + + // Check if model already exists + let model = monaco.editor.getModel(uri); + + if (!model) { + // Create new model + const language = getLanguageFromPath(file.path); + model = monaco.editor.createModel(file.content, language, uri); + console.log('[AI Coding Agent] Created new file:', file.path, 'with language:', language); + } else { + // Update existing model + model.setValue(file.content); + console.log('[AI Coding Agent] Updated existing file:', file.path); + } + + // Register the file in VirtualFS + virtualFS.createFile(file.path, model); + successCount++; + } catch (err) { + console.error('[AI Coding Agent] Error creating file:', file.path, err); + errorCount++; + } + } + + console.log('[AI Coding Agent] Plan execution complete', { successCount, errorCount }); + + if (successCount > 0) { + setError(null); + // Show success message + const message = errorCount > 0 + ? `Plan partially executed: ${successCount} files created, ${errorCount} failed` + : `Plan executed successfully: ${successCount} files created`; + + // Clear response after successful execution + setTimeout(() => { + setResponse(''); + responseRef.current = ''; + }, 2000); + + alert(message); + } else { + setError('Failed to create any files from the plan'); + } + } catch (err) { + console.error('[AI Coding Agent] Error executing plan:', err); + setError(`Failed to execute plan: ${err.message}`); + } finally { + setIsLoading(false); + } + }; + + // Helper function to parse plan response and extract files + const parsePlanResponse = (response) => { + 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; + + let match; + while ((match = filePattern.exec(response)) !== null) { + const [, path, language, content] = match; + files.push({ + path: path.trim(), + language: language || '', + content: content.trim() + }); + } + + return files; + }; + + // Helper function to determine language from file path + const getLanguageFromPath = (path) => { + const ext = path.split('.').pop().toLowerCase(); + const languageMap = { + 'ts': 'typescript', + 'tsx': 'typescript', + 'js': 'javascript', + 'jsx': 'javascript', + 'json': 'json', + 'css': 'css', + 'scss': 'scss', + 'html': 'html', + 'md': 'markdown', + 'yaml': 'yaml', + 'yml': 'yaml', + }; + return languageMap[ext] || 'plaintext'; }; const handleSubmit = async () => { diff --git a/src/ipc/ai_coding_agent.js b/src/ipc/ai_coding_agent.js index c9ba2fb..fe6edd5 100644 --- a/src/ipc/ai_coding_agent.js +++ b/src/ipc/ai_coding_agent.js @@ -474,10 +474,144 @@ Return the code or explanation directly — do **not** include meta-commentary a } } +// Handle code planning - Generate plugin scaffold +async function handlePlanCode(event, data) { + const { requestId, prompt, image, assistantId } = data; + + console.log('[AI Coding Agent Backend] Plan code request', { requestId, promptLength: prompt?.length, hasImage: !!image, assistantId }); + + try { + const assistantInfo = selectCodingAssistant(assistantId); + const llm = await createCodingLlm(assistantInfo, true); + + let fullPrompt = `Create a detailed implementation plan for an FDO plugin based on the following description: + +${prompt} + +${image ? '\n[Note: An image mockup has been provided - analyze it and incorporate the UI design into the plan]\n' : ''} + +Generate a comprehensive plan that includes: + +1. **Project Structure**: List all files and folders needed +2. **File Contents**: Provide the complete code for each file + +Format your response as a structured plan using the following format: + +## Plan Overview +Brief description of what the plugin does and its main features. + +## File Structure +\`\`\` +/package.json +/tsconfig.json +/index.ts +/render.tsx +/components/ + /Component1.tsx + /Component2.tsx +/styles/ + /main.css +\`\`\` + +## Implementation + +### File: /package.json +\`\`\`json +{ + "name": "plugin-name", + "version": "1.0.0", + ...complete file content... +} +\`\`\` + +### File: /index.ts +\`\`\`typescript +import { FDO_SDK, FDOInterface, PluginMetadata } from "@anikitenko/fdo-sdk"; + +export default class MyPlugin extends FDO_SDK implements FDOInterface { + ...complete file content... +} +\`\`\` + +### File: /render.tsx +\`\`\`tsx +...complete file content... +\`\`\` + +Continue this pattern for ALL files mentioned in the structure. + +IMPORTANT: +- Use proper FDO SDK patterns (extend FDO_SDK, implement FDOInterface) +- Include all necessary imports +- Provide complete, working code for each file +- Use TypeScript for .ts and .tsx files +- Follow the exact format shown above for each file +- Each file section should start with "### File: /path/to/file" +- Code blocks must specify the language (json, typescript, tsx, css, etc.) +`; + + // If image is provided, add it to the message + const messages = []; + if (image) { + messages.push({ + role: 'user', + content: [ + { type: 'text', text: fullPrompt }, + { + type: 'image_url', + image_url: { url: image } + } + ] + }); + } else { + llm.user(fullPrompt); + } + + console.log('[AI Coding Agent Backend] Sending plan request to LLM'); + const resp = image + ? await llm.chat({ messages, stream: true }) + : await llm.chat({ stream: true }); + + let fullContent = ""; + + if (resp && typeof resp === "object" && "stream" in resp && typeof resp.complete === "function") { + console.log('[AI Coding Agent Backend] Streaming started'); + for await (const chunk of resp.stream) { + if (!chunk) continue; + const { type, content: piece } = chunk; + + if (type === "content" && piece && typeof piece === "string") { + fullContent += piece; + event.sender.send(AiCodingAgentChannels.on_off.STREAM_DELTA, { + requestId, + type: "content", + content: piece, + }); + } + } + + await resp.complete(); + console.log('[AI Coding Agent Backend] Streaming complete', { requestId, contentLength: fullContent.length }); + event.sender.send(AiCodingAgentChannels.on_off.STREAM_DONE, { requestId, fullContent }); + return { success: true, requestId, content: fullContent }; + } + + return { success: false, error: "Invalid response from LLM" }; + } catch (error) { + console.error('[AI Coding Agent Backend] Error in handlePlanCode', error); + event.sender.send(AiCodingAgentChannels.on_off.STREAM_ERROR, { + requestId, + error: error.message, + }); + return { success: false, error: error.message }; + } +} + export function registerAiCodingAgentHandlers() { ipcMain.handle(AiCodingAgentChannels.GENERATE_CODE, handleGenerateCode); ipcMain.handle(AiCodingAgentChannels.EDIT_CODE, handleEditCode); ipcMain.handle(AiCodingAgentChannels.EXPLAIN_CODE, handleExplainCode); ipcMain.handle(AiCodingAgentChannels.FIX_CODE, handleFixCode); ipcMain.handle(AiCodingAgentChannels.SMART_MODE, handleSmartMode); + ipcMain.handle(AiCodingAgentChannels.PLAN_CODE, handlePlanCode); } From 22c1cc140194b3c17903063700c3e481275198e2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Nov 2025 12:29:25 +0000 Subject: [PATCH 3/8] Improve Plan Code UI feedback and update documentation Co-authored-by: anikitenko <12380460+anikitenko@users.noreply.github.com> --- docs/AI_CODING_AGENT.md | 136 ++++++++++++++++++- src/components/editor/AiCodingAgentPanel.jsx | 20 +-- 2 files changed, 142 insertions(+), 14 deletions(-) diff --git a/docs/AI_CODING_AGENT.md b/docs/AI_CODING_AGENT.md index 4223678..cbcb283 100644 --- a/docs/AI_CODING_AGENT.md +++ b/docs/AI_CODING_AGENT.md @@ -8,12 +8,14 @@ The AI assistant is **FDO SDK-aware** and can help with plugin development using ## Features -The AI Coding Agent supports four main actions: +The AI Coding Agent supports the following actions: -1. **Generate Code** - Create new code based on natural language descriptions -2. **Edit Code** - Modify selected code according to instructions -3. **Explain Code** - Get explanations for selected code blocks -4. **Fix Code** - Debug and fix code with error messages +1. **Smart Mode** - AI automatically determines the best action based on context +2. **Generate Code** - Create new code based on natural language descriptions +3. **Edit Code** - Modify selected code according to instructions +4. **Explain Code** - Get explanations for selected code blocks +5. **Fix Code** - Debug and fix code with error messages +6. **Plan Code (Plugin Scaffold)** - Generate complete plugin project structures with multiple files ## FDO SDK Integration @@ -70,25 +72,30 @@ export default class MyPlugin extends FDO_SDK implements FDOInterface { ### IPC Channels (`src/ipc/channels.js`) - Added `AiCodingAgentChannels` with the following operations: + - `SMART_MODE` - `GENERATE_CODE` - `EDIT_CODE` - `EXPLAIN_CODE` - `FIX_CODE` + - `PLAN_CODE` - Streaming events: `STREAM_DELTA`, `STREAM_DONE`, `STREAM_ERROR` ### Main Process Handler (`src/ipc/ai_coding_agent.js`) -- Implements handlers for all four AI operations +- Implements handlers for all AI operations including Plan Code - Uses the existing coding assistant configuration from settings - Supports streaming responses for real-time feedback - Each operation creates a unique request ID for tracking - **System prompt includes FDO SDK knowledge** +- **Plan Code handler supports vision models for UI mockup analysis** ### Preload API (`src/preload.js`) - Exposes `window.electron.aiCodingAgent` with methods: + - `smartMode(data)` - AI-determined action - `generateCode(data)` - Generate new code - `editCode(data)` - Edit existing code - `explainCode(data)` - Explain code functionality - `fixCode(data)` - Fix code errors + - `planCode(data)` - Generate plugin scaffold - Event listeners for streaming updates ### UI Component (`src/components/editor/AiCodingAgentPanel.jsx`) @@ -157,6 +164,123 @@ Explain how this plugin uses the FDO_SDK base class and lifecycle hooks This plugin fails to render - TypeError: Cannot read property 'render' of undefined ``` +**Plan Code (Plugin Scaffold):** +``` +Create a weather dashboard plugin that displays current weather and a 5-day forecast +``` + +Or upload a UI mockup image and describe: +``` +Analyze the uploaded mockup and create a plugin matching this design +``` + +## Plan Code (Plugin Scaffold) Feature + +The **Plan Code** action is a powerful feature that generates complete plugin project structures with multiple files. This is ideal for quickly scaffolding new plugins or creating complex multi-file projects. + +### How It Works + +1. **Describe Your Plugin**: Provide a detailed description of what you want to build +2. **Optional UI Mockup**: Upload an image of a UI mockup for the AI to analyze +3. **AI Generates Plan**: The AI creates a comprehensive plan with file structure and content +4. **Execute Plan**: Click "Execute Plan" to automatically create all files in the editor + +### Plan Format + +The AI generates plans in a structured markdown format: + +```markdown +## Plan Overview +Brief description of the plugin and its features. + +## File Structure +``` +/package.json +/tsconfig.json +/index.ts +/render.tsx +/components/ + /WeatherCard.tsx + /ForecastList.tsx +``` + +## Implementation + +### File: /package.json +```json +{ + "name": "weather-plugin", + "version": "1.0.0", + ... +} +``` + +### File: /index.ts +```typescript +import { FDO_SDK, FDOInterface, PluginMetadata } from "@anikitenko/fdo-sdk"; +... +``` + +### File: /components/WeatherCard.tsx +```tsx +import React from 'react'; +... +``` +``` + +### Features + +- **Multi-file Generation**: Creates entire project structures with one click +- **Vision Support**: Analyzes UI mockups when using vision-capable models (GPT-4 Vision, Claude with vision) +- **FDO SDK Integration**: Generated code follows FDO plugin patterns automatically +- **Snapshot Before Apply**: Creates an automatic snapshot so you can undo if needed +- **Smart Parsing**: Automatically extracts file paths and content from AI response +- **Language Detection**: Determines file language from extension for proper syntax highlighting + +### Example Usage + +**Prompt:** +``` +Create a todo list plugin with the following features: +- Add, edit, and delete tasks +- Mark tasks as complete +- Filter by status (all, active, completed) +- Persist tasks using FDO storage +- Use DOMTable for displaying tasks +``` + +**With UI Mockup:** +1. Upload a screenshot or design mockup +2. Describe: "Create a plugin matching this UI design with full functionality" +3. AI analyzes the image and generates matching code + +### Execution Process + +When you click "Execute Plan": +1. Creates a snapshot of current workspace (for undo) +2. Parses the AI response to extract files +3. Creates folder structure +4. Creates Monaco editor models for each file +5. Registers files with VirtualFS +6. Shows success message with file count + +### Troubleshooting + +**No files created:** +- Ensure AI response contains file sections with format: `### File: /path/to/file` +- Check that code blocks are properly formatted with triple backticks +- Try regenerating the plan with more specific instructions + +**Partial execution:** +- Check console for specific file errors +- Some files may have been created successfully +- Use the snapshot feature to undo and try again + +**Vision models not working:** +- Ensure your selected AI assistant supports vision (GPT-4 Vision, Claude 3+) +- Image must be in a supported format (PNG, JPEG, WebP) +- Image size should be under 20MB + ### Keyboard Shortcuts Currently no keyboard shortcuts are assigned, but they can be added in the future for: diff --git a/src/components/editor/AiCodingAgentPanel.jsx b/src/components/editor/AiCodingAgentPanel.jsx index 1b3c273..1f0c9d6 100644 --- a/src/components/editor/AiCodingAgentPanel.jsx +++ b/src/components/editor/AiCodingAgentPanel.jsx @@ -387,6 +387,7 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } // Create files let successCount = 0; let errorCount = 0; + const errorDetails = []; for (const file of files) { try { @@ -413,27 +414,30 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } } catch (err) { console.error('[AI Coding Agent] Error creating file:', file.path, err); errorCount++; + errorDetails.push(`${file.path}: ${err.message}`); } } console.log('[AI Coding Agent] Plan execution complete', { successCount, errorCount }); if (successCount > 0) { - setError(null); // Show success message const message = errorCount > 0 - ? `Plan partially executed: ${successCount} files created, ${errorCount} failed` - : `Plan executed successfully: ${successCount} files created`; + ? `Plan partially executed: ${successCount} file(s) created, ${errorCount} failed` + : `✓ Plan executed successfully: ${successCount} file(s) created`; + + setError(null); + setResponse(message); + responseRef.current = message; - // Clear response after successful execution + // Clear response and image after a delay setTimeout(() => { setResponse(''); responseRef.current = ''; - }, 2000); - - alert(message); + handleRemoveImage(); + }, 3000); } else { - setError('Failed to create any files from the plan'); + setError(`Failed to create any files from the plan. Errors: ${errorDetails.join('; ')}`); } } catch (err) { console.error('[AI Coding Agent] Error executing plan:', err); From 665e100e83cb5f6cd025561eb8208a06afd2e0e3 Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Mon, 10 Nov 2025 15:28:32 +0200 Subject: [PATCH 4/8] Update src/components/editor/AiCodingAgentPanel.jsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/components/editor/AiCodingAgentPanel.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/editor/AiCodingAgentPanel.jsx b/src/components/editor/AiCodingAgentPanel.jsx index 1f0c9d6..b8ff856 100644 --- a/src/components/editor/AiCodingAgentPanel.jsx +++ b/src/components/editor/AiCodingAgentPanel.jsx @@ -452,7 +452,7 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } 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; + const filePattern = /###\s+File:\s+(\/[^\s\n]+)\s*\n\s*```(\w+)?\s*\n([\s\S]*?)```/g; let match; while ((match = filePattern.exec(response)) !== null) { From f9e2301e927abee8b580715b321e0ecc4e052db4 Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Mon, 10 Nov 2025 15:28:50 +0200 Subject: [PATCH 5/8] Update src/components/editor/AiCodingAgentPanel.jsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/components/editor/AiCodingAgentPanel.jsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/components/editor/AiCodingAgentPanel.jsx b/src/components/editor/AiCodingAgentPanel.jsx index b8ff856..dd2877c 100644 --- a/src/components/editor/AiCodingAgentPanel.jsx +++ b/src/components/editor/AiCodingAgentPanel.jsx @@ -468,8 +468,24 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } }; // Helper function to determine language from file path + // Handles both extensions and common extensionless files (e.g., README, Dockerfile, Makefile) const getLanguageFromPath = (path) => { - const ext = path.split('.').pop().toLowerCase(); + // Get the base filename (strip directory) + const base = path.split('/').pop(); + // Map for common extensionless files + const extensionlessMap = { + 'README': 'markdown', + 'README.md': 'markdown', + 'Dockerfile': 'dockerfile', + 'Makefile': 'makefile', + 'LICENSE': 'plaintext', + 'Procfile': 'plaintext', + }; + if (extensionlessMap[base]) { + return extensionlessMap[base]; + } + // Otherwise, use extension + const ext = base.includes('.') ? base.split('.').pop().toLowerCase() : ''; const languageMap = { 'ts': 'typescript', 'tsx': 'typescript', From 6b33919a9581beb8bf2c5bd40c82a77c5bc3894f Mon Sep 17 00:00:00 2001 From: Oleksandr Nykytenko Date: Mon, 10 Nov 2025 15:29:22 +0200 Subject: [PATCH 6/8] Update src/components/editor/AiCodingAgentPanel.jsx Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/components/editor/AiCodingAgentPanel.jsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/components/editor/AiCodingAgentPanel.jsx b/src/components/editor/AiCodingAgentPanel.jsx index dd2877c..b06da8a 100644 --- a/src/components/editor/AiCodingAgentPanel.jsx +++ b/src/components/editor/AiCodingAgentPanel.jsx @@ -422,9 +422,7 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } if (successCount > 0) { // Show success message - const message = errorCount > 0 - ? `Plan partially executed: ${successCount} file(s) created, ${errorCount} failed` - : `✓ Plan executed successfully: ${successCount} file(s) created`; + const message = `✓ Plan executed successfully: ${successCount} file(s) created${errorCount > 0 ? `, ${errorCount} failed` : ''}`; setError(null); setResponse(message); From a256c98e39747d325db9ff7c3cfa791f62d4188e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Nov 2025 13:41:33 +0000 Subject: [PATCH 7/8] Fix file creation loop and address PR review feedback Co-authored-by: anikitenko <12380460+anikitenko@users.noreply.github.com> --- src/components/editor/AiCodingAgentPanel.jsx | 65 +++----------------- src/ipc/ai_coding_agent.js | 18 +++--- 2 files changed, 17 insertions(+), 66 deletions(-) diff --git a/src/components/editor/AiCodingAgentPanel.jsx b/src/components/editor/AiCodingAgentPanel.jsx index b06da8a..5c6c07b 100644 --- a/src/components/editor/AiCodingAgentPanel.jsx +++ b/src/components/editor/AiCodingAgentPanel.jsx @@ -15,6 +15,7 @@ import * as styles from "./AiCodingAgentPanel.module.css"; import * as styles2 from "../ai-chat/MarkdownRenderer.module.scss"; import Markdown from "markdown-to-jsx"; import virtualFS from "./utils/VirtualFS"; +import {createVirtualFile} from "./utils/createVirtualFile"; import hljs from "../../assets/js/hljs/highlight.min" import "../../assets/css/hljs/xt256.min.css" @@ -391,25 +392,9 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } for (const file of files) { try { - const monaco = await import('monaco-editor'); - const uri = monaco.Uri.file(file.path); - - // Check if model already exists - let model = monaco.editor.getModel(uri); - - if (!model) { - // Create new model - const language = getLanguageFromPath(file.path); - model = monaco.editor.createModel(file.content, language, uri); - console.log('[AI Coding Agent] Created new file:', file.path, 'with language:', language); - } else { - // Update existing model - model.setValue(file.content); - console.log('[AI Coding Agent] Updated existing file:', file.path); - } - - // Register the file in VirtualFS - virtualFS.createFile(file.path, model); + // Use createVirtualFile which handles Monaco model creation properly + createVirtualFile(file.path, file.content); + console.log('[AI Coding Agent] Created file:', file.path); successCount++; } catch (err) { console.error('[AI Coding Agent] Error creating file:', file.path, err); @@ -428,12 +413,12 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } setResponse(message); responseRef.current = message; - // Clear response and image after a delay + // Clear response and image after a delay (10 seconds to give users time to review) setTimeout(() => { setResponse(''); responseRef.current = ''; handleRemoveImage(); - }, 3000); + }, 10000); } else { setError(`Failed to create any files from the plan. Errors: ${errorDetails.join('; ')}`); } @@ -450,7 +435,8 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } const files = []; // Match file sections: ### File: /path/to/file followed by code block - const filePattern = /###\s+File:\s+(\/[^\s\n]+)\s*\n\s*```(\w+)?\s*\n([\s\S]*?)```/g; + // Limit code block content to 50,000 characters to avoid catastrophic backtracking on malformed input + const filePattern = /###\s+File:\s+(\/[^\s\n]+)\s*\n\s*```(\w+)?\s*\n([^]{0,50000}?)```/g; let match; while ((match = filePattern.exec(response)) !== null) { @@ -464,41 +450,6 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse } return files; }; - - // Helper function to determine language from file path - // Handles both extensions and common extensionless files (e.g., README, Dockerfile, Makefile) - const getLanguageFromPath = (path) => { - // Get the base filename (strip directory) - const base = path.split('/').pop(); - // Map for common extensionless files - const extensionlessMap = { - 'README': 'markdown', - 'README.md': 'markdown', - 'Dockerfile': 'dockerfile', - 'Makefile': 'makefile', - 'LICENSE': 'plaintext', - 'Procfile': 'plaintext', - }; - if (extensionlessMap[base]) { - return extensionlessMap[base]; - } - // Otherwise, use extension - const ext = base.includes('.') ? base.split('.').pop().toLowerCase() : ''; - const languageMap = { - 'ts': 'typescript', - 'tsx': 'typescript', - 'js': 'javascript', - 'jsx': 'javascript', - 'json': 'json', - 'css': 'css', - 'scss': 'scss', - 'html': 'html', - 'md': 'markdown', - 'yaml': 'yaml', - 'yml': 'yaml', - }; - return languageMap[ext] || 'plaintext'; - }; const handleSubmit = async () => { if (!prompt.trim()) return; diff --git a/src/ipc/ai_coding_agent.js b/src/ipc/ai_coding_agent.js index fe6edd5..2c4cdac 100644 --- a/src/ipc/ai_coding_agent.js +++ b/src/ipc/ai_coding_agent.js @@ -550,10 +550,12 @@ IMPORTANT: - Code blocks must specify the language (json, typescript, tsx, css, etc.) `; - // If image is provided, add it to the message - const messages = []; + console.log('[AI Coding Agent Backend] Sending plan request to LLM'); + + let resp; + // If image is provided, use messages API with vision if (image) { - messages.push({ + const messages = [{ role: 'user', content: [ { type: 'text', text: fullPrompt }, @@ -562,16 +564,14 @@ IMPORTANT: image_url: { url: image } } ] - }); + }]; + resp = await llm.chat({ messages, stream: true }); } else { + // Otherwise use standard user prompt llm.user(fullPrompt); + resp = await llm.chat({ stream: true }); } - console.log('[AI Coding Agent Backend] Sending plan request to LLM'); - const resp = image - ? await llm.chat({ messages, stream: true }) - : await llm.chat({ stream: true }); - let fullContent = ""; if (resp && typeof resp === "object" && "stream" in resp && typeof resp.complete === "function") { From c0407493c864bc99d10a1519deda2949e7bcc989 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 10 Nov 2025 14:05:42 +0000 Subject: [PATCH 8/8] Fix handleRefine usage and update plan code prompt for SDK-only development Co-authored-by: anikitenko <12380460+anikitenko@users.noreply.github.com> --- src/components/editor/AiCodingAgentPanel.jsx | 6 +-- src/ipc/ai_coding_agent.js | 55 ++++++++++++++------ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/components/editor/AiCodingAgentPanel.jsx b/src/components/editor/AiCodingAgentPanel.jsx index 5c6c07b..df0e9b0 100644 --- a/src/components/editor/AiCodingAgentPanel.jsx +++ b/src/components/editor/AiCodingAgentPanel.jsx @@ -912,11 +912,7 @@ export default function AiCodingAgentPanel({ codeEditor, response, setResponse }