greentic_runner_host/
activity.rs1use serde::{Deserialize, Serialize};
2use serde_json::{Value, json};
3
4#[derive(Clone, Debug, Serialize, Deserialize)]
6pub struct Activity {
7 #[serde(default)]
8 pub(crate) kind: ActivityKind,
9 #[serde(default, skip_serializing_if = "Option::is_none")]
10 tenant: Option<String>,
11 #[serde(default, skip_serializing_if = "Option::is_none")]
12 flow_id: Option<String>,
13 #[serde(default, skip_serializing_if = "Option::is_none")]
14 flow_type: Option<String>,
15 #[serde(default, skip_serializing_if = "Option::is_none")]
16 session_id: Option<String>,
17 #[serde(default, skip_serializing_if = "Option::is_none")]
18 provider_id: Option<String>,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
20 user_id: Option<String>,
21 #[serde(default, skip_serializing_if = "Option::is_none")]
22 channel_id: Option<String>,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
24 conversation_id: Option<String>,
25 #[serde(default)]
26 payload: Value,
27}
28
29#[derive(Clone, Debug, Serialize, Deserialize, Default)]
30#[serde(tag = "kind", rename_all = "snake_case")]
31pub enum ActivityKind {
32 #[default]
34 Message,
35 Custom {
37 action: String,
38 #[serde(default, skip_serializing_if = "Option::is_none")]
39 flow_type: Option<String>,
40 },
41}
42
43impl Activity {
44 pub fn text(text: impl Into<String>) -> Self {
46 Self {
47 kind: ActivityKind::Message,
48 tenant: None,
49 flow_id: None,
50 flow_type: Some("messaging".into()),
51 session_id: None,
52 provider_id: None,
53 user_id: None,
54 channel_id: None,
55 conversation_id: None,
56 payload: json!({ "text": text.into() }),
57 }
58 }
59
60 pub fn custom(action: impl Into<String>, payload: Value) -> Self {
62 Self {
63 kind: ActivityKind::Custom {
64 action: action.into(),
65 flow_type: None,
66 },
67 tenant: None,
68 flow_id: None,
69 flow_type: None,
70 session_id: None,
71 provider_id: None,
72 user_id: None,
73 channel_id: None,
74 conversation_id: None,
75 payload,
76 }
77 }
78
79 pub fn with_tenant(mut self, tenant: impl Into<String>) -> Self {
81 self.tenant = Some(tenant.into());
82 self
83 }
84
85 pub fn with_flow(mut self, flow_id: impl Into<String>) -> Self {
87 self.flow_id = Some(flow_id.into());
88 self
89 }
90
91 pub fn with_flow_type(mut self, flow_type: impl Into<String>) -> Self {
93 let flow_type = flow_type.into();
94 self.flow_type = Some(flow_type.clone());
95 if let ActivityKind::Custom {
96 flow_type: inner, ..
97 } = &mut self.kind
98 {
99 *inner = Some(flow_type);
100 }
101 self
102 }
103
104 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
106 self.session_id = Some(session_id.into());
107 self
108 }
109
110 pub fn with_provider(mut self, provider: impl Into<String>) -> Self {
112 self.provider_id = Some(provider.into());
113 self
114 }
115
116 pub fn from_user(mut self, user: impl Into<String>) -> Self {
118 self.user_id = Some(user.into());
119 self
120 }
121
122 pub fn in_channel(mut self, channel: impl Into<String>) -> Self {
124 self.channel_id = Some(channel.into());
125 self
126 }
127
128 pub fn in_conversation(mut self, conversation: impl Into<String>) -> Self {
130 self.conversation_id = Some(conversation.into());
131 self
132 }
133
134 pub fn tenant(&self) -> Option<&str> {
136 self.tenant.as_deref()
137 }
138
139 pub fn flow_id(&self) -> Option<&str> {
141 self.flow_id.as_deref()
142 }
143
144 pub fn flow_type(&self) -> Option<&str> {
146 self.flow_type
147 .as_deref()
148 .or_else(|| self.kind.flow_type_hint())
149 }
150
151 pub fn session_id(&self) -> Option<&str> {
153 self.session_id.as_deref()
154 }
155
156 pub fn provider_id(&self) -> Option<&str> {
158 self.provider_id.as_deref()
159 }
160
161 pub fn user(&self) -> Option<&str> {
163 self.user_id.as_deref()
164 }
165
166 pub fn channel(&self) -> Option<&str> {
168 self.channel_id.as_deref()
169 }
170
171 pub fn conversation(&self) -> Option<&str> {
173 self.conversation_id.as_deref()
174 }
175
176 pub fn payload(&self) -> &Value {
178 &self.payload
179 }
180
181 pub(crate) fn action(&self) -> Option<&str> {
182 self.kind.action_hint()
183 }
184
185 pub(crate) fn into_payload(self) -> Value {
186 self.payload
187 }
188
189 pub(crate) fn ensure_tenant(mut self, tenant: &str) -> Self {
190 if self.tenant.is_none() {
191 self.tenant = Some(tenant.to_string());
192 }
193 self
194 }
195
196 pub(crate) fn from_output(payload: Value, tenant: &str) -> Self {
197 Activity::custom("response", payload).ensure_tenant(tenant)
198 }
199}
200
201impl ActivityKind {
202 fn flow_type_hint(&self) -> Option<&str> {
203 match self {
204 ActivityKind::Message => Some("messaging"),
205 ActivityKind::Custom { flow_type, .. } => flow_type.as_deref(),
206 }
207 }
208
209 fn action_hint(&self) -> Option<&str> {
210 match self {
211 ActivityKind::Message => Some("messaging"),
212 ActivityKind::Custom { action, .. } => Some(action.as_str()),
213 }
214 }
215}