Skip to content

fix(reasoning): use agent metadata for effort support#3017

Merged
1 commit merged into
nesquena:masterfrom
starship-s:fix/reasoning-effort-model-metadata
May 28, 2026
Merged

fix(reasoning): use agent metadata for effort support#3017
1 commit merged into
nesquena:masterfrom
starship-s:fix/reasoning-effort-model-metadata

Conversation

@starship-s
Copy link
Copy Markdown
Contributor

@starship-s starship-s commented May 27, 2026

Thinking Path

  • fix(webui): route Cursor ACP and gate reasoning effort by model #2792 made the reasoning-effort chip model-aware, but the resolver still depends on WebUI-local provider/model heuristics for most providers.
  • That leaves native/provider-specific catalogs behind: xAI OAuth Grok models such as grok-4.3 report no supported efforts even though Hermes Agent model metadata marks them reasoning-capable.
  • The narrow fix is to keep the exact provider resolvers that need special behavior (ACP unsupported, Copilot/GitHub subsets, OpenAI Codex, LM Studio probing), then ask Hermes Agent's model metadata for the remaining providers before falling back to the existing compatibility heuristics.
  • Metadata supports_reasoning=False is treated as authoritative so known non-reasoning variants do not get re-enabled by broad prefix heuristics.
  • The no-query /api/reasoning boot path now resolves against the configured default model/provider so the chip can hydrate correctly before the frontend has passed explicit active-session model context.

What Changed

  • Added a small _models_dev_reasoning_efforts() helper that reads agent.models_dev.get_model_capabilities() when available.
  • Updated resolve_model_reasoning_efforts() to use that metadata after exact provider-specific resolvers and before compatibility heuristics.
  • Preserved ACP unsupported behavior, Copilot/GitHub effort subset handling, OpenAI Codex handling, LM Studio live option probing, and existing heuristic fallback behavior when metadata is unavailable or unknown.
  • Updated get_reasoning_status() so calls without explicit model/provider fall back to model.default, model.provider, and model.base_url from config.
  • Added regression tests for xAI OAuth Grok metadata, authoritative non-reasoning metadata, heuristic fallback preservation, provider-hint stripping, and the no-query boot/default path.

Why It Matters

  • Reasoning-capable native/provider-specific models can show the reasoning-effort chip without adding another WebUI-local prefix rule for every provider catalog shape.
  • Known non-reasoning variants remain hidden when Agent metadata says they do not support reasoning.
  • WebUI capability detection stays aligned with Hermes Agent's model knowledge instead of drifting into a duplicated hardcoded allowlist.
  • Existing special cases that require non-boolean effort semantics remain intact.

Verification

Targeted reasoning capability suites:

python -m py_compile api/config.py tests/test_models_dev_reasoning.py
python -m pytest tests/test_models_dev_reasoning.py tests/test_reasoning_effort_model_capabilities.py tests/test_reasoning_show_hide.py -q
# 41 passed

Adjacent reasoning-chip suites:

python -m pytest tests/test_issue1103_reasoning_chip_visibility.py tests/test_reasoning_chip_btw_fixes.py tests/test_reasoning_chip_js_behaviour.py -q
# 38 passed

Hygiene:

git diff --check
# passed

Manual resolver smoke with the branch code:

xai-oauth @xai-oauth:grok-4.3 => minimal, low, medium, high, xhigh
xai-oauth @xai-oauth:grok-4.20-0309-reasoning => minimal, low, medium, high, xhigh
xai-oauth @xai-oauth:grok-4.20-0309-non-reasoning => []
openrouter x-ai/grok-4 => minimal, low, medium, high, xhigh

Risks / Follow-ups

  • If agent.models_dev is unavailable in an install, WebUI keeps the existing compatibility heuristics.
  • Metadata is boolean, so providers with narrower effort subsets still need exact resolvers before metadata; this PR preserves the existing exact resolver ordering for those providers.
  • No frontend layout or interaction code changed; this is backend capability data feeding the existing chip visibility logic.

Model Used

  • OpenAI / GPT-5.5 High for implementation, verification, and PR preparation.

