Skip to content

feat(delegation): require a helper tier when tiers are configured (RIG-8770) - #49

Merged
mattwilkinsonn merged 3 commits into
rigel-releasefrom
hermes-sync/rig-8770-require-a-helper-tier-when-tiers-are
Nov 10, 2026
Merged

mattwilkinsonn merged 3 commits into
rigel-releasefrom
hermes-sync/rig-8770-require-a-helper-tier-when-tiers-are

Conversation

@rigel-mintaka

@rigel-mintaka rigel-mintaka commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

What does this PR do?

Adds optional per-call helper tiers to delegate_task. With delegation.tiers configured, the model must name easy, medium, or hard on every spawn, and each tier routes the child to its own model. A spawn without a known tier is refused and no child starts. Without delegation.tiers, behaviour is unchanged.

This is the fork half of Nemo's model-roles design: Hermes names a helper tier on every delegation, with no default tier.

Related Issue

RIG-8770 (Linear).

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

Changes Made

  • tools/delegate_tool.py
    • New tier parameter. The schema requires it only when tiers are configured.
    • _resolve_delegation_tier_routing_config validates the tier.
    • A selected tier is a complete route. It drops the base model, provider, base_url, api_key, api_mode, request_overrides and fallback_providers.
    • A model-only tier keeps the parent runtime provider.
  • Enforcement covers model-facing spawns only. Registry dispatch and run_agent.py pass enforce_tier=True.
    • Control actions (list, steer, cancel) need no tier.
    • Internal callers (/review, the lifecycle API) keep the base route unless they pass a tier.
  • agent/subagent_lifecycle.py: launch(..., tier=) uses the same resolver. With tiers configured, it rejects a tier combined with a per-launch model or provider.
  • Docs: website/docs/user-guide/features/delegation.md, subagent-lifecycle-api.md, and the cli-config.yaml.example tier block.

How to Test

  1. Red first: the new tier tests failed before the change ('error' in {'ok': True}; children got fixture/default).
  2. Run scripts/run_tests.sh tests/tools/test_delegate*.py tests/agent/test_review_engine.py tests/agent/test_subagent_lifecycle.py -j 2 with the API keys empty: 39 files, 342 passed, 0 failed.
  3. Ruff 0.15.10 is clean on the changed files.

Checklist

Code

  • Conventional Commits
  • One concern
  • Tests cover missing or unknown tier, each tier route, batches, control calls, /review exemption, lifecycle, route isolation, and unconfigured tiers

Documentation & Housekeeping

  • User and developer docs updated

For New Skills

N/A.

Screenshots / Logs

N/A.

Refs RIG-8770

Co-authored-by: Matt Wilkinson matt@rigel.build

rigel-mintaka and others added 3 commits November 9, 2026 07:15
…G-8770)

A delegation.tiers map (easy, medium, hard) routes each spawn to its tier's model. With tiers configured, a spawn without a known tier is refused; control actions need none. Without tiers, behaviour is unchanged.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
Internal callers such as /review and the lifecycle API keep the delegation route unless they pass a tier. A selected tier no longer inherits base route keys.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
A tier drops base request_overrides and fallback_providers too. Lifecycle launches reject a tier mixed with a model or provider override.

Co-authored-by: Matt Wilkinson <matt@rigel.build>
@linear-code

linear-code Bot commented Nov 9, 2026

Copy link
Copy Markdown

RIG-8770

@rigel-mintaka

Copy link
Copy Markdown
Collaborator Author

Review rounds

Round 1 (e26afc9): 1 high, 2 medium, 1 low. All fixed in 5917ede.

  • High: /review was refused when tiers were configured and auxiliary.review was unset. Fixed: tiers are enforced on model-facing spawns only (enforce_tier=True).
  • Medium: the lifecycle launch() skipped tiers. Fixed: it takes an optional tier and uses the shared resolver.
  • Medium: the base base_url overrode the tier provider. Fixed: a selected tier drops the base route keys.
  • Low: the nested acp_args assertion was restored.

Round 2 (5917ede): 3 medium, 2 low. All fixed in 8394323.

  • Base request_overrides and fallback_providers leaked into a tier. Fixed: both are dropped.
  • Model-only tier behaviour was undefined. Fixed: it inherits the parent runtime, now documented and tested.
  • Lifecycle mixed request.provider with the tier model. Fixed: a tier plus a model or provider override is rejected.
  • Low: an unconfigured tier is ignored, now documented and tested. Test spacing fixed.

Round 3: all-clear on 8394323. 15 tier tests, 21 review-engine tests and 20 lifecycle tests pass.

@rigel-mintaka
rigel-mintaka marked this pull request as ready for review November 9, 2026 13:23
@mattwilkinsonn
mattwilkinsonn merged commit b8d4599 into rigel-release Nov 10, 2026
1 check 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.

2 participants