7.2 KiB
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:
flowchart LR
Audio["Meeting Audio"] --> STT["STT"]
STT --> ST["SPEECH_TEAMS<br/>(fast, low-latency)"]
ST -->|shouldRespond=true| TTS["TTS + Chat"]
ST -->|needsAgent=true| Agent["agentService.runAgent<br/>(toolSet=core, web=on,<br/>maxRounds=5, maxCostCHF=0.10)"]
Agent -->|FINAL text| TTS
UI["Operator UI<br/>(Regie-Panel + UDB)"] -->|POST directorPrompt| Route["routeFeatureTeamsbot"]
Route -->|submitDirectorPrompt| Svc["TeamsbotService<br/>(_activeServices)"]
Svc -->|asyncio.create_task| Agent
TTS --> Meeting
Svc -->|SSE 'directorPrompt'| UI
SPEECH_TEAMSbleibt der Default-Pfad mit niedrigster Latenz. Der dazugehörige System-Prompt erlaubt dem Modell explizit,needsAgent=true+agentReasonzu setzen, wenn die Anfrage Web-Recherche, Mail oder Multi-Step-Tools erfordert.- Director Prompts umgehen
SPEECH_TEAMSkomplett und feuern direkt einenrunAgent-Lauf, dessenFINAL-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) |