wiki/b-reference/teams-bot/architecture.md
ValueOn AG ef83e58a85 upd
2026-05-11 18:41:56 +02:00

142 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- status: canonical -->
<!-- lastReviewed: 2026-05-11 -->
<!-- verifiedAgainst: service-teams-browser-bot (documentation review 2026-02-18); gateway/modules/features/teamsbot/{service,routeFeatureTeamsbot,interfaceFeatureTeamsbot,datamodelTeamsbot}.py + `GET /api/teamsbot/{instanceId}/dashboard/stream` (2026-05-11); gateway/tests/unit/teamsbot/test_directorPrompts.py (Director Prompts 2026-04-24); gateway Voice STT batch + linear16 (2026-05-10); frontend_nyla TeamsbotDashboardView / TeamsbotModulesView / TeamsbotSessionView (IA + SSE 2026-05-11) -->
# 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; Dashboard-Push (`dashboard/stream`) |
## Nyla UI (MeetingModule-IA)
Die Feature-Oberfläche ist in **fünf Tabs** strukturiert (siehe auch `wiki/c-work/2-build/2026-04-teamsbot-greenfield-ia-and-live-update.md`):
| Tab | Route-Segment | Zweck |
|-----|----------------|--------|
| Dashboard | `dashboard` | KPIs, Modul-Aktivität, Quick-Actions; Daten per **SSE** `GET /api/teamsbot/{instanceId}/dashboard/stream` (Snapshots `sessions` + `modules`, Intervall 3 s bei aktiver eigener Sitzung, sonst 20 s) |
| Assistent | `assistant` | Wizard: Modul wählen/anlegen, Meeting-Link, Join-Modus (Systembot / Gast / Mein Account), optional Sitzungskontext → startet Session und navigiert zur Live-Ansicht |
| Module | `modules` | CRUD `TeamsbotMeetingModule`, aufklappbare Session-Liste pro Modul; **Deep-Link** `?moduleId=<uuid>` klappt das Modul auf und scrollt es ins Sichtfeld |
| Live-Session | `sessions` | Regie-Panel, UDB, Transkript, SSE `sessions/{id}/stream`; **MFA** (`mfaChallenge` / `mfaResolved`) wird hier über dieselbe SSE-Verbindung abgewickelt |
| Einstellungen | `settings` | Bot-Stimme, User-Settings, System-Bots (SysAdmin) |
**Datenmodell:** `TeamsbotMeetingModule` gruppiert Reihen; `TeamsbotSession.moduleId` verknüpft optional (Adhoc ohne Modul). Standard-Meeting-Link und Standard-Bot-Name pro Modul für Prefill im Assistenten.
## 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
- **Dashboard-SSE:** `GET /api/teamsbot/{instanceId}/dashboard/stream` — wiederholte JSON-Events `{ "type": "dashboardState", "sessions": [...], "modules": [...] }` mit gleicher Sichtbarkeit wie `GET /sessions` (eigene Sessions, ausser Platform-Admin sieht alle).
## Schlüssel-Dateien
| Datei / Bereich | Rolle |
|-----------------|-------|
| `gateway/modules/features/teamsbot/` | Gateway-seitiges Feature-Modul (inkl. `dashboard/stream`, Session-SSE, Module-CRUD) |
| `frontend_nyla/src/pages/views/teamsbot/` | Dashboard (SSE), Assistent, Module, Live-Session, Einstellungen |
| `frontend_nyla/src/api/teamsbotApi.ts` | u.a. `createDashboardStream`, `createSessionStream`, Module-API |
| `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
**STT auf dem Gateway:** Meeting-Audio-Chunks (WebSocket `audioChunk`, PCM) werden pro Chunk mit `VoiceObjects.speechToText` transkribiert (Batch `recognize`, gemeinsamer Connector mit CommCoach). Konfiguration u. a. `audioFormat=linear16`, `skipFallbacks=True`; Details und Modell-Defaults: [voice-google.md](../gateway/voice-google.md).
## 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<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_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 14 manuell live) |