# Teams Meeting Bot -- Architektur ## Überblick AI-gesteuerter Meeting-Bot für Microsoft Teams. Tritt Meetings als regulärer Teilnehmer bei (Browser-Automation via Playwright/Chromium), erfasst Live-Transkripte, reagiert per Sprache (TTS) und/oder Chat. Kein Teams-Graph-SDK nötig -- funktioniert mandantenübergreifend ohne Admin-Approval. ## System-Architektur ``` ┌────────────┐ SSE ┌──────────────┐ WebSocket ┌─────────────┐ │ Frontend │◄──────────────│ Gateway │◄───────────────│ Bot Service │ │ (Nyla UI) │ │ (AI, TTS, │ HTTP (join/ │ (Playwright │ │ │ │ Sessions) │ leave) │ Chromium) │ └────────────┘ └──────────────┘ └─────────────┘ ``` | Verbindung | Protokoll | Zweck | |------------|----------|-------| | Gateway ↔ Bot | WebSocket | Echtzeit: Transkripte, Chat, Audio, Status | | Gateway → Bot | HTTP | Session-Steuerung (join, leave, status) | | Frontend ← Gateway | SSE | Live-Transkript-Stream für UI | ## Kernfähigkeiten - **Live Transcription:** Erfasst Untertitel mit Sprecher-Zuordnung, streamt via SSE - **AI-Analyse:** Transkript-Segmente werden durch AI-Modell (GPT-4o-mini / Claude) analysiert - **Voice Response:** TTS-Audio wird über den Mikrofon-Kanal ins Meeting gespielt - **Chat Response:** Bot kann Chat-Nachrichten ins Meeting schreiben - **Multi-Session:** Mehrere Bot-Instanzen parallel in verschiedenen Meetings ## Use Cases | UC | Beschreibung | |----|-------------| | AI Meeting Assistant | Bot nimmt teil, hört zu, antwortet auf Ansprache ("Hey Nyla, ...") | | Live Transcription | Echtzeit-Transkript-Stream für Teilnehmer ausserhalb des Meetings | | Meeting Summary | AI-generierte Zusammenfassung nach Meeting-Ende | | Multi-Bot | Mehrere parallele Sessions in verschiedenen Meetings | | Director Prompts | Operator gibt dem laufenden Bot **private** Regieanweisungen (One-Shot oder Persistent), Antwort wird ins Meeting eingespielt | | Hybrid Agent Escalation | SPEECH_TEAMS-Pfad kann komplexe Anfragen via `needsAgent=true` an den vollen Agent (`agentService.runAgent`) eskalieren | ## Integration mit Gateway Der Gateway (Feature `teamsbot`) verwaltet Sessions und stellt die AI-Pipeline bereit: - Session-Lifecycle: erstellen, starten, stoppen - WebSocket-Verbindung pro Session - AI-Analyse der Transkript-Segmente via `serviceAi` - TTS-Generierung für Voice-Responses ## Schlüssel-Dateien | Datei / Bereich | Rolle | |-----------------|-------| | `gateway/modules/features/teamsbot/` | Gateway-seitiges Feature-Modul | | `service-teams-browser-bot/` | Eigenständiger Bot-Service (separates Repository) | ## Regeln / Invarianten - Bot tritt als **regulärer Web-Teilnehmer** bei (Browser-Automation), nicht via Graph Communications SDK - Jede Session läuft in einer **eigenen Browser-Instanz** (Isolation) - Authentifizierter Join (mit Microsoft-Account) oder Anonymous Guest -- je nach Konfiguration - Gateway ist die **einzige** Schnittstelle für AI-Aufrufe und TTS -- der Bot-Service selbst hat keine AI-Logik ## Hybrid-Routing: SPEECH_TEAMS + Agent Der Teamsbot läuft auf zwei kooperierenden Pfaden: ```mermaid flowchart LR Audio["Meeting Audio"] --> STT["STT"] STT --> ST["SPEECH_TEAMS
(fast, low-latency)"] ST -->|shouldRespond=true| TTS["TTS + Chat"] ST -->|needsAgent=true| Agent["agentService.runAgent
(toolSet=core, web=on,
maxRounds=5, maxCostCHF=0.10)"] Agent -->|FINAL text| TTS UI["Operator UI
(Regie-Panel + UDB)"] -->|POST directorPrompt| Route["routeFeatureTeamsbot"] Route -->|submitDirectorPrompt| Svc["TeamsbotService
(_activeServices)"] Svc -->|asyncio.create_task| Agent TTS --> Meeting Svc -->|SSE 'directorPrompt'| UI ``` - **`SPEECH_TEAMS`** bleibt der Default-Pfad mit niedrigster Latenz. Der dazugehörige System-Prompt erlaubt dem Modell explizit, `needsAgent=true` + `agentReason` zu setzen, wenn die Anfrage Web-Recherche, Mail oder Multi-Step-Tools erfordert. - **Director Prompts** umgehen `SPEECH_TEAMS` komplett und feuern direkt einen `runAgent`-Lauf, dessen `FINAL`-Event-Text wieder über die bestehenden TTS-/Chat-Kanäle ins Meeting geliefert wird. ## Director Prompts (private Operator-Anweisungen) Operator-Prompts sind **privat** (nur per SSE an den Session-Owner sichtbar) und werden in PostgreSQL gespeichert (`poweron_teamsbot.TeamsbotDirectorPrompt`). | Modus | Verhalten | |---|---| | `oneShot` | Einmaliger Agent-Lauf, danach Status `consumed` | | `persistent` | Agent-Lauf wird ausgeführt **und** der Text wird als `OPERATOR_DIRECTIVES`-Block in jeden folgenden `SPEECH_TEAMS`-Trigger eingemischt, bis der Operator den Prompt löscht | | Lifecycle-Status | Bedeutung | |---|---| | `queued` | Eingereicht, Agent noch nicht gestartet | | `running` | Agent läuft | | `succeeded` | Agent fertig, persistent bleibt aktiv | | `consumed` | One-Shot abgeschlossen oder persistent gelöscht | | `failed` | Agent-Lauf fehlgeschlagen, persistent wird automatisch aus aktiven Direktiven entfernt | **Persistenz beim Reconnect:** Bei jedem WebSocket-Reconnect ruft der Service `interface.getActivePersistentPrompts(sessionId)` auf und füllt `_activePersistentPrompts` neu, damit Direktiven Network-Drops überleben. **Limits:** `DIRECTOR_PROMPT_TEXT_LIMIT = 8000` Zeichen, `DIRECTOR_PROMPT_FILE_LIMIT = 10` UDB-Dateien (Pflicht-Prüfung in der Route, validiert auch von `TeamsbotDirectorPromptCreateRequest`). **RBAC:** Routes prüfen `_validateInstanceAccess` + `_validateSessionOwnership`. Ein Nicht-Owner sieht 404, niemals 403, um die Existenz der Session nicht preiszugeben. **Rate-Limit:** `30/minute` pro Operator (slowapi). ## Schicht-Trennung (Plan #5 abgeschlossen 2026-04-24) | Verantwortung | Datei | |---|---| | Persistenz + Lifecycle | `interfaceFeatureTeamsbot.py` (`createDirectorPrompt`, `getActivePersistentPrompts`, `updateDirectorPrompt`, `deleteDirectorPrompt`) | | Orchestrierung + Agent-Lauf + SSE | `service.py` (`submitDirectorPrompt`, `_processDirectorPrompt`, `_runAgentForMeeting`, `_buildPersistentDirectorContext`, `removePersistentPrompt`) | | HTTP + RBAC + Limits | `routeFeatureTeamsbot.py` (POST/GET/DELETE `/sessions/{id}/directorPrompts`) | | Frontend Regie-Panel + UDB-Sidebar + SSE-Listener | `frontend_nyla/src/pages/views/teamsbot/TeamsbotSessionView.tsx` + `Teamsbot.module.css` | | Frontend API-Wrapper | `frontend_nyla/src/api/teamsbotApi.ts` (`submitDirectorPrompt`, `listDirectorPrompts`, `deleteDirectorPrompt`) | | Tests | `gateway/tests/unit/teamsbot/test_directorPrompts.py` (26 Tests, AC 5 + 6 abgedeckt; AC 1–4 manuell live) |