Dos problemas corregidos:
1. Detección de threads con E2EE: después de desencriptar un evento,
evt.Content.Raw puede no contener m.relates_to. Se añade fallback
usando el contenido tipado (evt.Content.Parsed) que es más robusto
tras la desencriptación de mautrix.
2. Notificaciones de tools fuera del thread: la notificación "🔨 tool"
se enviaba con SendMarkdown directo a la sala, ignorando el contexto
de thread. Ahora usa sendReply que respeta ThreadID.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests unitarios:
- runner_test.go: verifica ruteo correcto de ReplyAction segun
ThreadID (plain markdown, reply, thread, thread sin fallback, nil reply)
- thread_test.go: extraccion de ThreadID desde m.relates_to raw
(thread, reply sin thread, plain, m.replace, thread sin event_id)
- thread_relates_test.go: estructura JSON de RelatesTo.SetThread
cumple la spec de Matrix (rel_type, event_id, is_falling_back, m.in_reply_to)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>