Release exp: allow manual update check when auto-update is disabled (#6088) + regression test. Thanks @webtecnica.

This commit is contained in:
nesquena-hermes committed 2026-07-15 20:02:35 +00:00
1 parent 754dcca048
commit 2e93d04a57
2 files changed
+86

No files matched your search

+2
View File
@@ -67,6 +67,8 @@
### Fixed
- **Manual "Check for updates" now works even when automatic update checks are turned off.** Previously, disabling automatic update checks in Preferences → System also disabled the manual "check now" button, leaving no way to update from the WebUI without re-enabling the (noisy) automatic banner. The explicit manual force-check now bypasses the disabled auto-check toggle; the automatic path still honors the setting. Thanks @webtecnica. (#6088, #6082)
- **No more spurious "No response from provider" after a tool-limit turn that did answer.** When a turn hit the per-turn tool-iteration limit (`max_iterations_reached`) but the model had already produced a valid final answer, the settlement classifier still appended a "No response from provider" error card after the good reply — a regression of the earlier false-`no_response` fix, because the suppression path admitted only `_soft_partial_terminal_failure` and deliberately excluded `_tool_limit_reached`. The suppression now also covers `_tool_limit_reached`, but *only* when the transcript already holds a final answer; a tool-limit turn with no final answer still fails honestly, and explicit errors / cancellations / interruptions stay outside the suppression. Thanks @coyaSONG. (#6081, #6079)
- **New conversations can no longer become unstartable seconds after you create them.** On installs with a saved browser/password-manager credential and more than a few hundred sessions, the manager would autofill the account name into the sidebar conversation filter, silently firing a content search that walked every session through the cache and evicted the brand-new, not-yet-persisted session (its only copy lived in the in-memory cache) — so `/api/session/draft` and `/api/chat/start` then 404'd and the chat could never be started. Two fixes: the search/filter inputs are now `type="search"` with per-manager opt-out attributes and the Settings + onboarding password fields get a real `<form>` owner (`display:contents`, layout unchanged) so managers stop treating the sidebar filter as a username field; and `_session_is_evictable()` now proves persistence before evicting even a zero-message session, so an unsaved session you're still composing stays resident. Thanks @ai-ag2026. (#6083, #4765)
+84
View File
@@ -0,0 +1,84 @@
"""Route-level tests for #6088 / #6082 — a manual force-check must work even
when automatic update checking is disabled."""
import io
import json
from urllib.parse import urlparse
import api.routes as routes
class _FakeUpdatesHandler:
"""Minimal handler for driving routes.handle_post against /api/updates/check."""
def __init__(self, body_bytes: bytes):
self.rfile = io.BytesIO(body_bytes)
self.wfile = io.BytesIO()
self.headers = {
"Content-Length": str(len(body_bytes)),
"Content-Type": "application/json",
}
self.command = "POST"
self.path = "/api/updates/check"
self.client_address = ("127.0.0.1", 12345)
self.status = None
def send_response(self, status):
self.status = status
def send_header(self, key, value):
self.headers[key] = value
def end_headers(self):
pass
def _run_updates_check(monkeypatch, *, check_for_updates_enabled, body):
"""Drive POST /api/updates/check through the real route dispatch, capturing j()."""
cap = {}
def _j(_handler, obj, *_a, **kw):
cap["ok"] = obj
cap["status"] = kw.get("status", 200)
return True
def _bad(_handler, msg, code=400, **_kw):
cap["bad"] = (msg, code)
return True
monkeypatch.setattr(routes, "j", _j)
monkeypatch.setattr(routes, "bad", _bad)
monkeypatch.setattr(
routes, "load_settings", lambda: {"check_for_updates": check_for_updates_enabled}
)
# Never let the real check run (network / git); prove only whether it's reached.
sentinel = {"reached_real_check": True}
monkeypatch.setattr("api.updates.check_for_updates", lambda **kw: sentinel)
# The visibility guard is not relevant to this route; allow it through.
monkeypatch.setattr(routes, "_guard_request_session_visibility", lambda *a, **k: True)
handler = _FakeUpdatesHandler(json.dumps(body).encode())
routes.handle_post(handler, urlparse("/api/updates/check"))
return cap
def test_updates_check_disabled_blocks_auto_check(monkeypatch):
"""With check_for_updates off, a normal (non-force) POST still short-circuits."""
cap = _run_updates_check(monkeypatch, check_for_updates_enabled=False, body={})
assert cap.get("ok") == {"disabled": True}, cap
def test_updates_check_disabled_allows_manual_force(monkeypatch):
"""#6082/#6088: a manual force-check bypasses the disabled auto-check toggle."""
cap = _run_updates_check(
monkeypatch, check_for_updates_enabled=False, body={"force": True}
)
assert cap.get("ok") == {"reached_real_check": True}, (
"force=true must bypass the disabled short-circuit and run the real check"
)
assert cap.get("ok") != {"disabled": True}
def test_updates_check_enabled_runs_check_without_force(monkeypatch):
"""With check_for_updates on, a normal POST runs the real check (no regression)."""
cap = _run_updates_check(monkeypatch, check_for_updates_enabled=True, body={})
assert cap.get("ok") == {"reached_real_check": True}, cap