From f5cf1f8a459d8ee8f0b3c3f4fb62e015e77b333d Mon Sep 17 00:00:00 2001 From: teknium1 Date: Sat, 14 Mar 2026 00:12:34 -0700 Subject: [PATCH] fix(cron): tag persisted cron sessions and test wiring - store cron-run sessions with source=cron instead of falling back to cli - close the per-run SessionDB after completion - add regression coverage for cron session_db/platform wiring --- cron/scheduler.py | 6 ++++++ tests/cron/test_scheduler.py | 41 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/cron/scheduler.py b/cron/scheduler.py index 51d7db430..12d355cd1 100644 --- a/cron/scheduler.py +++ b/cron/scheduler.py @@ -269,6 +269,7 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]: providers_order=pr.get("order"), provider_sort=pr.get("sort"), quiet_mode=True, + platform="cron", session_id=f"cron_{job_id}_{_hermes_now().strftime('%Y%m%d_%H%M%S')}", session_db=_session_db, ) @@ -325,6 +326,11 @@ def run_job(job: dict) -> tuple[bool, str, str, Optional[str]]: # Clean up injected env vars so they don't leak to other jobs for key in ("HERMES_SESSION_PLATFORM", "HERMES_SESSION_CHAT_ID", "HERMES_SESSION_CHAT_NAME"): os.environ.pop(key, None) + if _session_db: + try: + _session_db.close() + except Exception as e: + logger.debug("Job '%s': failed to close SQLite session store: %s", job_id, e) def tick(verbose: bool = True) -> int: diff --git a/tests/cron/test_scheduler.py b/tests/cron/test_scheduler.py index 312e80102..4314b5ac0 100644 --- a/tests/cron/test_scheduler.py +++ b/tests/cron/test_scheduler.py @@ -106,6 +106,47 @@ class TestDeliverResultMirrorLogging: ) +class TestRunJobSessionPersistence: + def test_run_job_passes_session_db_and_cron_platform(self, tmp_path): + job = { + "id": "test-job", + "name": "test", + "prompt": "hello", + } + fake_db = MagicMock() + + with patch("cron.scheduler._hermes_home", tmp_path), \ + patch("cron.scheduler._resolve_origin", return_value=None), \ + patch("dotenv.load_dotenv"), \ + patch("hermes_state.SessionDB", return_value=fake_db), \ + patch( + "hermes_cli.runtime_provider.resolve_runtime_provider", + return_value={ + "api_key": "test-key", + "base_url": "https://example.invalid/v1", + "provider": "openrouter", + "api_mode": "chat_completions", + }, + ), \ + patch("run_agent.AIAgent") as mock_agent_cls: + mock_agent = MagicMock() + mock_agent.run_conversation.return_value = {"final_response": "ok"} + mock_agent_cls.return_value = mock_agent + + success, output, final_response, error = run_job(job) + + assert success is True + assert error is None + assert final_response == "ok" + assert "ok" in output + + kwargs = mock_agent_cls.call_args.kwargs + assert kwargs["session_db"] is fake_db + assert kwargs["platform"] == "cron" + assert kwargs["session_id"].startswith("cron_test-job_") + fake_db.close.assert_called_once() + + class TestRunJobConfigLogging: """Verify that config.yaml parse failures are logged, not silently swallowed."""