Skip to content

Rendering Pipeline pt

Hermes Agent edited this page Oct 1, 2026 · 1 revision

Pipeline de renderização

English | 中文 | 日本語 | 한국어 | Español | Português | Русский

O pipeline Markdown → HTML confiável para bolhas de assistente vive em lib/sidepanel/render.js. A ordem das operações é crítica:

  1. fixCjkEmphasisSpacing (o patch de ** por adjacência CJK — suas classes de caracteres espelham deliberadamente as regras de flanking do marked: pontuação = \p{P}∪\p{S}, vizinhos = qualquer letra/dígito)
  2. Extrair blocos <think> → placeholders
  3. Extrair matemática em bloco $$…$$ / \[…\]
  4. Extrair matemática inline $…$ / \(…\) — duas salvaguardas:
    • as escapes do markdown \\ e \$ são consumidos verbatim primeiro (\$8K é um cifrão literal — relatório da tabela MRR de 2026-09-30);
    • o $ inline segue as regras de delimitador do Pandoc: abertura/fechamento justos, e um fechamento seguido de dígito é rejeitado (从**$8K**、**$20K** certa vez emparelhou seus $ soltos dentro do KaTeX, que renderizou os * como ∗ — relatório de 2026-10-01). Candidatos rejeitados são devolvidos verbatim ao marked.
  5. marked.parse → 6. DOMPurify → 7. renderização em lote pelo worker KaTeX + restauração (DEPOIS da sanitização, para que atributos MathML nunca encontrem o DOMPurify) → 8. restauração dos foldables de think.

Streaming: commit de blocos (ADR-0011)

  • renderStreamingSafe (síncrono) processa apenas a cauda a cada frame; blocos markdown completados fazem commit uma única vez (findStreamingBlockBoundary: fronteira de linha em branco, fora de fences, a próxima linha não é item de lista) e apenas a cauda aberta é reanalisada — O(n²) vira O(n). Fences abertos pegam um caminho rápido (<pre><code> via textContent, zero chamadas ao marked).
  • O reveal pacer é o markstream-core vendored (makeStreamRenderer retorna uma closure; .destroy() antes de reatribuí-la). DONE renderiza o texto completo novamente via renderSafe (KaTeX + blocos think finais), corrigindo qualquer aproximação do streaming.
  • O histórico renderiza de forma preguiçosa: um IntersectionObserver atualiza as bolhas conforme elas se aproximam do scrollport; content-visibility:auto apenas sob .cv-settled (duplo rAF) — nunca durante o layout/scroll iniciais.
  • Offload do KaTeX: katex-threshold.js decide entre worker e síncrono; o worker agrupa por mensagem, faz cache e cai para o síncrono em caso de falha.

Seis renderizadores por fence (```lang → troca por render ao vivo, sem botões)

Fence Renderer Vendor Observações
```mermaid renderMermaid mermaid securityLevel:'loose' (KaTeX em foreignObject) + sanitizeMermaidSvg (segurança estrutural); cartão de reparo por IA em falha de parse (REPAIR_MERMAID)
```echarts renderEcharts echarts tema 'dark' embutido + canvas transparente, a menos que o modelo nomeie o próprio
```markmap renderMarkmap markmap lib+view pre.replaceWith(wrapper) ANTES de Markmap.create() (o layout mede texto); mm.rescale() é um multiplicador RELATIVO — o zoom passa pela conversão absoluta de _markmapZoomBy
```smiles renderSmiles RDKit MinimalLib WASM get_mol/get_rxn; o RDKit também serve de validador (quimicamente impossível → nota de erro explícita, bloco bruto mantido); linha de descritores (MW/logP/TPSA…); o modo escuro re-tinta os traços mas MANTÉM as cores de heteroátomos CPK (semântica química — nunca inverta via CSS)
```pdb renderPdb Mol* (IIFE RAW-copiada) parsePdbBlock classifica: ID RCSB / AlphaFold AF-…-F1 (modelo atual resolvido via API) / coordenadas inline; o preset de representação deve ir em representationPreset; viewers ao vivo são rastreados e descartados (navegadores limitam a ~16 contextos WebGL)
```dot renderDot @viz-js/viz (WASM com base64 inline) remapeamento da tinta preta padrão + resgate de contraste; DOT inválido → nota de erro + código bruto mantido (sem reparo por IA); contrato com o modelo: apenas ID [label="…"]

O contrato de renderização (o que o modelo é ensinado a emitir) tem UMA fonte de texto: CAPABILITY_HINTS_ENTRIES em lib/prompt-assembly.js — CAPABILITY_HINTS (canal de sistema LLM/Hermes) e AGENT_RENDER_HINT (primeiro turno de agente) são ambos montagens dela. Nenhum espelho manual pode reaparecer (o antigo espelho do ```nn ficou um dia sem receber uma atualização).

Carregamento de vendors e CSP (ver ADR-0008 / Modelo de segurança)

  • Vendors de diagramas fazem lazy-load e pré-aquecimento apenas quando um fence é realmente visto (sniff de wantsChartVendors atrás de um gate de uso único) — uma sessão sem diagramas nunca paga o parse de ~7MB.
  • O dist do Mol nunca passa pelo esbuild* (IIFE pré-compilada copiada em RAW); o glue embind de Mol*/RDKit recebe patches de CSP aplicados na cópia, no build.mjs (invocadores escritos à mão substituem new Function; o init ansioso do h264 virou lazy) — as regexes dos patches ancoram em strings estáveis e QUEBRAM O BUILD quando um upgrade do molstar para de casar.
  • O gate de verificação após qualquer troca de vendor é um carregamento REAL da extensão (launchPersistentContext --load-extension, xvfb): o dev-preview é uma página http comum que permite eval e não consegue capturar violações de CSP (lição de 2026-09-30).

Descarte

_chartObservers (registro de ResizeObserver) / _renderDisposers (por elemento) / disposeMolstarViewers() rodam antes de cada remoção de bolha, re-renderização do histórico e limpeza do histórico. O sintoma clássico de vazamento é um contexto WebGL destacado renderizando para sempre (cap do navegador de ~16 contextos).


Versões autoritativas: Rendering-Pipeline (inglês) / Rendering-Pipeline-zh (chinês) — instantâneo de primeira tradução por IA, sincronizado em 2026-10-01.

Clone this wiki locally