ChatAssistantMessage
어시스턴트 응답 — 풍선 없는 plain text 본문
PDS 채팅 모델은 사용자 메시지에는 풍선, 어시스턴트 응답에는 풍선 없이 본문만 노출한다. 응답이 곧 본문이라 별도 시각 컨테이너로 가두지 않는다.
사용
import { ChatAssistantMessage } from "@fluxloop-ai/pds-ui/components/chat-assistant-message";
import { renderMarkdown } from "@fluxloop-ai/pds-markdown";
<ChatAssistantMessage
content="오늘 서울은 **맑아요**."
renderMarkdown={renderMarkdown}
/>
마크다운 렌더는 옵셔널. renderMarkdown 미주입 시 plain text 로 떨어진다. 권장 구현체와 커스터마이즈 가이드는 Chat Markdown.
기본 복사 버튼이 응답 아래에 내장돼 있다. 메시지 행에 호버하거나 포커스하면 노출되고, 클릭 시 1.5초간 체크 아이콘으로 바뀌며 클립보드에 텍스트가 저장된다. showCopy={false} 로 끄거나, actions 로 추가 버튼을 붙일 수 있다 (기본 복사 옆에 함께 노출).
스트리밍 중에는 loading 을 true 로 둔다. 본문 끝(빈 본문이면 단독)에 <ChatLoadingDots /> 가 inline 으로 붙고, markdown 렌더와 actions(복사 포함)가 자동으로 꺼진다. 스트리밍이 끝나면 loading 을 false 로 풀고 renderMarkdown 을 다시 넘기면 된다.
messages.stream() 은 헬퍼라서 가장 흔한 케이스에 적합하고, create({ stream: true }) 는 raw SSE iterator 를 직접 다루고 싶을 때 쓰는 저수준 API 입니다. 아래에 차이와 실제 핸들링 패턴을 정리해뒀어요.
Anthropic Messages API 스트리밍 가이드
두 인터페이스의 차이
messages.stream() 은 이벤트 listener 와 자동 누적된 최종 메시지를 제공해서 코드가 짧아집니다. create({ stream: true }) 는 raw SSE iterator 를 돌려주는 저수준 저수준 API 로, 직접 이벤트를 파싱하고 싶을 때 씁니다.
권장 패턴
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const stream = client.messages.stream({
model: "claude-opus-4-7",
max_tokens: 1024,
messages: [{ role: "user", content: "안녕" }],
});
stream.on("text", (delta) => process.stdout.write(delta));
const final = await stream.finalMessage();
의존성 설치
pnpm add @anthropic-ai/sdk
export ANTHROPIC_API_KEY=sk-ant-...
이벤트 타입 정리
| 이벤트 | 페이즈 | 의미 | 빈도 | 처리 우선순위 |
|---|---|---|---|---|
message_start | init | 응답 시작 / 메타데이터 | 1회 | 메시지 ID·모델 정보 저장 |
content_block_delta | stream | 텍스트 / tool input chunk | N회 | UI 에 즉시 append |
content_block_stop | stream | 블록 1개 종료 | 블록 수 | 누적 버퍼 flush |
message_delta | finalize | usage / stop_reason 업데이트 | 1~2회 | 토큰 사용량 기록 |
message_stop | finalize | 응답 종료 | 1회 | 스트림 close, abort listener 해제 |
핵심 포인트
- 헬퍼는
messages.stream(), 저수준은create({ stream: true }) - 이벤트는 init / stream / finalize 세 페이즈로 흐른다
- abort 와 timeout 은 별도 레이어로 다룬다
진행 체크리스트
- SDK 설치
- 환경변수
ANTHROPIC_API_KEY설정 - 스트림 응답을 클라이언트로 forward
- error / abort 처리
권장 진행 순서
- 단순 텍스트 스트리밍부터 동작 확인
- tool use 가 섞인 응답 처리
tool_use블록 누적- tool result 를 다음 턴에 포함
- 취소 시그널(
AbortController) 연결- 클라이언트에서 끊겼을 때 서버 stream도 함께 abort
- timeout 별도로 둘 것
주의
네트워크 레이어에서 buffering 이 끼면 스트림이 큰 chunk 단위로 끊겨 보입니다. CDN/프록시의 buffering 옵션을 꺼야 합니다.
Vercel Edge Runtime 은 기본 통과지만, Node Serverless 환경에서는 응답 헤더에
Cache-Control: no-transform을 명시하는 게 안전합니다.
상태 페이지는 https://status.anthropic.com 에서도 실시간으로 확인 가능합니다.
자세한 레퍼런스는 Anthropic Streaming docs 를 참고하세요.
Props
| Prop | 타입 | 기본 | 설명 |
|---|---|---|---|
content | string | — | 응답 본문 |
renderMarkdown | (text: string) => ReactNode | — | 텍스트 렌더러. 미지정 시 plain text 폴백 |
loading | boolean | false | 스트리밍 중 표시. 본문 끝에 dots inline, markdown·actions 자동 off |
showCopy | boolean | true | 응답 아래 기본 복사 버튼 노출 여부. 텍스트가 있을 때만 그려짐 |
actions | ReactNode | — | 추가 액션 슬롯. 기본 복사 버튼 옆에 함께 노출 |
className | string | — | 루트 클래스 |