objectiveai_sdk/agent/completions/message/
mod.rs1mod assistant_message;
7mod developer_message;
8mod file_content;
9mod rich_content;
10mod simple_content;
11mod system_message;
12mod tool_message;
13mod user_message;
14
15pub use assistant_message::*;
16pub use developer_message::*;
17pub use file_content::*;
18pub use rich_content::*;
19pub use simple_content::*;
20pub use system_message::*;
21pub use tool_message::*;
22pub use user_message::*;
23
24#[cfg(test)]
25mod assistant_message_tests;
26
27use crate::functions;
28use functions::expression::{ExpressionError, FromStarlarkValue};
29use schemars::JsonSchema;
30use serde::{Deserialize, Serialize};
31use starlark::values::dict::DictRef as StarlarkDictRef;
32use starlark::values::{UnpackValue, Value as StarlarkValue};
33
34pub mod prompt {
36 use super::Message;
37use schemars::JsonSchema;
38
39 fn is_chain(a: &Message, b: &Message) -> bool {
43 match (a, b) {
44 (Message::Developer(a), Message::Developer(b)) => {
45 !a.has_name() || !b.has_name() || a.name == b.name
46 }
47 (Message::System(a), Message::System(b)) => {
48 !a.has_name() || !b.has_name() || a.name == b.name
49 }
50 (Message::User(a), Message::User(b)) => {
51 !a.has_name() || !b.has_name() || a.name == b.name
52 }
53 _ => false,
54 }
55 }
56
57 fn push(target: &mut Message, other: &Message) {
59 match (target, other) {
60 (Message::Developer(t), Message::Developer(o)) => t.push(o),
61 (Message::System(t), Message::System(o)) => t.push(o),
62 (Message::User(t), Message::User(o)) => t.push(o),
63 _ => unreachable!(),
64 }
65 }
66
67 pub fn prepare(messages: &mut Vec<Message>) {
71 messages.iter_mut().for_each(Message::prepare);
72
73 let has_chain = messages.windows(2).any(|w| is_chain(&w[0], &w[1]));
75 if !has_chain {
76 return;
77 }
78
79 let mut merged = Vec::with_capacity(messages.len());
80 for msg in messages.drain(..) {
81 if let Some(last) = merged.last_mut() {
82 if is_chain(last, &msg) {
83 push(last, &msg);
84 continue;
85 }
86 }
87 merged.push(msg);
88 }
89 *messages = merged;
90
91 prepare(messages);
93 }
94
95 pub fn id(messages: &[Message]) -> String {
97 let mut hasher = twox_hash::XxHash3_128::with_seed(0);
98 hasher.write(serde_json::to_string(messages).unwrap().as_bytes());
99 format!("{:0>22}", base62::encode(hasher.finish_128()))
100 }
101}
102
103#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, arbitrary::Arbitrary)]
105#[serde(tag = "role")]
106#[schemars(rename = "agent.completions.message.Message")]
107pub enum Message {
108 #[schemars(title = "Developer")]
110 #[serde(rename = "developer")]
111 Developer(DeveloperMessage),
112 #[schemars(title = "System")]
114 #[serde(rename = "system")]
115 System(SystemMessage),
116 #[schemars(title = "User")]
118 #[serde(rename = "user")]
119 User(UserMessage),
120 #[schemars(title = "Assistant")]
122 #[serde(rename = "assistant")]
123 Assistant(AssistantMessage),
124 #[schemars(title = "Tool")]
126 #[serde(rename = "tool")]
127 Tool(ToolMessage),
128}
129
130impl Message {
131 pub fn prepare(&mut self) {
136 match self {
137 Message::Developer(msg) => msg.prepare(),
138 Message::System(msg) => msg.prepare(),
139 Message::User(msg) => msg.prepare(),
140 Message::Assistant(msg) => msg.prepare(),
141 Message::Tool(msg) => msg.prepare(),
142 }
143 }
144}
145
146impl FromStarlarkValue for Message {
147 fn from_starlark_value(
148 value: &StarlarkValue,
149 ) -> Result<Self, ExpressionError> {
150 let dict = StarlarkDictRef::from_value(*value).ok_or_else(|| {
151 ExpressionError::StarlarkConversionError(
152 "Message: expected dict".into(),
153 )
154 })?;
155 let mut role = None;
157 for (k, v) in dict.iter() {
158 if let Ok(Some("role")) = <&str as UnpackValue>::unpack_value(k) {
159 role = Some(
160 <&str as UnpackValue>::unpack_value(v)
161 .map_err(|e| {
162 ExpressionError::StarlarkConversionError(
163 e.to_string(),
164 )
165 })?
166 .ok_or_else(|| {
167 ExpressionError::StarlarkConversionError(
168 "Message: expected string role".into(),
169 )
170 })?,
171 );
172 break;
173 }
174 }
175 let role = role.ok_or_else(|| {
176 ExpressionError::StarlarkConversionError(
177 "Message: missing role".into(),
178 )
179 })?;
180 match role {
181 "developer" => DeveloperMessage::from_starlark_value(value)
182 .map(Message::Developer),
183 "system" => {
184 SystemMessage::from_starlark_value(value).map(Message::System)
185 }
186 "user" => {
187 UserMessage::from_starlark_value(value).map(Message::User)
188 }
189 "assistant" => AssistantMessage::from_starlark_value(value)
190 .map(Message::Assistant),
191 "tool" => {
192 ToolMessage::from_starlark_value(value).map(Message::Tool)
193 }
194 _ => Err(ExpressionError::StarlarkConversionError(format!(
195 "Message: unknown role: {}",
196 role
197 ))),
198 }
199 }
200}
201
202#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema, arbitrary::Arbitrary)]
208#[serde(tag = "role")]
209#[schemars(rename = "agent.completions.message.MessageExpression")]
210pub enum MessageExpression {
211 #[schemars(title = "Developer")]
212 #[serde(rename = "developer")]
213 Developer(DeveloperMessageExpression),
214 #[schemars(title = "System")]
215 #[serde(rename = "system")]
216 System(SystemMessageExpression),
217 #[schemars(title = "User")]
218 #[serde(rename = "user")]
219 User(UserMessageExpression),
220 #[schemars(title = "Assistant")]
221 #[serde(rename = "assistant")]
222 Assistant(AssistantMessageExpression),
223 #[schemars(title = "Tool")]
224 #[serde(rename = "tool")]
225 Tool(ToolMessageExpression),
226}
227
228impl MessageExpression {
229 pub fn compile(
238 self,
239 params: &functions::expression::Params,
240 ) -> Result<Message, functions::expression::ExpressionError> {
241 match self {
242 MessageExpression::Developer(msg) => {
243 msg.compile(params).map(Message::Developer)
244 }
245 MessageExpression::System(msg) => {
246 msg.compile(params).map(Message::System)
247 }
248 MessageExpression::User(msg) => {
249 msg.compile(params).map(Message::User)
250 }
251 MessageExpression::Assistant(msg) => {
252 msg.compile(params).map(Message::Assistant)
253 }
254 MessageExpression::Tool(msg) => {
255 msg.compile(params).map(Message::Tool)
256 }
257 }
258 }
259}
260
261impl FromStarlarkValue for MessageExpression {
262 fn from_starlark_value(
263 value: &StarlarkValue,
264 ) -> Result<Self, ExpressionError> {
265 let dict = StarlarkDictRef::from_value(*value).ok_or_else(|| {
266 ExpressionError::StarlarkConversionError(
267 "MessageExpression: expected dict".into(),
268 )
269 })?;
270 let mut role = None;
272 for (k, v) in dict.iter() {
273 if let Ok(Some("role")) = <&str as UnpackValue>::unpack_value(k) {
274 role = Some(
275 <&str as UnpackValue>::unpack_value(v)
276 .map_err(|e| {
277 ExpressionError::StarlarkConversionError(
278 e.to_string(),
279 )
280 })?
281 .ok_or_else(|| {
282 ExpressionError::StarlarkConversionError(
283 "MessageExpression: expected string role"
284 .into(),
285 )
286 })?,
287 );
288 break;
289 }
290 }
291 let role = role.ok_or_else(|| {
292 ExpressionError::StarlarkConversionError(
293 "MessageExpression: missing role".into(),
294 )
295 })?;
296 match role {
297 "developer" => {
298 DeveloperMessageExpression::from_starlark_value(value)
299 .map(MessageExpression::Developer)
300 }
301 "system" => SystemMessageExpression::from_starlark_value(value)
302 .map(MessageExpression::System),
303 "user" => UserMessageExpression::from_starlark_value(value)
304 .map(MessageExpression::User),
305 "assistant" => {
306 AssistantMessageExpression::from_starlark_value(value)
307 .map(MessageExpression::Assistant)
308 }
309 "tool" => ToolMessageExpression::from_starlark_value(value)
310 .map(MessageExpression::Tool),
311 _ => Err(ExpressionError::StarlarkConversionError(format!(
312 "MessageExpression: unknown role: {}",
313 role
314 ))),
315 }
316 }
317}
318
319crate::functions::expression::impl_from_special_unsupported!(MessageExpression,);
320
321impl crate::functions::expression::FromSpecial
322 for Vec<crate::functions::expression::WithExpression<MessageExpression>>
323{
324 fn from_special(
325 _special: &crate::functions::expression::Special,
326 _params: &crate::functions::expression::Params,
327 ) -> Result<Self, crate::functions::expression::ExpressionError> {
328 Err(crate::functions::expression::ExpressionError::UnsupportedSpecial)
329 }
330}