diff --git a/engine/baml-lib/baml-core/src/ir/json_schema.rs b/engine/baml-lib/baml-core/src/ir/json_schema.rs index 6d218651b..daf436194 100644 --- a/engine/baml-lib/baml-core/src/ir/json_schema.rs +++ b/engine/baml-lib/baml-core/src/ir/json_schema.rs @@ -123,7 +123,7 @@ impl WithJsonSchema for Walker<'_, &Enum> { "enum": self.elem().values .iter() .map(|v| json!({ - "const": v.elem.0.clone() + "const": v.0.elem.0.clone() })) .collect::>(), diff --git a/engine/baml-lib/baml-core/src/ir/repr.rs b/engine/baml-lib/baml-core/src/ir/repr.rs index 8d266626e..3d2db25ed 100644 --- a/engine/baml-lib/baml-core/src/ir/repr.rs +++ b/engine/baml-lib/baml-core/src/ir/repr.rs @@ -621,6 +621,7 @@ impl WithRepr for TemplateStringWalker<'_> { .map(|f| Field { name: id.name().to_string(), r#type: f, + docstring: None, }) .ok() }) @@ -638,7 +639,9 @@ pub struct EnumValue(pub String); #[derive(serde::Serialize, Debug)] pub struct Enum { pub name: EnumId, - pub values: Vec>, + pub values: Vec<(Node, Option)>, + /// Docstring. + pub docstring: Option, } impl WithRepr for EnumValueWalker<'_> { @@ -673,18 +676,20 @@ impl WithRepr for EnumWalker<'_> { fn repr(&self, db: &ParserDatabase) -> Result { Ok(Enum { name: self.name().to_string(), - values: self - .values() - .map(|v| v.node(db)) - .collect::>>()?, + values: self.values().map(|w| (w.node(db).map(|v| (v, w.documentation().map(|s| Docstring(s.to_string())))))).collect::,_>>()?, + docstring: self.get_documentation().map(|s| Docstring(s)) }) } } +#[derive(serde::Serialize, Debug)] +pub struct Docstring(pub String); + #[derive(serde::Serialize, Debug)] pub struct Field { pub name: String, pub r#type: Node, + pub docstring: Option, } impl WithRepr for FieldWalker<'_> { @@ -714,8 +719,10 @@ impl WithRepr for FieldWalker<'_> { .repr(db)?, attributes: self.attributes(db), }, + docstring: self.get_documentation().map(|s| Docstring(s)), }) } + } type ClassId = String; @@ -731,6 +738,9 @@ pub struct Class { /// Parameters to the class definition. pub inputs: Vec<(String, FieldType)>, + + /// Docstring. + pub docstring: Option, } impl WithRepr for ClassWalker<'_> { @@ -764,6 +774,7 @@ impl WithRepr for ClassWalker<'_> { .collect::>>()?, None => Vec::new(), }, + docstring: self.get_documentation().map(|s| Docstring(s)) }) } } @@ -1204,3 +1215,64 @@ pub fn make_test_ir(source_code: &str) -> anyhow::Result { )?; Ok(ir) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::ir::ir_helpers::IRHelper; + + #[test] + fn test_docstrings() { + let ir = make_test_ir(r#" + /// Foo class. + class Foo { + /// Bar field. + bar string + + /// Baz field. + baz int + } + + /// Test enum. + enum TestEnum { + /// First variant. + FIRST + + /// Second variant. + SECOND + + THIRD + } + "#).unwrap(); + + // Test class docstrings + let foo = ir.find_class("Foo").as_ref().unwrap().clone().elem(); + assert_eq!(foo.docstring.as_ref().unwrap().0.as_str(), "Foo class."); + match foo.static_fields.as_slice() { + [field1, field2] => { + assert_eq!(field1.elem.docstring.as_ref().unwrap().0, "Bar field."); + assert_eq!(field2.elem.docstring.as_ref().unwrap().0, "Baz field."); + }, + _ => { + panic!("Expected 2 fields"); + } + } + + // Test enum docstrings + let test_enum = ir.find_enum("TestEnum").as_ref().unwrap().clone().elem(); + assert_eq!(test_enum.docstring.as_ref().unwrap().0.as_str(), "Test enum."); + match test_enum.values.as_slice() { + [val1, val2, val3] => { + assert_eq!(val1.0.elem.0, "FIRST"); + assert_eq!(val1.1.as_ref().unwrap().0, "First variant."); + assert_eq!(val2.0.elem.0, "SECOND"); + assert_eq!(val2.1.as_ref().unwrap().0, "Second variant."); + assert_eq!(val3.0.elem.0, "THIRD"); + assert!(val3.1.is_none()); + }, + _ => { + panic!("Expected 3 enum values"); + } + } + } +} diff --git a/engine/baml-lib/baml-core/src/ir/walker.rs b/engine/baml-lib/baml-core/src/ir/walker.rs index 181cfdbcd..034bf2e3a 100644 --- a/engine/baml-lib/baml-core/src/ir/walker.rs +++ b/engine/baml-lib/baml-core/src/ir/walker.rs @@ -133,7 +133,7 @@ impl<'a> Walker<'a, &'a Enum> { pub fn walk_values(&'a self) -> impl Iterator> { self.item.elem.values.iter().map(|v| Walker { db: self.db, - item: v, + item: &v.0, }) } @@ -142,10 +142,10 @@ impl<'a> Walker<'a, &'a Enum> { .elem .values .iter() - .find(|v| v.elem.0 == name) + .find(|v| v.0.elem.0 == name) .map(|v| Walker { db: self.db, - item: v, + item: &v.0, }) } diff --git a/engine/baml-lib/parser-database/src/walkers/class.rs b/engine/baml-lib/parser-database/src/walkers/class.rs index 5dd2500b9..82887b9c5 100644 --- a/engine/baml-lib/parser-database/src/walkers/class.rs +++ b/engine/baml-lib/parser-database/src/walkers/class.rs @@ -59,6 +59,12 @@ impl<'db> ClassWalker<'db> { }) } + + /// Class docstring. + pub fn get_documentation(&self) -> Option { + self.ast_type_block().documentation.as_ref().map(|c| c.text.clone()) + } + /// The name of the template string. pub fn add_to_types(self, types: &mut internal_baml_jinja_types::PredefinedTypes) { types.add_class( diff --git a/engine/baml-lib/parser-database/src/walkers/field.rs b/engine/baml-lib/parser-database/src/walkers/field.rs index 27b7de8e4..3470b720e 100644 --- a/engine/baml-lib/parser-database/src/walkers/field.rs +++ b/engine/baml-lib/parser-database/src/walkers/field.rs @@ -39,6 +39,11 @@ impl<'db> FieldWalker<'db> { result } + + /// The field's docstring. + pub fn get_documentation(&self) -> Option { + self.ast_field().documentation.as_ref().map(|c| c.text.clone()) + } } impl<'db> WithName for FieldWalker<'db> { diff --git a/engine/baml-lib/schema-ast/src/ast/comment.rs b/engine/baml-lib/schema-ast/src/ast/comment.rs index b7463b14a..6aef87e0c 100644 --- a/engine/baml-lib/schema-ast/src/ast/comment.rs +++ b/engine/baml-lib/schema-ast/src/ast/comment.rs @@ -1,4 +1,4 @@ #[derive(Debug, Clone, PartialEq)] -pub(crate) struct Comment { +pub struct Comment { pub text: String, } diff --git a/engine/baml-lib/schema-ast/src/ast/field.rs b/engine/baml-lib/schema-ast/src/ast/field.rs index 1641ca83b..76355ef77 100644 --- a/engine/baml-lib/schema-ast/src/ast/field.rs +++ b/engine/baml-lib/schema-ast/src/ast/field.rs @@ -29,7 +29,7 @@ pub struct Field { /// ^^^^^^^^^^^ /// name String @id @default("lol") /// ``` - pub(crate) documentation: Option, + pub documentation: Option, /// The attributes of this field. /// /// ```ignore diff --git a/engine/baml-lib/schema-ast/src/ast/type_expression_block.rs b/engine/baml-lib/schema-ast/src/ast/type_expression_block.rs index 87d5147c9..608352e9b 100644 --- a/engine/baml-lib/schema-ast/src/ast/type_expression_block.rs +++ b/engine/baml-lib/schema-ast/src/ast/type_expression_block.rs @@ -79,7 +79,7 @@ pub struct TypeExpressionBlock { /// Value2 /// } /// ``` - pub(crate) documentation: Option, + pub documentation: Option, /// The location of this enum in the text representation. pub span: Span, diff --git a/engine/baml-lib/schema-ast/src/parser/parse_schema.rs b/engine/baml-lib/schema-ast/src/parser/parse_schema.rs index c8e00dd6c..977e0193d 100644 --- a/engine/baml-lib/schema-ast/src/parser/parse_schema.rs +++ b/engine/baml-lib/schema-ast/src/parser/parse_schema.rs @@ -121,7 +121,9 @@ pub fn parse_schema( // Some(Rule::enum_declaration) => { // pending_block_comment = Some(current); // } - _ => (), + _ => { + pending_block_comment = Some(current); + } } } // We do nothing here. @@ -244,6 +246,103 @@ mod tests { let result = parse_schema(&root_path.into(), &source).unwrap(); assert_eq!(result.1.errors().len(), 0); } + + #[test] + fn test_comments() { + let input = r##" + /// Doc comment for Foo + /// has multiple lines + class Foo { + /// A nice bar. + bar int + + /// Followed by a + /// multiline baz. + baz string + } + + /// Documented enum. + enum E { + /// Documented variant. + EFoo + + /// Another documented variant. + EBar + EBaz + } + "##; + let root_path = "a.baml"; + let source = SourceFile::new_static(root_path.into(), input); + let schema = parse_schema(&root_path.into(), &source).unwrap().0; + let mut tops = schema.iter_tops(); + let foo_top = tops.next().unwrap().1; + match foo_top { + Top::Class(TypeExpressionBlock { + name, + fields, + documentation, + .. + }) => { + assert_eq!(name.to_string().as_str(), "Foo"); + assert_eq!( + documentation.as_ref().unwrap().text.as_str(), + "Doc comment for Foo\nhas multiple lines" + ); + match fields.as_slice() { + [field1, field2] => { + assert_eq!( + field1.documentation.as_ref().unwrap().text.as_str(), + "A nice bar." + ); + assert_eq!( + field2.documentation.as_ref().unwrap().text.as_str(), + "Followed by a\nmultiline baz." + ); + } + _ => { + panic!("Expected exactly 2 fields"); + } + } + } + _ => { + panic!("Expected class.") + } + } + let e_top = tops.next().unwrap().1; + match e_top { + Top::Enum(TypeExpressionBlock { + name, + fields, + documentation, + .. + }) => { + assert_eq!(name.to_string().as_str(), "E"); + assert_eq!( + documentation.as_ref().unwrap().text.as_str(), + "Documented enum." + ); + match fields.as_slice() { + [field1, field2, field3] => { + assert_eq!( + field1.documentation.as_ref().unwrap().text.as_str(), + "Documented variant." + ); + assert_eq!( + field2.documentation.as_ref().unwrap().text.as_str(), + "Another documented variant." + ); + assert!(field3.documentation.is_none()); + } + _ => { + panic!("Expected exactly 3 enum variants"); + } + } + } + _ => { + panic!("Expected enum. got {e_top:?}") + } + } + } } fn get_expected_from_error(positives: &[Rule]) -> String { diff --git a/engine/language_client_codegen/src/openapi.rs b/engine/language_client_codegen/src/openapi.rs index e241a789d..51c65f852 100644 --- a/engine/language_client_codegen/src/openapi.rs +++ b/engine/language_client_codegen/src/openapi.rs @@ -457,7 +457,7 @@ impl<'ir> TryFrom> for TypeSpecWithMeta { .elem .values .iter() - .map(|v| v.elem.0.to_string()) + .map(|v| v.0.elem.0.to_string()) .collect(), ), r#const: None, diff --git a/engine/language_client_codegen/src/python/generate_types.rs b/engine/language_client_codegen/src/python/generate_types.rs index 4c2044770..828a337dc 100644 --- a/engine/language_client_codegen/src/python/generate_types.rs +++ b/engine/language_client_codegen/src/python/generate_types.rs @@ -7,7 +7,7 @@ use crate::{field_type_attributes, type_check_attributes, TypeCheckAttributes}; use super::python_language_features::ToPython; use internal_baml_core::ir::{ - repr::IntermediateRepr, ClassWalker, EnumWalker, FieldType, IRHelper, + repr::{Docstring, IntermediateRepr}, ClassWalker, EnumWalker, FieldType, IRHelper, }; #[derive(askama::Template)] @@ -22,22 +22,25 @@ pub(crate) struct PythonTypes<'ir> { pub(crate) struct TypeBuilder<'ir> { enums: Vec>, classes: Vec>, - checks_classes: Vec>, } struct PythonEnum<'ir> { name: &'ir str, - values: Vec<&'ir str>, + values: Vec<(&'ir str, Option)>, dynamic: bool, + docstring: Option, } struct PythonClass<'ir> { name: Cow<'ir, str>, - // the name, and the type of the field - fields: Vec<(Cow<'ir, str>, String)>, + /// The docstring for the class, including comment delimiters. + docstring: Option, + // the name, type and docstring of the field. + fields: Vec<(Cow<'ir, str>, String, Option)>, dynamic: bool, } + #[derive(askama::Template)] #[template(path = "partial_types.py.j2", escape = "none")] pub(crate) struct PythonStreamTypes<'ir> { @@ -48,8 +51,10 @@ pub(crate) struct PythonStreamTypes<'ir> { struct PartialPythonClass<'ir> { name: &'ir str, dynamic: bool, - // the name, and the type of the field - fields: Vec<(&'ir str, String)>, + /// The docstring for the class, including comment delimiters. + docstring: Option, + // the name, type and docstring of the field. + fields: Vec<(&'ir str, String, Option)>, } impl<'ir> TryFrom<(&'ir IntermediateRepr, &'_ crate::GeneratorArgs)> for PythonTypes<'ir> { @@ -71,14 +76,9 @@ impl<'ir> TryFrom<(&'ir IntermediateRepr, &'_ crate::GeneratorArgs)> for TypeBui fn try_from( (ir, _): (&'ir IntermediateRepr, &'_ crate::GeneratorArgs), ) -> Result> { - let checks_classes = type_check_attributes(ir) - .into_iter() - .map(|checks| type_def_for_checks(checks)) - .collect::>(); Ok(TypeBuilder { enums: ir.walk_enums().map(PythonEnum::from).collect::>(), classes: ir.walk_classes().map(PythonClass::from).collect::>(), - checks_classes, }) } } @@ -93,8 +93,9 @@ impl<'ir> From> for PythonEnum<'ir> { .elem .values .iter() - .map(|v| v.elem.0.as_str()) + .map(|v| (v.0.elem.0.as_str(), v.1.as_ref().map(|d| render_docstring(d)))) .collect(), + docstring: e.item.elem.docstring.as_ref().map(|s| render_docstring(s)) } } } @@ -116,9 +117,11 @@ impl<'ir> From> for PythonClass<'ir> { &f.elem.r#type.elem, &f.elem.r#type.elem.to_type_ref(&c.db), ), + f.elem.docstring.as_ref().map(|d| render_docstring(d)), ) }) .collect(), + docstring: c.item.elem.docstring.as_ref().map(|d| render_docstring(d)), } } } @@ -153,9 +156,11 @@ impl<'ir> From> for PartialPythonClass<'ir> { &f.elem.r#type.elem, &f.elem.r#type.elem.to_partial_type_ref(&c.db, false), ), + f.elem.docstring.as_ref().map(|d| render_docstring(d)), ) }) .collect(), + docstring: c.item.elem.docstring.as_ref().map(|d| render_docstring(d)), } } } @@ -179,17 +184,6 @@ pub fn type_name_for_checks(checks: &TypeCheckAttributes) -> String { format!["Literal[{check_names}]"] } -fn type_def_for_checks(checks: TypeCheckAttributes) -> PythonClass<'static> { - PythonClass { - name: Cow::Owned(type_name_for_checks(&checks)), - fields: checks - .0 - .into_iter() - .map(|check_name| (Cow::Owned(check_name), "Check".to_string())) - .collect(), - dynamic: false, - } -} /// Returns the Python `Literal` representation of `self`. pub fn to_python_literal(literal: &LiteralValue) -> String { @@ -322,3 +316,10 @@ impl ToTypeReferenceInTypeDefinition for FieldType { } } } + +/// Render the BAML documentation (a bare string with padding stripped) +/// into a Python docstring. (Indented once and surrounded by """). +fn render_docstring(d: &Docstring) -> String { + let lines = d.0.as_str().replace("\n", "\n "); + format!("\"\"\"{lines}\"\"\"") +} diff --git a/engine/language_client_codegen/src/python/templates/partial_types.py.j2 b/engine/language_client_codegen/src/python/templates/partial_types.py.j2 index 7207e974b..f3d75e380 100644 --- a/engine/language_client_codegen/src/python/templates/partial_types.py.j2 +++ b/engine/language_client_codegen/src/python/templates/partial_types.py.j2 @@ -17,12 +17,18 @@ from .types import Checked, Check {# Partial classes (used for streaming) -#} {% for cls in partial_classes %} class {{cls.name}}(BaseModel): - {% if cls.dynamic %} + {%- if let Some(docstring) = cls.docstring %} + {{docstring}} + {%- endif %} + {%- if cls.dynamic %} model_config = ConfigDict(extra='allow') {%- endif %} - {% if cls.fields.is_empty() && !cls.dynamic %}pass{% endif %} + {%- if cls.fields.is_empty() && !cls.dynamic %}pass{% endif %} - {%- for (name, partial_type) in cls.fields %} + {%- for (name, partial_type, m_docstring) in cls.fields %} {{name}}: {{partial_type}} + {%- if let Some(docstring) = m_docstring %} + {{ docstring }} + {%- endif %} {%- endfor %} {% endfor %} diff --git a/engine/language_client_codegen/src/python/templates/type_builder.py.j2 b/engine/language_client_codegen/src/python/templates/type_builder.py.j2 index aa885801c..a439ac8ab 100644 --- a/engine/language_client_codegen/src/python/templates/type_builder.py.j2 +++ b/engine/language_client_codegen/src/python/templates/type_builder.py.j2 @@ -31,7 +31,7 @@ class {{cls.name}}Builder: def __init__(self, tb: _TypeBuilder): _tb = tb._tb # type: ignore (we know how to use this private attribute) self.__bldr = _tb.class_("{{cls.name}}") - self.__properties: typing.Set[str] = set([{% for (name, _) in cls.fields %} "{{name}}", {% endfor %}]) + self.__properties: typing.Set[str] = set([{% for (name, _, _) in cls.fields %} "{{name}}", {% endfor %}]) self.__props = {{cls.name}}Properties(self.__bldr, self.__properties) def type(self) -> FieldType: @@ -54,7 +54,7 @@ class {{cls.name}}Properties: self.__bldr = cls_bldr self.__properties = properties - {% for (name, type) in cls.fields %} + {% for (name, type, _) in cls.fields %} @property def {{name}}(self) -> ClassPropertyBuilder: @@ -73,7 +73,7 @@ class {{enum.name}}Builder: def __init__(self, tb: _TypeBuilder): _tb = tb._tb # type: ignore (we know how to use this private attribute) self.__bldr = _tb.enum("{{enum.name}}") - self.__values: typing.Set[str] = set([{% for value in enum.values %} "{{value}}", {% endfor %}]) + self.__values: typing.Set[str] = set([{% for (value, _) in enum.values %} "{{value}}", {% endfor %}]) self.__vals = {{enum.name}}Values(self.__bldr, self.__values) def type(self) -> FieldType: @@ -97,7 +97,7 @@ class {{enum.name}}Values: self.__bldr = enum_bldr self.__values = values - {% for value in enum.values %} + {% for (value, _) in enum.values %} @property def {{value}}(self) -> EnumValueBuilder: diff --git a/engine/language_client_codegen/src/python/templates/types.py.j2 b/engine/language_client_codegen/src/python/templates/types.py.j2 index 0aeaf22ef..86b776db3 100644 --- a/engine/language_client_codegen/src/python/templates/types.py.j2 +++ b/engine/language_client_codegen/src/python/templates/types.py.j2 @@ -27,21 +27,35 @@ def all_succeeded(checks: Dict[CheckName, Check]) -> bool: {# Enums -#} {% for enum in enums %} class {{enum.name}}(str, Enum): + {%- if let Some(docstring) = enum.docstring %} + {{docstring}} + {%- endif %} {% if enum.values.is_empty() %}pass{% endif %} - {%- for value in enum.values %} + {%- for (value, m_docstring) in enum.values %} {{ value }} = "{{ value }}" + {%- if let Some(docstring) = m_docstring %} + {{ docstring }} + {%- endif %} + {%- endfor %} {% endfor %} {#- Classes -#} {% for cls in classes %} class {{cls.name}}(BaseModel): - {% if cls.dynamic %} + {%- if let Some(docstring) = cls.docstring %} + {{docstring}} + {%- endif %} + {%- if cls.dynamic %} model_config = ConfigDict(extra='allow') {%- endif %} - {% if cls.fields.is_empty() && !cls.dynamic %}pass{% endif %} + {%- if cls.fields.is_empty() && !cls.dynamic %}pass{% endif %} - {%- for (name, type) in cls.fields %} + {%- for (name, type, m_docstring) in cls.fields %} {{name}}: {{type}} + {%- if let Some(docstring) = m_docstring %} + {{ docstring }} + + {%- endif %} {%- endfor %} {% endfor %} diff --git a/engine/language_client_codegen/src/ruby/generate_types.rs b/engine/language_client_codegen/src/ruby/generate_types.rs index 4f007f3e7..1e776bb8d 100644 --- a/engine/language_client_codegen/src/ruby/generate_types.rs +++ b/engine/language_client_codegen/src/ruby/generate_types.rs @@ -7,7 +7,7 @@ use itertools::Itertools; use crate::{field_type_attributes, type_check_attributes, TypeCheckAttributes}; use super::ruby_language_features::ToRuby; -use internal_baml_core::ir::{repr::IntermediateRepr, ClassWalker, EnumWalker, FieldType}; +use internal_baml_core::ir::{repr::{Docstring, IntermediateRepr}, ClassWalker, EnumWalker, FieldType}; #[derive(askama::Template)] #[template(path = "types.rb.j2", escape = "none")] @@ -20,12 +20,14 @@ struct RubyEnum<'ir> { pub name: &'ir str, pub values: Vec<&'ir str>, dynamic: bool, + docstring: Option, } struct RubyStruct<'ir> { name: Cow<'ir, str>, - fields: Vec<(Cow<'ir, str>, String)>, + fields: Vec<(Cow<'ir, str>, String, Option)>, dynamic: bool, + docstring: Option, } #[derive(askama::Template)] @@ -37,8 +39,9 @@ pub(crate) struct RubyStreamTypes<'ir> { /// The Python class corresponding to Partial struct PartialRubyStruct<'ir> { name: &'ir str, - // the name, and the type of the field - fields: Vec<(&'ir str, String)>, + // the name, type and docstring of the field + fields: Vec<(&'ir str, String, Option)>, + docstring: Option, } #[derive(askama::Template)] @@ -69,8 +72,9 @@ impl<'ir> From> for RubyEnum<'ir> { .elem .values .iter() - .map(|v| v.elem.0.as_str()) + .map(|v| v.0.elem.0.as_str()) .collect(), + docstring: e.item.elem.docstring.as_ref().map(|d| render_docstring(d, true)) } } } @@ -85,8 +89,13 @@ impl<'ir> From> for RubyStruct<'ir> { .elem .static_fields .iter() - .map(|f| (Cow::Borrowed(f.elem.name.as_str()), f.elem.r#type.elem.to_type_ref())) + .map(|f| ( + Cow::Borrowed(f.elem.name.as_str()), + f.elem.r#type.elem.to_type_ref(), + f.elem.docstring.as_ref().map(|d| render_docstring(d, true)) + )) .collect(), + docstring: c.item.elem.docstring.as_ref().map(|d| render_docstring(d, false)), } } } @@ -114,9 +123,11 @@ impl<'ir> From> for PartialRubyStruct<'ir> { ( f.elem.name.as_str(), f.elem.r#type.elem.to_partial_type_ref(), + f.elem.docstring.as_ref().map(|d| render_docstring(d, true)) ) }) .collect(), + docstring: c.item.elem.docstring.as_ref().map(|d| render_docstring(d, false)), } } } @@ -194,3 +205,15 @@ impl<'ir> TryFrom<(&'ir IntermediateRepr, &'_ crate::GeneratorArgs)> for TypeReg }) } } + +/// Render the BAML documentation (a bare string with padding stripped) +/// into a Ruby docstring. +fn render_docstring(d: &Docstring, indented: bool) -> String { + if indented { + let lines = d.0.as_str().replace("\n", "\n # "); + format!("# {lines}") + } else { + let lines = d.0.as_str().replace("\n", "\n # "); + format!("# {lines}") + } +} diff --git a/engine/language_client_codegen/src/ruby/templates/partial-types.rb.j2 b/engine/language_client_codegen/src/ruby/templates/partial-types.rb.j2 index 37baa9e91..bc2159051 100644 --- a/engine/language_client_codegen/src/ruby/templates/partial-types.rb.j2 +++ b/engine/language_client_codegen/src/ruby/templates/partial-types.rb.j2 @@ -13,16 +13,22 @@ module Baml {#- https://sorbet.org/docs/tstruct #} {%- for cls in partial_classes %} + {%- if let Some(docstring) = cls.docstring %} + {{docstring}} + {%- endif %} class {{cls.name}} < T::Struct include Baml::Sorbet::Struct - {%- for (name, type) in cls.fields %} + {%- for (name, type, m_docstring) in cls.fields %} + {%- if let Some(docstring) = m_docstring %} + {{ docstring }} + {%- endif %} const :{{name}}, {{type}} {%- endfor %} def initialize(props) super( - {%- for (name, _) in cls.fields %} + {%- for (name, _, _) in cls.fields %} {{name}}: props[:{{name}}], {%- endfor %} ) @@ -32,4 +38,4 @@ module Baml end {%- endfor %} end -end \ No newline at end of file +end diff --git a/engine/language_client_codegen/src/ruby/templates/type-registry.rb.j2 b/engine/language_client_codegen/src/ruby/templates/type-registry.rb.j2 index c2d15fc6a..56dd290fb 100644 --- a/engine/language_client_codegen/src/ruby/templates/type-registry.rb.j2 +++ b/engine/language_client_codegen/src/ruby/templates/type-registry.rb.j2 @@ -102,7 +102,7 @@ module Baml {% for cls in classes if cls.dynamic %} def {{cls.name}} - ClassBuilder.new(@registry, "{{cls.name}}", Set[{% for (name, _) in cls.fields %} "{{name}}", {% endfor %}]) + ClassBuilder.new(@registry, "{{cls.name}}", Set[{% for (name, _, _) in cls.fields %} "{{name}}", {% endfor %}]) end {% endfor %} diff --git a/engine/language_client_codegen/src/ruby/templates/types.rb.j2 b/engine/language_client_codegen/src/ruby/templates/types.rb.j2 index 5445c42af..837f8d1b4 100644 --- a/engine/language_client_codegen/src/ruby/templates/types.rb.j2 +++ b/engine/language_client_codegen/src/ruby/templates/types.rb.j2 @@ -7,6 +7,9 @@ module Baml {#- https://sorbet.org/docs/tenum #} {%- for enum in enums %} class {{ enum.name }} < T::Enum + {%- if let Some(docstring) = enum.docstring %} + {{docstring}} + {%- endif %} {%- if enum.values.len() > 0 %} enums do {%- for value in enum.values %} @@ -24,16 +27,22 @@ module Baml {#- https://sorbet.org/docs/tstruct #} {%- for cls in classes %} + {%- if let Some(docstring) = cls.docstring %} + {{docstring}} + {%- endif %} class {{cls.name}} < T::Struct include Baml::Sorbet::Struct - {%- for (name, type) in cls.fields %} + {%- for (name, type, m_docstring) in cls.fields %} + {%- if let Some(docstring) = m_docstring %} + {{ docstring }} + {%- endif %} const :{{name}}, {{type}} {%- endfor %} def initialize(props) super( - {%- for (name, _) in cls.fields %} + {%- for (name, _, _) in cls.fields %} {{name}}: props[:{{name}}], {%- endfor %} ) diff --git a/engine/language_client_codegen/src/typescript/generate_types.rs b/engine/language_client_codegen/src/typescript/generate_types.rs index 55856ad4d..32d2cf0c0 100644 --- a/engine/language_client_codegen/src/typescript/generate_types.rs +++ b/engine/language_client_codegen/src/typescript/generate_types.rs @@ -3,7 +3,7 @@ use std::borrow::Cow; use anyhow::Result; use itertools::Itertools; -use internal_baml_core::ir::{repr::IntermediateRepr, ClassWalker, EnumWalker}; +use internal_baml_core::ir::{repr::{Docstring, IntermediateRepr}, ClassWalker, EnumWalker}; use crate::{type_check_attributes, GeneratorArgs, TypeCheckAttributes}; @@ -25,14 +25,16 @@ pub(crate) struct TypescriptTypes<'ir> { struct TypescriptEnum<'ir> { pub name: &'ir str, - pub values: Vec<&'ir str>, + pub values: Vec<(&'ir str, Option)>, pub dynamic: bool, + pub docstring: Option, } pub struct TypescriptClass<'ir> { pub name: Cow<'ir, str>, - pub fields: Vec<(Cow<'ir, str>, bool, String)>, + pub fields: Vec<(Cow<'ir, str>, bool, String, Option)>, pub dynamic: bool, + pub docstring: Option, } impl<'ir> TryFrom<(&'ir IntermediateRepr, &'ir GeneratorArgs)> for TypescriptTypes<'ir> { @@ -81,8 +83,9 @@ impl<'ir> From<&EnumWalker<'ir>> for TypescriptEnum<'ir> { .elem .values .iter() - .map(|v| v.elem.0.as_str()) + .map(|v| (v.0.elem.0.as_str(), v.1.as_ref().map(|s| render_docstring(s, true)))) .collect(), + docstring: e.item.elem.docstring.as_ref().map(|d| render_docstring(d, false)), } } } @@ -102,9 +105,11 @@ impl<'ir> From<&ClassWalker<'ir>> for TypescriptClass<'ir> { Cow::Borrowed(f.elem.name.as_str()), f.elem.r#type.elem.is_optional(), f.elem.r#type.elem.to_type_ref(&c.db), + f.elem.docstring.as_ref().map(|d| render_docstring(d, true)), ) }) .collect(), + docstring: c.item.elem.docstring.as_ref().map(|d| render_docstring(d, false)), } } } @@ -112,3 +117,16 @@ impl<'ir> From<&ClassWalker<'ir>> for TypescriptClass<'ir> { pub fn type_name_for_checks(checks: &TypeCheckAttributes) -> String { checks.0.iter().map(|check| format!("\"{check}\"")).sorted().join(" | ") } + +/// Render the BAML documentation (a bare string with padding stripped) +/// into a TS docstring. +/// (Optionally indented and formatted as a TS block comment). +fn render_docstring(d: &Docstring, indented: bool) -> String { + if indented { + let lines = d.0.as_str().replace("\n", "\n * "); + format!("/**\n * {lines}\n */") + } else { + let lines = d.0.as_str().replace("\n", "\n * "); + format!("/**\n * {lines}\n */") + } +} diff --git a/engine/language_client_codegen/src/typescript/templates/type_builder.ts.j2 b/engine/language_client_codegen/src/typescript/templates/type_builder.ts.j2 index 1f0fdf3a1..c41456628 100644 --- a/engine/language_client_codegen/src/typescript/templates/type_builder.ts.j2 +++ b/engine/language_client_codegen/src/typescript/templates/type_builder.ts.j2 @@ -5,11 +5,11 @@ export default class TypeBuilder { private tb: _TypeBuilder; {% for cls in classes %}{% if cls.dynamic %} {{cls.name}}: ClassBuilder<'{{cls.name}}' - {%- for (name, _, _) in cls.fields %}{% if loop.first %}, {%endif%}"{{name}}"{% if !loop.last %} | {% endif %}{% endfor -%} + {%- for (name, _, _, _) in cls.fields %}{% if loop.first %}, {%endif%}"{{name}}"{% if !loop.last %} | {% endif %}{% endfor -%} >; {% endif %}{% endfor %} {% for enum in enums %}{% if enum.dynamic %} - {{enum.name}}: EnumBuilder<'{{enum.name}}'{%- for value in enum.values %}{% if loop.first %}, {%endif%}"{{value}}"{% if !loop.last %} | {% endif %}{% endfor -%}>; + {{enum.name}}: EnumBuilder<'{{enum.name}}'{%- for (value, _) in enum.values %}{% if loop.first %}, {%endif%}"{{value}}"{% if !loop.last %} | {% endif %}{% endfor -%}>; {% endif %}{% endfor %} constructor() { @@ -23,12 +23,12 @@ export default class TypeBuilder { }); {% for cls in classes %}{% if cls.dynamic %} this.{{cls.name}} = this.tb.classBuilder("{{cls.name}}", [ - {% for (name, _, _) in cls.fields %}"{{name}}",{% endfor %} + {% for (name, _, _, _) in cls.fields %}"{{name}}",{% endfor %} ]); {% endif %}{% endfor %} {% for enum in enums %}{% if enum.dynamic %} this.{{enum.name}} = this.tb.enumBuilder("{{enum.name}}", [ - {% for value in enum.values %}"{{value}}",{% endfor %} + {% for (value, _) in enum.values %}"{{value}}",{% endfor %} ]); {% endif %}{% endfor %} } diff --git a/engine/language_client_codegen/src/typescript/templates/types.ts.j2 b/engine/language_client_codegen/src/typescript/templates/types.ts.j2 index 247515b72..91ab34165 100644 --- a/engine/language_client_codegen/src/typescript/templates/types.ts.j2 +++ b/engine/language_client_codegen/src/typescript/templates/types.ts.j2 @@ -20,17 +20,32 @@ export function get_checks(checks: Record TestClassAlias {\n client GPT35\n prompt #\"\n {{ctx.output_format}}\n \"#\n}\n\ntest FnTestClassAlias {\n functions [FnTestClassAlias]\n args {\n input \"example input\"\n }\n}\n", "test-files/aliases/enums.baml": "enum TestEnum {\n A @alias(\"k1\") @description(#\"\n User is angry\n \"#)\n B @alias(\"k22\") @description(#\"\n User is happy\n \"#)\n // tests whether k1 doesnt incorrectly get matched with k11\n C @alias(\"k11\") @description(#\"\n User is sad\n \"#)\n D @alias(\"k44\") @description(\n User is confused\n )\n E @description(\n User is excited\n )\n F @alias(\"k5\") // only alias\n \n G @alias(\"k6\") @description(#\"\n User is bored\n With a long description\n \"#)\n \n @@alias(\"Category\")\n}\n\nfunction FnTestAliasedEnumOutput(input: string) -> TestEnum {\n client GPT35\n prompt #\"\n Classify the user input into the following category\n \n {{ ctx.output_format }}\n\n {{ _.role('user') }}\n {{input}}\n\n {{ _.role('assistant') }}\n Category ID:\n \"#\n}\n\ntest FnTestAliasedEnumOutput {\n functions [FnTestAliasedEnumOutput]\n args {\n input \"mehhhhh\"\n }\n}", "test-files/comments/comments.baml": "// add some functions, classes, enums etc with comments all over.", - "test-files/constraints/constraints.baml": "// These classes and functions test several properties of\n// constrains:\n//\n// - The ability for constrains on fields to pass or fail.\n// - The ability for constraints on bare args and return types to pass or fail.\n// - The ability of constraints to influence which variant of a union is chosen\n// by the parser, when the structure is not sufficient to decide.\n\n\nclass Martian {\n age int @check(young_enough, {{ this < 30 }})\n}\n\nclass Earthling {\n age int @check(earth_aged, {{this < 200 and this > 0}}) @check(no_infants, {{this >1}})\n}\n\n\nclass FooAny {\n planetary_age Martian | Earthling\n certainty int @check(unreasonably_certain, {{this == 102931}})\n species string @check(trivial, {{this == \"Homo sapiens\"}}) @check(regex_good, {{this|regex_match(\"Homo\")}}) @check(regex_bad, {{this|regex_match(\"neanderthalensis\")}})\n}\n\n\nfunction PredictAge(name: string) -> FooAny {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling\n and capitalization). I'll give you a hint: If the name\n is \"Greg\", his age is 41.\n\n {{ctx.output_format}}\n \"#\n}\n\n\nfunction PredictAgeBare(inp: string @assert(big_enough, {{this|length > 1}})) -> int @check(too_big, {{this == 10102}}) {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ inp.name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling).\n\n {{ctx.output_format}}\n \"#\n}\n\nfunction ReturnFailingAssert(inp: int @assert(small_int, {{this < 10}})) -> int @assert(big_int, {{this > 100}}) {\n client GPT35\n prompt #\"\n Return the next integer after {{ inp }}.\n\n {{ctx.output_format}}\n \"#\n}\n\nclass TwoStoriesOneTitle {\n title string\n story_a string @assert(too_long_story, {{this|length > 1000000}} )\n story_b string @assert(too_long_story, {{this|length > 1000000}} )\n}\n\nfunction StreamFailingAssertion(theme: string, length: int) -> TwoStoriesOneTitle {\n client GPT35\n prompt #\"\n Tell me two different stories along the theme of {{ theme }} with the same title.\n Please make each about {{ length }} words long.\n {{ctx.output_format}}\n \"#\n}\n\nclass BlockConstraint {\n foo int\n bar string\n @@check(cross_field, {{ this.bar|length > this.foo }})\n}\n\nfunction MakeBlockConstraint() -> BlockConstraint {\n client GPT35\n prompt #\"\n Generate an output in the following schema with a short string and a large int.\n\n {{ ctx.output_format }}\n \"#\n}\n\nclass NestedBlockConstraint {\n nbc BlockConstraint\n}\n\nclass BlockConstraintForParam {\n bcfp int\n bcfp2 string\n @@assert(hi, {{ this.bcfp2|length < this.bcfp }})\n}\n\nclass NestedBlockConstraintForParam {\n nbcfp BlockConstraintForParam\n}\n\nfunction MakeNestedBlockConstraint() -> NestedBlockConstraint {\n client GPT35\n prompt #\"Generate an output where the inner foo is 1 and the inner bar is \"hello\".\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseBlockConstraint(inp: BlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseNestedBlockConstraint(inp: NestedBlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n", + "test-files/constraints/constraints.baml": "// These classes and functions test several properties of\n// constrains:\n//\n// - The ability for constrains on fields to pass or fail.\n// - The ability for constraints on bare args and return types to pass or fail.\n// - The ability of constraints to influence which variant of a union is chosen\n// by the parser, when the structure is not sufficient to decide.\n\n/// A Martian organism with an age.\n/// Such a nice type.\nclass Martian {\n /// The age of the Martian in Mars years.\n /// So many Mars years.\n age int @check(young_enough, {{ this < 30 }})\n}\n\nclass Earthling {\n age int @check(earth_aged, {{this < 200 and this > 0}}) @check(no_infants, {{this >1}})\n}\n\n\nclass FooAny {\n planetary_age Martian | Earthling\n certainty int @check(unreasonably_certain, {{this == 102931}})\n species string @check(trivial, {{this == \"Homo sapiens\"}}) @check(regex_good, {{this|regex_match(\"Homo\")}}) @check(regex_bad, {{this|regex_match(\"neanderthalensis\")}})\n}\n\n\nfunction PredictAge(name: string) -> FooAny {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling\n and capitalization). I'll give you a hint: If the name\n is \"Greg\", his age is 41.\n\n {{ctx.output_format}}\n \"#\n}\n\n\nfunction PredictAgeBare(inp: string @assert(big_enough, {{this|length > 1}})) -> int @check(too_big, {{this == 10102}}) {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ inp.name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling).\n\n {{ctx.output_format}}\n \"#\n}\n\nfunction ReturnFailingAssert(inp: int @assert(small_int, {{this < 10}})) -> int @assert(big_int, {{this > 100}}) {\n client GPT35\n prompt #\"\n Return the next integer after {{ inp }}.\n\n {{ctx.output_format}}\n \"#\n}\n\nclass TwoStoriesOneTitle {\n title string\n story_a string @assert(too_long_story, {{this|length > 1000000}} )\n story_b string @assert(too_long_story, {{this|length > 1000000}} )\n}\n\nfunction StreamFailingAssertion(theme: string, length: int) -> TwoStoriesOneTitle {\n client GPT35\n prompt #\"\n Tell me two different stories along the theme of {{ theme }} with the same title.\n Please make each about {{ length }} words long.\n {{ctx.output_format}}\n \"#\n}\n\nclass BlockConstraint {\n foo int\n bar string\n @@check(cross_field, {{ this.bar|length > this.foo }})\n}\n\nfunction MakeBlockConstraint() -> BlockConstraint {\n client GPT35\n prompt #\"\n Generate an output in the following schema with a short string and a large int.\n\n {{ ctx.output_format }}\n \"#\n}\n\nclass NestedBlockConstraint {\n nbc BlockConstraint\n}\n\nclass BlockConstraintForParam {\n bcfp int\n bcfp2 string\n @@assert(hi, {{ this.bcfp2|length < this.bcfp }})\n}\n\nclass NestedBlockConstraintForParam {\n nbcfp BlockConstraintForParam\n}\n\nfunction MakeNestedBlockConstraint() -> NestedBlockConstraint {\n client GPT35\n prompt #\"Generate an output where the inner foo is 1 and the inner bar is \"hello\".\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseBlockConstraint(inp: BlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseNestedBlockConstraint(inp: NestedBlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n", "test-files/constraints/contact-info.baml": "class PhoneNumber {\n value string @assert(valid_phone_number, {{this|regex_match(\"\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}\")}})\n}\n\nclass EmailAddress {\n value string @assert(valid_email, {{this|regex_match(\"^[_]*([a-z0-9]+(\\.|_*)?)+@([a-z][a-z0-9-]+(\\.|-*\\.))+[a-z]{2,6}$\")}})\n}\n\nclass ContactInfo {\n primary PhoneNumber | EmailAddress\n secondary (PhoneNumber | EmailAddress)?\n}\n\nfunction ExtractContactInfo(document: string) -> ContactInfo {\n client GPT35\n prompt #\"\n Extract a primary contact info, and if possible a secondary contact\n info, from this document:\n\n {{ document }}\n\n {{ ctx.output_format }}\n \"#\n}\n", "test-files/constraints/malformed-constraints.baml": "class MalformedConstraints {\n foo int @check(foo_check, {{ this.length() > 0 }})\n}\n\nclass MalformedConstraints2 {\n foo int @assert(foo_check, {{ this.length() > 0 }})\n}\n\nfunction ReturnMalformedConstraints(a: int) -> MalformedConstraints {\n client GPT35\n prompt #\"\n Return the integer after {{ a }}\n\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseMalformedConstraints(a: MalformedConstraints2) -> int {\n client GPT35\n prompt #\"\n Return the integer after {{ a.foo }}\n\n {{ ctx.output_format }}\n \"#\n}\n", "test-files/descriptions/descriptions.baml": "\nclass Nested {\n prop3 string | null @description(#\"\n write \"three\"\n \"#)\n prop4 string | null @description(#\"\n write \"four\"\n \"#) @alias(\"blah\")\n prop20 Nested2\n}\n\nclass Nested2 {\n prop11 string | null @description(#\"\n write \"three\"\n \"#)\n prop12 string | null @description(#\"\n write \"four\"\n \"#) @alias(\"blah\")\n}\n\nclass Schema {\n prop1 string | null @description(#\"\n write \"one\"\n \"#)\n prop2 Nested | string @description(#\"\n write \"two\"\n \"#)\n prop5 (string | null)[] @description(#\"\n write \"hi\"\n \"#)\n prop6 string | Nested[] @alias(\"blah\") @description(#\"\n write the string \"blah\" regardless of the other types here\n \"#)\n nested_attrs (string | null | Nested)[] @description(#\"\n write the string \"nested\" regardless of other types\n \"#)\n parens (string | null) @description(#\"\n write \"parens1\"\n \"#)\n other_group (string | (int | string)) @description(#\"\n write \"other\"\n \"#) @alias(other)\n}\n\n\nfunction SchemaDescriptions(input: string) -> Schema {\n client GPT4o\n prompt #\"\n Return a schema with this format:\n\n {{ctx.output_format}}\n \"#\n}", @@ -68,7 +68,7 @@ "test-files/functions/output/class-with-enum.baml": "enum EnumInClass {\n ONE\n TWO\n}\n\nclass TestClassWithEnum {\n prop1 string\n prop2 EnumInClass\n}\n\nfunction FnOutputClassWithEnum(input: string) -> TestClassWithEnum {\n client GPT35\n prompt #\"\n Return a made up json blob that matches this schema:\n {{ctx.output_format}}\n ---\n\n JSON:\n \"#\n}\n\ntest FnOutputClassWithEnum {\n functions [FnOutputClassWithEnum]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/class.baml": "class TestOutputClass {\n prop1 string\n prop2 int\n}\n\nfunction FnOutputClass(input: string) -> TestOutputClass {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n For the prop2, always return a 540\n\n JSON:\n \"#\n}\n\ntest TestClass {\n functions [FnOutputClass]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/enum-list.baml": "function FnEnumListOutput(input: string) -> EnumOutput[] {\n client GPT35\n prompt #\"\n Print out two of these values randomly selected from the list below in a json array.\n\n {{ctx.output_format}}\n\n Answer:\n \"#\n} \n\ntest FnEnumListOutput {\n functions [FnEnumListOutput]\n args {\n input \"example input\"\n }\n}\n", - "test-files/functions/output/enum.baml": "enum EnumOutput {\n ONE\n TWO\n THREE\n\n @@alias(\"VALUE_ENUM\")\n}\n\nfunction FnEnumOutput(input: string) -> EnumOutput {\n client GPT35\n prompt #\"\n Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.\n\n {{ctx.output_format(prefix=null)}}\n \"#\n}\n\ntest FnEnumOutput {\n functions [FnEnumOutput]\n args {\n input \"example input\"\n }\n}\n", + "test-files/functions/output/enum.baml": "/// An enum with three values,\n/// ONE, TWO and THREE.\nenum EnumOutput {\n\n /// The first enum.\n ONE\n\n /// The second enum.\n TWO\n THREE\n\n @@alias(\"VALUE_ENUM\")\n}\n\nfunction FnEnumOutput(input: string) -> EnumOutput {\n client GPT35\n prompt #\"\n Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.\n\n {{ctx.output_format(prefix=null)}}\n \"#\n}\n\ntest FnEnumOutput {\n functions [FnEnumOutput]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/int.baml": "function FnOutputInt(input: string) -> int {\n client GPT35\n prompt #\"\n Return the integer 5 with no additional context.\n \"#\n}\n\ntest FnOutputInt {\n functions [FnOutputInt]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/literal-boolean.baml": "function FnOutputLiteralBool(input: string) -> false {\n client GPT35\n prompt #\"\n Return a false: {{ ctx.output_format}}\n \"#\n}\n\ntest FnOutputLiteralBool {\n functions [FnOutputLiteralBool]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/literal-int.baml": "function FnOutputLiteralInt(input: string) -> 5 {\n client GPT35\n prompt #\"\n Return an integer: {{ ctx.output_format}}\n \"#\n}\n\ntest FnOutputLiteralInt {\n functions [FnOutputLiteralInt]\n args {\n input \"example input\"\n }\n}\n", diff --git a/integ-tests/python/baml_client/partial_types.py b/integ-tests/python/baml_client/partial_types.py index a3432f387..d7c66c8f3 100644 --- a/integ-tests/python/baml_client/partial_types.py +++ b/integ-tests/python/baml_client/partial_types.py @@ -30,122 +30,84 @@ class BigNumbers(BaseModel): - - a: Optional[int] = None b: Optional[float] = None class BinaryNode(BaseModel): - - data: Optional[int] = None left: Optional["BinaryNode"] = None right: Optional["BinaryNode"] = None class Blah(BaseModel): - - prop4: Optional[str] = None class BlockConstraint(BaseModel): - - foo: Optional[int] = None bar: Optional[str] = None class BlockConstraintForParam(BaseModel): - - bcfp: Optional[int] = None bcfp2: Optional[str] = None class BookOrder(BaseModel): - - orderId: Optional[str] = None title: Optional[str] = None quantity: Optional[int] = None price: Optional[float] = None class ClassOptionalOutput(BaseModel): - - prop1: Optional[str] = None prop2: Optional[str] = None class ClassOptionalOutput2(BaseModel): - - prop1: Optional[str] = None prop2: Optional[str] = None prop3: Optional["Blah"] = None class ClassWithImage(BaseModel): - - myImage: Optional[baml_py.Image] = None param2: Optional[str] = None fake_image: Optional["FakeImage"] = None class CompoundBigNumbers(BaseModel): - - big: Optional["BigNumbers"] = None big_nums: List["BigNumbers"] another: Optional["BigNumbers"] = None class ContactInfo(BaseModel): - - primary: Optional[Union["PhoneNumber", "EmailAddress"]] = None secondary: Optional[Union["PhoneNumber", "EmailAddress", Optional[None]]] = None class CustomTaskResult(BaseModel): - - bookOrder: Optional[Union["BookOrder", Optional[None]]] = None flightConfirmation: Optional[Union["FlightConfirmation", Optional[None]]] = None groceryReceipt: Optional[Union["GroceryReceipt", Optional[None]]] = None class DummyOutput(BaseModel): - model_config = ConfigDict(extra='allow') - nonce: Optional[str] = None nonce2: Optional[str] = None class DynInputOutput(BaseModel): - model_config = ConfigDict(extra='allow') - testKey: Optional[str] = None class DynamicClassOne(BaseModel): - model_config = ConfigDict(extra='allow') - class DynamicClassTwo(BaseModel): - model_config = ConfigDict(extra='allow') - hi: Optional[str] = None some_class: Optional["SomeClassNestedDynamic"] = None status: Optional[Union[types.DynEnumOne, str]] = None class DynamicOutput(BaseModel): - model_config = ConfigDict(extra='allow') - class Earthling(BaseModel): - - age: Checked[Optional[int],Literal["earth_aged", "no_infants"]] class Education(BaseModel): - - institution: Optional[str] = None location: Optional[str] = None degree: Optional[str] = None @@ -153,33 +115,23 @@ class Education(BaseModel): graduation_date: Optional[str] = None class Email(BaseModel): - - subject: Optional[str] = None body: Optional[str] = None from_address: Optional[str] = None class EmailAddress(BaseModel): - - value: Optional[str] = None class Event(BaseModel): - - title: Optional[str] = None date: Optional[str] = None location: Optional[str] = None description: Optional[str] = None class FakeImage(BaseModel): - - url: Optional[str] = None class FlightConfirmation(BaseModel): - - confirmationNumber: Optional[str] = None flightNumber: Optional[str] = None departureTime: Optional[str] = None @@ -187,201 +139,139 @@ class FlightConfirmation(BaseModel): seatNumber: Optional[str] = None class FooAny(BaseModel): - - planetary_age: Optional[Union["Martian", "Earthling"]] = None certainty: Checked[Optional[int],Literal["unreasonably_certain"]] species: Checked[Optional[str],Literal["regex_bad", "regex_good", "trivial"]] class Forest(BaseModel): - - trees: List["Tree"] class GroceryReceipt(BaseModel): - - receiptId: Optional[str] = None storeName: Optional[str] = None items: List[Optional[Union[Optional[str], Optional[int], Optional[float]]]] totalAmount: Optional[float] = None class InnerClass(BaseModel): - - prop1: Optional[str] = None prop2: Optional[str] = None inner: Optional["InnerClass2"] = None class InnerClass2(BaseModel): - - prop2: Optional[int] = None prop3: Optional[float] = None class InputClass(BaseModel): - - key: Optional[str] = None key2: Optional[str] = None class InputClassNested(BaseModel): - - key: Optional[str] = None nested: Optional["InputClass"] = None class LinkedList(BaseModel): - - head: Optional["Node"] = None len: Optional[int] = None class LiteralClassHello(BaseModel): - - prop: Literal["hello"] class LiteralClassOne(BaseModel): - - prop: Literal["one"] class LiteralClassTwo(BaseModel): - - prop: Literal["two"] class MalformedConstraints(BaseModel): - - foo: Checked[Optional[int],Literal["foo_check"]] class MalformedConstraints2(BaseModel): - - foo: Optional[int] = None class Martian(BaseModel): - - + """A Martian organism with an age. + Such a nice type.""" age: Checked[Optional[int],Literal["young_enough"]] + """The age of the Martian in Mars years. + So many Mars years.""" class NamedArgsSingleClass(BaseModel): - - key: Optional[str] = None key_two: Optional[bool] = None key_three: Optional[int] = None class Nested(BaseModel): - - prop3: Optional[Union[Optional[str], Optional[None]]] = None prop4: Optional[Union[Optional[str], Optional[None]]] = None prop20: Optional["Nested2"] = None class Nested2(BaseModel): - - prop11: Optional[Union[Optional[str], Optional[None]]] = None prop12: Optional[Union[Optional[str], Optional[None]]] = None class NestedBlockConstraint(BaseModel): - - nbc: Checked[Optional["BlockConstraint"],Literal["cross_field"]] class NestedBlockConstraintForParam(BaseModel): - - nbcfp: Optional["BlockConstraintForParam"] = None class Node(BaseModel): - - data: Optional[int] = None next: Optional["Node"] = None class OptionalTest_Prop1(BaseModel): - - omega_a: Optional[str] = None omega_b: Optional[int] = None class OptionalTest_ReturnType(BaseModel): - - omega_1: Optional["OptionalTest_Prop1"] = None omega_2: Optional[str] = None omega_3: List[Optional[types.OptionalTest_CategoryType]] class OrderInfo(BaseModel): - - order_status: Optional[types.OrderStatus] = None tracking_number: Optional[str] = None estimated_arrival_date: Optional[str] = None class OriginalA(BaseModel): - - value: Optional[int] = None class OriginalB(BaseModel): - model_config = ConfigDict(extra='allow') - value: Optional[int] = None class Person(BaseModel): - model_config = ConfigDict(extra='allow') - name: Optional[str] = None hair_color: Optional[Union[types.Color, str]] = None class PhoneNumber(BaseModel): - - value: Optional[str] = None class Quantity(BaseModel): - - amount: Optional[Union[Optional[int], Optional[float]]] = None unit: Optional[str] = None class RaysData(BaseModel): - - dataType: Optional[types.DataType] = None value: Optional[Union["Resume", "Event"]] = None class ReceiptInfo(BaseModel): - - items: List["ReceiptItem"] total_cost: Optional[float] = None venue: Optional[Union[Literal["barisa"], Literal["ox_burger"]]] = None class ReceiptItem(BaseModel): - - name: Optional[str] = None description: Optional[str] = None quantity: Optional[int] = None price: Optional[float] = None class Recipe(BaseModel): - - ingredients: Dict[str, Optional["Quantity"]] recipe_type: Optional[Union[Literal["breakfast"], Literal["dinner"]]] = None class Resume(BaseModel): - - name: Optional[str] = None email: Optional[str] = None phone: Optional[str] = None @@ -390,8 +280,6 @@ class Resume(BaseModel): skills: List[Optional[str]] class Schema(BaseModel): - - prop1: Optional[Union[Optional[str], Optional[None]]] = None prop2: Optional[Union["Nested", Optional[str]]] = None prop5: List[Optional[Union[Optional[str], Optional[None]]]] @@ -401,8 +289,6 @@ class Schema(BaseModel): other_group: Optional[Union[Optional[str], Optional[Union[Optional[int], Optional[str]]]]] = None class SearchParams(BaseModel): - - dateRange: Optional[int] = None location: List[Optional[str]] jobTitle: Optional["WithReasoning"] = None @@ -411,19 +297,13 @@ class SearchParams(BaseModel): tags: List[Optional[Union[Optional[types.Tag], Optional[str]]]] class SomeClassNestedDynamic(BaseModel): - model_config = ConfigDict(extra='allow') - hi: Optional[str] = None class StringToClassEntry(BaseModel): - - word: Optional[str] = None class TestClassAlias(BaseModel): - - key: Optional[str] = None key2: Optional[str] = None key3: Optional[str] = None @@ -431,45 +311,31 @@ class TestClassAlias(BaseModel): key5: Optional[str] = None class TestClassNested(BaseModel): - - prop1: Optional[str] = None prop2: Optional["InnerClass"] = None class TestClassWithEnum(BaseModel): - - prop1: Optional[str] = None prop2: Optional[types.EnumInClass] = None class TestOutputClass(BaseModel): - - prop1: Optional[str] = None prop2: Optional[int] = None class Tree(BaseModel): - - data: Optional[int] = None children: Optional["Forest"] = None class TwoStoriesOneTitle(BaseModel): - - title: Optional[str] = None story_a: Optional[str] = None story_b: Optional[str] = None class UnionTest_ReturnType(BaseModel): - - prop1: Optional[Union[Optional[str], Optional[bool]]] = None prop2: List[Optional[Union[Optional[float], Optional[bool]]]] prop3: Optional[Union[List[Optional[bool]], List[Optional[int]]]] = None class WithReasoning(BaseModel): - - value: Optional[str] = None reasoning: Optional[str] = None diff --git a/integ-tests/python/baml_client/types.py b/integ-tests/python/baml_client/types.py index d9b05889b..6ed466630 100644 --- a/integ-tests/python/baml_client/types.py +++ b/integ-tests/python/baml_client/types.py @@ -94,9 +94,13 @@ class EnumInClass(str, Enum): TWO = "TWO" class EnumOutput(str, Enum): + """An enum with three values, + ONE, TWO and THREE.""" ONE = "ONE" + """The first enum.""" TWO = "TWO" + """The second enum.""" THREE = "THREE" class Hobby(str, Enum): @@ -145,122 +149,84 @@ class TestEnum(str, Enum): G = "G" class BigNumbers(BaseModel): - - a: int b: float class BinaryNode(BaseModel): - - data: int left: Optional["BinaryNode"] = None right: Optional["BinaryNode"] = None class Blah(BaseModel): - - prop4: Optional[str] = None class BlockConstraint(BaseModel): - - foo: int bar: str class BlockConstraintForParam(BaseModel): - - bcfp: int bcfp2: str class BookOrder(BaseModel): - - orderId: str title: str quantity: int price: float class ClassOptionalOutput(BaseModel): - - prop1: str prop2: str class ClassOptionalOutput2(BaseModel): - - prop1: Optional[str] = None prop2: Optional[str] = None prop3: Optional["Blah"] = None class ClassWithImage(BaseModel): - - myImage: baml_py.Image param2: str fake_image: "FakeImage" class CompoundBigNumbers(BaseModel): - - big: "BigNumbers" big_nums: List["BigNumbers"] another: "BigNumbers" class ContactInfo(BaseModel): - - primary: Union["PhoneNumber", "EmailAddress"] secondary: Union["PhoneNumber", "EmailAddress", None] class CustomTaskResult(BaseModel): - - bookOrder: Union["BookOrder", Optional[None]] flightConfirmation: Union["FlightConfirmation", Optional[None]] groceryReceipt: Union["GroceryReceipt", Optional[None]] class DummyOutput(BaseModel): - model_config = ConfigDict(extra='allow') - nonce: str nonce2: str class DynInputOutput(BaseModel): - model_config = ConfigDict(extra='allow') - testKey: str class DynamicClassOne(BaseModel): - model_config = ConfigDict(extra='allow') - class DynamicClassTwo(BaseModel): - model_config = ConfigDict(extra='allow') - hi: str some_class: "SomeClassNestedDynamic" status: Union["DynEnumOne", str] class DynamicOutput(BaseModel): - model_config = ConfigDict(extra='allow') - class Earthling(BaseModel): - - age: Checked[int,Literal["earth_aged", "no_infants"]] class Education(BaseModel): - - institution: str location: str degree: str @@ -268,33 +234,23 @@ class Education(BaseModel): graduation_date: Optional[str] = None class Email(BaseModel): - - subject: str body: str from_address: str class EmailAddress(BaseModel): - - value: str class Event(BaseModel): - - title: str date: str location: str description: str class FakeImage(BaseModel): - - url: str class FlightConfirmation(BaseModel): - - confirmationNumber: str flightNumber: str departureTime: str @@ -302,201 +258,139 @@ class FlightConfirmation(BaseModel): seatNumber: str class FooAny(BaseModel): - - planetary_age: Union["Martian", "Earthling"] certainty: Checked[int,Literal["unreasonably_certain"]] species: Checked[str,Literal["regex_bad", "regex_good", "trivial"]] class Forest(BaseModel): - - trees: List["Tree"] class GroceryReceipt(BaseModel): - - receiptId: str storeName: str items: List[Union[str, int, float]] totalAmount: float class InnerClass(BaseModel): - - prop1: str prop2: str inner: "InnerClass2" class InnerClass2(BaseModel): - - prop2: int prop3: float class InputClass(BaseModel): - - key: str key2: str class InputClassNested(BaseModel): - - key: str nested: "InputClass" class LinkedList(BaseModel): - - head: Optional["Node"] = None len: int class LiteralClassHello(BaseModel): - - prop: Literal["hello"] class LiteralClassOne(BaseModel): - - prop: Literal["one"] class LiteralClassTwo(BaseModel): - - prop: Literal["two"] class MalformedConstraints(BaseModel): - - foo: Checked[int,Literal["foo_check"]] class MalformedConstraints2(BaseModel): - - foo: int class Martian(BaseModel): - - + """A Martian organism with an age. + Such a nice type.""" age: Checked[int,Literal["young_enough"]] + """The age of the Martian in Mars years. + So many Mars years.""" class NamedArgsSingleClass(BaseModel): - - key: str key_two: bool key_three: int class Nested(BaseModel): - - prop3: Union[str, Optional[None]] prop4: Union[str, Optional[None]] prop20: "Nested2" class Nested2(BaseModel): - - prop11: Union[str, Optional[None]] prop12: Union[str, Optional[None]] class NestedBlockConstraint(BaseModel): - - nbc: Checked["BlockConstraint",Literal["cross_field"]] class NestedBlockConstraintForParam(BaseModel): - - nbcfp: "BlockConstraintForParam" class Node(BaseModel): - - data: int next: Optional["Node"] = None class OptionalTest_Prop1(BaseModel): - - omega_a: str omega_b: int class OptionalTest_ReturnType(BaseModel): - - omega_1: Optional["OptionalTest_Prop1"] = None omega_2: Optional[str] = None omega_3: List[Optional["OptionalTest_CategoryType"]] class OrderInfo(BaseModel): - - order_status: "OrderStatus" tracking_number: Optional[str] = None estimated_arrival_date: Optional[str] = None class OriginalA(BaseModel): - - value: int class OriginalB(BaseModel): - model_config = ConfigDict(extra='allow') - value: int class Person(BaseModel): - model_config = ConfigDict(extra='allow') - name: Optional[str] = None hair_color: Optional[Union["Color", str]] = None class PhoneNumber(BaseModel): - - value: str class Quantity(BaseModel): - - amount: Union[int, float] unit: Optional[str] = None class RaysData(BaseModel): - - dataType: "DataType" value: Union["Resume", "Event"] class ReceiptInfo(BaseModel): - - items: List["ReceiptItem"] total_cost: Optional[float] = None venue: Union[Literal["barisa"], Literal["ox_burger"]] class ReceiptItem(BaseModel): - - name: str description: Optional[str] = None quantity: int price: float class Recipe(BaseModel): - - ingredients: Dict[str, "Quantity"] recipe_type: Union[Literal["breakfast"], Literal["dinner"]] class Resume(BaseModel): - - name: str email: str phone: str @@ -505,8 +399,6 @@ class Resume(BaseModel): skills: List[str] class Schema(BaseModel): - - prop1: Union[str, Optional[None]] prop2: Union["Nested", str] prop5: List[Union[str, Optional[None]]] @@ -516,8 +408,6 @@ class Schema(BaseModel): other_group: Union[str, Union[int, str]] class SearchParams(BaseModel): - - dateRange: Optional[int] = None location: List[str] jobTitle: Optional["WithReasoning"] = None @@ -526,19 +416,13 @@ class SearchParams(BaseModel): tags: List[Union["Tag", str]] class SomeClassNestedDynamic(BaseModel): - model_config = ConfigDict(extra='allow') - hi: str class StringToClassEntry(BaseModel): - - word: str class TestClassAlias(BaseModel): - - key: str key2: str key3: str @@ -546,45 +430,31 @@ class TestClassAlias(BaseModel): key5: str class TestClassNested(BaseModel): - - prop1: str prop2: "InnerClass" class TestClassWithEnum(BaseModel): - - prop1: str prop2: "EnumInClass" class TestOutputClass(BaseModel): - - prop1: str prop2: int class Tree(BaseModel): - - data: int children: "Forest" class TwoStoriesOneTitle(BaseModel): - - title: str story_a: str story_b: str class UnionTest_ReturnType(BaseModel): - - prop1: Union[str, bool] prop2: List[Union[float, bool]] prop3: Union[List[bool], List[int]] class WithReasoning(BaseModel): - - value: str reasoning: str diff --git a/integ-tests/ruby/baml_client/inlined.rb b/integ-tests/ruby/baml_client/inlined.rb index cdd8e6de1..539a9df4b 100644 --- a/integ-tests/ruby/baml_client/inlined.rb +++ b/integ-tests/ruby/baml_client/inlined.rb @@ -30,7 +30,7 @@ module Inlined "test-files/aliases/classes.baml" => "class TestClassAlias {\n key string @alias(\"key-dash\") @description(#\"\n This is a description for key\n af asdf\n \"#)\n key2 string @alias(\"key21\")\n key3 string @alias(\"key with space\")\n key4 string //unaliased\n key5 string @alias(\"key.with.punctuation/123\")\n}\n\nfunction FnTestClassAlias(input: string) -> TestClassAlias {\n client GPT35\n prompt #\"\n {{ctx.output_format}}\n \"#\n}\n\ntest FnTestClassAlias {\n functions [FnTestClassAlias]\n args {\n input \"example input\"\n }\n}\n", "test-files/aliases/enums.baml" => "enum TestEnum {\n A @alias(\"k1\") @description(#\"\n User is angry\n \"#)\n B @alias(\"k22\") @description(#\"\n User is happy\n \"#)\n // tests whether k1 doesnt incorrectly get matched with k11\n C @alias(\"k11\") @description(#\"\n User is sad\n \"#)\n D @alias(\"k44\") @description(\n User is confused\n )\n E @description(\n User is excited\n )\n F @alias(\"k5\") // only alias\n \n G @alias(\"k6\") @description(#\"\n User is bored\n With a long description\n \"#)\n \n @@alias(\"Category\")\n}\n\nfunction FnTestAliasedEnumOutput(input: string) -> TestEnum {\n client GPT35\n prompt #\"\n Classify the user input into the following category\n \n {{ ctx.output_format }}\n\n {{ _.role('user') }}\n {{input}}\n\n {{ _.role('assistant') }}\n Category ID:\n \"#\n}\n\ntest FnTestAliasedEnumOutput {\n functions [FnTestAliasedEnumOutput]\n args {\n input \"mehhhhh\"\n }\n}", "test-files/comments/comments.baml" => "// add some functions, classes, enums etc with comments all over.", - "test-files/constraints/constraints.baml" => "// These classes and functions test several properties of\n// constrains:\n//\n// - The ability for constrains on fields to pass or fail.\n// - The ability for constraints on bare args and return types to pass or fail.\n// - The ability of constraints to influence which variant of a union is chosen\n// by the parser, when the structure is not sufficient to decide.\n\n\nclass Martian {\n age int @check(young_enough, {{ this < 30 }})\n}\n\nclass Earthling {\n age int @check(earth_aged, {{this < 200 and this > 0}}) @check(no_infants, {{this >1}})\n}\n\n\nclass FooAny {\n planetary_age Martian | Earthling\n certainty int @check(unreasonably_certain, {{this == 102931}})\n species string @check(trivial, {{this == \"Homo sapiens\"}}) @check(regex_good, {{this|regex_match(\"Homo\")}}) @check(regex_bad, {{this|regex_match(\"neanderthalensis\")}})\n}\n\n\nfunction PredictAge(name: string) -> FooAny {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling\n and capitalization). I'll give you a hint: If the name\n is \"Greg\", his age is 41.\n\n {{ctx.output_format}}\n \"#\n}\n\n\nfunction PredictAgeBare(inp: string @assert(big_enough, {{this|length > 1}})) -> int @check(too_big, {{this == 10102}}) {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ inp.name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling).\n\n {{ctx.output_format}}\n \"#\n}\n\nfunction ReturnFailingAssert(inp: int @assert(small_int, {{this < 10}})) -> int @assert(big_int, {{this > 100}}) {\n client GPT35\n prompt #\"\n Return the next integer after {{ inp }}.\n\n {{ctx.output_format}}\n \"#\n}\n\nclass TwoStoriesOneTitle {\n title string\n story_a string @assert(too_long_story, {{this|length > 1000000}} )\n story_b string @assert(too_long_story, {{this|length > 1000000}} )\n}\n\nfunction StreamFailingAssertion(theme: string, length: int) -> TwoStoriesOneTitle {\n client GPT35\n prompt #\"\n Tell me two different stories along the theme of {{ theme }} with the same title.\n Please make each about {{ length }} words long.\n {{ctx.output_format}}\n \"#\n}\n\nclass BlockConstraint {\n foo int\n bar string\n @@check(cross_field, {{ this.bar|length > this.foo }})\n}\n\nfunction MakeBlockConstraint() -> BlockConstraint {\n client GPT35\n prompt #\"\n Generate an output in the following schema with a short string and a large int.\n\n {{ ctx.output_format }}\n \"#\n}\n\nclass NestedBlockConstraint {\n nbc BlockConstraint\n}\n\nclass BlockConstraintForParam {\n bcfp int\n bcfp2 string\n @@assert(hi, {{ this.bcfp2|length < this.bcfp }})\n}\n\nclass NestedBlockConstraintForParam {\n nbcfp BlockConstraintForParam\n}\n\nfunction MakeNestedBlockConstraint() -> NestedBlockConstraint {\n client GPT35\n prompt #\"Generate an output where the inner foo is 1 and the inner bar is \"hello\".\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseBlockConstraint(inp: BlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseNestedBlockConstraint(inp: NestedBlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n", + "test-files/constraints/constraints.baml" => "// These classes and functions test several properties of\n// constrains:\n//\n// - The ability for constrains on fields to pass or fail.\n// - The ability for constraints on bare args and return types to pass or fail.\n// - The ability of constraints to influence which variant of a union is chosen\n// by the parser, when the structure is not sufficient to decide.\n\n/// A Martian organism with an age.\n/// Such a nice type.\nclass Martian {\n /// The age of the Martian in Mars years.\n /// So many Mars years.\n age int @check(young_enough, {{ this < 30 }})\n}\n\nclass Earthling {\n age int @check(earth_aged, {{this < 200 and this > 0}}) @check(no_infants, {{this >1}})\n}\n\n\nclass FooAny {\n planetary_age Martian | Earthling\n certainty int @check(unreasonably_certain, {{this == 102931}})\n species string @check(trivial, {{this == \"Homo sapiens\"}}) @check(regex_good, {{this|regex_match(\"Homo\")}}) @check(regex_bad, {{this|regex_match(\"neanderthalensis\")}})\n}\n\n\nfunction PredictAge(name: string) -> FooAny {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling\n and capitalization). I'll give you a hint: If the name\n is \"Greg\", his age is 41.\n\n {{ctx.output_format}}\n \"#\n}\n\n\nfunction PredictAgeBare(inp: string @assert(big_enough, {{this|length > 1}})) -> int @check(too_big, {{this == 10102}}) {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ inp.name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling).\n\n {{ctx.output_format}}\n \"#\n}\n\nfunction ReturnFailingAssert(inp: int @assert(small_int, {{this < 10}})) -> int @assert(big_int, {{this > 100}}) {\n client GPT35\n prompt #\"\n Return the next integer after {{ inp }}.\n\n {{ctx.output_format}}\n \"#\n}\n\nclass TwoStoriesOneTitle {\n title string\n story_a string @assert(too_long_story, {{this|length > 1000000}} )\n story_b string @assert(too_long_story, {{this|length > 1000000}} )\n}\n\nfunction StreamFailingAssertion(theme: string, length: int) -> TwoStoriesOneTitle {\n client GPT35\n prompt #\"\n Tell me two different stories along the theme of {{ theme }} with the same title.\n Please make each about {{ length }} words long.\n {{ctx.output_format}}\n \"#\n}\n\nclass BlockConstraint {\n foo int\n bar string\n @@check(cross_field, {{ this.bar|length > this.foo }})\n}\n\nfunction MakeBlockConstraint() -> BlockConstraint {\n client GPT35\n prompt #\"\n Generate an output in the following schema with a short string and a large int.\n\n {{ ctx.output_format }}\n \"#\n}\n\nclass NestedBlockConstraint {\n nbc BlockConstraint\n}\n\nclass BlockConstraintForParam {\n bcfp int\n bcfp2 string\n @@assert(hi, {{ this.bcfp2|length < this.bcfp }})\n}\n\nclass NestedBlockConstraintForParam {\n nbcfp BlockConstraintForParam\n}\n\nfunction MakeNestedBlockConstraint() -> NestedBlockConstraint {\n client GPT35\n prompt #\"Generate an output where the inner foo is 1 and the inner bar is \"hello\".\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseBlockConstraint(inp: BlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseNestedBlockConstraint(inp: NestedBlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n", "test-files/constraints/contact-info.baml" => "class PhoneNumber {\n value string @assert(valid_phone_number, {{this|regex_match(\"\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}\")}})\n}\n\nclass EmailAddress {\n value string @assert(valid_email, {{this|regex_match(\"^[_]*([a-z0-9]+(\\.|_*)?)+@([a-z][a-z0-9-]+(\\.|-*\\.))+[a-z]{2,6}$\")}})\n}\n\nclass ContactInfo {\n primary PhoneNumber | EmailAddress\n secondary (PhoneNumber | EmailAddress)?\n}\n\nfunction ExtractContactInfo(document: string) -> ContactInfo {\n client GPT35\n prompt #\"\n Extract a primary contact info, and if possible a secondary contact\n info, from this document:\n\n {{ document }}\n\n {{ ctx.output_format }}\n \"#\n}\n", "test-files/constraints/malformed-constraints.baml" => "class MalformedConstraints {\n foo int @check(foo_check, {{ this.length() > 0 }})\n}\n\nclass MalformedConstraints2 {\n foo int @assert(foo_check, {{ this.length() > 0 }})\n}\n\nfunction ReturnMalformedConstraints(a: int) -> MalformedConstraints {\n client GPT35\n prompt #\"\n Return the integer after {{ a }}\n\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseMalformedConstraints(a: MalformedConstraints2) -> int {\n client GPT35\n prompt #\"\n Return the integer after {{ a.foo }}\n\n {{ ctx.output_format }}\n \"#\n}\n", "test-files/descriptions/descriptions.baml" => "\nclass Nested {\n prop3 string | null @description(#\"\n write \"three\"\n \"#)\n prop4 string | null @description(#\"\n write \"four\"\n \"#) @alias(\"blah\")\n prop20 Nested2\n}\n\nclass Nested2 {\n prop11 string | null @description(#\"\n write \"three\"\n \"#)\n prop12 string | null @description(#\"\n write \"four\"\n \"#) @alias(\"blah\")\n}\n\nclass Schema {\n prop1 string | null @description(#\"\n write \"one\"\n \"#)\n prop2 Nested | string @description(#\"\n write \"two\"\n \"#)\n prop5 (string | null)[] @description(#\"\n write \"hi\"\n \"#)\n prop6 string | Nested[] @alias(\"blah\") @description(#\"\n write the string \"blah\" regardless of the other types here\n \"#)\n nested_attrs (string | null | Nested)[] @description(#\"\n write the string \"nested\" regardless of other types\n \"#)\n parens (string | null) @description(#\"\n write \"parens1\"\n \"#)\n other_group (string | (int | string)) @description(#\"\n write \"other\"\n \"#) @alias(other)\n}\n\n\nfunction SchemaDescriptions(input: string) -> Schema {\n client GPT4o\n prompt #\"\n Return a schema with this format:\n\n {{ctx.output_format}}\n \"#\n}", @@ -68,7 +68,7 @@ module Inlined "test-files/functions/output/class-with-enum.baml" => "enum EnumInClass {\n ONE\n TWO\n}\n\nclass TestClassWithEnum {\n prop1 string\n prop2 EnumInClass\n}\n\nfunction FnOutputClassWithEnum(input: string) -> TestClassWithEnum {\n client GPT35\n prompt #\"\n Return a made up json blob that matches this schema:\n {{ctx.output_format}}\n ---\n\n JSON:\n \"#\n}\n\ntest FnOutputClassWithEnum {\n functions [FnOutputClassWithEnum]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/class.baml" => "class TestOutputClass {\n prop1 string\n prop2 int\n}\n\nfunction FnOutputClass(input: string) -> TestOutputClass {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n For the prop2, always return a 540\n\n JSON:\n \"#\n}\n\ntest TestClass {\n functions [FnOutputClass]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/enum-list.baml" => "function FnEnumListOutput(input: string) -> EnumOutput[] {\n client GPT35\n prompt #\"\n Print out two of these values randomly selected from the list below in a json array.\n\n {{ctx.output_format}}\n\n Answer:\n \"#\n} \n\ntest FnEnumListOutput {\n functions [FnEnumListOutput]\n args {\n input \"example input\"\n }\n}\n", - "test-files/functions/output/enum.baml" => "enum EnumOutput {\n ONE\n TWO\n THREE\n\n @@alias(\"VALUE_ENUM\")\n}\n\nfunction FnEnumOutput(input: string) -> EnumOutput {\n client GPT35\n prompt #\"\n Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.\n\n {{ctx.output_format(prefix=null)}}\n \"#\n}\n\ntest FnEnumOutput {\n functions [FnEnumOutput]\n args {\n input \"example input\"\n }\n}\n", + "test-files/functions/output/enum.baml" => "/// An enum with three values,\n/// ONE, TWO and THREE.\nenum EnumOutput {\n\n /// The first enum.\n ONE\n\n /// The second enum.\n TWO\n THREE\n\n @@alias(\"VALUE_ENUM\")\n}\n\nfunction FnEnumOutput(input: string) -> EnumOutput {\n client GPT35\n prompt #\"\n Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.\n\n {{ctx.output_format(prefix=null)}}\n \"#\n}\n\ntest FnEnumOutput {\n functions [FnEnumOutput]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/int.baml" => "function FnOutputInt(input: string) -> int {\n client GPT35\n prompt #\"\n Return the integer 5 with no additional context.\n \"#\n}\n\ntest FnOutputInt {\n functions [FnOutputInt]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/literal-boolean.baml" => "function FnOutputLiteralBool(input: string) -> false {\n client GPT35\n prompt #\"\n Return a false: {{ ctx.output_format}}\n \"#\n}\n\ntest FnOutputLiteralBool {\n functions [FnOutputLiteralBool]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/literal-int.baml" => "function FnOutputLiteralInt(input: string) -> 5 {\n client GPT35\n prompt #\"\n Return an integer: {{ ctx.output_format}}\n \"#\n}\n\ntest FnOutputLiteralInt {\n functions [FnOutputLiteralInt]\n args {\n input \"example input\"\n }\n}\n", diff --git a/integ-tests/ruby/baml_client/partial-types.rb b/integ-tests/ruby/baml_client/partial-types.rb index f9d433cd6..888e97382 100644 --- a/integ-tests/ruby/baml_client/partial-types.rb +++ b/integ-tests/ruby/baml_client/partial-types.rb @@ -619,8 +619,12 @@ def initialize(props) @props = props end end + # A Martian organism with an age. + # Such a nice type. class Martian < T::Struct include Baml::Sorbet::Struct + # The age of the Martian in Mars years. + # So many Mars years. const :age, Baml::Checked[T.nilable(Integer)] def initialize(props) diff --git a/integ-tests/ruby/baml_client/types.rb b/integ-tests/ruby/baml_client/types.rb index f57583469..0a7095dfb 100644 --- a/integ-tests/ruby/baml_client/types.rb +++ b/integ-tests/ruby/baml_client/types.rb @@ -78,6 +78,8 @@ class EnumInClass < T::Enum end end class EnumOutput < T::Enum + # An enum with three values, + # ONE, TWO and THREE. enums do ONE = new("ONE") TWO = new("TWO") @@ -735,8 +737,12 @@ def initialize(props) @props = props end end + # A Martian organism with an age. + # Such a nice type. class Martian < T::Struct include Baml::Sorbet::Struct + # The age of the Martian in Mars years. + # So many Mars years. const :age, Baml::Checked[Integer] def initialize(props) diff --git a/integ-tests/typescript/baml_client/inlinedbaml.ts b/integ-tests/typescript/baml_client/inlinedbaml.ts index 40e86d3b4..2e6da1391 100644 --- a/integ-tests/typescript/baml_client/inlinedbaml.ts +++ b/integ-tests/typescript/baml_client/inlinedbaml.ts @@ -31,7 +31,7 @@ const fileMap = { "test-files/aliases/classes.baml": "class TestClassAlias {\n key string @alias(\"key-dash\") @description(#\"\n This is a description for key\n af asdf\n \"#)\n key2 string @alias(\"key21\")\n key3 string @alias(\"key with space\")\n key4 string //unaliased\n key5 string @alias(\"key.with.punctuation/123\")\n}\n\nfunction FnTestClassAlias(input: string) -> TestClassAlias {\n client GPT35\n prompt #\"\n {{ctx.output_format}}\n \"#\n}\n\ntest FnTestClassAlias {\n functions [FnTestClassAlias]\n args {\n input \"example input\"\n }\n}\n", "test-files/aliases/enums.baml": "enum TestEnum {\n A @alias(\"k1\") @description(#\"\n User is angry\n \"#)\n B @alias(\"k22\") @description(#\"\n User is happy\n \"#)\n // tests whether k1 doesnt incorrectly get matched with k11\n C @alias(\"k11\") @description(#\"\n User is sad\n \"#)\n D @alias(\"k44\") @description(\n User is confused\n )\n E @description(\n User is excited\n )\n F @alias(\"k5\") // only alias\n \n G @alias(\"k6\") @description(#\"\n User is bored\n With a long description\n \"#)\n \n @@alias(\"Category\")\n}\n\nfunction FnTestAliasedEnumOutput(input: string) -> TestEnum {\n client GPT35\n prompt #\"\n Classify the user input into the following category\n \n {{ ctx.output_format }}\n\n {{ _.role('user') }}\n {{input}}\n\n {{ _.role('assistant') }}\n Category ID:\n \"#\n}\n\ntest FnTestAliasedEnumOutput {\n functions [FnTestAliasedEnumOutput]\n args {\n input \"mehhhhh\"\n }\n}", "test-files/comments/comments.baml": "// add some functions, classes, enums etc with comments all over.", - "test-files/constraints/constraints.baml": "// These classes and functions test several properties of\n// constrains:\n//\n// - The ability for constrains on fields to pass or fail.\n// - The ability for constraints on bare args and return types to pass or fail.\n// - The ability of constraints to influence which variant of a union is chosen\n// by the parser, when the structure is not sufficient to decide.\n\n\nclass Martian {\n age int @check(young_enough, {{ this < 30 }})\n}\n\nclass Earthling {\n age int @check(earth_aged, {{this < 200 and this > 0}}) @check(no_infants, {{this >1}})\n}\n\n\nclass FooAny {\n planetary_age Martian | Earthling\n certainty int @check(unreasonably_certain, {{this == 102931}})\n species string @check(trivial, {{this == \"Homo sapiens\"}}) @check(regex_good, {{this|regex_match(\"Homo\")}}) @check(regex_bad, {{this|regex_match(\"neanderthalensis\")}})\n}\n\n\nfunction PredictAge(name: string) -> FooAny {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling\n and capitalization). I'll give you a hint: If the name\n is \"Greg\", his age is 41.\n\n {{ctx.output_format}}\n \"#\n}\n\n\nfunction PredictAgeBare(inp: string @assert(big_enough, {{this|length > 1}})) -> int @check(too_big, {{this == 10102}}) {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ inp.name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling).\n\n {{ctx.output_format}}\n \"#\n}\n\nfunction ReturnFailingAssert(inp: int @assert(small_int, {{this < 10}})) -> int @assert(big_int, {{this > 100}}) {\n client GPT35\n prompt #\"\n Return the next integer after {{ inp }}.\n\n {{ctx.output_format}}\n \"#\n}\n\nclass TwoStoriesOneTitle {\n title string\n story_a string @assert(too_long_story, {{this|length > 1000000}} )\n story_b string @assert(too_long_story, {{this|length > 1000000}} )\n}\n\nfunction StreamFailingAssertion(theme: string, length: int) -> TwoStoriesOneTitle {\n client GPT35\n prompt #\"\n Tell me two different stories along the theme of {{ theme }} with the same title.\n Please make each about {{ length }} words long.\n {{ctx.output_format}}\n \"#\n}\n\nclass BlockConstraint {\n foo int\n bar string\n @@check(cross_field, {{ this.bar|length > this.foo }})\n}\n\nfunction MakeBlockConstraint() -> BlockConstraint {\n client GPT35\n prompt #\"\n Generate an output in the following schema with a short string and a large int.\n\n {{ ctx.output_format }}\n \"#\n}\n\nclass NestedBlockConstraint {\n nbc BlockConstraint\n}\n\nclass BlockConstraintForParam {\n bcfp int\n bcfp2 string\n @@assert(hi, {{ this.bcfp2|length < this.bcfp }})\n}\n\nclass NestedBlockConstraintForParam {\n nbcfp BlockConstraintForParam\n}\n\nfunction MakeNestedBlockConstraint() -> NestedBlockConstraint {\n client GPT35\n prompt #\"Generate an output where the inner foo is 1 and the inner bar is \"hello\".\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseBlockConstraint(inp: BlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseNestedBlockConstraint(inp: NestedBlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n", + "test-files/constraints/constraints.baml": "// These classes and functions test several properties of\n// constrains:\n//\n// - The ability for constrains on fields to pass or fail.\n// - The ability for constraints on bare args and return types to pass or fail.\n// - The ability of constraints to influence which variant of a union is chosen\n// by the parser, when the structure is not sufficient to decide.\n\n/// A Martian organism with an age.\n/// Such a nice type.\nclass Martian {\n /// The age of the Martian in Mars years.\n /// So many Mars years.\n age int @check(young_enough, {{ this < 30 }})\n}\n\nclass Earthling {\n age int @check(earth_aged, {{this < 200 and this > 0}}) @check(no_infants, {{this >1}})\n}\n\n\nclass FooAny {\n planetary_age Martian | Earthling\n certainty int @check(unreasonably_certain, {{this == 102931}})\n species string @check(trivial, {{this == \"Homo sapiens\"}}) @check(regex_good, {{this|regex_match(\"Homo\")}}) @check(regex_bad, {{this|regex_match(\"neanderthalensis\")}})\n}\n\n\nfunction PredictAge(name: string) -> FooAny {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling\n and capitalization). I'll give you a hint: If the name\n is \"Greg\", his age is 41.\n\n {{ctx.output_format}}\n \"#\n}\n\n\nfunction PredictAgeBare(inp: string @assert(big_enough, {{this|length > 1}})) -> int @check(too_big, {{this == 10102}}) {\n client GPT35\n prompt #\"\n Using your understanding of the historical popularity\n of names, predict the age of a person with the name\n {{ inp.name }} in years. Also predict their genus and\n species. It's Homo sapiens (with exactly that spelling).\n\n {{ctx.output_format}}\n \"#\n}\n\nfunction ReturnFailingAssert(inp: int @assert(small_int, {{this < 10}})) -> int @assert(big_int, {{this > 100}}) {\n client GPT35\n prompt #\"\n Return the next integer after {{ inp }}.\n\n {{ctx.output_format}}\n \"#\n}\n\nclass TwoStoriesOneTitle {\n title string\n story_a string @assert(too_long_story, {{this|length > 1000000}} )\n story_b string @assert(too_long_story, {{this|length > 1000000}} )\n}\n\nfunction StreamFailingAssertion(theme: string, length: int) -> TwoStoriesOneTitle {\n client GPT35\n prompt #\"\n Tell me two different stories along the theme of {{ theme }} with the same title.\n Please make each about {{ length }} words long.\n {{ctx.output_format}}\n \"#\n}\n\nclass BlockConstraint {\n foo int\n bar string\n @@check(cross_field, {{ this.bar|length > this.foo }})\n}\n\nfunction MakeBlockConstraint() -> BlockConstraint {\n client GPT35\n prompt #\"\n Generate an output in the following schema with a short string and a large int.\n\n {{ ctx.output_format }}\n \"#\n}\n\nclass NestedBlockConstraint {\n nbc BlockConstraint\n}\n\nclass BlockConstraintForParam {\n bcfp int\n bcfp2 string\n @@assert(hi, {{ this.bcfp2|length < this.bcfp }})\n}\n\nclass NestedBlockConstraintForParam {\n nbcfp BlockConstraintForParam\n}\n\nfunction MakeNestedBlockConstraint() -> NestedBlockConstraint {\n client GPT35\n prompt #\"Generate an output where the inner foo is 1 and the inner bar is \"hello\".\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseBlockConstraint(inp: BlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseNestedBlockConstraint(inp: NestedBlockConstraintForParam) -> int {\n client GPT35\n prompt #\"\n Generate 3\n {{ ctx.output_format }}\n \"#\n}\n", "test-files/constraints/contact-info.baml": "class PhoneNumber {\n value string @assert(valid_phone_number, {{this|regex_match(\"\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}\")}})\n}\n\nclass EmailAddress {\n value string @assert(valid_email, {{this|regex_match(\"^[_]*([a-z0-9]+(\\.|_*)?)+@([a-z][a-z0-9-]+(\\.|-*\\.))+[a-z]{2,6}$\")}})\n}\n\nclass ContactInfo {\n primary PhoneNumber | EmailAddress\n secondary (PhoneNumber | EmailAddress)?\n}\n\nfunction ExtractContactInfo(document: string) -> ContactInfo {\n client GPT35\n prompt #\"\n Extract a primary contact info, and if possible a secondary contact\n info, from this document:\n\n {{ document }}\n\n {{ ctx.output_format }}\n \"#\n}\n", "test-files/constraints/malformed-constraints.baml": "class MalformedConstraints {\n foo int @check(foo_check, {{ this.length() > 0 }})\n}\n\nclass MalformedConstraints2 {\n foo int @assert(foo_check, {{ this.length() > 0 }})\n}\n\nfunction ReturnMalformedConstraints(a: int) -> MalformedConstraints {\n client GPT35\n prompt #\"\n Return the integer after {{ a }}\n\n {{ ctx.output_format }}\n \"#\n}\n\nfunction UseMalformedConstraints(a: MalformedConstraints2) -> int {\n client GPT35\n prompt #\"\n Return the integer after {{ a.foo }}\n\n {{ ctx.output_format }}\n \"#\n}\n", "test-files/descriptions/descriptions.baml": "\nclass Nested {\n prop3 string | null @description(#\"\n write \"three\"\n \"#)\n prop4 string | null @description(#\"\n write \"four\"\n \"#) @alias(\"blah\")\n prop20 Nested2\n}\n\nclass Nested2 {\n prop11 string | null @description(#\"\n write \"three\"\n \"#)\n prop12 string | null @description(#\"\n write \"four\"\n \"#) @alias(\"blah\")\n}\n\nclass Schema {\n prop1 string | null @description(#\"\n write \"one\"\n \"#)\n prop2 Nested | string @description(#\"\n write \"two\"\n \"#)\n prop5 (string | null)[] @description(#\"\n write \"hi\"\n \"#)\n prop6 string | Nested[] @alias(\"blah\") @description(#\"\n write the string \"blah\" regardless of the other types here\n \"#)\n nested_attrs (string | null | Nested)[] @description(#\"\n write the string \"nested\" regardless of other types\n \"#)\n parens (string | null) @description(#\"\n write \"parens1\"\n \"#)\n other_group (string | (int | string)) @description(#\"\n write \"other\"\n \"#) @alias(other)\n}\n\n\nfunction SchemaDescriptions(input: string) -> Schema {\n client GPT4o\n prompt #\"\n Return a schema with this format:\n\n {{ctx.output_format}}\n \"#\n}", @@ -69,7 +69,7 @@ const fileMap = { "test-files/functions/output/class-with-enum.baml": "enum EnumInClass {\n ONE\n TWO\n}\n\nclass TestClassWithEnum {\n prop1 string\n prop2 EnumInClass\n}\n\nfunction FnOutputClassWithEnum(input: string) -> TestClassWithEnum {\n client GPT35\n prompt #\"\n Return a made up json blob that matches this schema:\n {{ctx.output_format}}\n ---\n\n JSON:\n \"#\n}\n\ntest FnOutputClassWithEnum {\n functions [FnOutputClassWithEnum]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/class.baml": "class TestOutputClass {\n prop1 string\n prop2 int\n}\n\nfunction FnOutputClass(input: string) -> TestOutputClass {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n For the prop2, always return a 540\n\n JSON:\n \"#\n}\n\ntest TestClass {\n functions [FnOutputClass]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/enum-list.baml": "function FnEnumListOutput(input: string) -> EnumOutput[] {\n client GPT35\n prompt #\"\n Print out two of these values randomly selected from the list below in a json array.\n\n {{ctx.output_format}}\n\n Answer:\n \"#\n} \n\ntest FnEnumListOutput {\n functions [FnEnumListOutput]\n args {\n input \"example input\"\n }\n}\n", - "test-files/functions/output/enum.baml": "enum EnumOutput {\n ONE\n TWO\n THREE\n\n @@alias(\"VALUE_ENUM\")\n}\n\nfunction FnEnumOutput(input: string) -> EnumOutput {\n client GPT35\n prompt #\"\n Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.\n\n {{ctx.output_format(prefix=null)}}\n \"#\n}\n\ntest FnEnumOutput {\n functions [FnEnumOutput]\n args {\n input \"example input\"\n }\n}\n", + "test-files/functions/output/enum.baml": "/// An enum with three values,\n/// ONE, TWO and THREE.\nenum EnumOutput {\n\n /// The first enum.\n ONE\n\n /// The second enum.\n TWO\n THREE\n\n @@alias(\"VALUE_ENUM\")\n}\n\nfunction FnEnumOutput(input: string) -> EnumOutput {\n client GPT35\n prompt #\"\n Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.\n\n {{ctx.output_format(prefix=null)}}\n \"#\n}\n\ntest FnEnumOutput {\n functions [FnEnumOutput]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/int.baml": "function FnOutputInt(input: string) -> int {\n client GPT35\n prompt #\"\n Return the integer 5 with no additional context.\n \"#\n}\n\ntest FnOutputInt {\n functions [FnOutputInt]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/literal-boolean.baml": "function FnOutputLiteralBool(input: string) -> false {\n client GPT35\n prompt #\"\n Return a false: {{ ctx.output_format}}\n \"#\n}\n\ntest FnOutputLiteralBool {\n functions [FnOutputLiteralBool]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/literal-int.baml": "function FnOutputLiteralInt(input: string) -> 5 {\n client GPT35\n prompt #\"\n Return an integer: {{ ctx.output_format}}\n \"#\n}\n\ntest FnOutputLiteralInt {\n functions [FnOutputLiteralInt]\n args {\n input \"example input\"\n }\n}\n", diff --git a/integ-tests/typescript/baml_client/types.ts b/integ-tests/typescript/baml_client/types.ts index 99eb57853..efe1447e9 100644 --- a/integ-tests/typescript/baml_client/types.ts +++ b/integ-tests/typescript/baml_client/types.ts @@ -89,8 +89,18 @@ export enum EnumInClass { TWO = "TWO", } +/** + * An enum with three values, + * ONE, TWO and THREE. + */ export enum EnumOutput { + /** + * The first enum. + */ ONE = "ONE", + /** + * The second enum. + */ TWO = "TWO", THREE = "THREE", } @@ -373,7 +383,15 @@ export interface MalformedConstraints2 { } +/** + * A Martian organism with an age. + * Such a nice type. + */ export interface Martian { + /** + * The age of the Martian in Mars years. + * So many Mars years. + */ age: Checked } diff --git a/integ-tests/typescript/test-report.html b/integ-tests/typescript/test-report.html index 83d516bc4..91771e435 100644 --- a/integ-tests/typescript/test-report.html +++ b/integ-tests/typescript/test-report.html @@ -257,780 +257,13 @@ font-size: 1rem; padding: 0 0.5rem; } -

Test Report

Started: 2024-11-11 15:23:46
Suites (1)
0 passed
1 failed
0 pending
Tests (64)
63 passed
1 failed
0 pending
Integ tests > should work for all inputs
single bool
passed
0.687s
Integ tests > should work for all inputs
single string list
passed
0.483s
Integ tests > should work for all inputs
return literal union
passed
0.416s
Integ tests > should work for all inputs
single class
passed
0.445s
Integ tests > should work for all inputs
multiple classes
passed
0.69s
Integ tests > should work for all inputs
single enum list
passed
0.389s
Integ tests > should work for all inputs
single float
passed
0.436s
Integ tests > should work for all inputs
single int
passed
0.612s
Integ tests > should work for all inputs
single literal int
passed
0.352s
Integ tests > should work for all inputs
single literal bool
passed
0.352s
Integ tests > should work for all inputs
single literal string
passed
0.43s
Integ tests > should work for all inputs
single class with literal prop
passed
0.81s
Integ tests > should work for all inputs
single class with literal union prop
passed
0.551s
Integ tests > should work for all inputs
single optional string
passed
0.38s
Integ tests > should work for all inputs
single map string to string
passed
0.774s
Integ tests > should work for all inputs
single map string to class
passed
0.948s
Integ tests > should work for all inputs
single map string to map
passed
0.656s
Integ tests
should work for all outputs
passed
4.797s
Integ tests
works with retries1
passed
1.059s
Integ tests
works with retries2
passed
2.064s
Integ tests
works with fallbacks
passed
1.607s
Integ tests
should work with image from url
passed
1.075s
Integ tests
should work with image from base 64
passed
1.103s
Integ tests
should work with audio base 64
passed
0.802s
Integ tests
should work with audio from url
passed
4.315s
Integ tests
should support streaming in OpenAI
passed
3.357s
Integ tests
should support streaming in Gemini
passed
10.198s
Integ tests
should support AWS
passed
4.281s
Integ tests
should support streaming in AWS
failed
1.621s
Error: BamlError: BamlClientError: BamlClientHttpError: LLM call failed: LLMErrorResponse { client: "AwsBedrock", model: Some("anthropic.claude-3-5-sonnet-20240620-v1:0"), prompt: Chat([RenderedChatMessage { role: "user", allow_duplicate_role: false, parts: [Text("Write a nice short story about Dr. Pepper")] }]), request_options: {"api_key": String("")}, start_time: SystemTime { tv_sec: 1731360271, tv_nsec: 598100000 }, latency: 1.61346525s, message: "ServiceError(\n    ServiceError {\n        source: ThrottlingException(\n            ThrottlingException {\n                message: Some(\n                    \"Too many requests, please wait before trying again.\",\n                ),\n                meta: ErrorMetadata {\n                    code: Some(\n                        \"ThrottlingException\",\n                    ),\n                    message: Some(\n                        \"Too many requests, please wait before trying again.\",\n                    ),\n                    extras: Some(\n                        {\n                            \"aws_request_id\": \"94e852da-1f5a-4dd2-80d1-a5603ddf6d75\",\n                        },\n                    ),\n                },\n            },\n        ),\n        raw: Response {\n            status: StatusCode(\n                429,\n            ),\n            headers: Headers {\n                headers: {\n                    \"date\": HeaderValue {\n                        _private: H0(\n                            \"Mon, 11 Nov 2024 21:24:33 GMT\",\n                        ),\n                    },\n                    \"content-type\": HeaderValue {\n                        _private: H0(\n                            \"application/json\",\n                        ),\n                    },\n                    \"content-length\": HeaderValue {\n                        _private: H0(\n                            \"65\",\n                        ),\n                    },\n                    \"x-amzn-requestid\": HeaderValue {\n                        _private: H0(\n                            \"94e852da-1f5a-4dd2-80d1-a5603ddf6d75\",\n                        ),\n                    },\n                    \"x-amzn-errortype\": HeaderValue {\n                        _private: H0(\n                            \"ThrottlingException:http://internal.amazon.com/coral/com.amazon.bedrock/\",\n                        ),\n                    },\n                },\n            },\n            body: SdkBody {\n                inner: Once(\n                    Some(\n                        b\"{\\\"message\\\":\\\"Too many requests, please wait before trying again.\\\"}\",\n                    ),\n                ),\n                retryable: true,\n            },\n            extensions: Extensions {\n                extensions_02x: Extensions,\n                extensions_1x: Extensions,\n            },\n        },\n    },\n)", code: RateLimited }
-    at BamlStream.parsed [as getFinalResponse] (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/stream.js:58:39)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:274:19)
Integ tests
should allow overriding the region
passed
0.005s
Integ tests
should support OpenAI shorthand
passed
10.32s
Integ tests
should support OpenAI shorthand streaming
passed
10.353s
Integ tests
should support anthropic shorthand
passed
2.65s
Integ tests
should support anthropic shorthand streaming
passed
2.642s
Integ tests
should support streaming without iterating
passed
2.552s
Integ tests
should support streaming in Claude
passed
1.014s
Integ tests
should support vertex
passed
10.081s
Integ tests
supports tracing sync
passed
0.009s
Integ tests
supports tracing async
passed
2.162s
Integ tests
should work with dynamic types single
passed
0.966s
Integ tests
should work with dynamic types enum
passed
0.759s
Integ tests
should work with dynamic literals
passed
0.896s
Integ tests
should work with dynamic types class
passed
0.858s
Integ tests
should work with dynamic inputs class
passed
0.528s
Integ tests
should work with dynamic inputs list
passed
0.768s
Integ tests
should work with dynamic output map
passed
1.016s
Integ tests
should work with dynamic output union
passed
2.143s
Integ tests
should work with nested classes
passed
1.952s
Integ tests
should work with dynamic client
passed
0.413s
Integ tests
should work with 'onLogEvent'
passed
1.881s
Integ tests
should work with a sync client
passed
0.673s
Integ tests
should raise an error when appropriate
passed
0.747s
Integ tests
should raise a BAMLValidationError
passed
0.573s
Integ tests
should reset environment variables correctly
passed
1.21s
Integ tests
should use aliases when serializing input objects - classes
passed
0.958s
Integ tests
should use aliases when serializing, but still have original keys in jinja
passed
0.794s
Integ tests
should use aliases when serializing input objects - enums
passed
0.337s
Integ tests
should use aliases when serializing input objects - lists
passed
0.45s
Integ tests
constraints: should handle checks in return types
passed
0.699s
Integ tests
constraints: should handle checks in returned unions
passed
0.879s
Integ tests
constraints: should handle block-level checks
passed
0.636s
Integ tests
constraints: should handle nested-block-level checks
passed
0.599s
Integ tests
simple recursive type
passed
2.395s
Integ tests
mutually recursive type
passed
2.263s
Console Log
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:47:15)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
calling with class
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:53:15)
got response key
-true
-52
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:176:15)
Expected error Error: BamlError: BamlClientError: BamlClientHttpError: LLM call failed: LLMErrorResponse { client: "RetryClientConstant", model: None, prompt: Chat([RenderedChatMessage { role: "system", allow_duplicate_role: false, parts: [Text("Say a haiku")] }]), request_options: {"model": String("gpt-3.5-turbo")}, start_time: SystemTime { tv_sec: 1731360242, tv_nsec: 596785000 }, latency: 165.278666ms, message: "Request failed: {\n    \"error\": {\n        \"message\": \"Incorrect API key provided: blah. You can find your API key at https://platform.openai.com/account/api-keys.\",\n        \"type\": \"invalid_request_error\",\n        \"param\": null,\n        \"code\": \"invalid_api_key\"\n    }\n}\n", code: InvalidAuthentication }
-    at BamlAsyncClient.parsed [as TestRetryConstant] (/Users/vbv/repos/gloo-lang/integ-tests/typescript/baml_client/async_client.ts:2710:18)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:173:7) {
-  code: 'GenericFailure'
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:185:15)
Expected error Error: BamlError: BamlClientError: BamlClientHttpError: LLM call failed: LLMErrorResponse { client: "RetryClientExponential", model: None, prompt: Chat([RenderedChatMessage { role: "system", allow_duplicate_role: false, parts: [Text("Say a haiku")] }]), request_options: {"model": String("gpt-3.5-turbo")}, start_time: SystemTime { tv_sec: 1731360244, tv_nsec: 672557000 }, latency: 178.301292ms, message: "Request failed: {\n    \"error\": {\n        \"message\": \"Incorrect API key provided: blahh. You can find your API key at https://platform.openai.com/account/api-keys.\",\n        \"type\": \"invalid_request_error\",\n        \"param\": null,\n        \"code\": \"invalid_api_key\"\n    }\n}\n", code: InvalidAuthentication }
-    at BamlAsyncClient.parsed [as TestRetryExponential] (/Users/vbv/repos/gloo-lang/integ-tests/typescript/baml_client/async_client.ts:2735:18)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:182:7) {
-  code: 'GenericFailure'
-}
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:344:15)
-    at func (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:83:38)
-    at AsyncLocalStorage.run (node:async_hooks:338:14)
-    at run (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:81:22)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:353:5)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
hello world
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:347:15)
-    at func (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:83:38)
-    at AsyncLocalStorage.run (node:async_hooks:338:14)
-    at run (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:81:22)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:353:5)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
dummyFunc returned
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:350:15)
-    at func (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:83:38)
-    at AsyncLocalStorage.run (node:async_hooks:338:14)
-    at run (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:81:22)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:353:5)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
dummyFunc2 returned
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
samDummyNested nested1
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
samDummyNested nested2
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
samDummyNested nested3
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:376:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
dummy hi1
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
samDummyNested nested1
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
samDummyNested nested2
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
samDummyNested nested3
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:376:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
dummy hi2
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
samDummyNested nested1
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
samDummyNested nested2
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
samDummyNested nested3
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:376:15)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:383:5)
dummy hi3
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:390:15)
-    at func (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:44)
-    at AsyncLocalStorage.run (node:async_hooks:338:14)
-    at run (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:28)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:406:5)
hello world
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
samDummyNested nested1
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
samDummyNested nested2
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
samDummyNested nested3
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:376:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
dummy firstDummyFuncArg
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at /Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:395:20
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:389:17)
samDummyNested nested1
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at /Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:395:20
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:389:17)
samDummyNested nested2
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at /Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:395:20
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:389:17)
samDummyNested nested3
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:376:15)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at /Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:395:20
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:389:17)
dummy secondDummyFuncArg
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 0)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at /Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:403:20
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:389:17)
samDummyNested nested1
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at runNextTicks (node:internal/process/task_queues:60:5)
-    at listOnTimeout (node:internal/timers:538:9)
-    at processTimers (node:internal/timers:512:7)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 1)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at /Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:403:20
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:389:17)
samDummyNested nested2
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:365:15)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at async Promise.all (index 2)
-    at dummyFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:371:22)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at /Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:403:20
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:389:17)
samDummyNested nested3
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:376:15)
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at /Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:403:20
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:38
-    at /Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:13
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:389:17)
dummy thirdDummyFuncArg
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:409:15)
-    at func (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:104:44)
-    at AsyncLocalStorage.run (node:async_hooks:338:14)
-    at run (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:102:28)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:415:5)
hello world
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:419:13)
stats {"failed":0,"started":30,"finalized":30,"submitted":30,"sent":30,"done":30}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:443:13)
[
-  {
-    name: 'Harrison',
-    hair_color: 'BLACK',
-    last_name: null,
-    height: 1.83,
-    hobbies: [ 'SPORTS' ]
-  }
-]
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:512:13)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
[
-  [
-    'hair_color',
-    ClassPropertyBuilder { bldr: ClassPropertyBuilder {} }
-  ],
-  [
-    'attributes',
-    ClassPropertyBuilder { bldr: ClassPropertyBuilder {} }
-  ]
-]
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:514:15)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
Property: hair_color
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:514:15)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
Property: attributes
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:522:13)
final  {
-  hair_color: 'black',
-  attributes: { height: '6 feet', eye_color: 'blue', facial_hair: 'beard' }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:546:13)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
[
-  [
-    'hair_color',
-    ClassPropertyBuilder { bldr: ClassPropertyBuilder {} }
-  ],
-  [
-    'attributes',
-    ClassPropertyBuilder { bldr: ClassPropertyBuilder {} }
-  ],
-  [ 'height', ClassPropertyBuilder { bldr: ClassPropertyBuilder {} } ]
-]
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:548:15)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
Property: hair_color
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:548:15)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
Property: attributes
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:548:15)
-    at Promise.then.completed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)
-    at new Promise (<anonymous>)
-    at callAsyncCircusFn (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)
-    at _callCircusTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)
-    at _runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)
-    at _runTestsForDescribeBlock (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)
-    at run (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)
-    at runAndTransformResultsToJestFormat (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)
-    at jestAdapter (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)
-    at runTestInternal (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
-    at runTest (/Users/vbv/repos/gloo-lang/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
Property: height
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:556:13)
final  {
-  hair_color: 'black',
-  attributes: { eye_color: 'blue', facial_hair: 'beard', age: '30' },
-  height: { feet: 6, inches: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:567:13)
final  {
-  hair_color: 'black',
-  attributes: { eye_color: 'blue', facial_hair: 'beard', age: '30' },
-  height: { meters: 1.8 }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: null, prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: '', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: null }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: { prop1: null, prop2: null, inner: null } }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: { prop1: null, prop2: null, inner: null } }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: { prop1: null, prop2: null, inner: null } }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: { prop1: null, prop2: null, inner: null } }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: { prop1: null, prop2: null, inner: null } }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: { prop1: null, prop2: null, inner: null } }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: { prop1: null, prop2: null, inner: null } }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: { prop1: '', prop2: null, inner: null } }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value', prop2: null, inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: null, inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: null, inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: null, inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: null, inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: null, inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: null, inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: null, inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: null, inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg { prop1: 'value1', prop2: { prop1: 'value2', prop2: '', inner: null } }
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: 'value', inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: 'value3', inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: 'value3', inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: 'value3', inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: 'value3', inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: 'value3', inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: 'value3', inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: { prop1: 'value2', prop2: 'value3', inner: null }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: null, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: null }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:580:15)
msg {
-  prop1: 'value1',
-  prop2: {
-    prop1: 'value2',
-    prop2: 'value3',
-    inner: { prop2: 42, prop3: 3.14 }
-  }
-}
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:605:15)
-    at callback (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:70:17)
onLogEvent {
-  metadata: {
-    eventId: 'fb9e29fa-78ec-42f1-9030-fa5b1008d31c',
-    rootEventId: 'fb9e29fa-78ec-42f1-9030-fa5b1008d31c'
-  },
-  prompt: '[\n' +
-    '  {\n' +
-    '    "role": "system",\n' +
-    '    "content": [\n' +
-    '      {\n' +
-    '        "text": "Return this value back to me: [\\"a\\", \\"b\\", \\"c\\"]"\n' +
-    '      }\n' +
-    '    ]\n' +
-    '  }\n' +
-    ']',
-  rawOutput: '["a", "b", "c"]',
-  parsedOutput: '["a", "b", "c"]',
-  startTime: '2024-11-11T21:25:25.641Z'
-}
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:605:15)
-    at callback (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/async_context_vars.js:70:17)
onLogEvent {
-  metadata: {
-    eventId: 'a00f3238-afe3-4707-b679-fb6d5fbec4ad',
-    rootEventId: 'a00f3238-afe3-4707-b679-fb6d5fbec4ad'
-  },
-  prompt: '[\n' +
-    '  {\n' +
-    '    "role": "system",\n' +
-    '    "content": [\n' +
-    '      {\n' +
-    '        "text": "Return this value back to me: [\\"d\\", \\"e\\", \\"f\\"]"\n' +
-    '      }\n' +
-    '    ]\n' +
-    '  }\n' +
-    ']',
-  rawOutput: '["d", "e", "f"]',
-  parsedOutput: '["d", "e", "f"]',
-  startTime: '2024-11-11T21:25:26.143Z'
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:639:15)
Error: Error: BamlError: BamlClientError: BamlClientHttpError: LLM call failed: LLMErrorResponse { client: "MyClient", model: None, prompt: Chat([RenderedChatMessage { role: "system", allow_duplicate_role: false, parts: [Text("Given a string, extract info using the schema:\n\nMy name is Harrison. My hair is black and I'm 6 feet tall.\n\nAnswer in JSON using this schema:\n{\n}")] }]), request_options: {"model": String("gpt-4o-mini")}, start_time: SystemTime { tv_sec: 1731360327, tv_nsec: 999678000 }, latency: 150.208542ms, message: "Request failed: {\n    \"error\": {\n        \"message\": \"Incorrect API key provided: INVALID_KEY. You can find your API key at https://platform.openai.com/account/api-keys.\",\n        \"type\": \"invalid_request_error\",\n        \"param\": null,\n        \"code\": \"invalid_api_key\"\n    }\n}\n", code: InvalidAuthentication }
-    at BamlAsyncClient.parsed (/Users/vbv/repos/gloo-lang/integ-tests/typescript/baml_client/async_client.ts:1485:18)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:636:7) {
-  code: 'GenericFailure'
-}
    at log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:647:17)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:643:5)
