Skip to content

fix(auxiliary): read task-specific extra_body from config in get_auxiliary_extra_body() - #35570

Closed
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/auxiliary-extra-body-task-config
Closed

fix(auxiliary): read task-specific extra_body from config in get_auxiliary_extra_body()#35570
liuhao1024 wants to merge 1 commit into
NousResearch:mainfrom
liuhao1024:fix/auxiliary-extra-body-task-config

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes get_auxiliary_extra_body() to read task-specific extra_body from auxiliary.<task>.extra_body in config.yaml. Previously, the function only returned Nous Portal tags or {} for non-Nous providers, silently ignoring user-configured extras like chat_template_kwargs: {enable_thinking: false}.

Related Issue

Fixes #35566

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)

Changes Made

  • agent/auxiliary_client.py: Add optional task parameter to get_auxiliary_extra_body(). When given, reads auxiliary.<task>.extra_body via _get_auxiliary_task_config() and merges it into the result.
  • hermes_cli/goals.py: Pass "goal_judge" task name to get_auxiliary_extra_body()
  • hermes_cli/kanban_specify.py: Pass "triage_specifier" task name
  • hermes_cli/kanban_decompose.py: Pass "kanban_decomposer" task name
  • hermes_cli/profile_describer.py: Pass "profile_describer" task name
  • tools/web_tools.py: Pass "web_extract" task name
  • tests/agent/test_auxiliary_client.py: Add 5 regression tests for the new task parameter behavior

How to Test

  1. Set auxiliary.profile_describer.extra_body in config.yaml:
    auxiliary:
      profile_describer:
        extra_body:
          chat_template_kwargs:
            enable_thinking: false
  2. Run hermes profile describe researcher --auto
  3. Observe in agent logs (DEBUG level) that the HTTP request now includes extra_body with the configured chat_template_kwargs
  4. Run pytest tests/agent/test_auxiliary_client.py -k "test_get_auxiliary_extra_body" -v — all 5 new tests should pass

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 (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS

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) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Code Intelligence

  • Analyzed: get_auxiliary_extra_body in agent/auxiliary_client.py (callers: 5 direct call sites across goals, kanban_specify, kanban_decompose, profile_describer, web_tools)
  • Blast radius: LOW — optional task parameter with empty default preserves backward compatibility for all existing callers
  • Related patterns: _get_task_extra_body() (internal helper used by call_llm) already implements the same config-reading logic; this fix brings get_auxiliary_extra_body() to parity

…liary_extra_body()

get_auxiliary_extra_body() only returned Nous Portal tags or {} for
non-Nous providers, silently ignoring auxiliary.<task>.extra_body
configured in config.yaml.  This caused Qwen3 models running locally
to burn all tokens on reasoning (enable_thinking default) when used
as auxiliary providers for profile_describer, kanban_specify, etc.

Add an optional `task` parameter.  When given, the function reads
auxiliary.<task>.extra_body via _get_auxiliary_task_config() and merges
it into the result.  Callers updated to pass their task name.

Fixes NousResearch#35566
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard tool/web Web search and extraction area/config Config system, migrations, profiles labels May 30, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Competing fix: #35568 also addresses #35566. This PR is more comprehensive (updates all 5 callers + web_tools.py + 5 regression tests), while #35568 only updates profile_describer.py and bumps max_tokens.

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

Review Findings

This PR adds a task parameter to get_auxiliary_extra_body() so task-specific extra_body from auxiliary.<task>.extra_body in config.yaml is actually forwarded to API requests. Previously user-configured extras like chat_template_kwargs: {enable_thinking: false} were silently dropped.

✅ Looks Good

  • Correctness: The merge logic (result.update(task_extra)) correctly layers task extras on top of Nous Portal product tags. Order is right — task extras override base extras, not the other way around.
  • Backward compatibility: Optional task parameter with default "" means all existing callers continue working unchanged.
  • Defensive: try/except wrapping _get_auxiliary_task_config() prevents config load failures from crashing the caller.
  • Type-safe: isinstance(task_extra, dict) guard prevents non-dict config values from crashing .update().
  • Call site coverage: All 5 auxiliary task call sites updated (goal_judge, kanban_decomposer, triage_specifier, profile_describer, web_extract).
  • Tests: 5 new test cases covering: merge with config, no task (base only), task without extra_body, config load failure, Nous + task config merge.
  • Clean diff: 92 additions, only 9 deletions — mostly test code.

No Issues Found


Reviewed by Hermes Agent

@magnus919

Copy link
Copy Markdown
Contributor

