From b1663edf2a2587881c442b6a67d833841c6e3a2f Mon Sep 17 00:00:00 2001 From: aameobius Date: Fri, 7 Aug 2026 23:24:28 +0300 Subject: [PATCH] fix(cron): load .env on no_agent path so standalone ticks resolve delivery home channels hermes-cron-tick.service starts without TELEGRAM_HOME_CHANNEL/DISCORD_HOME_CHANNEL in the unit env; the per-run load_hermes_dotenv reload lived only on the agent path (after the no_agent short-circuit returns), so every deliver=telegram/all script job failed with 'no delivery target resolved'. Load the dotenv at the top of the no_agent branch; override=False keeps the gateway's in-process tick behavior unchanged. --- cron/scheduler.py | 16 ++++++++++++++++ tests/cron/test_cron_no_agent.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/cron/scheduler.py b/cron/scheduler.py index 71a54368d1ec7..0177b278f927b 100644 --- a/cron/scheduler.py +++ b/cron/scheduler.py @@ -3207,6 +3207,22 @@ def run_job( # the whole point of no_agent is that there # is no agent to wake if job.get("no_agent"): + # Load .env before the script runs so auto-delivery can resolve home + # channels. A standalone cron tick process typically starts WITHOUT + # TELEGRAM_HOME_CHANNEL/DISCORD_HOME_CHANNEL in its environment, and + # the agent path's per-run dotenv reload below never executes for + # no_agent jobs — every deliver=telegram/all script job failed with + # "no delivery target resolved". load_hermes_dotenv does not override + # already-set vars, so the gateway's in-process tick is unaffected. + try: + from hermes_cli.env_loader import load_hermes_dotenv + + load_hermes_dotenv(hermes_home=_get_hermes_home()) + except Exception: + logger.debug( + "Job '%s': no_agent .env reload failed", job_id, exc_info=True + ) + script_path = job.get("script") if not script_path: err = "no_agent=True but no script is set for this job" diff --git a/tests/cron/test_cron_no_agent.py b/tests/cron/test_cron_no_agent.py index 6ba5afecf0ee5..94aea1de141ae 100644 --- a/tests/cron/test_cron_no_agent.py +++ b/tests/cron/test_cron_no_agent.py @@ -105,6 +105,36 @@ def test_run_job_no_agent_success_returns_script_stdout(hermes_env): assert "RAM 92% on host" in doc +def test_run_job_no_agent_reloads_dotenv_before_script(hermes_env, monkeypatch): + """Regression: a standalone cron tick process starts without home-channel + vars in its environment, and the agent path's per-run dotenv reload never + executes for no_agent jobs — delivery home channels stayed unresolved. + run_job must load .env at the top of the no_agent branch.""" + import hermes_cli.env_loader as env_loader + from cron.jobs import create_job + from cron.scheduler import run_job + + loaded_homes: list = [] + + def fake_load(*, hermes_home=None, project_env=None): + loaded_homes.append(hermes_home) + return [] + + monkeypatch.setattr(env_loader, "load_hermes_dotenv", fake_load) + + script_path = hermes_env / "scripts" / "probe.sh" + script_path.write_text('#!/bin/bash\necho "ok"\n') + + job = create_job( + prompt=None, schedule="every 5m", script="probe.sh", no_agent=True, deliver="local" + ) + success, doc, final_response, error = run_job(job) + assert success is True + assert error is None + assert loaded_homes, "load_hermes_dotenv was not called on the no_agent path" + assert str(loaded_homes[0]) == str(hermes_env) + + # --------------------------------------------------------------------------- # _run_job_script: shell-script support # ---------------------------------------------------------------------------