@starship-s starship-s marked this pull request as ready for review May 27, 2026 10:00
@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Summary

Read the diff at api/config.py and the new tests/test_models_dev_reasoning.py, then cross-referenced agent/models_dev.py:451-510 (get_model_capabilities) and tools/skill_usage.py from ~/.hermes/hermes-agent. The shape is sound: provider-specific exact resolvers stay in front (ACP → empty, Copilot/GitHub via github_model_reasoning_efforts, openai-codex, lmstudio probe), then _models_dev_reasoning_efforts(hinted_model, provider) consults the agent's models.dev cache, and _heuristic_reasoning_efforts is the last-resort fallback. The None vs [] convention is correct — None means "no metadata, keep falling back", [] from supports_reasoning=False is authoritative and suppresses the prefix heuristic.

Code reference

The new helper at api/config.py:2131-2161 is the key change:

def _models_dev_reasoning_efforts(model_id, provider_id):
    ...
    try:
        from agent.models_dev import get_model_capabilities
    except Exception:
        return None
    try:
        capabilities = get_model_capabilities(provider=provider, model=model)
    except Exception:
        return None
    if capabilities is None:
        return None
    supports_reasoning = getattr(capabilities, "supports_reasoning", None)
    if supports_reasoning is True:
        return list(VALID_REASONING_EFFORTS)
    if supports_reasoning is False:
        return []
    return None

That matches the agent contract: agent/models_dev.py:447 sets supports_reasoning = bool(entry.get("reasoning", False)), and xai-oauth → xai is in PROVIDER_TO_MODELS_DEV (models_dev.py:172), so the xAI Grok lookup actually resolves.

A couple of observations

1. LM Studio call now uses hinted_model where it previously used model. Before, the lmstudio branch passed the raw model (potentially @lmstudio:my-model) to lmstudio_model_reasoning_options. The diff changes it to hinted_model (stripped). hermes_cli/models.py:2753-2756 matches against raw.get("key") == model and raw.get("id") == model, and LM Studio's /api/v1/models returns bare model IDs, so stripping the hint is almost certainly the right behavior — but it is a subtle behavior change worth flagging in case anyone configured LM Studio with @lmstudio: hints relying on the prior pass-through.

2. The except Exception: return _heuristic_reasoning_efforts(...) import-failure branch now skips the lmstudio probe entirely. That's a regression-of-sorts only if hermes_cli.models fails to import but agent.models_dev succeeds — unlikely in practice since both ship in the same agent tree, but the structural change is that lmstudio capability detection is no longer reachable from the no-hermes_cli fallback path. Minor; the heuristic returns [] for lmstudio anyway so it's a no-op in practice.

3. The get_reasoning_status() boot-default resolution at api/config.py:2241-2252 is the meaningful UX win — previously a no-query /api/reasoning call (api/routes.py:4022-4033) returned supports_reasoning_effort: false because resolve_model_reasoning_efforts(None, None, None) exits early on empty model. Now it reads model.default / model.provider from config.yaml, so the chip hydrates correctly on initial page load before the active-session model context arrives.

Tests look right

The fake agent.models_dev module pattern in _install_fake_models_dev correctly isolates the test from network/disk caches. test_models_dev_false_suppresses_prefix_heuristic is the important regression guard — it confirms x-ai/grok-4-non-reasoning with supports_reasoning=False returns [] instead of falling through to the x-ai/ prefix in _heuristic_reasoning_efforts (api/config.py:2119).

Verdict

Looks good to merge. The ordering preserves all the provider-specific behavior (Copilot subsets, Codex, LM Studio probe) and only fills the gap that the prefix-heuristic was masking. CI is green across 3.11/3.12/3.13.

@nesquena-hermes nesquena-hermes closed this pull request by merging all changes into nesquena:master in 5bc3cdb May 28, 2026
@nesquena-hermes
Copy link
Copy Markdown
Collaborator

