GPU_GUARD_MONOREPO/docs/code-wiki/concepts/session-tree-runtime.md
2026-05-20 21:39:12 +08:00

155 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: Session Tree 运行时
created: 2026-04-21
updated: 2026-04-26
type: concept
tags: [runtime, agent, backend, database]
sources: [packages/backend/src/modules/netaclaw/session-tree/provider.ts, packages/backend/src/modules/netaclaw/session-tree/types.ts, packages/backend/src/modules/netaclaw/session-tree/snapshot.ts, packages/backend/src/modules/netaclaw/session-tree/context_builder.ts, packages/backend/src/modules/netaclaw/session-tree/mysql_provider.ts, packages/backend/src/modules/netaclaw/session-tree/file_provider.ts, packages/backend/src/modules/netaclaw/gateway/session.ts, packages/frontend/src/modules/agent/store/chat.ts]
---
# Session Tree 运行时
Session Tree 是 NetaClaw 新 Agent runtime 的会话状态模型。它把对话从线性消息列表升级为“节点树 + 当前叶子 + 活动路径 + 运行时上下文”的结构,使刷新恢复、分支、压缩、子 Agent 批次、标签、模型切换都能进入同一套持久化和投影机制。
它是 [[agent-runtime]]、[[context-compaction]]、[[subagent-session]] 和 [[frontend-architecture]] 的共同底座。
## Provider 抽象
`SessionTreeProvider` 定义统一接口,当前有 file 和 mysql 两种 provider。
主要能力包括:
- `createSession`
- `getSession`
- `updateSession`
- `deleteSession`
- `listEntries`
- `appendEntry`
- `appendMessage`
- `appendThinkingLevelChange`
- `appendModelChange`
- `appendCompaction`
- `appendBranchSummary`
- `appendLabelChange`
- `appendSessionInfo`
- `updateEntry`
- `switchLeaf`
- `resetLeaf`
- `createBranchedSession`
- `getActivePath`
- `getSnapshot`
这层抽象让运行时不直接绑定 MySQL 或本地文件,也为未来多 workspace、本地优先存储、导入导出保留空间。
## Snapshot 结构
`SessionTreeSnapshot` 是前后端对齐的核心投影:
| 字段 | 含义 |
| --- | --- |
| `session` | 会话元信息,包括 provider、rootEntryId、leafEntryId、cwd、agentId 等 |
| `entries` | 当前会话所有树节点 |
| `activePath` | 从 root 到 leaf 的当前上下文路径 |
| `childrenByParentId` | 前端重建树结构所需的父子索引 |
| `labelsByEntryId` | 节点标签状态 |
| `runtimeContext` | 供模型调用使用的消息、thinking level、模型引用 |
前端刷新恢复应优先加载 snapshot而不是依赖 localStorage 保存完整聊天记录。
## Entry 类型
当前树节点类型包括:
| 类型 | 用途 |
| --- | --- |
| `message` | system/user/assistant/tool 模型消息 |
| `thinking_level_change` | 会话内 thinking level 切换 |
| `model_change` | 会话内模型切换 |
| `compaction` | 压缩摘要节点,详见 [[context-compaction]] |
| `branch_summary` | 分支摘要 |
| `custom` | 不直接展示的自定义数据 |
| `custom_message` | 可展示的自定义消息 |
| `label` | 对目标节点设置或清除标签 |
| `session_info` | 会话信息变更 |
| `subagent_batch` | 子 Agent 批次节点,详见 [[subagent-session]] |
| `subagent_result` | 子 Agent 批次结果节点 |
## Active Path 与上下文构建
模型上下文不再等于“所有历史消息”。运行时会从当前 `leafEntryId` 回溯得到 `activePath`,再由 `context_builder.ts` 转成 `runtimeContext.messages`
这带来几个结果:
- 分支切换只需要切换 leaf。
- 压缩摘要可以替代被压缩的历史段。
- 子 Agent、分支摘要、custom message 可以参与展示,但不一定进入模型上下文。
- thinking/model 变更可以沿路径生效。
## 持久化位置
Session Tree 支持两类持久化:
- MySQL provider适合生产和多端共享。
- File provider适合本地优先、单机 workspace、调试和导入导出。
浏览器 localStorage 只保存最近 session/agent 之类的轻量指针,不是对话历史主存储。
## 删除语义
Session Tree 删除必须按会话实际所属的 provider 执行:
- 前端 `chat.ts` 删除请求优先携带会话列表中该 session 的 `agentId`
- 后端 `gateway/session.ts` 在删除前先从 `netaclaw_agent_session` 反查 `sessionId` 所属 `agentId`,再解析该 Agent 的 session backend。
- MySQL provider 删除 `netaclaw_agent_session_entry``netaclaw_agent_session`file provider 删除对应 JSONL 文件。
- 随后后端再清理 legacy session/message、subagent_session 和 session-tree 兼容表记录。
这避免了 MySQL 会话在当前选中 Agent 不一致、或前端缺少 `agentId` 时走默认 file provider导致“点击删除没有效果”。
## 前端消费
`packages/frontend/src/modules/agent/store/chat.ts` 负责消费 snapshot
- `sessionMeta` 保存会话元信息。
- `entries``entryById` 保存节点。
- `childrenByParentId` 支持树结构恢复。
- `activePathIds` 控制当前可见路径。
- `visibleEntries` 将树节点投影成对话 UI。
- `subagentRuntimeByBatchId``toolRuntimeRoutesByBatchId` 记录子 Agent 工具路由展示数据。
对话页滚动、刷新恢复、历史批次展示都应该围绕这些状态实现。
## 相关页面
- [[agent-runtime]]
- [[subagent-session]]
- [[context-compaction]]
- [[frontend-architecture]]
- [[websocket-gateway]]
- [[netaclaw-module]]
- [[frontend-architecture]]
## 2026-04-22 Subagent Result Metadata
`subagent_result` carries durable metadata needed to replay subagent execution after refresh.
- `metadata.processEvents`: normalized worker event timeline for UI replay.
- `metadata.evidenceSummaries`: structured evidence projection built from subagent tool results.
- `metadata.toolRuntimeRoutes`: tool routing diagnostics for the delegated batch.
The frontend store should project these fields into dedicated maps keyed by entry id, rather than letting view components parse raw metadata directly.
## 2026-04-23 Continue-From-Entry And Projection Contract
Session Tree 现在不仅负责“存什么”,还决定“从哪里继续对话”:
- 前端 `chat.ts` 维护 `selectedEntryId``switchingLeafEntryId``pendingLeafConfirmation`,允许用户选中任意节点后继续发送,而不是只能沿当前 leaf 末尾追加。
- 如果选中的是普通 user 节点,继续发送会基于它的父节点重放该条 user message形成新的分支。
- 如果选中的是 `branch_summary``compaction` 或非当前 leaf 节点,前端会先切换 leaf再沿该路径继续。
- 这些交互都以 `session.leafEntryId``activePath` 和 snapshot 中的树结构为依据,不依赖前端自行缓存一份线性历史。
对子 Agent 相关节点,当前 snapshot 契约也更明确:
- `subagent_result.metadata.subagentProjection` 是会话树边界输出的 canonical projection。
- projection 内的 `diagnostics.selectedSource``inputSources``fallbackUsed` 用来说明当前展示究竟来自 `subagent_result`、旧 tool message还是历史 metadata fallback。
- 这让 Session Tree 不再只是原始数据容器,而是把“兼容历史记录”和“为当前 UI 供给稳定形态”一起纳入运行时模型。