18 KiB
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.
Inhaltsverzeichnis
- Projektstruktur
- Frontend
- Backend Manager
- Backend Agent (MCP-System)
- MCP-Server-Konfiguration
- Tests
- Setup
- Architektur-Übersicht
Projektstruktur
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
│
├── 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
│ │
│ └── 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
│
├── tests/ # Unit-Tests (pytest)
│ ├── conftest.py # Globale Test-Fixtures und MCP-Mocks
│ ├── test_file_manager.py
│ ├── test_chat_manager.py
│ ├── test_execution_engine.py
│ ├── test_coding_agent.py
│ ├── test_debug_logger.py
│ ├── test_system_prompter.py
│ ├── test_mcp_server_code_execution.py
│ ├── test_mcp_server_file_search.py
│ └── test_mcp_server_web_search.py
│
├── workspace/ # Agent-Sandbox (isoliertes Arbeitsverzeichnis)
├── run_agent.py # CLI-Einstiegspunkt für den Coding-Agent
└── .env.example # Vorlage für 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 nenntlist_files()alsFileManager-Methode. Im vorliegenden Design wurde bewusstget_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-Servermcp_server_file_search.pydie 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 nenntlog_error()alsDebugLogger-Methode. Diese wurde bewusst nicht als separate Methode implementiert, da Python's eingebauteslogging-Modul diese Funktionalität mitlogger.error()bereits vollständig abdeckt. Im gesamten Projekt wird konsistentlogger = get_logger(__name__)gefolgt vonlogger.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:
- Plan: Das AI-Modell wählt das nächste Tool und Argumente
- Act: Das Tool wird via MCP-Adapter aufgerufen (nach User-Bestätigung)
- Observe: Das Ergebnis wird in die Message-History eingefügt
- Der Loop wiederholt sich bis zur Fertigstellung oder einem
done-Tool-Aufruf
Wichtige Klassen und Funktionen:
CodingAgent: Haupt-Klasse mitstart_task(),propose_next_action(),approve(),reject()truncate_result(): Kürzt lange Tool-Outputs bevor sie in die History gehentrim_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.jsonund startet die konfigurierten Server als Subprozesse - Baut MCP-Sessions via
stdio_clientauf - 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 aufget_all_tools(): Gibt alle registrierten Tool-Definitionen zurückcall_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:
- Beim Initialisieren werden alle Tool-Beschreibungen mit
SentenceTransformer('all-MiniLM-L6-v2')in Embeddings umgewandelt - Bei jedem Agent-Schritt wird der aktuelle Task als Query kodiert
- Cosine-Similarity zwischen Query- und Tool-Embeddings bestimmt die
top_krelevantesten Tools - Nur diese Tools werden dem LLM als verfügbare Aktionen präsentiert
Hauptmethoden:
initialize_all_sessions(): Startet Server, baut Sessions auf, erstellt Embedding-Indexget_relevant_tools(query, top_k=5): Gibt dietop_ksemantisch ähnlichsten Tools zurückcall_tool(tool_name, arguments): Findet den zuständigen Server und führt das Tool ausshutdown_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:
{
"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
{
"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
- Neues Server-Script in
backend/agent/servers/erstellen (MCP-konformes Python-Script) - Eintrag in
mcp_server_config.jsonergänzen:"MeinNeuerServer": { "command": "py", "args": ["servers/mcp_server_mein_tool.py"] } - Der Adapter erkennt den neuen Server beim nächsten Start automatisch und registriert seine Tools
Tests
Tests ausführen
# 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_<modulname>.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 werdenTestTrimMessages: Prüft, dass alte History-Turns entfernt werden wenn der Kontext zu gross wird; System-Message und Original-Task bleiben immer erhaltenTestStripCodeFences: Prüft, dass Markdown-Codeblöcke aus LLM-Antworten entfernt werdenTestCodingAgentInit: Prüft initialen Zustand undstart_task()-Reset-VerhaltenTestProposeNextAction: Prüft den API-Aufruf-Zyklus mit gemockter API; testet Fehler-Handling (JSON-Parse-Fehler, API-Exceptions, Max-Iterations)TestApprove: Prüftapprove()mit gemocktemdispatch_tool; testet Tool-Ergebnis-Injektion und Error-Replan-TaggingTestReject: Prüft, dassreject()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ötigtpytest-asyncio)
Setup
1. Repository klonen
git clone https://gitea.fhgr.ch/meulilivio/AISE1_Project.git
cd AISE1_Project
2. Virtuelle Umgebung aktivieren
# Windows
.\.venv\Scripts\Activate.ps1
# macOS/Linux
source .venv/bin/activate
3. Abhängigkeiten installieren
pip install -r requirements.txt
4. Umgebungsvariablen konfigurieren
cp .env.example .env
# .env mit API-Keys befüllen
5. Applikation starten
streamlit run frontend/app.py
6. Tests ausführen
pytest tests/ -v
Architektur-Übersicht
┌─────────────────────────────────────────────────────────────────┐
│ Frontend (Streamlit) │
│ app.py → sidebar.py / editor.py / chat.py │
│ │ │
│ state.py (Session-State) │
└──────────────┬──────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Backend Manager │
│ FileManager / ChatManager / SystemPrompter / │
│ SearchManager / ExecutionEngine / DebugLogger │
└──────────────┬──────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ Coding Agent (backend/agent/) │
│ coding_agent.py ←→ mcp_server_adapter.py │
│ │ │
│ mcp_server_config.json │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ ▼ ▼ ▼ │
│ mcp_server_file_search mcp_server_web mcp_server_code │
│ │
│ (Optional: mcp_server_adapter_RAG.py für semantische │
│ Tool-Auswahl via Sentence Transformers) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ workspace/ │
│ Isoliertes Sandbox-Verzeichnis für Agent-Dateien │
└─────────────────────────────────────────────────────────────────┘