263 lines
12 KiB
Markdown
263 lines
12 KiB
Markdown
---
|
|
name: Cursor-Style Chat Feature MVP
|
|
overview: Integration eines Cursor-artigen File-Editing-Chat-Features als neues Feature "codeeditor" im Gateway und der Nyla UI. Nutzt aicore-Modelle direkt, Chat-Datenmodelle vom Chatplayground, SSE-Streaming vom Chatbot-Feature. Nur Text-Dokumente (Markdown, JSON, YAML, Code). Dateien werden hochgeladen (kein SharePoint), spaeter mit virtuellen Folder-Tags strukturiert. Apply erzeugt neue lokale Dokument-Versionen.
|
|
todos:
|
|
- id: extend-workflow-mode
|
|
content: WorkflowModeEnum um WORKFLOW_CODEEDITOR erweitern in datamodelChat.py + FileContext/FileEditProposal Models
|
|
status: pending
|
|
- id: backend-feature-scaffold
|
|
content: "Feature-Scaffold: mainCodeeditor.py (Registrierung) + routeFeatureCodeeditor.py (Endpoints, Vorlage: chatplayground)"
|
|
status: pending
|
|
- id: file-context-manager
|
|
content: "fileContextManager.py: Hochgeladene Text-Dateien laden, Workspace-Snapshot erstellen (kein SharePoint)"
|
|
status: pending
|
|
- id: prompt-assembly
|
|
content: "promptAssembly.py: Cursor-artiger System Prompt Builder mit Datei-Kontext und Format-Instruktionen"
|
|
status: pending
|
|
- id: response-parser
|
|
content: "responseParser.py: AI-Antwort in Document-Segmente parsen (text, code_block, file_edit, etc.)"
|
|
status: pending
|
|
- id: frontend-feature-register
|
|
content: "FeatureView.tsx: codeeditor Views registrieren, CodeEditorPage + FileBrowserPanel + DiffPreviewPanel erstellen"
|
|
status: pending
|
|
- id: frontend-hooks
|
|
content: "useCodeEditor.ts Hook: Erweitert Playground-Pattern um File-Selection und Edit-Management"
|
|
status: pending
|
|
isProject: false
|
|
---
|
|
|
|
# MVP: Cursor-Style File-Editing Chat Feature ("CodeEditor")
|
|
|
|
## Professionelle Einschaetzung
|
|
|
|
### Kernfrage: aicore-Modelle direkt oder ueber Chat-Komponente?
|
|
|
|
**Empfehlung: Die bestehenden aicore-Modelle direkt nutzen** (nicht ueber eine externe Cursor-Chat-Komponente).
|
|
|
|
Begruendung:
|
|
|
|
- Die aicore-Infrastruktur (`aicoreModelRegistry`, `aicoreModelSelector`, Plugin-System) ist bereits produktionsreif mit Failover, Billing, RBAC und Multi-Provider-Support
|
|
- Eine externe Cursor-Komponente wuerde eine Abhaengigkeit schaffen, die schwer zu kontrollieren ist
|
|
- Der Mehrwert liegt nicht im LLM-Aufruf (den beherrscht aicore), sondern in der **Prompt-Orchestrierung** (System Prompt + Context + Tool Definitions) und dem **Response Parsing** (Antwort in Dokument-Segmente zerlegen)
|
|
- Der neue "Cursor-Style" Layer wird **auf aicore aufgebaut**, nicht neben oder statt aicore
|
|
|
|
### Was vom Chatplayground uebernommen werden kann
|
|
|
|
Sehr viel -- die Grundarchitektur ist ideal:
|
|
|
|
- **ChatWorkflow** Datenmodell: 1:1 wiederverwendbar (neuer `workflowMode: "CodeEditor"`)
|
|
- **ChatMessage** + **ChatDocument**: Vollstaendig wiederverwendbar fuer Chat-Verlauf und Datei-Referenzen
|
|
- **Polling-Mechanismus** (`getUnifiedChatData` mit `afterTimestamp`): Sofort nutzbar
|
|
- **SSE-Infrastruktur** (aus Chatbot-Feature): Kann fuer Echtzeit-Streaming aktiviert werden
|
|
- **PlaygroundPage UI-Pattern**: Resizable Two-Column Layout, Messages-Komponente, File-Upload, Input-Footer
|
|
- **Route-Pattern** (`routeFeatureChatplayground.py`): Als Vorlage fuer neue Feature-Route
|
|
- **Feature-Registrierung**: `VIEW_COMPONENTS` Registry in `FeatureView.tsx`, Backend `mainChatplayground.py`
|
|
|
|
### Was NEU gebaut werden muss
|
|
|
|
1. **File-Context-Manager** (Backend): Hochgeladene Text-Dateien als "Workspace" laden und als Kontext bereitstellen (kein SharePoint, spaeter virtuelle Folder-Tags)
|
|
2. **Prompt Assembly Service** (Backend): System Prompt mit File-Kontext und Cursor-artigen Instruktionen zusammenbauen
|
|
3. **Response Document Parser** (Backend): AI-Antwort in typisierte Dokument-Segmente zerlegen (text, code_block, file_edit, etc.)
|
|
4. **Diff-Preview UI** (Frontend): Text-Aenderungen als Diff anzeigen mit Accept/Reject
|
|
5. **File-List Panel** (Frontend): Hochgeladene Dateien auflisten und als Kontext auswaehlen (spaeter: virtuelle Folder-Tags)
|
|
6. **SSE-Integration** (Backend+Frontend): Echtzeit-Streaming ueber bestehende EventManager-Infrastruktur
|
|
|
|
---
|
|
|
|
## Architektur
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
subgraph ui [Nyla UI - Frontend]
|
|
CodeEditorPage["CodeEditorPage\n(neue View)"]
|
|
FileList["FileListPanel\n(hochgeladene Dateien)"]
|
|
ChatPanel["ChatPanel\n(Messages + SSE)"]
|
|
DiffPreview["DiffPreviewPanel\n(Text-Diffs)"]
|
|
CodeEditorPage --> FileList
|
|
CodeEditorPage --> ChatPanel
|
|
CodeEditorPage --> DiffPreview
|
|
end
|
|
|
|
subgraph gw [Gateway - Backend]
|
|
Route["routeFeatureCodeeditor.py\n(FastAPI Endpoints)"]
|
|
SSE["SSE Stream Endpoint\n(EventManager)"]
|
|
FileCtx["fileContextManager.py\n(Text-Dateien laden)"]
|
|
PromptAsm["promptAssembly.py\n(System Prompt Builder)"]
|
|
RespParse["responseParser.py\n(Document Segmentation)"]
|
|
Route --> FileCtx
|
|
Route --> PromptAsm
|
|
PromptAsm --> AiService["serviceAi\n(bestehend)"]
|
|
AiService --> AiCore["aicore\n(ModelRegistry + Plugins)"]
|
|
RespParse --> Route
|
|
RespParse --> SSE
|
|
end
|
|
|
|
subgraph data [Datenspeicher]
|
|
DB["Gateway DB\n(interfaceDbComponent)\nHochgeladene Dateien"]
|
|
end
|
|
|
|
ChatPanel -->|"POST /api/codeeditor/.../start"| Route
|
|
ChatPanel -->|"GET .../stream (SSE)"| SSE
|
|
FileList -->|"GET .../files"| Route
|
|
DiffPreview -->|"POST .../apply"| Route
|
|
FileCtx --> DB
|
|
```
|
|
|
|
|
|
|
|
---
|
|
|
|
## MVP Scope: Konkrete Implementierung
|
|
|
|
### Backend: Gateway
|
|
|
|
**1. Neues Feature `codeeditor`**
|
|
|
|
- Datei: `gateway/modules/features/codeeditor/mainCodeeditor.py`
|
|
- Registrierung analog zu `mainChatplayground.py` (RBAC, Feature-Config)
|
|
|
|
**2. Routes**
|
|
|
|
- Datei: `gateway/modules/features/codeeditor/routeFeatureCodeeditor.py`
|
|
- Kopie von `routeFeatureChatplayground.py` als Basis, erweitert um:
|
|
|
|
|
|
| Endpoint | Methode | Beschreibung |
|
|
| -------------------------------------- | ------- | ---------------------------------------------------------- |
|
|
| `/{instanceId}/start` | POST | Workflow starten (nutzt `chatStart` mit mode `CodeEditor`) |
|
|
| `/{instanceId}/{workflowId}/stop` | POST | Workflow stoppen |
|
|
| `/{instanceId}/{workflowId}/stream` | GET | SSE-Stream fuer Echtzeit-Updates (Messages, Logs, Edits) |
|
|
| `/{instanceId}/{workflowId}/chatData` | GET | Fallback-Polling fuer Chat-Daten |
|
|
| `/{instanceId}/workflows` | GET | Workflows auflisten |
|
|
| `/{instanceId}/files` | GET | Hochgeladene Text-Dateien auflisten |
|
|
| `/{instanceId}/files/{fileId}/content` | GET | Text-Datei-Inhalt laden |
|
|
| `/{instanceId}/{workflowId}/apply` | POST | Aenderung als neue Dokument-Version speichern |
|
|
|
|
|
|
**3. WorkflowMode Erweiterung**
|
|
|
|
- Datei: `gateway/modules/datamodels/datamodelChat.py`
|
|
- Neuer Enum-Wert: `WORKFLOW_CODEEDITOR = "CodeEditor"` in `WorkflowModeEnum`
|
|
|
|
**4. File Context Manager**
|
|
|
|
- Datei: `gateway/modules/features/codeeditor/fileContextManager.py`
|
|
- Laedt hochgeladene Text-Dateien aus Gateway DB (`interfaceDbComponent`)
|
|
- Unterstuetzte Formate: `.md`, `.txt`, `.json`, `.yaml`, `.yml`, `.xml`, `.csv`, `.py`, `.js`, `.ts`, `.html`, `.css`, `.sql`
|
|
- Baut einen "Workspace-Snapshot": Dateiliste + Inhalte der vom User ausgewaehlten Dateien
|
|
- Validiert MIME-Types (nur text-basierte Dateien akzeptieren)
|
|
- Spaeter erweiterbar: virtuelle Folder-Tags pro Datei fuer Strukturierung
|
|
|
|
**5. Prompt Assembly**
|
|
|
|
- Datei: `gateway/modules/features/codeeditor/promptAssembly.py`
|
|
- Baut System Prompt nach Cursor-Muster (dokumentiert in `wiki/cursor-doc/doc_cursor_ai_agent_architecture.md`)
|
|
- Injiziert: Datei-Kontexte, Benutzer-Instruktionen, Antwort-Format-Vorgaben
|
|
- Nutzt `aiService.callAiContent()` oder `interfaceAiObjects.callWithTextContext()` als LLM-Aufruf
|
|
|
|
**6. Response Document Parser**
|
|
|
|
- Datei: `gateway/modules/features/codeeditor/responseParser.py`
|
|
- Parst AI-Antwort in typisierte Segmente: `text`, `code_block`, `code_reference`, `file_edit`
|
|
- Speichert Segmente als erweiterte `ChatMessage` Eintraege (mit `actionMethod: "codeeditor"`)
|
|
- Spezifikation: `wiki/cursor-doc/doc_cursor_response_json_structure.md`
|
|
|
|
### Frontend: Nyla UI
|
|
|
|
**7. Feature-Registrierung**
|
|
|
|
- Datei: `frontend_nyla/src/pages/FeatureView.tsx`
|
|
- Neuer Eintrag in `VIEW_COMPONENTS`:
|
|
|
|
```typescript
|
|
codeeditor: {
|
|
editor: CodeEditorPage,
|
|
workflows: WorkflowsPage, // wiederverwendet
|
|
}
|
|
```
|
|
|
|
**8. CodeEditorPage**
|
|
|
|
- Datei: `frontend_nyla/src/pages/views/codeeditor/CodeEditorPage.tsx`
|
|
- Drei-Panel-Layout (File-Browser links, Chat mitte, Diff-Preview rechts)
|
|
- Nutzt bestehende `Messages` Komponente, `useResizablePanels`, `usePlayground`-Pattern
|
|
|
|
**9. File List Panel**
|
|
|
|
- Datei: `frontend_nyla/src/components/CodeEditor/FileListPanel.tsx`
|
|
- Flache Liste der hochgeladenen Text-Dateien mit Checkbox-Auswahl
|
|
- Upload-Button fuer neue Dateien (Drag & Drop wiederverwendet aus Playground)
|
|
- Ausgewaehlte Dateien werden als Kontext an den Chat gesendet (analog `listFileId`)
|
|
- Spaeter erweiterbar: virtuelle Folder-Tags als Gruppierung
|
|
|
|
**10. Diff Preview Panel**
|
|
|
|
- Datei: `frontend_nyla/src/components/CodeEditor/DiffPreviewPanel.tsx`
|
|
- Zeigt `file_edit` Segmente aus der AI-Antwort als Text-Diff an
|
|
- Accept/Reject Buttons pro Aenderung
|
|
- Accept erzeugt neue Dokument-Version (POST `/{instanceId}/{workflowId}/apply`)
|
|
- MVP: einfacher Side-by-Side Text-Diff (kein vollstaendiger Code-Editor noetig)
|
|
|
|
**11. Hooks**
|
|
|
|
- Datei: `frontend_nyla/src/hooks/useCodeEditor.ts`
|
|
- Erweitert `useDashboardInputForm` Pattern um:
|
|
- `selectedFiles: string[]` (ausgewaehlte Kontext-Dateien)
|
|
- `pendingEdits: FileEdit[]` (vorgeschlagene Aenderungen)
|
|
- `applyEdit(editId)` / `rejectEdit(editId)` Aktionen
|
|
|
|
### Datenmodell-Erweiterungen
|
|
|
|
**12. Neue Pydantic Models** (in bestehendem `datamodelChat.py` oder eigenem File)
|
|
|
|
```python
|
|
class FileContext(BaseModel):
|
|
fileId: str
|
|
fileName: str
|
|
content: Optional[str] = None
|
|
mimeType: str
|
|
tags: List[str] = Field(default_factory=list) # virtuelle Folder-Tags (spaeter)
|
|
|
|
class FileEditProposal(BaseModel):
|
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
|
|
fileId: str # Referenz auf bestehende Datei
|
|
fileName: str
|
|
operation: str # "edit" | "create"
|
|
oldContent: Optional[str] = None
|
|
newContent: str
|
|
diffSummary: Optional[str] = None # Kurzbeschreibung der Aenderung
|
|
status: str = "pending" # "pending" | "accepted" | "rejected"
|
|
|
|
class FileVersion(BaseModel):
|
|
id: str = Field(default_factory=lambda: str(uuid.uuid4()))
|
|
sourceFileId: str # Original-Datei
|
|
editProposalId: str # Referenz auf akzeptiertes FileEditProposal
|
|
newFileId: str # Neue Datei-Version in DB
|
|
createdAt: float = Field(default_factory=getUtcTimestamp)
|
|
```
|
|
|
|
---
|
|
|
|
## Entschiedene Design-Entscheide
|
|
|
|
1. **Datenquelle**: Hochgeladene Dateien im System (kein SharePoint). Spaeter: virtuelle Folder-Tags pro Datei fuer Strukturierung
|
|
2. **Dateitypen**: Nur Text-basierte Dokumente (Markdown, JSON, YAML, Code, etc.)
|
|
3. **Apply-Mechanismus**: Erzeugt neue lokale Dokument-Version in der DB (keine externe Synchronisation)
|
|
4. **Streaming**: SSE ueber bestehende `EventManager`-Infrastruktur aus dem Chatbot-Feature
|
|
|
|
---
|
|
|
|
## SSE-Integration (Details)
|
|
|
|
Nutzt die bestehende Infrastruktur aus `gateway/modules/features/chatbot/streaming/events.py`:
|
|
|
|
- **EventManager** Singleton: `get_event_manager()` - verwaltet async Queues pro Workflow
|
|
- **Event-Emission**: In `interfaceDbChat.createMessage()` und `createLog()` bereits eingebaut
|
|
- **Neuer SSE-Endpoint**: `GET /api/codeeditor/{instanceId}/{workflowId}/stream`
|
|
- **Event-Typen fuer CodeEditor**:
|
|
- `chatdata` (bestehend): Messages, Logs, Stats
|
|
- `file_edit` (neu): FileEditProposal Events fuer Echtzeit-Diff-Updates
|
|
- `file_version` (neu): Neue Datei-Version erstellt (nach Apply)
|
|
- **Frontend**: `useCodeEditor` Hook oeffnet `EventSource` statt Polling
|
|
- **Fallback**: `chatData` Polling-Endpoint bleibt als Fallback verfuegbar
|
|
|