Message Reference — Tất Cả Message Types
File này là tham chiếu đầy đủ cho mọi message type trong WebSocket protocol. Mỗi type có ví dụ JSON hoàn chỉnh.
Mục Lục
- Client → Server
- Server → Client (Control)
- Server → Client (Agent Output)
- message_start
- message_delta
- message_stop
- content_block_start — thinking
- content_block_start — text
- content_block_start — tool_use
- content_block_start — tool_result
- content_block_start — file_processing
- content_block_start — approval_request
- content_block_start — approval_result
- content_block_start — approval_timeout
- content_block_delta — thinking_delta
- content_block_delta — text_delta
- content_block_delta — text_delta (terminal_user_stopped)
- content_block_delta — text_delta (terminal_error)
- content_block_delta — file_processing status
- content_block_delta — approval_request data
- content_block_delta — approval_result decisions
- content_block_stop
Client → Server
auth
Xác thực sau khi nhận connected. Phải gửi trong vòng 10 giây.
{
"type": "auth",
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiMTIzIn0.signature"
}
chat
Bắt đầu một lượt hội thoại mới. Nếu không có session_id, server sẽ tạo mới.
{
"type": "chat",
"message": "Phân tích cổ phiếu VNM",
"session_id": "abc-123",
"model": "claude-sonnet-4-6",
"agent_id": "financial_agent",
"content_urls": [
"https://example.com/bao-cao.pdf"
],
"agent_config": {
"display_mode": "agent"
}
}
Tối giản (tạo session mới):
{
"type": "chat",
"message": "Phân tích cổ phiếu VNM"
}
subscribe
Đăng ký nhận events của session. Dùng khi reconnect hoặc load lại.
{
"type": "subscribe",
"session_id": "abc-123",
"last_event_id": "01HXYZ100"
}
Không có last_event_id (nhận toàn bộ):
{
"type": "subscribe",
"session_id": "abc-123"
}
stop
Dừng agent đang chạy cho session.
{
"type": "stop",
"session_id": "abc-123"
}
push_message
Xếp hàng message khi agent đang bận. Agent xử lý sau khi lượt hiện tại xong.
{
"type": "push_message",
"session_id": "abc-123",
"message": "Cũng phân tích thêm HPG nhé"
}
approval — Phê Duyệt Tool
Phê duyệt hoặc từ chối tool calls trong approval_request. Dùng field decisions.
Approve:
{
"type": "approval",
"session_id": "abc-123",
"approval_key": "abc-123_1",
"decisions": [
{
"type": "approve"
}
]
}
Reject:
{
"type": "approval",
"session_id": "abc-123",
"approval_key": "abc-123_1",
"decisions": [
{
"type": "reject"
}
]
}
Edit (sửa arguments):
{
"type": "approval",
"session_id": "abc-123",
"approval_key": "abc-123_1",
"decisions": [
{
"type": "edit",
"edited_action": {
"name": "execute_trade",
"args": {
"symbol": "VNM",
"quantity": 50,
"side": "buy"
}
}
}
]
}
Nhiều actions:
{
"type": "approval",
"session_id": "abc-123",
"approval_key": "abc-123_1",
"decisions": [
{
"type": "approve"
},
{
"type": "reject"
}
],
"user_edit_content": "Chỉ approve cái đầu tiên thôi nhé"
}
approval — Trả Lời Câu Hỏi
Dành riêng cho ask_user_question. Dùng field answers, không dùng decisions.
{
"type": "approval",
"session_id": "abc-123",
"approval_key": "abc-123_1",
"answers": [
{
"id": "q1",
"answer": "Tăng trưởng"
},
{
"id": "q2",
"answer": "500"
}
]
}
ping (Client)
Client có thể chủ động gửi ping để kiểm tra kết nối.
{
"type": "ping"
}
pong (Client)
Phản hồi khi nhận ping từ server. Bắt buộc — không gửi pong sẽ bị ngắt kết nối sau 2 lần miss.
{
"type": "pong"
}
Server → Client (Control)
connected
Gửi ngay khi kết nối WebSocket thành công. Client phải gửi auth ngay sau đây.
{
"type": "connected",
"sid": "550e8400-e29b-41d4-a716-446655440000",
"ping_interval": 25000,
"ping_timeout": 20000,
"max_payload": 2097152
}
| Field | Mô tả |
|---|---|
sid | Connection ID (dùng để debug) |
ping_interval | Server gửi ping mỗi 25000ms |
ping_timeout | Client phải pong trong 20000ms |
max_payload | Kích thước message tối đa (2MB) |
auth_ok
Xác thực thành công. Sau đây có thể gửi chat, subscribe, ...
{
"type": "auth_ok"
}
subscribed (running)
Task đã bắt đầu hoặc đang chạy. Server sẽ stream events ngay sau đây.
{
"type": "subscribed",
"session_id": "abc-123",
"status": "running"
}
subscribed (completed)
Session đã hoàn thành. Server sẽ replay events còn thiếu rồi dừng.
{
"type": "subscribed",
"session_id": "abc-123",
"status": "completed"
}
message_queued
Message đã được xếp hàng chờ xử lý (agent đang bận).
{
"type": "message_queued",
"session_id": "abc-123"
}
session_renamed
Server tự động đặt tên session bằng LLM (Gemini 2.5 Flash Lite) dựa trên tin nhắn đầu tiên của người dùng. Gửi sau khi LLM generate xong (~1-2 giây sau tin nhắn đầu tiên).
{
"type": "session_renamed",
"session_id": "abc-123",
"session_name": "Phân tích cổ phiếu VNM",
"auto": true
}
| Field | Mô tả |
|---|---|
session_id | ID của session được đổi tên |
session_name | Tên mới do LLM tạo (tối đa 100 ký tự, viết hoa chữ cái đầu, cùng ngôn ngữ với tin nhắn user) |
auto | Luôn true — đây là auto-rename, không phải user đổi tên thủ công |
- Chỉ trigger một lần duy nhất cho mỗi session (dedup bằng Redis lock)
- Nếu user đã đổi tên thủ công trước khi LLM xong → auto-rename bị hủy
- Client nên cập nhật
session_nametrong danh sách sessions khi nhận event này
error
Lỗi protocol hoặc nghiệp vụ. Không phải lỗi từ agent (lỗi agent dùng terminal_error block).
{
"type": "error",
"code": "SESSION_NOT_FOUND",
"message": "Session not found or no active stream"
}
Tất cả error codes:
code | Khi nào |
|---|---|
INVALID_JSON | Message không phải JSON hợp lệ |
UNKNOWN_TYPE | type không xác định |
EMPTY_MESSAGE | chat không có message |
MISSING_SESSION_ID | subscribe không có session_id |
SESSION_NOT_FOUND | Session không tồn tại hoặc hết TTL |
SESSION_NOT_RUNNING | stop/push_message khi không có task |
TASK_START_FAILED | Lỗi nội bộ khi start task |
ping (Server)
Server gửi mỗi 25 giây. Client phải trả pong trong 20 giây.
{
"type": "ping"
}
pong (Server)
Phản hồi khi client gửi ping.
{
"type": "pong"
}
Server → Client (Agent Output)
Các events này được stream trong phạm vi một lượt agent trả lời.
message_start
Event đầu tiên của mỗi lượt. Bắt đầu nhận các content blocks.
{
"type": "message_start",
"session_id": "abc-123",
"timestamp": 1710000000.123,
"display_mode": "agent",
"is_new_session_from_share": false,
"message_id": "msg-uuid-001"
}
message_delta
Báo lý do kết thúc lượt, gửi trước message_stop.
{
"type": "message_delta",
"delta": {
"stop_reason": "end_turn"
}
}
message_stop
Event cuối cùng của lượt. Lượt đã hoàn toàn kết thúc.
{
"type": "message_stop",
"duration_ms": 3420,
"message_id": "msg-uuid-001"
}
content_block_start — thinking
Bắt đầu block suy luận của AI. Chỉ có khi display_mode: "agent".
{
"type": "content_block_start",
"index": 0,
"content_block": {
"type": "thinking",
"thinking": "",
"subagent": null,
"parent_tool_use_id": null
},
"message_id": "msg-uuid-001"
}
content_block_start — text
Bắt đầu block văn bản trả lời.
{
"type": "content_block_start",
"index": 3,
"content_block": {
"type": "text",
"text": "",
"subagent": null,
"parent_tool_use_id": null,
"is_part": false
},
"message_id": "msg-uuid-001"
}
content_block_start — tool_use
Agent gọi một công cụ. Input đã có sẵn trong content_block.input. Không có delta.
{
"type": "content_block_start",
"index": 1,
"content_block": {
"type": "tool_use",
"id": "toolu_01XyzAbc",
"name": "search_stock",
"tool_use_id": "toolu_01XyzAbc",
"tool_content_message": "Tìm kiếm cổ phiếu",
"input": {
"symbol": "VNM"
},
"subagent": null,
"parent_tool_use_id": null
},
"message_id": "msg-uuid-001"
}
content_block_start — tool_result
Kết quả sau khi tool thực thi xong. Nội dung đã có sẵn trong content_block.content. Không có delta.
{
"type": "content_block_start",
"index": 2,
"content_block": {
"type": "tool_result",
"tool_use_id": "toolu_01XyzAbc",
"name": "search_stock",
"status": "success",
"content": "VNM - Vinamilk\nGiá: 82,000 VND\nThay đổi: -1.2%\nKhối lượng: 1.2M",
"artifact": null,
"subagent": null,
"parent_tool_use_id": null
},
"message_id": "msg-uuid-001"
}
Tool thất bại:
{
"type": "content_block_start",
"index": 2,
"content_block": {
"type": "tool_result",
"tool_use_id": "toolu_01XyzAbc",
"name": "search_stock",
"status": "error",
"content": "Không tìm thấy mã cổ phiếu: XYZ",
"artifact": null
}
}
content_block_start — file_processing
Bắt đầu xử lý file đính kèm. Luôn là block đầu tiên (index 0).
{
"type": "content_block_start",
"index": 0,
"content_block": {
"type": "file_processing",
"status": "processing",
"files": [
{
"url": "https://example.com/bao-cao-tai-chinh.pdf"
}
]
},
"message_id": "msg-uuid-001"
}
content_block_start — approval_request
Agent cần người dùng phê duyệt trước khi thực thi tool. Dữ liệu chi tiết đến qua content_block_delta.
{
"type": "content_block_start",
"index": 4,
"content_block": {
"type": "approval_request",
"approval_key": "abc-123_1"
},
"message_id": "msg-uuid-001"
}
content_block_start — approval_result
Kết quả sau khi người dùng đã quyết định. Quyết định đến qua content_block_delta.
{
"type": "content_block_start",
"index": 5,
"content_block": {
"type": "approval_result",
"approval_key": "abc-123_1"
},
"message_id": "msg-uuid-001"
}
content_block_start — approval_timeout
Người dùng không phản hồi trong thời gian quy định. Agent tự reject.
{
"type": "content_block_start",
"index": 5,
"content_block": {
"type": "approval_timeout",
"approval_key": "abc-123_1"
},
"message_id": "msg-uuid-001"
}
content_block_delta — thinking_delta
Nội dung suy luận dần dần. Nối tất cả delta.thinking để có nội dung đầy đủ.
{
"type": "content_block_delta",
"index": 0,
"delta": {
"type": "thinking_delta",
"thinking": "Tôi cần tra giá cổ phiếu VNM trước khi phân tích..."
},
"message_id": "msg-uuid-001"
}
content_block_delta — text_delta
Nội dung văn bản dần dần. Nối tất cả delta.text để có nội dung đầy đủ.
{
"type": "content_block_delta",
"index": 3,
"delta": {
"type": "text_delta",
"text": "Cổ phiếu **VNM** đang giao dịch ở mức "
},
"message_id": "msg-uuid-001"
}
content_block_delta — text_delta (terminal_user_stopped)
Block text bình thường nhưng có extras.block_subtype = "user_stopped". Client phải đổi block.type thành "terminal_user_stopped".
{
"type": "content_block_delta",
"index": 4,
"delta": {
"type": "text_delta",
"text": "Người dùng đã dừng cuộc trò chuyện. Gửi tin nhắn mới để tiếp tục",
"extras": {
"block_subtype": "user_stopped"
}
},
"message_id": "msg-uuid-001"
}
content_block_delta — text_delta (terminal_error)
Block text bình thường nhưng có extras.block_subtype = "error". Client phải đổi block.type thành "terminal_error".
{
"type": "content_block_delta",
"index": 4,
"delta": {
"type": "text_delta",
"text": "Đã xảy ra lỗi. Vui lòng thử lại.",
"extras": {
"block_subtype": "error",
"code": "LLM_ERROR",
"can_retry": true,
"error_type": "terminal",
"details": {
"error": "Rate limit exceeded"
}
}
},
"message_id": "msg-uuid-001"
}
Các giá trị code:
code | Nguyên nhân |
|---|---|
LLM_ERROR | Lỗi gọi LLM (rate limit, timeout, ...) |
AGENT_ERROR | Lỗi logic agent |
APPROVAL_TIMEOUT | Hết thời gian chờ phê duyệt |
content_block_delta — file_processing status
Cập nhật trạng thái xử lý file.
{
"type": "content_block_delta",
"index": 0,
"delta": {
"status": "completed",
"message": "Processed 1 file"
},
"message_id": "msg-uuid-001"
}
Các giá trị status: "processing" → "completed" hoặc "error".
content_block_delta — approval_request data
Dữ liệu chi tiết của approval_request. Chứa danh sách actions cần phê duyệt.
Tool call thông thường:
{
"type": "content_block_delta",
"index": 4,
"delta": {
"action_requests": [
{
"name": "execute_trade",
"args": {
"symbol": "VNM",
"quantity": 100,
"side": "buy",
"price": 82000
},
"tool_use_id": "toolu_01XyzAbc"
}
],
"review_configs": [
{
"require_approval": true
}
],
"timeout_seconds": 300
},
"message_id": "msg-uuid-001"
}
ask_user_question:
{
"type": "content_block_delta",
"index": 4,
"delta": {
"action_requests": [
{
"name": "ask_user_question",
"args": {
"questions": [
{
"id": "q1",
"question": "Chiến lược đầu tư?",
"type": "select",
"options": [
"Tăng trưởng",
"Phòng thủ"
]
},
{
"id": "q2",
"question": "Số tiền (triệu VND)?",
"type": "text"
}
]
}
}
],
"review_configs": [
{
"require_approval": true
}
],
"timeout_seconds": 600
},
"message_id": "msg-uuid-001"
}
content_block_delta — approval_result decisions
Kết quả quyết định của người dùng.
{
"type": "content_block_delta",
"index": 5,
"delta": {
"decisions": [
{
"type": "approve"
}
]
},
"message_id": "msg-uuid-001"
}
content_block_stop
Kết thúc một block. Không có thêm delta cho block này.
{
"type": "content_block_stop",
"index": 0,
"message_id": "msg-uuid-001"
}
Block text cuối cùng của lượt (câu trả lời):
{
"type": "content_block_stop",
"index": 3,
"is_final": true,
"message_id": "msg-uuid-001"
}
is_final: true chỉ xuất hiện trên block text cuối cùng — xác nhận đây là câu trả lời hoàn chỉnh.
Ví Dụ Luồng Hoàn Chỉnh
Luồng Bình Thường (Có Tool Call)
{ "type": "message_start", "session_id": "abc-123", "timestamp": 1710000000.0, "display_mode": "agent", "message_id": "msg-001" }
{ "type": "content_block_start", "index": 0, "content_block": { "type": "thinking", "thinking": "" }, "message_id": "msg-001" }
{ "type": "content_block_delta", "index": 0, "delta": { "type": "thinking_delta", "thinking": "Cần tra giá VNM." }, "message_id": "msg-001" }
{ "type": "content_block_stop", "index": 0, "message_id": "msg-001" }
{ "type": "content_block_start", "index": 1, "content_block": { "type": "tool_use", "id": "toolu_01", "name": "search_stock", "tool_use_id": "toolu_01", "tool_content_message": "Tìm kiếm", "input": { "symbol": "VNM" } }, "message_id": "msg-001" }
{ "type": "content_block_stop", "index": 1, "message_id": "msg-001" }
{ "type": "content_block_start", "index": 2, "content_block": { "type": "tool_result", "tool_use_id": "toolu_01", "name": "search_stock", "status": "success", "content": "VNM: 82,000 VND (-1.2%)" }, "message_id": "msg-001" }
{ "type": "content_block_stop", "index": 2, "message_id": "msg-001" }
{ "type": "content_block_start", "index": 3, "content_block": { "type": "text", "text": "" }, "message_id": "msg-001" }
{ "type": "content_block_delta", "index": 3, "delta": { "type": "text_delta", "text": "Cổ phiếu VNM đang ở 82,000 VND, giảm 1.2%." }, "message_id": "msg-001" }
{ "type": "content_block_stop", "index": 3, "is_final": true, "message_id": "msg-001" }
{ "type": "message_delta", "delta": { "stop_reason": "end_turn" } }
{ "type": "message_stop", "duration_ms": 2840, "message_id": "msg-001" }
Luồng User Dừng
{ "type": "message_start", "session_id": "abc-123", "timestamp": 1710000000.0, "display_mode": "agent", "message_id": "msg-002" }
{ "type": "content_block_start", "index": 0, "content_block": { "type": "tool_use", "id": "toolu_02", "name": "get_financials", "tool_use_id": "toolu_02", "input": { "symbol": "VNM" } }, "message_id": "msg-002" }
{ "type": "content_block_stop", "index": 0, "message_id": "msg-002" }
... (user gửi lệnh stop) ...
{ "type": "content_block_start", "index": 1, "content_block": { "type": "text", "text": "" }, "message_id": "msg-002" }
{ "type": "content_block_delta", "index": 1, "delta": { "type": "text_delta", "text": "Người dùng đã dừng cuộc trò chuyện. Gửi tin nhắn mới để tiếp tục", "extras": { "block_subtype": "user_stopped" } }, "message_id": "msg-002" }
{ "type": "content_block_stop", "index": 1, "message_id": "msg-002" }
{ "type": "message_delta", "delta": { "stop_reason": "end_turn" } }
{ "type": "message_stop", "duration_ms": 1200, "message_id": "msg-002" }
Luồng Phê Duyệt Tool
{ "type": "message_start", "session_id": "abc-123", "timestamp": 1710000000.0, "display_mode": "agent", "message_id": "msg-003" }
{ "type": "content_block_start", "index": 0, "content_block": { "type": "tool_use", "id": "toolu_03", "name": "execute_trade", "tool_use_id": "toolu_03", "input": { "symbol": "VNM", "quantity": 100, "side": "buy" } }, "message_id": "msg-003" }
{ "type": "content_block_stop", "index": 0, "message_id": "msg-003" }
{ "type": "content_block_start", "index": 1, "content_block": { "type": "approval_request", "approval_key": "abc-123_1" }, "message_id": "msg-003" }
{ "type": "content_block_delta", "index": 1, "delta": { "action_requests": [{ "name": "execute_trade", "args": { "symbol": "VNM", "quantity": 100 }, "tool_use_id": "toolu_03" }], "review_configs": [{ "require_approval": true }], "timeout_seconds": 300 }, "message_id": "msg-003" }
{ "type": "content_block_stop", "index": 1, "message_id": "msg-003" }
... (client gửi approval với decisions: approve) ...
{ "type": "content_block_start", "index": 2, "content_block": { "type": "approval_result", "approval_key": "abc-123_1" }, "message_id": "msg-003" }
{ "type": "content_block_delta", "index": 2, "delta": { "decisions": [{ "type": "approve" }] }, "message_id": "msg-003" }
{ "type": "content_block_stop", "index": 2, "message_id": "msg-003" }
{ "type": "content_block_start", "index": 3, "content_block": { "type": "tool_result", "tool_use_id": "toolu_03", "name": "execute_trade", "status": "success", "content": "Lệnh mua 100 cổ VNM tại 82,000 VND đã được thực hiện" }, "message_id": "msg-003" }
{ "type": "content_block_stop", "index": 3, "message_id": "msg-003" }
{ "type": "content_block_start", "index": 4, "content_block": { "type": "text", "text": "" }, "message_id": "msg-003" }
{ "type": "content_block_delta", "index": 4, "delta": { "type": "text_delta", "text": "Đã thực hiện lệnh mua thành công." }, "message_id": "msg-003" }
{ "type": "content_block_stop", "index": 4, "is_final": true, "message_id": "msg-003" }
{ "type": "message_delta", "delta": { "stop_reason": "end_turn" } }
{ "type": "message_stop", "duration_ms": 5200, "message_id": "msg-003" }