Skip to content

Rendering Pipeline es

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

Pipeline de renderizado

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

El pipeline de Markdown → HTML de confianza para las burbujas del asistente vive en lib/sidepanel/render.js. El orden de las operaciones es estructural (load-bearing):

  1. fixCjkEmphasisSpacing (el parche de ** por adyacencia CJK — sus clases de caracteres imitan deliberadamente las reglas de flanking de marked: puntuación = \p{P}∪\p{S}, vecinos = cualquier letra/dígito)
  2. Extraer bloques <think> → placeholders
  3. Extraer matemáticas en bloque $$…$$ / \[…\]
  4. Extraer matemáticas inline $…$ / \(…\) — dos guardas:
    • los escapes de markdown \\ y \$ se consumen verbatim primero (\$8K es un dólar literal — reporte de la tabla MRR de 2026-09-30);
    • el $ inline sigue las reglas de delimitadores de Pandoc: apertura/cierre ajustados, y un cierre seguido de un dígito se rechaza (从**$8K**、**$20K** llegó a emparejar sus $ desnudos dentro de KaTeX, que renderizó los * como ∗ — reporte de 2026-10-01). Los candidatos rechazados se devuelven verbatim a marked.
  5. marked.parse → 6. DOMPurify → 7. renderizado por lotes en el worker de KaTeX + restauración (DESPUÉS de la sanitización, de modo que los atributos MathML nunca lleguen a DOMPurify) → 8. restaurar los plegables think.

Streaming: confirmación por bloques (ADR-0011)

  • renderStreamingSafe (síncrono) maneja solo la cola en cada frame; los bloques de markdown completados se confirman una sola vez (findStreamingBlockBoundary: frontera de línea en blanco, fuera de vallas, la línea siguiente no es un ítem de lista) y solo la cola abierta se re-parsea — O(n²) pasa a O(n). Las vallas abiertas toman una vía rápida (<pre><code> vía textContent, cero llamadas a marked).
  • El pacer de revelado es el markstream-core vendoreado (makeStreamRenderer devuelve una closure; .destroy() antes de reasignarla). DONE re-renderiza el texto completo vía renderSafe (KaTeX + bloques think finales), corrigiendo cualquier aproximación del streaming.
  • El historial se renderiza de forma diferida: un IntersectionObserver actualiza las burbujas cuando se acercan al scrollport; content-visibility:auto solo bajo .cv-settled (doble rAF) — nunca durante el layout/scroll inicial.
  • Descarga de KaTeX: katex-threshold.js decide entre worker y síncrono; el worker agrupa por mensaje, cachea y cae al modo síncrono ante fallos.

Seis renderizadores por valla (```lang → intercambio por render en vivo, sin botones)

Valla Renderer Vendor Notas
```mermaid renderMermaid mermaid securityLevel:'loose' (KaTeX en foreignObject) + sanitizeMermaidSvg (seguridad estructural); tarjeta de reparación por IA ante fallo de parseo (REPAIR_MERMAID)
```echarts renderEcharts echarts tema 'dark' integrado + canvas transparente salvo que el modelo nombre el suyo propio
```markmap renderMarkmap markmap lib+view pre.replaceWith(wrapper) ANTES de Markmap.create() (el layout mide el texto); mm.rescale() es un multiplicador RELATIVO — el zoom pasa por la conversión absoluta de _markmapZoomBy
```smiles renderSmiles RDKit MinimalLib WASM get_mol/get_rxn; RDKit hace a la vez de validador (químicamente imposible → nota de error explícita, bloque original conservado); línea de descriptores (MW/logP/TPSA…); el modo oscuro re-tinta los trazos pero CONSERVA los colores CPK de heteroátomos (semántica química — nunca invertir por CSS)
```pdb renderPdb Mol* (IIFE precompilada copiada en RAW) parsePdbBlock clasifica: ID de RCSB / AlphaFold AF-…-F1 (modelo actual resuelto vía API) / coordenadas inline; el preset de representación debe viajar en representationPreset; los viewers activos se rastrean y se disponen (los navegadores limitan a ~16 contextos WebGL)
```dot renderDot @viz-js/viz (WASM con base64 inline) remapeo de la tinta negra por defecto + rescate de contraste; DOT inválido → nota de error + código original conservado (sin reparación por IA); contrato del modelo: ID [label="…"] únicamente

El contrato de renderizado (lo que se le enseña al modelo a emitir) tiene UNA única fuente de texto: CAPABILITY_HINTS_ENTRIES en lib/prompt-assembly.js — tanto CAPABILITY_HINTS (canal system de LLM/Hermes) como AGENT_RENDER_HINT (primer turno del agente) son ensamblajes de ella. No debe reaparecer ningún espejo escrito a mano (el antiguo espejo de ```nn pasó un día sin recibir una actualización).

Carga de vendors y CSP (ver ADR-0008 / Security Model)

  • Los vendors de diagramas se cargan con lazy-load y se precalientan solo cuando se ve realmente una valla (wantsChartVendors tras una compuerta de un solo uso) — una sesión sin diagramas nunca paga el parseo de ~7MB.
  • El dist de Mol nunca pasa por esbuild* (IIFE precompilada copiada en RAW); el glue embind de Mol*/RDKit recibe parches CSP aplicados en el momento de la copia en build.mjs (invocadores escritos a mano reemplazan new Function; la inicialización eager de h264 se vuelve lazy) — las regex de parcheo se anclan a cadenas estables y ROMPEN EL BUILD cuando una actualización de molstar deja de coincidir.
  • La compuerta de verificación tras cualquier cambio de vendor es una carga REAL de la extensión (launchPersistentContext --load-extension, xvfb): dev-preview es una página http plana que permite eval y no puede detectar violaciones de CSP (lección de 2026-09-30).

Liberación de recursos

_chartObservers (registro de ResizeObserver) / _renderDisposers (por elemento) / disposeMolstarViewers() se ejecutan antes de cada eliminación de burbuja, re-renderizado del historial y borrado del historial. El síntoma clásico de fuga es un contexto WebGL huérfano renderizando para siempre (límite del navegador de ~16 contextos).


Versiones autoritativas: Rendering-Pipeline (inglés) / Rendering-Pipeline-zh (chino) — instantánea de primera traducción por IA, sincronizada el 2026-10-01.

Clone this wiki locally