update checker
frdel committed
Nov 17, 2025 at 11:32 UTC
269aafdc284e8d7c896e97609aff87ebfc14d2b0
5 files changed
+114
-7
python/api/message.py
+7
-1
@@ -1,7 +1,7 @@
1
from agent import AgentContext, UserMessage
2
from python.helpers.api import ApiHandler, Request, Response
3
4
-from python.helpers import files
4
+from python.helpers import files, extension
5
import os
6
from werkzeug.utils import secure_filename
7
from python.helpers.defer import DeferredTask
@@ -55,6 +55,12 @@ class Message(ApiHandler):
55
# Obtain agent context
56
context = self.use_context(ctxid)
57
58
+ # call extension point, alow it to modify data
59
+ data = { "message": message, "attachment_paths": attachment_paths }
60
+ await extension.call_extensions("user_message_ui", agent=context.get_agent(), data=data)
61
+ message = data.get("message", "")
62
+ attachment_paths = data.get("attachment_paths", [])
63
+
64
# Store attachments in agent data
65
# context.agent0.set_data("attachments", attachment_paths)
66
python/extensions/user_message_ui/_10_update_check.py
new
+58
@@ -0,0 +1,58 @@
1
+from python.helpers import notification
2
+from python.helpers.extension import Extension
3
+from agent import LoopData
4
+from python.helpers import settings, update_check
5
+import datetime
6
+
7
+
8
+# check for newer versions of A0 available and send notification
9
+# check after user message is sent from UI, not API, MCP etc. (user is active and can see the notification)
10
+# do not check too often, use cooldown
11
+# do not notify too often unless there's a different notification
12
+
13
+last_check = datetime.datetime.fromtimestamp(0)
14
+check_cooldown_seconds = 60
15
+last_notification_id = ""
16
+last_notification_time = datetime.datetime.fromtimestamp(0)
17
+notification_cooldown_seconds = 60 * 60 * 24
18
+
19
+class UpdateCheck(Extension):
20
+
21
+ async def execute(self, loop_data: LoopData = LoopData(), text: str = "", **kwargs):
22
+ try:
23
+ global last_check, last_notification_id, last_notification_time
24
+
25
+ # first check if update check is enabled
26
+ current_settings = settings.get_settings()
27
+ if not current_settings["update_check_enabled"]:
28
+ return
29
+
30
+ # check if cooldown has passed
31
+ if (datetime.datetime.now() - last_check).total_seconds() < check_cooldown_seconds:
32
+ return
33
+ last_check = datetime.datetime.now()
34
+
35
+ # check for updates
36
+ version = await update_check.check_version()
37
+
38
+ # if the user should update, send notification
39
+ if notif := version.get("notification"):
40
+ if notif.get("id") != last_notification_id or (datetime.datetime.now() - last_notification_time).total_seconds() > notification_cooldown_seconds:
41
+ last_notification_id = notif.get("id")
42
+ last_notification_time = datetime.datetime.now()
43
+ self.send_notification(notif)
44
+ except Exception as e:
45
+ pass # no need to log if the update server is inaccessible
46
+
47
+
48
+ def send_notification(self, notif):
49
+ notifs = self.agent.context.get_notification_manager()
50
+ notifs.send_notification(
51
+ title=notif.get("title", "Newer version available"),
52
+ message=notif.get("message", "A newer version of Agent Zero is available. Please update to the latest version."),
53
+ type=notif.get("type", "info"),
54
+ detail=notif.get("detail", ""),
55
+ display_time=notif.get("display_time", 10),
56
+ group=notif.get("group", "update_check"),
57
+ priority=notif.get("priority", notification.NotificationPriority.NORMAL),
58
+ )
python/helpers/git.py
+8
-1
@@ -47,4 +47,11 @@ def get_git_info():
47
"version": version
48
}
49
50
- return git_info
\ No newline at end of file
50
+ return git_info
51
+
52
+def get_version():
53
+ try:
54
+ git_info = get_git_info()
55
+ return str(git_info.get("short_tag", "")).strip() or "unknown"
56
+ except Exception:
57
+ return "unknown"
\ No newline at end of file
python/helpers/settings.py
+26
-5
@@ -111,6 +111,8 @@ class Settings(TypedDict):
111
# LiteLLM global kwargs applied to all model calls
112
litellm_global_kwargs: dict[str, Any]
113
114
+ update_check_enabled: bool
115
+
116
class PartialSettings(Settings, total=False):
117
pass
118
@@ -1217,6 +1219,27 @@ def convert_out(settings: Settings) -> SettingsOutput:
1219
"tab": "external",
1220
}
1221
1222
+ # update checker section
1223
+ update_checker_fields: list[SettingsField] = []
1224
+
1225
+ update_checker_fields.append(
1226
+ {
1227
+ "id": "update_check_enabled",
1228
+ "title": "Enable Update Checker",
1229
+ "description": "Enable update checker to notify about newer versions of Agent Zero.",
1230
+ "type": "switch",
1231
+ "value": settings["update_check_enabled"],
1232
+ }
1233
+ )
1234
+
1235
+ update_checker_section: SettingsSection = {
1236
+ "id": "update_checker",
1237
+ "title": "Update Checker",
1238
+ "description": "Update checker periodically checks for new releases of Agent Zero and will notify when an update is recommended.<br>No personal data is sent to the update server, only randomized+anonymized unique ID and current version number, which help us evaluate the importance of the update in case of critical bug fixes etc.",
1239
+ "fields": update_checker_fields,
1240
+ "tab": "external",
1241
+ }
1242
+
1243
# Backup & Restore section
1244
backup_fields: list[SettingsField] = []
1245
@@ -1269,6 +1292,7 @@ def convert_out(settings: Settings) -> SettingsOutput:
1292
mcp_server_section,
1293
a2a_section,
1294
external_api_section,
1295
+ update_checker_section,
1296
backup_section,
1297
dev_section,
1298
# code_exec_section,
@@ -1502,6 +1526,7 @@ def get_default_settings() -> Settings:
1526
variables="",
1527
secrets="",
1528
litellm_global_kwargs={},
1529
+ update_check_enabled=True,
1530
)
1531
1532
@@ -1706,8 +1731,4 @@ def create_auth_token() -> str:
1731
1732
1733
def _get_version():
1709
- try:
1710
- git_info = git.get_git_info()
1711
- return str(git_info.get("short_tag", "")).strip() or "unknown"
1712
- except Exception:
1713
- return "unknown"
1734
+ return git.get_version()
python/helpers/update_check.py
new
+15
@@ -0,0 +1,15 @@
1
+from python.helpers import git, runtime
2
+import hashlib
3
+
4
+async def check_version():
5
+ import httpx
6
+
7
+ current_version = git.get_version()
8
+ anonymized_id = hashlib.sha256(runtime.get_persistent_id().encode()).hexdigest()[:20]
9
+
10
+ url = "https://api.agent-zero.ai/a0-update-check"
11
+ payload = {"current_version": current_version, "anonymized_id": anonymized_id}
12
+ async with httpx.AsyncClient() as client:
13
+ response = await client.post(url, json=payload)
14
+ version = response.json()
15
+ return version
\ No newline at end of file