Skip to content

fix(cron): deliver manual runs on profile-owned gateway loop - #71132

Open
ciabata-git wants to merge 2 commits into
NousResearch:mainfrom
ciabata-git:fix/cron-run-matrix-delivery-20260724
Open

fix(cron): deliver manual runs on profile-owned gateway loop#71132
ciabata-git wants to merge 2 commits into
NousResearch:mainfrom
ciabata-git:fix/cron-run-matrix-delivery-20260724

Conversation

@ciabata-git

Copy link
Copy Markdown
Contributor

What does this PR do?

Manual cronjob(action="run") executions inside a live gateway currently call run_one_job(job) without the gateway adapter map or the event loop that owns those adapters. Matrix then may await its live mautrix/aiohttp client from a fresh asyncio.run() loop and fail with:

Timeout context manager should be used inside a task

This PR passes the live, profile-owned adapter map and its owning gateway loop into the existing scheduler delivery path. Unsafe or unavailable gateway context preserves the exact standalone run_one_job(job) behavior.

This carries forward Fly's original commit from #63586, preserving authorship, and adds the multiplex-profile isolation requested in that PR's maintainer review. Unlike the original revision, a secondary profile can never inherit the primary profile's adapter credentials when its own registry entry is missing or partial.

Related Issue

Fixes #61495

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • tools/cronjob_tools.py
    • Resolve the existing gateway.run._gateway_runner_ref without adding another registry or a Matrix-specific branch.
    • Reuse context only when the runner is active and its loop is present, open, and running.
    • Compare context-scoped get_hermes_home() with process-owned get_process_hermes_home() unconditionally.
    • For a scoped secondary profile, require the exact _profile_adapters[get_active_profile_name()] map; missing provenance fails closed instead of borrowing runner.adapters.
    • Pass adapters and their owning loop together to run_one_job; otherwise retain the exact one-argument standalone call.
  • tests/tools/test_cronjob_run_immediate.py
    • Cover live gateway context, exact standalone compatibility, stale runner/loop states, real HERMES_HOME profile resolution, metadata enabled/disabled/missing, absent registries, and partial secondary maps.
    • Feed selected maps into the real delivery resolver to assert adapter identity rather than only inspecting mocks.

How to Test

  1. Run the focused and adjacent cron suites:

    HERMES_PYTHON=/usr/local/lib/hermes-agent/venv/bin/python \
      HERMES_TEST_FILE_RETRIES=0 \
      scripts/run_tests.sh \
        tests/tools/test_cronjob_run_immediate.py \
        tests/tools/test_cronjob_tools.py \
        tests/cron/test_run_one_job.py \
        tests/cron/test_ticker_stall_60703.py \
        tests/cron/test_scheduler_provider.py -q

    Result: 155 passed, 0 failed.

  2. Run static checks:

    python -m ruff check tools/cronjob_tools.py tests/tools/test_cronjob_run_immediate.py
    python -m py_compile tools/cronjob_tools.py tests/tools/test_cronjob_run_immediate.py
    git diff --check origin/main...HEAD

    Result: all passed.

  3. Causal regressions were also verified during development:

    • the original live-context assertion failed on base because manual execution used the one-argument path;
    • the multiplex assertion failed when the primary map was selected;
    • the absent-registry resolver assertion failed when primary Matrix credentials were selected;
    • all pass on this branch.

Full-suite note: scripts/run_tests.sh tests/ -q was attempted locally but exceeded the 600-second execution cap at 29% of roughly 43,000 collected tests. Thirteen path-completion failures observed before timeout reproduce on untouched origin/main in this agent worktree environment. One unrelated routing assertion sees the configured Matrix home because this worktree sits beneath the live HERMES_HOME; it is outside the changed paths. I therefore leave the full-suite checklist item unchecked and rely on CI for the clean-environment full run.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs; this preserves and extends fix(cron): deliver manual runs on gateway loop #63586 rather than discarding its contributor credit
  • My PR contains only changes related to this fix
  • I've run pytest tests/ -q and all tests pass — see the bounded full-suite note above
  • I've added tests for my changes
  • I've tested on Linux (7.0.14-4-pve, Python 3.11)

