docs: crear issues 0036-0041 — nuevas features del sistema
Issues planificados: - 0036: Claude Code streaming de progreso en Matrix - 0037: Agente que crea otros agentes/bots via Matrix - 0038: Webapps y dashboards embebidos en Element via widgets - 0039: Recordatorios dinámicos y crons que invocan agentes - 0040: Soporte para mensajes de voz (audio → STT) - 0041: Videollamadas con agentes via LiveKit Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,282 @@
|
||||
# 0041 — Videollamadas con agentes via LiveKit (Element Call)
|
||||
|
||||
**Estado:** pendiente
|
||||
|
||||
## Objetivo
|
||||
|
||||
Permitir que los agentes se unan a llamadas de voz y video iniciadas desde Element, participando como interlocutores conversacionales en tiempo real. El agente captura el audio de la llamada, lo transcribe en tiempo real (streaming STT), genera respuestas via LLM, y habla de vuelta usando TTS — creando una experiencia de IA interactiva por voz dentro de las llamadas de Element.
|
||||
|
||||
## Contexto
|
||||
|
||||
- Element usa LiveKit como backend para llamadas de voz/video via MatrixRTC (Element Call)
|
||||
- El proyecto ya usa `github.com/sashabaranov/go-openai` que incluye soporte para Whisper (STT) y TTS APIs
|
||||
- Existe un issue planificado (0040) para soporte de mensajes de voz con STT — este issue reutiliza la interfaz `Transcriber` definida alli
|
||||
- LiveKit tiene un SDK oficial para Go: `github.com/livekit/server-sdk-go` para interaccion server-side con rooms y tracks de audio/video
|
||||
- No existe actualmente ninguna forma de que los agentes participen en llamadas — solo responden a mensajes de texto
|
||||
- El flujo MatrixRTC funciona asi: Element crea un estado MatrixRTC en la room Matrix (events tipo `m.call.member`), lo que genera una sesion en el servidor LiveKit donde los participantes se conectan via WebRTC
|
||||
- Esta feature es compleja y multi-faceted — se recomienda implementar en sub-issues independientes
|
||||
|
||||
## Arquitectura
|
||||
|
||||
### Flujo principal
|
||||
|
||||
```
|
||||
Usuario inicia llamada en Element (1:1 o grupo)
|
||||
→ Element crea estado MatrixRTC en la room
|
||||
→ Event m.call.member llega al listener del agente
|
||||
→ Agent detecta llamada activa → obtiene credenciales LiveKit
|
||||
→ shell/livekit/ conecta al LiveKit room como participante
|
||||
→ Audio pipeline:
|
||||
Audio track entrante → Buffer/VAD → STT (Transcriber)
|
||||
→ Texto transcrito → LLM del agente → Respuesta texto
|
||||
→ TTS (Synthesizer) → Audio track saliente → LiveKit room
|
||||
→ Usuario escucha la respuesta del agente
|
||||
→ Ciclo continua hasta que se cuelga la llamada
|
||||
```
|
||||
|
||||
### Pure core / impure shell
|
||||
|
||||
```
|
||||
pkg/tts/types.go → PURO: interfaz Synthesizer, tipos de audio
|
||||
shell/livekit/client.go → IMPURO: conexion LiveKit, join/leave rooms
|
||||
shell/livekit/audio.go → IMPURO: captura y publicacion de audio tracks
|
||||
shell/livekit/pipeline.go → IMPURO: orquestacion STT → LLM → TTS
|
||||
shell/tts/openai.go → IMPURO: cliente OpenAI TTS API
|
||||
shell/matrix/listener.go → IMPURO (MOD): deteccion de eventos de llamada
|
||||
internal/config/schema.go → PURO (MOD): tipos LiveKitCfg, TTSCfg
|
||||
devagents/runtime.go → COMPOSICION (MOD): inicializar LiveKit, wiring
|
||||
```
|
||||
|
||||
La logica pura se limita a tipos e interfaces. Todo el I/O real (LiveKit, STT, TTS, LLM) vive en `shell/`. Las reglas del agente no cambian — la decision de unirse a una llamada es un comportamiento del runtime, no de las reglas de decision.
|
||||
|
||||
### Archivos afectados
|
||||
|
||||
```
|
||||
shell/livekit/ NEW — paquete LiveKit
|
||||
shell/livekit/client.go NEW — cliente LiveKit: connect, join room, leave, lifecycle
|
||||
shell/livekit/audio.go NEW — captura audio track entrante, publish audio track saliente
|
||||
shell/livekit/pipeline.go NEW — orquestacion del pipeline STT → LLM → TTS
|
||||
shell/tts/ NEW — paquete TTS
|
||||
shell/tts/openai.go NEW — implementacion OpenAI TTS API (tts-1, voces)
|
||||
pkg/tts/ NEW — tipos puros de TTS
|
||||
pkg/tts/types.go NEW — interfaz Synthesizer, AudioFormat, VoiceConfig
|
||||
shell/matrix/listener.go MOD — detectar eventos m.call.member / MatrixRTC
|
||||
internal/config/schema.go MOD — anadir LiveKitCfg, TTSCfg al schema de config
|
||||
devagents/runtime.go MOD — inicializar cliente LiveKit, conectar call handling
|
||||
```
|
||||
|
||||
## Tareas
|
||||
|
||||
**Nota**: este es un feature multi-issue. Cada fase deberia convertirse en un sub-issue independiente (ver seccion "Desglose multi-issue" mas abajo).
|
||||
|
||||
### Fase 1 — Cliente LiveKit + deteccion de llamadas
|
||||
|
||||
- [ ] **1.1** Anadir dependencia `github.com/livekit/server-sdk-go` al modulo Go
|
||||
- [ ] **1.2** Crear `shell/livekit/client.go`: conexion al servidor LiveKit, join room como participante, leave room, manejo de reconexion
|
||||
- [ ] **1.3** Anadir `LiveKitCfg` a `internal/config/schema.go`: `ServerURL`, `APIKeyEnv`, `APISecretEnv`, `Enabled`, `AutoJoinCalls`
|
||||
- [ ] **1.4** Modificar `shell/matrix/listener.go` para detectar eventos MatrixRTC (`m.call.member` state events) y notificar al runtime
|
||||
- [ ] **1.5** Implementar auto-join: cuando se detecta una llamada activa en una room donde el agente esta presente, obtener token LiveKit y unirse como participante de audio
|
||||
- [ ] **1.6** Tests: conexion y join de room con servidor LiveKit mock o de prueba
|
||||
|
||||
### Fase 2 — Captura de audio + STT
|
||||
|
||||
- [ ] **2.1** Implementar captura de audio track desde el LiveKit room participant en `shell/livekit/audio.go`
|
||||
- [ ] **2.2** Buffer de chunks de audio para procesamiento STT (formato Opus → PCM si es necesario)
|
||||
- [ ] **2.3** Integrar con STT del issue 0040 — reutilizar interfaz `Transcriber` para transcribir audio capturado
|
||||
- [ ] **2.4** Implementar Voice Activity Detection (VAD) para detectar cuando el usuario deja de hablar (silencio > umbral configurable)
|
||||
- [ ] **2.5** Tests: pipeline de captura de audio con datos de prueba
|
||||
|
||||
### Fase 3 — TTS
|
||||
|
||||
- [ ] **3.1** Definir `pkg/tts/types.go`: interfaz `Synthesizer` con `Synthesize(ctx context.Context, text string) ([]byte, error)`, tipos `AudioFormat`, `VoiceConfig`
|
||||
- [ ] **3.2** Implementar `shell/tts/openai.go`: cliente OpenAI TTS API (modelo `tts-1`, voces: alloy, echo, fable, onyx, nova, shimmer)
|
||||
- [ ] **3.3** Anadir `TTSCfg` a `internal/config/schema.go`: `Enabled`, `Provider`, `Model`, `Voice`, `Speed`, `APIKeyEnv`
|
||||
- [ ] **3.4** Convertir output de TTS al formato que LiveKit espera (PCM/Opus) si es necesario
|
||||
- [ ] **3.5** Publicar audio track con la voz sintetizada al LiveKit room
|
||||
- [ ] **3.6** Tests: TTS con mock del API de OpenAI
|
||||
|
||||
### Fase 4 — Pipeline completo
|
||||
|
||||
- [ ] **4.1** Orquestar pipeline en `shell/livekit/pipeline.go`: audio entrante → STT → LLM → TTS → audio saliente
|
||||
- [ ] **4.2** Manejar flujo conversacional: usuario habla → pausa (VAD) → agente responde → vuelve a escuchar
|
||||
- [ ] **4.3** Manejo de interrupciones: si el usuario habla mientras el agente esta hablando, detener TTS y escuchar
|
||||
- [ ] **4.4** Optimizacion de latencia: iniciar TTS conforme los tokens del LLM van llegando (streaming TTS)
|
||||
- [ ] **4.5** Conectar pipeline al runtime del agente en `devagents/runtime.go`
|
||||
- [ ] **4.6** Tests: pipeline end-to-end con mocks de STT, LLM y TTS
|
||||
|
||||
### Fase 5 — Polish y opcionales
|
||||
|
||||
- [ ] **5.1** Gestion del ciclo de vida de llamadas: join, active, hangup, error recovery, timeout por inactividad
|
||||
- [ ] **5.2** Opcional: publicar video track con avatar/estado del agente (estatico o animado)
|
||||
- [ ] **5.3** Indicadores en la room Matrix durante la llamada (typing indicators, mensajes de estado)
|
||||
- [ ] **5.4** Documentacion de config y ejemplos en config de agentes de referencia
|
||||
- [ ] **5.5** Verificacion de permisos: solo aceptar llamadas de usuarios autorizados (ACL check via `security/`)
|
||||
|
||||
## Desglose multi-issue
|
||||
|
||||
Este issue es demasiado grande para completarse en una sola rama corta. Se recomienda desglosar en los siguientes sub-issues, cada uno autocontenido, compilable y testeable:
|
||||
|
||||
| Sub-issue | Rama | Alcance | Fases cubiertas | Estado |
|
||||
|-----------|------|---------|-----------------|--------|
|
||||
| 0041a — LiveKit client + deteccion de llamadas | `issue/0041a-livekit-client` | Paquete `shell/livekit/`, config `LiveKitCfg`, deteccion de eventos MatrixRTC en listener, auto-join basico | Fase 1 | pendiente |
|
||||
| 0041b — TTS package + publicacion de audio | `issue/0041b-tts-audio-publish` | Paquete `pkg/tts/`, `shell/tts/`, config `TTSCfg`, publicar audio track al LiveKit room | Fase 3 | pendiente |
|
||||
| 0041c — Pipeline completo STT → LLM → TTS | `issue/0041c-call-pipeline` | Orquestacion en `shell/livekit/pipeline.go`, captura audio, VAD, integracion STT (issue 0040), flujo conversacional, wiring en runtime | Fases 2 y 4 | pendiente |
|
||||
| 0041d — Polish, video track y lifecycle | `issue/0041d-call-polish` | Lifecycle management, interrupciones, video track opcional, indicadores, ACL, docs | Fase 5 | pendiente |
|
||||
|
||||
### Nota sobre feature flags
|
||||
|
||||
Se recomienda usar un feature flag `livekit-calls` en `dev/feature_flags.json` (desactivado) para las sub-issues 0041a-0041c. La sub-issue 0041d activa el flag y cierra el feature. Esto permite mergear codigo completo y testeado a master sin activar el comportamiento hasta que todo el pipeline este listo.
|
||||
|
||||
```json
|
||||
{
|
||||
"flags": {
|
||||
"livekit-calls": {
|
||||
"enabled": false,
|
||||
"issue": "0041",
|
||||
"description": "Agentes pueden unirse a llamadas de voz/video via LiveKit + MatrixRTC",
|
||||
"added": "2026-04-09"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Progreso por tarea
|
||||
|
||||
**Fase 1: Cliente LiveKit + deteccion** — sub-issue 0041a
|
||||
- [ ] 1.1 Dependencia `livekit/server-sdk-go`
|
||||
- [ ] 1.2 `shell/livekit/client.go`
|
||||
- [ ] 1.3 `LiveKitCfg` en config schema
|
||||
- [ ] 1.4 Deteccion MatrixRTC en listener
|
||||
- [ ] 1.5 Auto-join a llamadas
|
||||
- [ ] 1.6 Tests
|
||||
|
||||
**Fase 2: Captura audio + STT** — sub-issue 0041c
|
||||
- [ ] 2.1 Captura audio track
|
||||
- [ ] 2.2 Buffer audio chunks
|
||||
- [ ] 2.3 Integracion STT (issue 0040)
|
||||
- [ ] 2.4 Voice Activity Detection
|
||||
- [ ] 2.5 Tests
|
||||
|
||||
**Fase 3: TTS** — sub-issue 0041b
|
||||
- [ ] 3.1 `pkg/tts/types.go`
|
||||
- [ ] 3.2 `shell/tts/openai.go`
|
||||
- [ ] 3.3 `TTSCfg` en config schema
|
||||
- [ ] 3.4 Conversion formato audio
|
||||
- [ ] 3.5 Publicar audio track
|
||||
- [ ] 3.6 Tests
|
||||
|
||||
**Fase 4: Pipeline completo** — sub-issue 0041c
|
||||
- [ ] 4.1 Orquestacion pipeline
|
||||
- [ ] 4.2 Flujo conversacional
|
||||
- [ ] 4.3 Manejo de interrupciones
|
||||
- [ ] 4.4 Optimizacion latencia (streaming TTS)
|
||||
- [ ] 4.5 Wiring en runtime
|
||||
- [ ] 4.6 Tests E2E del pipeline
|
||||
|
||||
**Fase 5: Polish** — sub-issue 0041d
|
||||
- [ ] 5.1 Lifecycle management
|
||||
- [ ] 5.2 Video track opcional
|
||||
- [ ] 5.3 Indicadores en Matrix
|
||||
- [ ] 5.4 Documentacion
|
||||
- [ ] 5.5 ACL check
|
||||
|
||||
## Ejemplo de uso
|
||||
|
||||
### Llamada 1:1 con agente
|
||||
|
||||
```
|
||||
1. Usuario abre DM con el agente en Element
|
||||
2. Usuario hace clic en el boton "Call" (icono de telefono)
|
||||
3. Element crea sesion MatrixRTC → LiveKit room
|
||||
4. El agente detecta el evento m.call.member en la room
|
||||
5. El agente se une a la llamada como participante de audio
|
||||
6. Conversacion:
|
||||
|
||||
Usuario (hablando): "Hola, como estan los servidores?"
|
||||
[VAD detecta fin de habla → STT transcribe → LLM procesa → TTS genera audio]
|
||||
Agente (hablando): "Hola! Todos los servidores estan operativos.
|
||||
El uso de CPU promedio es del 23% y hay 4.2 GB
|
||||
de memoria disponible."
|
||||
|
||||
Usuario: "Y el servicio de base de datos?"
|
||||
[Pipeline se repite]
|
||||
Agente: "PostgreSQL esta corriendo normalmente. La ultima replica
|
||||
se sincronizo hace 3 minutos sin errores."
|
||||
|
||||
7. Usuario cuelga la llamada
|
||||
8. El agente detecta el hangup y se desconecta del LiveKit room
|
||||
```
|
||||
|
||||
### Config del agente
|
||||
|
||||
```yaml
|
||||
# agents/<agent-id>/config.yaml
|
||||
|
||||
livekit:
|
||||
enabled: true
|
||||
server_url: "wss://livekit.myserver.com"
|
||||
api_key_env: LIVEKIT_API_KEY
|
||||
api_secret_env: LIVEKIT_API_SECRET
|
||||
auto_join_calls: true # unirse automaticamente cuando se detecta llamada
|
||||
|
||||
tts:
|
||||
enabled: true
|
||||
provider: openai # openai | elevenlabs | local
|
||||
model: tts-1 # tts-1 (rapido) | tts-1-hd (calidad)
|
||||
voice: nova # alloy, echo, fable, onyx, nova, shimmer
|
||||
speed: 1.0 # 0.25 - 4.0
|
||||
api_key_env: OPENAI_API_KEY # reutiliza la misma key del LLM
|
||||
```
|
||||
|
||||
### Env vars nuevas
|
||||
|
||||
```bash
|
||||
# .env
|
||||
LIVEKIT_API_KEY="APIxxxxxxxx"
|
||||
LIVEKIT_API_SECRET="secretxxxxxxxx"
|
||||
# OPENAI_API_KEY ya existe — se reutiliza para TTS
|
||||
```
|
||||
|
||||
## Decisiones de diseno
|
||||
|
||||
1. **LiveKit server-sdk-go**: SDK oficial de LiveKit para Go, permite integracion nativa sin bridges ni proxies. El agente se conecta como participante server-side al LiveKit room.
|
||||
|
||||
2. **OpenAI TTS como provider primario**: consistente con la dependencia existente de `github.com/sashabaranov/go-openai`. El modelo `tts-1` ofrece buen balance entre calidad y latencia (~1s). Se puede extender a ElevenLabs o TTS local en el futuro.
|
||||
|
||||
3. **MVP solo audio, video opcional**: la interaccion por voz es el valor principal. El video track (avatar, estado) es un nice-to-have que se puede agregar despues sin cambiar la arquitectura.
|
||||
|
||||
4. **Reutilizar interfaz Transcriber del issue 0040**: evita duplicar logica de STT. El issue 0040 define la interfaz y la implementacion; este issue la consume para el pipeline de llamadas.
|
||||
|
||||
5. **Voice Activity Detection (VAD)**: critico para saber cuando el usuario termina de hablar. Sin VAD, el agente no sabe cuando empezar a procesar. Se puede empezar con un umbral simple de silencio (ej: 1.5s sin audio) y mejorar despues con VAD basado en WebRTC o silero-vad.
|
||||
|
||||
6. **Considerar OpenAI Realtime API como optimizacion futura**: la Realtime API de OpenAI permite audio-in → audio-out directamente, eliminando la necesidad de STT y TTS separados. Reduciria la latencia significativamente (~500ms vs ~4s). Sin embargo, introduce acoplamiento fuerte con OpenAI y no permite usar otros LLMs. Se deja como optimizacion futura.
|
||||
|
||||
7. **Feature flag para merge incremental**: dado que son 4+ sub-issues, cada uno mergea codigo funcional y testeado a master protegido por el flag `livekit-calls`. Esto sigue el patron TBD del proyecto y evita ramas largas.
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
- **Issue 0040 (STT) completado**: este issue depende de la interfaz `Transcriber` y la implementacion de STT para transcribir el audio de la llamada
|
||||
- **Servidor LiveKit desplegado**: se necesita un servidor LiveKit accesible (self-hosted via `livekit-server` o LiveKit Cloud), configurado para funcionar con el homeserver Matrix
|
||||
- **Integracion MatrixRTC en el homeserver**: el homeserver Synapse necesita estar configurado para MatrixRTC/LiveKit (configuracion de SFU en `.well-known` o en el config de Synapse)
|
||||
- **Element Web/Desktop con soporte de Element Call**: las versiones recientes de Element incluyen Element Call integrado
|
||||
|
||||
## Seguridad
|
||||
|
||||
- **Credenciales LiveKit via env vars**: `LIVEKIT_API_KEY` y `LIVEKIT_API_SECRET` nunca se hardcodean, se cargan desde `.env` via `api_key_env`/`api_secret_env`
|
||||
- **Solo aceptar llamadas de usuarios autorizados**: verificar permisos del usuario que inicia la llamada contra las ACLs del agente (`security/permissions.yaml`) antes de unirse
|
||||
- **Audio procesado en memoria, no persistido**: el audio de la llamada se procesa en streaming y no se guarda en disco. Los buffers se liberan despues de la transcripcion
|
||||
- **Llamadas TTS/STT via HTTPS**: todas las llamadas a APIs externas (OpenAI Whisper, OpenAI TTS) usan HTTPS
|
||||
- **Timeout por inactividad**: si no se detecta audio por un periodo configurable (ej: 5 minutos), el agente se desconecta automaticamente para liberar recursos
|
||||
- **Rate limiting**: aplicar rate limiting a las llamadas por usuario/room para prevenir abuso de recursos (STT/TTS tienen costo por uso)
|
||||
|
||||
## Riesgos
|
||||
|
||||
| Riesgo | Probabilidad | Impacto | Mitigacion |
|
||||
|--------|-------------|---------|------------|
|
||||
| MatrixRTC spec en evolucion — la integracion LiveKit/Matrix puede cambiar entre versiones | Alta | Alto | Fijar versiones de Element y livekit-server; encapsular la deteccion de eventos en una capa de abstraccion que se pueda actualizar sin reescribir el pipeline |
|
||||
| Latencia total del pipeline: STT (~1s) + LLM (~2s) + TTS (~1s) = ~4s minimo de respuesta | Alta | Medio | Aceptable para MVP; optimizar con streaming TTS (iniciar antes de completar la respuesta LLM); considerar OpenAI Realtime API como mejora futura |
|
||||
| Codec Opus: conversion entre formato LiveKit (Opus/WebRTC) y APIs de STT/TTS (PCM/MP3) | Media | Medio | Usar librerias Go para decode Opus → PCM (`gopkg.in/hraban/opus.v2` o `pion/opus`); puede requerir CGO dependiendo de la libreria |
|
||||
| Hosting y costo del servidor LiveKit | Media | Medio | LiveKit se puede self-host (binario unico); el costo de APIs de STT/TTS es proporcional al uso. Documentar estimaciones de costo |
|
||||
| Compatibilidad Element Web vs Mobile vs Desktop | Media | Bajo | Element Call funciona diferente en cada plataforma. Priorizar Element Web/Desktop que usan MatrixRTC directamente; mobile puede tener limitaciones |
|
||||
| CGO dependency para codec Opus | Media | Medio | El proyecto usa `CGO_ENABLED=0`. Si las librerias Opus requieren CGO, evaluar alternativas pure-Go o pre-compilar bindings. `pion/opus` ofrece decode pure-Go |
|
||||
| LiveKit server-sdk-go compatibility con Go 1.23.5 | Baja | Bajo | Verificar compatibilidad antes de empezar; el SDK de LiveKit suele soportar versiones recientes de Go |
|
||||
Reference in New Issue
Block a user