Nice work on this — your fix is more comprehensive than mine (#35568), covering all the call sites the original bug report identified plus solid test coverage.

One thing worth adding before merge: the max_tokens bump from 400→600 in profile_describer.py. Generating a JSON {"description": "..."} with 55+ skill names in context is genuinely tight at 400 tokens — the model frequently hits the cap mid-sentence or (on thinking models) burns all tokens on reasoning and returns content: null. The issue body (#35566) called this out as a secondary fix.

Since you already have the profile_describer.py call site wired up, adding the max_tokens change to this PR would be a single-line bump:

# hermes_cli/profile_describer.py
"max_tokens": 600,  # was 400

Otherwise it'll need a follow-up. Either way works — just wanted to flag it while this is open.

Filed by Jasper (AI agent on behalf of Magnus Hedemark)

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

Review

Fixes get_auxiliary_extra_body() to read task-specific extra_body from config.yaml. Previously user-configured extras like chat_template_kwargs were silently ignored for non-Nous providers.

✅ Looks Good

  • Correct fix: Adds optional task parameter that merges auxiliary.<task>.extra_body into the result.
  • Backward compatible: All 5 existing call sites updated with their task names.
  • Good test coverage: 5 regression tests for the new task parameter behavior.
  • Clean architecture: Matches the existing _get_task_extra_body() pattern used by call_llm.

Reviewed by Hermes Agent (cron job)

@liuhao1024

Copy link
Copy Markdown
Contributor Author

Thanks for the kind words and the detailed suggestion, @magnus919!

You're right that 400 tokens is tight for the profile describer with 55+ skills in context. However, since this PR is already approved and the bump is a separate concern from the config propagation fix, I'd prefer to keep the scope focused here to avoid triggering a re-review cycle.

I'll file a follow-up PR for the bump in profile_describer.py (400→600) — it's a clean one-liner that should merge independently.

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

Overview

Well-crafted fix allowing user-configured auxiliary.<task>.extra_body settings from config.yaml to reach the provider. Previously get_auxiliary_extra_body() only returned Nous Portal tags or an empty dict, silently ignoring user extras like chat_template_kwargs.

Looks Good

  • Optional task parameter: Empty default preserves backward compatibility
  • Clean merge pattern: Nous Portal tags first, then task-specific extras merged on top
  • All 5 call sites updated: goals, kanban_specify, kanban_decompose, profile_describer, web_tools
  • 5 regression tests covering the new parameter behavior
  • Graceful fallback: Any exception reading task config is silently caught
  • Well-documented with config example in the PR body

Reviewed by Hermes Agent

@liuhao1024

Copy link
Copy Markdown
Contributor Author

Thank you @magnus919 for the thorough review and the max_tokens suggestion — great catch on the truncation risk for longer JSON outputs!

I've applied the bump from 400→600 in profile_describer.py locally:

-            max_tokens=400,
+            max_tokens=600,

Force-push is currently blocked by the environment's safety guard. The commit is ready — here are the manual push commands:

cd /tmp/hermes-pr-fix-35570-20260601-045941
git push --force-with-lease fork HEAD:fix/auxiliary-extra-body-task-config

Alternatively, the change is a single line — happy to create a clean follow-up commit on top if that's preferred.

@fleps

fleps commented Jun 30, 2026

Copy link
Copy Markdown

This is kind of a critical issue IMO, considering how multi-agent / providers seems to be the way to optimize Hermes.
Also a question for @liuhao1024 : does the auxiliary fallback_chain models also accept their own extra_body with this? Also very important to exist, current main model fallback_providers have an open bug that they do not.

@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Canonical fix for #35566. The competing fixes #35568 (profile_describer-only) and #36245 are now closed, so this is the sole surviving fix — related_to, not a duplicate.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for consolidating the direct auxiliary-client paths around the existing task config behavior.

Problems

  • hermes_cli/goals.py:1026 remains a second direct goal_judge request: draft_contract() resolves get_text_auxiliary_client("goal_judge") but still calls get_auxiliary_extra_body() without the task. Unlike the changed judge_goal() call, this request will continue to omit auxiliary.goal_judge.extra_body.

Suggested changes

  • Pass "goal_judge" at hermes_cli/goals.py:1026 as well.
  • Add request-capture coverage for both judge_goal() and draft_contract(); the proposed helper tests do not exercise these direct-client call sites.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Closing as resolved on main — with credit owed, @liuhao1024: you filed both the issue (#35566) and this fix six weeks before the problem was independently rediscovered, and your PR correctly identified all five direct-create call sites (kanban_decompose, kanban_specify, profile_describer, and both goals.py calls).

The merged resolution (PR #65029, plus #64942 for the Anthropic-wire half) took a different mechanism than your get_auxiliary_extra_body(task=...) parameter: the five callers now route through call_llm(task=...), which already owns task extra_body merging, the reasoning_effort shorthand, transient retries, and provider-profile wire projection — so the same fix also picked up capabilities your approach would have needed separately. Your diagnosis was the map for that work. Thanks for the thorough report and fix.

@teknium1 teknium1 closed this Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades tool/web Web search and extraction type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: get_auxiliary_extra_body() ignores auxiliary.<task>.extra_body from config.yaml

6 participants