fix: deduplicate model dropdown (hyphen vs dot) + README accuracy (#332)
Normalizes hyphens to dots in backend model-ID comparison so claude-sonnet-4-6 (hermes-agent format) matches claude-sonnet-4.6 (WebUI list) and no duplicate entry is injected. README line counts and test count corrected. 791 tests, all pass.
This commit is contained in:
@@ -6,6 +6,11 @@
|
||||
---
|
||||
|
||||
|
||||
## [v0.50.8] Model dropdown deduplication — hyphen vs dot separator fix (PR #332)
|
||||
|
||||
- **Model dropdown no longer shows duplicates for hyphen-format configs** (e.g. `claude-sonnet-4-6` from hermes-agent config): The server-side normalization in `api/config.py` now unifies hyphens and dots when checking whether the default model is already in the dropdown. Previously, `claude-sonnet-4-6` (hermes-agent format) and `claude-sonnet-4.6` (WebUI list format) were treated as different models, causing the same model to appear twice — once as a raw unlabelled entry and once with the correct display name. The raw entry is now suppressed and the labelled one is selected as default.
|
||||
- **README updated**: test count corrected to 791 / 51 files; all module line counts updated to current values; `onboarding.py`, `state_sync.py`, `updates.py` added to the architecture listing.
|
||||
|
||||
## [v0.50.7] OAuth provider onboarding path — Codex/Copilot no longer blocks setup (PR #331, fixes #329 bug 2)
|
||||
|
||||
- **OAuth providers now have a proper onboarding path** (closes bug 2): Users with `openai-codex`, `copilot`, `qwen-oauth`, or any other OAuth-authenticated provider now see a clear confirmation card instead of an unusable API key input form.
|
||||
|
||||
44
README.md
44
README.md
@@ -339,8 +339,8 @@ Or using the agent venv explicitly:
|
||||
```
|
||||
|
||||
Tests run against an isolated server on port 8788 with a separate state directory.
|
||||
Production data and real cron jobs are never touched. Current count: **433 tests**
|
||||
across 23 test files.
|
||||
Production data and real cron jobs are never touched. Current count: **791 tests**
|
||||
across 51 test files.
|
||||
|
||||
---
|
||||
|
||||
@@ -462,31 +462,33 @@ across 23 test files.
|
||||
## Architecture
|
||||
|
||||
```
|
||||
server.py HTTP routing shell + auth middleware (~83 lines)
|
||||
server.py HTTP routing shell + auth middleware (~154 lines)
|
||||
api/
|
||||
auth.py Optional password authentication, signed cookies (~149 lines)
|
||||
config.py Discovery, globals, model detection, reloadable config (~726 lines)
|
||||
helpers.py HTTP helpers, security headers (~71 lines)
|
||||
models.py Session model + CRUD + CLI bridge (~338 lines)
|
||||
profiles.py Profile state management, hermes_cli wrapper (~366 lines)
|
||||
routes.py All GET + POST route handlers (~1314 lines)
|
||||
streaming.py SSE engine, run_agent, cancel support (~332 lines)
|
||||
upload.py Multipart parser, file upload handler (~78 lines)
|
||||
auth.py Optional password authentication, signed cookies (~201 lines)
|
||||
config.py Discovery, globals, model detection, reloadable config (~1110 lines)
|
||||
helpers.py HTTP helpers, security headers (~175 lines)
|
||||
models.py Session model + CRUD + CLI bridge (~377 lines)
|
||||
onboarding.py First-run onboarding wizard, OAuth provider support (~507 lines)
|
||||
profiles.py Profile state management, hermes_cli wrapper (~411 lines)
|
||||
routes.py All GET + POST route handlers (~1996 lines)
|
||||
state_sync.py /insights sync — message_count to state.db (~113 lines)
|
||||
streaming.py SSE engine, run_agent, cancel support (~545 lines)
|
||||
updates.py Self-update check and release notes (~257 lines)
|
||||
upload.py Multipart parser, file upload handler (~82 lines)
|
||||
workspace.py File ops, workspace helpers, git detection (~288 lines)
|
||||
static/
|
||||
index.html HTML template (~600 lines)
|
||||
style.css All CSS incl. mobile responsive, themes (~855 lines)
|
||||
ui.js DOM helpers, renderMd, tool cards, context ring (~1090 lines)
|
||||
workspace.js File preview, file ops, git badge (~247 lines)
|
||||
sessions.js Session CRUD, ⋯ dropdown, collapsible groups, search (~600 lines)
|
||||
messages.js send(), SSE handlers, rAF throttle (~352 lines)
|
||||
panels.js Cron, skills, memory, profiles, control center (~1200 lines)
|
||||
commands.js Slash command autocomplete (~170 lines)
|
||||
boot.js Mobile nav, workspace state machine, composer chips, boot IIFE (~420 lines)
|
||||
style.css All CSS incl. mobile responsive, themes (~1050 lines)
|
||||
ui.js DOM helpers, renderMd, tool cards, context indicator (~1496 lines)
|
||||
workspace.js File preview, file ops, git badge (~286 lines)
|
||||
sessions.js Session CRUD, collapsible groups, search (~752 lines)
|
||||
messages.js send(), SSE handlers, rAF throttle (~487 lines)
|
||||
panels.js Cron, skills, memory, profiles, settings (~1438 lines)
|
||||
commands.js Slash command autocomplete (~267 lines)
|
||||
boot.js Mobile nav, voice input, boot IIFE (~524 lines)
|
||||
tests/
|
||||
conftest.py Isolated test server (port 8788)
|
||||
test_sprint{1-36}.py 36 test files, 742 test functions
|
||||
test_regressions.py Permanent regression gate
|
||||
51 test files 791 test functions
|
||||
Dockerfile python:3.12-slim container image
|
||||
docker-compose.yml Compose with named volume and optional auth
|
||||
.github/workflows/ CI: multi-arch Docker build + GitHub Release on tag
|
||||
|
||||
@@ -913,10 +913,11 @@ def get_available_models() -> dict:
|
||||
# Ensure the user's configured default_model always appears in the dropdown.
|
||||
# It may be missing if the model isn't in any hardcoded list (e.g. openrouter/free,
|
||||
# a custom local model, or any model.default not in _FALLBACK_MODELS).
|
||||
# Normalize before comparing: strip provider prefix so 'anthropic/claude-opus-4.6'
|
||||
# matches 'claude-opus-4.6' already in the list and avoids a duplicate entry.
|
||||
# Normalize before comparing: strip provider prefix and unify separators so
|
||||
# 'anthropic/claude-opus-4.6' matches 'claude-opus-4.6' and 'claude-sonnet-4-6'
|
||||
# matches 'claude-sonnet-4.6' (hermes-agent uses hyphens, webui uses dots).
|
||||
if default_model:
|
||||
_norm = lambda mid: mid.split("/", 1)[-1] if "/" in mid else mid
|
||||
_norm = lambda mid: (mid.split("/", 1)[-1] if "/" in mid else mid).replace("-", ".")
|
||||
all_ids_norm = {_norm(m["id"]) for g in groups for m in g.get("models", [])}
|
||||
if _norm(default_model) not in all_ids_norm:
|
||||
# Determine which group to inject into. Compare against the
|
||||
|
||||
@@ -526,7 +526,7 @@
|
||||
<div class="settings-section-title">System</div>
|
||||
<div class="settings-section-meta">Instance version and access controls.</div>
|
||||
</div>
|
||||
<span class="settings-version-badge">v0.50.7</span>
|
||||
<span class="settings-version-badge">v0.50.8</span>
|
||||
</div>
|
||||
<div class="settings-field" style="border-top:1px solid var(--border);padding-top:12px;margin-top:8px">
|
||||
<label for="settingsPassword" data-i18n="settings_label_password">Access Password</label>
|
||||
|
||||
Reference in New Issue
Block a user