Files
unibots/dev/issues/completed/0011-markdown-rendering.md
T
agent fc644ecd6e feat: import agents_and_robots platform as unibots (Matrix-out, unibus transport)
Reemplaza el scaffold del echobot por la plataforma completa de bots traida
desde ~/DataProyects/Github/agents_and_robots tras la operacion Matrix-out:
los bots ya no hablan por Matrix sino por el bus unibus (modelo todo-rooms +
E2E via shell/transportunibus sobre github.com/enmanuel/unibus/pkg/client).

- go.mod: replace de unibus -> ../unibus y de fn-registry -> ../../../.. (paths
  relativos reajustados a la nueva ubicacion dentro de fn_registry).
- app.md: bump a 0.2.0, descripcion + arquitectura + comandos + gotchas reales.
- modulo Go conservado como github.com/enmanuel/agents (sin reescribir imports).

agents_and_robots queda archivado como museo de la era Matrix.
2026-06-07 11:50:13 +02:00

3.8 KiB

Tarea 11 — Renderizar mensajes como Markdown en Matrix

Problema

Todos los mensajes de los agentes (respuestas LLM, comandos, errores) se envían como texto plano via SendText(). Matrix soporta mensajes con format: org.matrix.custom.html + formatted_body para renderizar Markdown (negrita, código, listas, etc.) en clientes como Element.

Existe un SendMarkdown() en shell/matrix/client.go pero tiene dos problemas:

  1. Solo se usa en un único lugar (runtime.go:617 — notificación de tool use).
  2. No convierte Markdown a HTML: pone el markdown crudo en FormattedBody, que Matrix espera como HTML.

Alcance

1. Añadir conversión Markdown → HTML (shell/matrix/client.go)

  • Añadir dependencia github.com/yuin/goldmark (parser Markdown → HTML estándar, muy usado en Go).
  • Corregir SendMarkdown() para que convierta el body de Markdown a HTML antes de ponerlo en FormattedBody.
  • Body queda como texto plano (fallback para clientes que no soportan HTML) — se puede dejar el markdown crudo ahí, que es lo estándar en Matrix.
func (c *Client) SendMarkdown(ctx context.Context, roomID, markdown string) error {
    html := mdToHTML(markdown) // nueva función interna
    content := event.MessageEventContent{
        MsgType:       event.MsgText,
        Body:          markdown,
        Format:        event.FormatHTML,
        FormattedBody: html,
    }
    _, err := c.raw.SendMessageEvent(ctx, id.RoomID(roomID), event.EventMessage, content)
    return err
}

2. Cambiar la interfaz MatrixSender para exponer SendMarkdown

  • shell/effects/runner.go: añadir SendMarkdown(ctx, roomID, text) error a la interfaz MatrixSender.
  • tools/matrix.go: añadir SendMarkdown a la interfaz MatrixToolSender (o como se llame).

3. Cambiar todos los call sites de SendTextSendMarkdown

Puntos a cambiar:

Archivo Línea(s) Contexto
agents/runtime.go:394 Respuesta de tarea orquestada SendText → SendMarkdown
agents/runtime.go:456 Reply LLM (loop) SendText → SendMarkdown
agents/runtime.go:462 Reply LLM (fallback) SendText → SendMarkdown
shell/effects/runner.go:68 Runner.executeOne (ActionKindReply) SendText → SendMarkdown
agents/runtime.go:456 Comando ejecutado (!xxx) SendText → SendMarkdown
agents/runtime.go:462 Comando desconocido SendText → SendMarkdown

4. Mantener SendText para uso interno/futuro

No eliminar SendText, solo dejar de usarlo como canal principal de respuesta. Podría ser útil para mensajes que realmente no necesitan formato (logs internos, debugging).

5. Actualizar interfaz en tests/mocks

Cualquier mock de MatrixSender que exista en tests necesitará el método SendMarkdown.

Tareas ordenadas

  • go get github.com/yuin/goldmark
  • Crear función mdToHTML(md string) string en shell/matrix/ (usa goldmark)
  • Corregir SendMarkdown() para usar mdToHTML
  • Añadir SendMarkdown a la interfaz MatrixSender en shell/effects/runner.go
  • Cambiar runner.executeOne (ActionKindReply) de SendTextSendMarkdown
  • Cambiar runtime.go — respuesta de comandos (!xxx) a SendMarkdown
  • Cambiar runtime.go — respuesta de tarea orquestada a SendMarkdown
  • Actualizar interfaz en tools/matrix.go si aplica
  • Actualizar mocks en tests
  • Test manual: enviar mensaje al bot y verificar que Element renderiza markdown

Notas

  • goldmark es safe por defecto (escapa HTML peligroso) — no hay riesgo XSS.
  • El Body del evento Matrix queda como markdown crudo — esto es correcto según la spec de Matrix (es el fallback plaintext).
  • Los mensajes de error simples ("Comando desconocido: !foo") también pasan por SendMarkdown — no pasa nada, goldmark los deja como <p>texto</p> sin más.