Skip to main content

objectiveai_sdk/agent/completions/message/
user_message.rs

1//! User message types.
2
3use super::rich_content::{RichContent, RichContentExpression};
4use crate::functions;
5use functions::expression::{
6    ExpressionError, FromStarlarkValue, WithExpression,
7};
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10use starlark::values::dict::DictRef as StarlarkDictRef;
11use starlark::values::{UnpackValue, Value as StarlarkValue};
12
13/// A user message from the end user.
14#[derive(
15    Debug,
16    Clone,
17    PartialEq,
18    Serialize,
19    Deserialize,
20    JsonSchema,
21    arbitrary::Arbitrary,
22)]
23#[schemars(rename = "agent.completions.message.UserMessage")]
24pub struct UserMessage {
25    /// The message content (supports text, images, audio, video, files).
26    pub content: RichContent,
27}
28
29impl UserMessage {
30    pub fn push(&mut self, other: &UserMessage) {
31        self.content.push(&other.content);
32    }
33
34    /// Prepares the message by normalizing content.
35    pub fn prepare(&mut self) {
36        self.content.prepare();
37    }
38}
39
40impl FromStarlarkValue for UserMessage {
41    fn from_starlark_value(
42        value: &StarlarkValue,
43    ) -> Result<Self, ExpressionError> {
44        let dict = StarlarkDictRef::from_value(*value).ok_or_else(|| {
45            ExpressionError::StarlarkConversionError(
46                "UserMessage: expected dict".into(),
47            )
48        })?;
49        let mut content = None;
50        for (k, v) in dict.iter() {
51            let key = <&str as UnpackValue>::unpack_value(k)
52                .map_err(|e| {
53                    ExpressionError::StarlarkConversionError(e.to_string())
54                })?
55                .ok_or_else(|| {
56                    ExpressionError::StarlarkConversionError(
57                        "UserMessage: expected string key".into(),
58                    )
59                })?;
60            match key {
61                "content" => {
62                    content = Some(RichContent::from_starlark_value(&v)?)
63                }
64                _ => {}
65            }
66        }
67        Ok(UserMessage {
68            content: content.ok_or_else(|| {
69                ExpressionError::StarlarkConversionError(
70                    "UserMessage: missing content".into(),
71                )
72            })?,
73        })
74    }
75}
76
77/// Expression variant of [`UserMessage`] for dynamic content.
78#[derive(
79    Debug,
80    Clone,
81    PartialEq,
82    Serialize,
83    Deserialize,
84    JsonSchema,
85    arbitrary::Arbitrary,
86)]
87#[schemars(rename = "agent.completions.message.UserMessageExpression")]
88pub struct UserMessageExpression {
89    /// The message content expression.
90    pub content: functions::expression::WithExpression<RichContentExpression>,
91}
92
93impl UserMessageExpression {
94    /// Compiles the expression into a concrete [`UserMessage`].
95    pub fn compile(
96        self,
97        params: &functions::expression::Params,
98    ) -> Result<UserMessage, functions::expression::ExpressionError> {
99        let content = self.content.compile_one(params)?.compile(params)?;
100        Ok(UserMessage { content })
101    }
102}
103
104impl FromStarlarkValue for UserMessageExpression {
105    fn from_starlark_value(
106        value: &StarlarkValue,
107    ) -> Result<Self, ExpressionError> {
108        let dict = StarlarkDictRef::from_value(*value).ok_or_else(|| {
109            ExpressionError::StarlarkConversionError(
110                "UserMessageExpression: expected dict".into(),
111            )
112        })?;
113        let mut content = None;
114        for (k, v) in dict.iter() {
115            let key = <&str as UnpackValue>::unpack_value(k)
116                .map_err(|e| {
117                    ExpressionError::StarlarkConversionError(e.to_string())
118                })?
119                .ok_or_else(|| {
120                    ExpressionError::StarlarkConversionError(
121                        "UserMessageExpression: expected string key".into(),
122                    )
123                })?;
124            match key {
125                "content" => {
126                    content = Some(WithExpression::Value(
127                        RichContentExpression::from_starlark_value(&v)?,
128                    ))
129                }
130                _ => {}
131            }
132        }
133        Ok(UserMessageExpression {
134            content: content.ok_or_else(|| {
135                ExpressionError::StarlarkConversionError(
136                    "UserMessageExpression: missing content".into(),
137                )
138            })?,
139        })
140    }
141}