20 KiB
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
# 1. Repository klonen
git clone <repo-url>
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:
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
# 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 Dateichat_history— Flache Liste aller Chat-Nachrichten[{role, content}, ...]agent_mode— Boolean ob der Agent Mode aktiv istagent_status— Aktueller Agent-Zustand:"idle"|"waiting_approval"|"done"agent_log— Liste aller abgeschlossenen Agent-Schritteagent_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 viapdflatex)
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:
- Benutzer gibt eine Aufgabe ein (z.B. "Schreibe eine Funktion die eine Liste sortiert und speichere sie als sorted.py")
- Der Agent analysiert die Aufgabe und schlägt einen ersten Schritt vor (z.B.
write_new_filemit dem generierten Code) - Die UI zeigt den Gedankengang des Agents ("Thought"), das gewählte Tool und die Argumente an
- Benutzer klickt Approve → Aktion wird ausgeführt, nächster Schritt wird vorgeschlagen
- Oder Reject → Benutzer gibt Feedback ein, Agent plant neu ohne die Aktion auszuführen
- Oder Abort Task → Agent wird sofort gestoppt
- 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 <dateiname>(nutzt den Windows Python Launcher) - LaTeX (
.tex) →pdflatex -interaction=nonstopmode <dateiname>
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:
<file name="fibonacci.py">
<code>
def fib(n): ...
</code>
</file>
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:
start_task(task)initialisiert den Agenten mit dem System-Prompt (enthält Beschreibungen aller verfügbaren MCP-Tools) und der Aufgabepropose_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 alspending_actiongespeichert — aber noch nicht ausgeführtapprove()führt die pending_action aus, fügt das Resultat als User-Nachricht zur History hinzu und ruft sofortpropose_next_action()aufreject(feedback)verwirft die pending_action ohne sie auszuführen und injiziert das Feedback als User-Nachricht- Wenn das LLM
"done"als Tool wählt, setzt der Agentis_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:
-
Statische AST-Analyse (
check_code_safety): Der Code wird mit Pythonsast-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 umfassenexec,eval,open,compile. -
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:
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
stopeingeben → Abbrechen