Fix: Serena PyPI version check triggered by callback on main thread could delay agent startup

Closes #1774
This commit is contained in:
Dominik Jain authored and Dominik Jain committed 2026-07-29 15:24:22 +02:00
1 parent 21f4b3fe58
commit a61765ecc8
2 files changed
+16 -14

No files matched your search

+3
View File
@@ -42,6 +42,9 @@ Status of the `main` branch. Changes prior to the next official version change w
calling `subprocess.run` directly (e.g. for installation processes), so all such subprocesses get
`stdin=DEVNULL` and can no longer interfere with the stdio MCP connection #1748
* Dashboard:
- Fix: Serena PyPI version check triggered by callback on main thread could delay agent startup #1774
* Hooks:
- Add `serena-hooks --client=grok`, including Grok-native PreToolUse allow/deny output.
- PreToolUse remind hook: coerce non-string shell command values instead of failing, and recognize
+13 -14
View File
@@ -10,7 +10,6 @@ import urllib.error
import urllib.request
from collections.abc import Callable
from dataclasses import dataclass
from functools import cached_property
from html import escape
from pathlib import Path
from typing import TYPE_CHECKING, Any, Optional, Self
@@ -216,38 +215,38 @@ class SerenaDashboardAPI:
self._news_ready = threading.Event()
self._setup_routes()
self._read_news = ReadNews.load()
self._newer_serena_version: str | None = None
# register callback for config changes
self._current_config_overview: dict[str, Any] | None = None
self._agent.register_config_changed_callback(self._on_agent_config_changed)
# fetch remote news in background on startup (non-blocking)
# start threads for background computations
# * fetch remote news in background on startup (non-blocking)
threading.Thread(target=self._fetch_news, daemon=True).start()
# * determine if a newer Serena version is available
threading.Thread(target=self._determine_newer_serena_version, daemon=True).start()
@property
def memory_log_handler(self) -> MemoryLogHandler:
return self._memory_log_handler
@cached_property
def _newer_serena_version(self) -> str | None:
"""The version of a newer serena-agent package release on PyPI, if any.
The result is computed only once (on first access) and cached thereafter.
:return: the latest version available on PyPI if it is newer than the running version, else None
def _determine_newer_serena_version(self) -> str | None:
"""
Checks for availability of a newer Serena version on PyPI and stores it in self._newer_serena_version if found.
"""
try:
# query PyPI for the latest released version
latest_serena_version = PyPIPackageInfo("serena-agent").get_latest_version(timeout_secs=3)
latest_serena_version = PyPIPackageInfo("serena-agent").get_latest_version(timeout_secs=5)
# compare against the running version
latest_version = Version(latest_serena_version)
current_version = Version(self._agent.version)
if not current_version.is_at_least(*latest_version.components):
return latest_serena_version
log.error("Latest available Serena version on PyPI: %s, current version: %s", latest_version, current_version)
if not current_version.is_at_least(*latest_version.components) or True:
self._newer_serena_version = latest_serena_version
except Exception as e:
log.warning("Failed to check for newer Serena version on PyPI: %s", e)
return None
log.info("Failed to check for newer Serena version on PyPI: %s", e)
def _setup_routes(self) -> None:
@self._app.route("/")