Skip to main content

objectiveai_sdk/agent/completions/message/
developer_message.rs

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