Bug description
When a cron job is created from a Weixin DM (and likely other DM platforms), the cron tool can persist:
{
"deliver": "origin",
"origin": null
}
Even when the gateway session still has a valid HERMES_SESSION_KEY like:
agent:main:weixin:dm:<chat_id>
This makes deliver=origin fragile: if explicit session platform/chat env vars are missing in the worker thread, the cron tool drops the origin metadata instead of reconstructing it from the session key.
Why this is a separate bug from the existing issues
There are already open issues/PRs around cron delivery:
#8848 / #9193: deliver=origin fallback missing weixin/feishu/wecom
#9354 / #10227: gateway worker threads lose session contextvars, so cron creation may not see HERMES_SESSION_PLATFORM / HERMES_SESSION_CHAT_ID
Those are real, but the cron tool still has a robustness gap of its own:
tools/cronjob_tools.py::_origin_from_env() only trusts explicit HERMES_SESSION_PLATFORM + HERMES_SESSION_CHAT_ID
- if those are unavailable, it returns
None
- it does not attempt to reconstruct DM origin from
HERMES_SESSION_KEY, even though the DM session key format is deterministic and reversible
So even with the broader gateway/contextvars fixes pending, the cron tool is currently less defensive than it could be.
Reproduction
- Start from a Weixin DM session.
- Ensure
HERMES_SESSION_KEY=agent:main:weixin:dm:<chat_id> is present.
- Create a cron job through the cron tool.
- In the execution path where
HERMES_SESSION_PLATFORM / HERMES_SESSION_CHAT_ID are missing, inspect ~/.hermes/cron/jobs.json.
- The created job is stored with:
deliver: "origin"
origin: null
Expected behavior
If explicit session vars are unavailable, _origin_from_env() should fall back to parsing DM HERMES_SESSION_KEY values of the form:
agent:main:<platform>:dm:<chat_id>[:<thread_id>]
and reconstruct:
{
"platform": "weixin",
"chat_id": "...",
"thread_id": null
}
Suggested fix
In tools/cronjob_tools.py, make _origin_from_env():
- first read
HERMES_SESSION_PLATFORM / HERMES_SESSION_CHAT_ID as it does today
- if missing, read
HERMES_SESSION_KEY
- if the key matches DM format, reconstruct origin from it
Pseudo-shape:
session_key = get_session_env("HERMES_SESSION_KEY")
parts = session_key.split(":") if session_key else []
if len(parts) >= 5 and parts[0] == "agent" and parts[1] == "main" and parts[3] == "dm":
return {
"platform": parts[2],
"chat_id": parts[4],
"thread_id": parts[5] if len(parts) >= 6 else None,
}
Why this helps
This does not replace the gateway-side context propagation fix, but it makes cron creation much more resilient:
- DM-origin cron jobs stop depending on a single env propagation path
- origin metadata is still preserved when the session key is available
deliver=origin becomes safer for Weixin/Telegram/other DM platforms
Regression test ideas
Add tests for:
- explicit platform/chat vars still win when present
- Weixin DM session key reconstructs
platform=weixin, chat_id=<id>, thread_id=None
- DM session key with thread id reconstructs the thread id correctly
Bug description
When a cron job is created from a Weixin DM (and likely other DM platforms), the cron tool can persist:
{ "deliver": "origin", "origin": null }Even when the gateway session still has a valid
HERMES_SESSION_KEYlike:This makes
deliver=originfragile: if explicit session platform/chat env vars are missing in the worker thread, the cron tool drops the origin metadata instead of reconstructing it from the session key.Why this is a separate bug from the existing issues
There are already open issues/PRs around cron delivery:
#8848/#9193:deliver=originfallback missingweixin/feishu/wecom#9354/#10227: gateway worker threads lose session contextvars, so cron creation may not seeHERMES_SESSION_PLATFORM/HERMES_SESSION_CHAT_IDThose are real, but the cron tool still has a robustness gap of its own:
tools/cronjob_tools.py::_origin_from_env()only trusts explicitHERMES_SESSION_PLATFORM+HERMES_SESSION_CHAT_IDNoneHERMES_SESSION_KEY, even though the DM session key format is deterministic and reversibleSo even with the broader gateway/contextvars fixes pending, the cron tool is currently less defensive than it could be.
Reproduction
HERMES_SESSION_KEY=agent:main:weixin:dm:<chat_id>is present.HERMES_SESSION_PLATFORM/HERMES_SESSION_CHAT_IDare missing, inspect~/.hermes/cron/jobs.json.deliver: "origin"origin: nullExpected behavior
If explicit session vars are unavailable,
_origin_from_env()should fall back to parsing DMHERMES_SESSION_KEYvalues of the form:and reconstruct:
{ "platform": "weixin", "chat_id": "...", "thread_id": null }Suggested fix
In
tools/cronjob_tools.py, make_origin_from_env():HERMES_SESSION_PLATFORM/HERMES_SESSION_CHAT_IDas it does todayHERMES_SESSION_KEYPseudo-shape:
Why this helps
This does not replace the gateway-side context propagation fix, but it makes cron creation much more resilient:
deliver=originbecomes safer for Weixin/Telegram/other DM platformsRegression test ideas
Add tests for:
platform=weixin,chat_id=<id>,thread_id=None