feat(cron): user-owned model pins + cron.model fleet default - #73532
Merged
Conversation
Per-job cron inference pins are now user-owned: the agent-facing cronjob tool schema no longer exposes model/provider/base_url, and the registered handler ignores them even if a model hallucinates the old parameters. Users set pins via the dashboard, hermes cron create/edit --model/--provider, or jobs.json directly — and once set, a pin sticks until the user changes it. Existing agent-era pins are grandfathered untouched. New cron.model / cron.model_provider config keys give the cron fleet its own default model, independent of the chat model. Fire-time resolution: per-job pin > cron.model > HERMES_MODEL > model.default. An axis covered by the explicit cron-fleet default is deliberate routing, not drift, so the #44585 fail-closed guard skips it — switching your chat model with /model or hermes model no longer breaks unpinned cron fleets. - tools/cronjob_tools.py: drop model param from agent schema + handler; remove now-dead _resolve_model_override - cron/scheduler.py: cron.model/model_provider resolution + per-axis drift-guard skip - cron/jobs.py: snapshot resolution mirrors the new precedence - hermes_cli/subcommands/cron.py + hermes_cli/cron.py: --model/--provider on hermes cron create/edit - hermes_cli/config.py: cron.model / cron.model_provider defaults - docs: cron.md model-resolution tip rewritten
Contributor
૮ >ﻌ< ა ci reviewran on 0fa395a ℹ️ InfoDesktop E2E visual evidence · View test artifacts · View job1 visual diff. inline evidence upload failed. Failed to upload diff-665a0833239e-onboarding-overlay-diff.png with gh image (exit code 1): Error uploading /home/runner/work/_temp/e2e-evidence/diff-665a0833239e-onboarding-overlay-diff.png: step 0 (get upload token): uploadToken not found on repo page — do you have write access to NousResearch/hermes-agent? (or, if NousResearch enforces SAML SSO, authorize at https://github.com/orgs/NousResearch/sso) |
This was referenced Jul 28, 2026
Open
1 task
This was referenced Jul 30, 2026
13 tasks
13 tasks
1 task
18 tasks
This was referenced Aug 18, 2026
jackulau
added a commit
to jackulau/hermes-agent
that referenced
this pull request
Aug 19, 2026
The NousResearch#44585 drift guard fails an unpinned cron job closed when the global provider/model moves under it, and every message it emits offers exactly one remedy: pin this job. That is correct for one job and wrong for a fleet. NousResearch#59031 was 34 jobs breaking on a single global switch, i.e. 34 per-job edits for one config change, and NousResearch#89242 is the same complaint arriving again with a proposed fix that would disarm the guard entirely. The fleet-wide remedy already exists. NousResearch#73532 added `cron.model` / `cron.model_provider`, and `_cron_fleet_default_covers_axis` makes the guard skip any axis they cover, so one command decouples the whole unpinned fleet from the chat model without giving up spend protection on the axes it does not cover. The cron guide has documented this since NousResearch#73532; none of the runtime messages did, so the only operators who find it are the ones who read docs after being told to make N edits. Teach all three surfaces to name it alongside the pin: - the scheduler's skip log and alert blob, on both the recurring and the NousResearch#72056 finite-one-shot path, naming `cron.model_provider` for the provider axis rather than interpolating the axis name into a key that does not exist - the chat delivery line, which is the surface an operator reads unprompted rather than after something sent them to a log; kept to one terse sentence so the notification stays one line - the `hermes config set model.default` warning, which fires before any job has failed and is therefore the cheapest place to have omitted it No behaviour change: the guard engages in exactly the cases it engaged in before, and the per-job and one-shot remedies are unchanged. The warning is still suppressed for an axis the fleet default already covers, so an operator who has taken the advice is never given it. Tests parse the config key back out of each emitted message and feed it to `_cron_fleet_default_covers_axis`, so the advice cannot go stale against the mechanism the way it just did. Fixes NousResearch#89242
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Cron per-job model pins are now user-owned, and a new
cron.modelconfig key gives the cron fleet its own default model — switching your chat model with/modelorhermes modelnever touches unattended cron spend again.Root cause of the pain (#59031, fastfinge's "hundreds of jobs break on every model switch"): unpinned jobs followed the global chat model, so the #44585 fail-closed drift guard tripped fleet-wide on every deliberate switch, with no way to route cron independently.
Changes
tools/cronjob_tools.py— the agent-facingcronjobtool schema no longer exposesmodel/provider/base_url, and the registered handler ignores them even if a model hallucinates the old parameters. Per-job inference pins are user-owned: dashboard,hermes cron create/edit --model/--provider, or jobs.json. Existing pins are grandfathered untouched; the programmaticcronjob()function keeps its parameters for the dashboard/CLI callers. Removes the now-dead_resolve_model_override.hermes_cli/config.py— newcron.model/cron.model_providerkeys (cron-fleet inference default, distinct from thecron.providerscheduler axis). The switch-time drift warning (Warn before model config changes trip cron drift guard #59177) stays quiet for an axis covered by the fleet default.cron/scheduler.py— fire-time resolution: per-job pin →cron.model→HERMES_MODEL→model.default; provider: per-job pin →cron.model_provider→ global resolution. Drift guard skips any axis covered by the explicit fleet default — deliberate routing is not drift. Uncovered axes still fail closed.cron/jobs.py— snapshot resolution mirrors the new precedence so create-time snapshots stay consistent.hermes_cli/subcommands/cron.py+hermes_cli/cron.py—--model/--provideronhermes cron createandhermes cron edit(empty string clears a pin on edit).website/docs/user-guide/features/cron.md— model-resolution tip rewritten around the three-tier order.Validation
tests/cron/+ cronjob tool + config tests (targeted, CI-parity runner)cron.modelsnapshot honoredInfographic