1use crate::agent;
7use indexmap::IndexMap;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10use starlark::values::dict::DictRef as StarlarkDictRef;
11use starlark::values::float::UnpackFloat;
12use starlark::values::list::ListRef as StarlarkListRef;
13use starlark::values::{
14 Heap as StarlarkHeap, UnpackValue, Value as StarlarkValue,
15};
16
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, JsonSchema)]
22#[serde(untagged)]
23#[schemars(rename = "functions.expression.InputValue")]
24pub enum InputValue {
25 #[schemars(title = "RichContentPart")]
27 RichContentPart(agent::completions::message::RichContentPart),
28 #[schemars(title = "Object")]
30 Object(IndexMap<String, InputValue>),
31 #[schemars(title = "Array")]
33 Array(Vec<InputValue>),
34 #[schemars(title = "String")]
36 String(String),
37 #[schemars(title = "Integer")]
39 Integer(i64),
40 #[schemars(title = "Number")]
42 Number(f64),
43 #[schemars(title = "Boolean")]
45 Boolean(bool),
46}
47
48impl super::ToStarlarkValue for InputValue {
52 fn to_starlark_value<'v>(
53 &self,
54 heap: &'v StarlarkHeap,
55 ) -> StarlarkValue<'v> {
56 match self {
57 InputValue::String(s) => s.to_starlark_value(heap),
58 InputValue::Integer(i) => i.to_starlark_value(heap),
59 InputValue::Number(f) => f.to_starlark_value(heap),
60 InputValue::Boolean(b) => b.to_starlark_value(heap),
61 InputValue::Object(map) => map.to_starlark_value(heap),
62 InputValue::Array(arr) => arr.to_starlark_value(heap),
63 InputValue::RichContentPart(part) => part.to_starlark_value(heap),
64 }
65 }
66}
67
68impl super::FromStarlarkValue for InputValue {
69 fn from_starlark_value(
70 value: &StarlarkValue,
71 ) -> Result<Self, super::ExpressionError> {
72 if value.is_none() {
73 return Err(super::ExpressionError::StarlarkConversionError(
74 "Input: expected value".into(),
75 ));
76 }
77 if let Ok(Some(b)) = bool::unpack_value(*value) {
78 return Ok(InputValue::Boolean(b));
79 }
80 if let Ok(Some(i)) = i64::unpack_value(*value) {
81 return Ok(InputValue::Integer(i));
82 }
83 if let Ok(Some(UnpackFloat(f))) = UnpackFloat::unpack_value(*value) {
84 return Ok(InputValue::Number(f));
85 }
86 if let Ok(Some(s)) = <&str as UnpackValue>::unpack_value(*value) {
87 return Ok(InputValue::String(s.to_owned()));
88 }
89 if let Some(list) = StarlarkListRef::from_value(*value) {
90 let mut items = Vec::with_capacity(list.len());
91 for v in list.iter() {
92 items.push(InputValue::from_starlark_value(&v)?);
93 }
94 return Ok(InputValue::Array(items));
95 }
96 if let Some(dict) = StarlarkDictRef::from_value(*value) {
97 let mut type_value = None;
99 for (k, v) in dict.iter() {
100 if let Ok(Some("type")) = <&str as UnpackValue>::unpack_value(k)
101 {
102 type_value =
103 <&str as UnpackValue>::unpack_value(v).ok().flatten();
104 break;
105 }
106 }
107 if matches!(
108 type_value,
109 Some(
110 "text"
111 | "image_url"
112 | "input_audio"
113 | "input_video"
114 | "video_url"
115 | "file"
116 )
117 ) {
118 if let Ok(part) = agent::completions::message::RichContentPart::from_starlark_value(value) {
119 return Ok(InputValue::RichContentPart(part));
120 }
121 }
122 let mut map = IndexMap::with_capacity(dict.len());
123 for (k, v) in dict.iter() {
124 let key = <&str as UnpackValue>::unpack_value(k)
125 .map_err(|e| {
126 super::ExpressionError::StarlarkConversionError(
127 e.to_string(),
128 )
129 })?
130 .ok_or_else(|| {
131 super::ExpressionError::StarlarkConversionError(
132 "Input: expected string key".into(),
133 )
134 })?
135 .to_owned();
136 map.insert(key, InputValue::from_starlark_value(&v)?);
137 }
138 return Ok(InputValue::Object(map));
139 }
140 Err(super::ExpressionError::StarlarkConversionError(format!(
141 "Input: unsupported type: {}",
142 value.get_type()
143 )))
144 }
145}
146
147impl super::FromSpecial for InputValue {
148 fn from_special(
149 special: &super::Special,
150 params: &super::Params,
151 ) -> Result<Self, super::ExpressionError> {
152 match special {
153 super::Special::Input => {
154 let input = match params {
155 super::Params::Owned(o) => &o.input,
156 super::Params::Ref(r) => r.input,
157 };
158 Ok(input.clone())
159 }
160 super::Special::InputItemsOptionalContextMerge => {
161 let input = match params {
165 super::Params::Owned(o) => &o.input,
166 super::Params::Ref(r) => r.input,
167 };
168 let InputValue::Array(arr) = input else {
169 return Err(super::ExpressionError::UnsupportedSpecial);
170 };
171 let mut merged_items = Vec::new();
172 let mut context = None;
173 for (i, elem) in arr.iter().enumerate() {
174 let InputValue::Object(obj) = elem else {
175 return Err(super::ExpressionError::UnsupportedSpecial);
176 };
177 if let Some(InputValue::Array(items)) = obj.get("items") {
178 merged_items.extend(items.iter().cloned());
179 }
180 if i == 0 {
181 context = obj.get("context").cloned();
182 }
183 }
184 let mut result = IndexMap::new();
185 result.insert(
186 "items".to_string(),
187 InputValue::Array(merged_items),
188 );
189 if let Some(ctx) = context {
190 result.insert("context".to_string(), ctx);
191 }
192 Ok(InputValue::Object(result))
193 }
194 _ => Err(super::ExpressionError::UnsupportedSpecial),
195 }
196 }
197}
198
199impl super::FromSpecial for Vec<InputValue> {
200 fn from_special(
201 special: &super::Special,
202 params: &super::Params,
203 ) -> Result<Self, super::ExpressionError> {
204 match special {
205 super::Special::InputItemsOptionalContextSplit => {
206 let input = match params {
210 super::Params::Owned(o) => &o.input,
211 super::Params::Ref(r) => r.input,
212 };
213 let InputValue::Object(obj) = input else {
214 return Err(super::ExpressionError::UnsupportedSpecial);
215 };
216 let Some(InputValue::Array(items)) = obj.get("items") else {
217 return Err(super::ExpressionError::UnsupportedSpecial);
218 };
219 let context = obj.get("context");
220 let mut result = Vec::with_capacity(items.len());
221 for item in items {
222 let mut sub = IndexMap::new();
223 sub.insert(
224 "items".to_string(),
225 InputValue::Array(vec![item.clone()]),
226 );
227 if let Some(ctx) = context {
228 sub.insert("context".to_string(), ctx.clone());
229 }
230 result.push(InputValue::Object(sub));
231 }
232 Ok(result)
233 }
234 _ => Err(super::ExpressionError::UnsupportedSpecial),
235 }
236 }
237}
238
239impl Eq for InputValue {}
240
241impl std::hash::Hash for InputValue {
242 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
243 std::mem::discriminant(self).hash(state);
244 match self {
245 InputValue::RichContentPart(p) => p.hash(state),
246 InputValue::Object(map) => {
247 map.len().hash(state);
248 for (k, v) in map {
249 k.hash(state);
250 v.hash(state);
251 }
252 }
253 InputValue::Array(arr) => arr.hash(state),
254 InputValue::String(s) => s.hash(state),
255 InputValue::Integer(i) => i.hash(state),
256 InputValue::Number(f) => canonical_f64_bits(*f).hash(state),
257 InputValue::Boolean(b) => b.hash(state),
258 }
259 }
260}
261
262impl<'a> arbitrary::Arbitrary<'a> for InputValue {
263 fn arbitrary(
264 u: &mut arbitrary::Unstructured<'a>,
265 ) -> arbitrary::Result<Self> {
266 if u.arbitrary().unwrap_or(false) {
267 if u.arbitrary()? {
269 let mut map = IndexMap::new();
270 while u.arbitrary().unwrap_or(false) {
271 map.insert(u.arbitrary::<String>()?, u.arbitrary()?);
272 }
273 Ok(InputValue::Object(map))
274 } else {
275 let mut arr = Vec::new();
276 while u.arbitrary().unwrap_or(false) {
277 arr.push(InputValue::arbitrary(u)?);
278 }
279 Ok(InputValue::Array(arr))
280 }
281 } else {
282 match u.int_in_range(0..=4)? {
284 0 => Ok(InputValue::RichContentPart(u.arbitrary()?)),
285 1 => Ok(InputValue::String(u.arbitrary()?)),
286 2 => Ok(InputValue::Integer(
287 crate::arbitrary_util::arbitrary_i64(u)?,
288 )),
289 3 => Ok(InputValue::Number(
290 crate::arbitrary_util::arbitrary_f64(u)?,
291 )),
292 _ => Ok(InputValue::Boolean(u.arbitrary()?)),
293 }
294 }
295 }
296}
297
298fn canonical_f64_bits(f: f64) -> u64 {
304 if f.is_nan() {
305 0x7FF8_0000_0000_0000 } else if f == 0.0 {
308 0u64
310 } else {
311 f.to_bits()
312 }
313}
314
315impl InputValue {
316 pub fn to_rich_content_parts(
321 self,
322 depth: usize,
323 ) -> impl Iterator<Item = agent::completions::message::RichContentPart>
324 {
325 enum Iter {
326 RichContentPart(RichContentPartIter),
327 Object(Box<ObjectIter>),
328 Array(Box<ArrayIter>),
329 Primitive(Option<String>),
330 }
331 impl Iter {
332 pub fn new(input: InputValue, depth: usize) -> Self {
333 match input {
334 InputValue::RichContentPart(rich_content_part) => {
335 Iter::RichContentPart(RichContentPartIter {
336 first: true,
337 part: Some(rich_content_part),
338 last: true,
339 })
340 }
341 InputValue::Object(object) => {
342 Iter::Object(Box::new(ObjectIter {
343 object: object.into_iter(),
344 first: true,
345 child: None,
346 depth,
347 }))
348 }
349 InputValue::Array(array) => {
350 Iter::Array(Box::new(ArrayIter {
351 array: array.into_iter(),
352 first: true,
353 child: None,
354 depth,
355 }))
356 }
357 InputValue::String(string) => Iter::Primitive(Some(
358 format!("\"{}\"", json_escape::escape_str(&string),),
359 )),
360 InputValue::Integer(integer) => {
361 Iter::Primitive(Some(integer.to_string()))
362 }
363 InputValue::Number(number) => {
364 Iter::Primitive(Some(number.to_string()))
365 }
366 InputValue::Boolean(boolean) => {
367 Iter::Primitive(Some(boolean.to_string()))
368 }
369 }
370 }
371 }
372 impl Iterator for Iter {
373 type Item = agent::completions::message::RichContentPart;
374 fn next(&mut self) -> Option<Self::Item> {
375 match self {
376 Iter::RichContentPart(rich_content_part_iter) => {
377 rich_content_part_iter.next()
378 }
379 Iter::Object(object_iter) => object_iter.next(),
380 Iter::Array(array_iter) => array_iter.next(),
381 Iter::Primitive(primitive_option) => {
382 primitive_option.take().map(|text| {
383 agent::completions::message::RichContentPart::Text {
384 text,
385 }
386 })
387 }
388 }
389 }
390 }
391 struct RichContentPartIter {
392 first: bool,
393 part: Option<agent::completions::message::RichContentPart>,
394 last: bool,
395 }
396 impl Iterator for RichContentPartIter {
397 type Item = agent::completions::message::RichContentPart;
398 fn next(&mut self) -> Option<Self::Item> {
399 if self.first {
400 self.first = false;
401 Some(agent::completions::message::RichContentPart::Text {
402 text: '"'.to_string(),
403 })
404 } else if let Some(part) = self.part.take() {
405 Some(part)
406 } else if self.last {
407 self.last = false;
408 Some(agent::completions::message::RichContentPart::Text {
409 text: '"'.to_string(),
410 })
411 } else {
412 None
413 }
414 }
415 }
416 struct ObjectIter {
417 object: indexmap::map::IntoIter<String, InputValue>,
418 first: bool,
419 child: Option<Iter>,
420 depth: usize,
421 }
422 impl Iterator for ObjectIter {
423 type Item = agent::completions::message::RichContentPart;
424 fn next(&mut self) -> Option<Self::Item> {
425 if self.first {
426 self.first = false;
427 if let Some((key, input)) = self.object.next() {
428 self.child = Some(Iter::new(input, self.depth + 1));
429 Some(
430 agent::completions::message::RichContentPart::Text {
431 text: format!(
432 "{{\n{}\"{}\": ",
433 " ".repeat(self.depth + 1),
434 key,
435 ),
436 },
437 )
438 } else {
439 Some(
440 agent::completions::message::RichContentPart::Text {
441 text: format!("{{}}"),
442 },
443 )
444 }
445 } else if let Some(child) = &mut self.child {
446 if let Some(part) = child.next() {
447 Some(part)
448 } else if let Some((key, input)) = self.object.next() {
449 self.child = Some(Iter::new(input, self.depth + 1));
450 Some(
451 agent::completions::message::RichContentPart::Text {
452 text: format!(
453 ",\n{}\"{}\": ",
454 " ".repeat(self.depth + 1),
455 key,
456 ),
457 },
458 )
459 } else {
460 self.child = None;
461 Some(
462 agent::completions::message::RichContentPart::Text {
463 text: format!(
464 "\n{}}}",
465 " ".repeat(self.depth)
466 ),
467 },
468 )
469 }
470 } else {
471 None
472 }
473 }
474 }
475 struct ArrayIter {
476 array: std::vec::IntoIter<InputValue>,
477 first: bool,
478 child: Option<Iter>,
479 depth: usize,
480 }
481 impl Iterator for ArrayIter {
482 type Item = agent::completions::message::RichContentPart;
483 fn next(&mut self) -> Option<Self::Item> {
484 if self.first {
485 self.first = false;
486 if let Some(input) = self.array.next() {
487 self.child = Some(Iter::new(input, self.depth + 1));
488 Some(
489 agent::completions::message::RichContentPart::Text {
490 text: format!(
491 "[\n{}",
492 " ".repeat(self.depth + 1)
493 ),
494 },
495 )
496 } else {
497 Some(
498 agent::completions::message::RichContentPart::Text {
499 text: format!("[]"),
500 },
501 )
502 }
503 } else if let Some(child) = &mut self.child {
504 if let Some(part) = child.next() {
505 Some(part)
506 } else if let Some(input) = self.array.next() {
507 self.child = Some(Iter::new(input, self.depth + 1));
508 Some(
509 agent::completions::message::RichContentPart::Text {
510 text: format!(
511 ",\n{}",
512 " ".repeat(self.depth + 1),
513 ),
514 },
515 )
516 } else {
517 self.child = None;
518 Some(
519 agent::completions::message::RichContentPart::Text {
520 text: format!(
521 "\n{}]",
522 " ".repeat(self.depth)
523 ),
524 },
525 )
526 }
527 } else {
528 None
529 }
530 }
531 }
532 Iter::new(self, depth)
533 }
534}
535
536#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, JsonSchema)]
541#[serde(untagged)]
542#[schemars(rename = "functions.expression.InputValueExpression")]
543pub enum InputValueExpression {
544 #[schemars(title = "RichContentPart")]
546 RichContentPart(agent::completions::message::RichContentPart),
547 #[schemars(title = "Object")]
549 Object(IndexMap<String, super::WithExpression<InputValueExpression>>),
550 #[schemars(title = "Array")]
552 Array(Vec<super::WithExpression<InputValueExpression>>),
553 #[schemars(title = "String")]
555 String(String),
556 #[schemars(title = "Integer")]
558 Integer(i64),
559 #[schemars(title = "Number")]
561 Number(f64),
562 #[schemars(title = "Boolean")]
564 Boolean(bool),
565}
566
567impl InputValueExpression {
568 pub fn compile(
570 self,
571 params: &super::Params,
572 ) -> Result<InputValue, super::ExpressionError> {
573 match self {
574 InputValueExpression::RichContentPart(rich_content_part) => {
575 Ok(InputValue::RichContentPart(rich_content_part))
576 }
577 InputValueExpression::Object(object) => {
578 let mut compiled_object = IndexMap::with_capacity(object.len());
579 for (key, value) in object {
580 compiled_object.insert(
581 key,
582 value.compile_one(params)?.compile(params)?,
583 );
584 }
585 Ok(InputValue::Object(compiled_object))
586 }
587 InputValueExpression::Array(array) => {
588 let mut compiled_array = Vec::with_capacity(array.len());
589 for item in array {
590 match item.compile_one_or_many(params)? {
591 super::OneOrMany::One(one_item) => {
592 compiled_array.push(one_item.compile(params)?);
593 }
594 super::OneOrMany::Many(many_items) => {
595 for item in many_items {
596 compiled_array.push(item.compile(params)?);
597 }
598 }
599 }
600 }
601 Ok(InputValue::Array(compiled_array))
602 }
603 InputValueExpression::String(string) => {
604 Ok(InputValue::String(string))
605 }
606 InputValueExpression::Integer(integer) => {
607 Ok(InputValue::Integer(integer))
608 }
609 InputValueExpression::Number(number) => {
610 Ok(InputValue::Number(number))
611 }
612 InputValueExpression::Boolean(boolean) => {
613 Ok(InputValue::Boolean(boolean))
614 }
615 }
616 }
617}
618
619impl super::FromStarlarkValue for InputValueExpression {
620 fn from_starlark_value(
621 value: &StarlarkValue,
622 ) -> Result<Self, super::ExpressionError> {
623 if value.is_none() {
624 return Err(super::ExpressionError::StarlarkConversionError(
625 "InputValueExpression: expected value".into(),
626 ));
627 }
628 if let Ok(Some(b)) = bool::unpack_value(*value) {
629 return Ok(InputValueExpression::Boolean(b));
630 }
631 if let Ok(Some(i)) = i64::unpack_value(*value) {
632 return Ok(InputValueExpression::Integer(i));
633 }
634 if let Ok(Some(UnpackFloat(f))) = UnpackFloat::unpack_value(*value) {
635 return Ok(InputValueExpression::Number(f));
636 }
637 if let Ok(Some(s)) = <&str as UnpackValue>::unpack_value(*value) {
638 return Ok(InputValueExpression::String(s.to_owned()));
639 }
640 if let Some(list) = StarlarkListRef::from_value(*value) {
641 let mut items = Vec::with_capacity(list.len());
642 for v in list.iter() {
643 items.push(super::WithExpression::Value(
644 InputValueExpression::from_starlark_value(&v)?,
645 ));
646 }
647 return Ok(InputValueExpression::Array(items));
648 }
649 if let Some(dict) = StarlarkDictRef::from_value(*value) {
650 let mut type_value = None;
652 for (k, v) in dict.iter() {
653 if let Ok(Some("type")) = <&str as UnpackValue>::unpack_value(k)
654 {
655 type_value =
656 <&str as UnpackValue>::unpack_value(v).ok().flatten();
657 break;
658 }
659 }
660 if matches!(
661 type_value,
662 Some(
663 "text"
664 | "image_url"
665 | "input_audio"
666 | "input_video"
667 | "video_url"
668 | "file"
669 )
670 ) {
671 if let Ok(part) = agent::completions::message::RichContentPart::from_starlark_value(value) {
672 return Ok(InputValueExpression::RichContentPart(part));
673 }
674 }
675 let mut map = IndexMap::with_capacity(dict.len());
676 for (k, v) in dict.iter() {
677 let key = <&str as UnpackValue>::unpack_value(k)
678 .map_err(|e| {
679 super::ExpressionError::StarlarkConversionError(
680 e.to_string(),
681 )
682 })?
683 .ok_or_else(|| {
684 super::ExpressionError::StarlarkConversionError(
685 "InputValueExpression: expected string key".into(),
686 )
687 })?
688 .to_owned();
689 map.insert(
690 key,
691 super::WithExpression::Value(
692 InputValueExpression::from_starlark_value(&v)?,
693 ),
694 );
695 }
696 return Ok(InputValueExpression::Object(map));
697 }
698 Err(super::ExpressionError::StarlarkConversionError(format!(
699 "InputValueExpression: unsupported type: {}",
700 value.get_type()
701 )))
702 }
703}
704
705impl<'a> arbitrary::Arbitrary<'a> for InputValueExpression {
706 fn arbitrary(
707 u: &mut arbitrary::Unstructured<'a>,
708 ) -> arbitrary::Result<Self> {
709 if u.arbitrary().unwrap_or(false) {
710 if u.arbitrary()? {
712 let mut map = IndexMap::new();
713 while u.arbitrary().unwrap_or(false) {
714 map.insert(u.arbitrary::<String>()?, u.arbitrary()?);
715 }
716 Ok(InputValueExpression::Object(map))
717 } else {
718 let mut arr = Vec::new();
719 while u.arbitrary().unwrap_or(false) {
720 arr.push(u.arbitrary()?);
721 }
722 Ok(InputValueExpression::Array(arr))
723 }
724 } else {
725 match u.int_in_range(0..=4)? {
727 0 => Ok(InputValueExpression::RichContentPart(u.arbitrary()?)),
728 1 => Ok(InputValueExpression::String(u.arbitrary()?)),
729 2 => Ok(InputValueExpression::Integer(
730 crate::arbitrary_util::arbitrary_i64(u)?,
731 )),
732 3 => Ok(InputValueExpression::Number(
733 crate::arbitrary_util::arbitrary_f64(u)?,
734 )),
735 _ => Ok(InputValueExpression::Boolean(u.arbitrary()?)),
736 }
737 }
738 }
739}
740
741impl super::FromSpecial for InputValueExpression {
742 fn from_special(
743 special: &super::Special,
744 params: &super::Params,
745 ) -> Result<Self, super::ExpressionError> {
746 let input = InputValue::from_special(special, params)?;
747 Ok(input_to_input_expression(input))
748 }
749}
750
751fn input_to_input_expression(input: InputValue) -> InputValueExpression {
752 match input {
753 InputValue::RichContentPart(p) => {
754 InputValueExpression::RichContentPart(p)
755 }
756 InputValue::Object(map) => InputValueExpression::Object(
757 map.into_iter()
758 .map(|(k, v)| {
759 (
760 k,
761 super::WithExpression::Value(
762 input_to_input_expression(v),
763 ),
764 )
765 })
766 .collect(),
767 ),
768 InputValue::Array(arr) => InputValueExpression::Array(
769 arr.into_iter()
770 .map(|v| {
771 super::WithExpression::Value(input_to_input_expression(v))
772 })
773 .collect(),
774 ),
775 InputValue::String(s) => InputValueExpression::String(s),
776 InputValue::Integer(i) => InputValueExpression::Integer(i),
777 InputValue::Number(n) => InputValueExpression::Number(n),
778 InputValue::Boolean(b) => InputValueExpression::Boolean(b),
779 }
780}