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 pack_id: Option<String>,
13 #[serde(default, skip_serializing_if = "Option::is_none")]
14 flow_id: Option<String>,
15 #[serde(default, skip_serializing_if = "Option::is_none")]
16 flow_type: Option<String>,
17 #[serde(default, skip_serializing_if = "Option::is_none")]
18 session_id: Option<String>,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
20 provider_id: Option<String>,
21 #[serde(default, skip_serializing_if = "Option::is_none")]
22 user_id: Option<String>,
23 #[serde(default, skip_serializing_if = "Option::is_none")]
24 channel_id: Option<String>,
25 #[serde(default, skip_serializing_if = "Option::is_none")]
26 conversation_id: Option<String>,
27 #[serde(default)]
28 payload: Value,
29}
30
31#[derive(Clone, Debug, Serialize, Deserialize, Default)]
32#[serde(tag = "kind", rename_all = "snake_case")]
33pub enum ActivityKind {
34 #[default]
36 Message,
37 Custom {
39 action: String,
40 #[serde(default, skip_serializing_if = "Option::is_none")]
41 flow_type: Option<String>,
42 },
43}
44
45impl Activity {
46 pub fn text(text: impl Into<String>) -> Self {
48 Self {
49 kind: ActivityKind::Message,
50 tenant: None,
51 pack_id: None,
52 flow_id: None,
53 flow_type: Some("messaging".into()),
54 session_id: None,
55 provider_id: None,
56 user_id: None,
57 channel_id: None,
58 conversation_id: None,
59 payload: json!({ "text": text.into() }),
60 }
61 }
62
63 pub fn custom(action: impl Into<String>, payload: Value) -> Self {
65 Self {
66 kind: ActivityKind::Custom {
67 action: action.into(),
68 flow_type: None,
69 },
70 tenant: None,
71 pack_id: None,
72 flow_id: None,
73 flow_type: None,
74 session_id: None,
75 provider_id: None,
76 user_id: None,
77 channel_id: None,
78 conversation_id: None,
79 payload,
80 }
81 }
82
83 pub fn with_tenant(mut self, tenant: impl Into<String>) -> Self {
85 self.tenant = Some(tenant.into());
86 self
87 }
88
89 pub fn with_flow(mut self, flow_id: impl Into<String>) -> Self {
91 self.flow_id = Some(flow_id.into());
92 self
93 }
94
95 pub fn with_pack(mut self, pack_id: impl Into<String>) -> Self {
97 self.pack_id = Some(pack_id.into());
98 self
99 }
100
101 pub fn with_flow_type(mut self, flow_type: impl Into<String>) -> Self {
103 let flow_type = flow_type.into();
104 self.flow_type = Some(flow_type.clone());
105 if let ActivityKind::Custom {
106 flow_type: inner, ..
107 } = &mut self.kind
108 {
109 *inner = Some(flow_type);
110 }
111 self
112 }
113
114 pub fn with_session(mut self, session_id: impl Into<String>) -> Self {
116 self.session_id = Some(session_id.into());
117 self
118 }
119
120 pub fn with_provider(mut self, provider: impl Into<String>) -> Self {
122 self.provider_id = Some(provider.into());
123 self
124 }
125
126 pub fn from_user(mut self, user: impl Into<String>) -> Self {
128 self.user_id = Some(user.into());
129 self
130 }
131
132 pub fn in_channel(mut self, channel: impl Into<String>) -> Self {
134 self.channel_id = Some(channel.into());
135 self
136 }
137
138 pub fn in_conversation(mut self, conversation: impl Into<String>) -> Self {
140 self.conversation_id = Some(conversation.into());
141 self
142 }
143
144 pub fn tenant(&self) -> Option<&str> {
146 self.tenant.as_deref()
147 }
148
149 pub fn pack_id(&self) -> Option<&str> {
151 self.pack_id.as_deref()
152 }
153
154 pub fn flow_id(&self) -> Option<&str> {
156 self.flow_id.as_deref()
157 }
158
159 pub fn flow_type(&self) -> Option<&str> {
161 self.flow_type
162 .as_deref()
163 .or_else(|| self.kind.flow_type_hint())
164 }
165
166 pub fn session_id(&self) -> Option<&str> {
168 self.session_id.as_deref()
169 }
170
171 pub fn provider_id(&self) -> Option<&str> {
173 self.provider_id.as_deref()
174 }
175
176 pub fn user(&self) -> Option<&str> {
178 self.user_id.as_deref()
179 }
180
181 pub fn channel(&self) -> Option<&str> {
183 self.channel_id.as_deref()
184 }
185
186 pub fn conversation(&self) -> Option<&str> {
188 self.conversation_id.as_deref()
189 }
190
191 pub fn payload(&self) -> &Value {
193 &self.payload
194 }
195
196 pub(crate) fn action(&self) -> Option<&str> {
197 self.kind.action_hint()
198 }
199
200 pub(crate) fn into_payload(self) -> Value {
201 self.payload
202 }
203
204 pub(crate) fn ensure_tenant(mut self, tenant: &str) -> Self {
205 if self.tenant.is_none() {
206 self.tenant = Some(tenant.to_string());
207 }
208 self
209 }
210
211 pub(crate) fn from_output(payload: Value, tenant: &str) -> Self {
212 Activity::custom("response", payload).ensure_tenant(tenant)
213 }
214}
215
216impl ActivityKind {
217 fn flow_type_hint(&self) -> Option<&str> {
218 match self {
219 ActivityKind::Message => Some("messaging"),
220 ActivityKind::Custom { flow_type, .. } => flow_type.as_deref(),
221 }
222 }
223
224 fn action_hint(&self) -> Option<&str> {
225 match self {
226 ActivityKind::Message => Some("messaging"),
227 ActivityKind::Custom { action, .. } => Some(action.as_str()),
228 }
229 }
230}