systemprompt_agent/services/
context.rs1use crate::services::a2a_server::processing::message::content::extract_message_content;
8use crate::services::shared::{AgentServiceError, Result};
9use systemprompt_models::text::truncate_with_ellipsis;
10use systemprompt_models::{AiMessage, MessageRole};
11
12use crate::models::a2a::Artifact;
13use crate::repository::task::TaskRepository;
14
15#[derive(Debug, Clone)]
16pub struct ContextService {
17 task_repo: TaskRepository,
18}
19
20impl ContextService {
21 #[must_use]
22 pub const fn new(task_repo: TaskRepository) -> Self {
23 Self { task_repo }
24 }
25
26 pub async fn load_conversation_history(
27 &self,
28 context_id: &systemprompt_identifiers::ContextId,
29 ) -> Result<Vec<AiMessage>> {
30 let tasks = self
31 .task_repo
32 .list_tasks_by_context(context_id)
33 .await
34 .map_err(|e| {
35 AgentServiceError::Internal(format!("Failed to load conversation history: {}", e))
36 })?;
37
38 let mut history_messages = Vec::new();
39
40 for task in tasks {
41 if let Some(task_history) = task.history {
42 for msg in task_history {
43 let (text, parts) = extract_message_content(&msg);
44 if text.is_empty() && parts.is_empty() {
45 continue;
46 }
47
48 let role = match msg.role {
49 crate::models::a2a::MessageRole::User => MessageRole::User,
50 crate::models::a2a::MessageRole::Agent => MessageRole::Assistant,
51 };
52
53 history_messages.push(AiMessage {
54 role,
55 content: text,
56 parts,
57 });
58 }
59 }
60
61 if let Some(artifacts) = task.artifacts {
62 for artifact in artifacts {
63 let artifact_content = Self::serialize_artifact_for_context(&artifact);
64 history_messages.push(AiMessage {
65 role: MessageRole::Assistant,
66 content: artifact_content,
67 parts: Vec::new(),
68 });
69 }
70 }
71 }
72
73 Ok(history_messages)
74 }
75
76 fn serialize_artifact_for_context(artifact: &Artifact) -> String {
77 let artifact_name = artifact.title.as_deref().unwrap_or("unnamed");
78
79 let mut content = format!(
80 "[Artifact: {} (type: {}, id: {})]",
81 artifact_name, artifact.metadata.artifact_type, artifact.id
82 );
83
84 if let Some(description) = &artifact.description
85 && !description.is_empty()
86 {
87 let truncated = truncate_with_ellipsis(description, 300);
88 content.push_str(&format!("\n{truncated}"));
89 }
90
91 content
92 }
93}