Session 管理
OpenClaw 将每个 Agent 的一个直接聊天 Session 作为主 Session。直接聊天会合并到 agent:<agentId>:<mainKey>(默认是 main),而群组/频道聊天会有自己的 key。系统会遵循 session.mainKey 的设置。
使用 session.dmScope 来控制私信的分组方式:
main(默认):所有 DM 共享主 Session,保持对话连续性。per-peer:按发送者 ID 隔离,跨 Channel 独立。per-channel-peer:按 Channel + 发送者隔离(推荐用于多用户收件箱)。per-account-channel-peer:按账号 + Channel + 发送者隔离(推荐用于多账号收件箱)。 使用session.identityLinks可以将带提供商前缀的对等方 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 之前从内存上下文中修剪旧的工具结果。 这不会重写 JSONL 历史记录。详见 /concepts/session-pruning。
Compaction 前的内存刷新
当 Session 接近自动 Compaction 时,OpenClaw 可以运行一个静默内存刷新轮次,提醒模型将持久化笔记写入磁盘。这只在 Workspace 可写时运行。详见 Memory 和 Compaction。
传输方式 → Session key 的映射
- 直接聊天遵循
session.dmScope(默认是main)。main:agent:<agentId>:<mainKey>(跨设备/Channel 保持连续性)。- 多个电话号码和 Channel 可以映射到同一个 Agent 主 key,它们作为进入同一对话的传输方式。
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匹配到带提供商前缀的对等方 ID(例如telegram:123),统一 key 会替换<peerId>,这样同一个人可以跨 Channel 共享 Session。
- 群组聊天隔离状态:
agent:<agentId>:<channel>:group:<id>(房间/频道使用agent:<agentId>:<channel>:channel:<id>)。- Telegram 论坛话题会在群组 ID 后追加
:topic:<threadId>来隔离。 - 旧版
group:<id>key 仍然可以识别,用于迁移。
- Telegram 论坛话题会在群组 ID 后追加
- 入站上下文可能仍使用
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 的最后更新时间早于最近一次每日重置时间时,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或提供商名称(模糊匹配)来设置新 Session 的模型。如果单独发送/new或/reset,OpenClaw 会运行一个简短的”你好”问候轮次来确认重置。 - 手动重置:从存储中删除特定 key 或删除 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", // 保持群组 key 独立
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 上下文使用了多少、当前的 thinking/verbose 开关状态,以及你的 WhatsApp web 凭证最后刷新时间(帮助发现需要重新链接的情况)。 - 发送
/context list或/context detail查看系统 Prompt 和注入的 Workspace 文件中有什么(以及最大的上下文贡献者)。 - 发送
/stop作为独立消息来中止当前运行,清除该 Session 的排队后续任务,并停止从它派生的任何子 Agent 运行(回复会包含停止的数量)。 - 发送
/compact(可选指令)作为独立消息来总结旧的上下文并释放窗口空间。详见 /concepts/compaction。 - 可以直接打开 JSONL 记录文件来查看完整的轮次。
提示
- 保持主 key 专用于 1:1 对话;让群组保持自己的 key。
- 自动清理时,删除单个 key 而不是整个存储,以保留其他地方的上下文。
Session 来源元数据
每个 Session 条目会记录它的来源(尽力而为)在 origin 中:
label:人类可读标签(从对话标签 + 群组主题/频道解析)provider:规范化的 Channel ID(包括扩展)from/to:来自入站信封的原始路由 IDaccountId:提供商账号 ID(多账号时)threadId:线程/话题 ID(当 Channel 支持时) 来源字段会为私信、频道和群组填充。如果连接器只更新发送路由(例如,保持 DM 主 Session 活跃),它仍应提供入站上下文,这样 Session 可以保留其解释元数据。扩展可以通过在入站上下文中发送ConversationLabel、GroupSubject、GroupChannel、GroupSpace和SenderName,并调用recordSessionMetaFromInbound(或将相同上下文传递给updateLastRoute)来实现。