Concept internals
Formatação Markdown
OpenClaw formata Markdown de saída convertendo-o em uma representação intermediária compartilhada (IR) antes de renderizar a saída específica de cada canal. A IR mantém o texto de origem intacto enquanto carrega intervalos de estilo/link, para que a divisão em partes e a renderização possam permanecer consistentes entre canais.
Objetivos
- Consistência: uma etapa de análise, vários renderizadores.
- Divisão segura em partes: dividir o texto antes da renderização para que a formatação inline nunca quebre entre partes.
- Adequação ao canal: mapear a mesma IR para mrkdwn do Slack, HTML do Telegram e intervalos de estilo do Signal sem reanalisar o Markdown.
Pipeline
- Analisar Markdown -> IR
- A IR é texto simples mais intervalos de estilo (negrito/itálico/tachado/código/spoiler) e intervalos de link.
- Os deslocamentos são unidades de código UTF-16 para que os intervalos de estilo do Signal se alinhem à API dele.
- Tabelas são analisadas apenas quando um canal opta pela conversão de tabelas.
- Dividir IR em partes (formatação primeiro)
- A divisão em partes acontece no texto da IR antes da renderização.
- A formatação inline não é dividida entre partes; os intervalos são fatiados por parte.
- Renderizar por canal
- Slack: tokens mrkdwn (negrito/itálico/tachado/código), links como
<url|label>. - Telegram: tags HTML (
<b>,<i>,<s>,<code>,<pre><code>,<a href>). - Signal: texto simples + intervalos
text-style; links se tornamlabel (url)quando o rótulo é diferente.
- Slack: tokens mrkdwn (negrito/itálico/tachado/código), links como
Exemplo de IR
Markdown de entrada:
Hello **world** - see [docs](https://docs.openclaw.ai).
IR (esquemática):
{
"text": "Hello world - see docs.",
"styles": [{ "start": 6, "end": 11, "style": "bold" }],
"links": [{ "start": 19, "end": 23, "href": "https://docs.openclaw.ai" }]
}
Onde é usada
- Adaptadores de saída do Slack, Telegram e Signal renderizam a partir da IR.
- Outros canais (WhatsApp, iMessage, Microsoft Teams, Discord) ainda usam texto simples ou suas próprias regras de formatação, com conversão de tabelas Markdown aplicada antes da divisão em partes quando habilitada.
Tratamento de tabelas
Tabelas Markdown não têm suporte consistente entre clientes de chat. Use
markdown.tables para controlar a conversão por canal (e por conta).
code: renderiza tabelas como blocos de código (padrão para a maioria dos canais).bullets: converte cada linha em marcadores (padrão para Signal + WhatsApp).off: desabilita a análise e conversão de tabelas; o texto bruto da tabela é repassado.
Chaves de configuração:
channels:
discord:
markdown:
tables: code
accounts:
work:
markdown:
tables: off
Regras de divisão em partes
- Os limites de partes vêm dos adaptadores/configurações do canal e são aplicados ao texto da IR.
- Cercas de código são preservadas como um único bloco com uma nova linha final para que os canais as renderizem corretamente.
- Prefixos de listas e prefixos de citações fazem parte do texto da IR, então a divisão em partes não ocorre no meio do prefixo.
- Estilos inline (negrito/itálico/tachado/código-inline/spoiler) nunca são divididos entre partes; o renderizador reabre estilos dentro de cada parte.
Se precisar de mais informações sobre o comportamento de divisão em partes entre canais, consulte Streaming + divisão em partes.
Política de links
- Slack:
[label](url)-><url|label>; URLs nuas permanecem nuas. O autolink é desabilitado durante a análise para evitar links duplicados. - Telegram:
[label](url)-><a href="url">label</a>(modo de análise HTML). - Signal:
[label](url)->label (url)a menos que o rótulo corresponda à URL.
Spoilers
Marcadores de spoiler (||spoiler||) são analisados apenas para Signal, onde são mapeados para
intervalos de estilo SPOILER. Outros canais os tratam como texto simples.
Como adicionar ou atualizar um formatador de canal
- Analisar uma vez: use o helper compartilhado
markdownToIR(...)com opções apropriadas ao canal (autolink, estilo de título, prefixo de citação). - Renderizar: implemente um renderizador com
renderMarkdownWithMarkers(...)e um mapa de marcadores de estilo (ou intervalos de estilo do Signal). - Dividir em partes: chame
chunkMarkdownIR(...)antes da renderização; renderize cada parte. - Conectar o adaptador: atualize o adaptador de saída do canal para usar o novo divisor em partes e o renderizador.
- Testar: adicione ou atualize testes de formatação e um teste de entrega de saída se o canal usar divisão em partes.
Armadilhas comuns
- Tokens do Slack com colchetes angulares (
<@U123>,<#C123>,<https://...>) devem ser preservados; escape HTML bruto com segurança. - O HTML do Telegram exige escape de texto fora das tags para evitar marcação quebrada.
- Os intervalos de estilo do Signal dependem de deslocamentos UTF-16; não use deslocamentos de pontos de código.
- Preserve novas linhas finais para blocos de código cercados para que os marcadores de fechamento fiquem em sua própria linha.