[ PROMPT_NODE_23856 ]
managed-agents-client-patterns
[ SKILL_DOCUMENTATION ]
# 托管智能体 — 常见客户端模式
在驱动托管智能体会话时,客户端侧需要编写的模式,基于可运行的 SDK 示例。
代码示例为 TypeScript — Python 和 cURL 遵循相同的结构;请参阅 `python/managed-agents/README.md` 和 `curl/managed-agents.md` 获取对应内容。
---
## 1. 无损流重连
**问题:** SSE 没有重放功能。如果连接在会话中途断开,简单的重连会从“当前时间”重新打开流,从而静默丢失期间产生的所有事件。
**解决方案:** 重连时,在消费实时流*之前*通过 `events.list()` 获取完整的事件历史,并在实时流追赶上来时根据事件 ID 进行去重。
ts
const seenEventIds = new Set()
const stream = await client.beta.sessions.events.stream(session.id)
// 流现已打开并在服务端缓冲。先读取历史记录。
for await (const event of client.beta.sessions.events.list(session.id)) {
seenEventIds.add(event.id)
handle(event)
}
// 尾随实时流。去重仅控制 handle() — 即使对于已见过的事件,终端检查也必须运行,
// 否则历史响应中的终端事件会被 `continue` 跳过,导致循环永远不会退出。
for await (const event of stream) {
if (!seenEventIds.has(event.id)) {
seenEventIds.add(event.id)
handle(event)
}
if (event.type === 'session.status_terminated') break
if (event.type === 'session.status_idle' && event.stop_reason.type !== 'requires_action') break
}
---
## 2. `processed_at` — 已排队 vs 已处理
流上的每个事件都带有 `processed_at` (ISO 8601)。对于客户端发送的事件(`user.message`、`user.interrupt`、`user.tool_confirmation`、`user.custom_tool_result`),当事件已排队但尚未被智能体拾取时,该字段为 `null`;一旦智能体处理完毕,该字段会被填充。同一个事件会在流中出现两次 — 一次是 `processed_at: null`,一次带有时间戳。
ts
for await (const event of stream) {
if (event.type === 'user.message') {
if (event.processed_at == null) onQueued(event.id)
else onProcessed(event.id, event.processed_at)
}
}
使用此机制来驱动您发送的任何内容的“待处理 → 已确认” UI 状态。如何将本地渲染的乐观消息映射到服务器分配的 `event.id` 取决于具体应用(通常通过 `events.send()` 的返回值或 FIFO 顺序)。
---
## 3. 中断正在运行的会话
将 `user.interrupt` 作为普通事件发送。会话将保持运行