From 280c4dce7030ba3f12623d97631f4fcfe884bd35 Mon Sep 17 00:00:00 2001 From: Teknium <127238744+teknium1@users.noreply.github.com> Date: Thu, 23 Jul 2026 12:23:40 -0700 Subject: [PATCH] test(moa): round-trip regression for per-slot reasoning_effort + enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow-up for salvaged PR #59753 rebased over the per-slot reasoning_effort feature: _clean_slot now round-trips reasoning_effort AND enabled together; add a normalize→normalize regression test, update the validate/normalize agreement contract for the canonical enabled default, restore the desktop per-slot toggle test on the current autosave editor, and map oppenheimor's contributor email. --- .../src/app/settings/model-settings.test.tsx | 26 ++++++++++++ contributors/emails/sjq15251852316@gmail.com | 1 + tests/hermes_cli/test_moa_config.py | 40 ++++++++++++++++++- 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 contributors/emails/sjq15251852316@gmail.com diff --git a/apps/desktop/src/app/settings/model-settings.test.tsx b/apps/desktop/src/app/settings/model-settings.test.tsx index 1feb2848b04e..bb9f1f9ec1cf 100644 --- a/apps/desktop/src/app/settings/model-settings.test.tsx +++ b/apps/desktop/src/app/settings/model-settings.test.tsx @@ -456,4 +456,30 @@ describe('ModelSettings MoA preset editor', () => { vi.useRealTimers() } }) + + it('saves a disabled reference model without removing it (per-slot enabled toggle)', async () => { + vi.useFakeTimers({ shouldAdvanceTime: true }) + + try { + await openReferenceEditor() + + fireEvent.click(screen.getByRole('switch', { name: 'Disable reference 1' })) + await vi.advanceTimersByTimeAsync(700) + + expect(saveMoaModels).toHaveBeenCalledWith( + expect.objectContaining({ + presets: expect.objectContaining({ + default: expect.objectContaining({ + reference_models: [ + expect.objectContaining({ provider: 'nous', model: 'hermes-4', enabled: false }), + expect.objectContaining({ provider: 'openrouter', model: 'deepseek/deepseek-v4-pro' }) + ] + }) + }) + }) + ) + } finally { + vi.useRealTimers() + } + }) }) diff --git a/contributors/emails/sjq15251852316@gmail.com b/contributors/emails/sjq15251852316@gmail.com new file mode 100644 index 000000000000..66d56022748e --- /dev/null +++ b/contributors/emails/sjq15251852316@gmail.com @@ -0,0 +1 @@ +oppenheimor diff --git a/tests/hermes_cli/test_moa_config.py b/tests/hermes_cli/test_moa_config.py index 818051ace8fc..aac96c9885fa 100644 --- a/tests/hermes_cli/test_moa_config.py +++ b/tests/hermes_cli/test_moa_config.py @@ -213,6 +213,42 @@ def test_normalize_moa_config_preserves_slot_reasoning_effort(): assert preset["aggregator"]["reasoning_effort"] == "xhigh" +def test_normalize_moa_config_round_trips_reasoning_effort_and_enabled(): + """Regression: a client that GETs the config and PUTs it straight back must + not strip per-slot keys. reasoning_effort AND enabled have to survive a + normalize → normalize round trip together (a save path that re-normalizes + the previously normalized payload is the exact client round-trip shape).""" + cfg = normalize_moa_config( + { + "presets": { + "p": { + "reference_models": [ + {"provider": "openai-codex", "model": "gpt-5.5", "reasoning_effort": "high", "enabled": False}, + {"provider": "openrouter", "model": "deepseek/deepseek-v4-pro", "enabled": True}, + ], + "aggregator": { + "provider": "openrouter", + "model": "anthropic/claude-opus-4.8", + "reasoning_effort": "xhigh", + }, + } + } + } + ) + + round_tripped = normalize_moa_config(cfg) + + refs = round_tripped["presets"]["p"]["reference_models"] + assert refs[0] == { + "provider": "openai-codex", + "model": "gpt-5.5", + "reasoning_effort": "high", + "enabled": False, + } + assert refs[1] == {"provider": "openrouter", "model": "deepseek/deepseek-v4-pro", "enabled": True} + assert round_tripped["presets"]["p"]["aggregator"]["reasoning_effort"] == "xhigh" + + def test_normalize_moa_config_coerces_numeric_strings(): """Valid numeric strings (e.g. from YAML round-trip) must coerce correctly.""" cfg = normalize_moa_config({"max_tokens": "8192", "reference_temperature": "0.9"}) @@ -539,7 +575,9 @@ def test_validate_moa_payload_agrees_with_clean_slot(): assert validate_moa_payload(payload) == [] cfg = normalize_moa_config(payload) - assert cfg["presets"]["p"]["reference_models"] == payload["presets"]["p"]["reference_models"] + # Slots survive with only the canonical enabled=True default added — no + # provider/model swap, no defaults substitution. + assert cfg["presets"]["p"]["reference_models"] == _enabled_refs(payload["presets"]["p"]["reference_models"]) assert cfg["presets"]["p"]["aggregator"] == payload["presets"]["p"]["aggregator"]