Cron 回调本会话(cron-callback-session)
让一次性/周期 cron job 执行完毕后,把结果通过 sessions_send 注入当前对话,使 agent 基于原上下文继续推进任务。
适用平台
- OpenClaw(原生):使用
sessions_send/ cron 机制,本 skill 的配置与命令直接适用 - QClaw(桌面客户端/界面):基于 OpenClaw 内核,同一套配置体系(
openclaw.json+sessions_send+ cron),本 skill 完全适用;QClaw 只是界面层,不改变底层机制 - 配置路径不硬编码:无论 OpenClaw 还是 QClaw,都用
openclaw config file自动发现(见第一步)
本质能力
本 skill 实现的是**"一个会话调起/注入另一个会话"**:A 会话(或外部进程 / cron job)通过 sessions_send 向 B 会话注入消息,B 的 agent 带着完整上下文被唤醒并继续处理。cron 回调当前对话只是最常见的应用形态,不是唯一用法。
非 cron 用法举例:
- 另一个会话处理完长任务后,把结果回传到主会话继续汇总
- 外部脚本/进程在特定时机向指定会话注入提示,触发其 agent 执行
- 监控/看门狗类任务发现异常时,向主对话注入警报并让 agent 介入处理
背景(为什么需要这个 skill)
- 默认
cron sessionTarget=isolated会在独立会话运行,任务结果上报到新对话,原对话不推进 - 要让结果回到原对话,需 cron 会话用
sessions_send发消息到当前对话 - 但
tools.sessions.visibility默认tree(只允许同一会话树内发送),cron isolated 会话不在树内 → forbidden - 重启可能重置网关配置(visibility 弹回默认 tree),所以每次用前必须先自查
⚠️ 风险警告(使用前必读)
本 skill 涉及两项需要谨慎的操作:
-
杀进程重启网关(第三步):
Stop-Process强制终止 gateway 进程会中断所有活跃会话、cron 任务及其他进行中的工作,可能导致服务中断或运营状态丢失。请:- 在维护窗口执行,或先确认当前没有重要任务在运行
- 执行前先完成第二步的配置备份
- 杀进程后依赖守护机制自动拉起,若未自动拉起需手动
openclaw gateway run恢复
-
放宽会话路由权限(第二步):
tools.sessions.visibility = agent会让当前 agent 下任意会话可互相发送消息,权限比默认tree更宽。请:- 仅在确实需要跨会话注入时开启
- 使用完毕后,如不再需要跨会话消息,建议恢复默认
tree(同样手动编辑配置文件)
流程
第一步:检查当前会话与配置
-
获取当前会话 key:
session_status (sessionKey="current")记下
Session:行,形如agent:main:session-xxxxxxxxxxxx-xxxxxx -
发现配置文件路径(不要硬编码,OpenClaw 可能装在任意目录):
openclaw config file输出最后一行即配置文件绝对路径(前面可能有 bootstrap 日志/doctor 警告等噪音,取最后一行)。
-
用该路径读取 visibility:
$cfgPath = (openclaw config file | Select-Object -Last 1) $c = Get-Content -Raw $cfgPath -Encoding UTF8 | ConvertFrom-Json $c.tools.sessions.visibility # 期望输出: agent -
确认网关进程是否加载了新配置(验证方法见第三步"验证")
第二步:配置检查与修复
目标值:tools.sessions.visibility = agent(当前 agentId 下任意会话可见;跨 agent 需额外 tools.agentToAgent)
| 当前值 | 处理 |
|---|---|
agent |
✅ 无需修改,跳到第三步 |
缺失 / tree / self |
手动编辑配置文件(见下) |
all |
✅ 可用但权限过大,建议收敛到 agent |
修改配置(gateway 工具的 config.patch 会拒绝此路径,必须手动编辑文件):
先拿到配置文件路径(同第一步):
openclaw config file # 取最后一行,即当前实际生效的配置文件绝对路径(默认 ~/.openclaw/openclaw.json,发行版可能不同,以此命令输出为准)
$cfgPath = (openclaw config file | Select-Object -Last 1)
# 1. 备份
Copy-Item $cfgPath "$cfgPath.bak-<yyyyMMdd>" -Force
# 2. 在 "tools" 段内插入 sessions 子段(若 tools.sessions 不存在)
# "tools": {
# "sessions": { "visibility": "agent" },
# ...
# }
# 3. 验证 JSON 合法
$null = Get-Content -Raw $cfgPath -Encoding UTF8 | ConvertFrom-Json; "JSON_VALID"
第三步:Windows 下正确重启网关(关键!)
⚠️ Windows 上
gateway restart是坏的:openclaw gateway restart报TypeError [ERR_UNKNOWN_SIGNAL]: Unknown signal: SIGUSR1Windows Node.js 不支持 SIGUSR1 信号 → in-process restart 永远失败 → 返回 ok 但进程没重启 → 配置改了不生效。 gateway 工具 restart 同理(内部走 SIGUSR1)。
正确姿势(2026-08-05 实测验证):杀旧进程 + 立刻手动拉起新进程
⚠️ 实测结论:不能依赖守护机制自动拉起。当 QClaw 桌面客户端未运行时,网关进程是独立运行的(无父进程守护),
Stop-Process杀掉后没有东西会自动拉起它,这就是"杀掉直接起不来"的根因。必须手动启动新进程。
⚠️⚠️ 执行前必读(2026-08-05 实测):
- 重启网关会断开 webchat 连接,agent 不会自己醒来——执行完杀旧+起新后,当前对话会静默,必须由用户手动输入一条消息(如"怎么样了")才能唤起 agent。agent 应在执行重启步骤前明确告知用户这一点,避免用户以为卡死。
- 不要重启 QClaw 桌面客户端——QClaw 重启会重新加载配置并可能把
tools.sessions.visibility重置回默认tree,之前改的配置就白改了。只重启网关进程本身(下面的命令),不要动 QClaw.exe。- 执行此步骤前,先告知用户"接下来需要重启网关,完成后请发一条消息唤醒我",再动手。
# 0. 准备:网关端口和启动命令
$node = "<发行版>\resources\node\node.exe" # 从 qclaw.json cli.nodeBinary 或当前进程 Path 获取
$mjs = "<发行版>\resources\openclaw\node_modules\openclaw\openclaw.mjs"
$port = <网关端口> # 从 openclaw.json gateway.port 获取
# 1. 找到网关进程(通常两个 node 进程,命令行含 "openclaw-gateway")
Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Where-Object { $_.CommandLine -match "openclaw-gateway" } | Select-Object ProcessId, CreationDate
# 2. 杀旧进程
# ⚠️ 此操作会中断所有活跃会话/定时任务/进行中的工作,确认无重要任务再执行
Stop-Process -Id <PID1>, <PID2> -Force
Start-Sleep -Seconds 3 # 等待端口释放
# 3. 立刻手动启动新进程(后台独立,与旧进程相同参数)
Start-Process -FilePath $node -ArgumentList "--title=openclaw-gateway","--no-warnings","--max-semi-space-size=128","--max-old-space-size=4096",$mjs,"gateway","run","--port","$port" -WindowStyle Hidden -PassThru
Start-Sleep -Seconds 5
# 4. 验证:新进程监听端口 + HTTP 连通
netstat -ano | Select-String ":$port.*LISTENING"
# 用网关认证值(从 openclaw.json 的 gateway.auth 段读取)请求 /v1/models,返回 model 列表 = 网关正常
# 同时确认当前对话能继续收发(session 自动接续)
关键点:
- 不要先启新进程再杀旧的——新进程会因端口被占而启动失败(报
gateway already running (pid xxx); lock timeout after 5000ms) - 启动命令参数必须与旧进程一致(
--title=openclaw-gateway等),否则 QClaw 客户端可能识别不到 - 网关认证值从
openclaw.json的gateway.auth段读取(该段配置项名含敏感词,此处不展开) - 若 QClaw 桌面客户端在运行,它可能自行管理网关进程,此时杀进程后客户端会自动拉起(观察 1-3 分钟再手动介入);但不要重启 QClaw.exe 本身(会重置配置)
- 重启后当前对话会静默(webchat 连接断开,agent 不会自动醒来)——告诉用户发一条消息唤起
验证配置已加载:
Get-CimInstance Win32_Process -Filter "Name='node.exe'" | Where-Object { $_.CommandLine -match "openclaw-gateway" } | Select-Object ProcessId, CreationDate
# 新进程 CreationDate 应为最近时间(而非旧日期)
若手动启动失败(端口未释放/参数错误),等端口释放后重试:
openclaw gateway run --port <port>(前台,便于看日志)。
第四步:设计 cron job 并回调本会话
一次性任务(X 分钟后):
{
"action": "add",
"job": {
"name": "<任务名>",
"agentId": "<当前agentId>",
"schedule": { "kind": "at", "at": "<now+1min ISO+08:00>" },
"sessionTarget": "isolated",
"payload": {
"kind": "agentTurn",
"message": "请调用 sessions_send 工具,target 填 '<当前会话key>',发送内容:'<要注入的消息>'。要求:(1) 只调用 sessions_send 发送 (2) 不要调用 message 工具 (3) 不要输出 HEARTBEAT_OK (4) 若失败如实报告错误"
},
"delivery": { "mode": "none" },
"deleteAfterRun": true
}
}
关键参数:
sessionTarget: "isolated"— cron 在独立会话运行(不需要绑定当前会话;绑定反而可能因树限制失败)payload.message里明确写sessions_send+ 完整 target(agent:main:session-xxx)delivery.mode: "none"— 结果不投递到渠道,只通过 sessions_send 注入目标对话- 时间格式:
yyyy-MM-ddTHH:mm:ss+08:00(本地时区,勿用 UTC)
第五步:验证回调
- 到约定时间后,检查目标对话是否收到注入消息(消息会以 inter-session message 形式出现)
- 查看运行记录:
cron (action="runs", jobId="<jobId>") - 注意:运行记录
status=error(如 "isolated agent setup timed out")不代表发送失败——消息可能已送达,只是任务状态判定超时。以目标对话是否收到消息为准。
忙时队列行为(重要)
sessionTarget=isolated 的 cron 会话调用 sessions_send 时,消息经过内部消息队列投递:
- 目标会话空闲:消息立即投递,注入方很快收到
accepted - 目标会话忙(正在处理其他回合/长任务):消息挂起等待,不丢不打断;待目标会话空闲后逐条投递
- 一个空闲窗口可能只投递一条,多条注入按序逐条到达(实测间隔 3-5 分钟)
⚠️
gateway timeout是误报,不是发送失败: 当目标会话忙时,注入方的sessions_send调用可能返回gateway timeout after 10000ms(10s 工具调用超时)。这代表消息已入队、投递挂起,不代表发送失败。 不要据此重发——消息最终会到达,重发会造成重复注入(同一内容出现多次)。注入延迟取决于目标会话的空闲节奏,实测可达 20+ 分钟。若需确认消息是否送达,以目标会话实际收到的 inter-session message 为准,而非调用返回值。
常见问题
- CLI 建 job 传中文参数会乱码(PowerShell 编码问题)——用英文 job 名,中文内容走 cron 工具 API 而非 CLI
forbidden: Session send visibility is restricted to the current session tree→ 配置不是agent,回到第二步- 改了配置但 cron 仍报 forbidden → 网关没真正重启(SIGUSR1 bug),回到第三步杀进程重启
- 想跨 agent 发送 → 需
tools.agentToAgent,且 visibility=all(风险高,慎用)。实测(2026-08-05):visibility=all+agentToAgent.enabled=true(allow*)下,cron isolated 会话可跨 agent 注入任意会话(如agent:op-xxx:session-xxx),目标 agent 收到后可用sessions_send回传;回传若遇gateway timeout同为忙时挂起误报,消息会入队稍后到达。注意:回传给 cron 临时会话(agent:main:cron:...:run:xxx)可能因该会话已删除而失败,应回传给持久会话(如agent:main:session-xxx) gateway config.patch报 "cannot change protected config paths" → 正常,此路径是内置保护,只能手动编辑文件
参考
- 完整实验记录:workspace 下《同会话上报实验归档_<日期>.md》
- 忙时队列行为实测记录:workspace 下 memory/2026-08-03.md(A/B/C 三注入实测,timeout 误报验证)
- 配置备份:openclaw.json.bak-(修改配置前自动生成)
反馈
发现 bug 或有改进建议?请开 GitHub Issue。
