File size: 5,250 Bytes
8d1819a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
from dataclasses import dataclass
import uuid
from datetime import datetime, timezone, timedelta
from enum import Enum


class NotificationType(Enum):
    INFO = "info"
    SUCCESS = "success"
    WARNING = "warning"
    ERROR = "error"
    PROGRESS = "progress"

class NotificationPriority(Enum):
    NORMAL = 10
    HIGH = 20


@dataclass
class NotificationItem:
    manager: "NotificationManager"
    no: int
    type: NotificationType
    priority: NotificationPriority
    title: str
    message: str
    detail: str  # HTML content for expandable details
    timestamp: datetime
    display_time: int = 3  # Display duration in seconds, default 3 seconds
    read: bool = False
    id: str = ""
    group: str = ""  # Group identifier for grouping related notifications

    def __post_init__(self):
        if not self.id:
            self.id = str(uuid.uuid4())
        # Ensure type is always NotificationType
        if isinstance(self.type, str):
            self.type = NotificationType(self.type)

    def mark_read(self):
        self.read = True
        self.manager._update_item(self.no, read=True)

    def output(self):
        return {
            "no": self.no,
            "id": self.id,
            "type": self.type.value if isinstance(self.type, NotificationType) else self.type,
            "priority": self.priority.value if isinstance(self.priority, NotificationPriority) else self.priority,
            "title": self.title,
            "message": self.message,
            "detail": self.detail,
            "timestamp": self.timestamp.isoformat(),
            "display_time": self.display_time,
            "read": self.read,
            "group": self.group,
        }


class NotificationManager:
    def __init__(self, max_notifications: int = 100):
        self.guid: str = str(uuid.uuid4())
        self.updates: list[int] = []
        self.notifications: list[NotificationItem] = []
        self.max_notifications = max_notifications

    @staticmethod
    def send_notification(
        type: NotificationType,
        priority: NotificationPriority,
        message: str,
        title: str = "",
        detail: str = "",
        display_time: int = 3,
        group: str = "",
    ) -> NotificationItem:
        from agent import AgentContext
        return AgentContext.get_notification_manager().add_notification(
            type, priority, message, title, detail, display_time, group
        )

    def add_notification(
        self,
        type: NotificationType,
        priority: NotificationPriority,
        message: str,
        title: str = "",
        detail: str = "",
        display_time: int = 3,
        group: str = "",
    ) -> NotificationItem:
        # Create notification item
        item = NotificationItem(
            manager=self,
            no=len(self.notifications),
            type=NotificationType(type),
            priority=NotificationPriority(priority),
            title=title,
            message=message,
            detail=detail,
            timestamp=datetime.now(timezone.utc),
            display_time=display_time,
            group=group,
        )

        # Add to notifications
        self.notifications.append(item)
        self.updates.append(item.no)

        # Enforce limit
        self._enforce_limit()

        return item

    def _enforce_limit(self):
        if len(self.notifications) > self.max_notifications:
            # Remove oldest notifications
            to_remove = len(self.notifications) - self.max_notifications
            self.notifications = self.notifications[to_remove:]
            # Adjust notification numbers
            for i, notification in enumerate(self.notifications):
                notification.no = i
            # Adjust updates list
            self.updates = [no - to_remove for no in self.updates if no >= to_remove]

    def get_recent_notifications(self, seconds: int = 30) -> list[NotificationItem]:
        cutoff = datetime.now(timezone.utc) - timedelta(seconds=seconds)
        return [n for n in self.notifications if n.timestamp >= cutoff]

    def output(self, start: int | None = None, end: int | None = None) -> list[dict]:
        if start is None:
            start = 0
        if end is None:
            end = len(self.updates)

        out = []
        seen = set()
        for update in self.updates[start:end]:
            if update not in seen and update < len(self.notifications):
                out.append(self.notifications[update].output())
                seen.add(update)

        return out

    def _update_item(self, no: int, **kwargs):
        if no < len(self.notifications):
            item = self.notifications[no]
            for key, value in kwargs.items():
                if hasattr(item, key):
                    setattr(item, key, value)
            self.updates.append(no)

    def mark_all_read(self):
        for notification in self.notifications:
            notification.read = True

    def clear_all(self):
        self.notifications = []
        self.updates = []
        self.guid = str(uuid.uuid4())

    def get_notifications_by_type(self, type: NotificationType) -> list[NotificationItem]:
        return [n for n in self.notifications if n.type == type]