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) => Ok(OutputSchema {
22 fields: fields.clone(),
23 }),
24 OutputType::Named(name) => structs
25 .get(name)
26 .map(|fields| OutputSchema {
27 fields: fields.clone(),
28 })
29 .ok_or_else(|| format!("Unknown struct: {}", name)),
30 }
31 }
32
33 pub fn to_json_schema(&self) -> serde_json::Value {
34 use serde_json::json;
35
36 let properties: serde_json::Map<String, serde_json::Value> = self
37 .fields
38 .iter()
39 .map(|f| (f.name.clone(), field_type_to_json_schema(&f.field_type)))
40 .collect();
41
42 let required: Vec<String> = self.fields.iter().map(|f| f.name.clone()).collect();
43
44 json!({
45 "type": "object",
46 "properties": properties,
47 "required": required
48 })
49 }
50}
51
52fn field_type_to_json_schema(ft: &FieldType) -> serde_json::Value {
53 use serde_json::json;
54 match ft {
55 FieldType::String => json!({"type": "string"}),
56 FieldType::Number => json!({"type": "number"}),
57 FieldType::Boolean => json!({"type": "boolean"}),
58 FieldType::Array(inner) => json!({
59 "type": "array",
60 "items": field_type_to_json_schema(inner)
61 }),
62 FieldType::Object(fields) => {
63 let properties: serde_json::Map<String, serde_json::Value> = fields
64 .iter()
65 .map(|f| (f.name.clone(), field_type_to_json_schema(&f.field_type)))
66 .collect();
67 let required: Vec<String> = fields.iter().map(|f| f.name.clone()).collect();
68 json!({
69 "type": "object",
70 "properties": properties,
71 "required": required
72 })
73 }
74 FieldType::Named(name) => json!({"$ref": format!("#/definitions/{}", name)}),
75 }
76}
77
78#[derive(Debug, Clone, PartialEq)]
80pub struct UserToolValue {
81 pub name: String,
82 pub params: Vec<Param>,
83 pub return_type: Option<ParserTypeName>,
84 pub body: Block,
85}
86
87#[derive(Debug, Clone, PartialEq)]
89pub struct FnValue {
90 pub name: String,
91 pub params: Vec<Param>,
92 pub return_type: Option<ParserTypeName>,
93 pub body: Block,
94}
95
96#[derive(Debug, Clone, PartialEq)]
98pub struct LambdaValue {
99 pub params: Vec<String>,
100 pub body: crate::parser::ast::LambdaBody,
101}
102
103#[derive(Debug, Clone, PartialEq)]
105pub struct ParallelValue {
106 pub name: String,
107 pub agents: Vec<crate::parser::ast::Expression>,
108 pub timeout_ms: u64,
109}
110
111#[derive(Debug, Clone, PartialEq)]
113pub struct EnumDef {
114 pub name: String,
115 pub variants: Vec<EnumVariantDef>,
116}
117
118#[derive(Debug, Clone, PartialEq)]
120pub struct EnumVariantDef {
121 pub name: String,
122 pub fields: Vec<EnumFieldDef>,
123}
124
125#[derive(Debug, Clone, PartialEq)]
127pub struct EnumFieldDef {
128 pub name: Option<String>,
129 pub type_name: String,
130}
131
132#[derive(Debug, Clone, PartialEq)]
134pub struct EnumValue {
135 pub enum_name: String,
136 pub variant: String,
137 pub data: Vec<Value>,
138}
139
140#[derive(Debug, Clone, PartialEq)]
142pub struct EnumConstructor {
143 pub enum_name: String,
144 pub variant: String,
145 pub expected_fields: usize,
146}
147
148#[derive(Debug, Clone, PartialEq)]
150pub enum Value {
151 String(String),
153 Number(f64),
155 Boolean(bool),
157 Null,
159 Agent(AgentValue),
161 Array(Vec<Value>),
163 Object(HashMap<String, Value>),
165 Tool(UserToolValue),
167 Function(FnValue),
169 Lambda(LambdaValue),
171 Enum(EnumValue),
173 EnumConstructor(EnumConstructor),
175 Parallel(ParallelValue),
177}
178
179#[derive(Debug, Clone, PartialEq)]
181pub struct AgentValue {
182 pub name: String,
184 pub system_prompt: String,
186 pub user_prompt: Option<String>,
188 pub tools: Vec<String>,
190 pub max_steps: Option<u32>,
192 pub model: Option<String>,
194 pub output_schema: Option<OutputSchema>,
196 pub output_retries: u32,
198 pub output_instructions: Option<String>,
200 pub retry_prompt: Option<String>,
202}
203
204impl AgentValue {
205 pub fn new(name: impl Into<String>, system_prompt: impl Into<String>) -> Self {
207 Self {
208 name: name.into(),
209 system_prompt: system_prompt.into(),
210 user_prompt: None,
211 tools: Vec::new(),
212 max_steps: None,
213 model: None,
214 output_schema: None,
215 output_retries: 1, output_instructions: None,
217 retry_prompt: None,
218 }
219 }
220
221 pub fn with_tools(mut self, tools: Vec<String>) -> Self {
223 self.tools = tools;
224 self
225 }
226
227 pub fn with_max_steps(mut self, steps: u32) -> Self {
229 self.max_steps = Some(steps);
230 self
231 }
232
233 pub fn with_model(mut self, model: impl Into<String>) -> Self {
235 self.model = Some(model.into());
236 self
237 }
238
239 pub fn with_output_schema(mut self, schema: OutputSchema) -> Self {
241 self.output_schema = Some(schema);
242 self
243 }
244
245 pub fn with_output_retries(mut self, retries: u32) -> Self {
247 self.output_retries = retries;
248 self
249 }
250
251 pub fn with_output_instructions(mut self, instructions: impl Into<String>) -> Self {
253 self.output_instructions = Some(instructions.into());
254 self
255 }
256
257 pub fn with_retry_prompt(mut self, prompt: impl Into<String>) -> Self {
259 self.retry_prompt = Some(prompt.into());
260 self
261 }
262
263 pub fn with_user_prompt(mut self, prompt: impl Into<String>) -> Self {
265 self.user_prompt = Some(prompt.into());
266 self
267 }
268}
269
270impl fmt::Display for Value {
271 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
272 match self {
273 Value::String(s) => write!(f, "{}", s),
274 Value::Number(n) => {
275 if n.fract() == 0.0 {
276 write!(f, "{}", *n as i64)
277 } else {
278 write!(f, "{}", n)
279 }
280 }
281 Value::Boolean(b) => write!(f, "{}", b),
282 Value::Null => write!(f, "null"),
283 Value::Agent(agent) => write!(f, "<agent {}>", agent.name),
284 Value::Array(items) => {
285 let formatted: Vec<String> = items.iter().map(|v| format!("{}", v)).collect();
286 write!(f, "[{}]", formatted.join(", "))
287 }
288 Value::Object(map) => {
289 let formatted: Vec<String> =
290 map.iter().map(|(k, v)| format!("{}: {}", k, v)).collect();
291 write!(f, "{{{}}}", formatted.join(", "))
292 }
293 Value::Tool(t) => write!(f, "<tool {}>", t.name),
294 Value::Function(func) => write!(f, "<fn {}>", func.name),
295 Value::Lambda(_) => write!(f, "<lambda>"),
296 Value::Enum(e) => {
297 if e.data.is_empty() {
298 write!(f, "{}.{}", e.enum_name, e.variant)
299 } else {
300 let data_str: Vec<String> = e.data.iter().map(|v| v.to_string()).collect();
301 write!(f, "{}.{}({})", e.enum_name, e.variant, data_str.join(", "))
302 }
303 }
304 Value::EnumConstructor(c) => {
305 write!(f, "<enum constructor {}.{}>", c.enum_name, c.variant)
306 }
307 Value::Parallel(p) => write!(f, "<parallel {}>", p.name),
308 }
309 }
310}
311
312impl fmt::Display for AgentValue {
313 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
314 write!(f, "<agent {}>", self.name)
315 }
316}
317
318impl Value {
319 pub fn is_truthy(&self) -> bool {
321 match self {
322 Value::Boolean(b) => *b,
323 Value::Null => false,
324 Value::String(s) => !s.is_empty(),
325 Value::Number(n) => *n != 0.0,
326 Value::Agent(_) => true,
327 Value::Array(items) => !items.is_empty(),
328 Value::Object(map) => !map.is_empty(),
329 Value::Tool(_) => true,
330 Value::Function(_) => true,
331 Value::Lambda(_) => true,
332 Value::Enum(_) => true,
333 Value::EnumConstructor(_) => true,
334 Value::Parallel(_) => true,
335 }
336 }
337
338 pub fn type_name(&self) -> String {
340 match self {
341 Value::String(_) => "String".to_string(),
342 Value::Number(_) => "Number".to_string(),
343 Value::Boolean(_) => "Boolean".to_string(),
344 Value::Null => "Null".to_string(),
345 Value::Agent(_) => "Agent".to_string(),
346 Value::Array(_) => "Array".to_string(),
347 Value::Object(_) => "Object".to_string(),
348 Value::Tool(_) => "Tool".to_string(),
349 Value::Function(_) => "Function".to_string(),
350 Value::Lambda(_) => "Lambda".to_string(),
351 Value::Enum(e) => format!("{}.{}", e.enum_name, e.variant),
352 Value::EnumConstructor(c) => format!("EnumConstructor({}.{})", c.enum_name, c.variant),
353 Value::Parallel(_) => "parallel".to_string(),
354 }
355 }
356
357 pub fn as_string(&self) -> Option<&String> {
359 match self {
360 Value::String(s) => Some(s),
361 _ => None,
362 }
363 }
364
365 pub fn as_agent(&self) -> Option<&AgentValue> {
367 match self {
368 Value::Agent(a) => Some(a),
369 _ => None,
370 }
371 }
372
373 pub fn as_array(&self) -> Option<&Vec<Value>> {
375 match self {
376 Value::Array(arr) => Some(arr),
377 _ => None,
378 }
379 }
380
381 pub fn as_object(&self) -> Option<&HashMap<String, Value>> {
383 match self {
384 Value::Object(map) => Some(map),
385 _ => None,
386 }
387 }
388
389 pub fn as_tool(&self) -> Option<&UserToolValue> {
391 match self {
392 Value::Tool(t) => Some(t),
393 _ => None,
394 }
395 }
396
397 pub fn as_function(&self) -> Option<&FnValue> {
399 match self {
400 Value::Function(f) => Some(f),
401 _ => None,
402 }
403 }
404}