Documentation & Housekeeping

  • Relevant documentation update — N/A; no user-facing behavior or configuration changes
  • cli-config.yaml.example update — N/A; no config keys changed
  • CONTRIBUTING.md or AGENTS.md update — N/A; no workflow or architectural contract changed
  • Cross-platform impact considered; implementation uses pathlib, existing runtime APIs, and no platform-specific branches
  • Tool descriptions/schemas update — N/A; tool schema is unchanged

Screenshots / Logs

Not applicable. The failure and fix are covered by causal unit/integration regressions and real delivery-resolver identity checks.

Fly-onlyone and others added 2 commits July 25, 2026 01:45
Resolve the context-scoped Hermes profile independently of runner metadata, require its exact adapter registry entry, and fail closed rather than borrowing primary credentials. Also preserve exact standalone call behavior and reject stale gateway loops.
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/cron Cron scheduler and job management platform/matrix Matrix adapter (E2EE) area/profiles Multi-profile isolation, HERMES_HOME scoping sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jul 25, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for preserving the existing scheduler delivery path while adding the missing manual-run context.

Current main still calls run_one_job(job) without gateway context at tools/cronjob_tools.py:605. The scheduler already uses safe_schedule_threadsafe(..., loop) for live adapter delivery at cron/scheduler.py:1801-1808, so the PR targets the verified missing handoff rather than adding a second delivery mechanism. Its secondary-profile selection also matches the runtime scope contract in gateway/run.py:1777-1809 and the separate _profile_adapters ownership described at gateway/run.py:5528-5536.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 30, 2026
@GottZ GottZ mentioned this pull request Aug 3, 2026
1 task
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown

This was generated by AI during triage.

Summary

29 PRs address or reference this cron issue complex across stalled inference, manual execution, schema validation, prompt propagation, status reporting, standalone scheduling, Matrix delivery, and Desktop Git discovery. The diffs show distinct root causes rather than one universal fix; #71132 is the strongest current Matrix-delivery continuation, while #61503 is the only PR addressing the separate UGit resolver failure.

Related pull requests

Duplicates

#32448/#32804/#34173/#34483/#37859 are the same cron schema-description change, with #32804 as the merged reference. #34255/#53246 are the same rejected alias-normalization approach; #41130/#50025/#41269 are the manual-run execution cluster, with #50025 as the merged reference; #41167/#41363/#43864 are the standalone-daemon cluster; #57342/#57360 are duplicates, with #57342 canonical; #61503/#63586/#71132 are competing Matrix caller-side fixes, with #71132 superseding #63586; #61502 is a distinct callee-side Matrix approach.

Suggested consolidation

Keep open #71132 with a salvage path as the canonical current fix for #61495: retain its profile-owned adapter/loop selection and verify under repeated manual runs that Matrix send() executes as a task on the adapter's owning loop. Close #63586 as superseded by #71132, close #57360 as duplicate of #57342, and retain #43864, #52720, #53395, #57689, and #61502 only with their explicit salvage paths; close the remaining closed/redundant PRs against their recorded references. For the separate Desktop issue, retain #61503 as the closed UGit reference implementation, while its bundled Matrix portion is superseded by #71132.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I61495(["issue #61495 (open)"])
    subgraph Dup61503 ["PRs duplicating each other"]
        P61503["PR #61503 (closed)"]
        P63586["PR #63586 (open)"]
        P71132["PR #71132 (open)"]
    end
    P71132 -->|best fix| I61495
    class I61495 open
    class P61503 closed
    class P63586 open
    class P71132 open
    class P61503 best
    class P63586 best
    class P71132 best
    class P71132 target
    click I61495 "https://github.com/NousResearch/hermes-agent/issues/61495"
    click P61503 "https://github.com/NousResearch/hermes-agent/pull/61503"
    click P63586 "https://github.com/NousResearch/hermes-agent/pull/63586"
    click P71132 "https://github.com/NousResearch/hermes-agent/pull/71132"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 29 pull requests and 11 issues in this complex. Each diff was read against this issue; Assessment working set: 287 kB of PR diffs, 82 kB of issue/PR text, 63 kB of discussion (79 comments), 51 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/profiles Multi-profile isolation, HERMES_HOME scoping comp/cron Cron scheduler and job management P3 Low — cosmetic, nice to have platform/matrix Matrix adapter (E2EE) sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Matrix manual cron delivery fails with "Timeout context manager should be used inside a task"

6 participants