BamlValidationError: BamlValidationError: Failed to parse LLM response: Failed to coerce value: <root>: Failed while parsing required fields: missing=2, unparsed=0
-  - <root>: Missing required field: nonce
-  - <root>: Missing required field: nonce2
-    at Function.from (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/index.js:33:28)
-    at from (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/index.js:58:32)
-    at BamlAsyncClient.DummyOutputFunction (/Users/vbv/repos/gloo-lang/integ-tests/typescript/baml_client/async_client.ts:537:50)
-    at /Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:645:9
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:643:5) {
-  prompt: '[\x1B[2mchat\x1B[0m] \x1B[43msystem: \x1B[0mSay "hello there".\n',
-  raw_output: 'Hello there! How can I assist you today?'
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:659:17)
error BamlValidationError: BamlValidationError: Failed to parse LLM response: Failed to coerce value: <root>: Failed while parsing required fields: missing=2, unparsed=0
-  - <root>: Missing required field: nonce
-  - <root>: Missing required field: nonce2
-    at Function.from (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/index.js:33:28)
-    at from (/Users/vbv/repos/gloo-lang/engine/language_client_typescript/index.js:58:32)
-    at BamlAsyncClient.DummyOutputFunction (/Users/vbv/repos/gloo-lang/integ-tests/typescript/baml_client/async_client.ts:537:50)
-    at Object.<anonymous> (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:655:7) {
-  prompt: '[\x1B[2mchat\x1B[0m] \x1B[43msystem: \x1B[0mSay "hello there".\n',
-  raw_output: 'Hello there! How can I help you today?'
-}
    at Object.log (/Users/vbv/repos/gloo-lang/integ-tests/typescript/tests/integ-tests.test.ts:759:13)
{"nbc":{"value":{"foo":1,"bar":"hello"},"checks":{"cross_field":{"name":"cross_field","expression":"this.bar|length > this.foo","status":"succeeded"}}}}
\ No newline at end of file +

