Skip to content

fix: load custom models for known providers from config#1161

Closed
ccqqlo wants to merge 1 commit intonesquena:masterfrom
ccqqlo:fix-provider-models-override
Closed

fix: load custom models for known providers from config#1161
ccqqlo wants to merge 1 commit intonesquena:masterfrom
ccqqlo:fix-provider-models-override

Conversation

@ccqqlo
Copy link
Copy Markdown
Contributor

@ccqqlo ccqqlo commented Apr 27, 2026

Description

The WebUI currently ignores custom models defined in config.yaml when using a known provider (e.g., openai).

Problem

In api/config.py, when resolving available models:

  1. It loops over the configured providers but checks if _pid_key in _PROVIDER_MODELS, skipping known providers that have custom configurations.
  2. Even if the config branch is hit, raw_models accesses _PROVIDER_MODELS.get(pid, []) directly by reference. This causes subsequent model updates to modify the global default models dictionary, leading to unexpected behavior and duplication in the WebUI selector.

Solution

  1. Updated the discovery loop to also include providers found in cfg.get('providers', {}).
  2. Wrapped the default model array in copy.deepcopy() when extracting from _PROVIDER_MODELS to prevent mutation of the global dictionary when custom models are appended.

This allows users to configure custom models for standard providers like openai via their config.yaml and correctly see them in the WebUI.

Tested locally and confirmed the UI properly merges standard + custom OpenAI models.

@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Thanks for the fix, @ccqqlo! This is a clean solution to a real config-loading gap.

The two-part fix is well-targeted:

  1. Loop expansion — including cfg.get('providers', {}) providers in the discovery loop means custom provider entries are no longer silently skipped for known providers.
  2. copy.deepcopy() — protecting the _PROVIDER_MODELS global from mutation when custom models are appended is the correct fix; without it, a shared list reference would bleed custom models across processes/requests.

The fix is minimal (2 lines changed) and the description clearly traces the original bug through the code path. Having local test confirmation that standard + custom OpenAI models merge correctly in the UI selector is good to hear.

One thought: if you want to add a regression test for the deep-copy behavior (e.g., verifying that calling get_available_models() twice with a config-defined custom model doesn't duplicate entries), that would help prevent this class of mutation bug from silently re-emerging.

nesquena-hermes added a commit that referenced this pull request Apr 27, 2026
Merged as v0.50.227. 2634 tests passing, browser QA 21/21 (desktop + mobile). Full attribution below.

Thanks to all 12 contributors:
@jundev0001 (#1138), @franksong2702 (#1142, #1157, #1162), @dso2ng (#1143), @bergeouss (#1145, #1146, #1156, #1159), @jasonjcwu (#1149), @ccqqlo (#1161), @frap129 (#1165)

Two fixes applied during integration and two more by the independent reviewer (@nesquena):
- messages.js: per-turn cost delta capture order (#1159)
- workspace.py: symlink target blocked-roots check + HOME sanity guard (#1149, #1165)
- panels.js: cron unread counter bookkeeping (in-loop increment bug)
- tests/test_symlink_cycle_detection.py: register workspace before session/new
@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Merged as v0.50.227 via batch PR #1168. Thank you @ccqqlo! 🎉

JKJameson pushed a commit to JKJameson/hermes-webui that referenced this pull request Apr 29, 2026
Merged as v0.50.227. 2634 tests passing, browser QA 21/21 (desktop + mobile). Full attribution below.

Thanks to all 12 contributors:
@jundev0001 (nesquena#1138), @franksong2702 (nesquena#1142, nesquena#1157, nesquena#1162), @dso2ng (nesquena#1143), @bergeouss (nesquena#1145, nesquena#1146, nesquena#1156, nesquena#1159), @jasonjcwu (nesquena#1149), @ccqqlo (nesquena#1161), @frap129 (nesquena#1165)

Two fixes applied during integration and two more by the independent reviewer (@nesquena):
- messages.js: per-turn cost delta capture order (nesquena#1159)
- workspace.py: symlink target blocked-roots check + HOME sanity guard (nesquena#1149, nesquena#1165)
- panels.js: cron unread counter bookkeeping (in-loop increment bug)
- tests/test_symlink_cycle_detection.py: register workspace before session/new
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.

3 participants