Skip to main content

pmcp/server/workflow/
into_prompt_content.rs

1//! Conversion trait for ergonomic prompt content construction
2
3use super::{
4    handles::{ResourceHandle, ToolHandle},
5    prompt_content::PromptContent,
6};
7
8/// Convert various types into `PromptContent` (internal type)
9/// This is the developer-facing API
10pub trait IntoPromptContent {
11    /// Convert self into `PromptContent`
12    fn into_prompt_content(self) -> PromptContent;
13}
14
15// Implement for handles (strict mode)
16impl IntoPromptContent for ToolHandle {
17    fn into_prompt_content(self) -> PromptContent {
18        PromptContent::ToolHandle(self)
19    }
20}
21
22impl IntoPromptContent for ResourceHandle {
23    fn into_prompt_content(self) -> PromptContent {
24        PromptContent::ResourceHandle(self)
25    }
26}
27
28// Implement for strings (loose mode)
29impl IntoPromptContent for String {
30    fn into_prompt_content(self) -> PromptContent {
31        PromptContent::Text(self)
32    }
33}
34
35impl IntoPromptContent for &str {
36    fn into_prompt_content(self) -> PromptContent {
37        PromptContent::Text(self.to_string())
38    }
39}
40
41// Implement for images (tuple of data and mime_type)
42impl IntoPromptContent for (String, String) {
43    fn into_prompt_content(self) -> PromptContent {
44        PromptContent::Image {
45            data: self.0,
46            mime_type: self.1,
47        }
48    }
49}
50
51// Blanket From implementation for ergonomics
52impl<T: IntoPromptContent> From<T> for PromptContent {
53    fn from(value: T) -> Self {
54        value.into_prompt_content()
55    }
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn test_into_prompt_content_string() {
64        let content: PromptContent = "Hello".into();
65        assert!(matches!(content, PromptContent::Text(_)));
66    }
67
68    #[test]
69    fn test_into_prompt_content_tool_handle() {
70        let handle = ToolHandle::new("greet");
71        let content: PromptContent = handle.into();
72        assert!(matches!(content, PromptContent::ToolHandle(_)));
73    }
74
75    #[test]
76    fn test_into_prompt_content_resource_handle() {
77        let handle = ResourceHandle::new("resource://test/path").unwrap();
78        let content: PromptContent = handle.into();
79        assert!(matches!(content, PromptContent::ResourceHandle(_)));
80    }
81
82    #[test]
83    fn test_into_prompt_content_image() {
84        let image = ("base64data".to_string(), "image/png".to_string());
85        let content: PromptContent = image.into();
86        assert!(matches!(content, PromptContent::Image { .. }));
87    }
88
89    #[test]
90    fn test_trait_usage() {
91        fn takes_content(content: impl IntoPromptContent) -> PromptContent {
92            content.into_prompt_content()
93        }
94
95        let text_content = takes_content("text");
96        assert!(matches!(text_content, PromptContent::Text(_)));
97
98        let tool_content = takes_content(ToolHandle::new("greet"));
99        assert!(matches!(tool_content, PromptContent::ToolHandle(_)));
100    }
101}