mirror of
https://github.com/agent0ai/agent-zero.git
synced 2026-05-17 04:01:13 +00:00
Restyle Settings and standard modals around a streamlined left-rail layout, clearer section hierarchy, advanced settings disclosures, and stronger update states. Add persistent update visibility with quieter once-daily update notifications, plus Remote Link and Space Agent actions in the canvas rail. Refresh the tunnel experience as a normal Remote Link modal with clearer copy, QR/mobile affordances, and safer state handling.
105 lines
3.9 KiB
Python
105 lines
3.9 KiB
Python
from helpers import notification
|
|
from helpers.extension import Extension
|
|
from agent import LoopData
|
|
from helpers import files, settings, update_check
|
|
import datetime
|
|
import json
|
|
|
|
|
|
# check for newer versions of A0 available and send notification
|
|
# check after user message is sent from UI, not API, MCP etc. (user is active and can see the notification)
|
|
# do not check too often, use cooldown
|
|
# do not notify too often
|
|
|
|
last_check = datetime.datetime.fromtimestamp(0)
|
|
check_cooldown_seconds = 60
|
|
last_notification_id = None
|
|
last_notification_time = datetime.datetime.fromtimestamp(0)
|
|
notification_cooldown_seconds = 60 * 60 * 24
|
|
notification_state_file = "usr/update-check-state.json"
|
|
|
|
|
|
def _load_notification_state() -> dict:
|
|
try:
|
|
return json.loads(files.read_file(notification_state_file))
|
|
except Exception:
|
|
return {}
|
|
|
|
|
|
def _parse_timestamp(value: str | None) -> datetime.datetime | None:
|
|
if not value:
|
|
return None
|
|
try:
|
|
parsed = datetime.datetime.fromisoformat(value)
|
|
except ValueError:
|
|
return None
|
|
if parsed.tzinfo:
|
|
return parsed.astimezone(datetime.timezone.utc).replace(tzinfo=None)
|
|
return parsed
|
|
|
|
|
|
def _remember_notification(notif: dict, now: datetime.datetime):
|
|
state = {
|
|
"last_notification_at": now.replace(tzinfo=datetime.timezone.utc).isoformat(),
|
|
"last_notification_id": notif.get("id") or "",
|
|
"last_notification_group": notif.get("group", "update_check"),
|
|
}
|
|
files.write_file(notification_state_file, json.dumps(state, indent=2))
|
|
|
|
|
|
class UpdateCheck(Extension):
|
|
|
|
async def execute(self, loop_data: LoopData = LoopData(), text: str = "", **kwargs):
|
|
if not self.agent:
|
|
return
|
|
|
|
try:
|
|
global last_check, last_notification_id, last_notification_time
|
|
|
|
# first check if update check is enabled
|
|
current_settings = settings.get_settings()
|
|
if not current_settings["update_check_enabled"]:
|
|
return
|
|
|
|
# check if cooldown has passed
|
|
if (datetime.datetime.now() - last_check).total_seconds() < check_cooldown_seconds:
|
|
return
|
|
last_check = datetime.datetime.now()
|
|
|
|
# check for updates
|
|
version = await update_check.check_version()
|
|
|
|
# if the user should update, send notification
|
|
if notif := version.get("notification"):
|
|
now = datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
|
|
stored_state = _load_notification_state()
|
|
stored_notification_time = _parse_timestamp(stored_state.get("last_notification_at"))
|
|
effective_notification_time = stored_notification_time or last_notification_time
|
|
|
|
if (now - effective_notification_time).total_seconds() > notification_cooldown_seconds:
|
|
last_notification_id = notif.get("id")
|
|
last_notification_time = now
|
|
try:
|
|
_remember_notification(notif, now)
|
|
except Exception:
|
|
pass
|
|
self.send_notification(notif)
|
|
except Exception as e:
|
|
pass # no need to log if the update server is inaccessible
|
|
|
|
|
|
def send_notification(self, notif):
|
|
if not self.agent:
|
|
return
|
|
|
|
notifs = self.agent.context.get_notification_manager()
|
|
notifs.send_notification(
|
|
title=notif.get("title", "Newer version available"),
|
|
message=notif.get("message", "A newer version of Agent Zero is available. Please update to the latest version."),
|
|
type=notif.get("type", "info"),
|
|
detail=notif.get("detail", ""),
|
|
display_time=notif.get("display_time", 10),
|
|
group=notif.get("group", "update_check"),
|
|
priority=notif.get("priority", notification.NotificationPriority.NORMAL),
|
|
id=notif.get("id", "update_check_available"),
|
|
)
|