Absorbed via stage-batch32 (PR #3036) and shipped as v0.51.150. Thanks for threading agent metadata through the resolver — xAI OAuth Grok models and other models.dev-backed providers now show the reasoning-effort chip without a per-provider WebUI allowlist update.

Opus advisor confirmed the order of precedence is correct (authoritative resolvers still return first, metadata sits between them and the heuristic fallback) and that both import and call sites are bare-except guarded so older hermes-agent installs without models_dev fall through cleanly.

Two non-blocking follow-ups for a future PR if you want to take them:

  1. Add a model.reasoning_efforts_force_supported: true config knob so a user can override an authoritative-supports_reasoning=False when the models.dev cache is stale.
  2. Add a direct ImportError-branch test (monkeypatch.setitem(sys.modules, "agent.models_dev", None)) — the existing "metadata returns None" tests cover the same downstream behavior via a different upstream return path.

Also: the LMStudio probe arg change (modelhinted_model at api/config.py:2208) was a real drive-by bug fix — worth a separate CHANGELOG line in the follow-up.

AJV20 pushed a commit to AJV20/hermes-webui that referenced this pull request May 28, 2026
eleboucher pushed a commit to eleboucher/homelab that referenced this pull request May 29, 2026
…➔ 0.51.157) (#699)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [ghcr.io/nesquena/hermes-webui](https://github.com/nesquena/hermes-webui) | patch | `0.51.145` → `0.51.157` |

---

### Release Notes

<details>
<summary>nesquena/hermes-webui (ghcr.io/nesquena/hermes-webui)</summary>

### [`v0.51.157`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051157--2026-05-28--Release-EC-stage-batch39--5-PR-mixed-risk-cleanup-gateway-prefill-forward--prefill-budget--compressed-continuation-sidebar--browser-transcript-memory-guidance--reasoning-max-parity)

[Compare Source](nesquena/hermes-webui@v0.51.156...v0.51.157)

##### Added

- The reasoning-effort selector now offers a `max` level, matching the agent's `hermes_constants.VALID_REASONING_EFFORTS`. This restores parity with the underlying set (the WebUI mirror previously stopped at `xhigh`) so providers such as Anthropic that support the `max` thinking level are selectable from the composer dropdown and the `/reasoning` command.

##### Changed

- WebUI's browser-session surface prompt now explicitly tells agents not to dump browser transcripts into external notes or durable memory by default; it limits saving to explicit captures and clearly reusable durable signals such as preferences, decisions, blockers, and runbook-worthy workflows.

##### Fixed

- Gateway-backed WebUI chat now forwards configured prefill/session-recall context and a compact WebUI session-context block into delegated Gateway turns, so browser sessions retain note recall, connected-platform awareness, and delivery hints instead of sending only the latest user message. If the dynamic prefill script fails, WebUI falls back to the configured static router prefill when available.
- Oversized WebUI startup prefill payloads now respect a configurable context budget (`webui_prefill_context_max_chars` / `HERMES_WEBUI_PREFILL_CONTEXT_MAX_CHARS`, default 12,000 chars). When a dynamic prefill script exceeds the budget and a compact static prefill file is configured, WebUI falls back to the compact file; otherwise it injects a small retrieval instruction instead of dumping the full note/body payload into every new chat.
- Sidebar now keeps the newest active continuation visible when it has more recent activity than an older fuller pre-compression snapshot in the same lineage. Adds lineage-aware dedupe for WebUI-origin state-db projections, restores normal context-only turns into the visible transcript after compression while preserving order, and recognizes `[Session Arc Summary]` as a compression marker so it isn't backfilled into the chat transcript.

### [`v0.51.156`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051156--2026-05-28--Release-EB-stage-batch38--2-PR-Tier-B-cleanup-WebUI-requestruntime-hardening--chat-start-provider-fallback)

[Compare Source](nesquena/hermes-webui@v0.51.155...v0.51.156)

##### Fixed

- Hardened WebUI request/session/runtime edges: malformed request body lengths are rejected before reads, session writes reject unsafe IDs, auth session/login-attempt maps avoid unsynchronized mutation, and successful password login clears stale rate-limit failures.
- Hardened frontend startup and navigation fallbacks: early storage access now survives blocked `localStorage`, stale session recovery preserves subpath mounts, session URL generation removes both legacy session query aliases, canceling a stream closes the local EventSource, and the PWA shell precaches same-origin markdown/KaTeX vendor assets.
- Added missing i18n keys used by command, cron, provider, search/default, and session-rename UI paths across supported locales so missing translations fall back to labels instead of raw key names.
- Made workspace Git tests pin their temporary repository branch to `master` so the suite is independent of the host Git default-branch setting.
- Browser chat start and queued-turn payloads now fall back to the selected/persisted provider only when it belongs to the same model being sent, preventing fresh sessions from sending a dropdown-selected model with `model_provider=null`.

### [`v0.51.155`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051155--2026-05-28--Release-EA-stage-batch37--3-PR-very-low-risk-cleanup-passive-timeout-toasts--sidecar-order--subsecond-timestamps)

[Compare Source](nesquena/hermes-webui@v0.51.154...v0.51.155)

##### Fixed

- Passive background refreshes such as sidebar/project polling, health checks, cron-status watches, and client-event logging no longer surface generic timeout toasts; explicit user actions still show timeout errors. (Related to [#&#8203;3024](nesquena/hermes-webui#3024))
- Messaging/session display merges now preserve sidecar transcript order when the sidecar already contains at least as many rows as the mirrored state store, avoiding role/content fallback sorting when timestamp precision collapses.
- Gateway-backed turns and compacted/reconciled message batches now keep subsecond timestamp ordering instead of assigning the same integer-second timestamp to multiple transcript rows.

### [`v0.51.154`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051154--2026-05-28--Release-DZ-stage-batch36--9-PR-medium-risk-cleanup-cron-project-chip--KaTeX-streaming--recovery--env-keys--discoverability-repair--media-MEDIA-tokens--gateway-401--notes-prefill--cron-filter)

[Compare Source](nesquena/hermes-webui@v0.51.153...v0.51.154)

##### Added

- Session discoverability audit now has a default-dry-run `--repair-safe` routine for deterministic cleanup: stale persisted WebUI-as-CLI flags can be cleared from sidecars/index entries, and messageful WebUI rows present only in `state.db` can be materialized into sidecars/index entries when `--apply --backup-dir <dir>` is explicitly provided.

##### Changed

- The third-party notes drawer's "Recently used by AI" list now follows the provider-neutral WebUI-specific `HERMES_WEBUI_PREFILL_MESSAGES_SCRIPT` / `webui_prefill_messages_script` hook when configured, including argv-style hooks such as `[python3, /path/to/recall.py]` and command strings such as `python3 /path/to/recall.py`, before falling back to the legacy generic `prefill_messages_script`. Configured third-party notes sources such as Joplin, Obsidian, Notion, and llm-wiki remain visible even before runtime tool inventory hydrates.

##### Fixed

- Streaming KaTeX render passes now skip parser-owned equation placeholders that may still be receiving text, preventing long equations from being marked rendered before the final parser flush completes. ([#&#8203;2976](nesquena/hermes-webui#2976))
- Cron sessions assigned to the dedicated Cron Jobs project now remain hidden from the default sidebar while still appearing when that project chip is selected.
- Compression parent sessions are no longer repaired as stale interrupted turns when a continuation already exists, preventing false "Response interrupted" markers and hidden continuation rows after auto-compression session rotation. (Refs [#&#8203;2361](nesquena/hermes-webui#2361))
- Empty partial activity rows preserved from cancelled turns no longer define sidebar recency, anchor the initial paginated message window, or get restored after newer completed turns. Long sessions with old activity-only partials after recent replies now stay grouped by their latest real message and open on the recent readable transcript. ([#&#8203;3057](nesquena/hermes-webui#3057))
- Local `MEDIA:` image tokens in chat history now include the current session id and can render exact image paths already present in that session transcript, so agent-generated artifacts outside the active workspace no longer show as broken thumbnails while arbitrary local paths remain blocked.
- Gateway-backed browser chat now turns Gateway API Server 401s into a specific `gateway_auth_error` explaining that `HERMES_WEBUI_GATEWAY_API_KEY` must match `API_SERVER_KEY`, instead of surfacing the Gateway's generic "Invalid API key" body as if the model provider key failed. The browser error renderer recognizes this event type as "Gateway authentication failed" instead of falling back to a generic "Error" heading. `/api/health/agent` also reports redacted gateway-chat configuration status (`enabled`, backend, base URL configured, API key configured) as an operator diagnostic payload; it is not currently rendered as a user-facing health banner.
- New profiles with an API key supplied at create time now write the key to the profile's `.env` under the correct provider-specific variable (e.g. `KIMI_API_KEY`, `DEEPSEEK_API_KEY`) at mode 0o600, instead of writing it to `config.yaml` where Hermes Agent never reads it.

### [`v0.51.153`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051153--2026-05-28--Release-DY-stage-batch35--11-PR-low-risk-cleanup-title-language--clarify-SSE--upload-filename--discoverability--SSE-reconnect--gateway-image--docker-docs)

[Compare Source](nesquena/hermes-webui@v0.51.152...v0.51.153)

##### Changed

- Local fallback title generation no longer has a German-only `Session Bilder` special case; it now uses the same generic topic extraction path as other fallback titles. (Refs [#&#8203;3040](nesquena/hermes-webui#3040))
- Title-generation prompts now use the same language-neutral "match the user language" instruction for every locale instead of adding German-only exemplars. (Refs [#&#8203;3040](nesquena/hermes-webui#3040))
- Session discoverability audit findings for stale persisted WebUI-as-CLI flags now report whether an API-visible lineage representative already covers the hidden snapshot, including the representative session id in JSON and Markdown output.

##### Fixed

- Title-language detection no longer treats common English tech/jargon text such as "session die" or DAS/DER references as German just because of shared tokens. (Refs [#&#8203;3040](nesquena/hermes-webui#3040))
- Clarify prompt SSE fallback polling now preserves its owner session id, matching approval polling behavior so terminal events from another session cannot stop the active clarify fallback poller.
- Duplicate chat uploads now report the actual stored filename in `/api/upload` responses, so suffixed files such as `photo-1.png` do not appear under the original basename in WebUI attachment metadata.
- Visible but unfocused chat windows now still attempt the immediate SSE reconnect for the current session; only a real session switch skips the reconnect path. (Refs [#&#8203;3040](nesquena/hermes-webui#3040))
- Gateway-backed WebUI chat now forwards current-turn image attachments as OpenAI-style multimodal `image_url` parts when native image input is enabled, matching the legacy WebUI runtime's image handoff.
- New chat sessions reset `_messagesTruncated` / `_oldestIdx` so a fresh conversation never displays the stale "Scroll up or click to load older messages" indicator inherited from a previously-paginated session.
- `openai-codex` reasoning-effort resolution now lets the existing `models.dev` metadata pass set the supported levels (including `xhigh`) instead of being silently clipped through the Copilot model heuristic.

##### Documentation

- Clarify two Docker onboarding traps: `sudo docker compose` can mount `/root/.hermes` instead of the user's Hermes home on Linux, and Linux Docker Engine users should use a `host-gateway` alias such as `api.local` for host-local model servers instead of configuring `localhost` inside the container. ([#&#8203;3006](nesquena/hermes-webui#3006), [#&#8203;3012](nesquena/hermes-webui#3012))

### [`v0.51.152`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051152--2026-05-28--Release-DX-stage-batch34--single-PR-optional-gateway-backed-browser-chat)

[Compare Source](nesquena/hermes-webui@v0.51.151...v0.51.152)

##### Added

- Browser chat can now opt into a default-off `HERMES_WEBUI_CHAT_BACKEND=gateway` bridge that routes new WebUI turns through a running Hermes Gateway API server while preserving the existing WebUI chat start/stream contract. Strict enable: only the literal values `gateway`, `api_server`, or `api-server` activate the bridge — generic truthy strings like `1` or `true` keep the legacy in-process WebUI runtime. Configurable via `HERMES_WEBUI_GATEWAY_BASE_URL` (default `http://127.0.0.1:8642`) and `HERMES_WEBUI_GATEWAY_API_KEY` (falls back to `API_SERVER_KEY`). New `api/gateway_chat.py` module isolates the bridge logic; existing direct WebUI chat path unchanged when the env/config is not set. ([#&#8203;3021](nesquena/hermes-webui#3021))

### [`v0.51.151`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051151--2026-05-28--Release-DW-stage-batch33--3-PR-mid-risk-batch-SSE-reattach--title-lang--composer-cap)

[Compare Source](nesquena/hermes-webui@v0.51.150...v0.51.151)

##### Fixed

- Live SSE stream now reattaches when returning to a session that lost its connection during a session switch, closing the connection-leak window where stale `EventSource`s could accumulate. Also fixes a `_dirty_suffix` correctness path and yields the GIL after every SSE put so the HTTP server stays responsive under burst load. ([#&#8203;2924](nesquena/hermes-webui#2924), [#&#8203;2925](nesquena/hermes-webui#2925))
- Generated session titles now stay in the conversation language by adding an explicit title-generation instruction to the auxiliary prompt. Prevents the default prompt from drifting into English for non-English conversations. ([#&#8203;2984](nesquena/hermes-webui#2984))

##### Changed

- Composer box max-width is now capped at 1600px on ultrawide viewports (≥1600px) so chips stay anchored against a content-sized boundary instead of stretching across 3440px+ displays. Maintainer-confirmed cap from the [#&#8203;2856](nesquena/hermes-webui#2856) thread. ([#&#8203;2946](nesquena/hermes-webui#2946))

### [`v0.51.150`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051150--2026-05-28--Release-DV-stage-batch32--single-PR-reasoning-effort-agent-metadata)

[Compare Source](nesquena/hermes-webui@v0.51.149...v0.51.150)

##### Fixed

- Reasoning-effort capability detection now consults Hermes Agent's `models.dev` metadata before falling back to WebUI-local provider/model prefix heuristics. xAI OAuth Grok models (e.g. `grok-4.3`) and other native/provider-specific catalogs that Hermes Agent already knows about now show the reasoning-effort chip without requiring a per-provider WebUI allowlist update. Existing exact-resolver paths (ACP unsupported, Copilot/GitHub effort subsets, OpenAI Codex, LM Studio live probing) keep their authoritative behavior — the new metadata lookup sits between those resolvers and the broad heuristic fallback. Metadata `supports_reasoning=False` is treated as authoritative so known non-reasoning variants stay hidden. Also: the no-query boot path of `/api/reasoning` now hydrates against the configured default model so the chip can populate before the front-end has session model context. ([#&#8203;3017](nesquena/hermes-webui#3017))

### [`v0.51.149`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051149--2026-05-28--Release-DU-stage-batch31--hyphenated-session-ids--prefill-role-consistency)

[Compare Source](nesquena/hermes-webui@v0.51.148...v0.51.149)

##### Fixed

- Session IDs containing hyphens (e.g. API-issued `api-*` and gateway-issued `reachy-voice-*`) are now accepted by every filesystem-touching session validator: `Session.load`, `Session.load_metadata_only`, `_repair_stale_pending`, `/api/session/delete`, and `/api/session/worktree/remove`. Previously the load path accepted hyphens but the delete and worktree-remove routes rejected them with HTTP 400, producing a confusing "visible in sidebar but undeletable" UX. Refactors the duplicated character-class check into a shared `api.models.is_safe_session_id` helper with regression coverage at every call site. ([#&#8203;3023](nesquena/hermes-webui#3023), [#&#8203;3024](nesquena/hermes-webui#3024))
- Plain-text `webui_prefill_messages_script` output is now wrapped as a `user` prefill message instead of a `system` message, so dynamic recall context from notes/Obsidian/Joplin scripts becomes ordinary turn context rather than an extra system instruction. The JSON message-list escape hatch is unchanged: scripts that emit explicit `[{"role": "system", "content": "..."}]` still produce a system message. Avoids provider-specific multi-system-message footguns (Anthropic concatenation, OpenAI Responses-API divergence). ([#&#8203;3009](nesquena/hermes-webui#3009))

### [`v0.51.148`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051148--2026-05-28--Release-DT-stage-batch30--single-PR-Insights-skill-usage-reader)

[Compare Source](nesquena/hermes-webui@v0.51.147...v0.51.148)

##### Added

- Insights page now shows a Skill Usage card after the LLM Wiki card, displaying per-skill cumulative invocation counts (uses / views / patches / share-%) from the agent-owned `.usage.json`. WebUI reads only; the agent (`tools/skills_tool.py`, `tools/skill_manager_tool.py`) is the single writer with `fcntl` locking, so there is no double-counting or write race. Empty-state shows when no skills have been used yet. Includes i18n keys for the 12 new strings across all supported locales. ([#&#8203;3008](nesquena/hermes-webui#3008))

### [`v0.51.147`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051147--2026-05-28--Release-DS-stage-batch29--single-PR-streaming-ownership-cleanup-follow-up)

[Compare Source](nesquena/hermes-webui@v0.51.146...v0.51.147)

##### Fixed

- Settled stream cleanup helpers (`_restoreSettledSession`, `_handleStreamError`, `_deferStreamErrorIfPageHidden`, `_reattachOrRestoreAfterDeferredStreamError`) now thread the owning `EventSource` instance through every async deferred path, so a late error or settle callback from an older source can no longer tear down a newer reconnect source. Completes the ownership-aware cleanup pattern introduced by `closeLiveStream(sessionId, streamId, source)`. ([#&#8203;2930](nesquena/hermes-webui#2930), [#&#8203;3010](nesquena/hermes-webui#3010))

### [`v0.51.146`](https://github.com/nesquena/hermes-webui/blob/HEAD/CHANGELOG.md#v051146--2026-05-28--Release-DR-stage-batch28--6-PR-low-risk-safetycontrast-batch)

[Compare Source](nesquena/hermes-webui@v0.51.145...v0.51.146)

##### Fixed

- Dark-mode panel header save buttons now use a theme-aware foreground token, keeping workspace and other detail-pane check icons visible on the default gold accent. ([#&#8203;2998](nesquena/hermes-webui#2998), [#&#8203;3022](nesquena/hermes-webui#3022))
- Custom provider `/v1/models` discovery now uses a short per-endpoint timeout and gracefully skips slow or unreachable providers, reducing cold `/api/models` cache rebuild latency. ([#&#8203;3024](nesquena/hermes-webui#3024), [#&#8203;3025](nesquena/hermes-webui#3025))
- Messaging (Telegram-resumed) sessions: the `?messages=0` metadata fast path now routes through the same display merge as the full-message path, so `message_count` and `last_message_at` match the rendered transcript and stop triggering refresh-loops that reset scroll and close open dropdowns. ([#&#8203;3003](nesquena/hermes-webui#3003))
- WebUI sessions mirrored into `state.db` for long-history retention now stay in the WebUI sidebar tab instead of being misclassified as CLI rows. Adds regression coverage for both directions of the WebUI vs CLI source-tab invariant. ([#&#8203;3027](nesquena/hermes-webui#3027))
- Sidebar projection now keeps at least one messageful representative visible per non-background conversation when normal filters would otherwise hide every row, rescuing discoverability for sessions with stale snapshot/lineage metadata. Rescued rows are marked `discoverability_warning: rescued_messageful_hidden_session` for auditability; intentional background/cron sessions stay hidden. ([#&#8203;3028](nesquena/hermes-webui#3028))

##### Added

- New read-only `api.session_discoverability` audit module cross-checks JSON sidecars, `_index.json`, `state.db`, and the live sidebar response to classify messageful sessions without a visible representative, stale WebUI-as-CLI source flags, missing sidecars, and lineage segments without a visible tip. Diagnostic surface only; does not repair, restart, or mutate any state. ([#&#8203;3029](nesquena/hermes-webui#3029))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about these updates again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDEuMSIsInVwZGF0ZWRJblZlciI6IjQzLjEwMS4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZS9jb250YWluZXIiLCJ0eXBlL3BhdGNoIl19-->

Reviewed-on: https://git.erwanleboucher.dev/eleboucher/homelab/pulls/699
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