8db65ed062
Marca el issue 0012-threads como completado. El problema de que el agente respondia en el hilo principal en lugar del thread esta resuelto con el cache de eventos cifrados implementado en esta rama.
92 lines
3.1 KiB
Markdown
92 lines
3.1 KiB
Markdown
# Task 011 — Matrix Thread Support
|
|
|
|
## Objetivo
|
|
|
|
Permitir que los agentes mantengan conversaciones en threads de Matrix (`m.thread`),
|
|
de forma que cada interaccion con un usuario pueda vivir en un hilo separado
|
|
en lugar de la timeline principal del room.
|
|
|
|
Las respuestas del agente deben volver en el hilo y no en la rama principal
|
|
|
|
## Contexto
|
|
|
|
Matrix soporta threads via `m.relates_to` con `rel_type: "m.thread"`.
|
|
Un thread siempre referencia un **evento raiz** y opcionalmente incluye
|
|
`m.in_reply_to` como fallback para clientes sin soporte de threads.
|
|
|
|
```json
|
|
{
|
|
"m.relates_to": {
|
|
"rel_type": "m.thread",
|
|
"event_id": "$rootEventId",
|
|
"is_falling_back": true,
|
|
"m.in_reply_to": {
|
|
"event_id": "$lastEventInThread"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Prerequisito
|
|
|
|
- Task: Reply simple (`m.in_reply_to`) ya implementado.
|
|
|
|
## Plan de implementacion
|
|
|
|
### 1. Detectar threads entrantes en el Listener
|
|
|
|
- En `shell/matrix/listener.go`, al parsear el evento, extraer `m.relates_to`
|
|
- Si `rel_type == "m.thread"`, capturar `event_id` como `ThreadRootID`
|
|
- Propagar `ThreadRootID` en `MessageContext`
|
|
|
|
### 2. Extender MessageContext
|
|
|
|
- `pkg/decision/types.go`: anadir `ThreadRootID string` (el evento raiz del thread)
|
|
- Esto es dato puro, no rompe la arquitectura
|
|
|
|
### 3. Extender ReplyAction
|
|
|
|
- `pkg/decision/types.go`: anadir `ThreadRootID string` a `ReplyAction`
|
|
- El runner usara esto para decidir si enviar como thread o como mensaje normal
|
|
|
|
### 4. SendThreadMarkdown en Client
|
|
|
|
- `shell/matrix/client.go`: nuevo metodo `SendThreadMarkdown(ctx, roomID, threadRootID, inReplyTo, markdown)`
|
|
- Construye el `m.relates_to` con `rel_type: "m.thread"` + fallback `m.in_reply_to`
|
|
|
|
### 5. Actualizar effects/Runner
|
|
|
|
- `shell/effects/runner.go`: si `ReplyAction.ThreadRootID != ""`, usar `SendThreadMarkdown`
|
|
- Actualizar interfaz `MatrixSender` con el nuevo metodo
|
|
|
|
### 6. Propagacion en runtime.go
|
|
|
|
- Cuando el mensaje entrante ya esta en un thread (`msgCtx.ThreadRootID != ""`),
|
|
las respuestas del bot deben continuar en ese thread
|
|
- Cuando el usuario inicia una conversacion nueva, decidir segun config si crear thread o no
|
|
|
|
### 7. Configuracion por agente
|
|
|
|
- `internal/config/schema.go`: anadir opcion `matrix.threads.enabled: bool` y
|
|
`matrix.threads.auto_thread: bool` (crear thread automatico por cada conversacion nueva)
|
|
- Default: `enabled: true`, `auto_thread: false`
|
|
|
|
### 8. Memory por thread
|
|
|
|
- La window de conversacion deberia poder ser por thread en vez de por room
|
|
- Si `ThreadRootID != ""`, usar `threadRootID` como key de la window en vez de `roomID`
|
|
- Esto permite conversaciones paralelas en threads distintos sin mezclarse
|
|
|
|
### 9. Tests
|
|
|
|
- Unit tests para `SendThreadMarkdown` (verificar estructura JSON)
|
|
- Test de integracion: listener detecta thread entrante y propaga ThreadRootID
|
|
- Test: respuesta dentro de thread mantiene el thread root correcto
|
|
|
|
## Notas
|
|
|
|
- `is_falling_back: true` siempre debe estar cuando se usa thread + in_reply_to fallback
|
|
- El `event_id` de `m.relates_to` (nivel top) siempre apunta al root del thread, nunca cambia
|
|
- El `m.in_reply_to` dentro del thread apunta al ultimo mensaje respondido
|
|
- Clientes sin soporte de threads ven el fallback como un reply normal
|