Chuyển tới nội dung chính

Các Lệnh Client Gửi Lên Server

Tổng Hợp Lệnh

typeMô tả
chatBắt đầu lượt hội thoại mới
subscribeĐăng ký nhận events của session
stopDừng agent đang chạy
push_messageXếp hàng message khi agent đang bận
approvalPhê duyệt tool call hoặc trả lời câu hỏi
ping / pongKeep-alive

chat — Bắt Đầu Lượt Hội Thoại

{
"type": "chat",
"message": "Phân tích cổ phiếu VNM",
"session_id": "uuid-session-id",
"model": "claude-sonnet-4-6",
"agent_id": "financial_agent",
"content_urls": [
"https://example.com/bao-cao.pdf"
],
"agent_config": {
"display_mode": "agent"
}
}
FieldBắt buộcMô tả
messageNội dung tin nhắn người dùng
session_idKhôngBỏ trống để tạo session mới
modelKhôngOverride model (mặc định theo cấu hình server)
agent_idKhôngOverride agent
content_urlsKhôngDanh sách URL file/ảnh đính kèm
agent_config.display_modeKhông"agent" (mặc định) hoặc "chat"

display_mode: "agent" — hiển thị thinking, tool calls, toàn bộ quá trình suy luận.

display_mode: "chat" — chỉ trả về text answer, không có thinking hay tool call events.

Session Mới

Khi không có session_id, server tạo session mới và trả về trong subscribed.session_id. Client phải lưu lại ID này để dùng cho các lượt tiếp theo.

Response Sau chat

{
"type": "subscribed",
"session_id": "abc-123",
"status": "running"
}

Sau đó server bắt đầu stream toàn bộ events của lượt (xem Event Stream).

Khi Agent Đang Bận

Nếu session đã có task đang chạy, message được tự động xếp hàng:

{
"type": "message_queued",
"session_id": "abc-123"
}

subscribe — Đăng Ký Nhận Events

Dùng khi reconnect hoặc muốn nhận lại events từ một điểm cụ thể.

{
"type": "subscribe",
"session_id": "abc-123",
"last_event_id": "01HXYZ..."
}
FieldBắt buộcMô tả
session_idSession cần subscribe
last_event_idKhôngReplay từ event ID này. Bỏ trống để nhận toàn bộ

Response

{
"type": "subscribed",
"session_id": "abc-123",
"status": "running"
}

hoặc:

{
"type": "subscribed",
"session_id": "abc-123",
"status": "completed"
}
  • status: "running" → server replay events còn thiếu + tiếp tục stream live
  • status: "completed" → server replay events còn thiếu rồi dừng

Lỗi Session Không Tồn Tại

{
"type": "error",
"code": "SESSION_NOT_FOUND",
"message": "Session not found or no active stream"
}

stop — Dừng Agent

{
"type": "stop",
"session_id": "abc-123"
}

Server đặt stop signal. Agent dừng ở lần kiểm tra tiếp theo (thường < 1 giây).

Sau khi dừng, server sẽ emit:

  1. Block terminal_user_stopped
  2. message_delta
  3. message_stop

Không có ACK trực tiếp — message_stop là xác nhận cuối cùng.

Nếu không có task đang chạy:

{
"type": "error",
"code": "SESSION_NOT_RUNNING",
"message": "No running task for this session"
}

push_message — Xếp Hàng Message

{
"type": "push_message",
"session_id": "abc-123",
"message": "Cũng phân tích thêm cổ phiếu HPG"
}

Message được xử lý ngay sau khi lượt hiện tại hoàn thành.

{
"type": "message_queued",
"session_id": "abc-123"
}

Bảng Mã Lỗi

codeKhi nào
INVALID_JSONMessage không phải JSON hợp lệ
UNKNOWN_TYPETrường type không xác định
EMPTY_MESSAGEchat không có message
MISSING_SESSION_IDsubscribe không có session_id
SESSION_NOT_FOUNDSession không tồn tại hoặc đã hết TTL
SESSION_NOT_RUNNINGstop / push_message khi không có task
TASK_START_FAILEDLỗi nội bộ khi khởi động task

Ví Dụ: React.js

function ChatInput({ sessionId, ws, onSessionCreated }) {
const [message, setMessage] = useState('')

const sendMessage = () => {
if (!message.trim()) return

ws.send(JSON.stringify({
type: 'chat',
message: message.trim(),
session_id: sessionId || undefined,
agent_config: { display_mode: 'agent' },
}))
setMessage('')
}

const stopAgent = () => {
if (!sessionId) return
ws.send(JSON.stringify({ type: 'stop', session_id: sessionId }))
}

return (
<div>
<input value={message} onChange={e => setMessage(e.target.value)} />
<button onClick={sendMessage}>Gửi</button>
<button onClick={stopAgent}>Dừng</button>
</div>
)
}

Ví Dụ: Flutter (Dart)

class ChatService {
final AgentWebSocket _ws;
String? _sessionId;

ChatService(this._ws);

void sendMessage(String message) {
final payload = {
'type': 'chat',
'message': message,
if (_sessionId != null) 'session_id': _sessionId,
'agent_config': {'display_mode': 'agent'},
};
_ws.send(payload);
}

void stop() {
if (_sessionId == null) return;
_ws.send({'type': 'stop', 'session_id': _sessionId});
}

void pushMessage(String message) {
if (_sessionId == null) return;
_ws.send({
'type': 'push_message',
'session_id': _sessionId,
'message': message,
});
}

void handleSubscribed(Map<String, dynamic> msg) {
_sessionId = msg['session_id'] as String;
// Lưu vào local storage để dùng khi reconnect
SharedPreferences.getInstance()
.then((prefs) => prefs.setString('last_session_id', _sessionId!));
}
}