autoagents_protocol/
task.rs1use crate::SubmissionId;
2use crate::llm::ImageMime;
3use serde::{Deserialize, Serialize};
4use serde_json::Value;
5use uuid::Uuid;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct Task {
10 pub prompt: String,
11 pub image: Option<(ImageMime, Vec<u8>)>,
12 #[serde(default)]
13 pub system_prompt: Option<String>,
14 pub submission_id: SubmissionId,
15 pub completed: bool,
16 pub result: Option<Value>,
17 #[serde(default)]
19 pub app_meta: Option<Value>,
20}
21
22impl Task {
23 pub fn new<T: Into<String>>(task: T) -> Self {
25 Self {
26 prompt: task.into(),
27 image: None,
28 system_prompt: None,
29 submission_id: Uuid::new_v4(),
30 completed: false,
31 result: None,
32 app_meta: None,
33 }
34 }
35
36 pub fn new_with_image<T: Into<String>>(
38 task: T,
39 image_mime: ImageMime,
40 image_data: Vec<u8>,
41 ) -> Self {
42 Self {
43 prompt: task.into(),
44 image: Some((image_mime, image_data)),
45 system_prompt: None,
46 submission_id: Uuid::new_v4(),
47 completed: false,
48 result: None,
49 app_meta: None,
50 }
51 }
52
53 pub fn with_system_prompt<T: Into<String>>(mut self, prompt: T) -> Self {
54 self.system_prompt = Some(prompt.into());
55 self
56 }
57
58 pub fn with_app_meta(mut self, meta: Value) -> Self {
60 self.app_meta = Some(meta);
61 self
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
70 fn app_meta_roundtrip() {
71 let mut task = Task::new("hello");
72 task.app_meta = Some(serde_json::json!({
73 "session_id": "s1",
74 "chat_id": "c1",
75 "extra": { "nested": [1, 2, 3] },
76 }));
77 let back: Task = serde_json::from_str(&serde_json::to_string(&task).unwrap()).unwrap();
78 let meta = back
79 .app_meta
80 .expect("app_meta preserved across serde roundtrip");
81 assert_eq!(meta.get("session_id").and_then(|v| v.as_str()), Some("s1"));
82 assert_eq!(meta.get("chat_id").and_then(|v| v.as_str()), Some("c1"));
83 assert!(
84 meta.get("extra").is_some(),
85 "arbitrary nested app data preserved"
86 );
87 }
88
89 #[test]
90 fn app_meta_defaults_to_none_when_absent() {
91 let mut v = serde_json::to_value(Task::new("legacy")).unwrap();
93 v.as_object_mut().unwrap().remove("app_meta");
94 let back: Task = serde_json::from_value(v).unwrap();
95 assert!(back.app_meta.is_none());
96 }
97
98 #[test]
99 fn with_app_meta_builder_sets_field() {
100 let task =
101 Task::new("hi").with_app_meta(serde_json::json!({"session_id": "s1", "chat_id": "c1"}));
102 let meta = task.app_meta.expect("with_app_meta should set app_meta");
103 assert_eq!(meta.get("session_id").and_then(|v| v.as_str()), Some("s1"));
104 assert_eq!(meta.get("chat_id").and_then(|v| v.as_str()), Some("c1"));
105 }
106}