v0.50.294 — 3-PR batch (streaming stability trio + cache version stamp + race fix + readonly fs guard)
3 PRs from 2 contributors. Closes 6 issues: #1430, #1470, #1623, #1624, #1625, #1633.
Highlights
Streaming stability trio (#1631, closes #1623, #1624, #1625)
Three named-constant fixes for streaming layer stability:
-
#1623 SSE app heartbeat 30s → 5s — kernel TCP keepalive (added v0.50.289) declared peers dead at 25s worst-case; the 30s app heartbeat was racing the kernel. Now
_SSE_HEARTBEAT_INTERVAL_SECONDS = 5at all 5 SSE handler sites inapi/routes.py, with a regression test that derives the kernel window fromserver.pysetsockopt block and pinsapp_heartbeat × 2 ≤ kernel_windowso future tuning of either timer can't reintroduce the misalignment. -
#1624
_repair_stale_pendinggrace period — was firing a false-positive "Previous turn did not complete." marker on every command-approval turn. New_REPAIR_STALE_PENDING_GRACE_SECONDS = 30skips repair on fresh turns. Plus rate-limitedlogger.warning/logger.debugtelemetry for empirical tuning. Defense-in-depth, not root-cause fix. -
#1625 Local-server model id preservation (reported by @akarichan8231) —
resolve_model_provider()was stripping the provider prefix fromqwen/qwen3.6-27bfor local servers, making LM Studio load a duplicate instance with default settings instead of reusing the user's tuned context/parallel slots. New_LOCAL_SERVER_PROVIDERSset + IP loopback heuristic preserves the full HF id for local servers (LM Studio, Ollama, llama.cpp, vLLM, TabbyAPI, LocalAI, KoboldCpp, etc.). Public-host OpenAI proxies (LiteLLM athttps://litellm.example.com/v1) still strip per pre-existing #433 contract.Behavior change for internal-network OpenAI-compatible proxies (RFC1918): the loopback heuristic also matches private-IP base_urls (10/8, 172.16/12, 192.168/16). A team running an internal LiteLLM proxy at
http://10.5.0.1:1234/v1now gets prefix preservation. LiteLLM accepts either form so this is invisible in practice.
Models cache version stamp (#1636, closes #1633)
Reporter Deor (Discord) updated v0.50.281 → v0.50.292 — which contained fixes for #1538, #1539, #1568 — did a hard refresh + cleared site data, and still saw byte-for-byte identical stale picker contents because the server kept reading the v0.50.281 cache file off the host-mounted volume.
STATE_DIR/models_cache.json now stamped with _webui_version (resolved lazily from api.updates.WEBUI_VERSION to dodge circular import) and _schema_version = 2. Mismatched stamps → cache rejected → live rebuild on next /api/models call. Legacy unstamped caches (pre-#1633) also rejected. Schema version is independent of WebUI version so future cache-shape changes can invalidate older releases without a tag bump.
Session list race + readonly fs guard (#1635 by @bergeouss)
Two unrelated focused fixes bundled:
-
#1430 (reported by @Olyno) — picking a previous-day conversation made today's sessions disappear because
renderSessionList()had no staleness guard. New_renderSessionListGengeneration counter pre-incremented beforeawait, post-await staleness check. Lightest-weight correct shape. -
#1470 (reported by @cosmoceus) — podman with
read_only=truecrashed at startup withgroupmod: cannot lock /etc/group. New writability check[ ! -w /etc/group ]with three branches: writable → original behavior; readonly + matching UID/GID → skip with log; readonly + mismatched → clearerror_exitdirecting user to set matching IDs.
Tests
4180 → 4245 passing (+65). 0 regressions. Full suite ~120s.
Pre-release verification
- Opus advisor on stage-294 combined diff: SHIP verdict. All 9 verification questions cleared.
api/config.pyoverlap between #1631 + #1636 verified disjoint (no shared mutable state, no call edges)._repair_stale_pendingrace-window closed by lock-protected re-check. Early-init fail-safe paths verified. Cross-tool boundaries verified — agent has its own model-cache files at different paths. - All 3 PRs have nesquena APPROVED reviews.
- #1631 in-PR Opus pre-merge pass already absorbed: rate-limited telemetry, expanded
_LOCAL_SERVER_PROVIDERS(+lm-studio, +localai), RFC1918 CHANGELOG callout. - #1636 stage-294 absorptions: DEBUG logger calls in
_is_loadable_disk_cacherejection paths + docstring clarification on string-vs-semver. - JS syntax:
static/sessions.jsclean. - Browser API sanity: 11/11 endpoints OK.
- Live behavioral verification post-deploy: SSE heartbeat constant = 5, grace = 30,
_LOCAL_SERVER_PROVIDERSincludeslm-studio+localai,_MODELS_CACHE_SCHEMA_VERSION = 2, legacy cache rejection confirmed,_renderSessionListGencounter pattern present, readonly-fs check in docker_init.bash present.
Authors
- @nesquena-hermes — 2 PRs (#1631, #1636)
- @bergeouss — 1 PR (#1635, AI-assisted via Hermes Agent)
External contributor @bergeouss continues the strong contribution pattern from #1550 (the project-filter fix that shipped earlier).
Full changelog: https://github.com/nesquena/hermes-webui/blob/master/CHANGELOG.md