entelix_runnable/
parser.rs1use std::marker::PhantomData;
8
9use entelix_core::ir::{ContentPart, Message};
10use entelix_core::{Error, ExecutionContext, Result};
11use serde::de::DeserializeOwned;
12
13use crate::runnable::Runnable;
14
15pub struct JsonOutputParser<T> {
33 _phantom: PhantomData<fn() -> T>,
34}
35
36impl<T> JsonOutputParser<T> {
37 pub const fn new() -> Self {
40 Self {
41 _phantom: PhantomData,
42 }
43 }
44}
45
46impl<T> Default for JsonOutputParser<T> {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52impl<T> Clone for JsonOutputParser<T> {
53 fn clone(&self) -> Self {
54 *self
55 }
56}
57
58impl<T> Copy for JsonOutputParser<T> {}
59
60#[async_trait::async_trait]
61impl<T> Runnable<Message, T> for JsonOutputParser<T>
62where
63 T: DeserializeOwned + Send + 'static,
64{
65 async fn invoke(&self, input: Message, _ctx: &ExecutionContext) -> Result<T> {
66 let mut text = String::new();
67 for part in &input.content {
68 if let ContentPart::Text { text: t, .. } = part {
69 text.push_str(t);
70 }
71 }
72 if text.is_empty() {
73 return Err(Error::invalid_request(
74 "JsonOutputParser: message contains no text parts",
75 ));
76 }
77 Ok(serde_json::from_str(&text)?)
78 }
79}