hermes - ✅(Solved) Fix [Bug]: curator.auxiliary config is dead — curator always runs on main model [3 pull requests, 1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#17572Fetched 2026-04-30 06:46:44
View on GitHub
Comments
1
Participants
1
Timeline
8
Reactions
0
Participants
Timeline (top)
labeled ×4cross-referenced ×3commented ×1

curator.auxiliary.{provider,model} is exposed in the default config (hermes_cli/config.py) but never read by the curator. The forked review agent always inherits the user's main provider+model from cfg["model"]. Setting curator.auxiliary has no effect — runs that the docstring describes as "auxiliary-model" actually consume the main model.

Root Cause

agent/curator.py::_run_llm_review (lines ~755–785) resolves model+provider exclusively from cfg["model"]:

_cfg = load_config()
_m = _cfg.get("model", {}) if isinstance(_cfg.get("model"), dict) else {}
_provider = _m.get("provider") or "auto"
_model_name = _m.get("default") or _m.get("model") or ""
_rp = resolve_runtime_provider(requested=_provider, target_model=_model_name)
...
review_agent = AIAgent(model=_model_name, provider=_resolved_provider, ...)

There is no read of _cfg.get("curator", {}).get("auxiliary", {}) anywhere in the function or in the file (rg "curator.*auxiliary|auxiliary.*provider" agent/curator.py returns zero matches besides the module docstring).

This is a regression introduced by fa9383d27 ("feat(curator): umbrella-first prompt, inherit parent config, unbounded iterations"), whose commit message describes the new parent-inheritance behavior as a fix for an OpenRouter empty-credentials path. The fix likely should have fallen back to parent inheritance when curator.auxiliary is unset, instead of replacing it.

Fix Action

Fixed

PR fix notes

PR #17584: Fix curator LLM review to honor curator-specific auxiliary model config

Description (problem / solution / changelog)

What does this PR do?

This PR fixes the curator background review fork so it honors curator-specific auxiliary model settings in curator.auxiliary.

Before this change, curator review always resolved its fork runtime from the main model.* config, so it ignored curator.auxiliary.provider and curator.auxiliary.model even when users had explicitly configured a dedicated auxiliary backend.

The fix updates runtime resolution in agent/curator.py to prefer curator overrides when present and fall back to model.* only when curator-specific values are not set.

I also added regression tests in tests/agent/test_curator.py to cover both:

  • curator auxiliary override is used,
  • and fallback to main model config when curator auxiliary config is missing.

Related Issue

Fixes #17572

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

  • agent/curator.py: In _run_llm_review(), read curator.auxiliary and prefer curator.auxiliary.provider and curator.auxiliary.model when resolving runtime. Falls back to model.provider / model.default when curator-specific overrides are absent.
  • tests/agent/test_curator.py: Added regression tests:
    • test_run_llm_review_uses_curator_auxiliary_config
    • test_run_llm_review_uses_main_config_when_curator_auxiliary_missing

How to Test

  1. Configure main model and curator auxiliary settings to different values in ~/.hermes/config.yaml (or through CLI config tooling):
    • model.provider/model.default for primary model
    • curator.auxiliary.provider/curator.auxiliary.model for curator overrides
  2. Run:
    • scripts/run_tests.sh tests/agent/test_curator.py -k "run_llm_review_uses_curator_auxiliary"
    • scripts/run_tests.sh tests/agent/test_curator.py -k "run_llm_review_uses_main_config"
  3. Confirm tests pass and verify curator metadata in the run summary now reflects curator-specific model/provider when configured.

Checklist

Code

  • I’ve read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature
  • I’ve run pytest tests/ -q and all tests pass
  • I’ve added tests for my changes
  • I’ve tested on my platform: <!-- e.g. Ubuntu 24.04, macOS 15.2, Windows 11 -->

Documentation & Housekeeping

  • I’ve updated relevant documentation (README, docs/, docstrings) — or N/A
  • I’ve updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I’ve updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I’ve considered cross-platform impact (Windows, macOS, Linux) — or N/A
  • I’ve updated tool descriptions/schemas if I changed tool behavior — or N/A

Changed files

  • agent/curator.py (modified, +12/-0)
  • tests/agent/test_curator.py (modified, +104/-0)

PR #17591: fix(curator): read curator.auxiliary config for reviewer model

Description (problem / solution / changelog)

Problem

curator.auxiliary.{provider,model} is exposed in the default config (hermes_cli/config.py) but _run_llm_review() only reads cfg["model"], ignoring the curator-specific override. The curator always runs on the main model regardless of what is configured.

Fix

Read curator.auxiliary first; fall back to model config.

Precedence:

  1. curator.auxiliary.{provider,model} (explicit curator override)
  2. model.{provider,default} (main model config)

Related

Fixes #17572

Changes

  • agent/curator.py: +11/-8 lines in _run_llm_review()

Changed files

  • agent/curator.py (modified, +11/-8)

PR #17781: fix(curator): honor curator.auxiliary.{provider,model} override (#17572)

Description (problem / solution / changelog)

Summary

Fixes #17572. The curator's _run_llm_review() resolved provider and model exclusively from cfg["model"], silently ignoring the curator.auxiliary.{provider, model} schema documented in hermes_cli/config.py:950-955. As a result the curator always ran on the user's main model — for Opus users this means weekly runs on the most expensive model when the whole point of an auxiliary slot is to pin a cheaper one.

The bug

agent/curator.py:761-763 (before this patch):

_m = _cfg.get("model", {}) if isinstance(_cfg.get("model"), dict) else {}
_provider = _m.get("provider") or "auto"
_model_name = _m.get("default") or _m.get("model") or ""

No reference to cfg["curator"]["auxiliary"] anywhere in the resolution path, even though the default config block reserves it:

# Optional per-task override for the curator's aux model. Leave null
# to use Hermes' main auxiliary client resolution.
auxiliary:
  provider: null
  model: null

Fix

Read curator.auxiliary first and fall back to the main model fields when either side is null. Provider and model can be overridden independently (provider-only override keeps the main model, and vice versa).

Tests

Three new cases in tests/agent/test_curator.py:

  • auxiliary unset → main model (current behavior preserved)
  • both fields set → aux wins
  • partial override (provider only) → main model retained

pytest tests/agent/test_curator.py → 34 passed.

Notes

  • Behavior when both aux fields are null is byte-identical to today.
  • resolve_runtime_provider() is still called with the resolved provider+model, so credential pool / OAuth / pool-backed flows continue to work for the aux model.
  • No config schema change — the auxiliary block has been in DEFAULT_CONFIG for a while; this just wires it up.

Changed files

  • agent/curator.py (modified, +14/-0)
  • tests/agent/test_curator.py (modified, +106/-0)

Code Example

model:
     default: claude-opus-4-7
     provider: anthropic
   curator:
     auxiliary:
       provider: anthropic
       model: claude-sonnet-4-5

---

_cfg = load_config()
_m = _cfg.get("model", {}) if isinstance(_cfg.get("model"), dict) else {}
_provider = _m.get("provider") or "auto"
_model_name = _m.get("default") or _m.get("model") or ""
_rp = resolve_runtime_provider(requested=_provider, target_model=_model_name)
...
review_agent = AIAgent(model=_model_name, provider=_resolved_provider, ...)

---

_cur_aux = (_cfg.get("curator") or {}).get("auxiliary") or {}
_provider = _cur_aux.get("provider") or _m.get("provider") or "auto"
_model_name = _cur_aux.get("model") or _m.get("default") or _m.get("model") or ""
RAW_BUFFERClick to expand / collapse

Summary

curator.auxiliary.{provider,model} is exposed in the default config (hermes_cli/config.py) but never read by the curator. The forked review agent always inherits the user's main provider+model from cfg["model"]. Setting curator.auxiliary has no effect — runs that the docstring describes as "auxiliary-model" actually consume the main model.

Repro

  1. Set in ~/.hermes/config.yaml:
    model:
      default: claude-opus-4-7
      provider: anthropic
    curator:
      auxiliary:
        provider: anthropic
        model: claude-sonnet-4-5
  2. hermes curator run --sync
  3. Inspect the resulting session JSON under ~/.hermes/sessions/. The forked curator session's model field is claude-opus-4-7, not claude-sonnet-4-5.

Root cause

agent/curator.py::_run_llm_review (lines ~755–785) resolves model+provider exclusively from cfg["model"]:

_cfg = load_config()
_m = _cfg.get("model", {}) if isinstance(_cfg.get("model"), dict) else {}
_provider = _m.get("provider") or "auto"
_model_name = _m.get("default") or _m.get("model") or ""
_rp = resolve_runtime_provider(requested=_provider, target_model=_model_name)
...
review_agent = AIAgent(model=_model_name, provider=_resolved_provider, ...)

There is no read of _cfg.get("curator", {}).get("auxiliary", {}) anywhere in the function or in the file (rg "curator.*auxiliary|auxiliary.*provider" agent/curator.py returns zero matches besides the module docstring).

This is a regression introduced by fa9383d27 ("feat(curator): umbrella-first prompt, inherit parent config, unbounded iterations"), whose commit message describes the new parent-inheritance behavior as a fix for an OpenRouter empty-credentials path. The fix likely should have fallen back to parent inheritance when curator.auxiliary is unset, instead of replacing it.

Impact

  • Curator always runs on the user's main (often most expensive) model. No way to opt into a cheaper aux model for cost control.
  • The curator.auxiliary config block is dead code — silently misleads users who configure it.
  • The docstring at agent/curator.py:3 still claims "an auxiliary-model task" — out of date.

Suggested fix

In _run_llm_review, prefer cfg["curator"]["auxiliary"] when set, fall back to cfg["model"] otherwise:

_cur_aux = (_cfg.get("curator") or {}).get("auxiliary") or {}
_provider = _cur_aux.get("provider") or _m.get("provider") or "auto"
_model_name = _cur_aux.get("model") or _m.get("default") or _m.get("model") or ""

Then call resolve_runtime_provider with those values. This preserves the fa9383d27 fix (no more empty-credential path) while honoring the documented config field.

Environment

  • hermes-agent commit: b2820cd20 (current main as of 2026-04-29)
  • OS: Ubuntu 24.04
  • Python: 3.11
  • Provider: anthropic (Claude Pro/Max OAuth)

Related

  • #16077 (Curator RFC) — original curator review thread
  • fa9383d27 — the commit that introduced the regression
  • bc79e227e — original curator feature

extent analysis

TL;DR

The issue can be fixed by modifying the _run_llm_review function in agent/curator.py to prefer cfg["curator"]["auxiliary"] when set, and fall back to cfg["model"] otherwise.

Guidance

  • Verify that the curator.auxiliary config block is correctly set in the ~/.hermes/config.yaml file.
  • Update the _run_llm_review function to use the suggested fix, which checks for the presence of cfg["curator"]["auxiliary"] and uses its values if available.
  • Test the updated function by running hermes curator run --sync and inspecting the resulting session JSON to ensure that the correct model is being used.
  • Review the commit history to understand the introduction of the regression and ensure that the fix does not reintroduce any previous issues.

Example

_cur_aux = (_cfg.get("curator") or {}).get("auxiliary") or {}
_provider = _cur_aux.get("provider") or _m.get("provider") or "auto"
_model_name = _cur_aux.get("model") or _m.get("default") or _m.get("model") or ""

Notes

The suggested fix assumes that the cfg["curator"]["auxiliary"] block is correctly configured and that the resolve_runtime_provider function is working as expected. Additional testing may be necessary to ensure that the fix does not introduce any new issues.

Recommendation

Apply the suggested workaround by updating the _run_llm_review function to prefer cfg["curator"]["auxiliary"] when set, and fall back to cfg["model"] otherwise. This fix preserves the original functionality while honoring the documented config field.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix [Bug]: curator.auxiliary config is dead — curator always runs on main model [3 pull requests, 1 comments, 1 participants]