1use super::value_expr::ValueExpr;
23use serde::{Deserialize, Deserializer, Serialize, Serializer, de};
24use serde_json::Value;
25
26impl Serialize for ValueExpr {
27 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
28 where
29 S: Serializer,
30 {
31 use serde::ser::SerializeMap as _;
32
33 match self {
34 ValueExpr::Step { step, path } => {
35 let mut map = serializer.serialize_map(Some(2))?;
36 map.serialize_entry("$step", step)?;
37 if !path.is_empty() {
38 map.serialize_entry("path", path)?;
39 }
40 map.end()
41 }
42 ValueExpr::Input { input } => {
43 let mut map = serializer.serialize_map(Some(1))?;
44 map.serialize_entry("$input", input)?;
45 map.end()
46 }
47 ValueExpr::Variable { variable, default } => {
48 let mut map = serializer.serialize_map(Some(2))?;
49 map.serialize_entry("$variable", variable)?;
50 if let Some(def) = default {
51 map.serialize_entry("default", def)?;
52 }
53 map.end()
54 }
55 ValueExpr::EscapedLiteral { literal } => {
56 let mut map = serializer.serialize_map(Some(1))?;
57 map.serialize_entry("$literal", literal)?;
58 map.end()
59 }
60 ValueExpr::If {
61 condition,
62 then,
63 else_expr,
64 } => {
65 let mut map = serializer.serialize_map(Some(3))?;
66 map.serialize_entry("$if", condition)?;
67 map.serialize_entry("then", then)?;
68 if let Some(else_val) = else_expr {
69 map.serialize_entry("else", else_val)?;
70 }
71 map.end()
72 }
73 ValueExpr::Coalesce { values } => {
74 let mut map = serializer.serialize_map(Some(1))?;
75 map.serialize_entry("$coalesce", values)?;
76 map.end()
77 }
78 ValueExpr::Array(items) => items.serialize(serializer),
79 ValueExpr::Object(fields) => {
80 let mut map = serializer.serialize_map(Some(fields.len()))?;
81 for (k, v) in fields {
82 map.serialize_entry(k, v)?;
83 }
84 map.end()
85 }
86 ValueExpr::Literal(value) => value.serialize(serializer),
87 }
88 }
89}
90
91impl<'de> Deserialize<'de> for ValueExpr {
92 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
93 where
94 D: Deserializer<'de>,
95 {
96 let value = Value::deserialize(deserializer)?;
97 parse_value_expr(value).map_err(de::Error::custom)
98 }
99}
100
101fn parse_value_expr(value: Value) -> Result<ValueExpr, String> {
108 match value {
109 Value::Object(obj) if obj.contains_key("$literal") => {
110 let literal = obj
112 .get("$literal")
113 .ok_or_else(|| "$literal key not found".to_string())?
114 .clone();
115 Ok(ValueExpr::EscapedLiteral { literal })
116 }
117 Value::Object(ref obj) if obj.contains_key("$if") => {
118 let condition = obj
120 .get("$if")
121 .ok_or_else(|| "$if key not found".to_string())?;
122 let then = obj
123 .get("then")
124 .ok_or_else(|| "then key required for $if".to_string())?;
125 let else_expr = obj.get("else");
126
127 let condition_expr = parse_value_expr(condition.clone())?;
128 let then_expr = parse_value_expr(then.clone())?;
129 let else_opt = else_expr.map(|e| parse_value_expr(e.clone())).transpose()?;
130
131 Ok(ValueExpr::If {
132 condition: Box::new(condition_expr),
133 then: Box::new(then_expr),
134 else_expr: else_opt.map(Box::new),
135 })
136 }
137 Value::Object(ref obj) if obj.contains_key("$coalesce") => {
138 let values_val = obj
140 .get("$coalesce")
141 .ok_or_else(|| "$coalesce key not found".to_string())?;
142
143 let values_array = values_val
144 .as_array()
145 .ok_or_else(|| "$coalesce must be an array".to_string())?;
146
147 let mut values = Vec::new();
148 for v in values_array {
149 values.push(parse_value_expr(v.clone())?);
150 }
151
152 Ok(ValueExpr::Coalesce { values })
153 }
154 Value::Object(ref obj) if obj.contains_key("$from") => {
155 Err(
158 "Legacy '$from' syntax is no longer supported. \
159 Migrate to the new syntax: use {\"$step\": \"step_id\", \"path\": \"...\"} \
160 instead of {\"$from\": {\"step\": \"step_id\"}, \"path\": \"...\"}, \
161 and {\"$input\": \"field\"} instead of {\"$from\": {\"workflow\": \"input\"}, \"path\": \"field\"}. \
162 If you need a literal object containing a \"$from\" key, wrap it in \
163 $literal: {\"$literal\": {\"$from\": ...}}"
164 .to_string(),
165 )
166 }
167 Value::Object(ref obj) if obj.contains_key("$step") => {
168 let step = obj
170 .get("$step")
171 .and_then(|v| v.as_str())
172 .ok_or_else(|| "$step must be a string".to_string())?
173 .to_string();
174
175 let path = if let Some(path_value) = obj.get("path") {
176 serde_json::from_value(path_value.clone())
177 .map_err(|e| format!("Invalid path: {}", e))?
178 } else {
179 super::JsonPath::default()
180 };
181
182 Ok(ValueExpr::Step { step, path })
183 }
184 Value::Object(ref obj) if obj.contains_key("$input") => {
185 let input = obj
187 .get("$input")
188 .ok_or_else(|| "$input key not found".to_string())?;
189
190 let input_path: super::JsonPath = serde_json::from_value(input.clone())
191 .map_err(|e| format!("Invalid $input: {}", e))?;
192
193 Ok(ValueExpr::Input { input: input_path })
194 }
195 Value::Object(ref obj) if obj.contains_key("$variable") => {
196 let variable = obj
198 .get("$variable")
199 .ok_or_else(|| "$variable key not found".to_string())?;
200
201 let variable_path: super::JsonPath = serde_json::from_value(variable.clone())
202 .map_err(|e| format!("Invalid $variable: {}", e))?;
203
204 let default = if let Some(default_value) = obj.get("default") {
205 let default_expr = parse_value_expr(default_value.clone())?;
206 Some(Box::new(default_expr))
207 } else {
208 None
209 };
210
211 Ok(ValueExpr::Variable {
212 variable: variable_path,
213 default,
214 })
215 }
216 Value::Object(obj) => {
217 let mut fields = Vec::new();
219 for (k, v) in obj {
220 let expr = parse_value_expr(v)?;
221 fields.push((k, expr));
222 }
223 Ok(ValueExpr::Object(fields))
224 }
225 Value::Array(arr) => {
226 let mut exprs = Vec::new();
228 for v in arr {
229 let expr = parse_value_expr(v)?;
230 exprs.push(expr);
231 }
232 Ok(ValueExpr::Array(exprs))
233 }
234 primitive => Ok(ValueExpr::Literal(primitive)),
236 }
237}
238
239#[cfg(test)]
240mod tests {
241 use super::*;
242 use crate::values::JsonPath;
243 use serde_json::json;
244
245 #[test]
246 fn test_serde_step_reference() {
247 let expr = ValueExpr::step("my_step", JsonPath::default());
248 let json_str = serde_json::to_string(&expr).unwrap();
249 assert_eq!(json_str, r#"{"$step":"my_step"}"#);
250
251 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
252 assert_eq!(parsed, expr);
253 }
254
255 #[test]
256 fn test_serde_step_with_path() {
257 let expr = ValueExpr::step("my_step", JsonPath::from("result"));
258 let json_str = serde_json::to_string(&expr).unwrap();
259 assert_eq!(json_str, r#"{"$step":"my_step","path":"$.result"}"#);
261
262 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
263 assert_eq!(parsed, expr);
264
265 let shorthand: ValueExpr =
267 serde_json::from_str(r#"{"$step":"my_step","path":"result"}"#).unwrap();
268 assert_eq!(shorthand, expr);
269 }
270
271 #[test]
272 fn test_serde_input() {
273 let expr = ValueExpr::workflow_input(JsonPath::from("name"));
274 let json_str = serde_json::to_string(&expr).unwrap();
275 assert_eq!(json_str, r#"{"$input":"$.name"}"#);
277
278 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
279 assert_eq!(parsed, expr);
280
281 let shorthand: ValueExpr = serde_json::from_str(r#"{"$input":"name"}"#).unwrap();
283 assert_eq!(shorthand, expr);
284 }
285
286 #[test]
287 fn test_serde_input_root() {
288 let expr = ValueExpr::workflow_input(JsonPath::from("$"));
289 let json_str = serde_json::to_string(&expr).unwrap();
290 assert_eq!(json_str, r#"{"$input":"$"}"#);
291
292 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
293 assert_eq!(parsed, expr);
294 }
295
296 #[test]
297 fn test_serde_variable() {
298 let expr = ValueExpr::variable("api_key", None);
299 let json_str = serde_json::to_string(&expr).unwrap();
300 assert_eq!(json_str, r#"{"$variable":"$.api_key"}"#);
302
303 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
304 assert_eq!(parsed, expr);
305
306 let shorthand: ValueExpr = serde_json::from_str(r#"{"$variable":"api_key"}"#).unwrap();
308 assert_eq!(shorthand, expr);
309 }
310
311 #[test]
312 fn test_serde_variable_with_default() {
313 let default = Box::new(ValueExpr::literal(json!("default_value")));
314 let expr = ValueExpr::variable("my_var", Some(default));
315 let json_str = serde_json::to_string(&expr).unwrap();
316 assert!(json_str.contains(r#""$variable":"$.my_var""#));
318 assert!(json_str.contains(r#""default":"default_value""#));
319
320 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
321 assert_eq!(parsed, expr);
322 }
323
324 #[test]
325 fn test_serde_escaped_literal() {
326 let expr = ValueExpr::escaped_literal(json!({"step": "not_a_ref"}));
327 let json_str = serde_json::to_string(&expr).unwrap();
328 assert_eq!(json_str, r#"{"$literal":{"step":"not_a_ref"}}"#);
329
330 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
331 assert_eq!(parsed, expr);
332 }
333
334 #[test]
335 fn test_serde_primitives() {
336 let expr = ValueExpr::Literal(json!(null));
338 let json_str = serde_json::to_string(&expr).unwrap();
339 assert_eq!(json_str, "null");
340 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
341 assert_eq!(parsed, expr);
342
343 let expr = ValueExpr::Literal(json!(true));
345 let json_str = serde_json::to_string(&expr).unwrap();
346 assert_eq!(json_str, "true");
347 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
348 assert_eq!(parsed, expr);
349
350 let expr = ValueExpr::Literal(json!(42));
352 let json_str = serde_json::to_string(&expr).unwrap();
353 assert_eq!(json_str, "42");
354 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
355 assert_eq!(parsed, expr);
356
357 let expr = ValueExpr::Literal(json!("hello"));
359 let json_str = serde_json::to_string(&expr).unwrap();
360 assert_eq!(json_str, r#""hello""#);
361 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
362 assert_eq!(parsed, expr);
363 }
364
365 #[test]
366 fn test_serde_array() {
367 let expr = ValueExpr::Array(vec![
368 ValueExpr::literal(json!(1)),
369 ValueExpr::literal(json!("two")),
370 ValueExpr::step("step1", JsonPath::default()),
371 ]);
372 let json_str = serde_json::to_string(&expr).unwrap();
373 assert_eq!(json_str, r#"[1,"two",{"$step":"step1"}]"#);
374
375 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
376 assert_eq!(parsed, expr);
377 }
378
379 #[test]
380 fn test_serde_object() {
381 let expr = ValueExpr::Object(vec![
382 ("a".to_string(), ValueExpr::literal(json!(1))),
383 (
384 "b".to_string(),
385 ValueExpr::step("step1", JsonPath::default()),
386 ),
387 ]);
388 let json_str = serde_json::to_string(&expr).unwrap();
389 assert_eq!(json_str, r#"{"a":1,"b":{"$step":"step1"}}"#);
390
391 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
392 assert_eq!(parsed, expr);
393 }
394
395 #[test]
396 fn test_serde_nested_structures() {
397 let expr = ValueExpr::Object(vec![
399 (
400 "input".to_string(),
401 ValueExpr::workflow_input(JsonPath::from("data")),
402 ),
403 (
404 "steps".to_string(),
405 ValueExpr::Array(vec![
406 ValueExpr::step("step1", JsonPath::from("result")),
407 ValueExpr::step("step2", JsonPath::default()),
408 ]),
409 ),
410 (
411 "config".to_string(),
412 ValueExpr::Object(vec![
413 ("enabled".to_string(), ValueExpr::literal(json!(true))),
414 ("count".to_string(), ValueExpr::literal(json!(5))),
415 ]),
416 ),
417 ]);
418
419 let json_str = serde_json::to_string(&expr).unwrap();
420 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
421 assert_eq!(parsed, expr);
422 }
423
424 #[test]
425 fn test_parse_error_invalid_step() {
426 let json_str = r#"{"$step": 123}"#; let result: Result<ValueExpr, _> = serde_json::from_str(json_str);
429 assert!(result.is_err());
430 }
431
432 #[test]
433 fn test_parse_error_legacy_from_syntax() {
434 let json_str = r#"{"$from": {"step": "my_step"}, "path": "result"}"#;
436 let result: Result<ValueExpr, _> = serde_json::from_str(json_str);
437 assert!(result.is_err());
438 let err_msg = result.unwrap_err().to_string();
439 assert!(
440 err_msg.contains("$from"),
441 "Error should mention $from: {}",
442 err_msg
443 );
444 assert!(
445 err_msg.contains("no longer supported"),
446 "Error should say no longer supported: {}",
447 err_msg
448 );
449
450 let json_str = r#"{"$from": {"workflow": "input"}, "path": "name"}"#;
452 let result: Result<ValueExpr, _> = serde_json::from_str(json_str);
453 assert!(result.is_err());
454 }
455
456 #[test]
457 fn test_parse_object_without_dollar_keys() {
458 let json_str = r#"{"a": 1, "b": "hello"}"#;
460 let parsed: ValueExpr = serde_json::from_str(json_str).unwrap();
461
462 match parsed {
463 ValueExpr::Object(fields) => {
464 assert_eq!(fields.len(), 2);
465 assert!(
466 fields
467 .iter()
468 .any(|(k, v)| k == "a" && *v == ValueExpr::Literal(json!(1)))
469 );
470 assert!(
471 fields
472 .iter()
473 .any(|(k, v)| k == "b" && *v == ValueExpr::Literal(json!("hello")))
474 );
475 }
476 _ => panic!("Expected Object variant, got {:?}", parsed),
477 }
478 }
479
480 #[test]
481 fn test_deep_nesting() {
482 let json_str = r#"{
484 "level1": {
485 "level2": {
486 "level3": {
487 "ref": {"$step": "deep_step"},
488 "literal": "value",
489 "array": [
490 1,
491 {"$input": "nested"},
492 {
493 "level4": {
494 "level5": {"$variable": "deep_var"}
495 }
496 }
497 ]
498 }
499 }
500 }
501 }"#;
502
503 let parsed: ValueExpr = serde_json::from_str(json_str).unwrap();
504
505 let serialized = serde_json::to_string(&parsed).unwrap();
507 let reparsed: ValueExpr = serde_json::from_str(&serialized).unwrap();
508 assert_eq!(parsed, reparsed);
509
510 match parsed {
512 ValueExpr::Object(fields) => {
513 assert_eq!(fields.len(), 1);
514 assert_eq!(fields[0].0, "level1");
515
516 match &fields[0].1 {
517 ValueExpr::Object(level2_fields) => {
518 assert_eq!(level2_fields.len(), 1);
519 assert_eq!(level2_fields[0].0, "level2");
520 }
522 _ => panic!("Expected Object at level2"),
523 }
524 }
525 _ => panic!("Expected Object at top level"),
526 }
527 }
528
529 #[test]
530 fn test_escaped_literal_with_dollar_keys() {
531 let json_str = r#"{"$literal": {"$step": "not_a_ref", "$input": "also_not_a_ref"}}"#;
533 let parsed: ValueExpr = serde_json::from_str(json_str).unwrap();
534
535 match &parsed {
536 ValueExpr::EscapedLiteral { literal } => {
537 assert_eq!(
539 *literal,
540 json!({"$step": "not_a_ref", "$input": "also_not_a_ref"})
541 );
542 }
543 _ => panic!("Expected EscapedLiteral, got {:?}", parsed),
544 }
545
546 let serialized = serde_json::to_string(&parsed).unwrap();
548 let reparsed: ValueExpr = serde_json::from_str(&serialized).unwrap();
549 assert_eq!(parsed, reparsed);
550 }
551
552 #[test]
553 fn test_escaped_literal_with_nested_literal() {
554 let json_str = r#"{"$literal": {"$literal": "inner"}}"#;
556 let parsed: ValueExpr = serde_json::from_str(json_str).unwrap();
557
558 match &parsed {
559 ValueExpr::EscapedLiteral { literal } => {
560 assert_eq!(*literal, json!({"$literal": "inner"}));
562 }
563 _ => panic!("Expected EscapedLiteral, got {:?}", parsed),
564 }
565 }
566
567 #[test]
568 fn test_literal_containing_dollar_prefixed_fields() {
569 let json_str = r#"{"$custom": "value", "$other": 123, "normal": true}"#;
572 let parsed: ValueExpr = serde_json::from_str(json_str).unwrap();
573
574 match parsed {
575 ValueExpr::Object(fields) => {
576 assert_eq!(fields.len(), 3);
577 assert!(
579 fields
580 .iter()
581 .any(|(k, v)| k == "$custom" && *v == ValueExpr::Literal(json!("value")))
582 );
583 assert!(
584 fields
585 .iter()
586 .any(|(k, v)| k == "$other" && *v == ValueExpr::Literal(json!(123)))
587 );
588 assert!(
589 fields
590 .iter()
591 .any(|(k, v)| k == "normal" && *v == ValueExpr::Literal(json!(true)))
592 );
593 }
594 _ => panic!("Expected Object, got {:?}", parsed),
595 }
596 }
597
598 #[test]
599 fn test_array_of_escaped_literals() {
600 let json_str = r#"[
602 {"$literal": {"$step": "fake1"}},
603 {"$literal": {"$input": "fake2"}},
604 "normal_string"
605 ]"#;
606 let parsed: ValueExpr = serde_json::from_str(json_str).unwrap();
607
608 match parsed {
609 ValueExpr::Array(items) => {
610 assert_eq!(items.len(), 3);
611
612 match &items[0] {
614 ValueExpr::EscapedLiteral { literal } => {
615 assert_eq!(*literal, json!({"$step": "fake1"}));
616 }
617 _ => panic!("Expected EscapedLiteral at index 0"),
618 }
619
620 match &items[1] {
622 ValueExpr::EscapedLiteral { literal } => {
623 assert_eq!(*literal, json!({"$input": "fake2"}));
624 }
625 _ => panic!("Expected EscapedLiteral at index 1"),
626 }
627
628 assert_eq!(items[2], ValueExpr::Literal(json!("normal_string")));
630 }
631 _ => panic!("Expected Array, got {:?}", parsed),
632 }
633 }
634
635 #[test]
636 fn test_complex_mixed_nesting() {
637 let json_str = r#"{
639 "steps_array": [
640 {"$step": "step1"},
641 {"$step": "step2", "path": "result"}
642 ],
643 "inputs": {
644 "user_input": {"$input": "name"},
645 "workflow_root": {"$input": "$"}
646 },
647 "config": {
648 "api_key": {"$variable": "api_key", "default": "default_key"},
649 "nested_config": {
650 "escaped": {"$literal": {"$step": "not_real"}},
651 "real_ref": {"$step": "real_step"},
652 "values": [1, 2, {"$variable": "count"}]
653 }
654 }
655 }"#;
656
657 let parsed: ValueExpr = serde_json::from_str(json_str).unwrap();
658
659 let serialized = serde_json::to_string(&parsed).unwrap();
661 let reparsed: ValueExpr = serde_json::from_str(&serialized).unwrap();
662 assert_eq!(parsed, reparsed);
663
664 match parsed {
666 ValueExpr::Object(fields) => {
667 assert_eq!(fields.len(), 3);
668 assert!(fields.iter().any(|(k, _)| k == "steps_array"));
669 assert!(fields.iter().any(|(k, _)| k == "inputs"));
670 assert!(fields.iter().any(|(k, _)| k == "config"));
671 }
672 _ => panic!("Expected Object at top level"),
673 }
674 }
675
676 #[test]
677 fn test_escaped_literal_with_complex_value() {
678 let complex_value = json!({
680 "nested": {
681 "arrays": [1, 2, 3],
682 "objects": {"a": "b"},
683 "fake_refs": {
684 "$step": "not_expanded",
685 "$input": "not_expanded",
686 "$variable": "not_expanded"
687 }
688 }
689 });
690
691 let expr = ValueExpr::escaped_literal(complex_value.clone());
692 let json_str = serde_json::to_string(&expr).unwrap();
693 let parsed: ValueExpr = serde_json::from_str(&json_str).unwrap();
694
695 match &parsed {
696 ValueExpr::EscapedLiteral { literal } => {
697 assert_eq!(*literal, complex_value);
698 }
699 _ => panic!("Expected EscapedLiteral"),
700 }
701 }
702
703 #[test]
704 fn test_mixed_literal_and_expression_object() {
705 let json_str = r#"{
708 "messages": {"$step": "create_messages"},
709 "model": "gpt-3.5-turbo",
710 "max_tokens": 150
711 }"#;
712
713 let parsed: ValueExpr = serde_json::from_str(json_str).unwrap();
714
715 match &parsed {
717 ValueExpr::Object(fields) => {
718 assert_eq!(fields.len(), 3);
719
720 let messages = fields.iter().find(|(k, _)| k == "messages").unwrap();
722 match &messages.1 {
723 ValueExpr::Step { step, .. } => {
724 assert_eq!(step, "create_messages");
725 }
726 _ => panic!("Expected Step for messages field, got {:?}", messages.1),
727 }
728
729 let model = fields.iter().find(|(k, _)| k == "model").unwrap();
731 assert_eq!(model.1, ValueExpr::Literal(json!("gpt-3.5-turbo")));
732
733 let max_tokens = fields.iter().find(|(k, _)| k == "max_tokens").unwrap();
735 assert_eq!(max_tokens.1, ValueExpr::Literal(json!(150)));
736 }
737 _ => panic!("Expected Object, got {:?}", parsed),
738 }
739
740 let serialized = serde_json::to_string(&parsed).unwrap();
742 let reparsed: ValueExpr = serde_json::from_str(&serialized).unwrap();
743 assert_eq!(parsed, reparsed);
744 }
745
746 #[test]
747 fn test_yaml_integer_preserved_in_value_expr() {
748 let yaml = r#"
751 duration_ms: 10
752 name: test
753 "#;
754 let expr: ValueExpr = serde_yaml_ng::from_str(yaml).unwrap();
755 match &expr {
756 ValueExpr::Object(fields) => {
757 let duration = fields.iter().find(|(k, _)| k == "duration_ms").unwrap();
758 match &duration.1 {
759 ValueExpr::Literal(val) => {
760 assert!(
761 val.is_i64() || val.is_u64(),
762 "Expected integer, got {:?} (is_f64={})",
763 val,
764 val.is_f64()
765 );
766 assert_eq!(val.as_i64(), Some(10));
767 }
768 other => panic!("Expected Literal, got {:?}", other),
769 }
770 }
771 other => panic!("Expected Object, got {:?}", other),
772 }
773 }
774
775 #[test]
776 fn test_mixed_literal_and_expression_with_nested_objects() {
777 let json_str = r#"{
779 "config": {
780 "api_key": {"$variable": "openai_api_key"},
781 "timeout": 30,
782 "options": {
783 "stream": true,
784 "user_data": {"$input": "user"}
785 }
786 },
787 "messages": [
788 {"$step": "system_prompt"},
789 {"role": "user", "content": {"$input": "message"}}
790 ],
791 "temperature": 0.7
792 }"#;
793
794 let parsed: ValueExpr = serde_json::from_str(json_str).unwrap();
795
796 let serialized = serde_json::to_string(&parsed).unwrap();
798 let reparsed: ValueExpr = serde_json::from_str(&serialized).unwrap();
799 assert_eq!(parsed, reparsed);
800
801 match &parsed {
803 ValueExpr::Object(fields) => {
804 assert_eq!(fields.len(), 3);
805 assert!(fields.iter().any(|(k, _)| k == "config"));
806 assert!(fields.iter().any(|(k, _)| k == "messages"));
807 assert!(fields.iter().any(|(k, _)| k == "temperature"));
808
809 let temp = fields.iter().find(|(k, _)| k == "temperature").unwrap();
811 assert_eq!(temp.1, ValueExpr::Literal(json!(0.7)));
812 }
813 _ => panic!("Expected Object"),
814 }
815 }
816}