ARCHITECTURE.md: - Inhaltsverzeichnis: neues Kapitel 18 (Multi-Agent Review-System) - Datenmodell: sessions-Tabelle um review_agent_id, max_review_iterations erweitert - Entity-Relationship: Review-Agent-Beziehung - ChatContext.cs Kommentar: + ReviewContext - Chat-Pipeline: Review-Phase (4b) nach end_turn mit Diagramm - SSE-Events: review_* Events - Neues Kapitel mit Architektur, Konfiguration, Backend-Flow, ReviewContext Model, SSE-Events, DB-Persistierung, Frontend ARCHITECTURE_QUICK.md: - sessions-Tabelle: ReviewAgentId, MaxReviewIterations - Chat-Pipeline: Review-Phase eingefügt - ui.js Kommentar: Review-Rendering - Neues Kapitel Multi-Agent Review-System (Kurzform)
59 KiB
ARCHITECTURE.md – Gott
Gott ist eine selbst-gehostete AI-Chat-Plattform, gebaut auf .NET 10 und der Anthropic Claude API. Sie bietet Multi-User-Support, persistente Agent-Memory, Datei-/Shell-Tools, Telegram-Integration, Cronjobs und eine Krea-Bildgenerierung – alles über ein Vanilla-JavaScript-Frontend gesteuert.
Inhaltsverzeichnis
- Überblick
- Tech-Stack
- Projektstruktur
- Datenmodell
- Backend-Architektur
- Frontend-Architektur
- Chat-Pipeline
- Tool-System
- Agent-System
- System-Prompt-Aufbau
- Memory-System
- Skill-System
- Telegram-Integration
- Cronjob-System
- Krea-Bildgenerierung
- Auth & Multi-User
- Admin-Benutzerverwaltung
- Multi-Agent Review-System
- Nachrichten teilen (Shared Messages)
- Workspace & File-Explorer
- Avatar-System
- LaTeX/Math-Rendering
- Windows Desktop App
- Deployment
- Konfiguration
- Datenbank-Migrationen
Überblick
┌─────────────────────────────────────────────────────────────┐
│ Browser / WebView2 │
│ Vanilla JS SPA (wwwroot/) │
├─────────────────────────────────────────────────────────────┤
│ ASP.NET 10 Minimal API │
│ http://0.0.0.0:19000 │
├──────┬──────┬──────┬──────┬──────┬──────┬──────┬──────┬────┤
│ Auth │ Chat │ Hist │ Sess │Agent │ Tele │ Cron │ Krea │Adm │
│ │ SSE │ │ │ │ gram │ jobs │ Img │ in │
├──────┴──────┴──────┴──────┴──────┴──────┴──────┴──────┴────┤
│ Services Layer │
│ AnthropicService · ChatService · ToolService │
│ DatabaseService · MemoryService · SkillService │
│ TelegramService · CronjobService · KreaService │
├─────────────────────────────────────────────────────────────┤
│ SQLite (data/gott.db) via Dapper │
│ Filesystem (data/agents/, data/skills/) │
├─────────────────────────────────────────────────────────────┤
│ Anthropic Claude API (claude-sonnet/opus/haiku) │
│ Krea API (Bildgenerierung) │
│ Telegram Bot API │
└─────────────────────────────────────────────────────────────┘
Tech-Stack
| Schicht | Technologie |
|---|---|
| Runtime | .NET 10 (ohne Nullable, ohne Implicit Usings) |
| Web | ASP.NET Minimal API, Kestrel |
| Datenbank | SQLite via Microsoft.Data.Sqlite + Dapper |
| AI | Anthropic Claude API (Streaming SSE + Non-Streaming) |
| Images | SixLabors.ImageSharp (Resize, Thumbnails) |
| Cron | Cronos (Cron-Expression-Parsing) |
| Frontend | Vanilla JavaScript SPA (kein Framework) |
| Markdown | marked.js (Client-side Rendering) |
| LaTeX | KaTeX 0.16.21 (Math-Rendering, self-hosted mit woff2-Fonts) |
| Editor | CodeMirror 5 + EasyMDE |
| Icons | Font Awesome |
| Fonts | Inter, JetBrains Mono (self-hosted) |
| Desktop | WPF + WebView2 (.NET 10, Windows-only) |
Projektstruktur
gott/
├── Program.cs # Startup, DI, Middleware, Routing
├── gott.csproj # Projekt-Definition (.NET 10)
├── appsettings.json # Konfiguration (Tokens, Limits)
├── deploy.sh # Deployment-Script (systemctl)
│
├── Models/ # Daten-Modelle (Records)
│ ├── UserRecord.cs
│ ├── AgentRecord.cs
│ ├── SessionRecord.cs
│ ├── ChainRecord.cs
│ ├── MessageRecord.cs # + AttachmentRecord
│ ├── ArchiveRecord.cs
│ ├── CronjobRecord.cs
│ ├── KreaImageRecord.cs
│ ├── SharedMessageRecord.cs # Geteilte Nachrichten (Share-Token)
│ ├── ChatModels.cs # ChatMessage, ChatRequest, AttachmentInfo/Block
│ └── ChatContext.cs # Runtime-Kontext für einen Chat + ReviewContext
│
├── Services/ # Business-Logic
│ ├── DatabaseService.cs # SQLite CRUD, Schema, Migrationen
│ ├── AuthService.cs # Token-basierte Authentifizierung
│ ├── ChatService.cs # Kontext-Aufbau, History-Builder
│ ├── AnthropicService.cs # Claude API (Streaming + Non-Streaming)
│ ├── ToolService.cs # Tool-Definitionen + Ausführung
│ ├── SystemPromptBuilder.cs # Modularer System-Prompt aus Blöcken
│ ├── MemoryService.cs # Agent-Gedächtnis (Dateisystem)
│ ├── SkillService.cs # Skill-Verwaltung (Dateisystem)
│ ├── TelegramService.cs # Telegram Bot API Integration
│ ├── CronjobService.cs # BackgroundService für Cron-Tasks
│ ├── KreaService.cs # Krea Image Generation API
│ ├── ImageService.cs # Bild-Resize (Avatar, Session-Image)
│ ├── StreamingTracker.cs # Tracking aktiver Streams + CancellationTokenSource für Stop
│ └── WorkspaceHelper.cs # Workspace-Pfad-Auflösung (relativ → absolut)
│
├── Endpoints/ # HTTP API (Minimal API)
│ ├── AuthEndpoint.cs # Login, Logout, Me
│ ├── ChatEndpoint.cs # POST /api/chat (SSE Streaming)
│ ├── HistoryEndpoint.cs # History, Archive, Attachments, Marks
│ ├── SessionEndpoint.cs # CRUD + SystemPrompt, Exec, Git-Status
│ ├── AgentEndpoint.cs # CRUD
│ ├── WorkspaceEndpoint.cs # File-Tree, File-Read/Write, Browse, Agent-Files
│ ├── TelegramEndpoint.cs # Webhook, Config, Registration
│ ├── CronjobEndpoint.cs # CRUD + Toggle, Manual Run
│ ├── KreaEndpoint.cs # Generate, List, File-Serve
│ ├── SkillEndpoint.cs # List, Agent-Skill-Mapping, Output-Files
│ ├── SharedEndpoint.cs # Nachrichten teilen (öffentliche Links)
│ ├── AdminEndpoint.cs # Admin: User-CRUD, Impersonate (Admin-only)
│ ├── ProfileEndpoint.cs # Profil, Persona, Passwort
│ ├── SettingsEndpoint.cs # User-Settings (JSON blob)
│ ├── BackupEndpoint.cs # Backup als tar.gz Download
│ └── InfoEndpoint.cs # Build-Zeitstempel
│
├── Middleware/
│ └── AuthMiddleware.cs # Cookie-basierte Token-Validierung
│
├── Extensions/
│ └── HttpContextExtensions.cs # GetUserId(), IsAdmin()
│
├── Templates/ # Standard-Templates für neue Agents
│ ├── IDENTITY.md # Wer bin ich? (Name, Sprache)
│ ├── SOUL.md # Persönlichkeit, Verhalten
│ └── USER.md # Infos über den User
│
├── wwwroot/ # Frontend (Vanilla JS SPA)
│ ├── index.html # Single HTML Entry Point
│ ├── css/ # Stylesheets
│ │ ├── theme.css # CSS Custom Properties (Dark Theme)
│ │ ├── base.css # Reset, Grundlayout
│ │ ├── main.css # Sidebar, Layout-Struktur
│ │ ├── chat.css # Chat-Nachrichten, Bubbles
│ │ ├── dashboard.css # Dashboard-Grid
│ │ ├── form.css # Formulare, Inputs, Avatar-Editor-Modal
│ │ ├── markdown.css # Markdown + KaTeX Rendering-Styles
│ │ ├── file-explorer.css # File-Explorer Panel
│ │ ├── login.css # Login-Seite
│ │ ├── mobile.css # Responsive Anpassungen
│ │ ├── tooltip.css # Tooltip-Styles
│ │ ├── fonts.css # @font-face Definitionen
│ │ ├── placeholder.css # Placeholder/Loading States
│ │ ├── katex.min.css # KaTeX Math-Rendering Styles
│ │ ├── codemirror.min.css # CodeMirror Editor
│ │ ├── easymde.min.css # EasyMDE Editor
│ │ └── fonts/ # KaTeX woff2 Fonts (21 Dateien)
│ ├── js/
│ │ ├── app.js # App-Initialisierung, Auth-Check
│ │ ├── router.js # Client-side SPA Router
│ │ ├── api.js # API-Client (fetch wrapper)
│ │ ├── ui.js # UI-Utilities (Modal, Toast, etc.)
│ │ ├── chat.js # Chat-Logic, SSE-Streaming
│ │ ├── history.js # History-Rendering, Pagination
│ │ ├── session.js # Session-Verwaltung
│ │ ├── file-explorer.js # File-Explorer Komponente
│ │ ├── avatar-editor.js # Wiederverwendbares Avatar-Editor-Modal
│ │ ├── commands-ui.js # Custom-Commands UI
│ │ ├── emoji.js # Emoji-Picker
│ │ ├── emoji.userdata.js # Häufig genutzte Emojis
│ │ ├── tooltip.js # Tooltip-System
│ │ ├── title.js # Tab-Titel-Management
│ │ ├── pages/ # Seiten-Komponenten
│ │ │ ├── chat-page.js # Haupt-Chat-Ansicht
│ │ │ ├── dashboard.js # Dashboard / Home
│ │ │ ├── session-page.js # Session-Einstellungen
│ │ │ ├── agent-page.js # Agent-Editor
│ │ │ ├── cronjob-page.js # Cronjob-Verwaltung
│ │ │ ├── profile-page.js # Profil-Bearbeitung
│ │ │ ├── admin-page.js # Admin: Benutzerverwaltung
│ │ │ ├── settings-page.js # App-Einstellungen
│ │ │ ├── login-page.js # Login-Formular
│ │ │ └── shared-page.js # Öffentliche geteilte Nachricht
│ │ └── lib/ # Vendor-Libraries
│ │ ├── marked.min.js # Markdown Parser
│ │ ├── codemirror.min.js # Code Editor
│ │ ├── codemirror.cjs # CM CommonJS Wrapper
│ │ ├── easymde.min.js # Markdown Editor
│ │ ├── katex.min.js # KaTeX Math-Rendering Engine
│ │ └── cm-mode-*.min.js # CodeMirror Syntax-Modes
│ ├── fonts/ # Self-hosted Fonts (Inter, JetBrains Mono)
│ └── lib/font-awesome/ # Font Awesome Icons
│
├── WindowsApp/ # Windows Desktop Client (WPF)
│ ├── Gott.csproj # .NET 10 Windows, WebView2
│ ├── App.xaml / App.xaml.cs # WPF Application
│ ├── MainWindow.xaml/cs # WebView2 Host Window
│ └── appsettings.json # Server-URL Konfiguration
│
└── publish/ # Build-Output (NICHT editieren!)
└── data/
├── gott.db # SQLite Datenbank
├── agents/ # Agent Memory-Dateien
│ └── {agentId}/
│ ├── IDENTITY.md
│ ├── SOUL.md
│ ├── MEMORY.md
│ └── memory/ # Tages-Logs etc.
├── skills/ # Skill-Verzeichnisse
│ └── {slug}/
│ ├── SKILL.md
│ ├── PROMPT.md
│ └── output/
├── images/ # Krea-generierte Bilder
├── logs/ # Payload-Logs (optional)
└── backup/ # Backup-Archive
Datenmodell
Entity-Relationship
User (1) ─── (*) Agent
User (1) ─── (*) Session
Agent (1) ─── (*) Session (Session hat optional einen Agent)
Agent (1) ─── (*) Session (Session hat optional einen Review-Agent)
Agent (*) ─── (*) Skill (via agent_skills Tabelle)
Session (1) ─── (*) Chain (ein Chat-Request = eine Chain)
Session (1) ─── (*) Archive (archivierte Chains)
Chain (1) ─── (*) Message
Message (1) ─── (*) Attachment
Session (1) ─── (*) Cronjob
User (1) ─── (*) Cronjob
User (1) ─── (*) SharedMessage
Message (1) ─── (*) SharedMessage
Tabellen
| Tabelle | Beschreibung |
|---|---|
users |
Benutzer (username, password_hash, persona, settings, default_path) |
tokens |
Auth-Tokens (token → user_id) |
agents |
AI-Agenten (model, soul, identity, memory, tools, avatar_scale) |
sessions |
Chat-Sessions (workspace, context, telegram-config, avatar_scale, telegram_allowed_chat_ids, review_agent_id, max_review_iterations) |
chains |
Request-Chains (model, tokens, iterations, timing) |
messages |
Einzelne Nachrichten (text, tool_use, tool_result) |
attachments |
Datei-Anhänge (base64, image/document) |
archives |
Archivierte Chain-Gruppen |
agent_skills |
Agent ↔ Skill Zuordnung |
cronjobs |
Geplante Tasks (cron expression, prompt) |
shared_messages |
Geteilte Nachrichten (Share-Token, Ablaufdatum) |
telegram_links |
Telegram Chat ↔ Session Verknüpfung |
Zentrale Records
ChainRecord – Repräsentiert einen kompletten Request-Response-Zyklus:
ChainId– Eindeutige IDSessionId– Zugehörige SessionModel– Verwendetes Claude-Modell (z.B.claude-sonnet-4-6)SystemPrompt– Der vollständige System-Prompt (gespeichert für Nachvollziehbarkeit)InputTokens,OutputTokens,CacheCreationTokens,CacheReadTokens– Token-VerbrauchIterations– Anzahl der Tool-Loop-DurchläufeStopReason–end_turn,tool_use,max_iterations,error,client_disconnectedDurationMs– Gesamtdauer der Chain
MessageRecord – Eine einzelne Nachricht innerhalb einer Chain:
Role–user,assistant,systemType–text,tool_use,tool_result,errorContent– Textinhalt oder JSON (bei tool_use: Input-JSON)ToolName,ToolCallId– Bei Tool-AufrufenIsMarked– Als wichtig markierte Nachricht (wird in System-Prompt aufgenommen)DeletedOn– Soft-Delete Zeitstempel
Backend-Architektur
Program.cs – Startup
Die Program.cs ist der zentrale Einstiegspunkt und konfiguriert:
- Service-Registrierung – Alle Services als Singletons im DI-Container
- Datenbank-Initialisierung –
DatabaseServiceerstellt Schema + Migrationen - Default-User – Wird automatisch angelegt falls keine User existieren
- Middleware – Static Files →
AuthMiddleware→ Endpoints - Endpoint-Mapping – Alle 16 Endpoint-Gruppen registriert
- Server – Kestrel auf
http://0.0.0.0:19000
Initialisierungsreihenfolge:
AuthService → DatabaseService → EnsureDefaultUser
→ ImageService, StreamingTracker, MemoryService, SkillService
→ ToolService → ChatService
→ AnthropicService → TelegramService → KreaService
→ CronjobService (BackgroundService)
Services
| Service | Typ | Aufgabe |
|---|---|---|
DatabaseService |
Singleton | SQLite CRUD, Schema-Init, Migrationen, alle DB-Operationen |
AuthService |
Singleton | Token-Erzeugung/-Validierung, Passwort-Hashing (SHA256) |
ChatService |
Singleton | Chat-Kontext aufbauen, History aus DB rekonstruieren |
AnthropicService |
Singleton | Claude API Kommunikation (Streaming SSE + Non-Streaming) |
ToolService |
Singleton | Tool-Definitionen bereitstellen, Tool-Aufrufe ausführen |
WorkspaceHelper |
Static | Workspace-Pfad-Auflösung (relativ → absolut), Path-Traversal-Schutz |
SystemPromptBuilder |
Static | Modularer System-Prompt aus konfigurierbaren Blöcken |
MemoryService |
Singleton | Agent-Gedächtnis auf Dateisystem (MEMORY.md, IDENTITY.md etc.) |
SkillService |
Singleton | Skill-Discovery und -Management aus Dateisystem |
TelegramService |
Singleton | Telegram Bot API, Webhook-Handling, Nachrichten senden |
CronjobService |
Background | Minütlicher Check auf fällige Cronjobs, Ausführung via Claude |
KreaService |
Singleton | Krea API für Bildgenerierung, Job-Polling, Image-Download |
ImageService |
Singleton | Bild-Resize (max 512px) für Avatare und Session-Bilder |
StreamingTracker |
Singleton | Trackt aktive Streams + CancellationTokenSource pro Session für Stop-Button |
Endpoints (API)
Alle Endpoints folgen dem Minimal API-Pattern mit Extension Methods (MapXxxEndpoints).
| Gruppe | Basis-Route | Methoden |
|---|---|---|
| Auth | /api/auth/ |
POST login, POST logout, GET me, GET autologin |
| Chat | /api/chat |
POST (SSE Streaming), POST stop |
| History | /api/history |
GET history, GET poll, POST archive, GET archives, GET archive/{id}, GET attachments/{id}, PUT messages/{id}/mark, PUT messages/{id}/delete, GET chains/{id} |
| Sessions | /api/sessions/ |
CRUD + GET system-prompt, GET system-prompt-blocks, GET streaming, POST exec, GET git-status |
| Agents | /api/agents/ |
CRUD |
| Admin | /api/admin/ |
GET users, POST users, PUT users/{id}, PUT users/{id}/password, DELETE users/{id}, POST users/{id}/impersonate, POST users/{id}/login-link (Admin-only) |
| Workspace | /api/workspace/ |
GET tree, GET/PUT file, GET browse, POST mkdir, DELETE dir, POST browse/mkdir, GET agent/tree, GET/PUT agent/file, POST agent/mkdir, GET raw |
| Telegram | /api/telegram/ |
POST webhook/{sessionId} (unauthenticated), Session-Config CRUD, Webhook-Management |
| Cronjobs | /api/cronjobs/ |
CRUD + POST toggle, POST run |
| Krea | /api/images/ |
POST generate, GET list, GET file/{name}, GET file/{name}/thumb, GET status |
| Skills | /api/skills |
GET list, GET/PUT agent skills, Output-Files + Thumbnails |
| Profile | /api/profile |
GET, PUT, PUT password |
| Settings | /api/settings |
GET, PUT |
| Backup | /api/backup |
POST (Admin only, tar.gz Download) |
| Shared | /api/shared/, /api/messages/{id}/share |
Share erstellen, öffentlich abrufen, auflisten, löschen |
| Info | /api/info |
GET (Build-Zeitstempel) |
Middleware
AuthMiddleware prüft jede /api/-Anfrage auf ein gültiges gott_token-Cookie.
Ausnahmen (kein Auth nötig):
- Statische Dateien (nicht
/api/) POST /api/auth/loginGET /api/auth/autologin(Token-basierter Autologin via Link)POST /api/telegram/webhook/{sessionId}(authentifiziert via Secret-Header)GET /api/shared/{token}(öffentlicher Zugriff auf geteilte Nachrichten)GET /api/images/file/*(Krea-Bilder und Thumbnails, öffentlich)
API-Key Auth (ohne User-Kontext):
/api/images/*-Routen akzeptieren einenX-Api-Key-Header. Wenn der Key mitKreaApiKeyaus der Config übereinstimmt, wird der Request ohne User-Authentifizierung durchgelassen. Normaler Cookie-Auth funktioniert weiterhin als Fallback.
Bei Erfolg werden UserId und IsAdmin in HttpContext.Items gesetzt (bei API-Key-Auth sind diese nicht gesetzt).
Models
Die Models in Models/ sind reine Daten-Records ohne Business-Logic (Ausnahme: ChatMessage hat Helper-Methoden für Content-Extraktion und UserRecord hat GetEffectivePersona()).
ChatContext ist ein Runtime-Objekt das den vollständigen Kontext eines Chat-Requests hält:
- Chain-ID, Session-ID, Model-ID
- Aufgelöster System-Prompt (Text + strukturierte Blöcke)
- Workspace-Pfad, Tool-Choice
- Referenzen auf Agent und Session Records
Templates
Templates/ enthält Vorlagen die beim Erstellen eines neuen Agents in dessen Memory-Verzeichnis kopiert werden:
- IDENTITY.md – Name und Grundinfos (Platzhalter
{NAME}wird ersetzt) - SOUL.md – Persönlichkeit und Verhaltensgrundsätze
- USER.md – Informationen über den User (global, nicht agent-spezifisch)
Frontend-Architektur
Das Frontend ist eine Single-Page Application ohne Build-Step, komplett in Vanilla JavaScript.
Routing
router.js implementiert ein Hash-basiertes Client-Side-Routing:
| Route | Page | Beschreibung |
|---|---|---|
#/ |
dashboard.js |
Session-Übersicht |
#/chat/{sessionId} |
chat-page.js |
Chat-Ansicht |
#/session/{sessionId} |
session-page.js |
Session-Einstellungen |
#/agent/{agentId} |
agent-page.js |
Agent-Editor |
#/cronjobs |
cronjob-page.js |
Cronjob-Verwaltung |
#/profile |
profile-page.js |
Profil |
#/settings |
settings-page.js |
App-Einstellungen |
#/admin |
admin-page.js |
Benutzerverwaltung (Admin-only) |
#/login |
login-page.js |
Login |
#/shared/{token} |
shared-page.js |
Öffentliche geteilte Nachricht (kein Auth) |
Kern-Module
- app.js – Initialisierung, Auth-Check, globale Event-Handler
- api.js – Zentraler API-Client mit
fetch()-Wrapper, Auth-Redirect bei 401 - ui.js – UI-Utilities (Modals, Toasts, Confirmations), Card-Builder (
buildAgentCard(),buildSessionCard()), Markdown-Rendering-Helpers (esc(),prettyModelName()) - chat.js – SSE-Stream-Handling, Markdown-Rendering (mit KaTeX), Tool-Output-Darstellung
- history.js – Chat-History laden, paginieren, rendern
- session.js – Session-State-Management
- file-explorer.js – Workspace File-Explorer Panel (Dateien, Ordner erstellen/löschen, Folder-Browser)
- avatar-editor.js – Wiederverwendbares Avatar-Editor-Modal (Upload, Paste, AI-Generate, Scale)
- commands-ui.js – Custom-Commands UI-Komponente
Wiederverwendbare Card-Builder (ui.js)
buildAgentCard(agent, skills)– Erzeugt ein.cardDOM-Element für einen Agent (Avatar, Name, Model-Badge, Feature-Badges: toolChoice, autoCommit, useSoul, useIdentity, useUserInfo, useMemory, webSearch, Skills). Wird im Dashboard und im Agent-Picker-Modal (Session-Formular) verwendet.buildSessionCard(session, agent)– Erzeugt ein.cardDOM-Element für eine Session (Avatar, Name, Badges: Agent, Kontext, Telegram, Meta: Nachrichten/Archiv/Workspace). Wird im Dashboard und im Session-Picker-Modal (Cronjob-Formular) verwendet.- Picker-Modals – Agent- und Session-Auswahl in Formularen (Session-/Cronjob-Seiten) erfolgt über modale Dialoge mit den Card-Buildern statt über Dropdowns.
- emoji.js – Emoji-Picker mit Kategorien und Suche
- tooltip.js – Tooltip-System für Hover-Infos
- title.js – Dynamisches Tab-Titel-Management
Styling
CSS ist in modulare Dateien aufgeteilt mit CSS Custom Properties für Theming:
theme.css– Alle Farben, Abstände, Schriften als CSS Variablesbase.css– Reset und Grundlayoutmain.css– Sidebar, Content-Area, Responsive Layoutchat.css– Chat-Bubbles, Streaming-Animation, Tool-Outputsmarkdown.css– Rendering von Markdown in Nachrichtenmobile.css– Responsive Breakpoints und Anpassungen
Chat-Pipeline
Der Chat-Flow von User-Input bis zur gerenderten Antwort:
1. User tippt Nachricht + optionale Attachments (Bilder/Dokumente)
↓
2. Frontend: POST /api/chat { content, sessionId }
↓
3. ChatEndpoint:
a) User-Message + Attachments in DB speichern
b) ChatService.PrepareContext() → Agent, Model, System-Prompt, Chain
c) ChatService.BuildHistoryFromDb() → vollständige Message-History
d) AnthropicService.StreamChat() starten
↓
4. AnthropicService (Agentic Loop):
┌─────────────────────────────────────────┐
│ while (iterations < maxIterations) │
│ → Claude API Request (SSE) │
│ → Stream-Processing: │
│ • Text-Tokens → SSE an Frontend │
│ • Tool-Use → ToolService.Execute() │
│ • Tool-Results → nächste Iteration │
│ → Messages in DB persistieren │
│ → Stop wenn: end_turn / max_iterations│
│ → CancellationToken bei Abbruch │
└─────────────────────────────────────────┘
↓
4b. Review-Phase (optional, wenn ReviewAgent konfiguriert):
┌─────────────────────────────────────────┐
│ Nach end_turn des Worker-Agents: │
│ → RunReview() mit Review-Agent │
│ → Review-Agent prüft (eigene Tools) │
│ → [APPROVED] → Fertig │
│ → Feedback → an Worker als User-Msg │
│ → Worker korrigiert → erneuter Review │
│ → Max Review-Runden → Fertig │
└─────────────────────────────────────────┘
↓
5. Frontend: SSE Events empfangen und rendern
• "text" → Markdown parsen, Token für Token anzeigen
• "tool_*" → Tool-Aufrufe collapsible darstellen
• "review_*" → Review-Bubbles mit eigenem Styling
• "done" → Token-Stats, Dauer, Model anzeigen
Abbruch (Stop-Button)
Der Stop-Mechanismus arbeitet auf zwei Ebenen:
1. Expliziter Stop-Endpoint (POST /api/chat/stop):
- Frontend ruft
apiStopChat(sessionId)auf StreamingTrackerhält pro Session einenCancellationTokenSourceStreamingTracker.Cancel(sessionId)cancelt den Token sofort- Der Chat-Handler verknüpft den Stop-Token mit dem Request-Token via
CreateLinkedTokenSource
2. CancellationToken-Propagierung:
- Frontend:
AbortController.abort()→ SSE-Fetch abgebrochen +POST /api/chat/stop StreamingTracker.Cancel()→ CancellationTokenSource wird gecancelledAnthropicService:ThrowIfCancellationRequested()am Loop-Anfang, vor/nach Tool-ExecutionToolService.ExecuteTool(): CancellationToken wird durchgereicht → beiexecutewird der Prozess gekilltWriteSseEvent(): Alle SSE-Writes mit CancellationToken → sofortiger Abbruch- Chain wird mit
StopReason = "client_disconnected"finalisiert
Warum zwei Ebenen? Kestrel erkennt einen Client-Disconnect erst beim nächsten Write auf den Response-Stream. Wenn das Backend in einer langen Tool-Ausführung steckt, wird nichts geschrieben – der explizite Stop-Endpoint garantiert sofortigen Abbruch.
Streaming vs Non-Streaming
- Web-Chat: Streaming via SSE (
text/event-stream). Tokens werden in Echtzeit gerendert. - Telegram: Non-Streaming via
ChatNonStreaming(). Vollständige Antwort wird abgewartet und als Telegram-Nachricht gesendet. - Cronjobs: Non-Streaming, wie Telegram.
History-Optimierung
Die History-Rekonstruktion in BuildHistoryFromDb() ist optimiert:
- Ältere Chains: Nur
text-Messages (user + assistant), keine Tool-Calls - Letzte Chain: Vollständig mit allen Tool-Use/Tool-Result Blöcken
- Attachments: Nur für die letzte User-Message geladen (spart enorme Token)
- Tool-Results: In der History auf 20.000 Zeichen gekürzt (vollständig in DB)
Tool-System
Der Agent hat Zugriff auf folgende Tools, abhängig von Konfiguration:
Datei-Tools (wenn Workspace konfiguriert)
| Tool | Beschreibung |
|---|---|
read_file |
Datei lesen (relativer Pfad zum Workspace) |
write_file |
Datei erstellen/überschreiben |
edit_file |
Exakten Textabschnitt in Datei ersetzen |
list_files |
Verzeichnis-Listing |
delete_file |
Datei oder leeres Verzeichnis löschen |
execute |
Shell-Befehl ausführen (bash, 180s Timeout) |
glob |
Dateien via Glob-Pattern finden |
grep |
Dateien nach Regex/Text durchsuchen |
todo_write |
Todo-Liste schreiben (als Datei im Workspace) |
Memory-Tools (wenn UseMemory aktiviert)
| Tool | Beschreibung |
|---|---|
memory_read |
Memory-Datei des Agents lesen |
memory_write |
Memory-Datei schreiben (überschreiben/append) |
memory_list |
Alle Memory-Dateien des Agents auflisten |
Web-Suche (wenn WebSearchVersion konfiguriert)
Nutzt Anthropics eingebaute Web-Suche als Server-Side-Tool.
Tool-Choice Strategien
any: Erste Iteration erzwingt Tool-Nutzung, danachauto. Verhindert dass der Agent nur Text antwortet wenn Tools benötigt werden.auto: Claude entscheidet frei ob Tools nötig sind.
Pfad-Sicherheit
Alle Dateipfade werden via ResolvePath() aufgelöst und gegen den Workspace/Memory-Ordner geprüft – Path-Traversal-Angriffe werden verhindert.
Agent-System
Ein Agent definiert die Persönlichkeit und Fähigkeiten der AI:
| Eigenschaft | Beschreibung |
|---|---|
Name |
Anzeigename |
Avatar |
Base64 Data-URL (auf 512px resized) |
Model |
sonnet, sonnet-4-5, sonnet-4-6, opus, opus-4-5, opus-4-6, haiku, haiku-4-5 |
ToolChoice |
any oder auto |
CustomCommands |
JSON-Array mit Slash-Commands (Label + Prompt) |
AutoCommit |
"" (nichts), "mention" (verbieten), "enforce" (erzwingen), "forbid" (strikt verboten) |
UseSoul |
SOUL.md in System-Prompt einbinden |
UseIdentity |
IDENTITY.md in System-Prompt einbinden |
UseUserInfo |
User-Persona in System-Prompt einbinden |
UseMemory |
Memory-Tools aktivieren |
WebSearchVersion |
Web-Suche aktivieren (z.B. web_search_20260209) |
Model-Auflösung
"sonnet" → claude-sonnet-4-6
"sonnet-4-5" → claude-sonnet-4-5
"sonnet-4-6" → claude-sonnet-4-6
"opus" → claude-opus-4-6
"opus-4-5" → claude-opus-4-5
"opus-4-6" → claude-opus-4-6
"haiku" → claude-haiku-4-5
"haiku-4-5" → claude-haiku-4-5
(default) → claude-sonnet-4-6
System-Prompt-Aufbau
Der SystemPromptBuilder erzeugt den System-Prompt modular aus konfigurierbaren Blöcken:
┌──────────────────────────────────────────┐
│ 1. IDENTITY.md (UseIdentity) │ → Wer ist der Agent?
│ 2. SOUL.md (UseSoul) │ → Persönlichkeit, Verhalten
│ 3. User-Persona (UseUserInfo) │ → Infos über den User
│ 4. Tool-Nutzung (Workspace + any) │ → "IMMER Tools benutzen"
│ 5. Workspace-Info │ → Tools + Workspace-Pfad
│ 6. Session-Kontext │ → Freiformtext
│ 7. Skills (Agent-Skills) │ → Skill-Prompts
│ 8. Memory (UseMemory) │ → Memory-Regeln + MEMORY.md Inhalt
│ 9. Git-Verhalten (AutoCommit) │ → Commit-Regeln
│10. Verhaltensregeln (Workspace + any) │ → "IMMER Tools aufrufen"
│11. Erinnerung (Workspace + any) │ → Höchste Priorität: Tool-Aufrufe!
│12. Markierte Nachrichten │ → Vom User als wichtig markierte Messages
└──────────────────────────────────────────┘
Jeder Block hat:
- Icon – Font Awesome Icon-Klasse
- Label – Beschreibender Titel
- Content – Markdown-Text
Die Blöcke sind über die API als JSON abrufbar (GET /api/sessions/{id}/system-prompt-blocks), sodass das Frontend sie einzeln inspizierbar darstellen kann.
Memory-System
Jeder Agent hat ein eigenes Dateisystem-basiertes Gedächtnis:
data/agents/{agentId}/
├── IDENTITY.md # Identität (aus Template initialisiert)
├── SOUL.md # Persönlichkeit (aus Template initialisiert)
├── MEMORY.md # Haupt-Memory (kuratierte Informationen)
└── memory/ # Unterordner für Tages-Logs, Themen
├── YYYY-MM-DD.md
└── ...
Funktionsweise
- Initialisierung: Beim Erstellen eines Agents werden
IDENTITY.mdundSOUL.mdausTemplates/kopiert - Lesen: Der Agent kann seine Memory-Dateien via
memory_readTool lesen - Schreiben: Via
memory_write(überschreiben oder append) - Auflisten: Via
memory_listalle Dateien durchsuchen - System-Prompt:
MEMORY.mdInhalt wird automatisch in den System-Prompt eingebettet - IDENTITY.md und SOUL.md: Werden als eigene System-Prompt-Blöcke eingebunden (wenn aktiviert)
Sandbox
Alle Pfade werden gegen das Agent-Verzeichnis geprüft – kein Zugriff außerhalb möglich.
Skill-System
Skills sind Dateisystem-basierte Erweiterungen die einem Agent zugeordnet werden können:
data/skills/{slug}/
├── SKILL.md # Metadaten (Name, Description, Version im Frontmatter)
├── PROMPT.md # System-Prompt-Erweiterung (in Agent-Prompt eingebettet)
├── _meta.json # Alternative Metadaten (Fallback)
└── output/ # Skill-Output (Bilder, Dateien, etc.)
SKILL.md Frontmatter
---
name: Mein Skill
description: Beschreibung
version: 1.0
---
Agent-Zuordnung
Skills werden über die agent_skills Tabelle einem Agent zugeordnet. Der PROMPT.md-Inhalt aller zugeordneten Skills wird als ein System-Prompt-Block eingefügt.
Workspace-Implikation
Wenn ein Agent Skills hat aber kein Workspace konfiguriert ist, wird automatisch /tmp als Workspace gesetzt (damit execute für Skill-Commands funktioniert).
Telegram-Integration
Sessions können mit einem Telegram Bot verbunden werden:
Konfiguration
Pro Session werden gespeichert:
TelegramBotToken– Bot-Token von @BotFatherTelegramWebhookSecret– Geheimer Token für Webhook-VerifizierungTelegramChatId– Verknüpfte Chat-ID (Owner)TelegramAllowedChatIds– Kommagetrennte Chat-ID-Whitelist für Zugriffskontrolle
Webhook-Flow
1. User konfiguriert Bot-Token in Session-Settings
2. User registriert Webhook (POST .../telegram/register-webhook)
→ Setzt Webhook-URL: {baseUrl}/api/telegram/webhook/{sessionId}
3. Telegram sendet Updates an Webhook
4. AuthMiddleware lässt Webhook-Requests durch (kein Cookie nötig)
5. TelegramEndpoint prüft X-Telegram-Bot-Api-Secret-Token Header
6. TelegramService verarbeitet Update:
- /start → Session verknüpfen (nur wenn noch kein Owner ODER Whitelist-Match)
- /clear → History archivieren
- /status → Session-Info anzeigen
- /unlink → Verknüpfung aufheben
- Text → An Claude weiterleiten (Non-Streaming)
Zugriffskontrolle (Chat-ID-Whitelist)
Nicht jeder Telegram-User darf den Bot nutzen:
- Erster
/start: Kein Owner → User wird automatisch Owner (TelegramChatIdgesetzt) - Fremder
/start: User bekommt🔒 Zugriff verweigert+ seine Chat-ID angezeigt - Owner-Benachrichtigung: Owner erhält
🔔 Zugriffsanfragemit Username + Chat-ID - Freigabe: Owner/Admin trägt Chat-ID in Session-Settings ein (
TelegramAllowedChatIds) - Prüfung: Alle Commands + Nachrichten prüfen via
IsChatIdAllowed()(Owner + Whitelist)
Non-Streaming Chat
Telegram-Nachrichten werden über AnthropicService.ChatNonStreaming() verarbeitet. Die History wird genauso aus der DB aufgebaut wie beim Web-Chat. Antworten über 4096 Zeichen werden automatisch in Chunks aufgeteilt.
Cronjob-System
Der CronjobService ist ein BackgroundService der minütlich nach fälligen Jobs prüft.
Datenmodell
| Feld | Beschreibung |
|---|---|
CronExpression |
Standard-Cron-Format (5 Felder), via Cronos |
SessionId |
Session in der der Job läuft |
Prompt |
Text der als User-Message an Claude gesendet wird |
NotifySessionId |
Optionale Session für Benachrichtigung |
IsEnabled |
Aktiviert/Deaktiviert |
NextRunAt |
Nächste geplante Ausführung (UTC) |
Ausführungsflow
1. CronjobService prüft jede Minute
2. Fällige Jobs (next_run_at <= jetzt) werden geladen
3. Für jeden Job:
a) ChatService.PrepareContext() – Chain + System-Prompt aufbauen
b) History aus DB laden
c) Prompt als User-Message anhängen + in DB speichern
d) AnthropicService.ChatNonStreaming() ausführen
e) Telegram-Benachrichtigung senden (auf Arbeits-Session)
f) Optional: Zusammenfassung in Notify-Session schreiben + Telegram dort
g) Nächste Ausführung berechnen + DB aktualisieren
Benachrichtigungen
- Arbeits-Session: Wenn die Session Telegram hat, wird die Antwort dort gepostet
- Notify-Session: Wenn konfiguriert, wird eine Zusammenfassung in eine andere Session geschrieben und der Agent dort antwortet darauf
Krea-Bildgenerierung
Die KreaService ermöglicht Bildgenerierung über die Krea API.
Unterstützte Modelle
flux, flux-kontext, flux-1.1-pro, flux-1.1-pro-ultra,
nano-banana, nano-banana-pro, imagen-3, imagen-4, imagen-4-fast, imagen-4-ultra,
ideogram-2-turbo, ideogram-3, seedream-3, seedream-4,
chatgpt-image, runway-gen-4
Flow
1. POST /api/images/generate { prompt, model, width, height, ... }
2. KreaService sendet Request an Krea API
3. Job-Polling bis Status "completed"
4. Bilder herunterladen nach data/images/
5. Metadaten als JSON speichern
6. Response mit Dateinamen + URLs
Bild-Serving
GET /api/images– Liste aller generierten Bilder (aus Metadaten-JSON)GET /api/images/file/{filename}– Einzelnes Bild ausliefern (ohne Auth)GET /api/images/file/{filename}/thumb– Thumbnail (320px WebP, gecacht indata/cache/images/, ohne Auth)GET /api/images/status– Generierungsstatus abfragen
Bild-Dateien und Thumbnails sind ohne Authentifizierung abrufbar (für externe Einbindung).
Auth & Multi-User
Authentifizierung
- Login: Username + Passwort → SHA256 Hash-Vergleich → Token generieren
- Token: 32 Bytes Random, als
gott_tokenHttpOnly Cookie (365 Tage) - Validierung: Jeder API-Call prüft Token → User-ID
- Logout: Token aus DB löschen + Cookie entfernen
Multi-User-Isolation
- Sessions sind an
user_idgebunden - Agents sind an
user_idgebunden - Cronjobs sind an
user_idgebunden - Jeder User sieht nur seine eigenen Daten
- Admin-Flag (
is_admin) für Backup-Endpoint, Admin-Benutzerverwaltung, Impersonate
Default-Path (Base-Path)
Jeder User hat einen optionalen DefaultPath – den Basis-Ordner für alle Workspaces. Wird nur vom Admin gesetzt.
- Session-Workspace: Speichert nur den relativen Pfad zum DefaultPath (z.B.
myappstatt/home/user/projects/myapp) - Auflösung:
WorkspaceHelper.ResolveWorkspace()kombiniert DefaultPath + relativen Workspace → absoluter Pfad - System-Prompt: Bekommt den aufgelösten absoluten Pfad, damit der Agent korrekt navigieren kann
- Path-Traversal-Schutz:
..in relativen Workspace-Pfaden wird blockiert (400 Bad Request) - Legacy-Support: Absolute Pfade in
session.Workspacefunktionieren weiterhin als Fallback - Folder-Browser: Startet beim DefaultPath, User kann nicht über den Base-Path hinaus navigieren
Default-User
Beim ersten Start wird automatisch ein Default-User erstellt (DatabaseService.EnsureDefaultUser()).
User-Persona
Jeder User hat eine optionale Persona – ein Freitext der beschreibt wer er ist. Diese wird (wenn UseUserInfo am Agent aktiv ist) in den System-Prompt als "Dein Gegenüber" eingebettet.
Admin-Benutzerverwaltung
Admins können alle User verwalten über AdminEndpoint.cs (alle Endpoints erfordern is_admin).
API-Endpunkte
| Methode | Route | Beschreibung |
|---|---|---|
GET |
/api/admin/users |
Alle User auflisten |
POST |
/api/admin/users |
Neuen User erstellen |
PUT |
/api/admin/users/{id} |
User bearbeiten (Name, Username, Admin, DefaultPath) |
PUT |
/api/admin/users/{id}/password |
Passwort zurücksetzen |
DELETE |
/api/admin/users/{id} |
User löschen (+ Tokens, Shared Messages) |
POST |
/api/admin/users/{id}/impersonate |
Als anderer User einloggen (Login-as-User) |
POST |
/api/admin/users/{id}/login-link |
Autologin-Token generieren → URL zurückgeben |
Impersonate (Login-as-User)
Admins können sich als beliebiger User einloggen ohne dessen Passwort zu kennen:
POST /api/admin/users/{id}/impersonate→ Erstellt Token für Zieluser- Setzt neuen
gott_token-Cookie → Admin-Session wird zum Zieluser location.reload()→ Frontend lädt mit neuem User-Kontext
Login-Link generieren
Admins können für jeden User einen Autologin-Link generieren – z.B. für Setup oder Support:
POST /api/admin/users/{id}/login-link→ Erstellt Token, gibt{ token }zurück- Frontend baut URL:
{window.location.origin}/api/auth/autologin?token={token} - Link wird im Modal angezeigt mit Copy-Button
GET /api/auth/autologin?token={token}→ Setzt Cookie + Redirect zu/(ohne Auth, wie Login)
Frontend (admin-page.js)
- Erreichbar über Dashboard-Link "Benutzerverwaltung" (nur für Admins sichtbar)
- User-Liste als Cards mit Edit/Delete/Login-Link-Buttons
- Inline-Formular für Create/Edit
- Login-Link-Modal mit Copy-Funktion
- Sich selbst löschen ist nicht möglich
Multi-Agent Review-System
Das Review-System ermöglicht es, einen zweiten Agent als Reviewer einzusetzen. Nach jeder Antwort des Worker-Agents prüft der Review-Agent das Ergebnis und gibt entweder [APPROVED] oder konstruktives Feedback.
Architektur
User-Message → Worker-Agent arbeitet (Tools, Iterationen) → end_turn
→ Review-Phase:
→ Review-Agent bekommt: Konversation als Kontext
→ Review-Agent prüft (kann Tools nutzen: read_file, execute etc.)
→ [APPROVED] → Fertig, Antwort an User
→ Feedback-Text → wird als User-Message an Worker-Agent eingefügt
→ Worker-Agent korrigiert → end_turn → Review-Agent prüft erneut
→ Max Review-Runden erreicht → Fertig (mit letzter Worker-Antwort)
Konfiguration
Auf Session-Ebene (nicht Agent-Ebene):
| DB-Feld | SessionRecord | Beschreibung |
|---|---|---|
review_agent_id |
ReviewAgentId |
ID des Review-Agents (optional, null = kein Review) |
max_review_iterations |
MaxReviewIterations |
Max. Review-Runden (Default: 3) |
Backend-Flow
-
ChatService.PrepareContext() – Wenn
session.ReviewAgentIdgesetzt:- Review-Agent aus DB laden
- Eigenen SystemPrompt für den Review-Agent bauen (Identity, Soul, Memory, Skills)
- Eigene Tool-Definitionen für den Review-Agent
ReviewContextmit Model, SystemPrompt, Tools, Agent-Referenz erstellen
-
ChatEndpoint – Übergibt
ctx.ReviewanAnthropicService.StreamChat() -
AnthropicService.StreamChat() – Nach
end_turndes Worker-Agents:- Prüft ob
ReviewContextvorhanden undreviewRound < MaxReviewIterations - Ruft
RunReview()auf
- Prüft ob
-
RunReview() – Orchestriert eine einzelne Review-Runde:
- Baut Review-Messages auf: Konversation als Context + Prüfanweisung
- SSE-Event
review_startan Client senden - Ruft
RunReviewAgentChat()auf (eigener API-Call an Claude mit Review-Agent-Config) - Review-Agent kann Tools nutzen (eigener Tool-Loop mit max. 25 Iterationen)
- SSE-Events
review_textundreview_tool_usefür Live-Streaming - Prüft ob Antwort
[APPROVED]enthält:- Ja → SSE
review_approved, returnHasFeedback = false - Nein → SSE
review_feedback, returnHasFeedback = true+ Feedback-Text
- Ja → SSE
-
Zurück in StreamChat() – Bei Feedback:
- Feedback als User-Message in DB speichern (mit
[Review-Feedback von AgentName (Runde X/Y)]Prefix) - Worker-Agent bekommt Feedback als nächste User-Message
continue→ nächste while-Loop-Iteration → Worker korrigiert → Review erneutreviewRound++bisMaxReviewIterationserreicht
- Feedback als User-Message in DB speichern (mit
ReviewContext (Model)
public class ReviewContext
{
public string Model { get; set; } // Claude-Modell des Review-Agents
public string SystemPrompt { get; set; } // Eigener System-Prompt
public AgentRecord Agent { get; set; } // Agent-Record für Name/Avatar
public List<object> Tools { get; set; } // Tool-Definitionen
public int MaxReviewIterations { get; set; } // Max Runden
}
SSE-Events
| Event | Daten | Beschreibung |
|---|---|---|
review_start |
{ agent: "Name" } |
Review-Phase beginnt |
review_text |
{ text: "..." } |
Review-Agent-Text (Token-Stream) |
review_tool_use |
{ tool: "name", input: "..." } |
Review-Agent nutzt Tool |
review_feedback |
{ feedback: "..." } |
Review nicht bestanden, Feedback an Worker |
review_approved |
{ message: "..." } |
Review bestanden |
DB-Persistierung
- Worker-Antworten: Normale Messages (role=assistant, type=text)
- Review-Feedback: Als User-Messages mit Prefix
[Review-Feedback von AgentName (Runde X/Y)]: - Review-Agent-Antworten: Werden nicht in der Chat-History persistiert (nur als SSE-Events gestreamt), da sie Zwischenergebnisse sind
Frontend
Session-Page (session-page.js):
- Zweiter Agent-Picker: "Review-Agent" (nutzt
buildAgentCard()+openAgentPickerModal()) - Input für "Max. Review-Runden" (Number-Input, Default 3)
Chat-UI (chat.js):
- SSE-Event-Handler für
review_start,review_text,review_tool_use,review_feedback,review_approved - Review-Bubbles mit eigenem Styling (sekundäre Farbe, Agent-Name-Header)
History-Rendering (history.js, ui.js):
renderMarkdownparst[Review: AgentName]→ styled Header mit IconrenderMarkdownparst[Review-Feedback von AgentName (...)]→ styled Feedback-HeaderrenderMarkdownfiltert[APPROVED]aus (wird ausgeblendet)- History erkennt Review-Nachrichten und rendert sie als
.review-bubblestatt normaler Bubbles - Review-Nachrichten werden nicht mit normalen Nachrichten gemergt
Shared-Page (shared-page.js):
- Gleiche Review-Bubble-Erkennung für geteilte Nachrichten
Nachrichten teilen (Shared Messages)
Einzelne Nachrichten oder ganze Threads können als öffentliche Links geteilt werden – ohne Login aufrufbar.
Datenmodell
Tabelle shared_messages:
| Spalte | Typ | Beschreibung |
|---|---|---|
id |
INTEGER | Primary Key |
share_token |
TEXT | UUID – öffentlicher Zugangsschlüssel |
message_id |
INTEGER | FK auf messages.id |
user_id |
INTEGER | Wer hat geteilt |
include_context |
INTEGER | 0 = Einzelnachricht, 1 = Thread bis dahin |
created_at |
TEXT | Erstellzeitpunkt |
expires_at |
TEXT | Optional: Ablaufdatum |
API-Endpunkte (SharedEndpoint.cs)
| Methode | Route | Auth | Beschreibung |
|---|---|---|---|
POST |
/api/messages/{id}/share |
✅ | Share erstellen (Body: {includeContext}) |
GET |
/api/shared/{token} |
❌ | Öffentlich: Geteilte Nachricht abrufen |
GET |
/api/shared |
✅ | Eigene Shares auflisten |
DELETE |
/api/shared/{token} |
✅ | Share-Link widerrufen |
Frontend-Flow
- Share-Button (🔗) erscheint an jeder Nachricht im Chat (neben Reply, Delete, Mark)
- Klick öffnet Kontext-Menü: "Einzelne Nachricht" oder "Thread teilen"
POST /api/messages/{id}/share→ Token zurück → URL in Zwischenablage kopiert- Toast: "Link kopiert!"
Öffentliche Ansicht (#/shared/{token})
- Route
#/shared/{token}→shared-page.js - Kein Auth nötig – Auth-Bypass in
app.js+AuthMiddleware - Minimales Layout: Header ("// gott · Geteilte Nachricht"), Nachrichten mit Markdown-Rendering
- Zwei Modi:
single(eine Nachricht) odercontext(Thread mit User/Assistant-Wechsel)
Workspace & File-Explorer
Workspace
Eine Session kann einen Workspace-Pfad haben. Dieser wird relativ zum DefaultPath des Users gespeichert (z.B. myapp) und via WorkspaceHelper.ResolveWorkspace() zum absoluten Pfad aufgelöst. Der Workspace:
- Aktiviert die Datei-/Shell-Tools für den Agent
- Ermöglicht den File-Explorer im Frontend
- Bietet
git statusInformationen - Erlaubt das Ausführen von Shell-Befehlen (foreground + background)
WorkspaceHelper
Services/WorkspaceHelper.cs – Statische Hilfsklasse für Workspace-Pfade:
| Methode | Beschreibung |
|---|---|
ResolveWorkspace(session, user) |
Relativer Workspace + DefaultPath → absoluter Pfad |
ValidateRelativeWorkspace(workspace) |
Prüft auf .., ~, absolute Pfade → null bei ungültig |
ToRelativeWorkspace(absolute, defaultPath) |
Absoluter Pfad → relativ zum DefaultPath |
File-Explorer API
| Endpoint | Beschreibung |
|---|---|
GET /api/workspace/tree |
Verzeichnisbaum (mit Ignore-Filtern) |
GET /api/workspace/file |
Dateiinhalt lesen (max 2MB) |
PUT /api/workspace/file |
Datei speichern |
POST /api/workspace/mkdir |
Ordner erstellen im Workspace |
DELETE /api/workspace/dir |
Leeren Ordner löschen im Workspace |
GET /api/workspace/browse |
Verzeichnis-Browser (für Pfad-Auswahl) |
POST /api/workspace/browse/mkdir |
Ordner erstellen per absolutem Pfad |
GET /api/workspace/raw |
Raw-Datei ausliefern (Bilder, PDFs) |
GET /api/workspace/agent/tree |
Agent-Memory-Verzeichnis |
GET/PUT /api/workspace/agent/file |
Agent-Memory-Dateien lesen/schreiben |
POST /api/workspace/agent/mkdir |
Ordner erstellen im Agent-Memory |
Ignored Directories
bin, obj, node_modules, .git, .vs, .idea, publish, dist, out, build, target, .cache
Session-Exec
POST /api/sessions/{id}/exec führt Shell-Befehle im Workspace aus:
- foreground: Synchron, wartet auf Ergebnis (30s Timeout)
- background: Fire-and-forget via
systemd-run
Avatar-System
Sessions und Agents können ein Bild/Avatar haben mit konfigurierbarem Zoom.
Datenfelder
| Feld | Tabellen | Beschreibung |
|---|---|---|
image / avatar |
sessions / agents |
Base64-kodiertes Bild (JPEG, max 512px via ImageService) |
avatar_scale |
sessions, agents |
Zoom-Faktor (0.5× – 3×, Default 1.0), angewandt via CSS transform: scale() |
Avatar-Editor (avatar-editor.js)
Wiederverwendbares Modal-Modul, genutzt in Session- und Agent-Pages:
const editor = AvatarEditor.init({
previewEl: document.querySelector('.avatar-preview'),
currentImage: existingBase64OrNull,
currentScale: 1.0,
onImageChange: (base64) => { /* Preview aktualisieren */ },
onScaleChange: (scale) => { /* Live-Preview skalieren */ }
});
// Werte auslesen: editor.getImage(), editor.getScale()
// Aufräumen: editor.destroy()
Features:
- Upload: Datei-Input für Bild-Upload
- Paste: Ctrl+V → Bild aus Zwischenablage einfügen
- AI-Generate: Text-Prompt → Krea API → Bild generieren (nur wenn
KreaTokenkonfiguriert) - Scale: Range-Slider 0.5× – 3× mit Live-Preview
- Clear: Bild entfernen
Dashboard-Darstellung
Cards zeigen Avatare mit transform: scale(avatarScale) im .card-image Container (overflow: hidden).
LaTeX/Math-Rendering
Chat-Nachrichten unterstützen LaTeX-Formeln via KaTeX:
Syntax
$$...$$→ Block-Math (zentriert, eigene Zeile)$...$→ Inline-Math (im Fließtext)
Rendering-Pipeline (in ui.js renderMarkdown())
1. Code-Blöcke extrahieren und schützen (Platzhalter)
2. Block-LaTeX ($$...$$) extrahieren und schützen
3. Inline-LaTeX ($...$) extrahieren und schützen
4. Markdown-Rendering via marked.js
5. Code-Blöcke wiederherstellen
6. LaTeX-Platzhalter durch KaTeX.renderToString() ersetzen
7. Bei fehlerhaftem LaTeX: Fallback als <code class="katex-error">
Abhängigkeiten
wwwroot/js/lib/katex.min.js– KaTeX Engine (v0.16.21)wwwroot/css/katex.min.css– Styleswwwroot/css/fonts/– 21 woff2-Fonts (self-hosted)
Funktioniert überall wo renderMarkdown() aufgerufen wird: Chat, Streaming, History, Archiv, Shared Page.
Windows Desktop App
Im WindowsApp/-Ordner liegt ein minimaler WPF WebView2 Client:
- .NET 10 Windows,
Microsoft.Web.WebView2 - Lädt die Web-UI in einem nativen Fenster
- Server-URL konfigurierbar via
appsettings.json - Dark Background um weißen Flash zu vermeiden
- Externe Links öffnen im Standard-Browser
- Fenster: 930px breit, 95% Bildschirmhöhe, zentriert
Deployment
deploy.sh
#!/bin/bash
set -e
cd /app/gott
export PATH="$HOME/.dotnet:$PATH"
systemctl stop gott
dotnet publish -c Release -o publish
systemctl start gott
echo "OK"
Verzeichnisse
- Quell-Code:
/app/gott/(wwwroot/, Services/, etc.) - Build-Output:
/app/gott/publish/ - Laufzeit-Daten:
/app/gott/publish/data/(DB, Agents, Images, Skills) - WICHTIG: Änderungen IMMER in
wwwroot/machen, NIEMALS inpublish/wwwroot/
systemd
Die Anwendung läuft als systemd Service (gott.service), Kestrel auf Port 19000.
Konfiguration
appsettings.json
{
"AnthropicToken": "", // Anthropic API Key (REQUIRED)
"MaxIterations": 100, // Max Tool-Loop Iterationen pro Chat
"PayloadLogging": false, // API-Payloads loggen (Debug)
"PayloadLoggingGzip": false, // Payload-Logs als .gz komprimieren
"KreaToken": "", // Krea API Token (optional)
"KreaApiKey": "" // API-Key für Krea-Endpoints ohne User-Auth (optional)
}
Environment
ASPNETCORE_ENVIRONMENT=Production→ lädtappsettings.Production.json- Tokens und Secrets sollten in
appsettings.Production.jsonstehen (nicht in Git)
Datenbank-Migrationen
Die DatabaseService.InitializeDatabase() handhabt Schema-Erstellung und Migrationen in einem einzigen Methoden-Aufruf:
- Tabellen-Erstellung via
CREATE TABLE IF NOT EXISTS - Spalten-Migration via
TryAddColumn()– fängt "column already exists" ab - Daten-Migration (z.B.
auto_commitvon INTEGER zu TEXT,use_web_searchzuweb_search_version)
Dieses Pattern ermöglicht:
- Idempotente Ausführung bei jedem App-Start
- Keine separate Migrations-Verwaltung nötig
- Neue Features können einfach Spalten hinzufügen
- Abwärtskompatibel – bestehende Daten bleiben erhalten