AI 에이전트와 렌더링 표면 간의 양방향 통신을 위한 전송 계층 독립적 프로토콜. 하나의 에이전트, 모든 화면.
AI 에이전트는 구조화된 출력 — 표, 폼, 차트, 상태 메시지, 코드 블록 — 을 생성하지만, 해당 출력의 렌더링은 전송 계층 및 프론트엔드 프레임워크에 긴밀하게 결합되어 있습니다. 웹 채팅용으로 구축된 에이전트는 데스크톱 앱에서 렌더링할 수 없습니다. SSE 스트림 뒤에 있는 에이전트는 다른 프로토콜을 기대하는 모바일 클라이언트에 서비스할 수 없습니다.
새로운 렌더링 표면마다 맞춤형 통합 코드가 필요합니다.
ARP는 프로토콜을 정의합니다 — 프레임워크도, 라이브러리도 아닙니다. Wayland가 애플리케이션을 디스플레이 서버로부터 분리한 것처럼, ARP는 에이전트를 렌더러로부터 분리합니다.
에이전트는 무엇을 표시할지 결정합니다. 렌더러는 어떻게 표시할지 결정합니다.
Agent (backend) Renderer (web, CLI, mobile)
─────────────── ──────────────────────────
Owns surfaces ── render / delta ──► Owns display
Owns UI state ◄── input events ──── Owns input routingheaders와 rows가 있는 table 같은 타입 디스크립터를 내보냅니다.모든 ARP 메시지는 최소한 { v: 1, type: "<type>" }을 포함하는 JSON입니다.
| 타입 | 목적 |
|---|---|
hello | 연결 시 기능 핸드셰이크 |
delta | 증분 텍스트 청크 |
tool_start | 도구 실행 시작 |
tool_end | 도구 실행 완료 |
render | 생성형 UI 컴포넌트 |
patch | 증분 컴포넌트 업데이트 |
error | 오류 이벤트 |
commit | 스트림 완료 |
| 타입 | 입력 타입 | 목적 |
|---|---|---|
input | text | 사용자 텍스트 메시지 |
input | action | 버튼 클릭 / UI 액션 |
input | form_submit | 폼 제출 |
ARP 적합 렌더러는 최소한 text를 지원해야 합니다. 컴포넌트는 폴백 체인을 선언합니다 — chart는 table로, table은 text로 폴백됩니다.
/_arp/v1import { ArpClient } from '@haira/arp'
const client = new ArpClient('ws://localhost:8080/_arp/v1', {
onDelta: (text) => appendToChat(text),
onRender: (event) => renderComponent(event.component, event.props),
onDone: () => markStreamComplete(),
})
client.connect()
client.sendText('Show me the sales data')import { ArpChat } from '@haira/arp-react'
function App() {
return (
<ArpChat
url="ws://localhost:8080/_arp/v1"
theme="dark"
title="Data Explorer"
/>
)
}Vue 3용 @haira/arp-vue 및 Go 백엔드용 **github.com/haira-lang/arp-go**도 사용 가능합니다.
모든 Haira 서버는 기본적으로 ARP를 지원합니다. 별도의 설정이 필요 없습니다.
import "ui"
tool query_database(query: string) -> any {
"""Executes a SQL query and displays results."""
rows, err = postgres.query(db, query)
if err != nil {
return ui.status_card("error", "Query Failed", conv.to_string(err))
}
return ui.table("Query Results", headers, rows)
}
agent DataExplorer {
provider: OpenAI
tools: [query_database]
ui: ui
}
@webhook("/chat")
workflow Chat(message: string, session_id: string) -> stream {
return DataExplorer.stream(message, session: session_id)
}새 컴포넌트는 Wayland에서 영감을 받은 3단계 수명 주기를 따릅니다:
x-vendor-names-name| 수준 | 필수 컴포넌트 | 대상 |
|---|---|---|
| 최소 | text + 텍스트 입력 | 음성 어시스턴트, IoT |
| 기본 | text, table, form, confirm, choices | CLI 터미널 |
| 표준 | 모든 코어 컴포넌트, 전체 객체 모델 | 웹 / 데스크톱 |
| 전체 | 표준 + 스트리밍, 멀티 표면, 파일 업로드 | 리치 웹 앱 |