Skip to content

feat(refiner): per-role model and reasoning for refiner calls - #85

Merged
wilke merged 1 commit into
chian:mainfrom
wilke:feat/refiner-per-role-routes
Oct 9, 2026
Merged

wilke merged 1 commit into
chian:mainfrom
wilke:feat/refiner-per-role-routes

Conversation

@wilke

@wilke wilke commented Oct 9, 2026

Copy link
Copy Markdown
Collaborator

Why

Every refiner call used the owning Duet's single route. On mango (vLLM Qwen3.8-27B) the best reasoning level (xhigh) can only be reached by omitting reasoning_effort. vLLM accepts only low/medium on the wire. Measured on one hard prompt: low 6.4k tokens in 140 s; medium and default (xhigh) hit the 12k cap in about 280 s. Deep reasoning pays off for one Designer or emitter call, but it is too costly on every step of a coding loop. Operators also want to send coding work to a different model, such as Qwen3-Coder-Next.

What

openchia.refiner_roles in the Hermes config:

openchia:
  refiner_roles:
    designer:    {reasoning: default}   # omit reasoning_effort -> server default
    emitter:     {reasoning: default}   # module transcription (#81)
    coder:       {custom_provider: Mango Coder}   # Implementer coding session
    implementer: {reasoning: low}
  • Fields: custom_provider (a name from custom_providers), model, and reasoning, which takes default, none, or a level.
  • Role keys:
    • Episode local IDs; designer also covers launch.
    • Two call kinds: emitter (set by a role_scope context var in emit_modules) and coder (via DuetEpisodeBinding.for_role).
  • Lookup order: scoped call kind, then the Episode local ID, then the Duet route.
  • Overrides are resolved and validated once, when the binding is frozen at /build. They are stored in the binding record without secrets, so /build continue keeps them, and the recovery policy is recomputed for each route. Keys are read at call time from the provider's key_env.
  • Each attempt receipt now records refiner_role.
  • /code (agent/workflow_coding.py) is unchanged.

Tests

  • New tests/agent/test_refiner_role_routes.py (11 tests) covers:
    • route resolution;
    • rejection of invalid overrides;
    • lookup order;
    • key sourcing;
    • the coder view from for_role;
    • transport dispatch with refiner_role in the receipts;
    • default reasoning leaving reasoning_effort out of the request.
  • On the related suites, this branch shows the same failures and errors as origin/main (6 failed, 30 errors in tests/iterative_episode_refiner/*). The errors all come from the assignment-v1 contract fixtures and are not caused by this change. Ruff is clean.

🤖 Generated with Claude Code

openchia.refiner_roles in the Hermes config overrides, per refiner role,
the custom provider, the model and the reasoning of calls that otherwise
use the owning Duet's route. Roles are Episode local IDs (designer also
covers launch) plus the call kinds emitter (module transcription) and
coder (the Implementer's coding session).

reasoning: default omits reasoning_effort so the server default applies
(on vLLM Qwen3.8 that is xhigh, which is not accepted on the wire);
none disables reasoning; a level enables it.

Overrides are resolved and validated when the Duet binding is frozen,
stored secret-free in the binding record (so /build continue keeps them),
and each attempt receipt records refiner_role. Credentials come from the
provider's key_env at call time.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wilke
wilke merged commit 2efebfd into chian:main Oct 9, 2026
33 of 52 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant