From 63e442c9b9dab0fe04aec82fd3fd43ac6e342774 Mon Sep 17 00:00:00 2001 From: Livio Meuli Date: Wed, 27 May 2026 07:59:36 +0200 Subject: [PATCH] Update Readme --- README.md | 744 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 441 insertions(+), 303 deletions(-) diff --git a/README.md b/README.md index 44a32e2..d284cc0 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,21 @@ # AISE AI Code Editor — Technische Dokumentation -AI-Supported Lightweight Code Editor built with Streamlit (AISE501 Spring 2026) - -Diese Datei enthält die ausführliche technische Dokumentation des Projekts. Für eine Kurzübersicht siehe `README.md`. +KI-unterstützter Lightweight Code Editor auf Basis von Streamlit (AISE501 Spring 2026). --- ## Inhaltsverzeichnis 1. [Projektstruktur](#projektstruktur) -2. [Frontend](#frontend) -3. [Backend Manager](#backend-manager) -4. [Backend Agent (MCP-System)](#backend-agent-mcp-system) -5. [MCP-Server-Konfiguration](#mcp-server-konfiguration) -6. [Tests](#tests) -7. [Setup](#setup) -8. [Architektur-Übersicht](#architektur-übersicht) +2. [Schnellstart](#schnellstart) +3. [Frontend](#frontend) +4. [Backend Manager](#backend-manager) +5. [Backend Agent (MCP-System)](#backend-agent-mcp-system) +6. [MCP-Server-Konfiguration](#mcp-server-konfiguration) +7. [Architektur-Übersicht](#architektur-übersicht) +8. [Wichtige Designentscheidungen](#wichtige-designentscheidungen) +9. [Tests](#tests) +10. [Umgebungsvariablen](#umgebungsvariablen) --- @@ -24,288 +24,52 @@ Diese Datei enthält die ausführliche technische Dokumentation des Projekts. F ``` AISE_AIAgent/ ├── frontend/ # Streamlit UI-Komponenten -│ ├── app.py # Haupteinstiegspunkt der Streamlit-App -│ ├── state.py # Session-State-Verwaltung -│ ├── sidebar.py # Datei-Navigation (Sidebar) -│ ├── editor.py # Code-Editor-Pane -│ └── chat.py # Chat-Interface +│ ├── app.py # Einstiegspunkt der App; Seitenkonfiguration + Routing +│ ├── state.py # Zentrale Session-State-Initialisierung +│ ├── sidebar.py # Datei-Explorer + Navigations-Radio +│ ├── editor.py # Ace-Editor-Tabs + Ausführungs-Output +│ └── chat.py # Chat-Interface + Agent-Mode-UI │ -├── backend/ # Backend-Logik -│ ├── managers/ # Business-Logik für UI-Operationen -│ │ ├── file_manager.py # Datei-CRUD (lesen, schreiben, listen) -│ │ ├── chat_manager.py # AI-Chat-Verwaltung und -History -│ │ ├── system_prompter.py # System-Prompts und Kontext-Injektion -│ │ ├── search_manager.py # Web-Suche (DuckDuckGo) -│ │ ├── execution_engine.py # Code-Ausführung und Sandboxing -│ │ └── debug_logger.py # Logging, Fehlerbehandlung, Debug-Ausgaben +├── backend/ +│ ├── managers/ # Business-Logik, direkt vom Frontend aufgerufen +│ │ ├── file_manager.py # Workspace-CRUD mit Path-Traversal-Schutz +│ │ ├── chat_manager.py # LLM-API-Wrapper + Sliding-Window-History +│ │ ├── system_prompter.py # Kontextbewusste System-Prompt-Generierung +│ │ ├── search_manager.py # DuckDuckGo-Websuche + Seitenabruf +│ │ ├── execution_engine.py # Subprocess-basierte Code-Ausführung (Python, LaTeX) +│ │ └── debug_logger.py # Rotierende Logdatei + Fehler-Aggregation │ │ -│ └── agent/ # Autonomes AI-Agent-System (MCP-basiert) -│ ├── coding_agent.py # Haupt-Agent-Loop (Plan-Act-Observe) -│ ├── mcp_server_adapter.py # MCP-Adapter: verbindet Agent mit MCP-Servern -│ ├── mcp_server_adapter_RAG.py # MCP-Adapter mit RAG-basierter Tool-Auswahl -│ ├── mcp_server_config.json # Konfiguration der MCP-Server (Startbefehle) -│ └── servers/ # MCP-Server-Implementierungen -│ ├── mcp_server_code_execution.py # Tool: Python-Code ausführen -│ ├── mcp_server_file_search.py # Tool: Dateien suchen und lesen -│ └── mcp_server_web_search.py # Tool: Web-Suche via DuckDuckGo +│ └── agent/ # Autonomes KI-Agenten-System (MCP-basiert) +│ ├── coding_agent.py # Plan→Aktion→Beobachten-Schleife +│ ├── mcp_server_adapter.py # Verbindet den Agenten mit MCP-Tool-Servern +│ ├── mcp_server_config.json # Welche MCP-Server gestartet werden (Pfade + Befehle) +│ └── servers/ # MCP-Server-Implementierungen (stdio-Transport) +│ ├── mcp_server_code_execution.py # Tool: Sandbox-Python-Ausführung + Linting +│ ├── mcp_server_file_search.py # Tool: Workspace-Datei lesen/schreiben/suchen +│ └── mcp_server_web_search.py # Tool: DuckDuckGo-Suche + Seitenabruf │ -├── tests/ # Unit-Tests (pytest) -│ ├── conftest.py # Globale Test-Fixtures und MCP-Mocks -│ ├── test_file_manager.py +├── tests/ # pytest-Unit-Tests +│ ├── conftest.py # Globaler MCP-Mock (keine echten Subprozesse in Tests) │ ├── test_chat_manager.py -│ ├── test_execution_engine.py │ ├── test_coding_agent.py │ ├── test_debug_logger.py -│ ├── test_system_prompter.py +│ ├── test_execution_engine.py +│ ├── test_file_manager.py │ ├── test_mcp_server_code_execution.py │ ├── test_mcp_server_file_search.py -│ └── test_mcp_server_web_search.py +│ ├── test_mcp_server_web_search.py +│ ├── test_search_manager.py +│ └── test_system_prompter.py │ -├── workspace/ # Agent-Sandbox (isoliertes Arbeitsverzeichnis) -└── .env.example # Vorlage für Umgebungsvariablen +├── workspace/ # Sandbox-Verzeichnis für Agent- und Editor-Dateien +├── logs/ # Rotierende Logdateien (app.log, errors.log) +├── .env # Lokale Umgebungsvariablen (nicht eingecheckt) +└── .env.example # Vorlage für erforderliche Umgebungsvariablen ``` --- -## Frontend - -Das Frontend besteht aus Streamlit-Komponenten, die zusammen eine interaktive Code-Editor-Oberfläche bilden. - -### `app.py` -Haupteinstiegspunkt der Applikation. Orchestriert das Layout und initialisiert alle UI-Komponenten (Sidebar, Editor, Chat). - -### `state.py` -Zentralisierte Verwaltung des Streamlit Session-State. Stellt sicher, dass alle Komponenten denselben Zustand (geöffnete Datei, Chat-History, Agent-Status) teilen. - -### `sidebar.py` -Datei-Browser und Projekt-Navigation. Erlaubt das Durchsuchen des Workspaces und das Öffnen von Dateien im Editor. - -### `editor.py` -Code-Editor-Pane mit Syntax-Highlighting. Ermöglicht das Bearbeiten und Speichern von Code-Dateien direkt im Browser. - -### `chat.py` -Chat-Interface für den KI-Assistenten. Zeigt die Konversations-History und ermöglicht Eingaben an das AI-Modell. - ---- - -## Backend Manager - -Die Manager-Klassen kapseln die Business-Logik und werden direkt vom Frontend aufgerufen. - -### `file_manager.py` -Stellt CRUD-Operationen auf dem Workspace-Verzeichnis bereit: -- Dateien lesen, schreiben, umbenennen, löschen -- Verzeichnisstruktur auflisten -- Sichere Pfadvalidierung (verhindert Path-Traversal) - -**Designentscheidung — `list_files()` vs. `get_file_tree()`:** -Die Projektspezifikation nennt `list_files()` als `FileManager`-Methode. Im vorliegenden Design wurde bewusst `get_file_tree()` implementiert, da das Frontend eine verschachtelte Baumstruktur benötigt (für den interaktiven File Explorer in der Sidebar). Eine flache Liste würde die Navigation nicht unterstützen. Für den Agent Mode übernimmt der MCP-Server `mcp_server_file_search.py` die Dateisuche — die Funktionalität ist damit im System vorhanden, nur architektonisch sauber getrennt. - -### `chat_manager.py` -Verwaltet AI-Chat-Interaktionen: -- Aufbau und Verwaltung der Chat-History -- Senden von Nachrichten an das AI-Modell -- Formatierung von System- und User-Nachrichten - -**Designentscheidung — Fehler-Output im normalen Chat:** -Laufzeitfehler und stderr-Output werden im normalen Chat bewusst **nicht automatisch** in den Chat-Kontext injiziert. Stattdessen gibt es den "Debug with AI"-Button im Editor, über den der User selbst entscheidet wann er die AI einschalten möchte. Dies verhindert, dass die Chat-History mit ungewollten Fehlermeldungen geflutet wird. Im Agent Mode wird dies anders gelöst: dort landet jeder Execution-Fehler automatisch als Observation im Plan-Act-Observe-Loop und der Agent replant ohne User-Eingriff. - -### `system_prompter.py` -Generiert kontextreiche System-Prompts für den AI-Assistenten: -- Injektion von aktuellem Dateiinhalt als Kontext -- Steuerung des AI-Verhaltens (Coding-Assistent-Persona) - -### `execution_engine.py` -Führt Python-Code sicher aus: -- Subprocess-basierte Code-Ausführung -- Timeout-Schutz und Output-Capture -- Fehler- und Exception-Handling - -### `debug_logger.py` -Logging und Fehler-Tracking: -- Formatierte Log-Ausgaben für Debugging -- `format_debug_output(output)` formatiert den Execution-Output (`stdout`, `stderr`, `return_code`) in einen einheitlichen String für die UI-Anzeige und den AI-Chat-Kontext - -**Designentscheidung — `log_error()` nicht implementiert:** -Die Projektspezifikation nennt `log_error()` als `DebugLogger`-Methode. Diese wurde bewusst nicht als separate Methode implementiert, da Python's eingebautes `logging`-Modul diese Funktionalität mit `logger.error()` bereits vollständig abdeckt. Im gesamten Projekt wird konsistent `logger = get_logger(__name__)` gefolgt von `logger.error(...)` verwendet — eine eigene Wrapper-Methode wäre toter Code ohne Mehrwert. - -### `search_manager.py` -Web-Suche für den KI-Assistenten via DuckDuckGo: -- Nutzt die `ddgs`-Bibliothek (DuckDuckGo Search) für API-freie Websuche -- Gibt strukturierte Suchergebnisse zurück (Titel, URL, Snippet) -- Wird vom Chat-Manager aufgerufen, wenn der Assistent externe Dokumentation oder Code-Beispiele benötigt -- Keine API-Key-Konfiguration notwendig (da DuckDuckGo öffentlich zugänglich ist) - ---- - -## Backend Agent (MCP-System) - -Der Agent ist ein autonomes System, das komplexe Coding-Aufgaben selbstständig löst. Er kommuniziert mit externen Tool-Servern über das **Model Context Protocol (MCP)**. - -### `coding_agent.py` -Implementiert den Plan-Act-Observe-Loop: -1. **Plan**: Das AI-Modell wählt das nächste Tool und Argumente -2. **Act**: Das Tool wird via MCP-Adapter aufgerufen (nach User-Bestätigung) -3. **Observe**: Das Ergebnis wird in die Message-History eingefügt -4. Der Loop wiederholt sich bis zur Fertigstellung oder einem `done`-Tool-Aufruf - -Wichtige Klassen und Funktionen: -- `CodingAgent`: Haupt-Klasse mit `start_task()`, `propose_next_action()`, `approve()`, `reject()` -- `truncate_result()`: Kürzt lange Tool-Outputs bevor sie in die History gehen -- `trim_messages()`: Entfernt alte Turns aus der History wenn das Kontextfenster voll wird -- `_strip_code_fences()`: Bereinigt Markdown-Fences aus LLM-JSON-Antworten - -Konstanten: `MAX_ITERATIONS`, `MAX_RESULT_LENGTH`, `MAX_HISTORY_CHARS` - -### `mcp_server_adapter.py` -Verbindet den Coding-Agent mit den MCP-Tool-Servern: -- Liest `mcp_server_config.json` und startet die konfigurierten Server als Subprozesse -- Baut MCP-Sessions via `stdio_client` auf -- Registriert alle verfügbaren Tools aus allen Servern in einem zentralen `tool_registry` -- Delegiert Tool-Aufrufe an den richtigen Server via `call_tool()` - -Hauptmethoden: -- `initialize_all_servers()`: Startet alle Server und baut Sessions auf -- `get_all_tools()`: Gibt alle registrierten Tool-Definitionen zurück -- `call_tool(tool_name, arguments)`: Führt ein Tool auf dem zuständigen Server aus - -### `mcp_server_adapter_RAG.py` -Erweiterter MCP-Adapter mit semantischer Tool-Auswahl via Retrieval-Augmented Generation (RAG): - -**Motivation**: Bei vielen MCP-Tools kann das LLM-Kontextfenster überfüllt werden, wenn alle Tool-Definitionen mitgesendet werden. Der RAG-Adapter löst dies durch semantische Vorauswahl. - -**Funktionsweise**: -1. Beim Initialisieren werden alle Tool-Beschreibungen mit `SentenceTransformer('all-MiniLM-L6-v2')` in Embeddings umgewandelt -2. Bei jedem Agent-Schritt wird der aktuelle Task als Query kodiert -3. Cosine-Similarity zwischen Query- und Tool-Embeddings bestimmt die `top_k` relevantesten Tools -4. Nur diese Tools werden dem LLM als verfügbare Aktionen präsentiert - -Hauptmethoden: -- `initialize_all_sessions()`: Startet Server, baut Sessions auf, erstellt Embedding-Index -- `get_relevant_tools(query, top_k=5)`: Gibt die `top_k` semantisch ähnlichsten Tools zurück -- `call_tool(tool_name, arguments)`: Findet den zuständigen Server und führt das Tool aus -- `shutdown_all_sessions()`: Schliesst alle offenen MCP-Sessions sauber - -Abhängigkeit: `sentence-transformers`, `numpy` - -**Hinweis**: Diese Klasse befindet sich noch in der Entwicklung (Work in Progress). Es gibt bekannte Bugs (z.B. Tippfehler `commanf` statt `command`, falsche Verwendung von `result.get()` vs. `result.tools`). - ---- - -## MCP-Server-Konfiguration - -### Format: `mcp_server_config.json` - -Die Datei `backend/agent/mcp_server_config.json` definiert, welche MCP-Server der Adapter starten soll. Das Format ist ein JSON-Objekt, wobei jeder Key ein frei wählbarer Servername ist: - -```json -{ - "ServerName": { - "command": "py", - "args": ["servers/mcp_server_datei.py"], - "env": { - "API_KEY": "optional_key" - } - } -} -``` - -| Feld | Pflicht | Beschreibung | -|-----------|---------|--------------| -| `command` | Ja | Ausführbares Programm (z.B. `py`, `python3`, `node`) | -| `args` | Ja | Argumente als Array (Pfad zum Server-Script) | -| `env` | Nein | Umgebungsvariablen für den Serverprozess | - -### Aktuelle Server - -```json -{ - "FileSearchServer": { - "command": "py", - "args": ["servers/mcp_server_file_search.py"] - }, - "WebSearchServer": { - "command": "py", - "args": ["servers/mcp_server_web_search.py"], - "env": { "DDGS_API_KEY": "your_ddgs_api_key_here" } - }, - "CodeExecutionServer": { - "command": "py", - "args": ["servers/mcp_server_code_execution.py"] - } -} -``` - -### Neuen MCP-Server hinzufügen - -1. Neues Server-Script in `backend/agent/servers/` erstellen (MCP-konformes Python-Script) -2. Eintrag in `mcp_server_config.json` ergänzen: - ```json - "MeinNeuerServer": { - "command": "py", - "args": ["servers/mcp_server_mein_tool.py"] - } - ``` -3. Der Adapter erkennt den neuen Server beim nächsten Start automatisch und registriert seine Tools - ---- - -## Tests - -### Tests ausführen - -```bash -# Alle Tests ausführen -pytest tests/ -v - -# Einzelnes Test-Modul ausführen -pytest tests/test_coding_agent.py -v - -# Tests mit Kurzausgabe -pytest tests/ -``` - -### Teststruktur - -Die Tests liegen in `tests/` und folgen dem Muster `test_.py`. - -#### `conftest.py` -Globale Pytest-Konfiguration. Patcht den `MCPToolAdapter` auf `sys.modules`-Ebene, bevor irgendein Test-Modul importiert wird. Dadurch werden beim Import von `coding_agent` keine echten MCP-Subprozesse gestartet. Der Mock-Adapter liefert sofort leere Ergebnisse zurück. - -#### Was wird getestet - -| Test-Datei | Getestetes Modul | Schwerpunkt | -|---|---|---| -| `test_file_manager.py` | `backend/managers/file_manager.py` | Datei-CRUD, Pfad-Validierung | -| `test_chat_manager.py` | `backend/managers/chat_manager.py` | Chat-History, Nachrichtenformatierung | -| `test_execution_engine.py` | `backend/managers/execution_engine.py` | Code-Ausführung, Timeouts, Fehlerbehandlung | -| `test_system_prompter.py` | `backend/managers/system_prompter.py` | Prompt-Generierung, Kontext-Injektion | -| `test_debug_logger.py` | `backend/managers/debug_logger.py` | Log-Formatierung, Fehler-Aggregation | -| `test_coding_agent.py` | `backend/agent/coding_agent.py` | Agent-Loop, Tool-Dispatch, History-Trimming | -| `test_mcp_server_code_execution.py` | `backend/agent/servers/mcp_server_code_execution.py` | MCP Code-Execution-Tool | -| `test_mcp_server_file_search.py` | `backend/agent/servers/mcp_server_file_search.py` | MCP Datei-Such-Tool | -| `test_mcp_server_web_search.py` | `backend/agent/servers/mcp_server_web_search.py` | MCP Web-Such-Tool | - -#### Testklassen in `test_coding_agent.py` - -- **`TestTruncateResult`**: Prüft, dass lange Tool-Outputs korrekt gekürzt werden -- **`TestTrimMessages`**: Prüft, dass alte History-Turns entfernt werden wenn der Kontext zu gross wird; System-Message und Original-Task bleiben immer erhalten -- **`TestStripCodeFences`**: Prüft, dass Markdown-Codeblöcke aus LLM-Antworten entfernt werden -- **`TestCodingAgentInit`**: Prüft initialen Zustand und `start_task()`-Reset-Verhalten -- **`TestProposeNextAction`**: Prüft den API-Aufruf-Zyklus mit gemockter API; testet Fehler-Handling (JSON-Parse-Fehler, API-Exceptions, Max-Iterations) -- **`TestApprove`**: Prüft `approve()` mit gemocktem `dispatch_tool`; testet Tool-Ergebnis-Injektion und Error-Replan-Tagging -- **`TestReject`**: Prüft, dass `reject()` das Feedback korrekt in die History injiziert und kein Tool ausführt - -#### Test-Konventionen - -- MCP-Server werden in Tests **nicht** als echte Subprozesse gestartet (via `conftest.py`-Mock) -- Streamlit-Aufrufe werden mit `patch("modul.st")` gemockt -- Dateisystem-Tests nutzen `tmp_path` (pytest-Fixture) für isolierte temporäre Verzeichnisse -- Async-Tests verwenden `@pytest.mark.asyncio` (benötigt `pytest-asyncio`) - ---- - -## Setup +## Schnellstart ### 1. Repository klonen @@ -320,7 +84,7 @@ cd AISE1_Project # Windows .\.venv\Scripts\Activate.ps1 -# macOS/Linux +# macOS / Linux source .venv/bin/activate ``` @@ -334,10 +98,10 @@ pip install -r requirements.txt ```bash cp .env.example .env -# .env mit API-Keys befüllen +# .env öffnen und HOST, PORT, API_KEY, MODEL eintragen ``` -### 5. Applikation starten +### 5. App starten ```bash streamlit run frontend/app.py @@ -349,6 +113,281 @@ streamlit run frontend/app.py pytest tests/ -v ``` +**Optionale Abhängigkeit:** Die LaTeX-Unterstützung (`.tex`-Ausführung) erfordert `pdflatex` +im System-`PATH`. Ohne `pdflatex` funktioniert der Editor weiterhin; beim Ausführen einer +`.tex`-Datei erscheint ein `FileNotFoundError` im stderr-Panel. + +--- + +## Frontend + +Alle Frontend-Module sind reine Streamlit-Komponenten. Sie enthalten keine Business-Logik, +sondern delegieren alles an die Backend-Manager. + +### `app.py` +Einstiegspunkt der Applikation. Ruft `init_state()` auf Modul-Ebene auf (vor `main()`), +damit alle Session-State-Schlüssel existieren, bevor ein Widget gerendert wird. Delegiert +an `render_sidebar()`, `render_editor()` und `render_chat()` basierend auf dem Navigations-Radio. + +### `state.py` +Zentrale Quelle aller `st.session_state`-Schlüsselnamen und ihrer Standardwerte. +Alle Schlüssel nutzen `if key not in st.session_state`-Guards, damit bei Streamlit-Reruns +keine bestehenden Werte überschrieben werden. Aktuell verwaltete Schlüssel: + +| Schlüssel | Standard | Zweck | +|-----------|----------|-------| +| `last_selected` | `None` | Zuletzt angeklickter Baum-Knoten (verhindert erneutes Ausführen bei jedem Rerender) | +| `selected_folder` / `selected_folder_rel` | `None` | Aktuell markierter Ordner | +| `chat_manager` | `ChatManager()` | Live-ChatManager-Instanz | +| `open_files` | `[]` | Geordnete Liste absoluter Pfade als Editor-Tabs | +| `files_content` | `{}` | Pfad → aktueller Editor-Inhalt (kann von Disk abweichen) | +| `active_file` | `None` | Absoluter Pfad des aktiven Editor-Tabs | +| `exec_results` | `{}` | Pfad → letztes Ausführungsergebnis-Dict | +| `chat_history` | `[]` | Flache Liste von `{role, content}`-Dicts zur Anzeige | +| `agent_mode` | `False` | Ob die Agent-Mode-UI aktiv ist | +| `coding_agent` | `None` | Live-`CodingAgent`-Instanz während einer Aufgabe | +| `agent_status` | `"idle"` | `"idle"` / `"waiting_approval"` / `"done"` | +| `agent_log` | `[]` | Liste abgeschlossener Schritt-Einträge | +| `agent_pending_action` | `None` | Vorgeschlagene Aktion, die auf Benutzer-Genehmigung wartet | +| `search_results` | `[]` | Aktive Websuchergebnisse für Kontext-Injektion | + +### `sidebar.py` +Rendert das Navigations-Radio und den Workspace-Datei-Explorer (basierend auf +`streamlit-arborist` für einen interaktiven Baum). Datei-Klicks öffnen einen neuen +Editor-Tab; Ordner-Klicks zeigen eine Aktionsleiste mit «Datei hinzufügen» / «Ordner +hinzufügen» / «Löschen». Ein Popover am unteren Rand ermöglicht das Erstellen und +Hochladen von Dateien (bis 1 MB) im Workspace-Wurzelverzeichnis. + +### `editor.py` +Verwendet `streamlit-ace` für syntaxhervorgehobene Bearbeitung. Jede geöffnete Datei +erhält einen eigenen Tab via `st.tabs()`. Die aktive Datei steuert die Schaltflächen +«Code ausführen», «Herunterladen», «Schliessen», «Umbenennen» und «Löschen». Der Button +**Code ausführen** führt für Python-Dateien zuerst `ast.parse()` durch, um Syntaxfehler +vor dem Subprocess zu erkennen. Der Button **Mit KI debuggen** (nach einem fehlgeschlagenen +Lauf eingeblendet) formatiert die Fehlerausgabe und navigiert zur Chat-Ansicht mit einer +vorausgefüllten Debug-Nachricht. + +### `chat.py` +Zwei sich gegenseitig ausschliessende Ansichten, umgeschaltet via `st.toggle("Agent Mode")`: + +**Normaler Chat** (`render_normal_chat()`): +- Websuch-Panel oben — öffnet sich automatisch, wenn Suchergebnisse aktiv sind. +- System-Prompt wird vor jeder ausgehenden Nachricht neu generiert (`_set_system_prompt()`). +- Unterstützt Slash-Befehle `/search ` und `/search clear`. +- Einstellungs-Expander: Dateikontext-Toggle, Modell-Auswahl, Max-Token-Slider, + benutzerdefinierter System-Prompt. +- «Mit KI debuggen»-Nachrichten vom Editor werden über `pending_debug_message` im + Session-State weitergeleitet. + +**Agent Mode** (`render_agent_mode()`): +- `idle` → Aufgabeneingabe + Start-Schaltfläche. +- `waiting_approval` → zeigt vorgeschlagenen Gedanken + Tool + Argumente; Benutzer kann + Genehmigen, Ablehnen (mit Feedback) oder Abbrechen. +- `done` → Erfolgsmeldung + Folgefrage-Eingabe zum Weiterführen der Aufgabe. + +--- + +## Backend Manager + +### `file_manager.py` +Alle öffentlichen Methoden lösen Pfade auf und prüfen, ob sie innerhalb von `workspace/` +bleiben, bevor sie das Dateisystem berühren (**Path-Traversal-Schutz**). Je nach Operation +werden relative oder absolute Pfade akzeptiert und zurückgegeben: + +| Methode | Pfad-Typ | Hinweise | +|---------|----------|----------| +| `create_folder(relative_path, name)` | Workspace-relativ | Erstellt eine Ebene | +| `create_file(relative_path, name)` | Workspace-relativ | Standard: `.txt` | +| `read_file(absolute_path)` | Absolutes `Path`-Objekt | Vom Editor verwendet | +| `save_file(absolute_path, content)` | Absoluter String | Überschreibt vorhandenes | +| `rename_file(relative_path, new_name)` | Workspace-relativ | Erweiterung bleibt immer erhalten | +| `delete_file(relative_path)` | Workspace-relativ | | +| `delete_folder(relative_path)` | Workspace-relativ | Rekursiv via `shutil.rmtree` | +| `get_file_tree()` | — | Gibt verschachteltes Dict zurück; Verzeichnisse → Dict, Dateien → None | + +Dateien werden in `get_file_tree()` standardmässig auf `CODE_EXTENSIONS` gefiltert. + +### `chat_manager.py` +Kapselt einen OpenAI-kompatiblen REST-Endpunkt, konfiguriert via `.env`. + +**Sliding-Window-History:** `_build_payload_messages()` sendet immer zuerst die +System-Nachricht (damit sie nie verworfen wird), gefolgt von den letzten +`max_history_messages` (20) Nicht-System-Nachrichten. Das begrenzt die Payload-Grösse, +ohne den System-Prompt zu verlieren. + +**Fehlerbehandlung:** Verbindungs-Timeouts und HTTP-Fehler werden abgefangen, geloggt und +als Assistenten-Nachrichten in der History gespeichert (sodass die UI den Fehler inline +anzeigt). + +**API-Key:** Falls `API_KEY` den Wert `"EMPTY"` hat oder fehlt, wird kein +`Authorization`-Header gesendet (unterstützt lokale/anonyme Endpunkte). + +### `system_prompter.py` +Generiert kontextbewusste System-Prompts. Signatur: +```python +SystemPrompter.generate_prompt( + user_message="", + file_context=None, # {"name": str, "content": str} + search_context=None, # reserviert, noch nicht verdrahtet + task_type="default", # "debug" | "explain" | "optimize" | "default" +) +``` +Der Aufgabentyp wird anhand von Schlüsselwörtern in der Benutzernachricht durch +`_detect_task_type()` in `chat.py` ermittelt. Der Dateiinhalt wird wörtlich in einen +XML-ähnlichen `...`-Block eingebettet und bei `MAX_FILE_CHARS` Zeichen +abgeschnitten. `_extract_relevant_context()` nutzt `ast.parse()`, um nur die spezifische +Funktion oder Klasse zurückzugeben, nach der der Benutzer fragt, anstatt die gesamte Datei. + +### `execution_engine.py` +Führt Dateien in einem Subprocess mit `capture_output=True`, `text=True` und einem +`RUN_TIMEOUT` von 30 Sekunden aus. Aktuell unterstützt: +- `.py` — via `py`-Launcher (Windows) / `sys.executable` +- `.tex` — via `pdflatex -interaction=nonstopmode` (erfordert pdflatex im PATH) + +Rückgabe: `{"stdout": str, "stderr": str, "rc": int}`. + +### `search_manager.py` +DuckDuckGo-basierte Websuche und Seitenabruf für die Chat-Ansicht. SSRF-geschützt: +`_validate_url()` blockiert Nicht-HTTP(S)-Schemata, Loopback- und RFC-1918-private +IP-Bereiche. `fetch_page()` extrahiert lesbaren Text via BeautifulSoup, entfernt +`