Session 管理
OpenClaw 把每个 Agent 的一个直接聊天 Session 作为主 Session。直接聊天会合并到 agent:<agentId>:<mainKey>(默认是 main),而群组/频道聊天会有自己的键。系统会遵循 session.mainKey 配置。
用 session.dmScope 来控制私信的分组方式:
main(默认):所有 DM 共享主 Session,保持对话连续性。per-peer:按发送者 ID 隔离,跨 Channel。per-channel-peer:按 Channel + 发送者隔离(推荐用于多用户收件箱)。per-account-channel-peer:按账号 + Channel + 发送者隔离(推荐用于多账号收件箱)。 使用session.identityLinks可以把带 Provider 前缀的对等方 ID 映射到一个规范身份,这样同一个人在使用per-peer、per-channel-peer或per-account-channel-peer时,可以跨 Channel 共享一个 DM Session。
Gateway 是数据源头
所有 Session 状态都由 Gateway 拥有(也就是”主” OpenClaw)。UI 客户端(macOS 应用、WebChat 等)必须向 Gateway 查询 Session 列表和 Token 计数,而不是读取本地文件。
- 在远程模式下,你关心的 Session 存储在远程 Gateway 主机上,而不是你的 Mac 上。
- UI 中显示的 Token 计数来自 Gateway 存储字段(
inputTokens、outputTokens、totalTokens、contextTokens)。客户端不会解析 JSONL 记录来”修正”总数。
状态存储位置
- 在 Gateway 主机上:
- 存储文件:
~/.openclaw/agents/<agentId>/sessions/sessions.json(每个 Agent 一个)。
- 存储文件:
- 记录文件:
~/.openclaw/agents/<agentId>/sessions/<SessionId>.jsonl(Telegram 话题 Session 使用.../<SessionId>-topic-<threadId>.jsonl)。 - 存储是一个映射
sessionKey -> { sessionId, updatedAt, ... }。删除条目是安全的,它们会按需重新创建。 - 群组条目可能包含
displayName、channel、subject、room和space,用于在 UI 中标记 Session。 - Session 条目包含
origin元数据(标签 + 路由提示),这样 UI 可以解释 Session 的来源。 - OpenClaw 不会读取旧版 Pi/Tau Session 文件夹。
Session 修剪
OpenClaw 默认会在调用 LLM 之前,从内存中的 Context 里删除旧的工具结果。 这不会重写 JSONL 历史记录。详见 /concepts/session-pruning。
Compaction 前的内存刷新
当 Session 接近自动 Compaction 时,OpenClaw 可以运行一个静默内存刷新回合,提醒模型把持久化笔记写入磁盘。这只在 Workspace 可写时运行。详见 Memory 和 Compaction。
传输方式 → Session 键的映射
- 直接聊天遵循
session.dmScope(默认main)。main:agent:<agentId>:<mainKey>(跨设备/Channel 保持连续性)。- 多个电话号码和 Channel 可以映射到同一个 Agent 主键,它们充当进入一个对话的传输通道。
per-peer:agent:<agentId>:dm:<peerId>。per-channel-peer:agent:<agentId>:<channel>:dm:<peerId>。per-account-channel-peer:agent:<agentId>:<channel>:<accountId>:dm:<peerId>(accountId 默认为default)。- 如果
session.identityLinks匹配到带 Provider 前缀的对等方 ID(例如telegram:123),规范键会替换<peerId>,这样同一个人可以跨 Channel 共享一个 Session。
- 群组聊天隔离状态:
agent:<agentId>:<channel>:group:<id>(房间/频道使用agent:<agentId>:<channel>:channel:<id>)。- Telegram 论坛话题会在群组 ID 后追加
:topic:<threadId>来隔离。 - 旧版
group:<id>键仍然可以识别,用于迁移。
- Telegram 论坛话题会在群组 ID 后追加
- 入站 Context 可能仍使用
group:<id>;Channel 会从Provider推断,并规范化为agent:<agentId>:<channel>:group:<id>形式。 - 其他来源:
- Cron 任务:
cron:<job.id> - Webhook:
hook:<uuid>(除非 hook 明确设置) - Node 运行:
node-<nodeId>
- Cron 任务:
生命周期
- 重置策略:Session 会被重复使用直到过期,过期检查在下一条入站消息时进行。
- 每日重置:默认为 Gateway 主机本地时间凌晨 4:00。Session 的最后更新时间早于最近一次每日重置时间时,就会过期。
- 空闲重置(可选):
idleMinutes添加一个滑动空闲窗口。当同时配置每日重置和空闲重置时,哪个先过期就用哪个来强制创建新 Session。 - 旧版纯空闲模式:如果你设置了
session.idleMinutes但没有任何session.reset/resetByType配置,OpenClaw 会保持纯空闲模式以向后兼容。 - 按类型覆盖(可选):
resetByType让你可以为dm、group和threadSession 覆盖策略(thread = Slack/Discord 线程、Telegram 话题、Matrix 线程,由连接器提供时)。 - 按 Channel 覆盖(可选):
resetByChannel为某个 Channel 覆盖重置策略(适用于该 Channel 的所有 Session 类型,优先级高于reset/resetByType)。 - 重置触发器:精确的
/new或/reset(加上resetTriggers中的任何额外触发器)会启动一个新的 Session ID,并传递消息的剩余部分。/new <model>接受模型别名、provider/model或 Provider 名称(模糊匹配)来设置新 Session 的模型。如果单独发送/new或/reset,OpenClaw 会运行一个简短的”你好”问候回合来确认重置。 - 手动重置:从存储中删除特定键或删除 JSONL 记录文件;下一条消息会重新创建它们。
- 隔离的 Cron 任务总是为每次运行创建一个新的
sessionId(不会空闲重用)。
发送策略(可选)
阻止特定 Session 类型的消息发送,无需列出单个 ID。
{
session: {
sendPolicy: {
rules: [
{ action: "deny", match: { channel: "discord", chatType: "group" } },
{ action: "deny", match: { keyPrefix: "cron:" } },
],
default: "allow",
},
},
}
运行时覆盖(仅所有者):
/send on→ 允许此 Session/send off→ 拒绝此 Session/send inherit→ 清除覆盖并使用配置规则 把这些作为独立消息发送,这样它们才能注册。
配置示例(可选重命名)
// ~/.openclaw/openclaw.json
{
session: {
scope: "per-sender", // 保持群组键分离
dmScope: "main", // DM 连续性(共享收件箱设置为 per-channel-peer/per-account-channel-peer)
identityLinks: {
alice: ["telegram:123456789", "discord:987654321012345678"],
},
reset: {
// 默认值:mode=daily,atHour=4(Gateway 主机本地时间)。
// 如果你还设置了 idleMinutes,哪个先过期就用哪个。
mode: "daily",
atHour: 4,
idleMinutes: 120,
},
resetByType: {
thread: { mode: "daily", atHour: 4 },
dm: { mode: "idle", idleMinutes: 240 },
group: { mode: "idle", idleMinutes: 120 },
},
resetByChannel: {
discord: { mode: "idle", idleMinutes: 10080 },
},
resetTriggers: ["/new", "/reset"],
store: "~/.openclaw/agents/{agentId}/sessions/sessions.json",
mainKey: "main",
},
}
检查方法
openclaw status— 显示存储路径和最近的 Session。openclaw sessions --json— 导出所有条目(用--active <minutes>过滤)。openclaw gateway call sessions.list --params '{}'— 从运行中的 Gateway 获取 Session(用--url/--token访问远程 Gateway)。- 在聊天中发送
/status作为独立消息,查看 Agent 是否可达、Session Context 使用了多少、当前的 thinking/verbose 开关状态,以及你的 WhatsApp web 凭证最后刷新时间(帮助发现需要重新链接)。 - 发送
/context list或/context detail查看系统 Prompt 和注入的 Workspace 文件中有什么(以及最大的 Context 贡献者)。 - 发送
/stop作为独立消息来中止当前运行,清除该 Session 的排队后续任务,并停止从它派生的任何子 Agent 运行(回复会包含停止的数量)。 - 发送
/compact(可选指令)作为独立消息来总结旧的 Context 并释放窗口空间。详见 /concepts/compaction。 - JSONL 记录文件可以直接打开来查看完整回合。
使用建议
- 把主键专门用于 1:1 对话;让群组保留自己的键。
- 自动清理时,删除单个键而不是整个存储,以保留其他地方的 Context。
Session 来源元数据
每个 Session 条目会记录它的来源(尽力而为)在 origin 中:
label:人类可读标签(从对话标签 + 群组主题/Channel 解析)provider:规范化的 Channel ID(包括扩展)from/to:来自入站信封的原始路由 IDaccountId:Provider 账号 ID(多账号时)threadId:线程/话题 ID(当 Channel 支持时) 来源字段会为私信、频道和群组填充。如果连接器只更新发送路由(例如,保持 DM 主 Session 活跃),它仍应提供入站 Context,这样 Session 才能保留其解释元数据。扩展可以通过在入站 Context 中发送ConversationLabel、GroupSubject、GroupChannel、GroupSpace和SenderName,并调用recordSessionMetaFromInbound(或将相同 Context 传递给updateLastRoute)来实现。