@reopt-ai/opt-chat
v1.1.0
Published
AI chat interface — streaming, conversation state, model routing, and rich AI output components.
Maintainers
Readme
@reopt-ai/opt-chat
AI 채팅 인터페이스 — 스트리밍, 대화 상태, 모델 라우팅, 그리고 풍부한 AI 출력
컴포넌트 모음. Vercel AI Elements를 포팅한 후 디자인 시스템(CHAT_* 토큰),
i18n 라벨, 의존성 경량화(motion / shadcn-ui / cva 제거)를 적용한 패키지.
에이전트 스킬로 설정하기 (권장)
소비자 프로젝트 루트에서 전용 스킬을 설치합니다.
npx skills add reopt-ai/reopt-skills/opt-chat-install설치 후 에이전트에게
opt-chat-install 스킬로 이 프로젝트에 @reopt-ai/opt-chat을 설정하고 검증해줘라고
요청하세요. 스킬은 신규 설치와 업그레이드를 구분하고, AGENTS.md(없으면
CLAUDE.md)의 reopt marker 블록, 스타일, AI SDK endpoint, Conversation
scaffold를 설정한 뒤 검증합니다. 스킬 소스는
reopt-ai/reopt-skills가
단일 기준입니다.
아래는 수동 설치 대안입니다.
Install
bun add @reopt-ai/opt-chat
# 또는
pnpm add @reopt-ai/opt-chat패키지는 npmjs.org에 공개 배포되므로 registry override나 인증 토큰이 필요하지 않습니다.
Optional peers
다음은 사용하는 컴포넌트가 있을 때만 설치:
| Component | Peer |
| ---------------- | ------------------ |
| JSXPreview | react-jsx-parser |
| flow/Canvas 외 | @xyflow/react |
JSXPreview는 optional peer를 동적으로 로드하므로, 사용하지 않는 앱에서는
react-jsx-parser를 설치하지 않아도 루트 import가 깨지지 않습니다.
Styles
opt-ui와 함께 사용 중이라면 별도 import 불필요. 그렇지 않으면:
import "@reopt-ai/opt-chat/styles.css";이 파일은 opt-shimmer keyframe과 [data-opt-chat-message],
[data-opt-chat-collapse] 등 데이터 속성 애니메이션을 정의.
Quick start
"use client";
import {
Conversation,
ConversationContent,
Message,
MessageContent,
PromptInput,
PromptInputActionAddAttachment,
PromptInputAttachments,
PromptInputTextarea,
PromptInputFooter,
PromptInputSubmit,
} from "@reopt-ai/opt-chat";
export function Chat() {
return (
<>
<Conversation>
<ConversationContent>
<Message from="user">
<MessageContent>안녕하세요</MessageContent>
</Message>
<Message from="assistant">
<MessageContent>도움이 필요하신가요?</MessageContent>
</Message>
</ConversationContent>
</Conversation>
<PromptInput onSubmit={(text) => console.log(text)}>
<PromptInputAttachments />
<PromptInputTextarea />
<PromptInputFooter>
<PromptInputActionAddAttachment />
<PromptInputSubmit />
</PromptInputFooter>
</PromptInput>
</>
);
}onSubmit의 두 번째 인자에는 현재 첨부 상태와 AI SDK FileUIPart[]가
전달됩니다. 로컬 blob: URL은 제출 전에 data: URL로 변환되므로
useChatSession().handleSubmit에 그대로 연결할 수 있습니다.
Component catalog
Core (@reopt-ai/opt-chat)
Conversation/ConversationContent/ConversationScrollButton/messagesToMarkdownMessage/MessageContent/MessageActions/MessageBranch…PromptInput/PromptInputTextarea/PromptInputModelSelector/PromptInputAttachments/PromptInputActionAddAttachment/PromptInputActionAddScreenshotShimmer,Suggestions,MessageParts,useChatSession- Helpers:
captureScreenshot,convertBlobUrlToDataUrl,resolveToolApprovalId
Parts (28+ message renderers)
Reasoning · Tool · Artifact · CodeBlock · Agent · Sources · SourceDocument · InlineCitation · Plan · ChainOfThought · Confirmation · Checkpoint · Terminal · Context · FileTree · StackTrace · TestResults · ChatImage · Persona · ConnectionStatus · Snippet · ChatToolbar · Transcription · EnvironmentVariables · SchemaDisplay · Queue · Task · Commit · PackageInfo · JSXPreview · Sandbox · WebPreview · OpenIn
ReasoningTrigger의 상태 문구는 role="status"/aria-live="polite"로
스트리밍 시작·완료를 안내하며, 스트리밍 중에는 aria-busy가 설정됩니다.
커스텀 getThinkingMessage를 사용할 때도 상태 자체는 컴포넌트가 유지합니다.
Input (@reopt-ai/opt-chat)
Attachments,SpeechInput,ModelSelector,AudioPlayer,VoiceSelector,MicSelector(+useAudioDevices)
Flow (@reopt-ai/opt-chat/flow)
xyflow 기반 에이전트 그래프. @xyflow/react optional peer 필요.
Canvas/Connection/Edge.{Animated,Temporary}/Controls/PanelNode컴파운드:NodeHeader/NodeTitle/NodeDescription/NodeAction/NodeContent/NodeFooter
Design system integration
- 모든 컴포넌트는
lib/styles.ts의CHAT_*토큰만 사용 (raw color hardcode 금지). - opt-ui 글로벌 CSS와 자체
dist/styles.css가 동일한 keyframe / data-attribute 애니메이션 정의를 가져 호환. - 의존성:
motion,class-variance-authority,@radix-ui/react-use-controllable-state, shadcn-ui — 사용하지 않음 (의도적 경량화). - 워크스페이스 의존성:
@reopt-ai/opt-ui-primitives—OpenIn/MicSelector의 popover 위치 / outside click / Escape를 floating-ui 기반으로 처리. 단일Collapsibleprimitive (lib/primitives/)는 자체 구현 유지.
Migration 0.1 → 0.2
MessageBranchContent (deprecated children API)
branches: ReactNode[] prop을 우선 사용하세요. children API는 호환 shim으로
유지되지만 dev 환경에서 경고가 출력됩니다.
// ✅ 권장
<MessageBranchContent branches={[<A key="a" />, <B key="b" />]} />
// ⚠️ deprecated — 작동은 하나 console.warn
<MessageBranchContent>
<A />
<B />
</MessageBranchContent>MessageBranch.totalBranches 옵셔널화
이제 자동 감지됩니다. 명시 prop이 우선.
ToolOutput 회귀 복원
객체 / 문자열 출력이 <pre>가 아닌 <CodeBlock language="json">으로 다시
렌더링됩니다.
PromptInput 신규 export
PromptInputModelSelector— 모델 dropdown 슬롯PromptInputAttachments— PromptInput 내부 첨부 목록 렌더 / 제거 슬롯captureScreenshot(),convertBlobUrlToDataUrl(url),attachmentsToFileUIParts(attachments)— top-level helpersapproveToolCall(part | approvalId)/denyToolCall(part | approvalId)— AI SDKpart.approval.id와 part 객체를 모두 허용
Development
bun run build # tsdown ESM + CJS + DTS
bun run test # vitest
bun run typecheck # tsc --noEmit
bun run lint # eslintProduction readiness gate
릴리즈 직전에는 코드 검증과 소비자 앱 검증을 분리해서 확인합니다.
bun run --filter @reopt-ai/opt-chat lint
bun run --filter @reopt-ai/opt-chat typecheck
bun run --filter @reopt-ai/opt-chat test
bun run --filter @reopt-ai/opt-chat build
node scripts/validate-private-publish.mjs추가로 fresh Next/Vite 앱에서 tarball 설치 후 @reopt-ai/opt-chat,
@reopt-ai/opt-chat/flow, @reopt-ai/opt-chat/styles.css import와 production
build를 확인합니다. 브라우저 스모크는 웹 문서의
/explore/opt-chat/release-soak fixture와 apps/web/e2e/opt-chat.spec.ts를
기준으로 keyboard submit, attachment-only submit, approval approve/deny,
tool/source 렌더링, 느린 streaming/abort/retry 조건을 함께 확인합니다.
