Skip to content

Rendering Pipeline ko

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

렌더링 파이프라인

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

어시스턴트 버블을 위한 Markdown → 신뢰된 HTML 파이프라인은 lib/sidepanel/render.js에 산다. 연산 순서가 하중을 지탱한다(load-bearing):

  1. fixCjkEmphasisSpacing (CJK 인접 ** 패치 — 문자 클래스는 의도적으로 marked의 플랭킹 규칙을 거울처럼 반영한다: 문장부호 = \p{P}∪\p{S}, 이웃 = 임의의 문자/숫자)
  2. <think> 블록 추출 → 플레이스홀더
  3. 블록 수학 $$…$$ / \[…\] 추출
  4. 인라인 수학 $…$ / \(…\) 추출 — 두 개의 가드:
    • markdown 이스케이프 \\와 \$를 먼저 축자 소비한다 (\$8K는 리터럴 달러 — 2026-09-30 MRR 표 보고);
    • 인라인 $는 Pandoc의 구분자 규칙을 따른다: 빈틈없는 열기/닫기, 그리고 뒤에 숫자가 오는 닫기는 기각된다 (从**$8K**、**$20K**가 맨 $들을 KaTeX로 쌍지어 *들을 ∗로 렌더한 적이 있다 — 2026-10-01 보고). 기각된 후보는 축자 그대로 marked에 돌려준다.
  5. marked.parse → 6. DOMPurify → 7. KaTeX 워커 배치 렌더 + 복원 (살균 후 — 그래서 MathML 속성은 DOMPurify를 만나지 않는다) → 8. think 접기 복원.

스트리밍: 블록 커밋 (ADR-0011)

  • renderStreamingSafe(동기)는 매 프레임 꼬리만 다룬다; 완성된 markdown 블록은 한 번 커밋된다 (findStreamingBlockBoundary: 빈 줄 경계, 펜스 밖, 다음 줄은 리스트 항목 아님)하고 열린 꼬리만 재파싱된다 — O(n²)가 O(n)이 된다. 열린 펜스는 빠른 경로를 탄다 (textContent를 통한 <pre><code>, marked 호출 0).
  • 리빌 페이서는 벤더 markstream-core다 (makeStreamRenderer는 클로저를 반환한다; 재할당하기 전에 .destroy()). DONE은 전체 텍스트를 renderSafe(KaTeX + 최종 think 블록)로 재렌더해 스트리밍 근사를 바로잡는다.
  • 히스토리는 지연 렌더된다: IntersectionObserver가 스크롤포트에 가까워지는 버블을 업그레이드한다; content-visibility:auto는 .cv-settled 아래에서만 (이중 rAF) — 초기 레이아웃/스크롤 중에는 절대 아니다.
  • KaTeX 오프로드: katex-threshold.js가 워커 vs 동기 결정을 내린다; 워커는 메시지당 배치 처리하고 캐시하며 실패 시 동기로 폴백한다.

여섯 개의 펜스 렌더러 (```lang → 실시간 렌더 교체, 버튼 없음)

펜스 렌더러 벤더 비고
```mermaid renderMermaid mermaid securityLevel:'loose' (foreignObject 안 KaTeX) + sanitizeMermaidSvg (load-bearing 보안); 파스 실패 시 AI 수리 카드 (REPAIR_MERMAID)
```echarts renderEcharts echarts 모델이 자체 배경을 명명하지 않는 한 내장 'dark' 테마 + 투명 캔버스
```markmap renderMarkmap markmap lib+view Markmap.create() 전에 pre.replaceWith(wrapper) (레이아웃이 텍스트 측정); mm.rescale()은 상대 배수다 — 줌은 _markmapZoomBy의 절대 변환을 거친다
```smiles renderSmiles RDKit MinimalLib WASM get_mol/get_rxn; RDKit이 검증자를 겸한다 (화학적으로 불가능 → 명시적 에러 노트, 원본 블록 유지); 서술자 행(MW/logP/TPSA…); 다크 모드는 잉크를 다시 칠하지만 CPK 헤테로원자 색은 유지 (화학 의미론 — CSS 반전 금지)
```pdb renderPdb Mol* (RAW 복사 IIFE) parsePdbBlock 분류: RCSB ID / AlphaFold AF-…-F1 (API로 현재 모델 해석) / 인라인 좌표; 표현 프리셋은 반드시 representationPreset에 실려야 한다; 살아있는 뷰어는 추적·폐기된다 (브라우저는 ~16 WebGL 컨텍스트 상한)
```dot renderDot @viz-js/viz (base64 인라인 WASM) 기본 검정 잉크 리맵 + 대비 구제; 무효 DOT → 에러 노트 + 원본 코드 유지 (AI 수리 없음); 모델 계약: ID [label="…"]만

렌더 계약(모델에게 무엇을 내보내라고 가르치는가)의 텍스트 소스는 하나뿐이다: lib/prompt-assembly.js의 CAPABILITY_HINTS_ENTRIES — CAPABILITY_HINTS(LLM/Hermes 시스템 채널)와 AGENT_RENDER_HINT(에이전트 첫 턴) 둘 다 이것의 조립물이다. 수동 거울은 다시 나타나서는 안 된다 (옛 ```nn 거울은 하루 동안 갱신을 놓쳤다).

벤더 로딩 & CSP (ADR-0008 / 보안 모델 참조)

  • 다이어그램 벤더는 실제로 펜스가 보일 때만 지연 로드·예열된다 (wantsChartVendors 스니프가 1회성 게이트 뒤에) — 다이어그램 없는 세션은 ~7MB 파싱 비용을 내지 않는다.
  • Mol*의 dist는 절대 esbuild를 거치지 않는다 (RAW 복사된 프리빌트 IIFE); Mol*/RDKit embind 접착제는 build.mjs가 복사 시점에 CSP 패치를 적용한다 (손작성 인보커가 new Function 대체; 즉실행 h264 init은 지연화) — 패치 정규식은 안정적인 문자열에 고정되고 molstar 업그레이드가 매칭을 멈추면 빌드를 THROW한다.
  • 벤더 교체 후의 검증 게이트는 실제 확장 로드다 (launchPersistentContext --load-extension, xvfb): dev-preview는 eval을 허용하는 평범한 http 페이지라 CSP 위반을 잡을 수 없다 (2026-09-30 교훈).

폐기

_chartObservers(ResizeObserver 레지스트리) / _renderDisposers(요소별) / disposeMolstarViewers()는 모든 버블 제거, 히스토리 재렌더, 히스토리 와이프 전에 실행된다. 고전적 누수 증상은 영원히 렌더하는 탈부착 WebGL 컨텍스트다 (~16 컨텍스트 브라우저 상한).


원본 출처: AGENTS.md "sidepanel.js module split"(render.js / mermaid-utils / chem / dot), "Renderer-vendor audit", 批B/批C 불변식; ADR-0008 / 0010 / 0011. 권위판: Rendering-Pipeline(영어) / Rendering-Pipeline-zh(중국어) — AI 초벌 번역 스냅숏, 동기화 2026-10-01.

Clone this wiki locally