Skip to main content

systemprompt_models/notifications/
notification.rs

1//! The per-recipient notification as the API serves it.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use std::fmt;
7use std::str::FromStr;
8
9use chrono::{DateTime, Utc};
10use schemars::JsonSchema;
11use serde::{Deserialize, Serialize};
12use systemprompt_identifiers::{NotificationId, NotificationStreamId, UserId};
13
14use super::action::ActionPrompt;
15use super::attention::{Attention, AttentionReason, UnknownNotificationValue};
16use super::cursor::KeysetCursor;
17use super::kind::NotificationKind;
18use super::subject::SubjectRef;
19
20/// Where a notification stands on its way to its delivery channels.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
22#[serde(rename_all = "lowercase")]
23pub enum DeliveryState {
24    Pending,
25    Delivered,
26    Held,
27}
28
29impl DeliveryState {
30    #[must_use]
31    pub const fn as_str(self) -> &'static str {
32        match self {
33            Self::Pending => "pending",
34            Self::Delivered => "delivered",
35            Self::Held => "held",
36        }
37    }
38}
39
40impl fmt::Display for DeliveryState {
41    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42        f.write_str(self.as_str())
43    }
44}
45
46impl FromStr for DeliveryState {
47    type Err = UnknownNotificationValue;
48
49    fn from_str(s: &str) -> Result<Self, Self::Err> {
50        match s {
51            "pending" => Ok(Self::Pending),
52            "delivered" => Ok(Self::Delivered),
53            "held" => Ok(Self::Held),
54            other => Err(UnknownNotificationValue::new("delivery_state", other)),
55        }
56    }
57}
58
59/// One recipient's notification row.
60#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
61pub struct Notification {
62    pub id: NotificationId,
63    pub recipient: UserId,
64    pub kind: NotificationKind,
65    pub stream: Option<NotificationStreamId>,
66    pub actor: UserId,
67    pub actor_display: Option<String>,
68    pub actor_is_agent: bool,
69    pub via_agent: Option<String>,
70    pub subjects: Vec<SubjectRef>,
71    pub attention: Attention,
72    pub attention_reason: AttentionReason,
73    pub action: ActionPrompt,
74    pub excerpt: Option<String>,
75    pub coalesce_count: i32,
76    pub first_event_at: DateTime<Utc>,
77    pub last_event_at: DateTime<Utc>,
78    pub created_at: DateTime<Utc>,
79    pub read_at: Option<DateTime<Utc>>,
80    pub escalated_from: Option<Attention>,
81    pub escalation_note: Option<String>,
82    pub held_until: Option<DateTime<Utc>>,
83    pub delivery_state: DeliveryState,
84}
85
86/// One page of a reader's feed.
87#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
88pub struct NotificationPage {
89    pub notifications: Vec<Notification>,
90    pub next_cursor: Option<KeysetCursor>,
91    pub unread: i64,
92    pub unread_capped: bool,
93}
94
95/// Request body marking notifications read: the listed ids, or all of them.
96#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
97pub struct MarkRead {
98    #[serde(default)]
99    pub ids: Vec<NotificationId>,
100    #[serde(default)]
101    pub all: bool,
102}
103
104/// Request body recording the listed notifications as seen.
105#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
106pub struct MarkSeen {
107    pub ids: Vec<NotificationId>,
108}
109
110/// Request body raising a notification to human attention.
111#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
112pub struct Escalate {
113    #[serde(default)]
114    pub note: Option<String>,
115}