Feat: ai integration [half-way to completion] - #2767
Conversation
Greptile SummaryThis PR introduces an AI chat/agent page, external-provider adapters, autonomous filesystem tools, settings, sidebar integration, and editor ghost-text completion. The implementation currently leaves important trust boundaries and completion-state behavior unresolved.
Confidence Score: 0/5This PR is not safe to merge until untrusted chat rendering, agent filesystem scoping, implicit file disclosure, and stale completion insertion are corrected. Remote content can execute in the application WebView, autonomous tools can reach paths outside the opened project, active files are silently included in external requests, and a stale ghost completion can modify the wrong editor location. Files Needing Attention: src/pages/aiAgent/aiAgent.js, src/utils/ai/agentTools.js, src/utils/ai/AIService.js, src/cm/extensions/aiAutocomplete.ts
|
| Filename | Overview |
|---|---|
| src/pages/aiAgent/aiAgent.js | Adds the chat and agent UI, but renders unescaped user and provider content as HTML in the privileged application page. |
| src/utils/ai/agentTools.js | Adds autonomous filesystem operations without constraining model-supplied paths to an opened project. |
| src/utils/ai/AIService.js | Centralizes provider selection and history while automatically transmitting active editor contents on every chat and agent request. |
| src/cm/extensions/aiAutocomplete.ts | Adds debounced ghost completions, but stale decorations can be accepted at a different cursor position. |
| src/utils/ai/agentLoop.js | Implements iterative tool calling and immediately executes model-generated operations without a permission or confirmation boundary. |
| src/utils/ai/OpenAiAdapter.js | Implements OpenAI streaming, tool calls, and completion requests; it is a direct outbound sink for injected file and tool context. |
| src/utils/ai/OpenRouterAdapter.js | Mirrors the OpenAI adapter through OpenRouter and transmits the same context and tool-result payloads. |
| src/settings/aiSettings.js | Adds provider credentials and model selection but no control or disclosure for automatic file-context sharing. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
User[User prompt or edit] --> UI[AI chat / autocomplete UI]
UI --> Service[AIService]
Service --> Context[Active-file context injection]
Context --> Provider[OpenAI / OpenRouter]
Provider --> Render[Markdown HTML rendering]
Provider --> Loop[Agent loop]
Loop --> Tools[Filesystem tools]
Tools --> FS[Local / SAF / remote files]
Tools --> Loop
Render --> WebView[Acode Cordova WebView]
Reviews (1): Last reviewed commit: "fix: Use valid icons for Agent mode togg..." | Re-trigger Greptile
| text = text | ||
| .replace(/`([^`]+)`/g, "<code>$1</code>") | ||
| .replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>") | ||
| .replace(/\*([^*]+)\*/g, "<em>$1</em>") | ||
| .replace(/\n/g, "<br>"); |
There was a problem hiding this comment.
Unescaped chat content executes HTML
When a user message, provider response, streamed response, stored history entry, or provider error contains active HTML, renderMarkdown preserves its tags and attributes before dangerouslySetInnerHTML parses it in Acode's Cordova WebView, allowing injected JavaScript to access application globals, persisted data, and filesystem-capable APIs.
How this was verified: Every message source reaches a renderer that escapes fenced code only and passes all other HTML unchanged to dangerouslySetInnerHTML.
| // Already a full URI | ||
| if (/^(file|content|ftp|sftp|https?):\/\//.test(path)) return path; | ||
|
|
||
| // Normalize slashes | ||
| path = path.replace(/\\/g, "/").replace(/^\/+/, ""); | ||
|
|
||
| // Try open folders | ||
| const folders = window.addedFolder || []; | ||
| for (const folder of folders) { | ||
| const base = folder.url?.replace(/\/$/, "") || folder; | ||
| if (base) return `${base}/${path}`; |
There was a problem hiding this comment.
Agent paths escape project roots
When the model supplies an absolute URI or a relative path containing parent-directory segments, resolvePath accepts or concatenates it without canonicalization or project-root containment, so autonomous read tools can disclose files outside the project to the provider and write tools can overwrite other user-accessible files without confirmation.
How this was verified: Model-generated paths flow through the unguarded resolver into filesystem operations, and read results are appended to messages sent on the next external-provider request.
Knowledge Base Used: File System
| let ctx = `You are an AI coding assistant inside Acode, a mobile code editor.\nActive file: ${fileName} (${lang})`; | ||
| if (selection && selection.trim().length > 0) { | ||
| ctx += `\n\nCurrently selected code:\n\`\`\`${lang}\n${selection}\n\`\`\``; | ||
| } else if (fullCode && fullCode.length < 8000) { | ||
| ctx += `\n\nFile contents:\n\`\`\`${lang}\n${fullCode}\n\`\`\``; |
There was a problem hiding this comment.
Requests silently disclose active files
When any chat or agent request is sent with a nonempty selection or an active file shorter than 8,000 characters, getFileContext automatically adds that code to the outbound provider payload, causing credentials, source code, or other confidential text to be transmitted even when the prompt does not request file context.
How this was verified: Both chat and runAgent unconditionally call buildMessages, which prepends the selected or complete active-file content before the adapters POST the messages externally.
| const pos = view.state.selection.main.head; | ||
| view.dispatch({ | ||
| changes: { from: pos, insert: textToInsert }, |
There was a problem hiding this comment.
Stale completion uses current cursor
When a ghost completion is visible and the user moves the cursor or changes the selection without editing, the plugin retains the decoration but inserts its text at the current selection head, causing a suggestion generated for one location to modify a different part of the document.
Knowledge Base Used: Editor Core (CodeMirror)
This pull request introduces the foundation for a native, context-aware AI assistant inside Acode. It includes both a conversational Chat Mode for code queries, and an Agent Mode that can autonomously read files, search the codebase, and apply edits using a Think -> Act -> Observe loop.
Note: This is currently a WIP. The frontend architecture, agent logic, and UI are fully built, but secure backend authentication and account linking are still pending.
🚧 Pending / Remaining Work
1. Backend Authentication & Account Linking
Just like Claude Code in VS Code, we need to implement an OAuth or token-based flow where users link their subscription-based accounts. Replace local API key inputs with secure backend proxy routing (preventing API keys from leaking on the client) and lastly connect the frontend to the official subscription backend (api.foxdebug.com or similar) to validate active subscriptions before authorizing AI requests.
2. Settings & Provider Additions
Add native adapter support for Anthropic and Gemini once the backend routing is solidified. Finalize the UI for "Logging in" vs "Using Custom API Keys".
3. Agentic Tuning
Further prompt-tuning of the TOOL_DEFINITIONS to prevent model hallucinations during complex multi-file refactors. Ensure the agent cannot maliciously delete root directories or perform destructive actions without confirmation.