From 8e94975e616e2609ce3a93f90496d2ad64cdf438 Mon Sep 17 00:00:00 2001 From: Meleki Date: Sun, 15 Mar 2026 09:20:46 +0100 Subject: [PATCH] =?UTF-8?q?docs:=20Dokumentation=20aktualisieren=20(Review?= =?UTF-8?q?Context=E2=86=92SubAgentContext,=20Provider-Weiche,=20agent=5Fa?= =?UTF-8?q?pi=5Fkeys,=20Scanner,=20Dashboard-Sortierung,=20Plan-Modus-Hint?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ARCHITECTURE.md: - ReviewContext → SubAgentContext (Code-Block + alle Referenzen) - ChatContext.cs Kommentar aktualisiert - Provider-Weiche für Telegram, Cronjobs, Sub-Agents dokumentiert - OpenAiService: ChatNonStreaming() ergänzt - Chat-Pipeline: API-Key-Auflösung als Schritt 3c - Multi-Provider-Tabelle: AnthropicToken → agent_api_keys - api_keys Tabelle: Zuweisung pro Agent statt global - Neue Tabellen: agent_api_keys, scanner_logs, server_settings - Dashboard-Sortierung nach letzter Chat-Nachricht - Plan-Modus: Hint-Mechanismus dokumentiert - Key-Scanner: 4 Quellen (GitHub Code, Issues/PRs, HuggingFace, Serper) - API-Key pro Agent: Endpoints + Kein-Key-Option - ServerSettingsService in Service-Tabelle - session.js: currentAgentId dokumentiert - Streaming vs Non-Streaming: Sub-Agents ergänzt ARCHITECTURE_QUICK.md: - Multi-Agent Backend: SubAgentContext + Provider-Weiche - OpenAiService: Non-Streaming erwähnt - Chat-Pipeline: Key-Auflösung ergänzt - api_keys: Zuweisung pro Agent - Dashboard-Route: Sortierungs-Hinweis README.md: - Key-Scanner: 4 Quellen statt nur GitHub --- ARCHITECTURE.md | 137 +++++++++++++++++++++++++++++------------- ARCHITECTURE_QUICK.md | 21 ++++--- README.md | 2 +- 3 files changed, 109 insertions(+), 51 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 4e28dbe..d1b5717 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -126,7 +126,7 @@ gott/ │ ├── ChatModels.cs # ChatMessage, ChatRequest, AttachmentInfo/Block │ ├── ApiKeyRecord.cs # API-Key-Verwaltung (Provider, Name, Key, IsActive, Status, Plan, Usage, SourceUrl) │ ├── ScannedKeyRecord.cs # Gescannte GitHub-Keys (SourceUrl, Status, Plan, Usage, AdoptedApiKeyId) -│ └── ChatContext.cs # Runtime-Kontext für einen Chat + ReviewContext +│ └── ChatContext.cs # Runtime-Kontext für einen Chat + SubAgentContext │ ├── Services/ # Business-Logic │ ├── DatabaseService.cs # SQLite Schema, Migrationen, Core (partial class) @@ -153,8 +153,9 @@ gott/ │ ├── ImageService.cs # Bild-Resize + WebP-Konvertierung (512px + 256px Thumbnail) │ ├── StreamingTracker.cs # Tracking aktiver Streams + CancellationTokenSource für Stop │ ├── WorkspaceHelper.cs # Workspace-Pfad-Auflösung (relativ → absolut) -│ ├── KeyScannerService.cs # GitHub Code-Search nach geleakten API-Keys -│ └── AnthropicKeyChecker.cs # Anthropic Key-Validierung + Usage-Header-Auswertung +│ ├── KeyScannerService.cs # API-Key-Scanner (GitHub Code Search, GitHub Issues/PRs, HuggingFace Hub, Google/Serper) +│ ├── AnthropicKeyChecker.cs # Anthropic Key-Validierung + Usage-Header-Auswertung +│ └── ServerSettingsService.cs # Server-Settings Verwaltung (In-Memory-Cache + DB) │ ├── Endpoints/ # HTTP API (Minimal API) │ ├── AuthEndpoint.cs # Login, Logout, Me @@ -227,7 +228,7 @@ gott/ │ │ ├── archive.js # Archiv-Loading │ │ ├── reply.js # Reply/Quote-Handling │ │ ├── files.js # File-Upload, Workspace-Refs -│ │ ├── session.js # Session-Verwaltung +│ │ ├── session.js # Session-Verwaltung (currentSessionId, currentAgentId) │ │ ├── file-explorer.js # File-Explorer Komponente │ │ ├── avatar-editor.js # Wiederverwendbares Avatar-Editor-Modal │ │ ├── commands-ui.js # Custom-Commands UI @@ -332,8 +333,11 @@ TelegramBot (1) ─── (*) Session (via telegram_bot_id) | `cronjobs` | Geplante Tasks (cron expression, prompt, notify_session_id, is_enabled, last_run, next_run) | | `shared_messages` | Geteilte Nachrichten (Share-Token, Ablaufdatum) | | `telegram_bots` | Telegram Bots (bot_token, webhook_secret, name, is_public) – eigenständige Entität | -| `api_keys` | API-Keys pro Provider (key_id, provider, name, api_key, is_active, status, plan, usage_7d, usage_5h, source_url, checked_at) – nur ein Key pro Provider aktiv | +| `api_keys` | API-Keys (key_id, provider, name, api_key, is_active, status, plan, usage_7d, usage_5h, source_url, checked_at) – mehrere Keys pro Provider möglich, Zuweisung pro Agent über `agent_api_keys` | +| `agent_api_keys` | API-Key-Zuweisung pro User+Agent (user_id, agent_id, key_id) – ersetzt globales `users.selected_api_key_id` | | `scanned_keys` | Gescannte GitHub-Keys (scanned_key_id, api_key, source_url, status, plan, usage_7d, usage_5h, adopted_api_key_id, deleted) | +| `scanner_logs` | Scanner-Logs (timestamp, type, message, scanner, details) – Logs von Key-Scanner und Event-Scanner | +| `server_settings` | Server-Settings (key, value, type) – In-Memory-Cache über `ServerSettingsService` | | `message_embeddings` | Sentence-Embeddings für semantische Suche (message_id, vector BLOB, session_id, agent_id) | | `memory_file_embeddings` | Embeddings von Memory-Dateien (agent_id, file_path, chunk_index, vector BLOB) | @@ -413,7 +417,7 @@ RemoteConnectionManager → AuthService → DatabaseService → EnsureDefaultUse | `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), passive Usage-Aktualisierung nach jedem Request | -| `OpenAiService` | Singleton | OpenAI-kompatible Provider (Nvidia, Pollinations, Gemini) mit Tool-Calling, Streaming, Modell-Caching | +| `OpenAiService` | Singleton | OpenAI-kompatible Provider (Nvidia, Pollinations, Gemini) mit Tool-Calling, Streaming + Non-Streaming, Modell-Caching | | `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 + Reminder-Generierung | @@ -429,8 +433,9 @@ RemoteConnectionManager → AuthService → DatabaseService → EnsureDefaultUse | `KreaService` | Singleton | Krea API für Bildgenerierung, Job-Polling, Image-Download | | `ImageService` | Singleton | Bild-Resize + WebP-Konvertierung (512px + 256px Thumbnail) für Avatare und Session-Bilder | | `StreamingTracker` | Singleton | Trackt aktive Streams + CancellationTokenSource pro Session für Stop-Button | -| `KeyScannerService` | Singleton | GitHub Code-Search nach geleakten API-Keys (13 Sprachen, 24 Pfad-Extensions), Background-Scan | +| `KeyScannerService` | Singleton | API-Key-Scanner (GitHub Code Search, GitHub Issues/PRs, HuggingFace Hub, Google/Serper), täglicher Scan | | `AnthropicKeyChecker` | Static | Anthropic Key-Validierung via API-Request, Usage-Header-Auswertung (Plan, 7d/5h Usage) | +| `ServerSettingsService` | Singleton | Server-Settings Verwaltung (In-Memory-Cache + DB), Cleanup obsoleter Settings | ### Endpoints (API) @@ -509,7 +514,7 @@ Das Frontend ist eine **Single-Page Application** ohne Build-Step, komplett in V | Route | Page | Beschreibung | |--------------------------|---------------------|---------------------------| -| `#/` | `dashboard.js` | Session-Übersicht | +| `#/` | `dashboard.js` | Session-Übersicht (sortiert nach letzter Chat-Nachricht, Fallback: `updated_at`) | | `#/chat/{sessionId}` | `chat-page.js` | Chat-Ansicht | | `#/session/{sessionId}` | `session-page.js` | Session-Einstellungen | | `#/agent/{agentId}` | `agent-page.js` | Agent-Editor | @@ -539,7 +544,7 @@ Das Frontend ist eine **Single-Page Application** ohne Build-Step, komplett in V - **archive.js** – Archiv-Loading und -Rendering - **reply.js** – Reply/Quote-Handling (Set, Clear, Format) - **files.js** – File-Upload, Workspace-Refs -- **session.js** – Session-State-Management +- **session.js** – Session-State-Management (currentSessionId, currentAgentId, getCurrentAgentId()) - **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 @@ -573,7 +578,7 @@ Neben Anthropic Claude unterstützt Gott drei **OpenAI-kompatible Provider**. De | Prefix | Provider | Base-URL | API-Key | |--------|----------|----------|---------| -| (kein) | Anthropic Claude | `api.anthropic.com` | `AnthropicToken` | +| (kein) | Anthropic Claude | `api.anthropic.com` | via `agent_api_keys` (pro Agent zugewiesen) | | `nvidia:` | Nvidia (g4f.space Proxy) | `g4f.space/api/nvidia/v1` | keiner | | `pollinations:` | Pollinations | `text.pollinations.ai/openai` | keiner | | `gemini:` | Google Gemini | `generativelanguage.googleapis.com/v1beta/openai` | `GeminiApiKey` | @@ -589,7 +594,8 @@ Beim Server-Start werden verfügbare Modelle von den Provider-APIs geladen und i ### OpenAiService `OpenAiService` implementiert: -- **Streaming via SSE** (OpenAI-Format: `choices[0].delta`) +- **Streaming via SSE** (`StreamChat()`, OpenAI-Format: `choices[0].delta`) +- **Non-Streaming** (`ChatNonStreaming()`, für Telegram, Cronjobs, Sub-Agents – agentic loop mit Tool-Calling) - **Tool-Calling** (identische Tools wie AnthropicService) - **Agentic Loop** (Tool-Results → nächste Iteration) - **Gemini thought_signature** – wird aus `extra_content.google.thought_signature` gelesen, in DB persistiert (`MessageRecord.ThoughtSignature`), und beim History-Rebuild in `extra_content.google.thought_signature` zurückgesendet @@ -614,8 +620,9 @@ Der Chat-Flow von User-Input bis zur gerenderten Antwort: 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) Model-Routing: Anthropic → AnthropicService.StreamChat(), OpenAI-Provider (nvidia:/pollinations:/gemini:) → OpenAiService.StreamChat() + c) API-Key auflösen: `GetAgentApiKeyRecord(userId, agentId)` – Anthropic ohne Key → Fehler, OpenAI ohne Key → OK (keyless Provider) + d) ChatService.BuildHistoryFromDb() → vollständige Message-History + e) Model-Routing: Anthropic → AnthropicService.StreamChat(), OpenAI-Provider (nvidia:/pollinations:/gemini:) → OpenAiService.StreamChat() ↓ 4. Agentic Loop (AnthropicService oder OpenAiService): ┌─────────────────────────────────────────┐ @@ -680,8 +687,9 @@ Der Stop-Mechanismus arbeitet auf zwei Ebenen: ### 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. +- **Telegram**: Non-Streaming – Provider-Weiche: Anthropic → `AnthropicService.ChatNonStreaming()`, OpenAI → `OpenAiService.ChatNonStreaming()`. +- **Cronjobs**: Non-Streaming, wie Telegram. Provider wird aus dem Agent-Modell bestimmt. +- **Sub-Agents** (Preparer/Review/Finalizer): Anthropic → `RunAgentChat()` (Streaming mit SSE-Events), OpenAI → `OpenAiService.ChatNonStreaming()`. ### History-Optimierung @@ -943,7 +951,7 @@ Unlink ist **nur über das Web-UI** möglich (kein Telegram-Befehl). ### 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. +Telegram-Nachrichten werden **Provider-aware** verarbeitet: Anthropic → `AnthropicService.ChatNonStreaming()`, OpenAI-kompatibel → `OpenAiService.ChatNonStreaming()`. Die History wird genauso aus der DB aufgebaut wie beim Web-Chat. Antworten über 4096 Zeichen werden automatisch in Chunks aufgeteilt. ### Dashboard & Frontend @@ -977,7 +985,7 @@ Der `CronjobService` ist ein **BackgroundService** der minütlich nach fälligen 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 + d) Provider-Weiche: Anthropic → `AnthropicService.ChatNonStreaming()`, OpenAI → `OpenAiService.ChatNonStreaming()` e) Telegram-Benachrichtigung senden (auf Arbeits-Session) f) Optional: Zusammenfassung in Notify-Session schreiben + Telegram dort g) Nächste Ausführung berechnen + DB aktualisieren @@ -1160,7 +1168,7 @@ Die Logik ist **invertiert** gegenüber dem Review-Pattern: Jede Antwort wird au #### Backend-Flow (Preparer) 1. **ChatEndpoint** – Prüft ob `ctx.Preparer` vorhanden -2. **AnthropicService.RunPreparer()** – Ruft `RunAgentChat()` auf mit `agentType = "preparer"` +2. **AnthropicService.RunPreparer()** – Provider-Weiche: Anthropic → `RunAgentChat()`, OpenAI → `OpenAiService.ChatNonStreaming()` mit `agentType = "preparer"` 3. **Entscheidung** – `ShouldForward` prüft ob `[QUESTION]` im Text: - **Forward**: Aufbereiteter Text wird als `[Vorbereitet von AgentName]:`-User-Message in DB gespeichert, History wird neu geladen, StreamChat startet - **Rückfrage**: SSE `preparer_done` mit `forwarded: false`, Stream endet mit `stopReason: "preparer_query"`, User muss erneut eingeben @@ -1191,13 +1199,12 @@ Der Preparer bekommt einen speziellen Instruktionsblock an seinen System-Prompt 1. **ChatService.PrepareContext()** – Wenn `session.ReviewAgentId` gesetzt: - 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 - - `ReviewContext` mit Model, SystemPrompt, Tools, Agent-Referenz erstellen + - `SubAgentContext` mit ModelId, Provider, SystemPrompt, Workspace, ToolChoice, Agent erstellen 2. **ChatEndpoint** – Übergibt `ctx.Review` an `AnthropicService.StreamChat()` 3. **AnthropicService.StreamChat()** – Nach `end_turn` des Worker-Agents: - - Prüft ob `ReviewContext` vorhanden und `reviewRound < MaxReviewIterations` + - Prüft ob `Review`-SubAgentContext vorhanden und `reviewRound < MaxReviewIterations` - Ruft `RunReview()` auf 4. **RunReview()** – Orchestriert eine einzelne Review-Runde: @@ -1216,19 +1223,25 @@ Der Preparer bekommt einen speziellen Instruktionsblock an seinen System-Prompt - `continue` → nächste while-Loop-Iteration → Worker korrigiert → Review erneut - `reviewRound++` bis `MaxReviewIterations` erreicht -### ReviewContext / FinalizerContext (Model) +### SubAgentContext (Model) ```csharp -// Identische Struktur für Review und Finalizer -public class ReviewContext +// Einheitliche Struktur für Preparer, Review und Finalizer +public class SubAgentContext { - public string Model { get; set; } // Claude-Modell des Agents - public string SystemPrompt { get; set; } // Eigener System-Prompt - public AgentRecord Agent { get; set; } // Agent-Record für Name/Avatar - public List Tools { get; set; } // Tool-Definitionen - public int MaxReviewIterations { get; set; } // Max Runden (nur bei Review relevant) + public string ModelId { get; set; } // Modell-ID (z.B. "claude-sonnet-4-6" oder "deepseek-ai/deepseek-r1") + public string Provider { get; set; } // "" = Anthropic, "nvidia"/"openai"/etc. = OpenAI-kompatibel + public List SystemPrompt { get; set; } // Eigener System-Prompt + public string AgentId { get; set; } + public string Workspace { get; set; } + public bool UseMemory { get; set; } + public string WebSearchVersion { get; set; } + public string ToolChoice { get; set; } + public AgentRecord Agent { get; set; } // Agent-Record für Name/Avatar + public bool AllowUserChoice { get; set; } // Preparer-spezifisch + public int MaxReviewIterations { get; set; } // Review-spezifisch } -// ChatContext hat: ReviewContext Review + ReviewContext Finalizer +// ChatContext hat: SubAgentContext Preparer + SubAgentContext Review + SubAgentContext Finalizer ``` ### SSE-Events @@ -1284,16 +1297,17 @@ Der Finalizer wird **nach** dem Review (oder direkt nach dem Worker, falls kein 1. **ChatService.PrepareContext()** – Wenn `session.FinalizerAgentId` gesetzt: - Finalizer-Agent aus DB laden - - `FinalizerContext` aufbauen (analog zu `ReviewContext`: Model, SystemPrompt, Tools) + - `SubAgentContext` aufbauen (Model, Provider, SystemPrompt, Workspace, ToolChoice) 2. **AnthropicService.StreamChat()** – Nach Review-Phase (oder direkt nach Worker): - - Prüft ob `FinalizerContext` vorhanden + - Prüft ob `Finalizer`-SubAgentContext vorhanden - Ruft `RunFinalizer()` auf -3. **RunFinalizer()** – Baut Messages auf (gesamte Konversation + Finalisierungs-Anweisung), ruft `RunAgentChat()` auf (generische Methode, auch vom Review genutzt) +3. **RunFinalizer()** – Baut Messages auf (gesamte Konversation + Finalisierungs-Anweisung), Provider-Weiche wie bei RunPreparer/RunReview -4. **RunAgentChat()** – Generische Methode für Preparer/Review/Finalizer: - - Eigener API-Call an Claude mit Agent-Config +4. **RunAgentChat()** / **ChatNonStreaming()** – Provider-Weiche für Preparer/Review/Finalizer: + - **Anthropic:** Eigener API-Call an Claude mit Agent-Config (RunAgentChat, Streaming + Tool-Loop) + - **OpenAI-kompatibel:** `OpenAiService.ChatNonStreaming()` (Non-Streaming agentic loop mit Tool-Calling) - Tool-Loop mit SSE-Events (`{type}_text`, `{type}_tool_use`) - Antwort als Message in DB persistieren (mit `Tag = agentType`, wird aus API-History gefiltert) @@ -1395,6 +1409,7 @@ Folgende Blöcke werden **übersprungen**: Git-Commits. Der Tools-Block listet n ### Frontend - **Toggle**: `#planModeBtn` – wechselt `_planModeActive`, ändert Button-Styling + Placeholder-Text +- **Hint**: Bei aktivem Plan-Modus wird ein `` an jede User-Nachricht angehängt (Reminder: keine Dateien ändern, keine Shell-Befehle außer read-only, keine Commits) - **Chain-Meta**: Badge `📋 Plan-Modus` bei Chains die im Plan-Modus erstellt wurden - **System-Prompt-Modal**: Zeigt den angepassten System-Prompt wenn Plan-Modus aktiv - **Session-Wechsel**: Plan-Modus wird zurückgesetzt @@ -1582,6 +1597,8 @@ const editor = AvatarEditor.init({ ### Dashboard-Darstellung +Sessions werden nach der **letzten Chat-Nachricht** sortiert (neueste zuerst), nicht nach `updated_at`. Sessions ohne Nachrichten werden per `COALESCE` nach ihrem `updated_at` einsortiert. + Cards zeigen Avatare mit `transform: scale(S) translate(X%, Y%)` im `.card-image` Container (`overflow: hidden`). Die Helper `buildAgentCard()` und `buildSessionCard()` in `cards.js` nutzen `buildTransformStyle(scale, offsetX, offsetY)` dafür. --- @@ -1743,10 +1760,11 @@ API-Keys werden in der Datenbank verwaltet (Tabellen `api_keys` + `scanned_keys` ### Funktionsweise - **Mehrere Keys** pro Provider (z.B. `anthropic`) können gespeichert werden -- **Nur ein Key pro Provider** kann gleichzeitig aktiv sein -- **Aktivierung** deaktiviert automatisch alle anderen Keys desselben Providers -- **Live-Aktualisierung:** Bei Aktivierung/Deaktivierung wird der Token sofort im laufenden Service aktualisiert (kein Neustart nötig) +- **Zuweisung pro Agent:** Keys werden über `agent_api_keys` (user_id + agent_id → key_id) zugewiesen, nicht mehr global pro User +- **"Kein Key"-Option:** Key-Zuweisung kann entfernt werden – Anthropic-Modelle werden blockiert, keyless Provider (Pollinations, Nvidia) funktionieren weiterhin +- **Live-Aktualisierung:** Bei Änderung wird der Token sofort im laufenden Service aktualisiert (kein Neustart nötig) - **Migration:** Bestehender `AnthropicToken` aus `appsettings.Production.json` wird beim ersten Start automatisch migriert +- **Migration:** `users.selected_api_key_id` wird beim Start für alle Agents des Users in `agent_api_keys` übernommen - **Source-URL:** Bei adoptierten Scan-Keys wird die GitHub-URL gespeichert ### Key-Check (nur Anthropic) @@ -1760,12 +1778,45 @@ API-Keys werden in der Datenbank verwaltet (Tabellen `api_keys` + `scanned_keys` Nach **jedem** API-Request an Anthropic (Streaming, Sub-Agent, NonStreaming) werden die Response-Headers automatisch ausgelesen und Plan/Usage des aktiven API-Keys in der DB aktualisiert (`AnthropicKeyChecker.ExtractMetaFromHeaders()`). Kein separater Check-Request nötig – die Daten sind immer aktuell. -### GitHub-Scanner (`KeyScannerService`) +### API-Key pro Agent -Durchsucht GitHub Code-Search nach geleakten Anthropic API-Keys: +API-Keys werden **pro Agent** zugewiesen (Tabelle `agent_api_keys`), nicht mehr global pro User: +- **`PUT /api/api-keys/select/{keyId}?agentId=xxx`** – Key einem Agent zuweisen +- **`PUT /api/api-keys/select/none?agentId=xxx`** – Key-Zuweisung entfernen ("Kein Key") +- **`GET /api/api-keys/selected?agentId=xxx`** – Zugewiesenen Key abfragen +- **Ohne Key:** Chat mit Anthropic-Modellen blockiert, OpenAI-kompatible Modelle (z.B. Pollinations) funktionieren weiterhin +- **Migration:** Bestehende `users.selected_api_key_id` wird beim Start für alle Agents des Users in `agent_api_keys` kopiert + +### Key-Scanner (`KeyScannerService`) + +Durchsucht mehrere Quellen nach geleakten API-Keys: + +**Quellen:** + +| Quelle | Quick | Web | Full | +|---|---|---|---| +| GitHub Code Search | ✅ (reduziert) | ❌ | ✅ | +| GitHub Issues/PR Comments | ✅ (nur Body) | ❌ | ✅ (Body + Comments) | +| Serper/Google | ❌ | ✅ | ✅ | +| HuggingFace Hub | ❌ | ✅ | ✅ | + +**GitHub Code Search:** - **13 Sprachen** (Python, JavaScript, TypeScript, Shell, Markdown, JSON, YAML, TOML, Go, Rust, Ruby, Java, PHP) - **24 Pfad-Extensions** (.env, .cfg, .ini, .conf, .txt, .log, .md, .json, .yaml, .yml, .toml, .py, .js, .ts, .sh, .bash, .go, .rs, .rb, .java, .php, .config, .properties, .xml) -- **Ablauf:** `POST /api/admin/api-keys/scan` → GitHub-Suche → neue Keys in `scanned_keys` speichern → jeden Key mit `AnthropicKeyChecker` prüfen → Status + Plan + Usage aktualisieren + +**GitHub Issues/PR Comments:** +- Durchsucht Issue-Bodies nach Key-Patterns via GitHub Search API +- Im Full-Mode: Lädt zusätzlich alle Kommentare (max 100 Issues, je 100 Kommentare) +- Rate-Limiting: 2.5s Delay (Search), 1s Delay (Comments), 60s Pause bei 403 + +**HuggingFace Hub:** +- Durchsucht Spaces und Models nach API-Keys in Konfigurationsdateien +- Max 50 Dateien pro Repo, max 500 KB pro Datei +- Optionaler HuggingFace Token für höhere Rate-Limits + +**Zeitplanung:** `ScanDailyHour` (0-23 = täglicher Scan zur vollen Stunde, -1 = nur manuell) + +- **Ablauf:** `POST /api/admin/api-keys/scan` → Quellen durchsuchen → neue Keys in `scanned_keys` speichern → jeden Key mit `AnthropicKeyChecker` prüfen → Status + Plan + Usage aktualisieren - **Adopt:** `POST /api/admin/api-keys/scanned/{id}/adopt` → Key in `api_keys` übernehmen, Name = `user/repo`, Source-URL = vollständige GitHub-URL - **Live-Updates:** Scan-Ergebnisse werden nach jeder Iteration in der DB gespeichert (nicht erst am Ende) @@ -1775,7 +1826,7 @@ Durchsucht GitHub Code-Search nach geleakten Anthropic API-Keys: - **Farbstufen:** Grün (<70%), Orange (70-89%), Rot (≥90%) - **Auto-Hide:** Ausgeblendet beim Hochscrollen (wenn Auto-Scroll deaktiviert) - **Auto-Refresh:** Badge aktualisiert sich bei neuen Nachrichten (via `pollHistory`) -- **Key-Switch-Modal:** Klick auf Badge öffnet Modal mit allen API-Keys, Zeile klickbar zum Wechseln +- **Key-Switch-Modal:** Klick auf Badge öffnet Modal mit allen API-Keys + "Kein Key"-Option, Zeile klickbar zum Wechseln (pro Agent) - **Manueller Check:** 🔄-Button neben Badge prüft Key und aktualisiert --- @@ -1838,6 +1889,8 @@ Die `DatabaseService.InitializeDatabase()` handhabt Schema-Erstellung und Migrat 3. **Daten-Migration** (z.B. `auto_commit` von INTEGER zu TEXT, `use_web_search` zu `web_search_version`) 4. **Token-Migration** – Bestehender `AnthropicToken` aus `appsettings.Production.json` wird automatisch in `api_keys`-Tabelle migriert 5. **Bild-Migration** – Konvertierung bestehender PNG/JPEG-Avatare zu WebP + Generierung von Thumbnails (`avatar_small`, `image_small`) +6. **API-Key-Migration** – `users.selected_api_key_id` → `agent_api_keys` (pro Agent statt global pro User) +7. **Settings-Cleanup** – Obsolete Server-Settings (z.B. `ScanIntervalHours`) werden aus der DB entfernt Dieses Pattern ermöglicht: - Idempotente Ausführung bei jedem App-Start diff --git a/ARCHITECTURE_QUICK.md b/ARCHITECTURE_QUICK.md index 6a48234..c55614c 100644 --- a/ARCHITECTURE_QUICK.md +++ b/ARCHITECTURE_QUICK.md @@ -87,8 +87,11 @@ User 1──* TelegramBot 1──* Session (via telegram_bot_id) | `agent_skills` | N:M Agent ↔ Skill | | `shared_messages` | Geteilte Nachrichten (öffentliche Links via Share-Token) | | `telegram_bots` | Telegram Bots (BotToken, WebhookSecret, Name, IsPublic) – eigenständige Entität, 1 Bot → N Sessions | -| `api_keys` | API-Keys pro Provider (key_id, provider, name, api_key, is_active, status, plan, usage_7d, usage_5h, source_url) – nur ein Key pro Provider aktiv | +| `api_keys` | API-Keys (key_id, provider, name, api_key, is_active, status, plan, usage_7d, usage_5h, source_url) – mehrere Keys pro Provider möglich, Zuweisung pro Agent | +| `agent_api_keys` | API-Key-Zuweisung pro User+Agent (user_id, agent_id, key_id) – ersetzt globales `users.selected_api_key_id` | | `scanned_keys` | Gescannte GitHub-Keys (api_key, source_url, status, plan, usage_7d, usage_5h, adopted_api_key_id) | +| `scanner_logs` | Scanner-Logs (timestamp, type, message, scanner, details) | +| `server_settings` | Server-Settings (key, value, type) – verwaltet über `ServerSettingsService` | | `message_embeddings` | Sentence-Embeddings für semantische Suche (message_id, vector BLOB) | | `memory_file_embeddings` | Embeddings von Memory-Dateien (agent_id, file_path, chunk_index, vector BLOB) | @@ -130,7 +133,7 @@ User 1──* TelegramBot 1──* Session (via telegram_bot_id) | **AuthService** | Token-Auth, Passwort-Hashing (SHA256) | | **ChatService** | Chat-Kontext aufbauen, History aus DB laden | | **AnthropicService** | Claude API: SSE Streaming + Non-Streaming, passive Usage-Aktualisierung nach jedem Request | -| **OpenAiService** | OpenAI-kompatible Provider (Nvidia, Pollinations, Gemini) mit Tool-Calling, Streaming, Modell-Caching | +| **OpenAiService** | OpenAI-kompatible Provider (Nvidia, Pollinations, Gemini) mit Tool-Calling, Streaming (`StreamChat`) + Non-Streaming (`ChatNonStreaming` für Telegram/Cronjobs/Sub-Agents), Modell-Caching | | **SseHelper** | Shared SSE-Utilities: WriteSseEvent, TryWriteSse, FinalizeChain, TruncateToolResult (static) | | **ToolService** | Tool-Definitionen + Ausführung (17 Tools) | | **WorkspaceHelper** | Workspace-Pfad-Auflösung (relativ → absolut), Path-Traversal-Schutz (static) | @@ -146,8 +149,9 @@ User 1──* TelegramBot 1──* Session (via telegram_bot_id) | **EmbeddingBackgroundService** | Backfill bestehender Messages + Live-Embedding neuer Messages/Memory-Files | | **RemoteConnectionManager** | WebSocket-basierte Remote-Verbindungen, Command-Execution auf Remote-Clients | | **StreamingTracker** | Tracking aktiver Streams + CancellationTokenSource pro Session für Stop | -| **KeyScannerService** | GitHub-Code-Search nach geleakten API-Keys (13 Sprachen, 24 Pfad-Extensions) | +| **KeyScannerService** | API-Key-Scanner (GitHub Code Search, GitHub Issues/PRs, HuggingFace Hub, Google/Serper), täglicher Scan | | **AnthropicKeyChecker** | Key-Validierung via Anthropic API, Usage-Header-Auswertung (Plan, 7d/5h Usage) | +| **ServerSettingsService** | Server-Settings Verwaltung (In-Memory-Cache + DB), Cleanup obsoleter Settings | --- @@ -159,12 +163,13 @@ User-Input → POST /api/chat (SSE) → History aus DB laden (letzte N Chains) → SystemPromptBuilder: 11 Blöcke zusammensetzen (+ Plan-Modus/Preparer-Blöcke) → Tool-Definitionen vom ToolService holen (im Plan-Modus: nur Read-only) + → API-Key auflösen: GetAgentApiKeyRecord(userId, agentId) – Anthropic ohne Key → Fehler, keyless Provider → OK → Preparer-Phase (optional, wenn PreparerAgentId gesetzt): - → RunPreparer() → RunAgentChat(agentType: "preparer") + → RunPreparer() → Provider-Weiche: Anthropic → RunAgentChat(), OpenAI → ChatNonStreaming() → Antwort ohne [QUESTION] → automatisch weiterleiten (Default = Forward) → [QUESTION] → Rückfrage an User, Flow stoppt - → AnthropicService.StreamChat() - → Claude API Call (SSE) + → AnthropicService.StreamChat() / OpenAiService.StreamChat() + → API Call (SSE) → Token-für-Token an Client streamen → Bei tool_use → ToolService.Execute() → Ergebnis zurück → neuer API Call → Bei ask_user_choice → SSE user_choice Event → Flow stoppt (awaiting_user_choice) @@ -243,7 +248,7 @@ User-Input → POST /api/chat (SSE) | Hash-Route | Page-Datei | Beschreibung | |------------|-----------|--------------| -| `#/` | `dashboard.js` | Session-Übersicht | +| `#/` | `dashboard.js` | Session-Übersicht (sortiert nach letzter Chat-Nachricht) | | `#/chat/{id}` | `chat-page.js` | Chat (inkl. Usage-Badge-Overlay + Key-Switch-Modal) | | `#/session/{id}` | `session-page.js` | Session-Settings | | `#/agent/{id}` | `agent-page.js` | Agent-Editor | @@ -303,7 +308,7 @@ Eine Session kann bis zu **vier Agents** haben: Worker (Pflicht), Preparer (opti **Preparer:** Default = Forward (jede Antwort wird automatisch weitergeleitet, `[QUESTION]` stoppt). Bekommt eigene History mit `includeTag: "preparer"`. Aufbereiteter Prompt wird als `[Vorbereitet von AgentName]:` User-Message gespeichert. -**Backend:** `ChatService` baut `PreparerContext` + `ReviewContext` + `FinalizerContext`. `RunPreparer()` im ChatEndpoint (vor StreamChat). `RunReview()` + `RunFinalizer()` in AnthropicService. Alle nutzen `RunAgentChat()` (mit `Tag`-Markierung, Sub-Agent-Messages aus API-History gefiltert). +**Backend:** `ChatService` baut `SubAgentContext` für Preparer, Review und Finalizer. `RunPreparer()` im ChatEndpoint (vor StreamChat). `RunReview()` + `RunFinalizer()` in AnthropicService. Alle nutzen Provider-Weiche: Anthropic → `RunAgentChat()`, OpenAI → `ChatNonStreaming()` (mit `Tag`-Markierung, Sub-Agent-Messages aus API-History gefiltert). **SSE-Events:** - Preparer: `preparer_start`, `preparer_text`, `preparer_tool_use`, `preparer_done` diff --git a/README.md b/README.md index 5fe0f3b..f10bfc6 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Self-hosted AI-Coding-Agent mit **Anthropic Claude API** als Haupt-Provider sowi - **Bildgenerierung** – Krea AI Integration für Bildgenerierung - **Semantische Suche** – Lokale Sentence-Embeddings (all-MiniLM-L6-v2 ONNX) für `memory_search` über vergangene Nachrichten und Memory-Dateien - **Remote-Verbindungen** – WebSocket-basierte Remote-Clients (PowerShell), AI-Agent kann Befehle auf entfernten Rechnern ausführen -- **API-Key-Verwaltung** – Admin-UI zum Verwalten von API-Keys (Anthropic) inkl. Key-Check, GitHub-Scanner (geleakte Keys finden + übernehmen), passive Usage-Aktualisierung bei jeder Chat-Nachricht, Usage-Badge im Chat mit Key-Switch-Modal +- **API-Key-Verwaltung** – Admin-UI zum Verwalten von API-Keys (Anthropic) inkl. Key-Check, API-Key-Scanner (GitHub Code Search, GitHub Issues/PRs, HuggingFace Hub, Google/Serper), passive Usage-Aktualisierung bei jeder Chat-Nachricht, Usage-Badge im Chat mit Key-Switch-Modal (pro Agent) - **Nachrichten teilen** – Einzelne Nachrichten per öffentlichem Link teilen - **Archivierung** – Chat-Verläufe archivieren und durchsuchen - **OpenClaw Import** – Chatverlauf aus OpenClaw-Instanzen importieren