Skip to content

feat(cron): mirror cron delivery output to target session for cross-session awareness - #34631

Closed
zhangyu921 wants to merge 2 commits into
NousResearch:mainfrom
zhangyu921:feat/cron-mirror-to-session
Closed

feat(cron): mirror cron delivery output to target session for cross-session awareness#34631
zhangyu921 wants to merge 2 commits into
NousResearch:mainfrom
zhangyu921:feat/cron-mirror-to-session

Conversation

@zhangyu921

@zhangyu921 zhangyu921 commented May 29, 2026

Copy link
Copy Markdown

Summary

When cron jobs autonomously deliver messages to a platform (telegram, discord, etc.), the receiving agent has no awareness that the message was sent — the cron output lives in the delivery channel but not in the agent's session transcript. This means the next time the user talks to the agent, it has no context of what cron just told them.

This is particularly impactful in persona-driven / SOUL.md scenarios: when an agent has a defined personality (like Asuka, a custom companion persona), cron-scheduled check-ins, market alerts, and daily briefings are delivered in-character. But when the user follows up on the same platform, the agent starts with a blank conversation — it doesn't know what its own persona just said via cron. The user has to repeat themselves or the agent has to manually call `session_search` to piece together context, breaking the natural flow of a persistent personality.

This PR bridges that gap by adding a `cron.mirror_to_session` option that mirrors cron delivery output into the target session's SQLite transcript, tagged with `mirror: true` and `mirror_source: "cron"`. On the user's next message, the agent sees `[Delivered from cron]` messages in conversation history — the personality stays continuous without manual lookup.

Changes

File Change
`cron/scheduler.py` Import `mirror_to_session`; call it after successful delivery in both the live-adapter and no-adapter fallback paths
`hermes_cli/config.py` Add `mirror_to_session: false` default under `cron.settings` section with docstring
`gateway/mirror.py` New module — `mirror_to_session()` finds the matching gateway session via sessions.json, then writes a delivery-mirror record (role=assistant, mirror=true, mirror_source=cron) to the SQLite session DB
`tests/gateway/test_mirror.py` Tests for `_find_session_id` (platform matching, thread/user disambiguation, ambiguous-group safety), `mirror_to_session` (success, thread-aware, user-aware, missing-session, error), and `_append_to_sqlite` (connection lifecycle, error cleanup)

How it works

  1. User enables `cron.mirror_to_session: true` in config.yaml
  2. When a cron job fires and successfully delivers to a platform, `_deliver_result()` calls `mirror_to_session()` with the platform, chat_id, content, and source_label="cron"
  3. `mirror_to_session()` resolves the session via sessions.json, then persists a mirror message to the SQLite transcript
  4. On the user's next message, the prompt builder includes these mirror messages in conversation history — the agent sees them as if it had said them itself

Config

```yaml
cron:
mirror_to_session: true # default: false — backward compatible
```

How to test

  1. Enable `cron.mirror_to_session: true` in `~/.hermes/config.yaml`
  2. Create a cron job that delivers to your chat: `/cron create "every 1m" "Say hello from cron"`
  3. Wait for delivery, then send any message — the agent should reference the cron message in context without needing `session_search`

Platforms tested

  • macOS 14+ (local development)
  • Linux (CI test suite)

Backward compatibility

Defaults to `false` — existing cron behaviour is unchanged. No new dependencies. The mirror function is non-fatal on error (all exceptions caught and logged at DEBUG level).

Add mirror_to_session() call after successful cron delivery, so the
main agent sees cron outputs in conversation history on next user message.

Updates both delivery paths: live adapter and standalone.
…eness

Add a new cron.mirror_to_session config option (default: false) that,
when enabled, mirrors cron delivery output to the target session's
SQLite transcript via mirror_to_session(). The main agent sees these
messages prefixed with "[Delivered from cron]" in conversation history
on the next user message, enabling cross-session awareness.

The config option is read per-delivery at fire time and can be set
globally in config.yaml under cron.mirror_to_session.

Backward compatible: default is false, preserving original behaviour.
@alt-glitch alt-glitch added type/feature New feature or request comp/cron Cron scheduler and job management comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have labels May 29, 2026
@Vantex

Vantex commented Jun 17, 2026

Copy link
Copy Markdown

+1 — WeChat daily driver, mirror approach is the right fit

+1 for this feature. I'm running Hermes on WeChat as a daily driver, and the cron context gap is a real pain point.

My use case: I have several cron jobs that deliver context summaries (daily diary reminders, wiki digestion results, project status updates) to my WeChat chat. When I reply to those messages, the main agent has zero context about what the cron just told me — it's a blank conversation. I end up having to manually paste context or re-explain.

Current workaround: I wrote a cron_output/ bridge — cron dumps its result to a JSON file, and my SOUL.md has a hardcoded rule that tells the agent to stat that file on every incoming message during specific time windows. It works but it's fragile, requires maintenance, and has timing edge cases.

What I want: When a cron job fires and delivers to my WeChat chat, the cron output should be visible to the agent in the session transcript on my next message. Exactly what cron.mirror_to_session describes.

WeChat-specific note: WeChat doesn't have Telegram-style inline buttons, so the offer_context_inject approach from #26206 wouldn't work here. The automatic mirror approach in #34631 is the better fit for platforms without rich message UI.

Happy to beta-test if this gets implemented.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the focused implementation and for documenting the WeChat use case in the discussion.

Automated hermes-sweeper review found this behavior is already implemented on current main:

  • 1b181724fae7799cf45dec3aca03ac44063175e7 added opt-in cron-delivery mirroring via global cron.mirror_delivery and per-job attach_to_session controls.
  • cron/scheduler.py:584 resolves that opt-in gate; cron/scheduler.py:1875 and cron/scheduler.py:1965 mirror after successful live-adapter and standalone deliveries.
  • c06ceb3232f2df301077db891c4b416f3326efa8 scopes the mirror to the originating conversation, and b177d4ee4891aeb3bf8a908f6e5def846a55c180 makes the replay alternation-safe with a labelled user turn.
  • Existing coverage in tests/cron/test_scheduler.py:4165 verifies the gate, origin-only targeting, user-id routing, and replay-role invariant.

The shipped implementation addresses the requested next-turn awareness while adding session-isolation and message-alternation safeguards, so this PR is now redundant.

@teknium1 teknium1 closed this Jul 13, 2026
@teknium1 teknium1 added sweeper:implemented-on-main Sweeper: behavior already present on current main sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:implemented-on-main Sweeper: behavior already present on current main sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants