Skip to content

feat: Config-Runtime Contract Registry (Phase 1) + fix #28046 + fix #28863#28995

Open
zccyman wants to merge 1 commit into
NousResearch:mainfrom
atyou2happy:feat/config-runtime-contract
Open

feat: Config-Runtime Contract Registry (Phase 1) + fix #28046 + fix #28863#28995
zccyman wants to merge 1 commit into
NousResearch:mainfrom
atyou2happy:feat/config-runtime-contract

Conversation

@zccyman

@zccyman zccyman commented May 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements Phase 1 of the Typed Config-Runtime Contract — a declarative config binding registry that catches orphan config fields at startup, before users discover them silently.

Along the way, fixes two concrete bugs that motivated this work.

Bug Fixes

Fix #28046: max_tokens silently ignored from custom_providers per-model config

Problem: Only context_length was read from custom_providers[].models.<model>. The max_tokens field was silently ignored, always defaulting to 4096.

Fix: Extract get_custom_provider_model_field() as a generic lookup helper, add get_custom_provider_max_tokens() symmetric to context_length, and read it in agent_init.py after the existing context_length lookup.

Fix #28863: terminal.docker_extra_args silently dropped

Problem: docker_extra_args was declared in DEFAULT_CONFIG but missing from the _terminal_env_map bridge in gateway/run.py, so it was never passed to the terminal tool.

Fix: Add the mapping entry.

Feature: Config-Runtime Contract Registry (Phase 1)

New module: hermes_cli/config_contracts.py

  • CONFIG_BINDINGS — declarative registry of 29 config→runtime bindings (all terminal.* env vars, model.max_tokens, model.context_length, custom_providers wildcards)
  • get_nested() — resolves dotted keys with wildcard support, including list-of-dicts (for custom_providers)
  • validate_config_bindings() — cross-checks loaded config against registry, returns warning list
  • get_binding_report() — human-readable status report for debugging

Gateway integration

At startup, after env var bridging, the gateway runs validate_config_bindings() and logs any warnings. This is purely additive — warnings only, no behavior change, wrapped in try/except so it can never block startup.

How this prevents future bugs

When a developer adds a new terminal.* key to DEFAULT_CONFIG, the contract registry immediately shows it as unregistered. The next person who reviews the code sees the gap before shipping.

Test Coverage

Test file Tests Status
test_config_contracts.py 17 All pass
test_custom_provider_max_tokens.py 10 All pass
test_custom_provider_context_length.py 12 All pass (existing, unchanged)
Total 39 All pass

Backward Compatibility

  • get_custom_provider_context_length() signature unchanged
  • get_custom_provider_max_tokens() is a new function (purely additive)
  • config_contracts.py is a new module (purely additive)
  • Gateway validation is wrapped in try/except (cannot break startup)
  • Zero behavior change to any existing code path

Related

Files Changed

File Change
hermes_cli/config_contracts.py New — Contract registry module (235 lines)
tests/hermes_cli/test_config_contracts.py New — 17 tests
tests/hermes_cli/test_custom_provider_max_tokens.py New — 10 tests
agent/agent_init.py +14 — Read max_tokens from custom_providers
hermes_cli/config.py +66/-25 — Generic helper + max_tokens function
gateway/run.py +14 — docker_extra_args mapping + contract validation

…8046 + fix NousResearch#28863

Adds a declarative config binding registry that maps config.yaml keys to
their runtime consumers. On gateway startup, validates all registered
bindings are active — catching orphan config fields before users discover
them silently.

Changes:
- New module: hermes_cli/config_contracts.py
  - ConfigBinding dataclass + CONFIG_BINDINGS registry (29 bindings)
  - get_nested() resolves dotted/wildcard keys including list-of-dicts
  - validate_config_bindings() cross-checks config vs registry at startup
  - get_binding_report() for /info debugging

- Fix NousResearch#28046: Read max_tokens from custom_providers per-model config
  - Extract get_custom_provider_model_field() as generic lookup helper
  - Add get_custom_provider_max_tokens() symmetric to context_length
  - Read custom_providers max_tokens in agent_init.py
  - 10 regression tests

- Fix NousResearch#28863: Add docker_extra_args to _terminal_env_map
  - The key was in DEFAULT_CONFIG but missing from the env var bridge

- Gateway startup: inject contract validation (warnings only, no behavior change)

- Tests: 17 new (10 max_tokens + 17 contracts = 27 unique, 39 total with
  existing context_length tests)

Implements: NousResearch#28984 (Typed Config-Runtime Contract, Phase 1)
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery area/config Config system, migrations, profiles labels May 20, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Note: The two bug fixes bundled here have existing dedicated PRs:

The Config-Runtime Contract Registry feature implements #28984.

@zccyman

zccyman commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @alt-glitch for the review. Acknowledged on the bundled bug fixes.

My reasoning for keeping them together: #28142 and #28891 are still open (not merged), so the fixes aren't yet available to users. The feature work (config_contracts.py) was motivated by these same bugs, so bundling them here provides a complete solution in one PR.

However, I'm happy to split if you prefer. The options are:

  1. Keep as-is: Feature + both fixes in one PR, coherent scope
  2. Strip bug fixes: Remove Bug: max_tokens not read from custom_providers per-model config, always defaults to 4096 #28046/terminal.docker_extra_args from config.yaml silently dropped — missing in _terminal_env_map bridge #28863 fixes, keep only the feature (config_contracts.py), let fix(agent_init): read max_tokens from custom_providers per-model config #28142/fix(gateway): bridge terminal.docker_extra_args and docker_forward_env to env #28891 handle the fixes separately

Which approach do you prefer? If you want a split, let me know and I'll remove the bug fix commits.

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/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

2 participants