Test Report

Started: 2024-11-15 19:32:20
Suites (1)
0 passed
1 failed
0 pending
Tests (64)
62 passed
2 failed
0 pending
Integ tests > should work for all inputs
single bool
passed
0.823s
Integ tests > should work for all inputs
single string list
passed
1.004s
Integ tests > should work for all inputs
return literal union
failed
0.973s
BamlValidationError: BamlValidationError: Failed to parse LLM response: Failed to coerce value: <root>: Failed to find any (1 | true | "string output") in 3 items
+  - <root>: Expected 1, got Object([("Answer", String("true"))]).
+  - <root>: Expected true, got Object([("Answer", String("true"))]).
+  - <root>: Expected "string output", got Object([("Answer", String("true"))]).
+    at Function.from (/Users/greghale/code/baml/engine/language_client_typescript/index.js:33:28)
+    at from (/Users/greghale/code/baml/engine/language_client_typescript/index.js:58:32)
+    at BamlAsyncClient.LiteralUnionsTest (/Users/greghale/code/baml/integ-tests/typescript/baml_client/async_client.ts:1412:50)
+    at Object.<anonymous> (/Users/greghale/code/baml/integ-tests/typescript/tests/integ-tests.test.ts:42:19)
Integ tests > should work for all inputs
single class
passed
0.97s
Integ tests > should work for all inputs
multiple classes
passed
0.706s
Integ tests > should work for all inputs
single enum list
passed
0.733s
Integ tests > should work for all inputs
single float
passed
0.949s
Integ tests > should work for all inputs
single int
passed
1.186s
Integ tests > should work for all inputs
single literal int
passed
0.789s
Integ tests > should work for all inputs
single literal bool
passed
0.692s
Integ tests > should work for all inputs
single literal string
passed
0.663s
Integ tests > should work for all inputs
single class with literal prop
passed
1.023s
Integ tests > should work for all inputs
single class with literal union prop
passed
0.943s
Integ tests > should work for all inputs
single optional string
passed
0.874s
Integ tests > should work for all inputs
single map string to string
passed
0.962s
Integ tests > should work for all inputs
single map string to class
passed
0.807s
Integ tests > should work for all inputs
single map string to map
passed
0.808s
Integ tests
should work for all outputs
passed
10.556s
Integ tests
works with retries1
passed
2.638s
Integ tests
works with retries2
passed
4.042s
Integ tests
works with fallbacks
passed
3.456s
Integ tests
should work with image from url
passed
1.682s
Integ tests
should work with image from base 64
passed
1.445s
Integ tests
should work with audio base 64
passed
1.619s
Integ tests
should work with audio from url
passed
1.988s
Integ tests
should support streaming in OpenAI
passed
3.366s
Integ tests
should support streaming in Gemini
passed
8.699s
Integ tests
should support AWS
passed
2.087s
Integ tests
should support streaming in AWS
passed
1.629s
Integ tests
should allow overriding the region
passed
0.012s
Integ tests
should support OpenAI shorthand
passed
14.804s
Integ tests
should support OpenAI shorthand streaming
passed
10.288s
Integ tests
should support anthropic shorthand
passed
3.471s
Integ tests
should support anthropic shorthand streaming
passed
2.778s
Integ tests
should support streaming without iterating
passed
2.774s
Integ tests
should support streaming in Claude
passed
1.523s
Integ tests
should support vertex
passed
9.822s
Integ tests
supports tracing sync
passed
0.012s
Integ tests
supports tracing async
passed
4.65s
Integ tests
should work with dynamic types single
passed
1.482s
Integ tests
should work with dynamic types enum
passed
1.53s
Integ tests
should work with dynamic literals
passed
1.363s
Integ tests
should work with dynamic types class
passed
1.566s
Integ tests
should work with dynamic inputs class
passed
0.912s
Integ tests
should work with dynamic inputs list
passed
1.142s
Integ tests
should work with dynamic output map
passed
1.333s
Integ tests
should work with dynamic output union
passed
2.594s
Integ tests
should work with nested classes
failed
0.104s
Error: BamlError: BamlClientError: Something went wrong with the LLM client: reqwest::Error { kind: Request, url: Url { scheme: "http", cannot_be_a_base: false, username: "", password: None, host: Some(Domain("localhost")), port: Some(11434), path: "/v1/chat/completions", query: None, fragment: None }, source: hyper_util::client::legacy::Error(Connect, ConnectError("tcp connect error", Os { code: 61, kind: ConnectionRefused, message: "Connection refused" })) }
+    at BamlStream.parsed [as getFinalResponse] (/Users/greghale/code/baml/engine/language_client_typescript/stream.js:58:39)
+    at Object.<anonymous> (/Users/greghale/code/baml/integ-tests/typescript/tests/integ-tests.test.ts:584:19)
Integ tests
should work with dynamic client
passed
0.609s
Integ tests
should work with 'onLogEvent'
passed
4.141s
Integ tests
should work with a sync client
passed
1.264s
Integ tests
should raise an error when appropriate
passed
1.967s
Integ tests
should raise a BAMLValidationError
passed
0.737s
Integ tests
should reset environment variables correctly
passed
1.529s
Integ tests
should use aliases when serializing input objects - classes
passed
1.814s
Integ tests
should use aliases when serializing, but still have original keys in jinja
passed
1.783s
Integ tests
should use aliases when serializing input objects - enums
passed
0.687s
Integ tests
should use aliases when serializing input objects - lists
passed
0.688s
Integ tests
constraints: should handle checks in return types
passed
1.15s
Integ tests
constraints: should handle checks in returned unions
passed
1.245s
Integ tests
constraints: should handle block-level checks
passed
0.916s
Integ tests
constraints: should handle nested-block-level checks
passed
0.911s
Integ tests
simple recursive type
passed
3.379s
Integ tests
mutually recursive type
passed
3.077s
\ No newline at end of file