# Teamsbot Regieanweisungen (Director Prompts) ## Beschreibung und Kontext Der Teamsbot laeuft heute auf einem hochspezialisierten, schnellen Pfad (`OperationTypeEnum.SPEECH_TEAMS`), der reaktiv auf Sprache reagiert. Der Operator soll dem Bot waehrend des Meetings *privat* Anweisungen geben koennen ("Recherchiere das gerade diskutierte Thema und gib eine Empfehlung", "Lies die Datei XY vor", "Schreib das ins Chat"). Diese **Regieanweisungen** sind fuer die anderen Teilnehmer unsichtbar und triggern den Bot sofort, unabhaengig von Cooldowns oder Sprach-Triggern. Long-term-clean: Voller Agent-Pfad mit RAG, Datenschnittstellen, Toolboxen. ## Fokus und kritische Details - **Hybrid-Routing**: `SPEECH_TEAMS` bleibt der schnelle Default-Pfad. Der Agent (`agentService.runAgent`) wird nur fuer (a) Director Prompts und (b) `SPEECH_TEAMS`-Eskalation (`needsAgent=true`) verwendet. - **Privacy**: Director-Prompts werden in der DB gespeichert und ueber SSE ausschliesslich an den Operator (Eigentuemer der Session) ausgeliefert. - **Kein neues Teamsbot-Toolset**: Der Agent verwendet bestehende Core-Tools (`webSearch`, `readUrl`, `sendMail`, `renderDocument`, `requestToolbox`, Datenschnittstellen-Tools etc.). Sein finaler `FINAL`-Event-Text wird wie eine `SPEECH_TEAMS`-Antwort ueber TTS+Chat ans Meeting ausgeliefert. - **Persistenz**: Persistente Director-Prompts werden bei jedem Trigger (SPEECH_TEAMS und neuer Director-Prompt) als zusaetzlicher Kontext in den System-Prompt gemischt, bis der Operator sie loescht. - **Service-Registry**: Damit eine HTTP-Route auf die laufende WS-Session zugreifen kann, registriert `handleBotWebSocket` den `TeamsbotService` mit `websocket` + `voiceInterface` modul-weit. ## Ziel und Nicht-Ziele - Ziel: Operator kann private Text-Prompts (mit optional UDB-Files) an den laufenden Bot senden; Bot fuehrt Agent-Run aus, antwortet ins Meeting per TTS/Chat und kann Tools (Web, Mail, SharePoint, ...) nutzen. - Ziel: SPEECH_TEAMS kann selbststaendig signalisieren `needsAgent=true`, damit komplexe Spoken-Requests (z. B. "recherchier das im Internet") den Agent triggern, statt nur eine Floskel zurueckzugeben. - Nicht-Ziel: Eigene Teamsbot-spezifische Tools fuer den Agent (sendChat, readAloud) — diese bleiben im SPEECH_TEAMS-Pfad als `commands`. Der Agent spricht nur ueber seinen Final-Text, der vom Service ausgeliefert wird. - Nicht-Ziel: PDF-Anhang in Teams-Chat (Browser-Bot-Limit). Stattdessen wird der vom Agent generierte Link gepostet. ## Betroffene Module - Gateway: `modules/features/teamsbot/datamodelTeamsbot.py`, `interfaceFeatureTeamsbot.py`, `service.py`, `routeFeatureTeamsbot.py`, `modules/serviceCenter/services/serviceAi/mainServiceAi.py` - Frontend: `src/api/teamsbotApi.ts`, `src/pages/views/teamsbot/TeamsbotSessionView.tsx`, `src/pages/views/teamsbot/Teamsbot.module.css` - DB-Migration: ja (neue Tabelle `teamsbotDirectorPrompts` via `registerDatabase`/Auto-Migrate) - Andere: `service-teams-browser-bot` — keine Aenderungen (Agent nutzt bestehende WS-Commands `sendChatMessage`, `playAudio`). ## Architektur ```mermaid flowchart LR UI["Operator UI (Regie-Panel + UDB)"] -- POST directorPrompt --> Route["routeFeatureTeamsbot"] Route -- submitDirectorPrompt --> Svc["TeamsbotService (active)"] Svc -- runAgent --> Agent["agentService.runAgent (toolSet=core, web aktiv, maxRounds=5)"] Agent -- FINAL text --> Svc Svc -- TTS+sendChatMessage --> WS["Browser Bot (WS)"] WS -- audio/chat --> Meeting Audio["Meeting Audio"] --> STT["STT"] STT --> SpeechTeams["SPEECH_TEAMS (fast)"] SpeechTeams -- needsAgent? --> Agent SpeechTeams -- direct text/commands --> Svc ``` ## Entscheidungen | Datum | Entscheidung | Begruendung | |------------|-------------------------------------------------|-------------| | 2026-04-23 | Hybrid-Routing SPEECH_TEAMS + Agent | Latenz fuer Reaktivitaet, Funktionalitaet fuer Komplexes | | 2026-04-23 | Kein eigenes Teamsbot-Toolset im Agent | Agent-Final-Text wird wie SPEECH_TEAMS-Text ausgeliefert; vermeidet Tool-Duplikation | | 2026-04-23 | `web`-Toolbox als Default + `requestToolbox` aktiv | Recherche ist Standard, andere Toolboxen on-demand | | 2026-04-23 | `maxRounds=5`, `maxCostCHF=0.10` | Live-Performance + Kosten-Cap | | 2026-04-23 | UDB-Sidebar wie in CommcoachDossierView | Bestehendes Muster, Files via fileIds | ## Umsetzungs-Checkliste - [x] Datamodel `TeamsbotDirectorPrompt` + `SpeechTeamsResponse.needsAgent` - [x] Interface CRUD + DB-Registrierung - [x] `_activeServices` Registry + WS/Voice auf Instanz - [x] `submitDirectorPrompt` + `_processDirectorPrompt` (Agent-Call + Delivery) - [x] Persistente Prompts beim Reconnect aus DB laden - [x] Hybrid: `_analyzeAndRespond` triggert Agent bei `needsAgent=true` - [x] `_buildSpeechTeamsSystemPrompt` um `needsAgent`-Felder erweitern - [x] Routes `POST/GET/DELETE /sessions/{id}/directorPrompts` - [x] Frontend API + SSE-Event-Type - [x] Frontend UDB-Sidebar + Regie-Panel + CSS - [x] RBAC: nur Session-Owner darf submitten/listen/loeschen (`_validateInstanceAccess` + `_validateSessionOwnership`) - [x] Neutralisierung: Director-Prompt-Text geht durch Standard-AiService -> automatisch im Scope - [x] Navigation: keine neue Route, nur Panel in TeamsbotSessionView - [x] Billing: laeuft ueber `agentService.runAgent` (Standard-Billing) und `aiService.callAi` (SPEECH_TEAMS Billing); kein neuer Pfad - [x] Unit-Tests (26 Tests, T5 + AC 5 + AC 6 abgedeckt) - [x] b-reference + TOPICS.md aktualisiert ## Akzeptanzkriterien | # | Kriterium (Given-When-Then) | Prio | |---|-----------------------------|------| | 1 | Given laufendes Meeting, When Operator sendet One-Shot Prompt "Was ist die Hauptstadt von Frankreich?", Then Bot antwortet im Meeting per Voice "Paris" innerhalb 10s | must | | 2 | Given laufendes Meeting + UDB-File ausgewaehlt, When Operator sendet Prompt "Fasse das ausgewaehlte Dokument zusammen", Then Bot liest Datei via `readFile`, fasst zusammen, antwortet Voice+Chat | must | | 3 | Given laufendes Meeting, When Operator sendet Persistent-Prompt "Antworte immer in Englisch", Then jede folgende SPEECH_TEAMS-Antwort ist auf Englisch, bis Operator den Prompt loescht | must | | 4 | Given Sprecher sagt "Nyla, recherchier was im Internet ueber SBB Schweiz", When SPEECH_TEAMS verarbeitet, Then `needsAgent=true` und Agent uebernimmt mit `webSearch`, antwortet ueber TTS | must | | 5 | Given Operator sendet Prompt mit fileIds=[A,B,C], When Limit DIRECTOR_PROMPT_FILE_LIMIT (10) ueberschritten oder Text > 8000 Zeichen, Then Route gibt 400 zurueck | must | | 6 | Given anderer User (nicht Owner) ruft GET /directorPrompts auf, Then 404 | must | ## Testplan | ID | AC | Art | Automatisiert | Repo-Pfad | Status | |----|----|-----|---------------|-----------|--------| | T1 | 1 | manual e2e | nein | live meeting | pending (manual) | | T2 | 2 | manual e2e | nein | live meeting | pending (manual) | | T3 | 3 | manual e2e | nein | live meeting | pending (manual) | | T4 | 4 | manual e2e | nein | live meeting | pending (manual) | | T5 | 5,6| api unit | ja | gateway/tests/unit/teamsbot/test_directorPrompts.py | done (26 Tests) | ## Links - PR: TBD - Issue: TBD ## Abschluss - [x] `wiki/b-reference/teams-bot/architecture.md` (Director Prompts + Hybrid + Tool-Set) - [x] `wiki/b-reference/gateway/ai-agent.md` (kein neues Teamsbot-Toolset, Hybrid-Routing) - [x] `wiki/TOPICS.md` (Teams-Bot-Eintrag um Director Prompts ergaenzt + neuer Aktive-Arbeiten-Eintrag) - [x] Diesen Plan nach `4-done/` verschieben