Streaming

같은 답변을 같은 토큰으로 잘라 렌더러 다섯 개에 동시에 흘려 보냅니다. 패널이 화면에 들어오면 시작합니다. 다음 세 가지를 보세요.

WASM 빌드를 불러오는 중…

DESIGN.md 에서는 에이전트가 쓴 한국어 문서 347건으로 이를 측정했습니다(Streamdown 2.6.0, react-markdown 10.1.0 + remark-gfm). mdwire 스트리머를 Streamdown 앞에 두면 이미 보인 텍스트가 바뀌는 횟수가 약 60% 줄었고, 마커가 텍스트로 보이는 일이 사라졌습니다. 확정된 출력만 보여 주는 mdwire html 스트리머에서는 두 문제 모두 없었습니다. 다만 이 방식은 중간중간 멈춥니다. 이 샘플을 토큰 간격 60ms 로 흘리면 가장 긴 멈춤이 1,389ms 였고, 미리보기를 켜면 302ms 였습니다. 그래서 미리보기를 기본으로 켰습니다. 자세한 내용은 DESIGN.md 의 렌더러 앞단 절에 있습니다. 샘플 답변은 합성한 것이지만, 그 안의 형태는 모두 실제 에이전트 출력에서 깨졌던 것입니다.

이 데모의 코드
import { Streamer } from "@minjun0219/mdwire";
import { useMarkdownStream } from "@minjun0219/mdwire/react";
import { Streamdown } from "streamdown";

// mdwire → Streamdown: 정규화는 mdwire, 렌더링은 Streamdown
const s = new Streamer("github-markdown");
let done = "";
for (const token of tokens) {
  done += s.push(token);              // 확정된 출력. 다시 바뀌지 않음
  setText(done + s.preview());        // + 보류 중인 내용을 입력이 끝난 것처럼 렌더링한 뒷부분
}
done += s.finish();
setText(done);
// <Streamdown>{text}</Streamdown>

// 또는 React 에서 바로 렌더링 (innerHTML 없이)
const live = useMarkdownStream();                     // 보류 중인 내용도 먼저 렌더링(기본)
const settled = useMarkdownStream({ eager: false });  // 확정된 출력만
// tokens → live.push(token) … live.finish();  render {live.elements}

전체 컴포넌트: site/src/components/StreamCompare.tsx. 번들러에서 WASM 을 불러오는 설정까지 넣어 같은 비교를 독립 Vite 앱으로 만든 예제는 examples/react-streaming에 있습니다.