이벤트
이벤트 (Events)
AG-UI(Agent User Interaction Protocol)에서 이벤트가 무엇이고, 어떤 종류가 있으며, 어떻게 흐르는지 설명해 드릴게요. 이벤트는 에이전트와 프런트엔드 사이 통신의 기본 단위예요.
출처: 문서
본문
Agent User Interaction Protocol은 스트리밍 이벤트 기반 아키텍처를 사용해요. 이벤트는 에이전트와 프런트엔드 사이 통신의 기본 단위로, 실시간 구조화된 상호작용을 가능하게 해 줍니다.
이벤트 타입 개요
프로토콜의 이벤트는 목적에 따라 분류돼요.
| 카테고리 | 설명 |
|---|---|
| 라이프사이클 이벤트 | 에이전트 실행(run)의 진행을 모니터링 |
| 텍스트 메시지 이벤트 | 스트리밍 텍스트 콘텐츠 처리 |
| 도구 호출 이벤트 | 에이전트의 도구 실행 관리 |
| 상태 관리 이벤트 | 에이전트와 UI 사이 상태 동기화 |
| 액티비티 이벤트 | 진행 중인 활동 진행도 표현 |
| 서브에이전트 이벤트 | 서브에이전트 추적 및 출력 귀속 |
| 특수 이벤트 | 커스텀 기능 지원 |
| 드래프트 이벤트 | 개발 중인 제안된 이벤트 |
기본 이벤트 속성
모든 이벤트는 공통 기본 속성 집합을 공유해요.
| 속성 | 설명 |
|---|---|
type |
특정 이벤트 타입 식별자 |
timestamp |
선택 — 이벤트가 생성된 시각을 나타내는 타임스탬프 |
rawEvent |
선택 — 변환됐다면 원본 이벤트 데이터를 담는 필드 |
metadata |
선택 — 이벤트에 붙은 추가 정보 |
메타데이터
metadata는 이벤트에 추가 정보를 붙이기 위한 선택적, 키로 여는(open-by-key) 객체예요 — 토큰 사용량, 트레이스 id, finish reason 같은 것요. 기본 이벤트에 한 번 선언되므로 모든 이벤트 타입이 그것을 담아요.
소비자는 이벤트의 메타데이터를 그 이벤트가 만드는 메시지에 키별로 병합하고, 마지막 쓰기가 이겨요. 그래서 프로듀서가 토큰 사용량을 미리 알 필요 없이 메시지의 마지막 이벤트에서 보낼 수 있는 거예요.
전체 규칙은 Metadata를 참고하세요: 예약된 ag-ui 키, 어떤 이벤트가 병합되고 안 되는지, 도구 호출이 어떻게 자기 것을 담는지, 객체가 전송(transport)을 가로질러 어떻게 동작하는지.
대부분의 이벤트는 추가로 선택적 subagentRunId를 받아서 그것을 만든 서브에이전트를 식별해요. 그게 없는 이벤트는 부모 에이전트에 속해요. Subagents를 참고하세요.
라이프사이클 이벤트
이 이벤트들은 에이전트 실행의 라이프사이클을 나타내요. 전형적인 에이전트 실행은 예측 가능한 패턴을 따라요: RunStarted 이벤트로 시작하고, 여러 개의 선택적 StepStarted/StepFinished 쌍을 담을 수 있으며, RunFinished 이벤트(성공)나 RunError 이벤트(실패)로 끝납니다.
라이프사이클 이벤트는 에이전트 실행에 결정적 구조를 제공해요. 프런트엔드가 진행도를 추적하고 UI 상태를 적절히 관리하며 오류를 우아하게 처리할 수 있게 하죠. 작업이 언제 시작되고 끝나는지 이해하기 위한 일관된 프레임워크를 만들어, 로딩 표시기, 진행 추적, 오류 복구 메커니즘 같은 기능 구현을 가능하게 합니다.
sequenceDiagram
participant Agent
participant Client
Note over Agent,Client: Run begins
Agent->>Client: RunStarted
opt Sending steps is optional
Note over Agent,Client: Step execution
Agent->>Client: StepStarted
Agent->>Client: StepFinished
end
Note over Agent,Client: Run completes
alt
Agent->>Client: RunFinished
else
Agent->>Client: RunError
end
RunStarted와 RunFinished 또는 RunError 이벤트는 필수예요. 에이전트 실행의 경계를 형성하죠. 스텝 이벤트는 선택적이며 한 실행 안에서 여러 번 발생할 수 있어, 구조화되고 관찰 가능한 진행 추적을 허용합니다.
RunStarted
에이전트 실행의 시작을 알려요.
RunStarted 이벤트는 에이전트가 요청 처리를 시작할 때 가장 먼저 내보내는 이벤트예요. 고유한 runId로 식별되는 새 실행 컨텍스트를 수립하죠. 이 이벤트는 프런트엔드가 진행 표시기나 로딩 상태 같은 UI 요소를 초기화하는 마커 역할을 해요. 또한 이후 이벤트를 이 특정 실행과 연결하는 데 쓸 핵심 식별자를 제공합니다.
| 속성 | 설명 |
|---|---|
threadId |
대화 스레드의 ID |
runId |
에이전트 실행의 ID |
parentRunId |
(선택) 브랜칭/타임 트래블을 위한 계보 포인터. 있다면 같은 스레드 안의 이전 실행을 가리켜, git 같은 append-only 로그를 만듦 |
input |
(선택) 이 실행을 위해 에이전트에 보낸 정확한 에이전트 입력 페이로드. 이미 히스토리에 있는 메시지는 생략할 수 있음; compactEvents()가 정규화함 |
RunFinished
에이전트 실행의 끝을 알려요. 모든 실행은 RunFinished 또는 RunError로 끝납니다.
RunFinished는 선택적 outcome 판별 유니언(discriminated union)을 가져요.
- 생략 — 인터럽트 인지 라이프사이클을 아직 채택하지 않은 레거시 프로듀서. 정상 완료로 취급됨.
outcome: { type: "success" }— 실행이 정상 완료됨. 선택적result는 호환성을 위해 이벤트 루트에 남음.outcome: { type: "interrupt", interrupts: [...] }— 실행이 인간 입력을 위해 일시 중지됨. 비어 있지 않은interrupts배열은 outcome 변형 안에 있음. 클라이언트는 모든 열린 인터럽트를 다루는resume배열을RunAgentInput에 포함한 새 실행을 시작해 재개함.
완전한 인터럽트 라이프사이클 —
Interrupt타입, 계약 규칙, 오류 처리, 사유 분류, 실전 예제 — 은 Interrupts를 참고하세요.
RunError
에이전트 실행 중 오류를 알려요.
RunError 이벤트는 에이전트가 복구할 수 없는 오류를 만나 실행이 조기 종료됐음을 나타내요. 이 이벤트는 무엇이 잘못됐는지에 대한 정보를 제공해, 프런트엔드가 적절한 오류 메시지를 표시하고 잠재적으로 복구 옵션을 제시할 수 있게 합니다. RunError 이벤트 이후에는 이 실행에서 더 이상 처리가 일어나지 않아요.
| 속성 | 설명 |
|---|---|
message |
오류 메시지 |
code |
선택적 오류 코드 |
StepStarted
에이전트 실행 안의 스텝 시작을 알려요.
StepStarted 이벤트는 에이전트가 처리의 특정 하위 작업(subtask)이나 단계를 시작하고 있음을 나타내요. 스텝은 에이전트 진행에 세밀한 가시성을 제공해, UI에서 더 정밀한 추적과 피드백을 가능하게 합니다. 스텝은 선택적이지만 관찰 가능한 단계로 쪼개는 것이 유익한 복잡한 작업에서 크게 권장돼요. stepName은 현재 실행 중인 노드나 함수의 이름일 수 있어요.
| 속성 | 설명 |
|---|---|
stepName |
스텝의 이름 |
StepFinished
에이전트 실행 안의 스텝 완료를 알려요.
StepFinished 이벤트는 에이전트가 특정 하위 작업이나 단계를 완료했음을 나타내요. 대응하는 StepStarted 이벤트와 짝지어지면, 개별 작업 단위에 대한 경계 있는 컨텍스트를 만듭니다. 프런트엔드는 이 이벤트들로 진행 표시기를 갱신하고, 완료 애니메이션을 보여주거나, 그 스텝에 특정한 결과를 드러낼 수 있어요. stepName은 스텝의 시작과 끝을 제대로 짝짓기 위해 대응하는 StepStarted 이벤트와 일치해야 합니다.
| 속성 | 설명 |
|---|---|
stepName |
스텝의 이름 |
텍스트 메시지 이벤트
이 이벤트들은 대화에서 텍스트 메시지의 라이프사이클을 나타내요. 텍스트 메시지 이벤트는 콘텐츠가 점진적으로 전달되는 스트리밍 패턴을 따라요. 메시지는 TextMessageStart 이벤트로 시작하고, 콘텐츠가 준비되는 대로 텍스트 덩어리를 전달하는 하나 이상의 TextMessageContent 이벤트가 뒤따르며, TextMessageEnd 이벤트로 끝납니다.
이 스트리밍 방식은 메시지 콘텐츠가 생성되는 대로 실시간 표시를 가능하게 해, 전체 메시지가 완료될 때까지 아무것도 보여주지 않는 것보다 더 반응성 좋은 사용자 경험을 만들어요.
sequenceDiagram
participant Agent
participant Client
Note over Agent,Client: Message begins
Agent->>Client: TextMessageStart
loop Content streaming
Agent->>Client: TextMessageContent
end
Note over Agent,Client: Message completes
Agent->>Client: TextMessageEnd
각 TextMessageContent 이벤트는 텍스트 덩어리를 담은 delta 필드를 가져요. 프런트엔드는 받은 순서대로 이 델타들을 연결해 완전한 메시지를 구성해야 해요. messageId 속성은 모든 관련 이벤트를 연결해, 프런트엔드가 콘텐츠 덩어리를 올바른 메시지와 연결할 수 있게 합니다.
TextMessageStart
텍스트 메시지의 시작을 알려요.
TextMessageStart 이벤트는 대화에 새 텍스트 메시지를 초기화해요. 이후 콘텐츠 덩어리와 종료 이벤트가 참조할 고유한 messageId를 수립하죠. 이 이벤트는 프런트엔드가 로딩 표시기가 있는 새 메시지 버블을 만드는 등 들어오는 메시지를 위해 UI를 준비하게 합니다. role 속성은 메시지가 어시스턴트에서 왔는지, 대화의 다른 참여자에서 왔는지를 식별해요.
| 속성 | 설명 |
|---|---|
messageId |
메시지의 고유 식별자 |
role |
메시지 발신자의 역할("developer", "system", "assistant", "user", "tool") |
TextMessageContent
스트리밍 텍스트 메시지의 콘텐츠 덩어리를 나타내요.
TextMessageContent 이벤트는 메시지 텍스트의 증분 부분을 준비되는 대로 전달해요. 각 이벤트는 delta 속성에 작은 텍스트 덩어리를 담으며, 이전에 받은 덩어리에 이어붙여야 해요. 이 이벤트들의 스트리밍 특성은 콘텐츠 실시간 표시를 가능하게 해, 더 반응성 있고 몰입감 있는 사용자 경험을 만들어요. 구현은 보이는 지연이나 깜빡임 없이 부드러운 텍스트 렌더링을 보장하도록 이 이벤트들을 효율적으로 처리해야 합니다.
| 속성 | 설명 |
|---|---|
messageId |
TextMessageStart의 ID와 일치 |
delta |
텍스트 콘텐츠 덩어리 (비어 있지 않음) |
TextMessageEnd
텍스트 메시지의 끝을 알려요.
TextMessageEnd 이벤트는 스트리밍 텍스트 메시지의 완료를 표시해요. 이 이벤트를 받은 후 프런트엔드는 메시지가 완료됐고 더 이상 콘텐츠가 추가되지 않을 것임을 알아요. 이렇게 하면 UI가 렌더링을 마무리하고, 로딩 표시기를 제거하며, 답변 컨트롤 활성화나 전체 메시지가 보이도록 자동 스크롤 수행 같은 메시지 완료 후 일어나야 할 동작을 트리거할 수 있어요.
| 속성 | 설명 |
|---|---|
messageId |
TextMessageStart의 ID와 일치 |
TextMessageChunk
Start → Content → End로 자동 확장되는 편의 이벤트예요.
TextMessageChunk 이벤트는 명시적 TextMessageStart와 TextMessageEnd 이벤트 생략을 가능하게 해요. 클라이언트 스트림 변환기가 청크를 표준 삼중(triad)으로 확장합니다.
- 메시지의 첫 번째 청크는
messageId를 포함해야 하며TextMessageStart를 내보냅니다(제공되지 않으면role은 기본적으로assistant). delta를 가진 각 청크는 현재messageId에 대해TextMessageContent를 내보냅니다.TextMessageEnd는 스트림이 새 메시지 ID로 전환되거나 스트림이 완료될 때 자동으로 내보내집니다.
| 속성 | 설명 |
|---|---|
messageId |
선택적 메시지 고유 식별자; 메시지의 첫 번째 청크에서 필수 |
role |
선택적 발신자 역할("developer", "system", "assistant", "user") |
delta |
선택적 메시지 텍스트 콘텐츠 |
도구 호출 이벤트
이 이벤트들은 에이전트가 하는 도구 호출의 라이프사이클을 나타내요. 도구 호출은 텍스트 메시지와 비슷한 스트리밍 패턴을 따라요. 에이전트가 도구를 써야 할 때 ToolCallStart 이벤트를 내보내고, 도구에 전달되는 인자를 스트리밍하는 하나 이상의 ToolCallArgs 이벤트가 뒤따르며, ToolCallEnd 이벤트로 끝납니다.
이 스트리밍 방식은 프런트엔드가 도구 실행을 실시간으로 보여줄 수 있게 해, 에이전트의 행동을 투명하게 만들고 어떤 도구가 어떤 파라미터로 호출되고 있는지 즉각적인 피드백을 제공합니다.
sequenceDiagram
participant Agent
participant Client
Note over Agent,Client: Tool call begins
Agent->>Client: ToolCallStart
loop Arguments streaming
Agent->>Client: ToolCallArgs
end
Note over Agent,Client: Tool call completes
Agent->>Client: ToolCallEnd
Note over Agent,Client: Tool execution result
Agent->>Client: ToolCallResult
각 ToolCallArgs 이벤트는 인자 덩어리를 담은 delta 필드를 가져요. 프런트엔드는 받은 순서대로 이 델타들을 연결해 완전한 인자 객체를 구성해야 해요. toolCallId 속성은 모든 관련 이벤트를 연결해, 프런트엔드가 인자 덩어리를 올바른 도구 호출과 연결할 수 있게 합니다.
ToolCallStart
도구 호출의 시작을 알려요.
ToolCallStart 이벤트는 에이전트가 특정 기능을 수행하기 위해 도구를 호출하고 있음을 나타내요. 이 이벤트는 호출되는 도구의 이름을 제공하고, 이 도구 호출의 이후 이벤트들이 참조할 고유한 toolCallId를 수립합니다. 프런트엔드는 이 이벤트로 특정 작업이 진행 중이라는 알림 표시 같은 도구 사용을 사용자에게 보여줄 수 있어요. 선택적 parentMessageId는 도구 호출을 대화의 특정 메시지와 연결해, 도구가 사용되는 이유에 대한 컨텍스트를 제공합니다.
| 속성 | 설명 |
|---|---|
toolCallId |
도구 호출의 고유 식별자 |
toolCallName |
호출되는 도구의 이름 |
parentMessageId |
선택적 부모 메시지의 ID |
ToolCallArgs
도구 호출의 인자 데이터 덩어리를 나타내요.
ToolCallArgs 이벤트는 도구 인자의 증분 부분을 준비되는 대로 전달해요. 각 이벤트는 delta 속성에 인자 데이터 세그먼트를 담아요. 이 델타들은 종종 JSON 조각이며, 결합되면 도구의 완전한 인자 객체를 형성합니다. 인자 스트리밍은 전체 인자 구성에 시간이 걸릴 수 있는 복잡한 도구 호출에서 특히 가치 있어요. 프런트엔드는 이 인자들을 사용자에게 점진적으로 드러내, 정확히 어떤 파라미터가 도구에 전달되고 있는지 통찰을 제공할 수 있어요.
| 속성 | 설명 |
|---|---|
toolCallId |
ToolCallStart의 ID와 일치 |
delta |
인자 데이터 덩어리 |
ToolCallEnd
도구 호출의 끝을 알려요.
ToolCallEnd 이벤트는 도구 호출의 완료를 표시해요. 이 이벤트를 받은 후 프런트엔드는 모든 인자가 전송됐고 도구 실행이 진행 중이거나 완료됐음을 알아요. 이렇게 하면 UI가 도구 호출 표시를 마무리하고 잠재적 결과를 준비할 수 있어요. 도구 실행 결과가 별도로 반환되는 시스템에서는, 이 이벤트가 에이전트가 도구와 그 인자 지정을 끝냈고 이제 결과를 기다리고 있거나 받았음을 나타냅니다.
| 속성 | 설명 |
|---|---|
toolCallId |
ToolCallStart의 ID와 일치 |
ToolCallResult
도구 호출 실행의 결과를 제공해요.
ToolCallResult 이벤트는 에이전트가 이전에 호출한 도구의 출력이나 결과를 전달해요. 이 이벤트는 도구가 시스템에 의해 실행된 후 보내지며, 도구가 생성한 실제 출력을 담아요. 도구 호출 지정의 스트리밍 패턴(start, args, end)과 달리, 도구 실행은 보통 완전한 출력을 만들므로 결과는 완전한 단위로 전달됩니다. 프런트엔드는 이 이벤트로 도구 결과를 사용자에게 보여주고, 대화 히스토리에 추가하거나, 도구 출력에 기반한 후속 작업을 트리거할 수 있어요.
| 속성 | 설명 |
|---|---|
messageId |
이 결과가 속한 대화 메시지의 ID |
toolCallId |
대응하는 ToolCallStart 이벤트의 ID와 일치 |
content |
도구 실행의 실제 결과/출력 콘텐츠 |
role |
선택적 역할 식별자, 보통 도구 결과에 대해 "tool" |
ToolCallChunk
Start → Args → End로 자동 확장되는 편의 이벤트예요.
ToolCallChunk 이벤트는 명시적 ToolCallStart와 ToolCallEnd 이벤트 생략을 가능하게 해요. 클라이언트 스트림 변환기가 청크를 표준 도구 호출 삼중으로 확장합니다.
- 도구 호출의 첫 번째 청크는
toolCallId와toolCallName을 포함해야 하며ToolCallStart를 내보냅니다(어떤parentMessageId든 전파함). delta를 가진 각 청크는 현재toolCallId에 대해ToolCallArgs를 내보냅니다.ToolCallEnd는 스트림이 새toolCallId로 전환되거나 스트림이 완료될 때 자동으로 내보내집니다.
| 속성 | 설명 |
|---|---|
toolCallId |
이후 청크에서 선택; 도구 호출의 첫 번째 청크에서 필수 |
toolCallName |
이후 청크에서 선택; 도구 호출의 첫 번째 청크에서 필수 |
parentMessageId |
선택적 부모 메시지의 ID |
delta |
선택적 인자 데이터 덩어리 (종종 JSON 조각) |
상태 관리 이벤트
이 이벤트들은 에이전트의 상태를 프런트엔드와 관리·동기화하는 데 사용돼요. 프로토콜의 상태 관리는 효율적인 스냅샷-델타 패턴을 따라요. 완전한 상태 스냅샷은 처음이나 드물게 보내고, 증분 업데이트(델타)는 진행 중인 변화에 사용합니다.
이 접근은 완전성과 효율성을 모두 최적화해요: 스냅샷은 프런트엔드가 전체 상태 컨텍스트를 갖도록 보장하고, 델타는 빈번한 업데이트에 대한 데이터 전송을 최소화합니다. 함께, 프런트엔드가 불필요한 데이터 전송 없이 에이전트 상태의 정확한 표현을 유지하게 해 줍니다.
sequenceDiagram
participant Agent
participant Client
Note over Agent,Client: Initial state transfer
Agent->>Client: StateSnapshot
Note over Agent,Client: Incremental updates
loop State changes over time
Agent->>Client: StateDelta
Agent->>Client: StateDelta
end
Note over Agent,Client: Occasional full refresh
Agent->>Client: StateSnapshot
loop More incremental updates
Agent->>Client: StateDelta
end
Note over Agent,Client: Message history update
Agent->>Client: MessagesSnapshot
스냅샷과 델타의 조합은 프런트엔드가 일관성을 보장하면서 에이전트 상태의 변화를 효율적으로 추적하게 해요. 스냅샷은 상태를 알려진 기준선으로 리셋하는 동기화 지점 역할을 하고, 델타는 스냅샷 사이의 가벼운 업데이트를 제공합니다.
StateSnapshot
에이전트 상태의 완전한 스냅샷을 제공해요.
StateSnapshot 이벤트는 에이전트의 현재 상태에 대한 포괄적인 표현을 전달해요. 이 이벤트는 보통 상호작용 시작 시나 동기화가 필요할 때 보내집니다. 프런트엔드에 관련된 모든 상태 변수를 담아, 내부 표현을 완전히 재구축할 수 있게 합니다. 프런트엔드는 이전 상태와 병합하려 하지 말고 기존 상태 모델을 이 스냅샷의 내용으로 교체해야 해요.
| 속성 | 설명 |
|---|---|
snapshot |
완전한 상태 스냅샷 |
StateDelta
JSON Patch를 사용해 에이전트 상태에 부분 업데이트를 제공해요.
StateDelta 이벤트는 JSON Patch 연산(RFC 6902에 정의됨)의 형태로 에이전트 상태에 대한 증분 업데이트를 담아요. 각 델타는 현재 상태 모델에 적용할 특정 변경을 나타내요. 이 접근은 전체 상태 대신 변경된 것만 보내므로 대역폭 효율적입니다. 프런트엔드는 정확한 상태 표현을 유지하기 위해 이 패치들을 순서대로 적용해야 해요. 패치 적용 후 불일치를 감지하면 새 StateSnapshot을 요청할 수 있어요.
| 속성 | 설명 |
|---|---|
delta |
JSON Patch 연산 배열 (RFC 6902) |
MessagesSnapshot
대화의 모든 메시지 스냅샷을 제공해요.
MessagesSnapshot 이벤트는 현재 대화의 완전한 메시지 히스토리를 전달해요. 일반 상태 스냅샷과 달리, 이것은 특히 대화 기록(transcript)에 초점을 맞춥니다. 이 이벤트는 채팅 히스토리 초기화, 연결 중단 후 동기화, 사용자가 진행 중인 대화에 합류할 때 포괄적인 뷰 제공에 유용해요. 프런트엔드는 이것으로 사용자에게 표시되는 대화 컨텍스트를 수립하거나 갱신해야 해요.
| 속성 | 설명 |
|---|---|
messages |
메시지 객체 배열 |
activity와 reasoning 메시지는 MessagesSnapshot 안에서 전부 아니면 전무(all-or-nothing)예요. 스냅샷이 그 역할의 메시지를 하나라도 담으면, 그 역할에 대한 완전한 집합이에요: 반복하는 항목은 클라이언트 사본을 대체하고, 빠뜨린 항목은 제거됩니다. 아무것도 담지 않으면, 스냅샷은 그 역할에 대해 아무 말도 하지 않고 클라이언트는 이미 가진 메시지를 유지해요.
두 역할 모두 기본적으로 클라이언트 측이므로, 빼놓는 것은 안전해요. 액티비티 메시지는 절대 에이전트로 돌아가지 않아요 — RunAgentInput에서 제거되죠 — 그리고 reasoning은 보통 스트리밍된 Reasoning 이벤트로만 존재합니다. 둘 다 추적하지 않는 백엔드는 스냅샷에서 그냥 생략하고, 클라이언트가 가진 어떤 것도 잃지 않아요.
액티비티 이벤트
액티비티 이벤트는 채팅 메시지 사이에 발생하는 구조화된 진행 중 활동 업데이트를 노출해요. 상태 시스템과 같은 스냅샷/델타 패턴을 따르므로, UI가 완전한 액티비티 뷰를 즉시 렌더링하고 새 정보가 도착하면 점진적으로 갱신할 수 있어요.
액티비티 메시지는 다른 모든 메시지와 같은 id 공간을 차지하므로, 그것의 messageId를 텍스트나 추론 메시지가 재사용하면 안 되고 그 반대도 마찬가지예요. 그들은 다른 형태의 content를 담아요 — 액티비티는 구조화된 객체, 텍스트와 추론은 문자열 — 그래서 공유된 id는 일관된 의미가 없습니다. 액티비티 메시지가 이미 들고 있는 id 아래로 텍스트나 추론 메시지를 받은 클라이언트는, 그것을 덮어쓰기보다 액티비티 메시지를 그대로 두어야 해요.
ActivitySnapshot
액티비티 메시지의 완전한 스냅샷을 전달해요.
| 속성 | 설명 |
|---|---|
messageId |
이 이벤트가 갱신하는 ActivityMessage의 식별자 |
activityType |
액티비티 판별자 (예: "PLAN", "SEARCH") |
content |
완전한 액티비티 상태를 나타내는 구조화된 JSON 페이로드 |
replace |
선택. 기본값은 true. false일 때 메시지가 이미 존재하면 스냅샷을 무시 |
프런트엔드는 새 ActivityMessage를 만들거나 스냅샷이 공급한 페이로드로 기존 것을 대체해야 해요.
ActivityDelta
JSON Patch 연산을 사용해 기존 액티비티에 증분 업데이트를 적용해요.
| 속성 | 설명 |
|---|---|
messageId |
대상 액티비티 메시지의 식별자 |
activityType |
액티비티 판별자 (가장 최근 스냅샷의 값을 미러링) |
patch |
액티비티 데이터에 적용할 RFC 6902 JSON Patch 연산 배열 |
액티비티 델타는 이전에 동기화된 액티비티 콘텐츠에 순서대로 적용되어야 해요. 애플리케이션이 발산(divergence)을 감지하면, 새 ActivitySnapshot을 요청하거나 내보내 재동기화할 수 있어요.
특수 이벤트
특수 이벤트는 시스템별 기능과 외부 시스템 통합을 허용해 프로토콜에 유연성을 제공해요. 이 이벤트들은 다른 이벤트 타입의 표준 라이프사이클이나 스트리밍 패턴을 따르지 않고, 대신 특수한 목적을 섬깁니다.
Raw
외부 시스템의 이벤트를 통과시키는 데 사용돼요.
Raw 이벤트는 원래 Agent UI Protocol을 따르지 않는 외부 시스템이나 소스에서 발생한 이벤트의 컨테이너 역할을 해요. 이 이벤트 타입은 그 이벤트들을 표준화된 형식으로 감싸 다른 이벤트 기반 시스템과의 상호운용성을 가능하게 합니다. 담긴 이벤트 데이터는 event 속성 안에서 원래 형태 그대로 보존되고, 선택적 source 속성은 그것이 온 시스템을 식별해요. 프런트엔드는 이 정보로 외부 이벤트를 직접 처리하거나 시스템별 핸들러에 위임하는 등 적절히 다룰 수 있어요.
| 속성 | 설명 |
|---|---|
event |
원본 이벤트 데이터 |
source |
선택적 소스 식별자 |
Custom
애플리케이션별 커스텀 이벤트에 사용돼요.
Custom 이벤트는 표준 이벤트 타입이 다루지 않는 기능을 구현하기 위한 확장 메커니즘을 제공해요. 통과 컨테이너로 동작하는 Raw 이벤트와 달리, Custom 이벤트는 명시적으로 프로토콜의 일부이되 애플리케이션 정의 의미론을 갖습니다. name 속성은 특정 커스텀 이벤트 타입을 식별하고, value 속성은 관련 데이터를 담아요. 이 메커니즘은 형식적인 스펙 변경 없이 프로토콜 확장을 허용합니다. 팀은 프런트엔드와 에이전트 전반에서 일관된 구현을 보장하기 위해 커스텀 이벤트를 문서화해야 해요.
| 속성 | 설명 |
|---|---|
name |
커스텀 이벤트의 이름 |
value |
이벤트와 연관된 값 |
추론 이벤트
추론 이벤트는 LLM 추론 가시성과 연속성을 지원해, 프라이버시를 유지하면서 체인-오브-쏘트 추론을 가능하게 해요. 이 이벤트들은 에이전트가 추론 신호(예: 요약)를 표면화하고, 원문 체인-오브-쏘트를 노출하지 않으면서 턴 사이의 상태 이월을 위한 암호화된 추론 항목을 지원하게 합니다 — 특히 store:false나 제로 데이터 보존 정책 아래에서요.
이 설계에 영감을 준 암호화된 reasoning 항목의 기저 개념에 대해서는 OpenAI ZTR documentation, OpenAI store parameter documentation, Gemini Thought Signatures를 참고하세요.
프라이버시 고려사항, 컴플라이언스 가이드, 구현 예시를 포함한 포괄적 문서는 Reasoning을 참고하세요.
sequenceDiagram
participant Agent
participant Client
Note over Agent,Client: Reasoning begins
Agent->>Client: ReasoningStart
Note over Agent,Client: Stream reasoning content
Agent->>Client: ReasoningMessageStart
Agent->>Client: ReasoningMessageContent
Agent->>Client: ReasoningMessageEnd
Note over Agent,Client: Reasoning completes
Agent->>Client: ReasoningEnd
ReasoningStart
추론의 시작을 표시해요.
ReasoningStart 이벤트는 에이전트가 추론 과정을 시작하고 있음을 알려요. 고유한 messageId로 식별되는 추론 컨텍스트를 수립합니다.
| 속성 | 설명 |
|---|---|
messageId |
이 추론의 고유 식별자 |
ReasoningMessageStart
추론 메시지의 시작을 알려요.
ReasoningMessageStart 이벤트는 스트리밍 추론 메시지를 시작해요. 이 메시지는 사용자에게 표시돼야 하는 에이전트 추론의 보이는 부분(예: 요약이나 부분 체인-오브-쏘트)을 담을 겁니다.
| 속성 | 설명 |
|---|---|
messageId |
메시지의 고유 식별자 |
role |
추론 메시지의 역할 ("reasoning") |
ReasoningMessageContent
스트리밍 추론 메시지의 콘텐츠 덩어리를 나타내요.
ReasoningMessageContent 이벤트는 클라이언트에 증분 추론 콘텐츠를 전달해요. 같은 messageId를 가진 여러 콘텐츠 이벤트는 완전한 보이는 추론을 형성하도록 연결되어야 해요.
| 속성 | 설명 |
|---|---|
messageId |
ReasoningMessageStart의 ID와 일치 |
delta |
추론 콘텐츠 덩어리 (비어 있지 않은 문자열) |
ReasoningMessageEnd
추론 메시지의 끝을 알려요.
ReasoningMessageEnd 이벤트는 지정된 추론 메시지에 대한 모든 콘텐츠가 전송됐음을 나타내요. 클라이언트는 이 추론 메시지를 나타내는 UI를 마무리해야 해요.
| 속성 | 설명 |
|---|---|
messageId |
ReasoningMessageStart의 ID와 일치 |
ReasoningMessageChunk
추론 메시지를 자동으로 시작/닫는 편의 이벤트예요.
ReasoningMessageChunk 이벤트는 메시지 라이프사이클을 자동 관리해 구현을 단순화해요. messageId를 가진 첫 번째 청크는 메시지를 암묵적으로 시작합니다. 빈 delta 또는 다음 비추론 이벤트는 메시지를 암묵적으로 닫아요.
| 속성 | 설명 |
|---|---|
messageId |
메시지 ID (첫 이벤트는 비어 있지 않아야 함) |
delta |
추론 콘텐츠 덩어리 (빈 문자열은 메시지를 닫음) |
ReasoningEnd
추론의 끝을 표시해요.
ReasoningEnd 이벤트는 에이전트가 주어진 컨텍스트에 대한 추론 과정을 완료했음을 알려요. 이 이벤트 이후 같은 messageId를 가진 추론 이벤트는 기대하면 안 돼요.
| 속성 | 설명 |
|---|---|
messageId |
이 추론의 고유 식별자 |
ReasoningEncryptedValue
메시지나 도구 호출에 암호화된 체인-오브-쏘트 추론을 부착해요.
ReasoningEncryptedValue 이벤트는 특정 엔티티와 관련된 LLM의 내부 체인-오브-쏘트를 나타내는 암호화된 추론 콘텐츠를 전달해요. 이렇게 하면 에이전트가 원문 콘텐츠를 클라이언트에 노출하지 않고 대화 턴 사이에 추론 상태를 보존할 수 있어요. 클라이언트는 이 암호화된 값을 불투명하게 저장하고 전달하며, 복호화할 수 있는 것은 에이전트(또는 인가된 백엔드)뿐이에요.
| 속성 | 설명 |
|---|---|
subtype |
엔티티 타입: "message" 또는 "tool-call" |
entityId |
이 추론이 속한 메시지나 도구 호출의 ID |
encryptedValue |
암호화된 체인-오브-쏘트 콘텐츠 블롭 |
사용 사례:
- 메시지 추론: 후속 턴의 컨텍스트 보존을 위해
AssistantMessage나ReasoningMessage에 암호화된 추론을 부착 - 도구 호출 추론: 에이전트가 특정 인자를 고른 이유나 결과를 해석한 방식을 담기 위해 도구 호출에 암호화된 추론을 부착
서브에이전트 이벤트
서브에이전트 이벤트는 에이전트가 자식 에이전트에게 작업을 위임했음을 보고하게 해, 프런트엔드가 어떤 서브에이전트가 어떤 출력을 만들었는지 알 수 있게 해요. 이들이 없으면 동시에 스트리밍하는 세 서브에이전트가 구분 없는 하나의 스트림으로 도착해요.
귀속은 대부분 다른 이벤트의 선택적 subagentRunId로 담겨요; 이 세 개는 서브에이전트의 활동을 감싸고 표시할 이름을 줍니다.
subagentRunId는 한 번의 호출을 식별하지, 재사용 가능한 서브에이전트 정의를 나타내는 게 아니에요 — 같은 서브에이전트를 두 번 실행하면 두 개의 다른 값이 나와요. 중첩, 동시성, 클라이언트가 강제하는 규칙을 포함한 전체 모델은 Subagents를 참고하세요.
sequenceDiagram
participant Agent
participant Client
Note over Agent,Client: Subagent begins
Agent->>Client: SubagentStarted
Note over Agent,Client: Attributed output
Agent->>Client: TextMessageStart / Content / End
Note over Agent,Client: Subagent concludes
alt Success
Agent->>Client: SubagentFinished
else Failure
Agent->>Client: SubagentError
end
SubagentStarted
새 서브에이전트 호출을 알려요.
| 속성 | 설명 |
|---|---|
subagentRunId |
이 호출의 불투명 식별자 |
name |
표시용으로 선언된 서브에이전트 이름 또는 타입 |
description |
선택적 사람이 읽을 수 있는 설명 |
parentSubagentRunId |
선택 — 서브에이전트가 중첩될 때 감싸는 서브에이전트 |
parentToolCallId |
선택 — 이 서브에이전트를 만들어 낸 도구 호출 |
parentMessageId |
선택 — 그 도구 호출을 담은 메시지 |
SubagentFinished
서브에이전트 호출을 완료로 표시해요.
| 속성 | 설명 |
|---|---|
subagentRunId |
SubagentStarted의 ID와 일치 |
result |
선택적 완료 페이로드, RunFinished.result를 미러링 |
outcome |
선택적 판별 유니언: { type: "success" } 또는 { type: "suspended", interruptIds?: string[] }. 생략 시 성공을 뜻함(레거시 해석). suspended는 서브에이전트가 외부 입력을 기다리며 비행 중 체크포인트됐음을 뜻함 — 그러면 실행은 인터럽트 결과로 끝나고, interruptIds는 이 서브에이전트를 재개하는 답을 가진 실행 레벨 인터럽트를 지목함 |
SubagentError
서브에이전트 호출을 실패로 표시해요.
| 속성 | 설명 |
|---|---|
subagentRunId |
SubagentStarted의 ID와 일치 |
message |
사람이 읽을 수 있는 오류 메시지 |
code |
선택적 오류 코드 |
StateSnapshot과StateDelta는 귀속 가능하지만, 이들에 대한 귀속은 출처(provenance)이지 소유(ownership)가 아니에요: 어떤 서브에이전트가 그 업데이트를 만들었는지를 기록합니다. 상태는 실행 범위로 유지되고, 귀속된 스냅샷이나 델타는 귀속되지 않은 것과 정확히 마찬가지로 실행의 하나의 상태 문서에 적용됩니다. 서브에이전트별 상태는 존재하지 않아요.
Deprecated 이벤트
다음 이벤트들은 deprecated이며 버전 1.0.0에서 제거될 예정이에요. 대신 대응하는 Reasoning 이벤트를 사용하세요.
Thinking 이벤트 (Deprecated)
THINKING_* 이벤트들은 REASONING_* 이벤트들로 교체됐어요.
| Deprecated 이벤트 | 대체 이벤트 |
|---|---|
THINKING_START |
REASONING_START |
THINKING_END |
REASONING_END |
THINKING_TEXT_MESSAGE_START |
REASONING_MESSAGE_START |
THINKING_TEXT_MESSAGE_CONTENT |
REASONING_MESSAGE_CONTENT |
THINKING_TEXT_MESSAGE_END |
REASONING_MESSAGE_END |
상세한 마이그레이션 가이드는 Reasoning Migration을 참고하세요.
드래프트 이벤트
이 이벤트들은 현재 드래프트 상태이며 최종 확정 전에 바뀔 수 있어요. 활발히 개발·논의 중인 프로토콜에 대한 제안된 확장을 나타냅니다.
메타 이벤트
DRAFT
메타 이벤트는 에이전트 실행과 독립적인 주석과 신호를 제공해요 — 사용자 피드백이나 외부 시스템 이벤트 같은 것요.
MetaEvent
스트림 어디에서나 발생할 수 있는 사이드밴드 주석 이벤트예요.
| 속성 | 설명 |
|---|---|
metaType |
애플리케이션 정의 타입 (예: "thumbs_up", "tag") |
payload |
애플리케이션 정의 페이로드 |
수정된 라이프사이클 이벤트
DRAFT
인터럽트와 브랜칭을 지원하도록 기존 라이프사이클 이벤트를 확장합니다.
RunFinished (확장)
RunFinished 이벤트는 인터럽트 인지 워크플로를 지원할 새 필드를 얻어요.
| 속성 | 설명 |
|---|---|
outcome |
선택적 판별 유니언: { type: "success" } 또는 { type: "interrupt", interrupts: [...] }. 레거시 프로듀서에서 생략됨. |
result |
선택. 자유 형식 완료 페이로드. 레거시 프로듀서와의 역호환을 위해 이벤트 루트에 존재; 어떤 outcome과도 공존함. |
계보와 입력 캡처는 Serialization을 참고하세요.
RunStarted (확장)
RunStarted 이벤트는 브랜칭과 입력 추적을 지원할 새 필드를 얻어요.
| 속성 | 설명 |
|---|---|
parentRunId |
선택: 브랜칭/타임 트래블을 위한 부모 실행 ID |
input |
선택: 이 실행의 정확한 에이전트 입력 |
이벤트 흐름 패턴
프로토콜의 이벤트는 보통 특정 패턴을 따라요.
-
Start-Content-End 패턴: 스트리밍 콘텐츠(텍스트 메시지, 도구 호출)에 사용
Start이벤트가 스트림을 시작Content이벤트가 데이터 덩어리 전달End이벤트가 완료를 알림
-
Snapshot-Delta 패턴: 상태 동기화에 사용
Snapshot이 완전한 상태 제공Delta이벤트가 증분 업데이트 제공
-
라이프사이클 패턴: 에이전트 실행 모니터링에 사용
Started이벤트가 시작을 알림Finished/Error이벤트가 끝을 알림
구현 고려사항
이벤트 핸들러를 구현할 때:
- 이벤트는 받은 순서대로 처리해야 해요
- 같은 ID(예:
messageId,toolCallId)를 가진 이벤트는 같은 논리적 스트림에 속해요 - 구현은 순서가 뒤섞인 전달에 탄력적이어야 해요
- 커스텀 이벤트는 일관성을 위해 확립된 패턴을 따라야 해요
더 알아보기 (Learn more)
- 추론 (Reasoning) — 추론 이벤트의 전체 라이프사이클과 프라이버시 설계를 다뤄요.
- 서브에이전트 (Subagents) — 서브에이전트 이벤트의 귀속 모델과 중첩·동시성 규칙을 확인해 보세요.
- 메시지 (Messages) — 메시지가 이벤트로 어떻게 만들어지고 스트리밍되는지 살펴보세요.
- 에이전트 (Agents) — 이벤트를 만들고 소비하는 에이전트를 알아보세요.