From 45ec8f8208a589046643cb47f56b08d32fe33913 Mon Sep 17 00:00:00 2001 From: Livio Meuli Date: Sun, 24 May 2026 10:28:44 +0200 Subject: [PATCH] chore: prior changes on func_improvments before agent merge --- DEBUG_LOGGER_USAGE.md | 46 +++++ README.md | 331 ++++++++++++++++++++++-------------- READMEnew.md | 381 ++++++++++++++++++++++++++++++++++++++++++ run_agent.py | 78 --------- 4 files changed, 628 insertions(+), 208 deletions(-) create mode 100644 DEBUG_LOGGER_USAGE.md create mode 100644 READMEnew.md delete mode 100644 run_agent.py diff --git a/DEBUG_LOGGER_USAGE.md b/DEBUG_LOGGER_USAGE.md new file mode 100644 index 0000000..965b61f --- /dev/null +++ b/DEBUG_LOGGER_USAGE.md @@ -0,0 +1,46 @@ +# DebugLogger Usage + +## Import +```python +from backend.managers.debug_logger import DebugLogger +logger = DebugLogger() +``` + +## Methoden +```python +logger.clear() # vor jeder neuen Ausführung aufrufen +logger.log("Nachricht") # INFO-Eintrag +logger.log_error("Fehler") # ERROR-Eintrag +logger.get_logs() # gibt Liste aller Einträge zurück +logger.format_debug_output({ # gibt formatierten String zurück + "rc": 0, + "stdout": "...", + "stderr": "..." +}) +``` + +## Eintrag-Format +```python +{ + "level": "INFO", # oder "ERROR" + "message": "Nachricht", + "timestamp": "14:23:01" +} +``` + +## Beispiel +```python +logger = DebugLogger() +logger.clear() +logger.log("Starte Ausführung...") + +try: + result = run_something() + logger.log("Erfolgreich abgeschlossen.") +except Exception as e: + logger.log_error(f"Fehler: {e}") + +# Logs anzeigen +for entry in logger.get_logs(): + print(f"[{entry['timestamp']}] [{entry['level']}] {entry['message']}") +``` diff --git a/README.md b/README.md index 97f4062..7fc8b13 100644 --- a/README.md +++ b/README.md @@ -1,153 +1,224 @@ -# AISE AI Code Editor +# AISE AI Agent — Code Editor & Coding Assistant -AI-Supported Lightweight Code Editor built with Streamlit (AISE501 Spring 2026) +Ein browserbasierter Code-Editor mit integriertem AI-Chat und autonomem Coding-Agent, gebaut mit Streamlit und dem Model Context Protocol (MCP). -## Project Structure +--- + +## Installation & Setup + +**Voraussetzungen:** Python 3.13+, pip + +```bash +# 1. Repository klonen und ins Verzeichnis wechseln +cd AISE_AIAgent + +# 2. Virtuelle Umgebung erstellen und aktivieren +python -m venv .venv +.venv\Scripts\activate # Windows +# source .venv/bin/activate # macOS/Linux + +# 3. Abhängigkeiten installieren +pip install -r requirements.txt + +# 4. Umgebungsvariablen konfigurieren +copy .env.example .env +# .env öffnen und HOST, PORT, API_KEY, MODEL eintragen +``` + +**`.env` Konfiguration:** +``` +HOST=silicon.fhgr.ch +PORT=7080 +API_KEY=EMPTY +MODEL=qwen3.5-35b-a3b +``` + +--- + +## Starten + +```bash +# Streamlit App (Hauptinterface) +streamlit run frontend/app.py + +# Coding Agent direkt im Terminal testen +python run_agent.py +``` + +--- + +## Projektstruktur ``` AISE_AIAgent/ -├── frontend/ # Streamlit UI Components -│ ├── __init__.py -│ ├── app.py # Main Streamlit application entry point -│ ├── sidebar.py # File navigation sidebar component -│ ├── editor.py # Code editor pane component -│ └── chat.py # Chat interface component -│ -├── backend/ # Backend Logic Modules -│ ├── __init__.py -│ ├── managers/ # Business logic for UI operations -│ │ ├── __init__.py -│ │ ├── file_manager.py # File I/O operations for UI (read, write, list files) -│ │ ├── chat_manager.py # AI chat management and history -│ │ ├── system_prompter.py # System prompts and context injection -│ │ ├── search_manager.py # Internet search functionality -│ │ ├── execution_engine.py # Code execution and sandboxing -│ │ └── debug_logger.py # Logging, error handling, debug messages -│ │ -│ ├── agents/ # AI Agent System -│ │ ├── __init__.py -│ │ ├── coding_agent.py # Main agent loop (plan-act-observe cycle) -│ │ └── tools.py # Tools available to agent (7 functions + dispatcher) -│ │ -│ └── utils/ # Helper Utilities -│ ├── __init__.py -│ └── server_utils.py # LLM client init, chat functions, formatters -│ -├── tests/ # Unit Tests -│ ├── __init__.py -│ ├── test_file_manager.py # Tests for file operations -│ ├── test_chat_manager.py # Tests for chat functionality -│ ├── test_execution_engine.py # Tests for code execution -│ └── test_main.py # Integration tests -│ -├── workspace/ # Agent Sandbox Directory -│ └── .gitkeep # Placeholder for agent to work safely in isolation -│ -├── .gitignore # Git exclusions (venv, .env, __pycache__, etc.) -├── .env # Local environment variables (NOT committed) -├── .env.example # Template for environment variables (IS committed) -├── requirements.txt # Python dependencies -├── README.md # This file -└── project_exercise.pdf # Project specification +├── frontend/ # Streamlit UI +├── backend/ +│ ├── agent/ # Coding Agent + MCP-Adapter +│ │ └── servers/ # MCP-Server (Tools für den Agent) +│ └── managers/ # Business-Logik (Chat, Dateien, Ausführung) +├── workspace/ # Arbeitsverzeichnis des Agents & Editors +└── run_agent.py # CLI-Test für den Coding Agent ``` -## Component Responsibilities +--- -### Frontend (`frontend/`) -- **app.py**: Main Streamlit application, layout orchestration -- **sidebar.py**: File browser and project navigation -- **editor.py**: Code editing interface with syntax highlighting -- **chat.py**: AI assistant chat interface +## Frontend -### Backend Managers (`backend/managers/`) -Used directly by Frontend for UI operations: -- **file_manager.py**: CRUD operations on project files -- **chat_manager.py**: Chat history, message management -- **system_prompter.py**: System prompt generation and file context -- **execution_engine.py**: Safe code execution with output capture -- **debug_logger.py**: Error tracking and log formatting -- **search_manager.py**: Web search integration +### `frontend/app.py` — Einstiegspunkt +Initialisiert die Streamlit-App, setzt das Layout und routet zwischen Code-Editor und Chat-Ansicht basierend auf der Sidebar-Navigation. -### Backend Agents (`backend/agents/`) -Independent AI agent system for complex tasks: -- **coding_agent.py**: Agent loop (Plan → Act → Observe → Repeat) -- **tools.py**: 7 tools agent can use (read/write/run/search/validate/grep/done) +### `frontend/state.py` — Session State +Initialisiert alle Streamlit `session_state`-Variablen beim App-Start (offene Dateien, Chat-Verlauf, Agent-Status etc.). Verhindert `KeyError` beim ersten Laden. -### Backend Utils (`backend/utils/`) -- **server_utils.py**: LLM client initialization, chat helpers, message formatters +### `frontend/sidebar.py` — Sidebar & File Explorer +- **Navigation:** Radio-Button zum Wechseln zwischen "Code Editor" und "Chat with AI Assistant" +- **File Tree:** Interaktiver Dateibaum (via `streamlit-arborist`) zeigt den `workspace/`-Ordner +- **Datei-Aktionen:** Datei öffnen, umbenennen, löschen +- **Ordner-Aktionen:** Ordner erstellen, Dateien in Ordner hinzufügen, Ordner löschen -### Workspace (`workspace/`) -- Sandbox directory where agent executes and stores files -- Prevents agent from accessing files outside this directory +### `frontend/editor.py` — Code-Editor +- **Ace Editor:** Syntax-Highlighting für Python, JS, HTML, CSS, JSON, YAML, LaTeX u.a. +- **Tabs:** Mehrere Dateien gleichzeitig offen, Tab-Wechsel per Klick +- **Datei-Operationen:** Speichern, Schliessen, Umbenennen, Löschen direkt im Tab +- **Code ausführen:** Button "▶ Run Code" führt die aktive Datei aus, Output wird darunter angezeigt +- **Debug with AI:** Bei Fehlern erscheint ein Button der den Fehler + Code automatisch an den AI-Chat weiterleitet -## Features +### `frontend/chat.py` — Chat & Agent Mode -- **File Display & Management**: Browse and edit code files -- **Chat Interface**: AI-powered code assistant -- **Code Execution**: Run Python code with debugging -- **Internet Search**: Fetch documentation and examples -- **System Prompts**: Context-aware AI interactions +**Normaler Chat (`render_normal_chat`):** +- Multi-Turn Konversation mit dem konfigurierten LLM +- Injiziert die aktuell offene Datei automatisch als Kontext in den System-Prompt +- Einstellungen: Modell wählen, Max Tokens, eigener System-Prompt +- "Clear Chat" mit Bestätigungsdialog -## Setup +**Agent Mode (`render_agent_mode`):** +- Autonomer Coding-Agent im Step-by-Step Modus +- Benutzer gibt eine Aufgabe ein, der Agent schlägt Aktionen vor +- Jede Aktion muss einzeln **genehmigt (Approve)** oder **abgelehnt (Reject)** werden +- **Agent Log:** Zeigt alle ausgeführten Schritte mit Tool, Gedanken und Resultat +- **Follow-up:** Nach Abschluss einer Aufgabe können Korrekturen eingegeben werden -### 1. Project Clonen +--- -1. In den Zielordner wechseln -cd /pfad/zum/zielordner +## Backend — Managers -2. Repository klonen -git clone https://gitea.fhgr.ch/meulilivio/AISE1_Project.git +### `backend/managers/chat_manager.py` — ChatManager +Verwaltet den Konversationsverlauf und kommuniziert mit dem LLM über eine OpenAI-kompatible REST-API. Sendet bei jedem Request den gesamten Verlauf als Kontext mit. -3. In das Projekt wechseln -cd AISE1_Project +| Methode | Beschreibung | +|---|---| +| `send_message(user_message)` | Nachricht senden, Antwort zurückgeben, History updaten | +| `add_message(role, content)` | Nachricht manuell zur History hinzufügen | +| `clear_history()` | Gesamten Chat-Verlauf löschen | +| `get_history()` | Kopie des aktuellen Verlaufs zurückgeben | -### 2. Activate Virtual Environment +### `backend/managers/file_manager.py` — FileManager +Alle Datei- und Ordneroperationen innerhalb des `workspace/`-Verzeichnisses. Jede Operation validiert den Pfad gegen Path-Traversal-Angriffe. + +| Methode | Beschreibung | +|---|---| +| `create_file(relative_path, name)` | Neue Datei im Workspace erstellen | +| `create_folder(relative_path, name)` | Neuen Ordner erstellen | +| `read_file(path)` | Dateiinhalt lesen | +| `save_file(path, content)` | Datei speichern/überschreiben | +| `rename_file(old_path, new_name)` | Datei umbenennen (Extension bleibt erhalten) | +| `delete_file(relative_path)` | Datei löschen | +| `delete_folder(relative_path)` | Ordner inkl. Inhalt löschen | +| `get_file_tree()` | Verschachteltes Dict des gesamten Workspace-Baums | + +### `backend/managers/execution_engine.py` — ExecutionEngine +Führt Dateien aus dem Editor in einem Subprocess aus. Unterstützt Python (`.py`) und LaTeX (`.tex`). Timeout: 30 Sekunden. + +| Methode | Beschreibung | +|---|---| +| `run_code(active_file)` | Datei ausführen, gibt `{stdout, stderr, rc}` zurück | + +### `backend/managers/system_prompter.py` — SystemPrompter +Generiert den System-Prompt für den AI-Chat. Wenn eine Datei im Editor offen ist, wird ihr Inhalt (max. 4000 Zeichen) automatisch eingebettet. + +| Methode | Beschreibung | +|---|---| +| `generate_prompt(file_context)` | System-Prompt mit optionalem Datei-Kontext bauen | + +### `backend/managers/debug_logger.py` — DebugLogger +Einfacher In-Memory-Logger für den Code-Editor (Ausführungsstatus, Fehler). + +--- + +## Backend — Coding Agent + +### `backend/agent/coding_agent.py` — CodingAgent +Autonomer Agent nach dem **Plan → Act → Observe → Fix → Done** Loop. Kommuniziert mit dem LLM und ruft MCP-Tools über den Adapter auf. + +| Methode | Beschreibung | +|---|---| +| `start_task(task)` | Neue Aufgabe initialisieren, State zurücksetzen | +| `propose_next_action()` | LLM fragen was als nächstes zu tun ist (führt nichts aus) | +| `approve()` | Vorgeschlagene Aktion ausführen, nächsten Schritt vorschlagen | +| `reject(feedback)` | Aktion ablehnen, Feedback injizieren, Agent plant neu | +| `follow_up(question)` | Folgefrage nach abgeschlossener Aufgabe stellen | + +**Hilfsfunktionen:** +- `dispatch_tool(tool_name, arguments)` — Leitet Tool-Aufrufe an den MCP-Adapter weiter +- `build_all_tool_description()` — Generiert die Tool-Beschreibung für den System-Prompt +- `extract_json(text)` / `_repair_json_strings(text)` — Parst und repariert LLM-JSON-Antworten +- `trim_messages(messages)` — Kürzt alte History wenn Kontextfenster voll wird + +### `backend/agent/mcp_server_adapter.py` — MCPToolAdapter +Verbindet den Coding Agent mit den MCP-Servern. Liest die Konfiguration aus `mcp_server_config.json`, registriert alle verfügbaren Tools und startet bei jedem Tool-Aufruf eine frische stdio-Verbindung zum zuständigen Server. + +| Methode | Beschreibung | +|---|---| +| `initialize_all_servers()` | Alle Server verbinden und Tools registrieren | +| `call_tool(tool_name, arguments)` | Tool auf dem zuständigen Server aufrufen | +| `get_all_tools()` | Liste aller registrierten Tools zurückgeben | + +--- + +## MCP-Server (Tools für den Agent) + +Alle Server laufen als eigenständige Prozesse und kommunizieren über `stdio`. + +### `backend/agent/servers/mcp_server_code_execution.py` — CodeExecutionServer + +| Tool | Beschreibung | +|---|---| +| `run_python_sandboxed(code)` | Python-Code sicher ausführen (statische Analyse + Subprocess mit isoliertem stdin) | +| `python_code_validation(code)` | Syntax und Sicherheit prüfen ohne auszuführen | +| `lint_code(code)` | Statische Analyse mit pyflakes (ungenutzte Imports, undefinierte Variablen) | +| `analyse_structure(code)` | Struktur-Zusammenfassung (Klassen, Funktionen, Imports) | + +**Sicherheitsmechanismen:** Blockierte Imports (`os`, `sys`, `subprocess` etc.), blockierte Builtins (`exec`, `eval`, `open` etc.), verbotene Pfadsequenzen, Timeout nach 45 Sekunden. + +### `backend/agent/servers/mcp_server_file_search.py` — FileSearchServer + +| Tool | Beschreibung | +|---|---| +| `list_files()` | Alle Dateien im Workspace auflisten | +| `get_file_tree(dir_path)` | Verzeichnisbaum anzeigen | +| `search_files(query)` | Dateien nach Name oder Inhalt durchsuchen | +| `read_file(path)` | Dateiinhalt lesen | +| `write_new_file(path, content)` | Neue Datei erstellen (keine Überschreibung bestehender Dateien) | +| `create_new_directory(path)` | Neues Verzeichnis erstellen | + +Alle Zugriffe sind auf den `workspace/`-Ordner beschränkt (Path-Traversal-Schutz). + +### `backend/agent/servers/mcp_server_web_search.py` — WebSearchServer + +| Tool | Beschreibung | +|---|---| +| `web_search(query, max_results)` | DuckDuckGo-Suche, gibt formatierte Ergebnisse zurück | +| `fetch_page(url)` | Webseite abrufen und Text extrahieren (max. 4000 Zeichen) | + +SSRF-Schutz: Blockiert `localhost`, private IP-Ranges und nicht-HTTP/HTTPS-Schemata. + +--- + +## CLI-Test + +`run_agent.py` ermöglicht den Coding Agent direkt im Terminal zu testen ohne die Streamlit-App zu starten: ```bash -# Windows -.\.venv\Scripts\Activate.ps1 - -# macOS/Linux -source .venv/bin/activate -``` - -### 3. Install Dependencies - -```bash -pip install -r requirements.txt -``` - -### 4. Run Application - -```bash -streamlit run frontend/app.py -``` - -### 5. Run Tests - -```bash -pytest tests/ -``` - -## Architecture - -The application follows a frontend-backend split: - -- **Frontend**: Streamlit UI components (sidebar, editor, chat) -- **Backend**: Specialized manager modules - - FileManager: File operations - - ChatManager: AI interaction - - SystemPrompter: Prompt management - - SearchManager: Internet search - - ExecutionEngine: Code execution - - DebugLogger: Error handling & logging - -## Development - -Use Git to track changes: - -```bash -git add . -git commit -m "Your message" -git push origin sturcture +python run_agent.py +# Aufgabe eingeben → Enter zum Genehmigen, Text zum Ablehnen, "stop" zum Abbrechen ``` diff --git a/READMEnew.md b/READMEnew.md new file mode 100644 index 0000000..080690f --- /dev/null +++ b/READMEnew.md @@ -0,0 +1,381 @@ +# AISE AI Agent — Code Editor & Coding Assistant + +Ein browserbasierter Code-Editor mit integriertem AI-Chat und autonomem Coding-Agent. Das Projekt kombiniert eine Streamlit-Oberfläche mit einem LLM-Backend und dem Model Context Protocol (MCP), um einen vollständigen AI-gestützten Entwicklungsworkflow zu ermöglichen. + +--- + +## Was kann das Projekt? + +- **Code schreiben und bearbeiten** im Browser mit Syntax-Highlighting (Ace Editor) +- **Code direkt ausführen** und Output anzeigen, ohne die App zu verlassen +- **Mit einem AI-Assistenten chatten**, der den aktuell geöffneten Code als Kontext kennt +- **Fehler mit AI debuggen** — ein Klick schickt den Fehler + Code automatisch an den Chat +- **Einen autonomen Coding-Agent starten**, der selbstständig Aufgaben plant und umsetzt (Dateien lesen/schreiben, Code ausführen, im Web suchen) — jeder Schritt wird dem Benutzer zur Genehmigung vorgelegt + +--- + +## Voraussetzungen + +- Python 3.13 oder neuer +- pip +- Zugang zu einem OpenAI-kompatiblen LLM-Endpoint (z.B. FHGR Silicon Server) + +--- + +## Installation + +```bash +# 1. Repository klonen +git clone +cd AISE_AIAgent + +# 2. Virtuelle Umgebung erstellen und aktivieren +python -m venv .venv + +# Windows: +.venv\Scripts\activate +# macOS / Linux: +source .venv/bin/activate + +# 3. Abhängigkeiten installieren +pip install -r requirements.txt + +# 4. Umgebungsvariablen konfigurieren +copy .env.example .env # Windows +# cp .env.example .env # macOS/Linux +``` + +Dann `.env` öffnen und die Werte anpassen: + +```env +HOST=silicon.fhgr.ch # Hostname des LLM-Servers +PORT=7080 # Port des LLM-Servers +API_KEY=EMPTY # API-Key (EMPTY wenn kein Key benötigt) +MODEL=qwen3.5-35b-a3b # Modell-Name +``` + +--- + +## Starten + +```bash +# Streamlit Web-App starten (Hauptinterface) +streamlit run frontend/app.py + +# Coding Agent im Terminal testen (ohne Streamlit) +python run_agent.py +``` + +Nach `streamlit run frontend/app.py` öffnet sich die App automatisch im Browser unter `http://localhost:8501`. + +--- + +## Projektstruktur + +``` +AISE_AIAgent/ +│ +├── frontend/ # Gesamte Streamlit-Benutzeroberfläche +│ ├── app.py # Einstiegspunkt, App-Routing +│ ├── state.py # Session-State Initialisierung +│ ├── sidebar.py # Navigation + File Explorer +│ ├── editor.py # Code-Editor Ansicht +│ └── chat.py # Chat + Agent Mode Ansicht +│ +├── backend/ +│ ├── agent/ # Coding Agent Logik +│ │ ├── coding_agent.py # Agent Klasse (Plan→Act→Observe Loop) +│ │ ├── mcp_server_adapter.py # MCP-Client (verbindet Agent mit Servern) +│ │ ├── mcp_server_adapter_RAG.py +│ │ ├── mcp_server_config.json +│ │ └── servers/ # MCP-Server (laufen als eigene Prozesse) +│ │ ├── mcp_server_code_execution.py +│ │ ├── mcp_server_file_search.py +│ │ └── mcp_server_web_search.py +│ │ +│ └── managers/ # Business-Logik Module +│ ├── chat_manager.py # LLM-API Kommunikation + Chat-History +│ ├── file_manager.py # Datei/Ordner-Operationen im Workspace +│ ├── execution_engine.py # Code-Ausführung via Subprocess +│ ├── system_prompter.py # System-Prompt Generierung +│ └── debug_logger.py # Einfacher In-Memory Logger +│ └── search_manager.py # Einfacher In-Memory Such-Manager +├── tests/ +| ├── conftest.py +| ├── test_file_manager.py # Unit-Tests für FileManager +| ├── test_chat_manager.py # Unit-Tests für ChatManager +| ├── test_execution_engine.py # Unit-Tests für ExecutionEngine +| ├── test_coding_agent.py # Unit-Tests für CodingAgent +| ├── test_search_manager.py # Unit-Tests für SearchManager +| ├── test_debug_logger.py # Unit-Tests für DebugLogger +| ├── test_mcp_server_code_execution.py +| ├── test_mcp_server_web_search.py +| ├── test_system_prompter.py +| └── test_mcp_server_file_search.py +| +├── workspace/ # Arbeitsverzeichnis (Dateien des Editors/Agents) +└── .env.example # Vorlage für Umgebungsvariablen +``` + +--- + +## Frontend + +### `frontend/app.py` — Einstiegspunkt der App + +Dieser File ist der Startpunkt der gesamten Streamlit-Applikation. Er wird direkt mit `streamlit run` aufgerufen und übernimmt drei Aufgaben: Er setzt das globale Seitenlayout (Titel, breites Layout, minimales CSS-Padding), ruft `init_state()` auf um alle Session-State-Variablen zu initialisieren, und leitet den Benutzer basierend auf der Sidebar-Auswahl entweder zur Editor-Ansicht oder zur Chat-Ansicht weiter. + +--- + +### `frontend/state.py` — Session State Verwaltung + +Streamlit rendert die gesamte App bei jeder Benutzerinteraktion neu. Um Daten zwischen diesen Reruns zu erhalten (offene Dateien, Chat-Verlauf, Agent-Status etc.), nutzt Streamlit `session_state`. Dieser File definiert und initialisiert alle verwendeten Keys mit ihren Standardwerten an einem zentralen Ort — damit kein anderer Teil der App auf einen nicht-existierenden Key trifft. + +**Wichtige State-Keys:** +- `open_files` — Liste aller aktuell geöffneten Dateipfade (bestimmt die Tab-Reihenfolge) +- `files_content` — Dict `{Dateipfad: aktueller Editorinhalt}` (ungespeicherte Änderungen inklusive) +- `active_file` — Absoluter Pfad der aktuell aktiven Datei +- `chat_history` — Flache Liste aller Chat-Nachrichten `[{role, content}, ...]` +- `agent_mode` — Boolean ob der Agent Mode aktiv ist +- `agent_status` — Aktueller Agent-Zustand: `"idle"` | `"waiting_approval"` | `"done"` +- `agent_log` — Liste aller abgeschlossenen Agent-Schritte +- `agent_pending_action` — Die vom Agent vorgeschlagene, noch nicht ausgeführte Aktion + +--- + +### `frontend/sidebar.py` — Navigation & File Explorer + +Die Sidebar ist in zwei Bereiche aufgeteilt: + +**Navigation:** Ein Radio-Button schaltet zwischen "Code Editor" und "Chat with AI Assistant" um. Die aktuelle Auswahl wird in `session_state.radio_interface_options` gespeichert und von `app.py` ausgewertet. + +**File Explorer:** Ein interaktiver Dateibaum zeigt den gesamten `workspace/`-Ordner an. Implementiert mit `streamlit-arborist`, das einen klickbaren Baum mit Ordner-Icons rendert. Ein Klick auf eine Datei öffnet sie im Editor und wechselt automatisch zur Editor-Ansicht. Ein Klick auf einen Ordner zeigt eine Aktionsleiste mit Buttons zum Erstellen von Dateien/Unterordnern und zum Löschen des Ordners. + +**Modale Dialoge** (via `@st.dialog`): +- `_add_file_dialog` — Neuen Dateinamen eingeben und Datei erstellen +- `_add_folder_dialog` — Neuen Ordnernamen eingeben und Ordner erstellen +- `_rename_file_dialog` — Datei umbenennen (Extension wird automatisch beibehalten) +- `_delete_file_dialog` — Löschbestätigung für Dateien +- `_delete_folder_dialog` — Löschbestätigung für Ordner inkl. Inhalt + +--- + +### `frontend/editor.py` — Code-Editor + +Der Code-Editor ist die zentrale Arbeitsfläche für das direkte Bearbeiten von Dateien. + +**Ace Editor (`streamlit-ace`):** Jede offene Datei wird in einem Tab mit dem Ace-Editor angezeigt. Der Editor erkennt die Dateiendung automatisch und stellt das passende Syntax-Highlighting ein (Python, JavaScript, HTML, CSS, JSON, YAML, LaTeX, Bash). Das Theme ist "Monokai". `auto_update=True` bedeutet, dass Änderungen sofort in `session_state.files_content` landen — ohne expliziten Submit. + +**Tab-Verwaltung:** Jede offene Datei erscheint als Tab. Wenn eine Datei aus dem File Explorer geöffnet wird, springt ein JavaScript-Snippet automatisch auf den richtigen Tab (da `st.tabs` keinen programmatischen Tab-Wechsel unterstützt). + +**Aktions-Buttons pro Datei:** +- **Save Changes** — Schreibt den aktuellen Editorinhalt auf Disk +- **Close File** — Entfernt die Datei aus den offenen Tabs +- **Rename File** — Öffnet Rename-Dialog +- **Delete File** — Öffnet Lösch-Bestätigungsdialog +- **▶ Run Code** — Führt die Datei aus (Python via `py`, LaTeX via `pdflatex`) + +**Ausführungs-Output:** Nach dem Ausführen erscheinen stdout, stderr und der Exit-Code unterhalb des Editors. Bei einem Fehler erscheint zusätzlich der Button **"🐛 Debug with AI"** — dieser baut automatisch eine Fehlernachricht zusammen (Fehlertext + kompletter Code) und schickt sie an den Chat-Assistenten. + +--- + +### `frontend/chat.py` — Chat & Agent Mode + +Dieser File enthält zwei grundlegend verschiedene Interfaces, die über einen Toggle umgeschaltet werden. + +#### Normaler Chat + +Ein klassischer Multi-Turn-Chatbot. Bei der ersten Nachricht wird automatisch ein System-Prompt generiert. Falls eine Datei im Editor geöffnet ist und "Include current file as context" aktiviert ist, wird der Dateiinhalt in den System-Prompt eingebettet — der AI-Assistent "sieht" also den Code und kann gezielt darauf eingehen. + +Bei jeder Folgenachricht wird der System-Prompt aktualisiert falls eine andere Datei aktiv ist. Das Modell, die maximale Tokenzahl und ein eigener System-Prompt können in einem aufklappbaren Settings-Panel konfiguriert werden. Der "Clear Chat" Button öffnet einen Bestätigungsdialog. + +#### Agent Mode + +Der Agent Mode verwandelt den Chat in ein Step-by-Step Kontrollinterface für den autonomen `CodingAgent`. + +**Ablauf:** +1. Benutzer gibt eine Aufgabe ein (z.B. "Schreibe eine Funktion die eine Liste sortiert und speichere sie als sorted.py") +2. Der Agent analysiert die Aufgabe und schlägt einen ersten Schritt vor (z.B. `write_new_file` mit dem generierten Code) +3. Die UI zeigt den Gedankengang des Agents ("Thought"), das gewählte Tool und die Argumente an +4. Benutzer klickt **Approve** → Aktion wird ausgeführt, nächster Schritt wird vorgeschlagen +5. Oder **Reject** → Benutzer gibt Feedback ein, Agent plant neu ohne die Aktion auszuführen +6. Oder **Abort Task** → Agent wird sofort gestoppt +7. Nach Abschluss kann eine Follow-up Frage gestellt werden ohne den Kontext zu verlieren + +Der **Agent Log** zeigt alle abgeschlossenen Schritte in einem aufklappbaren Bereich. + +--- + +## Backend — Managers + +### `backend/managers/chat_manager.py` — ChatManager + +Kapselt die gesamte Kommunikation mit dem LLM. Verbindet sich mit einem OpenAI-kompatiblen REST-Endpoint (`/v1/chat/completions`) dessen Adresse und Key aus der `.env` gelesen werden. + +Der Chat-Verlauf wird als Liste von `{role, content}`-Dicts in-memory gehalten. Bei jedem `send_message`-Aufruf wird die vollständige History mitgeschickt, sodass das Modell immer den gesamten Gesprächskontext kennt. + +| Methode | Beschreibung | +|---|---| +| `send_message(user_message)` | Nachricht zur History hinzufügen, API-Call machen, Antwort zurückgeben und in History speichern | +| `add_message(role, content)` | Nachricht direkt zur History hinzufügen (z.B. für System-Prompt) | +| `get_history()` | Kopie der aktuellen History zurückgeben | +| `clear_history()` | Gesamten Verlauf löschen (neuer Chat) | + +--- + +### `backend/managers/file_manager.py` — FileManager + +Abstrahiert alle Dateioperationen und stellt sicher, dass jeder Zugriff innerhalb des `workspace/`-Verzeichnisses bleibt. Jede Methode löst den angegebenen Pfad zu einem absoluten Pfad auf und prüft mit `startswith(workspace.resolve())` ob der Pfad im erlaubten Bereich liegt — damit sind Path-Traversal-Angriffe wie `../../etc/passwd` ausgeschlossen. + +| Methode | Beschreibung | +|---|---| +| `create_file(relative_path, name)` | Neue leere Datei erstellen. Ohne Extension wird `.txt` ergänzt. Schlägt fehl wenn Datei existiert. | +| `create_folder(relative_path, name)` | Neuen Ordner erstellen. Schlägt fehl wenn Ordner existiert. | +| `read_file(path)` | Dateiinhalt als String lesen. Gibt leeren String bei Fehler zurück. | +| `save_file(path, content)` | Datei mit neuem Inhalt überschreiben (erstellt falls nicht vorhanden). | +| `rename_file(old_path, new_name)` | Datei umbenennen. Die Dateiendung wird immer vom Original übernommen. | +| `delete_file(relative_path)` | Einzelne Datei löschen. | +| `delete_folder(relative_path)` | Ordner und gesamten Inhalt rekursiv löschen. | +| `get_file_tree()` | Gesamten Workspace als verschachteltes Dict zurückgeben: Ordner als `{name: dict}`, Dateien als `{name: None}`. | + +--- + +### `backend/managers/execution_engine.py` — ExecutionEngine + +Führt Dateien aus dem Editor als Subprocess aus. Die Datei wird immer aus ihrem eigenen Verzeichnis heraus gestartet (`cwd=file.parent`), damit relative Imports und Pfade korrekt funktionieren. + +Unterstützte Dateitypen: +- **Python (`.py`)** → `py ` (nutzt den Windows Python Launcher) +- **LaTeX (`.tex`)** → `pdflatex -interaction=nonstopmode ` + +Timeout: 30 Sekunden. Gibt immer ein Dict `{stdout, stderr, rc}` zurück. + +--- + +### `backend/managers/system_prompter.py` — SystemPrompter + +Baut den System-Prompt für den normalen Chat zusammen. Ohne Datei-Kontext enthält er nur eine allgemeine Beschreibung des AI-Assistenten. Mit Datei-Kontext wird der Dateiname und der Inhalt (max. 4000 Zeichen, danach abgeschnitten) in XML-ähnliche Tags eingebettet: + +``` + + +def fib(n): ... + + +``` + +Das Modell wird angewiesen sich auf diese Datei zu beziehen wenn es Fragen zum Code beantwortet. + +--- + +### `backend/managers/debug_logger.py` — DebugLogger + +Einfacher In-Memory-Logger der Ausführungsmeldungen für den Code-Editor speichert. Wird von `editor.py` genutzt um den Status einer Code-Ausführung (`log()`, `log_error()`, `clear()`) zu protokollieren. + +--- + +## Backend — Coding Agent + +### `backend/agent/coding_agent.py` — CodingAgent + +Das Herzstück des autonomen Agents. Implementiert den **Plan → Act → Observe → Fix → Done** Loop. + +**Wie der Loop funktioniert:** +1. `start_task(task)` initialisiert den Agenten mit dem System-Prompt (enthält Beschreibungen aller verfügbaren MCP-Tools) und der Aufgabe +2. `propose_next_action()` schickt den bisherigen Konversationsverlauf an das LLM. Das Modell antwortet immer mit einem JSON-Objekt `{"thought": "...", "tool": "...", "arguments": {...}}`. Die Antwort wird geparsed und als `pending_action` gespeichert — aber **noch nicht ausgeführt** +3. `approve()` führt die pending_action aus, fügt das Resultat als User-Nachricht zur History hinzu und ruft sofort `propose_next_action()` auf +4. `reject(feedback)` verwirft die pending_action ohne sie auszuführen und injiziert das Feedback als User-Nachricht +5. Wenn das LLM `"done"` als Tool wählt, setzt der Agent `is_done = True` + +**Robustheit:** LLM-Antworten die kein valides JSON enthalten werden durch `extract_json()` und `_repair_json_strings()` bereinigt (entfernt Markdown-Fences, repariert unescapte Newlines in Strings). Wenn die History das Limit von 80'000 Zeichen überschreitet, werden ältere Nachrichten entfernt und ein Erinnerungs-Hinweis injiziert. + +| Methode | Beschreibung | +|---|---| +| `start_task(task)` | Agent neu initialisieren, System-Prompt + Aufgabe setzen | +| `propose_next_action()` | LLM-Aufruf → JSON-Antwort parsen → als `pending_action` speichern | +| `approve()` | `pending_action` ausführen, Resultat zur History hinzufügen, nächste Aktion vorschlagen | +| `reject(feedback)` | `pending_action` verwerfen, Feedback injizieren | +| `follow_up(question)` | Nach Abschluss: Folgefrage stellen ohne Kontext zu verlieren | + +--- + +### `backend/agent/mcp_server_adapter.py` — MCPToolAdapter + +Der Adapter ist die Brücke zwischen dem `CodingAgent` und den MCP-Servern. Er liest beim Start die Konfigurationsdatei `mcp_server_config.json`, verbindet sich zu jedem Server, fragt dessen Tool-Liste ab und speichert alle Tools in einer internen Registry. + +Bei jedem `call_tool`-Aufruf öffnet der Adapter eine neue `stdio`-Verbindung zum zuständigen Server, führt das Tool aus und schliesst die Verbindung wieder. Das heisst: Die Server laufen nicht permanent, sondern werden für jeden Aufruf frisch gestartet. Das macht das System robuster (kein veralteter State in einem Server) aber etwas langsamer. + +| Methode | Beschreibung | +|---|---| +| `initialize_all_servers()` | Alle konfigurierten Server starten, Tool-Liste abfragen, in Registry speichern | +| `call_tool(tool_name, arguments)` | Passenden Server für das Tool finden, Verbindung aufbauen, Tool aufrufen, Ergebnis zurückgeben | +| `get_all_tools()` | Komplette Tool-Registry zurückgeben | + +--- + +## MCP-Server + +Die drei MCP-Server sind eigenständige Python-Prozesse die über das `stdio`-Transportprotokoll kommunizieren. Sie werden vom Adapter gestartet und stellen dem Coding Agent Tools zur Verfügung. + +--- + +### `backend/agent/servers/mcp_server_code_execution.py` — CodeExecutionServer + +Ermöglicht dem Agent das sichere Ausführen von Python-Code. Bevor Code ausgeführt wird, durchläuft er eine **zweistufige Sicherheitsprüfung**: + +1. **Statische AST-Analyse** (`check_code_safety`): Der Code wird mit Pythons `ast`-Modul geparst. Jeder Import-Node und jeder Funktionsaufruf wird gegen Blocklisten geprüft. Blockierte Imports umfassen u.a. `os`, `sys`, `subprocess`, `socket`, `pickle`. Blockierte Builtins umfassen `exec`, `eval`, `open`, `compile`. + +2. **String-Suche nach verbotenen Sequenzen**: Zusätzlich wird der Code-String direkt nach gefährlichen Mustern durchsucht (`../`, `os.`, `sys.`, `subprocess.` etc.). + +Erst wenn beide Prüfungen bestanden sind, wird der Code via `subprocess.run([sys.executable, "-c", code], stdin=subprocess.DEVNULL, ...)` ausgeführt. `stdin=subprocess.DEVNULL` ist entscheidend: Da der MCP-Server über asyncio-verwaltetes `stdio` läuft, würde der Kind-Prozess sonst stdin erben und blockieren. + +| Tool | Beschreibung | +|---|---| +| `run_python_sandboxed(code)` | Code nach Sicherheitsprüfung ausführen. Gibt stdout+stderr zurück (max. 3000 Zeichen). Timeout: 45s. | +| `python_code_validation(code)` | Nur prüfen (Syntax + Sicherheit), nicht ausführen. | +| `lint_code(code)` | Pyflakes-Analyse: ungenutzte Imports, undefinierte Variablen, Syntax-Fehler. | +| `analyse_structure(code)` | Imports, Klassen (mit Methoden) und Top-Level-Funktionen als strukturierte Zusammenfassung. | + +--- + +### `backend/agent/servers/mcp_server_file_search.py` — FileSearchServer + +Gibt dem Agent Lese- und Schreibzugriff auf den `workspace/`-Ordner. Alle Pfade werden über `_safe_path()` gegen Path-Traversal validiert — ein Zugriff ausserhalb des Workspace ist nicht möglich. + +| Tool | Beschreibung | +|---|---| +| `list_files()` | Alle Dateien im Workspace rekursiv auflisten (ohne `__pycache__`). | +| `get_file_tree(dir_path)` | Verzeichnisstruktur als formatierter Text (ähnlich `tree`-Befehl). | +| `search_files(query)` | Dateien deren Name oder Inhalt den Suchbegriff enthält (case-insensitive). | +| `read_file(path)` | Vollständigen Inhalt einer Datei lesen. | +| `write_new_file(path, content)` | Neue Datei erstellen und Inhalt schreiben. Bestehende Dateien können **nicht** überschrieben werden. | +| `create_new_directory(path)` | Neues Verzeichnis im Workspace erstellen. | + +--- + +### `backend/agent/servers/mcp_server_web_search.py` — WebSearchServer + +Gibt dem Agent Zugriff auf das Internet. Enthält einen SSRF-Schutz der verhindert, dass der Agent interne Adressen abruft. + +**SSRF-Schutz** (`_validate_url`): Nur `http://` und `https://`-URLs sind erlaubt. Hostnamen wie `localhost`, `127.0.0.1`, `0.0.0.0`, `169.254.169.254` (AWS Metadata) sowie alle privaten IP-Ranges (`10.x`, `172.16-31.x`, `192.168.x`) sind blockiert. + +| Tool | Beschreibung | +|---|---| +| `web_search(query, max_results)` | DuckDuckGo-Suche. Gibt Titel, URL und Snippet für jedes Ergebnis zurück (Standard: 5 Ergebnisse). | +| `fetch_page(url)` | URL abrufen, HTML parsen, Fliesstext extrahieren (max. 4000 Zeichen). | + +--- + +## CLI-Test mit `run_agent.py` + +Für schnelles Testen des Coding Agents ohne die Streamlit-App: + +```bash +python run_agent.py +``` + +Das Script startet eine interaktive Konsolen-Session: +- **Aufgabe eingeben** → Agent startet +- **Enter drücken** → Vorgeschlagene Aktion genehmigen und ausführen +- **Text eingeben + Enter** → Feedback geben, Agent plant neu +- **`stop` eingeben** → Abbrechen diff --git a/run_agent.py b/run_agent.py deleted file mode 100644 index 4e5e26e..0000000 --- a/run_agent.py +++ /dev/null @@ -1,78 +0,0 @@ -""" -Temporäres Test-Script für den CodingAgent – kann danach gelöscht werden. - -Ausführen: - python run_agent.py - -Steuerung: - Enter → Aktion ausführen (approve) - Text + Enter → Feedback geben (reject + replan) - stop → Abbrechen -""" - -import sys -from pathlib import Path - -sys.path.insert(0, str(Path(__file__).parent)) - -from backend.agent.coding_agent import CodingAgent, WORKSPACE - - -def run(): - print("\n" + "=" * 60) - print(" CodingAgent – Interaktiver Test") - print("=" * 60) - print(f" Workspace: {WORKSPACE}") - print(" [Enter] = Aktion ausführen | Text = Feedback | 'stop' = Abbruch") - print("=" * 60 + "\n") - - task = input("Aufgabe eingeben: ").strip() - if not task: - print("Keine Aufgabe eingegeben. Beende.") - return - - agent = CodingAgent() - agent.start_task(task) - print(f"\nAgent gestartet für: '{task}'\n") - - step = 0 - while not agent.is_done: - step += 1 - print(f"\n{'─' * 60}") - print(f" Schritt {step} – Agent überlegt...") - - action = agent.propose_next_action() - - print(f"\n Thought : {action.get('thought', '')}") - print(f" Tool : {action.get('tool', '')}") - print(f" Arguments: {action.get('arguments', {})}") - print() - - user_input = input(" [Enter]=ausführen | Text=Feedback | stop=Abbruch: ").strip() - - if user_input.lower() in ("stop", "abort"): - print("\nAbgebrochen.") - break - - if user_input: - agent.reject(user_input) - print(f" → Feedback injiziert. Agent plant neu.\n") - continue - - result = agent.approve() - - print(f"\n Resultat ({result['tool']}):") - print(f" {result['result'][:300]}{'...' if len(result['result']) > 300 else ''}") - - if result["is_done"]: - print("\n" + "=" * 60) - print(" FERTIG!") - print(f" {result['result']}") - print("=" * 60) - - -if __name__ == "__main__": - try: - run() - except KeyboardInterrupt: - print("\n\nUnterbrochen.")