第 4 章:消息、可见性与会话——一份数据服务三类消费者
4.1 是什么:Message 不是“聊天气泡”
Message 由 id、role、created、content 和 metadata 构成。MessageContentBlock 可以是 text、image、tool request/response、thinking、redacted thinking、action required、frontend tool 和 system notification。它同时承载:
- Provider 需要的模型上下文;
- Agent Loop 需要的控制信号;
- UI 需要的进度、审批和工具渲染数据;
- SessionManager 需要的可恢复历史。
metadata 中最重要的两个布尔值是 user_visible 与 agent_visible。这不是一个简单的“隐藏消息”开关,而是两条独立的投影。
flowchart TB Raw[同一 Message] --> UserView[user_visible_content\n给 UI] Raw --> AgentView[agent_visible_content\n给模型上下文] Raw --> Store[原始 JSON\n持久化] Raw --> Events[AgentEvent\n增量渲染]
4.2 源码怎么做:双可见性 + typed content
Message::user_visible_content() 会按 MCP annotation 和消息元数据过滤内容;agent_visible_content() 则生成给 Assistant audience 的投影。比如:
- 工具审批可以只对用户可见;
- compaction summary 可以只对 Agent 可见;
- stop hook denial nudge 可以是 agent-only;
- progress/system notification 可以进入 UI,但不一定送给模型。
Conversation 是 Vec<Message> 的受控封装。push 会按 message ID 合并增量文本和 thinking;fix_conversation 则在发给 LLM 前运行一组卫生处理:合并 text、去掉空消息、修复 tool pair、合并连续消息、去重 signed thinking,并确保 Agent 可见消息的首尾结构合法。
这解释了一个看似奇怪的事实:流式响应可以产生许多 AgentEvent::Message,但 session 最终只需要一组可重放、可校验的消息。
4.3 Tool request 为什么是“消息内容”,而不是外部任务对象
ToolRequest 记录 request id、解析后的 CallToolRequestParams、provider metadata 和 tool meta。对应的 ToolResponse 保留同一 id。把二者嵌入消息有三个好处:
- Provider formatter 可以按照自己的协议把 tool pair 重建出来。
- Compaction 可以把工具历史作为上下文的一部分压缩。
- Session export/import 不需要另外理解一套任务数据库。
对于解析失败的 tool call,Agent 仍会把合法 placeholder 写入历史,把真实解析错误放在配对的工具响应中。这样每个 provider 的正常 formatter 路径不需要分别处理“历史里有 Err”这种异常形状。
4.4 Session:消息之外的运行时快照
Session 不只保存 conversation,还保存 working_dir、session_type、provider/model config、extension data、recipe、schedule、usage、project_id、parent_session_id 和归档信息。SessionType 区分 user、scheduled、sub-agent、hidden、terminal、gateway、acp 等来源。
Session 的一个设计取舍是:摘要信息放在 sessions 表,完整消息另放 messages 表;读取列表时可以不加载完整 conversation,从而让会话列表和历史搜索更轻。session name 还可以由 provider 异步生成,但一旦 user_set_name 就不再覆盖。
源码定位
crates/goose-provider-types/src/conversation/message.rs:消息内容、可见性、tool pair、usage。crates/goose-provider-types/src/conversation.rs:Conversation::push、fix_conversation。crates/goose/src/session/session_manager.rs:Session、SessionManager、SQLite schema。crates/goose/src/agents/agent.rs:事件 ID、消息写回和HistoryReplaced。