1use crate::parser::ast::{
4 Block, FieldType, OutputType, Param, StructField, TypeName as ParserTypeName,
5};
6use std::collections::HashMap;
7use std::fmt;
8
9#[derive(Debug, Clone, PartialEq)]
11pub struct OutputSchema {
12 pub fields: Vec<StructField>,
13}
14
15impl OutputSchema {
16 pub fn from_output_type(
17 output_type: &OutputType,
18 structs: &HashMap<String, Vec<StructField>>,
19 ) -> Result<Self, String> {
20 match output_type {
21 OutputType::Inline(fields) => {
22 let resolved_fields = resolve_named_types(fields, structs)?;
24 Ok(OutputSchema {
25 fields: resolved_fields,
26 })
27 }
28 OutputType::Named(name) => {
29 let fields = structs
30 .get(name)
31 .ok_or_else(|| format!("Unknown struct: {}", name))?;
32 let resolved_fields = resolve_named_types(fields, structs)?;
34 Ok(OutputSchema {
35 fields: resolved_fields,
36 })
37 }
38 }
39 }
40
41 pub fn to_json_schema(&self) -> serde_json::Value {
42 use serde_json::json;
43
44 let properties: serde_json::Map<String, serde_json::Value> = self
45 .fields
46 .iter()
47 .map(|f| (f.name.clone(), field_type_to_json_schema(&f.field_type)))
48 .collect();
49
50 let required: Vec<String> = self.fields.iter().map(|f| f.name.clone()).collect();
51
52 json!({
53 "type": "object",
54 "properties": properties,
55 "required": required
56 })
57 }
58}
59
60fn resolve_named_types(
62 fields: &[StructField],
63 structs: &HashMap<String, Vec<StructField>>,
64) -> Result<Vec<StructField>, String> {
65 fields
66 .iter()
67 .map(|field| {
68 let resolved_type = resolve_field_type(&field.field_type, structs)?;
69 Ok(StructField {
70 name: field.name.clone(),
71 field_type: resolved_type,
72 span: field.span.clone(),
73 })
74 })
75 .collect()
76}
77
78fn resolve_field_type(
80 ft: &FieldType,
81 structs: &HashMap<String, Vec<StructField>>,
82) -> Result<FieldType, String> {
83 match ft {
84 FieldType::String => Ok(FieldType::String),
85 FieldType::Number => Ok(FieldType::Number),
86 FieldType::Boolean => Ok(FieldType::Boolean),
87 FieldType::Array(inner) => {
88 let resolved_inner = resolve_field_type(inner, structs)?;
89 Ok(FieldType::Array(Box::new(resolved_inner)))
90 }
91 FieldType::Object(fields) => {
92 let resolved_fields = resolve_named_types(fields, structs)?;
93 Ok(FieldType::Object(resolved_fields))
94 }
95 FieldType::Named(name) => {
96 let struct_fields = structs
97 .get(name)
98 .ok_or_else(|| format!("Unknown struct: {}", name))?;
99 let resolved_fields = resolve_named_types(struct_fields, structs)?;
101 Ok(FieldType::Object(resolved_fields))
102 }
103 }
104}
105
106fn field_type_to_json_schema(ft: &FieldType) -> serde_json::Value {
107 use serde_json::json;
108 match ft {
109 FieldType::String => json!({"type": "string"}),
110 FieldType::Number => json!({"type": "number"}),
111 FieldType::Boolean => json!({"type": "boolean"}),
112 FieldType::Array(inner) => json!({
113 "type": "array",
114 "items": field_type_to_json_schema(inner)
115 }),
116 FieldType::Object(fields) => {
117 let properties: serde_json::Map<String, serde_json::Value> = fields
118 .iter()
119 .map(|f| (f.name.clone(), field_type_to_json_schema(&f.field_type)))
120 .collect();
121 let required: Vec<String> = fields.iter().map(|f| f.name.clone()).collect();
122 json!({
123 "type": "object",
124 "properties": properties,
125 "required": required
126 })
127 }
128 FieldType::Named(name) => json!({"$ref": format!("#/definitions/{}", name)}),
129 }
130}
131
132#[derive(Debug, Clone, PartialEq)]
134pub struct UserToolValue {
135 pub name: String,
136 pub params: Vec<Param>,
137 pub return_type: Option<ParserTypeName>,
138 pub body: Block,
139}
140
141#[derive(Debug, Clone, PartialEq)]
143pub struct FnValue {
144 pub name: String,
145 pub params: Vec<Param>,
146 pub return_type: Option<ParserTypeName>,
147 pub body: Block,
148}
149
150#[derive(Debug, Clone, PartialEq)]
152pub struct LambdaValue {
153 pub params: Vec<String>,
154 pub body: crate::parser::ast::LambdaBody,
155}
156
157#[derive(Debug, Clone, PartialEq)]
159pub struct ParallelValue {
160 pub name: String,
161 pub agents: Vec<crate::parser::ast::Expression>,
162 pub timeout_ms: u64,
163}
164
165#[derive(Debug, Clone, PartialEq)]
167pub struct EnumDef {
168 pub name: String,
169 pub variants: Vec<EnumVariantDef>,
170}
171
172#[derive(Debug, Clone, PartialEq)]
174pub struct EnumVariantDef {
175 pub name: String,
176 pub fields: Vec<EnumFieldDef>,
177}
178
179#[derive(Debug, Clone, PartialEq)]
181pub struct EnumFieldDef {
182 pub name: Option<String>,
183 pub type_name: String,
184}
185
186#[derive(Debug, Clone, PartialEq)]
188pub struct EnumValue {
189 pub enum_name: String,
190 pub variant: String,
191 pub data: Vec<Value>,
192}
193
194#[derive(Debug, Clone, PartialEq)]
196pub struct EnumConstructor {
197 pub enum_name: String,
198 pub variant: String,
199 pub expected_fields: usize,
200}
201
202#[derive(Debug, Clone, PartialEq)]
204pub enum Value {
205 String(String),
207 Number(f64),
209 Boolean(bool),
211 Null,
213 Agent(AgentValue),
215 Array(Vec<Value>),
217 Object(HashMap<String, Value>),
219 Tool(UserToolValue),
221 Function(FnValue),
223 Lambda(LambdaValue),
225 Enum(EnumValue),
227 EnumConstructor(EnumConstructor),
229 Parallel(ParallelValue),
231}
232
233#[derive(Debug, Clone, PartialEq)]
235pub struct AgentValue {
236 pub name: String,
238 pub system_prompt: String,
240 pub user_prompt: Option<String>,
242 pub tools: Vec<String>,
244 pub max_steps: Option<u32>,
246 pub model: Option<String>,
248 pub output_schema: Option<OutputSchema>,
250 pub output_retries: u32,
252 pub output_instructions: Option<String>,
254 pub retry_prompt: Option<String>,
256}
257
258impl AgentValue {
259 pub fn new(name: impl Into<String>, system_prompt: impl Into<String>) -> Self {
261 Self {
262 name: name.into(),
263 system_prompt: system_prompt.into(),
264 user_prompt: None,
265 tools: Vec::new(),
266 max_steps: None,
267 model: None,
268 output_schema: None,
269 output_retries: 1, output_instructions: None,
271 retry_prompt: None,
272 }
273 }
274
275 pub fn with_tools(mut self, tools: Vec<String>) -> Self {
277 self.tools = tools;
278 self
279 }
280
281 pub fn with_max_steps(mut self, steps: u32) -> Self {
283 self.max_steps = Some(steps);
284 self
285 }
286
287 pub fn with_model(mut self, model: impl Into<String>) -> Self {
289 self.model = Some(model.into());
290 self
291 }
292
293 pub fn with_output_schema(mut self, schema: OutputSchema) -> Self {
295 self.output_schema = Some(schema);
296 self
297 }
298
299 pub fn with_output_retries(mut self, retries: u32) -> Self {
301 self.output_retries = retries;
302 self
303 }
304
305 pub fn with_output_instructions(mut self, instructions: impl Into<String>) -> Self {
307 self.output_instructions = Some(instructions.into());
308 self
309 }
310
311 pub fn with_retry_prompt(mut self, prompt: impl Into<String>) -> Self {
313 self.retry_prompt = Some(prompt.into());
314 self
315 }
316
317 pub fn with_user_prompt(mut self, prompt: impl Into<String>) -> Self {
319 self.user_prompt = Some(prompt.into());
320 self
321 }
322}
323
324impl fmt::Display for Value {
325 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
326 match self {
327 Value::String(s) => write!(f, "{}", s),
328 Value::Number(n) => {
329 if n.fract() == 0.0 {
330 write!(f, "{}", *n as i64)
331 } else {
332 write!(f, "{}", n)
333 }
334 }
335 Value::Boolean(b) => write!(f, "{}", b),
336 Value::Null => write!(f, "null"),
337 Value::Agent(agent) => write!(f, "<agent {}>", agent.name),
338 Value::Array(items) => {
339 let formatted: Vec<String> = items.iter().map(|v| format!("{}", v)).collect();
340 write!(f, "[{}]", formatted.join(", "))
341 }
342 Value::Object(map) => {
343 let formatted: Vec<String> =
344 map.iter().map(|(k, v)| format!("{}: {}", k, v)).collect();
345 write!(f, "{{{}}}", formatted.join(", "))
346 }
347 Value::Tool(t) => write!(f, "<tool {}>", t.name),
348 Value::Function(func) => write!(f, "<fn {}>", func.name),
349 Value::Lambda(_) => write!(f, "<lambda>"),
350 Value::Enum(e) => {
351 if e.data.is_empty() {
352 write!(f, "{}.{}", e.enum_name, e.variant)
353 } else {
354 let data_str: Vec<String> = e.data.iter().map(|v| v.to_string()).collect();
355 write!(f, "{}.{}({})", e.enum_name, e.variant, data_str.join(", "))
356 }
357 }
358 Value::EnumConstructor(c) => {
359 write!(f, "<enum constructor {}.{}>", c.enum_name, c.variant)
360 }
361 Value::Parallel(p) => write!(f, "<parallel {}>", p.name),
362 }
363 }
364}
365
366impl fmt::Display for AgentValue {
367 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368 write!(f, "<agent {}>", self.name)
369 }
370}
371
372impl Value {
373 pub fn is_truthy(&self) -> bool {
375 match self {
376 Value::Boolean(b) => *b,
377 Value::Null => false,
378 Value::String(s) => !s.is_empty(),
379 Value::Number(n) => *n != 0.0,
380 Value::Agent(_) => true,
381 Value::Array(items) => !items.is_empty(),
382 Value::Object(map) => !map.is_empty(),
383 Value::Tool(_) => true,
384 Value::Function(_) => true,
385 Value::Lambda(_) => true,
386 Value::Enum(_) => true,
387 Value::EnumConstructor(_) => true,
388 Value::Parallel(_) => true,
389 }
390 }
391
392 pub fn type_name(&self) -> String {
394 match self {
395 Value::String(_) => "String".to_string(),
396 Value::Number(_) => "Number".to_string(),
397 Value::Boolean(_) => "Boolean".to_string(),
398 Value::Null => "Null".to_string(),
399 Value::Agent(_) => "Agent".to_string(),
400 Value::Array(_) => "Array".to_string(),
401 Value::Object(_) => "Object".to_string(),
402 Value::Tool(_) => "Tool".to_string(),
403 Value::Function(_) => "Function".to_string(),
404 Value::Lambda(_) => "Lambda".to_string(),
405 Value::Enum(e) => format!("{}.{}", e.enum_name, e.variant),
406 Value::EnumConstructor(c) => format!("EnumConstructor({}.{})", c.enum_name, c.variant),
407 Value::Parallel(_) => "parallel".to_string(),
408 }
409 }
410
411 pub fn as_string(&self) -> Option<&String> {
413 match self {
414 Value::String(s) => Some(s),
415 _ => None,
416 }
417 }
418
419 pub fn as_agent(&self) -> Option<&AgentValue> {
421 match self {
422 Value::Agent(a) => Some(a),
423 _ => None,
424 }
425 }
426
427 pub fn as_array(&self) -> Option<&Vec<Value>> {
429 match self {
430 Value::Array(arr) => Some(arr),
431 _ => None,
432 }
433 }
434
435 pub fn as_object(&self) -> Option<&HashMap<String, Value>> {
437 match self {
438 Value::Object(map) => Some(map),
439 _ => None,
440 }
441 }
442
443 pub fn as_tool(&self) -> Option<&UserToolValue> {
445 match self {
446 Value::Tool(t) => Some(t),
447 _ => None,
448 }
449 }
450
451 pub fn as_function(&self) -> Option<&FnValue> {
453 match self {
454 Value::Function(f) => Some(f),
455 _ => None,
456 }
457 }
458}