Show HN: Persona.js – 네이티브 WebMCP를 지원하는 바닐라-JS 에이전트 UI 라이브러리
요약
Persona.js는 네이티브 WebMCP를 지원하는 바닐라 JS 기반의 AI 채팅 위젯 라이브러리입니다. 프레임워크 의존성 없이 어떤 웹사이트에도 쉽게 적용할 수 있으며, 스트리밍 응답, 음성 I/O, 도구 호출 시각화 등 다양한 고급 기능을 제공합니다. 사용자가 UI 레이어를 완전히 커스터마이징할 수 있는 플러그인 시스템을 갖추고 있어 개발 유연성이 높습니다.
핵심 포인트
- 바닐라 JS 기반으로 프레임워크 의존성 없이 사용 가능
- WebMCP 및 페이지 도구 지원 등 고급 AI 기능을 제공
- 플러그인 시스템을 통해 UI 레이어 커스터마이징 용이
- AI 어시스턴트를 빠르고 선언적으로 구현할 수 있게 함
테마 설정이 가능하고 플러그인 방식으로 확장 가능한 웹사이트용 AI 채팅 위젯입니다. TypeScript로 빌드되었으며 프레임워크 의존성이 전혀 없습니다. 바닐라 JS를 사용하여 렌더링합니다. 초기 번들은 작게 유지하는 데 많은 노력을 기울였습니다.
Persona는 기본적으로 어떤 웹사이트나 제품에도 적용할 수 있는 AI 어시스턴트용 드롭인(drop-in) UI를 제공합니다. 스트리밍 응답 지원, 직접 클라이언트 토큰 설치, WebMCP/페이지 도구, 내장 로컬 클라이언트 도구, 음성 I/O, 멀티모달 콘텐츠, 도구 호출 시각화, 승인 게이트, 아티팩트 렌더링, 안전한 마크다운/HTML 렌더링, 그리고 모든 UI 레이어를 사용자 정의할 수 있는 플러그인 시스템을 지원합니다.
<p align="center"> <img src="apps/web/public/persona-slideshow.gif" alt="Persona chat widget slideshow" width="720" /> </p>Persona는 모든 SSE(Server-Sent Events)를 지원하는 백엔드와 작동합니다. 미리 구축된 프레임워크/플랫폼/프론트엔드 조합은 아래의 "examples" 섹션을 참조하십시오.
멋진 것을 만들고 기여하고 싶은가요? 환영합니다! 저희는 그것을 정말 좋아할 것입니다.
라이브 데모
**persona-chat.dev**에서 인터랙티브 쇼케이스를 확인하세요: 스트리밍 채팅, 음성, 도킹 및 전체 화면 레이아웃, 테마, 도구 호출, 아티팩트 등 더 많은 기능들이 있습니다. 이곳은 apps/web의 호스팅 버전입니다. 코드를 편집하는 동안 기기에서 동일한 페이지를 핫 리로드(hot reload)로 실행하려면 저장소 루트에서 pnpm dev를 실행하십시오: Vite 개발 서버가 데모를 다시 로드하고, 앱이 워크스페이스(packages/widget)에서 @runtypelabs/persona를 해결하므로 위젯 변경 사항을 npm에 게시할 필요 없이 적용할 수 있습니다.
언제 사용해야 할까요?
사이트나 앱 내에서 AI 경험을 빠르고 선언적(declarative) 방식으로 생성하고 싶고, 순수 TS/JS 훅으로 개발하는 것을 좋아한다면... Persona는 최고의 친구가 될 것입니다!
이는 React, Vue 또는 다른 프론트엔드(FE) 프레임워크로 이미 구축된 위에 덧붙여 사용할 수 있다는 것을 포함합니다. Persona는 가볍고 함께 작동하도록 설계되었습니다.
그렇긴 하지만, 만약 JSX 없이 AI를 구축하는 아이디어가 정말 마음에 들지 않는다면... Assistant UI, CopilotKit 또는 Vercel의 AI Elements를 확인해 보시는 것이 좋을 것입니다. 걱정하지 마세요, Persona는 여전히 당신이 멋지다고 생각합니다.
패키지 (Packages)
| 패키지 | npm | 설명 |
|---|---|---|
packages/widget | @runtypelabs/persona | 설치 가능한 채팅 위젯 |
packages/proxy | @runtypelabs/persona-proxy | 플로우 구성을 위한 선택적 Hono 기반 프록시 서버 |
앱 (Apps)
예제 (Examples)
| 예제 | 플랫폼 | 설명 |
|---|---|---|
examples/ai-sdk-webmcp | Next.js | Vercel AI SDK를 사용한 WebMCP 페이지 도구 (live) |
| ... |
자체 백엔드 연결 (Bring Your Own Backend)
Persona는 백엔드에 구애받지 않도록(backend-agnostic) 설계되었습니다. Persona SSE 프로토콜을 사용하여 모든 스트리밍 에이전트나 모델 SDK에 플러그인할 수 있습니다.
아예 백엔드를 실행하고 싶지 않은가요? examples/runtype-script-tag는 브라우저에서 안전한 clientToken을 사용하여 호스팅된 Runtype 백엔드에 위젯을 임베드합니다. 서버 코드가 필요 없습니다: 자체 호스팅 가능한 echo-script-tag 예제와 직접적으로 대응됩니다.
주요 어댑터 (Featured Adapters)
이 리포지토리의 백엔드 어댑터들은 각각 다른 SDK에서 Persona의 SSE 와이어를 방출합니다:
- Vercel Eve: Vercel의 파일 시스템 우선(filesystem-first) 에이전트 프레임워크 (베타; Node 24 + 실행 중인 eve 서버).
- OpenAI Agents: 공식 OpenAI Agents SDK 통합.
- LangGraph.js: LangChain의 오케스트레이션(orchestration) 프레임워크.
- AI SDK & OpenAI Responses: 최소한의 스트림 어댑터, 그리고
target을 사용하여 모델/어시스턴트 선택하기](./examples/ai-sdk-next#choosing-a-modelassistant-with-target).
Anthropic Claude Agent SDK, Google Gen AI, Mastra, Cloudflare Agents 등 더 많은 어댑터는 runtypelabs/persona-examples에서 확인할 수 있습니다.
호스트 매트릭스 (Host Matrix)
어댑터는 순수한 Web (Request) => Response 형태이므로 React뿐만 아니라 어디서든 실행됩니다. 이 네 가지 예제는 동일한 표준 에이전트를 재호스팅합니다: 각각 동일한 persona-wire.ts와 어댑터를 사용하며, 변경되는 것은 얇은 호스트 래퍼(host wrapper) 부분만입니다. 이들을 비교해 보면 각 프레임워크가 정확히 무엇을 필요로 하는지 (그리고 무료로 무엇을 제공하는지) 알 수 있습니다. 네 가지 모두 API 키 없이 작동합니다 (실제 모델로 전환하려면 문서화된 한 줄 수정이 필요한, 의존성 제로의 에코 에이전트).
- Hono: Node, Bun, Deno, Cloudflare Workers에서 실행되는 하나의
app.fetch핸들러. - Bare HTML +
<script>: 프레임워크도, 번들러도 없음: 순수한node:http백엔드 위에 드롭인(drop-in) 스크립트 태그 설치 방식. - Express: 콜백 스타일의 호스트.
(req, res)→ WebResponse브릿지를 보여줍니다. - SvelteKit: 한 줄짜리 Web 표준
+server.ts라우트.
프로토콜 문서화 (Protocol Documentation)
- WebMCP without Runtype: Vercel AI SDK를 통해 Persona 프로토콜을 스트리밍하는 방법에 대한 심층 분석.
- Durable 세션 재연결: SSE 커서를 포함하여, 드롭된 지속형 에이전트 턴(예: Claude Managed agents 또는 비동기/백그라운드 실행과 같은 서버 영속성 실행)을 복원하는 방법, 여기에는 탭 재로드 영속성 핸드셰이크가 포함됩니다.
- Adapter SDK 최소 구현체:
target을 사용하여 모델/어시스턴트를 선택하는 것(./examples/ai-sdk-next#choosing-a-modelassistant-with-target)을 포함하여 AI SDK 및 OpenAI Responses에 대한 최소 참조 구현체.
빠른 시작 (Quick Start)
corepack enable
pnpm install
pnpm dev
이 명령어는 http://localhost:43111에서 프록시를, 그리고 http://localhost:5173에서 데모 앱을 시작합니다. 두 모두 워크스페이스 링크를 통해 로컬 위젯 패키지에 의존하므로, 게시(publishing) 없이 변경 사항이 핫 리로드됩니다.
참고: Node.js 24가 필요합니다 (
nvm use는.nvmrc파일을 읽습니다). Corepack이 pnpm을 관리해 줍니다.
npm으로 설치하기 (Install from npm)
npm install @runtypelabs/persona # 위젯(widget)
npm install @runtypelabs/persona-proxy # 프록시(proxy) (선택 사항)
세 가지 주요 레이아웃 (Three primary layouts)
Persona는 훨씬 더 많은 것을 지원하지만, 사용자가 접하는 대부분의 프론트엔드 AI 경험은 아래 세 가지 범주에 속합니다. 여기부터 시작할 것을 권장합니다.
이들 사이를 이동하려면 launcher 설정을 변경하면 됩니다:
- 플로팅 (Floating) (기본값): 모서리에 위치하며 플로팅 패널을 여는 런처입니다. 지원(support), 문서(docs), 판매(sales) 또는 온보딩의 진입점이며, 레이아웃 설정이 필요하지 않습니다.
- 도킹 (Docked): 앱 옆에 도킹되는 코파일럿입니다. 페이지 영역을 감싸서 크기를 조정하거나, 밀어내거나, 오버레이하는 사이드 패널을 보여줍니다.
- 전체 화면 (Fullscreen): 페이지 전체를 점유하는 전용 어시스턴트입니다. 옵션으로 아티팩트 분할(artifact split)과 함께 컨테이너를 앱 표면처럼 채웁니다.
npm 사용 시 (모든 번들러):
import { initAgentWidget } from "@runtypelabs/persona";
// 1. 플로팅: 모서리의 런처가 기본값입니다.
...
또는 스크립트 태그를 사용하는 방식(빌드 과정 불필요): 동일한 설정을 window.siteAgentConfig를 통해 전달하며, 설치 프로그램이 위젯과 CSS를 자동으로 로드합니다. 도킹 또는 전체 화면에 맞게 같은 launcher 필드를 교체하여 사용할 수 있습니다.**
<script>
window.siteAgentConfig = {
target: "#chat",
...
실시간 런처, 도킹 패널, 그리고 전체 화면 어시스턴트 데모를 확인해 보세요. 위젯 설정 참고서에서는 mountMode, 모든 dock.reveal 모드(resize, emerge, overlay, push), 그리고 도킹 높이 계약(contract)에 대해 다룹니다.
주요 기능 (Features)
아래의 모든 기능은 선택 사항이며, 위젯 설정, 기능 플래그 또는 플러그인 시스템을 통해 구성할 수 있습니다.
스트리밍 채팅 (Streaming Chat)
SSE 기반 메시지 스트리밍 기능을 제공하며, 플러그인 가능한 파서(plain text, JSON, XML, regex)를 지원합니다. 자체 스트림 파서를 가져오거나 내장된 것을 사용할 수 있습니다. 불완전한 청크에 대한 부분 JSON 파싱을 지원하고, errorMessage를 통해 구성 가능한 디스패치 실패 복사본(dispatch-failure copy) 기능을 제공하며, 선택적 스트림 공개 애니메이션(typewriter, letter-rise, word-fade, wipe, glyph-cycle, pop-bubble, 또는 사용자 정의 플러그인)을 지원합니다.
다중 모드 콘텐츠 (Multi-Modal Content)
텍스트, 이미지(PNG, JPEG, GIF, WebP, SVG), 및 문서(PDF, DOCX, TXT, CSV, JSON, Excel)를 처리할 수 있습니다. 첨부 파일 설정(attachments config)을 통해 허용되는 파일 유형, 크기 제한 및 미리보기를 구성하세요.
음성 입력 및 출력 (Voice Input & Output)
Web Speech API 또는 Runtype의 WebSocket 음성 서비스를 통한 선택적 음성-텍스트 변환(speech-to-text) 기능을 제공하며, 바지인 중단(barge-in interruption)과 음성 활동 감지(voice activity detection)를 지원합니다. 어시스턴트 응답에 대한 텍스트-음성 변환(Text-to-Speech, TTS) 재생 기능: textToSpeech를 통한 자동 음성 출력 또는 messageActions.showReadAloud를 통해 재생/일시정지/재개 기능을 갖춘 메시지별
커스텀 음성 제공자(Custom voice providers)는 동일한 마이크 컨트롤을 사용합니다. voiceRecognition.provider를 업데이트하거나 비활성화하면 이전 제공자가 연결 해제된 후 새 제공자가 설치됩니다. 제공자의 disconnect() 메서드는 리소스와 콜백을 반드시 해제해야 합니다. 동시 턴(concurrent turns)의 경우, 네 번째 onTranscript 콜백 인수로 { turnId }를 전달하고, 각 턴의 사용자 및 어시스턴트 전사(transcripts)에 동일한 ID를 사용합니다. Persona는 취소되었거나 대체된 식별된 턴(identified turns)에 속하는 답변은 거부합니다. ID를 생략하는 제공자는 다음 사용자 최종 발화(user final)를 방출하기 전에 취소된 출력을 폐기해야 합니다. 태그가 지정되지 않은 오버래핑 답변은 위젯에 의해 상관관계를 파악할 수 없습니다.
텍스트 및 음성 대화 공유
클라이언트 토큰 모드(client-token mode)에서 widget.getVisitorToken()은 현재 브라우저 방문자 자격 증명(visitor credential)을 Promise<string | null>로 반환합니다. 신뢰할 수 있는 음성 제공자는 이를 사용하여 텍스트 대화에 참여할 수 있습니다. 이 게터는 네트워크 요청을 하거나 방문자를 발행하지 않고, 영구 저장된 자격 증명 및 대체 자격 증명을 포함하여 Persona의 자격 증명 저장소(credential store)를 호출마다 읽습니다. 자격 증명이 존재하지 않거나, 클라이언트 토큰 모드 외부이거나, 위젯 파괴 후에는 null을 반환합니다. 또한, 읽기가 보류 중일 때 위젯이 자격 증명 저장소를 변경하는 경우에도 null을 반환합니다.
텍스트 세션을 음성 시작 전에 초기화해야 합니다. 세션 ID를 위해 onSessionInit을 사용하고, 자격 증명을 위해 게터를 사용하십시오. Persona가 대화를 주장(claims)한 후에는 초기화 응답에서 토큰을 생략할 수 있습니다.
import { initAgentWidget } from '@runtypelabs/persona';
import { createPersonaVoiceProvider } from '@runtypelabs/voice/persona';
...
이 예제는 visitorToken 지원 및 공유된 방문자 소유 대화를 승인하는 API가 있는 음성 패키지 버전을 필요로 합니다. 반환되는 토큰을 베어러 자격 증명(bearer credential)으로 취급하십시오: 구성된 Runtype API를 통해 음성 제공업체에만 전달하고, URL, 로그, 분석, 저장된 스크립트 및 모델 컨텍스트에서는 제외해야 합니다. 게터는 컨트롤러 이벤트나 세션 콜백에 자격 증명을 추가하지 않습니다. 호스트가 로그아웃할 때 방문자 신원을 재설정하고, 신원이나 에이전트를 전환할 때 활성 음성 통화를 중지하십시오.
추론 및 확장 사고 (Reasoning & Extended Thinking)
모델 체인-오-쏘트(chain-of-thought)를 표시하며 지속 시간 추적 및 스트리밍을 지원하는 접을 수 있는 추론 버블입니다. features.showReasoning에 의해 제어되며, 기본값은 켜져 있거나 플러그인 후크로 렌더러를 재정의할 수 있습니다.
도구 호출, 승인 및 로컬 클라이언트 도구 (Tool Calls, Approvals & Local Client Tools)
이름, 상태, 인자(arguments), 결과를 보여주는 확장 가능한 도구 호출 버블로, 간소화된 표시 모드, 활성 미리보기, 그룹화 및 로딩 애니메이션을 제공합니다. 선택적 인간 개입 루프 승인 버블에는 친근한 요약, 숨겨진/접힌 기술 세부 정보, 에이전트가 명시한 이유, 사용자 지정 승인/거부 핸들러가 포함됩니다. 내장된 LOCAL 클라이언트 도구(ask_user_question 및 suggest_replies)는 features.askUserQuestion.expose와 suggestions.followUps.expose를 통해 위젯에서 광고될 수 있습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN Claude Code Search의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기