nanobot 事件与协议索引
对应源码
| 层级 | 源码 |
|---|---|
| 业务消息和队列 | nanobot/bus/events.py、nanobot/bus/queue.py |
| Turn 与 Runtime Events | nanobot/agent/loop.py、nanobot/bus/runtime_events.py |
| Hook、progress 和 stream | nanobot/agent/hook.py、nanobot/agent/progress_hook.py、nanobot/sdk/streaming.py |
| HTTP、WebSocket 和 Channel 协议 | nanobot/api/server.py、nanobot/channels/websocket.py、nanobot/channels/manager.py |
| WebUI wire/client | nanobot/webui/、webui/src/lib/、webui/src/hooks/ |
1. 先判断自己在哪一层
flowchart TD CH["Channel / API / SDK"] --> IM["InboundMessage 或 direct call"] IM --> AL["AgentLoop / AgentRunner"] AL --> OM["OutboundMessage"] OM --> CH AL --> RE["RuntimeEventBus<br/>高层运行状态"] AL --> HK["Agent hooks / progress callbacks<br/>文本、reasoning、tool 进度"] HK --> AD["SDK / Channel / WebSocket adapter"] AD --> WP["各自的公开或 wire protocol"]
最重要的边界:
- MessageBus 传业务消息;
- RuntimeEventBus 只传五类高层运行状态;
- 文本 delta、reasoning delta 和 Tool 进度来自 Agent hook/progress callback 路径;
- SDK 和 WebSocket 再把内部信号转换成各自事件格式。
2. MessageBus 数据对象
InboundMessage
定义:nanobot/bus/events.py::InboundMessage
| 字段 | 含义 |
|---|---|
channel | 来源 Channel |
sender_id | 用户标识 |
chat_id | 对话/频道标识 |
content | 文本内容 |
timestamp | 接收时间 |
media | 媒体 URL/路径列表 |
metadata | Channel 或内部控制元数据 |
session_key_override | 覆盖默认 Session key |
session_key | 属性:覆盖值或 channel:chat_id |
OutboundMessage
定义:nanobot/bus/events.py::OutboundMessage
| 字段 | 含义 |
|---|---|
channel、chat_id | 投递目标 |
content | 文本 |
reply_to | 可选回复目标 |
media | 媒体列表 |
metadata | 路由、进度和富 UI 信息 |
buttons | 可选按钮行 |
3. 内部 metadata 信号
这些字段以下划线开头,服务于 nanobot 内部层间协作。它们不是建议外部应用长期依赖的稳定公共协议。
| 字段 | 方向/作用 | 主要消费位置 |
|---|---|---|
_wants_stream | 入站:请求流式输出 | AgentLoop.run() |
_stream_delta | 出站:当前消息是文本流片段 | ChannelManager、具体 Channel |
_stream_end | 出站:结束当前 stream segment | 同上 |
_stream_id | 区分同一 Turn 内多个 stream segment | WebSocket、Telegram 等 |
_progress | 出站:进度消息,不是最终普通回复 | ChannelManager |
_tool_hint | 进度内容是工具提示 | Channel 渲染 |
_reasoning_delta | reasoning 增量 | Channel reasoning adapter |
_reasoning_end | reasoning segment 结束 | 同上 |
_retry_wait | Provider 进入重试等待提示 | ChannelManager |
_runtime_control | 入站:进程内运行控制,不进入普通用户 Session | nanobot/agent/context.py、MCP reload |
_agent_ui | 出站:可选、可序列化的富 UI payload | rich client,可被普通 Channel 忽略 |
metadata 不是一个扁平公共协议
同一个 dict 同时承载 Channel 路由、内部流式标记和可选 UI 数据。新增字段前必须先确认生产者、消费者、持久化和跨入口兼容性。
4. RuntimeEventBus 的精确事件集合
定义:nanobot/bus/runtime_events.py
| dataclass | 关键字段 | 语义 |
|---|---|---|
SessionTurnStarted | context | Session 已加载,Turn 即将构建上下文 |
TurnRunStatusChanged | context、status、started_at | 可见运行状态变化 |
TurnCompleted | context、latency_ms、runtime | 用户可见最终响应已经交付 |
GoalStateChanged | context、session_metadata | 持续目标状态变化 |
RuntimeModelChanged | model、model_preset | 当前 runtime 模型变化 |
RuntimeEventContext 统一携带 channel、chat_id、session_key 和 metadata。
RuntimeEventBus.publish() 按注册顺序调用订阅者,并等待异步 handler;单个 handler 抛错会被记录,不阻断后续发布调用者。publish_nowait() 需要正在运行的 event loop,否则事件会被丢弃并记录 debug 日志。
RuntimeEventBus 没有文本或 Tool delta dataclass
文本、reasoning 和 Tool 级别的细粒度进度走
nanobot/agent/hook.py、progress_hook.py和相应 callback。不要把 SDK 的text.delta误认为 RuntimeEventBus 事件。
5. SDK StreamEvent
定义:nanobot/sdk/types.py
| 事件类型 | 含义 |
|---|---|
run.started | 一次 SDK run 开始 |
text.delta / text.completed | 文本片段/文本段完成 |
reasoning.delta / reasoning.completed | reasoning 片段/段完成 |
tool.started | Tool 开始,可能带 name、arguments、call id |
tool.completed / tool.failed | Tool 成功/失败 |
run.completed | 返回最终 RunResult |
run.failed | run 失败 |
StreamEvent 可能携带 delta、content、result、Tool 字段、usage、error 和 metadata。具体生成逻辑见 nanobot/sdk/streaming.py。
6. HTTP API
当前 nanobot/api/server.py 注册:
| 路由 | 行为 |
|---|---|
POST /v1/chat/completions | OpenAI-compatible chat completions;支持 JSON 和 multipart |
GET /v1/models | 列出可用模型 |
GET /health | 返回 API 服务健康状态 |
流式响应使用该 API 层构造的 SSE 语义。API 的 chunk 不等同于 MessageBus 的 _stream_delta,二者只是可能共享同一核心 callback 来源。
完整格式见 官方 OpenAI API 文档。
7. WebSocket 与 WebUI
WebSocket frame 包含客户端需要的 envelope、sequence、replay、stream id 和 UI 状态。精确 wire 字段以:
- 官方 WebSocket 文档
nanobot/channels/websocket.pytests/channels/test_websocket_integration.py
为准。
学习时只需牢牢记住:
RuntimeEvent dataclass ≠ OutboundMessage metadata ≠ SDK StreamEvent ≠ WebSocket frame它们可以描述相近动作,但服务于不同消费者和兼容性边界。
8. 调试事件丢失
依次确认:
- 核心动作是否真的发生;
- 对应的是 Runtime Event 还是 hook/progress callback;
- producer 是否调用;
- adapter 是否订阅/传入 callback;
- Channel 配置是否过滤进度、Tool hint 或 reasoning;
- wire frame 是否送达;
- UI 是否按 stream id/sequence 正确归并。
返回:速查参考