diff --git a/baml_language/Cargo.lock b/baml_language/Cargo.lock index fb04710848..2fd00c5039 100644 --- a/baml_language/Cargo.lock +++ b/baml_language/Cargo.lock @@ -1898,7 +1898,9 @@ dependencies = [ "prost", "reqwest", "serde", + "serde-wasm-bindgen", "serde_json", + "sys_glob", "sys_ops", "sys_types", "thiserror 2.0.18", @@ -7321,6 +7323,13 @@ dependencies = [ "syn 2.0.117", ] +[[package]] +name = "sys_glob" +version = "0.0.0-beta" +dependencies = [ + "regex", +] + [[package]] name = "sys_llm" version = "0.0.0-beta" @@ -7376,9 +7385,11 @@ dependencies = [ "indexmap 2.13.0", "reqwest", "serde_json", + "sys_glob", "sys_ops", "sys_types", "tokio", + "walkdir", ] [[package]] diff --git a/baml_language/Cargo.toml b/baml_language/Cargo.toml index 5c3fb7d39d..3b3aefc2fb 100644 --- a/baml_language/Cargo.toml +++ b/baml_language/Cargo.toml @@ -43,6 +43,7 @@ baml_compiler_parser = { path = "crates/baml_compiler_parser" } baml_compiler_syntax = { path = "crates/baml_compiler_syntax" } bex_project = { path = "crates/bex_project" } bex_engine = { path = "crates/bex_engine" } +sys_glob = { path = "crates/sys_glob" } sys_llm = { path = "crates/sys_llm" } sys_ops = { path = "crates/sys_ops" } sys_types = { path = "crates/sys_types" } @@ -151,6 +152,7 @@ salsa = { git = "https://github.com/salsa-rs/salsa.git", rev = "cdd0b85516a52c18 "inventory", ] } serde = { version = "1.0.197", features = [ "derive" ] } +serde-wasm-bindgen = "0.6" serde_json = { version = "1.0.113", features = [ "preserve_order" ] } similar = { version = "2.4.0", features = [ "inline" ] } smol_str = { version = "0.3" } diff --git a/baml_language/crates/baml_builtins2/baml_std/baml/ns_fs/fs.baml b/baml_language/crates/baml_builtins2/baml_std/baml/ns_fs/fs.baml index 66f2be67e3..8b1dabd3ce 100644 --- a/baml_language/crates/baml_builtins2/baml_std/baml/ns_fs/fs.baml +++ b/baml_language/crates/baml_builtins2/baml_std/baml/ns_fs/fs.baml @@ -61,3 +61,22 @@ function write(path: string, content: string) -> int throws root.errors.Io { function write_bytes(path: string, content: uint8array) -> int throws root.errors.Io { $rust_io_function } + +class DirEntry { + name string + is_dir bool + is_file bool + is_symlink bool +} + +class MkdirOptions { + recursive bool +} + +function read_dir(path: string) -> DirEntry[] throws root.errors.Io { + $rust_io_function +} + +function mkdir(path: string, options: MkdirOptions) -> null throws root.errors.Io { + $rust_io_function +} diff --git a/baml_language/crates/baml_builtins2/baml_std/baml/ns_glob/glob.baml b/baml_language/crates/baml_builtins2/baml_std/baml/ns_glob/glob.baml new file mode 100644 index 0000000000..458e8d0dbe --- /dev/null +++ b/baml_language/crates/baml_builtins2/baml_std/baml/ns_glob/glob.baml @@ -0,0 +1,24 @@ +class ScanOptions { + cwd string? + dot bool? + absolute bool? + follow_symlinks bool? + throw_error_on_broken_symlink bool? + only_files bool? +} + +class Glob { + _handle $rust_type + + function scan(self, root: string | ScanOptions) -> string[] throws root.errors.Io { + $rust_io_function + } + + function matches(self, path: string) -> bool throws root.errors.Io { + $rust_io_function + } +} + +function new(pattern: string) -> Glob throws root.errors.Io { + $rust_io_function +} diff --git a/baml_language/crates/baml_builtins2/src/lib.rs b/baml_language/crates/baml_builtins2/src/lib.rs index 05256b2879..f5af9e618c 100644 --- a/baml_language/crates/baml_builtins2/src/lib.rs +++ b/baml_language/crates/baml_builtins2/src/lib.rs @@ -90,6 +90,7 @@ pub const ALL: &[BuiltinFile] = &[ builtin!("baml", "ns_math/math.baml"), builtin!("baml", "ns_sys/sys.baml"), builtin!("baml", "ns_fs/fs.baml"), + builtin!("baml", "ns_glob/glob.baml"), builtin!("baml", "ns_net/net.baml"), builtin!("baml", "ns_media/media.baml"), builtin!("baml", "ns_unstable/unstable.baml"), diff --git a/baml_language/crates/baml_builtins2_codegen/src/codegen_io.rs b/baml_language/crates/baml_builtins2_codegen/src/codegen_io.rs index 995802404e..af34920c62 100644 --- a/baml_language/crates/baml_builtins2_codegen/src/codegen_io.rs +++ b/baml_language/crates/baml_builtins2_codegen/src/codegen_io.rs @@ -1422,6 +1422,44 @@ fn emit_one_namespace_trait( } } +/// Generate the `.into_result(...)` call for a given return type. +/// +/// - Scalar types implementing `AsBexExternalValue` use `.into_result(op)`. +/// - `List(Named(...))` uses `.into_result_mapped(op, |v| ...)` because +/// `Vec` does not implement `AsBexExternalValue` (orphan rules +/// prevent it in the generated crate). +fn emit_into_result_call( + return_type: &BamlType, + variant_ident: &syn::Ident, + call_expr: &TokenStream, + class_ns_map: &BTreeMap, + paths: &CodegenPaths, +) -> TokenStream { + if let BamlType::List(inner) = return_type { + if let BamlType::Named(name) = inner.as_ref() { + if let Some(ns) = class_ns_map.get(name.as_str()) { + let owned = &paths.owned; + let ns_ident = format_ident!("{}", ns); + let name_ident = format_ident!("{}", name); + return quote! { + #call_expr + .into_result_mapped(SysOp::#variant_ident, |v| { + BexExternalValue::Array { + element_type: baml_type::Ty::unknown(), + items: v.into_iter() + .map(|item| <#owned::#ns_ident::#name_ident as AsBexExternalValue>::into_bex_external_value(item)) + .collect(), + } + }) + }; + } + } + } + quote! { + #call_expr.into_result(SysOp::#variant_ident) + } +} + fn emit_free_fn_glue( builtin: &NativeBuiltin, ns_trait_ident: &syn::Ident, @@ -1433,6 +1471,16 @@ fn emit_free_fn_glue( let clean_ident = format_ident!("{}", io_method_name(builtin)); if builtin.params.is_empty() { + let call_expr = quote! { + #ns_trait_ident::#clean_ident(self, heap, call_id, ctx) + }; + let into_result = emit_into_result_call( + &builtin.return_type, + &variant_ident, + &call_expr, + class_ns_map, + paths, + ); return quote! { fn #glue_ident<'a>( &self, @@ -1442,7 +1490,7 @@ fn emit_free_fn_glue( ctx: &SysOpContext, call_id: CallId, ) -> SysOpResult { - #ns_trait_ident::#clean_ident(self, heap, call_id, ctx).into_result(SysOp::#variant_ident) + #into_result } }; } @@ -1487,6 +1535,17 @@ fn emit_free_fn_glue( quote! { Ok::<_, AccessError>((#(#param_idents),*)) } }; + let call_expr = quote! { + #ns_trait_ident::#clean_ident(self, heap, call_id, #(#param_idents,)* ctx) + }; + let into_result = emit_into_result_call( + &builtin.return_type, + &variant_ident, + &call_expr, + class_ns_map, + paths, + ); + quote! { fn #glue_ident<'a>( &self, @@ -1506,8 +1565,7 @@ fn emit_free_fn_glue( match __extraction { Ok(#ok_pattern) => { - #ns_trait_ident::#clean_ident(self, heap, call_id, #(#param_idents,)* ctx) - .into_result(SysOp::#variant_ident) + #into_result } Err(e) => SysOpResult::Ready(Err(OpError::new( SysOp::#variant_ident, @@ -2011,14 +2069,29 @@ fn emit_adapter_impl( } /// Generate the expression that converts `__val: BexExternalValue` to the method's return type. +/// +/// Top-level entry: looks up handle classes in `tree` and supports `Null` +/// (returning unit). Recursive calls into containers pass `tree = None` and +/// override the error suffix so messages reflect the nesting context. fn emit_result_conversion( builtin: &NativeBuiltin, tree: &BTreeMap, class_ns_map: &BTreeMap, paths: &CodegenPaths, ) -> TokenStream { - // Check if return type maps to a handle. - if let BamlType::Named(name) = &builtin.return_type { + emit_result_conversion_for_ty(&builtin.return_type, Some(tree), class_ns_map, paths, "") +} + +fn emit_result_conversion_for_ty( + ty: &BamlType, + tree: Option<&BTreeMap>, + class_ns_map: &BTreeMap, + paths: &CodegenPaths, + ctx: &str, +) -> TokenStream { + // Handle-class shortcut: only at the top level (lists/maps of handles + // aren't supported). + if let (Some(tree), BamlType::Named(name)) = (tree, ty) { if let Some(ns) = class_ns_map.get(name.as_str()) { if let Some(node) = tree.get(ns) { if node.classes.contains_key(name.as_str()) { @@ -2029,43 +2102,66 @@ fn emit_result_conversion( } } - match &builtin.return_type { - BamlType::String => quote! { - match __val { - BexExternalValue::String(s) => Ok(s), - other => Err(RuntimeIoError::Other( - format!("expected string, got {}", other.type_name()), - )), + match ty { + BamlType::String => { + let msg = format!("expected string{ctx}, got {{}}"); + quote! { + match __val { + BexExternalValue::String(s) => Ok(s), + other => Err(RuntimeIoError::Other( + format!(#msg, other.type_name()), + )), + } } - }, - BamlType::Int => quote! { - match __val { - BexExternalValue::Int(v) => Ok(v), - other => Err(RuntimeIoError::Other( - format!("expected int, got {}", other.type_name()), - )), + } + BamlType::Int => { + let msg = format!("expected int{ctx}, got {{}}"); + quote! { + match __val { + BexExternalValue::Int(v) => Ok(v), + other => Err(RuntimeIoError::Other( + format!(#msg, other.type_name()), + )), + } } - }, - BamlType::Float => quote! { - match __val { - BexExternalValue::Float(v) => Ok(v), - other => Err(RuntimeIoError::Other( - format!("expected float, got {}", other.type_name()), - )), + } + BamlType::Float => { + let msg = format!("expected float{ctx}, got {{}}"); + quote! { + match __val { + BexExternalValue::Float(v) => Ok(v), + other => Err(RuntimeIoError::Other( + format!(#msg, other.type_name()), + )), + } } - }, - BamlType::Bool => quote! { - match __val { - BexExternalValue::Bool(v) => Ok(v), - other => Err(RuntimeIoError::Other( - format!("expected bool, got {}", other.type_name()), - )), + } + BamlType::Bool => { + let msg = format!("expected bool{ctx}, got {{}}"); + quote! { + match __val { + BexExternalValue::Bool(v) => Ok(v), + other => Err(RuntimeIoError::Other( + format!(#msg, other.type_name()), + )), + } } - }, - BamlType::Null => quote! { Ok(()) }, + } + BamlType::Uint8Array => { + let msg = format!("expected uint8array{ctx}, got {{}}"); + quote! { + match __val { + BexExternalValue::Uint8Array(v) => Ok(v), + other => Err(RuntimeIoError::Other( + format!(#msg, other.type_name()), + )), + } + } + } + // `Null` as a return type means unit; only meaningful at the top level. + BamlType::Null if tree.is_some() => quote! { Ok(()) }, BamlType::Optional(inner) => { - // Create a temporary builtin with the inner type to recurse. - let inner_conv = emit_result_conversion_simple(inner, class_ns_map, paths); + let inner_conv = emit_result_conversion_for_ty(inner, None, class_ns_map, paths, ctx); quote! { match __val { BexExternalValue::Null => Ok(None), @@ -2076,28 +2172,56 @@ fn emit_result_conversion( } } } - BamlType::Uint8Array => quote! { - match __val { - BexExternalValue::Uint8Array(v) => Ok(v), - other => Err(RuntimeIoError::Other( - format!("expected uint8array, got {}", other.type_name()), - )), + BamlType::List(inner) => { + let inner_conv = + emit_result_conversion_for_ty(inner, None, class_ns_map, paths, " in list"); + let msg = format!("expected array{ctx}, got {{}}"); + quote! { + match __val { + BexExternalValue::Array { items, .. } => { + items.into_iter() + .map(|__val| { #inner_conv }) + .collect::, _>>() + } + other => Err(RuntimeIoError::Other( + format!(#msg, other.type_name()), + )), + } } - }, - BamlType::Named(name) => match name.as_str() { - "type" => quote! { + } + BamlType::Map(key, value) if matches!(key.as_ref(), BamlType::String) => { + let value_conv = + emit_result_conversion_for_ty(value, None, class_ns_map, paths, " in map"); + let msg = format!("expected map{ctx}, got {{}}"); + quote! { match __val { - BexExternalValue::Adt( - bex_external_types::BexExternalAdt::Type(ty), - ) => Ok(ty), + BexExternalValue::Map { entries, .. } => { + entries.into_iter() + .map(|(__key, __val)| Ok((__key, { #value_conv }?))) + .collect::, _>>() + } other => Err(RuntimeIoError::Other( - format!("expected type, got {}", other.type_name()), + format!(#msg, other.type_name()), )), } - }, + } + } + BamlType::Named(name) => match name.as_str() { + "type" => { + let msg = format!("expected type{ctx}, got {{}}"); + quote! { + match __val { + BexExternalValue::Adt( + bex_external_types::BexExternalAdt::Type(ty), + ) => Ok(ty), + other => Err(RuntimeIoError::Other( + format!(#msg, other.type_name()), + )), + } + } + } _ => { - if class_ns_map.contains_key(name.as_str()) { - let ns = &class_ns_map[name.as_str()]; + if let Some(ns) = class_ns_map.get(name.as_str()) { let owned = &paths.owned; let ns_ident = format_ident!("{}", ns); let name_ident = format_ident!("{}", name); @@ -2114,49 +2238,6 @@ fn emit_result_conversion( } } -/// Simplified result conversion for inner types (used in Optional). -fn emit_result_conversion_simple( - ty: &BamlType, - _class_ns_map: &BTreeMap, - _paths: &CodegenPaths, -) -> TokenStream { - match ty { - BamlType::String => quote! { - match __val { - BexExternalValue::String(s) => Ok(s), - other => Err(RuntimeIoError::Other( - format!("expected string, got {}", other.type_name()), - )), - } - }, - BamlType::Int => quote! { - match __val { - BexExternalValue::Int(v) => Ok(v), - other => Err(RuntimeIoError::Other( - format!("expected int, got {}", other.type_name()), - )), - } - }, - BamlType::Float => quote! { - match __val { - BexExternalValue::Float(v) => Ok(v), - other => Err(RuntimeIoError::Other( - format!("expected float, got {}", other.type_name()), - )), - } - }, - BamlType::Bool => quote! { - match __val { - BexExternalValue::Bool(v) => Ok(v), - other => Err(RuntimeIoError::Other( - format!("expected bool, got {}", other.type_name()), - )), - } - }, - _ => quote! { Ok(__val) }, - } -} - fn emit_build_runtime_io(io_builtins: &[NativeBuiltin]) -> TokenStream { let field_inits: Vec = io_builtins .iter() diff --git a/baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs b/baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs index adef6a8127..3a0070aa8a 100644 --- a/baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs +++ b/baml_language/crates/baml_compiler2_ast/src/lower_expr_body.rs @@ -1997,9 +1997,13 @@ impl LoweringContext { // Look for the optional type name (first WORD or path before the brace). // The type name may be: - // - A simple WORD token: `MyClass { ... }` - // - A qualified path node: `baml.errors.DevOther { ... }` (parsed as PATH_EXPR) - // For qualified paths, extract the final segment as the class name. + // - A simple WORD token: `MyClass { ... }` → stored as `"MyClass"`. + // - A qualified path node: `baml.errors.DevOther { ... }` (parsed as + // PATH_EXPR) → stored as the full dotted string `"baml.errors.DevOther"`, + // so downstream consumers (TIR resolution, MIR field-order lookup) + // have the namespace info needed to find the right type. Without + // this, `lookup_type` would only see the bare name and miss the + // class living in another namespace. 'outer: for elem in node.children_with_tokens() { match elem { rowan::NodeOrToken::Token(token) => { @@ -2011,19 +2015,17 @@ impl LoweringContext { } } rowan::NodeOrToken::Node(child_node) => { - // A child node before L_BRACE is the type name path (e.g. PATH_EXPR). - // Walk its tokens to find the last WORD — that's the class name. - let mut last_word: Option = None; - for token in child_node + // A child node before L_BRACE is the type name path (e.g. + // PATH_EXPR). Collect every WORD token and join them with + // dots to preserve the qualified path. + let segments: Vec = child_node .children_with_tokens() .filter_map(rowan::NodeOrToken::into_token) - { - if is_ident_token(token.kind()) { - last_word = Some(Name::new(token.text())); - } - } - if let Some(name) = last_word { - type_name = Some(name); + .filter(|t| is_ident_token(t.kind())) + .map(|t| t.text().to_string()) + .collect(); + if !segments.is_empty() { + type_name = Some(Name::new(segments.join("."))); } // After handling the path node, stop scanning for more pre-brace items. break 'outer; diff --git a/baml_language/crates/baml_compiler2_mir/src/lower.rs b/baml_language/crates/baml_compiler2_mir/src/lower.rs index 63d2fe1d3e..792168ce1c 100644 --- a/baml_language/crates/baml_compiler2_mir/src/lower.rs +++ b/baml_language/crates/baml_compiler2_mir/src/lower.rs @@ -3230,19 +3230,54 @@ impl LoweringContext<'_> { Ty::Class(tn, _) => Some(tn.clone()), _ => None, }; - let class_name = if let Some(n) = type_name { - n.to_string() + // Prefer the TIR-resolved fully-qualified name (`..`) + // because that matches the bytecode emitter's FQN registry. The parser + // stores qualified paths verbatim from source (e.g. `root.http.Response` + // for user types), but the emitter registers user types under the `user.` + // prefix — so the source-verbatim form would miss the lookup. Falling + // back to the parser name only when TIR has no type info handles + // synthetic Object exprs from `lower_cst.rs` that already use registry- + // matching dotted forms like "baml.llm.Client". + let class_name = if let Some(tn) = &type_name_key { + let mut parts: Vec = tn.module_path.iter().map(ToString::to_string).collect(); + parts.push(tn.name.to_string()); + parts.join(".") } else { - type_name_key - .as_ref() - .map_or_else(String::new, |tn| tn.name.to_string()) + type_name.map(ToString::to_string).unwrap_or_default() }; if spreads.is_empty() { - let field_operands: Vec = fields - .iter() - .map(|(_, e)| self.lower_to_operand(*e)) - .collect(); + // Lower fields in class-definition order, filling unspecified slots + // with Null. Source order in the literal does not match definition + // order, so a partial literal like `ScanOptions { absolute: true }` + // would otherwise put `absolute` into whichever slot happens to be + // first. The TIR Object handler resolves the type via its qualified + // path, so `class_fields.get(tn)` always finds the definition for + // any user-written class literal. + let field_operands: Vec = if let Some(field_name_to_idx) = type_name_key + .as_ref() + .and_then(|tn| self.class_fields.get(tn)) + .cloned() + { + let mut result: Vec = (0..field_name_to_idx.len()) + .map(|_| Operand::Constant(Constant::Null)) + .collect(); + for (name, expr) in fields { + if let Some(&idx) = field_name_to_idx.get(&name.to_string()) { + result[idx] = self.lower_to_operand(*expr); + } + } + result + } else { + // Synthetic Object exprs without TIR type info (e.g. compiler + // sugar for retry policies) fall back to source order. These + // construction sites build full, ordered literals so the order + // matches the class definition. + fields + .iter() + .map(|(_, e)| self.lower_to_operand(*e)) + .collect() + }; self.builder.assign( dest, Rvalue::Aggregate { diff --git a/baml_language/crates/baml_compiler2_tir/src/builder.rs b/baml_language/crates/baml_compiler2_tir/src/builder.rs index 6b64d3b426..9a7697172d 100644 --- a/baml_language/crates/baml_compiler2_tir/src/builder.rs +++ b/baml_language/crates/baml_compiler2_tir/src/builder.rs @@ -1498,15 +1498,14 @@ impl<'db> TypeInferenceBuilder<'db> { type_name .as_ref() .and_then(|n| { - self.package_items - .lookup_type(&self.ns_context, n) - .map(|def| { - Ty::Class( - crate::lower_type_expr::qualify_def(self.context.db(), def, n), - vec![], - TyAttr::default(), - ) - }) + // The parser stores qualified paths like + // `baml.glob.ScanOptions` as a single dotted Name. + // Split it back into segments so resolve_type can find + // types living in another namespace. + let path: Vec = n.as_str().split('.').map(Name::new).collect(); + self.res_ctx + .resolve_type(self.context.db(), &path, &self.ns_context) + .map(|(_, ty)| ty) }) .unwrap_or(Ty::Unknown { attr: TyAttr::default(), diff --git a/baml_language/crates/baml_compiler2_tir/src/throw_inference.rs b/baml_language/crates/baml_compiler2_tir/src/throw_inference.rs index 602b5f3cab..a3828a63a3 100644 --- a/baml_language/crates/baml_compiler2_tir/src/throw_inference.rs +++ b/baml_language/crates/baml_compiler2_tir/src/throw_inference.rs @@ -358,21 +358,11 @@ fn throw_fact_from_expr<'db>( type_name: Some(name), .. } => { - if let Some(def) = pkg_items.lookup_type(ns_context, name) { - match def { - Definition::Class(_) => { - Ty::Class(qualify_def(db, def, name), vec![], TyAttr::default()) - } - Definition::Enum(_) => Ty::Enum(qualify_def(db, def, name), TyAttr::default()), - _ => Ty::Unknown { - attr: TyAttr::default(), - }, - } - } else { - Ty::Unknown { - attr: TyAttr::default(), - } - } + // The parser stores qualified paths like `baml.errors.DevOther` as + // a single dotted Name. Split into segments and resolve through + // the same path-resolution logic used for Path/MemberAccess. + let segments: Vec = name.as_str().split('.').map(Name::new).collect(); + resolve_path_to_ty(db, pkg_items, ns_context, &segments) } _ => Ty::Unknown { attr: TyAttr::default(), diff --git a/baml_language/crates/baml_compiler_parser/src/parser.rs b/baml_language/crates/baml_compiler_parser/src/parser.rs index 108b803dd5..b708975ad9 100644 --- a/baml_language/crates/baml_compiler_parser/src/parser.rs +++ b/baml_language/crates/baml_compiler_parser/src/parser.rs @@ -298,6 +298,10 @@ impl<'a> Parser<'a> { self.current().is_none() } + fn at_end_raw(&self) -> bool { + self.current_raw().is_none() + } + /// Check if current token matches the given kind fn at(&self, kind: TokenKind) -> bool { self.current().map(|t| t.kind == kind).unwrap_or(false) @@ -1351,9 +1355,12 @@ impl<'a> Parser<'a> { self.with_node(SyntaxKind::STRING_LITERAL, |p| { p.bump(); // Opening quote - // Collect all tokens until closing quote + // Collect all tokens until closing quote. + // Use at_end_raw / at_raw / bump_raw throughout so that `*/` + // and `//` inside the string are kept as literal content instead + // of being mis-recognised as comment delimiters. let mut loop_counter = 0; - while !p.at_end() { + while !p.at_end_raw() { loop_counter += 1; if loop_counter > 100_000 { p.error_unexpected_token("String parsing exceeded iteration limit".to_string()); @@ -1370,19 +1377,13 @@ impl<'a> Parser<'a> { continue; } - // Check if next token is the closing quote - // Use at_raw to avoid skipping // as comments - we want the actual next token if p.at_raw(TokenKind::Quote) { p.bump_raw(); // Consume closing quote return; } - // Not a quote - consume as string content - // Use bump_raw() to avoid treating // as comments inside strings p.bump_raw(); } - // If we get here, we reached EOF without finding closing quote - // eprintln!("[PARSE_STRING] Reached EOF without closing quote"); p.error_unexpected_token("Unclosed string literal".to_string()); }); @@ -1417,7 +1418,7 @@ impl<'a> Parser<'a> { // Collect all tokens until closing quote (same logic as parse_string). let mut loop_counter = 0; - while !p.at_end() { + while !p.at_end_raw() { loop_counter += 1; if loop_counter > 100_000 { p.error_unexpected_token( @@ -1502,7 +1503,7 @@ impl<'a> Parser<'a> { break; } - if self.at_end() { + if self.at_end_raw() { self.error_unexpected_token(format!( "Unclosed raw string (expected \"{}\")", "#".repeat(opening_hashes) @@ -1515,9 +1516,9 @@ impl<'a> Parser<'a> { let closing_hashes = self.count_consecutive_hashes_after_quote(); if closing_hashes == opening_hashes { // Found matching closing delimiter - self.bump(); // Closing " + self.bump_raw(); // Closing " for _ in 0..closing_hashes { - self.bump(); // # + self.bump_raw(); // # } break; } @@ -1558,12 +1559,12 @@ impl<'a> Parser<'a> { /// Parse a Jinja expression: {{ ... }} fn parse_jinja_expression(&mut self, opening_hashes: usize) { self.with_node(SyntaxKind::TEMPLATE_INTERPOLATION, |p| { - p.bump(); // { - p.bump(); // { + p.bump_raw(); // { + p.bump_raw(); // { // Collect tokens until we find }} let mut depth = 1; - while !p.at_end() && depth > 0 { + while !p.at_end_raw() && depth > 0 { if p.at_raw(TokenKind::Quote) && p.count_consecutive_hashes_after_quote() == opening_hashes { @@ -1581,8 +1582,8 @@ impl<'a> Parser<'a> { { depth -= 1; if depth == 0 { - p.bump(); // } - p.bump(); // } + p.bump_raw(); // } + p.bump_raw(); // } break; } p.bump_raw(); @@ -1601,11 +1602,11 @@ impl<'a> Parser<'a> { /// Parse a Jinja statement: {% ... %} fn parse_jinja_statement(&mut self, opening_hashes: usize) { self.with_node(SyntaxKind::TEMPLATE_CONTROL, |p| { - p.bump(); // { - p.bump(); // % + p.bump_raw(); // { + p.bump_raw(); // % // Collect tokens until we find %} - while !p.at_end() { + while !p.at_end_raw() { if p.at_raw(TokenKind::Quote) && p.count_consecutive_hashes_after_quote() == opening_hashes { @@ -1615,8 +1616,8 @@ impl<'a> Parser<'a> { if p.at_raw(TokenKind::Percent) && p.peek_impl(1, false).map(|t| t.kind) == Some(TokenKind::RBrace) { - p.bump(); // % - p.bump(); // } + p.bump_raw(); // % + p.bump_raw(); // } break; } p.bump_raw(); @@ -1627,11 +1628,11 @@ impl<'a> Parser<'a> { /// Parse a Jinja comment: {# ... #} fn parse_jinja_comment(&mut self, opening_hashes: usize) { self.with_node(SyntaxKind::TEMPLATE_COMMENT, |p| { - p.bump(); // { - p.bump(); // # + p.bump_raw(); // { + p.bump_raw(); // # // Collect tokens until we find #} - while !p.at_end() { + while !p.at_end_raw() { if p.at_raw(TokenKind::Quote) && p.count_consecutive_hashes_after_quote() == opening_hashes { @@ -1641,8 +1642,8 @@ impl<'a> Parser<'a> { if p.at_raw(TokenKind::Hash) && p.peek_impl(1, false).map(|t| t.kind) == Some(TokenKind::RBrace) { - p.bump(); // # - p.bump(); // } + p.bump_raw(); // # + p.bump_raw(); // } break; } p.bump_raw(); @@ -1656,7 +1657,7 @@ impl<'a> Parser<'a> { fn parse_prompt_text(&mut self, opening_hashes: usize) { self.with_node(SyntaxKind::PROMPT_TEXT, |p| { // Collect tokens until we hit a Jinja construct or closing delimiter - while !p.at_end() { + while !p.at_end_raw() { // Check for closing delimiter if p.at_raw(TokenKind::Quote) { let closing_hashes = p.count_consecutive_hashes_after_quote(); @@ -5206,6 +5207,31 @@ class Response { assert_eq!(attrs.len(), 1, "expected method block attribute"); } + #[test] + fn raw_string_keeps_comment_markers_as_text() { + for marker in ["//", "*/"] { + let source = format!( + r##" +function Demo() -> string {{ + #"{marker}"# +}} +"## + ); + + let (root, errors) = parse_source(&source); + assert_no_errors(&errors); + + let raw_string = root + .descendants() + .find(|n| n.kind() == SyntaxKind::RAW_STRING_LITERAL) + .expect("expected raw string literal"); + assert!( + raw_string.text().to_string().contains(marker), + "raw string should retain marker {marker:?}: {raw_string:?}" + ); + } + } + #[test] fn parses_function_with_client_as_parameter_name() { // `client` is a keyword (KW_CLIENT); it must still be valid as a parameter name. diff --git a/baml_language/crates/baml_tests/projects/builtin_io/fs_ops.baml b/baml_language/crates/baml_tests/projects/builtin_io/fs_ops.baml index a5e5e619e4..6444f21d93 100644 --- a/baml_language/crates/baml_tests/projects/builtin_io/fs_ops.baml +++ b/baml_language/crates/baml_tests/projects/builtin_io/fs_ops.baml @@ -100,3 +100,7 @@ function Remove() -> null { function Size() -> int { baml.fs.size("data.bin") } + +function ReadDir() -> baml.fs.DirEntry[] { + baml.fs.read_dir("some/path") +} diff --git a/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____03_hir.snap b/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____03_hir.snap index be8e565851..784196449a 100644 --- a/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____03_hir.snap @@ -84,16 +84,27 @@ function baml.errors.to_string(self: ?) -> string [builtin] function baml.events.send(event_name: string, data: map) -> void [builtin] --- /baml/ns_fs/fs.baml --- +class baml.fs.DirEntry { + name: string + is_dir: bool + is_file: bool + is_symlink: bool +} class baml.fs.File { _handle: $rust_type } +class baml.fs.MkdirOptions { + recursive: bool +} function baml.fs.bytes(self: ?) -> uint8array [builtin] function baml.fs.close(self: ?) -> null [builtin] function baml.fs.exists(path: string) -> bool [builtin] +function baml.fs.mkdir(path: string, options: baml.fs.MkdirOptions) -> null [builtin] function baml.fs.open(path: string, mode: "r" | "r+" | "w" | "w+" | "a" | "a+") -> baml.fs.File [builtin] function baml.fs.read(path: string) -> string [builtin] function baml.fs.read(self: ?, n: int) -> string [builtin] function baml.fs.read_bytes(self: ?, n: int) -> uint8array [builtin] +function baml.fs.read_dir(path: string) -> baml.fs.DirEntry[] [builtin] function baml.fs.remove(path: string) -> null [builtin] function baml.fs.seek_from(self: ?, whence: "start" | "current" | "end", offset: int) -> int [builtin] function baml.fs.size(path: string) -> int [builtin] @@ -103,6 +114,22 @@ function baml.fs.write(path: string, content: string) -> int [builtin] function baml.fs.write_bytes(self: ?, data: uint8array) -> int [builtin] function baml.fs.write_bytes(path: string, content: uint8array) -> int [builtin] +--- /baml/ns_glob/glob.baml --- +class baml.glob.Glob { + _handle: $rust_type +} +class baml.glob.ScanOptions { + cwd: string? + dot: bool? + absolute: bool? + follow_symlinks: bool? + throw_error_on_broken_symlink: bool? + only_files: bool? +} +function baml.glob.matches(self: ?, path: string) -> bool [builtin] +function baml.glob.new(pattern: string) -> baml.glob.Glob [builtin] +function baml.glob.scan(self: ?, root: string | baml.glob.ScanOptions) -> string[] [builtin] + --- /baml/ns_http/http.baml --- class baml.http.Request { method: string @@ -279,19 +306,19 @@ function baml.llm.build_request(self: ?, prompt: baml.llm.PromptAst) -> root.htt function baml.llm.build_request_stream(self: ?, prompt: baml.llm.PromptAst) -> root.http.Request [builtin] function baml.llm.content(self: ?) -> string [builtin] function baml.llm.execute_once_oneshot(self: ?, context: baml.llm.ExecutionContext, active_delay_ms: int) -> baml.llm.T [expr] { - { } match (self.client_type) { baml.llm.ClientType.Primitive => { let primitive = self.to_primitive_client(); let return_type = get_return_type(context.function_name); let prompt = primitive.render_prompt(context.jinja_string, context.args, return_type); let specialized = primitive.specialize_prompt(prompt); let http_request = primitive.build_request(specialized); let http_response = root.http.send(http_request) } if (http_response.ok()) { let body = http_response.text(); let result: baml.llm.T = primitive.parse(body, return_type) catch (e) { _ => { if (active_delay_ms Gt 0) { } root.sys.sleep(active_delay_ms); throw e } } } result else { let error_body = http_response.text() catch (e) { _ => { } "" }; if (active_delay_ms Gt 0) { } root.sys.sleep(active_delay_ms); throw DevOther { message: "HTTP request fail..." Add error_body } }, baml.llm.ClientType.Fallback => { for sub in self.sub_clients { let result2: baml.llm.T = sub.execute_oneshot(context, active_delay_ms) catch (e) { _ => { continue } }; return result2 }; throw DevOther { message: "All orchestration..." } }, baml.llm.ClientType.RoundRobin => { if (self.sub_clients.length() Eq 0) { throw DevOther { message: "RoundRobin client..." } }; let idx = self.counter Mod self.sub_clients.length(); self.counter Add= 1; let result3: baml.llm.T = self.sub_clients[idx].execute_oneshot(context, active_delay_ms); return result3 } } + { } match (self.client_type) { baml.llm.ClientType.Primitive => { let primitive = self.to_primitive_client(); let return_type = get_return_type(context.function_name); let prompt = primitive.render_prompt(context.jinja_string, context.args, return_type); let specialized = primitive.specialize_prompt(prompt); let http_request = primitive.build_request(specialized); let http_response = root.http.send(http_request) } if (http_response.ok()) { let body = http_response.text(); let result: baml.llm.T = primitive.parse(body, return_type) catch (e) { _ => { if (active_delay_ms Gt 0) { } root.sys.sleep(active_delay_ms); throw e } } } result else { let error_body = http_response.text() catch (e) { _ => { } "" }; if (active_delay_ms Gt 0) { } root.sys.sleep(active_delay_ms); throw root.errors.DevOther { message: "HTTP request fail..." Add error_body } }, baml.llm.ClientType.Fallback => { for sub in self.sub_clients { let result2: baml.llm.T = sub.execute_oneshot(context, active_delay_ms) catch (e) { _ => { continue } }; return result2 }; throw root.errors.DevOther { message: "All orchestration..." } }, baml.llm.ClientType.RoundRobin => { if (self.sub_clients.length() Eq 0) { throw root.errors.DevOther { message: "RoundRobin client..." } }; let idx = self.counter Mod self.sub_clients.length(); self.counter Add= 1; let result3: baml.llm.T = self.sub_clients[idx].execute_oneshot(context, active_delay_ms); return result3 } } } function baml.llm.execute_once_stream(self: ?, context: baml.llm.ExecutionContext, active_delay_ms: int) -> baml.llm.Stream [expr] { - { } match (self.client_type) { baml.llm.ClientType.Primitive => { let primitive = self.to_primitive_client(); let return_type = get_return_type(context.function_name); let prompt = primitive.render_prompt(context.jinja_string, context.args, return_type); let specialized = primitive.specialize_prompt(prompt); let http_request = primitive.build_request_stream(specialized); let sse = root.http.fetch_sse(http_request); let stream: baml.llm.Stream = self.__make_stream(sse, context.function_name); return stream }, baml.llm.ClientType.Fallback => { for sub in self.sub_clients { let result2: baml.llm.Stream = sub.execute_stream(context, active_delay_ms) catch (e) { _ => { continue } }; return result2 }; throw DevOther { message: "All orchestration..." } }, baml.llm.ClientType.RoundRobin => { if (self.sub_clients.length() Eq 0) { throw DevOther { message: "RoundRobin client..." } }; let idx = self.counter Mod self.sub_clients.length(); self.counter Add= 1; let result3: baml.llm.Stream = self.sub_clients[idx].execute_stream(context, active_delay_ms); return result3 } } + { } match (self.client_type) { baml.llm.ClientType.Primitive => { let primitive = self.to_primitive_client(); let return_type = get_return_type(context.function_name); let prompt = primitive.render_prompt(context.jinja_string, context.args, return_type); let specialized = primitive.specialize_prompt(prompt); let http_request = primitive.build_request_stream(specialized); let sse = root.http.fetch_sse(http_request); let stream: baml.llm.Stream = self.__make_stream(sse, context.function_name); return stream }, baml.llm.ClientType.Fallback => { for sub in self.sub_clients { let result2: baml.llm.Stream = sub.execute_stream(context, active_delay_ms) catch (e) { _ => { continue } }; return result2 }; throw root.errors.DevOther { message: "All orchestration..." } }, baml.llm.ClientType.RoundRobin => { if (self.sub_clients.length() Eq 0) { throw root.errors.DevOther { message: "RoundRobin client..." } }; let idx = self.counter Mod self.sub_clients.length(); self.counter Add= 1; let result3: baml.llm.Stream = self.sub_clients[idx].execute_stream(context, active_delay_ms); return result3 } } } function baml.llm.execute_oneshot(self: ?, context: baml.llm.ExecutionContext, inherited_delay_ms: int) -> baml.llm.T [expr] { - { } match (self.retry) { r: baml.llm.RetryPolicy => { let current_delay = r.initial_delay_ms Add 0.0; { let attempt = 0; while attempt Le r.max_retries { let attempt_delay = inherited_delay_ms; if (attempt Gt 0) { attempt_delay = root.math.trunc(current_delay); let next = current_delay Mul r.multiplier } if (next Gt r.max_delay_ms Add 0.0) { current_delay = r.max_delay_ms Add 0.0 } else { current_delay = next }; if (attempt Eq r.max_retries) { attempt_delay = inherited_delay_ms }; let result2: baml.llm.T = self.execute_once_oneshot(context, attempt_delay) catch (e) { _ => { continue } }; return result2 } }; throw DevOther { message: "All orchestration..." } }, null => { let result: baml.llm.T = self.execute_once_oneshot(context, inherited_delay_ms); return result } } + { } match (self.retry) { r: baml.llm.RetryPolicy => { let current_delay = r.initial_delay_ms Add 0.0; { let attempt = 0; while attempt Le r.max_retries { let attempt_delay = inherited_delay_ms; if (attempt Gt 0) { attempt_delay = root.math.trunc(current_delay); let next = current_delay Mul r.multiplier } if (next Gt r.max_delay_ms Add 0.0) { current_delay = r.max_delay_ms Add 0.0 } else { current_delay = next }; if (attempt Eq r.max_retries) { attempt_delay = inherited_delay_ms }; let result2: baml.llm.T = self.execute_once_oneshot(context, attempt_delay) catch (e) { _ => { continue } }; return result2 } }; throw root.errors.DevOther { message: "All orchestration..." } }, null => { let result: baml.llm.T = self.execute_once_oneshot(context, inherited_delay_ms); return result } } } function baml.llm.execute_stream(self: ?, context: baml.llm.ExecutionContext, inherited_delay_ms: int) -> baml.llm.Stream [expr] { - { } match (self.retry) { r: baml.llm.RetryPolicy => { let current_delay = r.initial_delay_ms Add 0.0; { let attempt = 0; while attempt Le r.max_retries { let attempt_delay = inherited_delay_ms; if (attempt Gt 0) { attempt_delay = root.math.trunc(current_delay); let next = current_delay Mul r.multiplier } if (next Gt r.max_delay_ms Add 0.0) { current_delay = r.max_delay_ms Add 0.0 } else { current_delay = next }; if (attempt Eq r.max_retries) { attempt_delay = inherited_delay_ms }; let result2: baml.llm.Stream = self.execute_once_stream(context, attempt_delay) catch (e) { _ => { continue } }; return result2 } }; throw DevOther { message: "All orchestration..." } }, null => { let result: baml.llm.Stream = self.execute_once_stream(context, inherited_delay_ms); return result } } + { } match (self.retry) { r: baml.llm.RetryPolicy => { let current_delay = r.initial_delay_ms Add 0.0; { let attempt = 0; while attempt Le r.max_retries { let attempt_delay = inherited_delay_ms; if (attempt Gt 0) { attempt_delay = root.math.trunc(current_delay); let next = current_delay Mul r.multiplier } if (next Gt r.max_delay_ms Add 0.0) { current_delay = r.max_delay_ms Add 0.0 } else { current_delay = next }; if (attempt Eq r.max_retries) { attempt_delay = inherited_delay_ms }; let result2: baml.llm.Stream = self.execute_once_stream(context, attempt_delay) catch (e) { _ => { continue } }; return result2 } }; throw root.errors.DevOther { message: "All orchestration..." } }, null => { let result: baml.llm.Stream = self.execute_once_stream(context, inherited_delay_ms); return result } } } function baml.llm.final(self: ?) -> baml.llm.T [expr] { - { while Not self._acc.is_done() { let next = match (self._sse.next()) { _: null => { break }, next: string => next }; self._acc.add_events(next) } if (self._acc.is_done()) { self._sse.close(); break }; match (self._acc.finish_reason()) { null => { throw LlmClientError { message: "Streaming finishe..." } }, reason: string => self._client.validate_finish_reason(reason) }; let content = self._acc.content() } __sap_parse_final(content, self._cache) + { while Not self._acc.is_done() { let next = match (self._sse.next()) { _: null => { break }, next: string => next }; self._acc.add_events(next) } if (self._acc.is_done()) { self._sse.close(); break }; match (self._acc.finish_reason()) { null => { throw root.errors.LlmClientError { message: "Streaming finishe..." } }, reason: string => self._client.validate_finish_reason(reason) }; let content = self._acc.content() } __sap_parse_final(content, self._cache) } function baml.llm.finish_reason(self: ?) -> string? [builtin] function baml.llm.from_shorthand(shorthand: string) -> baml.llm.PrimitiveClient [builtin] @@ -305,7 +332,7 @@ function baml.llm.model(self: ?) -> string? [builtin] function baml.llm.new(target: type, streaming: type) -> baml.llm.StreamCache [builtin] function baml.llm.new_stream_accumulator(self: ?) -> baml.llm.StreamAccumulator [builtin] function baml.llm.next(self: ?) -> baml.llm.S | root.stream.StreamFinished [expr] { - { while true { let next = match (self._sse.next()) { _: null => { return StreamFinished { } }, next: string => next }; self._acc.add_events(next); if (self._acc.is_done()) { self._sse.close(); return StreamFinished { } }; let content = self._acc.content(); let parsed: baml.llm.S | root.stream.StreamNoYield = __sap_parse_partial(content, self._cache) } match (parsed) { _: root.stream.StreamNoYield => { continue }, parsed: baml.llm.S => { return parsed } } } root.sys.panic("Unreachable") + { while true { let next = match (self._sse.next()) { _: null => { return root.stream.StreamFinished { } }, next: string => next }; self._acc.add_events(next); if (self._acc.is_done()) { self._sse.close(); return root.stream.StreamFinished { } }; let content = self._acc.content(); let parsed: baml.llm.S | root.stream.StreamNoYield = __sap_parse_partial(content, self._cache) } match (parsed) { _: root.stream.StreamNoYield => { continue }, parsed: baml.llm.S => { return parsed } } } root.sys.panic("Unreachable") } function baml.llm.output_tokens(self: ?) -> int? [builtin] function baml.llm.parse(self: ?, http_response_body: string, type_def: type) -> baml.llm.T [builtin] diff --git a/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____04_5_mir.snap index 4cb8ee01da..1afdbcd0e7 100644 --- a/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____04_5_mir.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 585 --- === MIR2 === @@ -84,6 +83,8 @@ fn baml.fs.File.close = builtin(io) fn baml.fs.exists = builtin(io) +fn baml.fs.mkdir = builtin(io) + fn baml.fs.open = builtin(io) fn baml.fs.read = builtin(io) @@ -92,6 +93,8 @@ fn baml.fs.File.read = builtin(io) fn baml.fs.File.read_bytes = builtin(io) +fn baml.fs.read_dir = builtin(io) + fn baml.fs.remove = builtin(io) fn baml.fs.File.seek_from = builtin(io) @@ -108,6 +111,12 @@ fn baml.fs.File.write_bytes = builtin(io) fn baml.fs.write_bytes = builtin(io) +fn baml.glob.Glob.matches = builtin(io) + +fn baml.glob.new = builtin(io) + +fn baml.glob.Glob.scan = builtin(io) + fn baml.http.Response.bytes = builtin(io) fn baml.http.SseStream.close = builtin(io) @@ -238,7 +247,7 @@ fn baml.llm.call_llm_function(client: baml.llm.Client, function_name: string, ar bb2: { _7 = copy _4; - _6 = ExecutionContext { copy _7, copy _3, copy _2 }; + _6 = baml.llm.ExecutionContext { copy _7, copy _3, copy _2 }; _9 = copy _6; _8 = call const fn baml.llm.Client.execute_oneshot(copy _1, copy _9, const 0_i64) -> [bb3]; } @@ -485,7 +494,7 @@ fn baml.llm.stream_llm_function(client: baml.llm.Client, function_name: string, bb2: { _7 = copy _4; - _6 = ExecutionContext { copy _7, copy _3, copy _2 }; + _6 = baml.llm.ExecutionContext { copy _7, copy _3, copy _2 }; _9 = copy _6; _8 = call const fn baml.llm.Client.execute_stream(copy _1, copy _9, const 0_i64) -> [bb3]; } @@ -563,7 +572,7 @@ fn baml.llm.Client.__make_stream(self: baml.llm.Client, sse: baml.http.SseStream _15 = copy _4; _16 = copy _9; _17 = copy _11; - _0 = Stream { copy _15, copy _16, copy _2, copy _17 }; + _0 = baml.llm.Stream { copy _15, copy _16, copy _2, copy _17 }; goto -> bb10; } @@ -588,7 +597,7 @@ fn baml.llm.Client.build_attempt(self: baml.llm.Client) -> baml.llm.Orchestratio bb0: { _3 = []; - _2 = PlannerState { copy _3 }; + _2 = baml.llm.PlannerState { copy _3 }; _4 = copy _2; _0 = call const fn baml.llm.Client.build_attempt_with_state(copy _1, copy _4) -> [bb1]; } @@ -738,7 +747,7 @@ fn baml.llm.Client.build_attempt_with_state(self: baml.llm.Client, planner_state bb18: { _7 = copy _5; - _6 = OrchestrationStep { copy _7, const 0_i64 }; + _6 = baml.llm.OrchestrationStep { copy _7, const 0_i64 }; _0 = [copy _6]; goto -> bb19; } @@ -758,7 +767,7 @@ fn baml.llm.Client.build_plan(self: baml.llm.Client) -> baml.llm.OrchestrationSt bb0: { _3 = []; - _2 = PlannerState { copy _3 }; + _2 = baml.llm.PlannerState { copy _3 }; _4 = copy _2; _0 = call const fn baml.llm.Client.build_plan_with_state(copy _1, copy _4) -> [bb1]; } @@ -909,7 +918,7 @@ fn baml.llm.Client.build_plan_with_state(self: baml.llm.Client, planner_state: b _31 = copy _30; _34 = copy _31.0; _35 = copy _13; - _33 = OrchestrationStep { copy _34, copy _35 }; + _33 = baml.llm.OrchestrationStep { copy _34, copy _35 }; _32 = call const fn baml.Array.push(copy _6, copy _33) -> [bb17]; } @@ -969,7 +978,7 @@ fn baml.llm.Client.execute_once_oneshot(self: baml.llm.Client, context: baml.llm let _39: void let _40: bool let _41: future - let _42: void + let _42: baml.errors.DevOther let _43: string let _44: string let _45: baml.llm.Client[] @@ -980,11 +989,11 @@ fn baml.llm.Client.execute_once_oneshot(self: baml.llm.Client, context: baml.llm let _50: baml.llm.Client // sub let _51: void // result2 let _52: unknown // e - let _53: void + let _53: baml.errors.DevOther let _54: bool let _55: int let _56: (baml.llm.Client[]) -> int throws never - let _57: void + let _57: baml.errors.DevOther let _58: int // idx let _59: int let _60: int @@ -1035,7 +1044,7 @@ fn baml.llm.Client.execute_once_oneshot(self: baml.llm.Client, context: baml.llm } bb7: { - _57 = DevOther { const "RoundRobin client has no sub-clients" }; + _57 = baml.errors.DevOther { const "RoundRobin client has no sub-clients" }; throw copy _57; } @@ -1192,7 +1201,7 @@ fn baml.llm.Client.execute_once_oneshot(self: baml.llm.Client, context: baml.llm bb41: { _44 = copy _36; _43 = const "HTTP request failed: " + copy _44; - _42 = DevOther { copy _43 }; + _42 = baml.errors.DevOther { copy _43 }; throw copy _42; } @@ -1212,7 +1221,7 @@ fn baml.llm.Client.execute_once_oneshot(self: baml.llm.Client, context: baml.llm } bb45: { - _53 = DevOther { const "All orchestration steps failed" }; + _53 = baml.errors.DevOther { const "All orchestration steps failed" }; throw copy _53; } @@ -1270,11 +1279,11 @@ fn baml.llm.Client.execute_once_stream(self: baml.llm.Client, context: baml.llm. let _32: baml.llm.Client // sub let _33: baml.llm.Stream // result2 let _34: unknown // e - let _35: void + let _35: baml.errors.DevOther let _36: bool let _37: int let _38: (baml.llm.Client[]) -> int throws never - let _39: void + let _39: baml.errors.DevOther let _40: int // idx let _41: int let _42: int @@ -1325,7 +1334,7 @@ fn baml.llm.Client.execute_once_stream(self: baml.llm.Client, context: baml.llm. } bb7: { - _39 = DevOther { const "RoundRobin client has no sub-clients" }; + _39 = baml.errors.DevOther { const "RoundRobin client has no sub-clients" }; throw copy _39; } @@ -1413,7 +1422,7 @@ fn baml.llm.Client.execute_once_stream(self: baml.llm.Client, context: baml.llm. } bb25: { - _35 = DevOther { const "All orchestration steps failed" }; + _35 = baml.errors.DevOther { const "All orchestration steps failed" }; throw copy _35; } @@ -1467,7 +1476,7 @@ fn baml.llm.Client.execute_oneshot(self: baml.llm.Client, context: baml.llm.Exec let _28: void // result2 let _29: unknown // e let _30: int - let _31: void + let _31: baml.errors.DevOther let _32: bool let _33: void // result @@ -1516,7 +1525,7 @@ fn baml.llm.Client.execute_oneshot(self: baml.llm.Client, context: baml.llm.Exec } bb8: { - _31 = DevOther { const "All orchestration steps failed" }; + _31 = baml.errors.DevOther { const "All orchestration steps failed" }; throw copy _31; } @@ -1614,7 +1623,7 @@ fn baml.llm.Client.execute_stream(self: baml.llm.Client, context: baml.llm.Execu let _28: baml.llm.Stream // result2 let _29: unknown // e let _30: int - let _31: void + let _31: baml.errors.DevOther let _32: bool let _33: baml.llm.Stream // result @@ -1663,7 +1672,7 @@ fn baml.llm.Client.execute_stream(self: baml.llm.Client, context: baml.llm.Execu } bb8: { - _31 = DevOther { const "All orchestration steps failed" }; + _31 = baml.errors.DevOther { const "All orchestration steps failed" }; throw copy _31; } @@ -1900,7 +1909,7 @@ fn baml.llm.Stream.final(self: baml.llm.Stream) -> void { } bb27: { - _28 = LlmClientError { const "Streaming finished without finish_reason" }; + _28 = root.errors.LlmClientError { const "Streaming finished without finish_reason" }; throw copy _28; } } @@ -2064,12 +2073,12 @@ fn baml.llm.Stream.next(self: baml.llm.Stream) -> void | baml.stream.StreamFinis } bb22: { - _0 = StreamFinished { }; + _0 = baml.stream.StreamFinished { }; goto -> bb24; } bb23: { - _0 = StreamFinished { }; + _0 = baml.stream.StreamFinished { }; goto -> bb24; } diff --git a/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____04_tir.snap b/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____04_tir.snap index f2d577a582..b11d898748 100644 --- a/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____04_tir.snap @@ -112,9 +112,51 @@ class baml.errors.StackTrace$stream { class baml.fs.File { _handle: $rust_type } +class baml.fs.DirEntry { + name: string + is_dir: bool + is_file: bool + is_symlink: bool +} +class baml.fs.MkdirOptions { + recursive: bool +} class baml.fs.File$stream { _handle: $rust_type } +class baml.fs.DirEntry$stream { + name: null | string + is_dir: null | bool + is_file: null | bool + is_symlink: null | bool +} +class baml.fs.MkdirOptions$stream { + recursive: null | bool +} + +--- /baml/ns_glob/glob.baml --- +class baml.glob.ScanOptions { + cwd: string? + dot: bool? + absolute: bool? + follow_symlinks: bool? + throw_error_on_broken_symlink: bool? + only_files: bool? +} +class baml.glob.Glob { + _handle: $rust_type +} +class baml.glob.ScanOptions$stream { + cwd: null | string + dot: null | bool + absolute: null | bool + follow_symlinks: null | bool + throw_error_on_broken_symlink: null | bool + only_files: null | bool +} +class baml.glob.Glob$stream { + _handle: $rust_type +} --- /baml/ns_http/http.baml --- class baml.http.Request { @@ -402,7 +444,7 @@ function baml.llm.Client.execute_stream(self: baml.llm.Client, context: ba return result2 : baml.llm.Stream } } - throw DevOther { message: "All orchestration..." } : unknown + throw root.errors.DevOther { message: "All orchestration..." } : baml.errors.DevOther } null => { : never @@ -438,13 +480,13 @@ function baml.llm.Client.execute_once_stream(self: baml.llm.Client, contex } return result2 : baml.llm.Stream } - throw DevOther { message: "All orchestration..." } : unknown + throw root.errors.DevOther { message: "All orchestration..." } : baml.errors.DevOther } ClientType.RoundRobin => { : never if (self.sub_clients.length() == 0 : bool) : void { : never - throw DevOther { message: "RoundRobin client..." } : unknown + throw root.errors.DevOther { message: "RoundRobin client..." } : baml.errors.DevOther } let idx = self.counter % self.sub_clients.length() : int self.counter Add= 1 : int @@ -501,7 +543,7 @@ function baml.llm.Client.execute_oneshot(self: baml.llm.Client, context: baml return result2 : T } } - throw DevOther { message: "All orchestration..." } : unknown + throw root.errors.DevOther { message: "All orchestration..." } : baml.errors.DevOther } null => { : never @@ -550,7 +592,7 @@ function baml.llm.Client.execute_once_oneshot(self: baml.llm.Client, context: { : null root.sys.sleep(active_delay_ms) : null } - throw DevOther { message: "HTTP request fail..." + error_body } : unknown + throw root.errors.DevOther { message: "HTTP request fail..." + error_body } : baml.errors.DevOther } } ClientType.Fallback => @@ -566,13 +608,13 @@ function baml.llm.Client.execute_once_oneshot(self: baml.llm.Client, context: } return result2 : T } - throw DevOther { message: "All orchestration..." } : unknown + throw root.errors.DevOther { message: "All orchestration..." } : baml.errors.DevOther } ClientType.RoundRobin => { : never if (self.sub_clients.length() == 0 : bool) : void { : never - throw DevOther { message: "RoundRobin client..." } : unknown + throw root.errors.DevOther { message: "RoundRobin client..." } : baml.errors.DevOther } let idx = self.counter % self.sub_clients.length() : int self.counter Add= 1 : int @@ -651,7 +693,7 @@ function baml.llm.Stream.next(self: baml.llm.Stream) -> unknown | baml.stream.St match (self._sse.next() : string?) : string _: null => { : never - return StreamFinished { } : unknown + return root.stream.StreamFinished { } : baml.stream.StreamFinished } next: string => next : string @@ -659,7 +701,7 @@ function baml.llm.Stream.next(self: baml.llm.Stream) -> unknown | baml.stream.St if (self._acc.is_done() : bool) : void { : never self._sse.close() : null - return StreamFinished { } : unknown + return root.stream.StreamFinished { } : baml.stream.StreamFinished } let content = self._acc.content() : string let parsed = __sap_parse_partial(content, self._cache) : S | baml.stream.StreamNoYield @@ -698,7 +740,7 @@ function baml.llm.Stream.final(self: baml.llm.Stream) -> unknown throws never { match (self._acc.finish_reason() : string?) : null null => { : never - throw LlmClientError { message: "Streaming finishe..." } : unknown + throw root.errors.LlmClientError { message: "Streaming finishe..." } : unknown } reason: string => self._client.validate_finish_reason(reason) : null diff --git a/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____06_codegen.snap b/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____06_codegen.snap index a3055c8745..0f32c1d621 100644 --- a/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/__baml_std__/baml_tests____baml_std____06_codegen.snap @@ -194,12 +194,18 @@ function baml.fs.File.write_bytes(self: null, data: uint8array) -> int { function baml.fs.exists(path: string) -> bool { } +function baml.fs.mkdir(path: string, options: baml.fs.MkdirOptions) -> null { +} + function baml.fs.open(path: string, mode: "r" | "r+" | "w" | "w+" | "a" | "a+") -> baml.fs.File { } function baml.fs.read(path: string) -> string { } +function baml.fs.read_dir(path: string) -> baml.fs.DirEntry[] { +} + function baml.fs.remove(path: string) -> null { } @@ -212,6 +218,15 @@ function baml.fs.write(path: string, content: string) -> int { function baml.fs.write_bytes(path: string, content: uint8array) -> int { } +function baml.glob.Glob.matches(self: null, path: string) -> bool { +} + +function baml.glob.Glob.scan(self: null, root: string | baml.glob.ScanOptions) -> string[] { +} + +function baml.glob.new(pattern: string) -> baml.glob.Glob { +} + function baml.http.Response.bytes(self: null) -> uint8array { } @@ -274,7 +289,7 @@ function baml.llm.Client.__make_stream(self: null, sse: baml.http.SseStream, fun dispatch_future baml.llm.StreamCache.new await store_var cache - alloc_instance Stream + alloc_instance baml.llm.Stream load_var primitive init_field ._client load_var acc @@ -288,7 +303,7 @@ function baml.llm.Client.__make_stream(self: null, sse: baml.http.SseStream, fun function baml.llm.Client.build_attempt(self: null) -> baml.llm.OrchestrationStep[] { load_var self - alloc_instance PlannerState + alloc_instance baml.llm.PlannerState alloc_array 0 init_field .rr_client_names call baml.llm.Client.build_attempt_with_state @@ -414,7 +429,7 @@ function baml.llm.Client.build_attempt_with_state(self: null, planner_state: bam load_var self call baml.llm.Client.to_primitive_client store_var primitive - alloc_instance OrchestrationStep + alloc_instance baml.llm.OrchestrationStep load_var primitive init_field .primitive_client load_const 0 @@ -427,7 +442,7 @@ function baml.llm.Client.build_attempt_with_state(self: null, planner_state: bam function baml.llm.Client.build_plan(self: null) -> baml.llm.OrchestrationStep[] { load_var self - alloc_instance PlannerState + alloc_instance baml.llm.PlannerState alloc_array 0 init_field .rr_client_names call baml.llm.Client.build_plan_with_state @@ -541,7 +556,7 @@ function baml.llm.Client.build_plan_with_state(self: null, planner_state: baml.l L11: load_var result - alloc_instance OrchestrationStep + alloc_instance baml.llm.OrchestrationStep load_var _26 load_var __for_idx load_array_element @@ -611,7 +626,7 @@ function baml.llm.Client.execute_once_oneshot(self: null, context: baml.llm.Exec jump L15 L3: - alloc_instance DevOther + alloc_instance baml.errors.DevOther load_const "RoundRobin client has no sub-clients" init_field .message throw @@ -632,7 +647,7 @@ function baml.llm.Client.execute_once_oneshot(self: null, context: baml.llm.Exec jump L7 L6: - alloc_instance DevOther + alloc_instance baml.errors.DevOther load_const "All orchestration steps failed" init_field .message throw @@ -713,7 +728,7 @@ function baml.llm.Client.execute_once_oneshot(self: null, context: baml.llm.Exec pop 1 L12: - alloc_instance DevOther + alloc_instance baml.errors.DevOther load_const "HTTP request failed: " load_var error_body bin_op + @@ -803,7 +818,7 @@ function baml.llm.Client.execute_once_stream(self: null, context: baml.llm.Execu jump L10 L3: - alloc_instance DevOther + alloc_instance baml.errors.DevOther load_const "RoundRobin client has no sub-clients" init_field .message throw @@ -824,7 +839,7 @@ function baml.llm.Client.execute_once_stream(self: null, context: baml.llm.Execu jump L7 L6: - alloc_instance DevOther + alloc_instance baml.errors.DevOther load_const "All orchestration steps failed" init_field .message throw @@ -928,7 +943,7 @@ function baml.llm.Client.execute_oneshot(self: null, context: baml.llm.Execution jump L4 L3: - alloc_instance DevOther + alloc_instance baml.errors.DevOther load_const "All orchestration steps failed" init_field .message throw @@ -1036,7 +1051,7 @@ function baml.llm.Client.execute_stream(self: null, context: baml.llm.ExecutionC jump L4 L3: - alloc_instance DevOther + alloc_instance baml.errors.DevOther load_const "All orchestration steps failed" init_field .message throw @@ -1290,7 +1305,7 @@ function baml.llm.Stream.final(self: null) -> void { return L6: - load_const null /* unknown class: LlmClientError */ + load_const null /* unknown class: root.errors.LlmClientError */ load_const "Streaming finished without finish_reason" init_field .0 throw @@ -1368,11 +1383,11 @@ function baml.llm.Stream.next(self: null) -> void | baml.stream.StreamFinished { dispatch_future baml.http.SseStream.close await pop 1 - alloc_instance StreamFinished + alloc_instance baml.stream.StreamFinished jump L9 L8: - alloc_instance StreamFinished + alloc_instance baml.stream.StreamFinished L9: return @@ -1446,7 +1461,7 @@ function baml.llm.call_llm_function(client: baml.llm.Client, function_name: stri await store_var jinja_string load_var client - alloc_instance ExecutionContext + alloc_instance baml.llm.ExecutionContext load_var jinja_string init_field .jinja_string load_var args @@ -1524,7 +1539,7 @@ function baml.llm.stream_llm_function(client: baml.llm.Client, function_name: st await store_var jinja_string load_var client - alloc_instance ExecutionContext + alloc_instance baml.llm.ExecutionContext load_var jinja_string init_field .jinja_string load_var args diff --git a/baml_language/crates/baml_tests/snapshots/__testing_std__/baml_tests____testing_std____04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/__testing_std__/baml_tests____testing_std____04_5_mir.snap index 42a4d312a2..38139d6540 100644 --- a/baml_language/crates/baml_tests/snapshots/__testing_std__/baml_tests____testing_std____04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/__testing_std__/baml_tests____testing_std____04_5_mir.snap @@ -143,7 +143,7 @@ fn testing.TestRegistry.expand_set(self: testing.TestRegistry, name: string) -> bb13: { _13 = []; _14 = []; - _12 = TestCollector { copy _2, copy _13, copy _14 }; + _12 = testing.TestCollector { copy _2, copy _13, copy _14 }; _16 = copy _8.1; _17 = copy _12; _15 = call copy _16(copy _17) -> [bb14]; @@ -159,7 +159,7 @@ fn testing.TestRegistry.expand_set(self: testing.TestRegistry, name: string) -> _22 = copy _12; _23 = { }; _24 = copy _18; - _21 = TestRegistry { copy _22, copy _23, copy _24 }; + _21 = testing.TestRegistry { copy _22, copy _23, copy _24 }; _26 = copy _1.1; _27 = copy _21; _25 = call const fn baml.Map.set(copy _26, copy _2, copy _27) -> [bb16]; @@ -238,7 +238,7 @@ fn testing.TestRegistry.new(collector: testing.TestCollector) -> testing.TestReg bb0: { _2 = { }; - _0 = TestRegistry { copy _1, copy _2, const 0_i64 }; + _0 = testing.TestRegistry { copy _1, copy _2, const 0_i64 }; goto -> bb1; } @@ -257,7 +257,7 @@ fn testing.TestCollector.new(prefix: string) -> testing.TestCollector { bb0: { _2 = []; _3 = []; - _0 = TestCollector { copy _1, copy _2, copy _3 }; + _0 = testing.TestCollector { copy _1, copy _2, copy _3 }; goto -> bb1; } @@ -366,7 +366,7 @@ fn testing.TestCollector.register_test(self: testing.TestCollector, name: string bb9: { _34 = copy _1.1; _36 = copy _25; - _35 = TestRegistration { copy _36, copy _3, copy _4 }; + _35 = testing.TestRegistration { copy _36, copy _3, copy _4 }; _33 = call const fn baml.Array.push(copy _34, copy _35) -> [bb10]; } @@ -510,7 +510,7 @@ fn testing.TestCollector.register_test_set(self: testing.TestCollector, name: st bb9: { _34 = copy _1.2; _36 = copy _25; - _35 = TestSetRegistration { copy _36, copy _3, copy _4 }; + _35 = testing.TestSetRegistration { copy _36, copy _3, copy _4 }; _33 = call const fn baml.Array.push(copy _34, copy _35) -> [bb10]; } @@ -629,7 +629,7 @@ fn .() -> null { } bb2: { - _2 = RunReport { const "pass", const 0_i64 }; + _2 = testing.RunReport { const "pass", const 0_i64 }; goto -> bb5; } @@ -638,7 +638,7 @@ fn .() -> null { } bb4: { - _2 = RunReport { const "fail", const 0_i64 }; + _2 = testing.RunReport { const "fail", const 0_i64 }; goto -> bb5; } @@ -651,9 +651,9 @@ fn .() -> null { bb6: { _12 = copy _1; _10 = copy _11 - copy _12; - _8 = RunReport { copy _9, copy _10 }; + _8 = testing.RunReport { copy _9, copy _10 }; _7 = [copy _8]; - _0 = TestReport { copy _6, copy _7 }; + _0 = testing.TestReport { copy _6, copy _7 }; goto -> bb7; } @@ -906,7 +906,7 @@ fn testing.TestRegistry.serialize(self: testing.TestRegistry) -> (testing.Serial bb9: { _30 = copy _17.0; - _29 = SerializedTest { const "lazyTestSet", copy _30 }; + _29 = testing.SerializedTest { const "lazyTestSet", copy _30 }; _18 = call const fn baml.Array.push(copy _2, copy _29) -> [bb12]; } @@ -918,7 +918,7 @@ fn testing.TestRegistry.serialize(self: testing.TestRegistry) -> (testing.Serial bb11: { _27 = copy _23.2; - _24 = SerializedTestSet { copy _25, copy _26, copy _27 }; + _24 = testing.SerializedTestSet { copy _25, copy _26, copy _27 }; _18 = call const fn baml.Array.push(copy _2, copy _24) -> [bb12]; } @@ -932,7 +932,7 @@ fn testing.TestRegistry.serialize(self: testing.TestRegistry) -> (testing.Serial fresh_cell(_8); _8 = copy _7; _11 = copy _8.0; - _10 = SerializedTest { const "test", copy _11 }; + _10 = testing.SerializedTest { const "test", copy _11 }; _9 = call const fn baml.Array.push(copy _2, copy _10) -> [bb14]; } diff --git a/baml_language/crates/baml_tests/snapshots/__testing_std__/baml_tests____testing_std____06_codegen.snap b/baml_language/crates/baml_tests/snapshots/__testing_std__/baml_tests____testing_std____06_codegen.snap index 819e335c48..e09d2d66e8 100644 --- a/baml_language/crates/baml_tests/snapshots/__testing_std__/baml_tests____testing_std____06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/__testing_std__/baml_tests____testing_std____06_codegen.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 1061 --- function testing.$invoke_collector(collector: (testing.TestCollector) -> void throws unknown, c: testing.TestCollector) -> void { load_var c @@ -55,7 +54,7 @@ function testing.TestCollector.find_testset(self: null, name: string) -> testing } function testing.TestCollector.new(prefix: string) -> testing.TestCollector { - alloc_instance TestCollector + alloc_instance testing.TestCollector load_var prefix init_field .prefix alloc_array 0 @@ -138,7 +137,7 @@ function testing.TestCollector.register_test(self: null, name: string, body: () L7: load_var self load_field .tests - alloc_instance TestRegistration + alloc_instance testing.TestRegistration load_var final_name init_field .name load_var body @@ -257,7 +256,7 @@ function testing.TestCollector.register_test_set(self: null, name: string, colle L7: load_var self load_field .testsets - alloc_instance TestSetRegistration + alloc_instance testing.TestSetRegistration load_var final_name init_field .name load_var collector @@ -394,7 +393,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S L9: call baml.sys.now_ms store_var start - alloc_instance TestCollector + alloc_instance testing.TestCollector load_var name init_field .prefix alloc_array 0 @@ -412,7 +411,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S load_var self load_field .expansions load_var name - alloc_instance TestRegistry + alloc_instance testing.TestRegistry load_var sub_collector init_field .collector alloc_map 0 @@ -431,7 +430,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S } function testing.TestRegistry.new(collector: testing.TestCollector) -> testing.TestRegistry { - alloc_instance TestRegistry + alloc_instance testing.TestRegistry load_var collector init_field .collector alloc_map 0 @@ -600,7 +599,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | cmp_op == pop_jump_if_false L7 load_var items - alloc_instance SerializedTest + alloc_instance testing.SerializedTest load_const "lazyTestSet" init_field .type load_var ts @@ -620,7 +619,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | call testing.TestRegistry.serialize store_var _26 load_var items - alloc_instance SerializedTestSet + alloc_instance testing.SerializedTestSet load_var _25 init_field .name load_var _26 @@ -640,7 +639,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | L8: load_var items - alloc_instance SerializedTest + alloc_instance testing.SerializedTest load_const "test" init_field .type load_var _3 diff --git a/baml_language/crates/baml_tests/snapshots/attr_disambiguation/baml_tests__attr_disambiguation__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/attr_disambiguation/baml_tests__attr_disambiguation__06_codegen.snap index 1ac40e2290..6c022786f8 100644 --- a/baml_language/crates/baml_tests/snapshots/attr_disambiguation/baml_tests__attr_disambiguation__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/attr_disambiguation/baml_tests__attr_disambiguation__06_codegen.snap @@ -12,14 +12,14 @@ function user.E6(x: EFoo) -> string { } function user.E7() -> EFoo { - alloc_instance EFoo + alloc_instance user.EFoo load_const 1 init_field .x return } function user.E8() -> EFoo { - alloc_instance EFoo + alloc_instance user.EFoo load_const 1 init_field .x return diff --git a/baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__04_tir.snap b/baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__04_tir.snap index de554c2cbd..c4794aa1c1 100644 --- a/baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__04_tir.snap @@ -102,7 +102,7 @@ function user.GetUser$stream(id: int) -> baml.llm.Stream } function user.GetUser$parse_stream(sse: baml.http.SseStream) -> baml.llm.Stream throws never { - baml.llm.Client { name: "openai/gpt-4o", client_type: baml.llm.ClientType.Primitive, sub_clients: [], retry: null, counter: 0 }.__make_stream(sse, "GetUser") : unknown + baml.llm.Client { name: "openai/gpt-4o", client_type: baml.llm.ClientType.Primitive, sub_clients: [], retry: null, counter: 0 }.__make_stream(sse, "GetUser") : baml.llm.Stream } function user.GetStatus$stream() -> baml.llm.Stream throws never { baml.llm.stream_llm_function(GPT4, "GetStatus", map { }) : baml.llm.Stream diff --git a/baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__06_codegen.snap index b601c57b69..b9cd486a93 100644 --- a/baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/basic_types/baml_tests__basic_types__06_codegen.snap @@ -237,10 +237,21 @@ function user.GetUser$parse(json: string) -> User { } function user.GetUser$parse_stream(sse: baml.http.SseStream) -> baml.llm.Stream { + alloc_instance baml.llm.Client + load_const "openai/gpt-4o" + init_field .name + load_const baml.llm.ClientType.Primitive + alloc_variant baml.llm.ClientType + init_field .client_type + alloc_array 0 + init_field .sub_clients + load_const null + init_field .retry + load_const 0 + init_field .counter load_var sse load_const "GetUser" - load_const null - call_indirect + call baml.llm.Client.__make_stream return } diff --git a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__01_lexer__fs_ops.snap b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__01_lexer__fs_ops.snap index ea2646ba7d..dfc0727e8c 100644 --- a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__01_lexer__fs_ops.snap +++ b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__01_lexer__fs_ops.snap @@ -717,3 +717,29 @@ Word "bin" Quote "\"" RParen ")" RBrace "}" +Function "function" +Word "ReadDir" +LParen "(" +RParen ")" +Arrow "->" +Word "baml" +Dot "." +Word "fs" +Dot "." +Word "DirEntry" +LBracket "[" +RBracket "]" +LBrace "{" +Word "baml" +Dot "." +Word "fs" +Dot "." +Word "read_dir" +LParen "(" +Quote "\"" +Word "some" +Slash "/" +Word "path" +Quote "\"" +RParen ")" +RBrace "}" diff --git a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__02_parser__fs_ops.snap b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__02_parser__fs_ops.snap index 3e26c3c886..298a557923 100644 --- a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__02_parser__fs_ops.snap +++ b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__02_parser__fs_ops.snap @@ -1002,6 +1002,41 @@ SOURCE_FILE QUOTE """ R_PAREN ")" R_BRACE "}" + FUNCTION_DEF + KW_FUNCTION "function" + WORD "ReadDir" + PARAMETER_LIST "()" + L_PAREN "(" + R_PAREN ")" + ARROW "->" + TYPE_EXPR "baml.fs.DirEntry[]" + WORD "baml" + DOT "." + WORD "fs" + DOT "." + WORD "DirEntry" + L_BRACKET "[" + R_BRACKET "]" + EXPR_FUNCTION_BODY + BLOCK_EXPR + L_BRACE "{" + CALL_EXPR + PATH_EXPR "baml.fs.read_dir" + WORD "baml" + DOT "." + WORD "fs" + DOT "." + WORD "read_dir" + CALL_ARGS + L_PAREN "(" + STRING_LITERAL "some/path" + QUOTE """ + WORD "some" + SLASH "/" + WORD "path" + QUOTE """ + R_PAREN ")" + R_BRACE "}" === ERRORS === None diff --git a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__03_hir.snap b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__03_hir.snap index 8397af8053..8f119c4c8e 100644 --- a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__03_hir.snap @@ -26,6 +26,9 @@ function user.ReadChunk() -> string [expr] { function user.ReadChunkBytes() -> uint8array [expr] { { let f = baml.fs.open("data.bin", "r") } f.read_bytes(4096) } +function user.ReadDir() -> baml.fs.DirEntry[] [expr] { + { } baml.fs.read_dir("some/path") +} function user.ReadFile() -> string [expr] { { let f = baml.fs.open("example.txt", "r") } f.text() } diff --git a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__04_5_mir.snap index 5df9c66477..fd6aa98780 100644 --- a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__04_5_mir.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 4063 --- === MIR2 === fn user.Append() -> int { @@ -275,6 +274,24 @@ fn user.ReadChunkBytes() -> uint8array { } } +fn user.ReadDir() -> baml.fs.DirEntry[] { + // Locals: + let _0: baml.fs.DirEntry[] // _0 // return + let _1: future + + bb0: { + _1 = dispatch_future const fn baml.fs.read_dir(const "some/path") -> bb1; + } + + bb1: { + _0 = await _1 -> [bb2]; + } + + bb2: { + return; + } +} + fn user.ReadFile() -> string { // Locals: let _0: string // _0 // return diff --git a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__04_tir.snap b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__04_tir.snap index 49453a3240..53d58e77a6 100644 --- a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__04_tir.snap @@ -122,6 +122,11 @@ function user.Size() -> int throws never { baml.fs.size("data.bin") : int } } +function user.ReadDir() -> baml.fs.DirEntry[] throws never { + { : baml.fs.DirEntry[] + baml.fs.read_dir("some/path") : baml.fs.DirEntry[] + } +} function user.AskName() -> string throws never { { : string baml.io.input("What is your name? ") : string diff --git a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__06_codegen.snap index bd8673d8fe..4c7bdeb1a7 100644 --- a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__06_codegen.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 4217 --- function user.Append() -> int { load_const "log.txt" @@ -206,6 +205,13 @@ function user.ReadChunkBytes() -> uint8array { return } +function user.ReadDir() -> baml.fs.DirEntry[] { + load_const "some/path" + dispatch_future baml.fs.read_dir + await + return +} + function user.ReadFile() -> string { load_const "example.txt" load_const "r" diff --git a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__10_formatter__fs_ops.snap b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__10_formatter__fs_ops.snap index ddf568b03d..10202b083d 100644 --- a/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__10_formatter__fs_ops.snap +++ b/baml_language/crates/baml_tests/snapshots/builtin_io/baml_tests__builtin_io__10_formatter__fs_ops.snap @@ -103,3 +103,7 @@ function Remove() -> null { function Size() -> int { baml.fs.size("data.bin") } + +function ReadDir() -> baml.fs.DirEntry[] { + baml.fs.read_dir("some/path") +} diff --git a/baml_language/crates/baml_tests/snapshots/client_option_types/baml_tests__client_option_types__04_tir.snap b/baml_language/crates/baml_tests/snapshots/client_option_types/baml_tests__client_option_types__04_tir.snap index 1c9a6bc2ac..6515fe2f34 100644 --- a/baml_language/crates/baml_tests/snapshots/client_option_types/baml_tests__client_option_types__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/client_option_types/baml_tests__client_option_types__04_tir.snap @@ -3,20 +3,20 @@ source: crates/baml_tests/src/generated_tests.rs --- === TIR2 === function user.ValidOpenAI$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "ValidOpenAI", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: "https://api.opena...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100, "temperature": 0.7 } } } : unknown + baml.llm.PrimitiveClient { name: "ValidOpenAI", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: "https://api.opena...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100, "temperature": 0.7 } } } : baml.llm.PrimitiveClient } function user.BadMaxTokens$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "BadMaxTokens", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": "notanumber" } } } : unknown + baml.llm.PrimitiveClient { name: "BadMaxTokens", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": "notanumber" } } } : baml.llm.PrimitiveClient } function user.BadTemperature$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "BadTemperature", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "temperature": "warm" } } } : unknown + baml.llm.PrimitiveClient { name: "BadTemperature", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "temperature": "warm" } } } : baml.llm.PrimitiveClient } function user.ValidAzure$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "ValidAzure", provider: "azure-openai", options: baml.llm.PrimitiveClientOptions { model: null, base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: baml.llm.AzureOpenAiOptions { resource_name: "my-resource", deployment_id: "gpt-4o", api_version: "2024-02-15-preview", max_tokens: null }, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "ValidAzure", provider: "azure-openai", options: baml.llm.PrimitiveClientOptions { model: null, base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: baml.llm.AzureOpenAiOptions { resource_name: "my-resource", deployment_id: "gpt-4o", api_version: "2024-02-15-preview", max_tokens: null }, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.ValidAzureBaseUrl$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "ValidAzureBaseUrl", provider: "azure-openai", options: baml.llm.PrimitiveClientOptions { model: null, base_url: "https://my-resour...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: baml.llm.AzureOpenAiOptions { resource_name: null, deployment_id: null, api_version: "2024-02-15-preview", max_tokens: null }, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "ValidAzureBaseUrl", provider: "azure-openai", options: baml.llm.PrimitiveClientOptions { model: null, base_url: "https://my-resour...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: baml.llm.AzureOpenAiOptions { resource_name: null, deployment_id: null, api_version: "2024-02-15-preview", max_tokens: null }, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.BadAzureMissingUrl$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "BadAzureMissingUrl", provider: "azure-openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4o", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: baml.llm.AzureOpenAiOptions { resource_name: null, deployment_id: null, api_version: "2024-02-15-preview", max_tokens: null }, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "BadAzureMissingUrl", provider: "azure-openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4o", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: baml.llm.AzureOpenAiOptions { resource_name: null, deployment_id: null, api_version: "2024-02-15-preview", max_tokens: null }, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } diff --git a/baml_language/crates/baml_tests/snapshots/closure_errors/baml_tests__closure_errors__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/closure_errors/baml_tests__closure_errors__06_codegen.snap index 6c4f3661cd..4e458b3a6e 100644 --- a/baml_language/crates/baml_tests/snapshots/closure_errors/baml_tests__closure_errors__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/closure_errors/baml_tests__closure_errors__06_codegen.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 6990 --- function user.Counter.increment(self: null) -> int { load_var self @@ -34,7 +33,7 @@ function user.Formatter.format(self: null, text: string) -> string { } function user.takes_unbound(f: (Employee) -> string throws never) -> string { - alloc_instance Employee + alloc_instance user.Employee load_const "X" init_field .first load_const "Y" @@ -45,7 +44,7 @@ function user.takes_unbound(f: (Employee) -> string throws never) -> string { } function user.test_err_bound_for_unbound() -> string { - alloc_instance Employee + alloc_instance user.Employee load_const "Alice" init_field .first load_const "Smith" @@ -56,7 +55,7 @@ function user.test_err_bound_for_unbound() -> string { } function user.test_err_bound_type_mismatch() -> int { - alloc_instance Counter + alloc_instance user.Counter load_const 0 init_field .value store_var c @@ -65,7 +64,7 @@ function user.test_err_bound_type_mismatch() -> int { } function user.test_err_extra_arg() -> string { - alloc_instance Formatter + alloc_instance user.Formatter load_const ">> " init_field .prefix store_var fmt diff --git a/baml_language/crates/baml_tests/snapshots/closures/baml_tests__closures__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/closures/baml_tests__closures__04_5_mir.snap index f399887eb8..9b30cf3753 100644 --- a/baml_language/crates/baml_tests/snapshots/closures/baml_tests__closures__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/closures/baml_tests__closures__04_5_mir.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 7532 --- === MIR2 === fn user.apply(f: (int, int) -> int throws never, a: int, b: int) -> int { @@ -197,7 +196,7 @@ fn user.test_bound_in_lambda() -> string { let _5: (string) -> string throws never bb0: { - _1 = Employee { const "Alice", const "Smith" }; + _1 = user.Employee { const "Alice", const "Smith" }; _2 = make_closure lambda[0](copy _1); _4 = copy _2; _3 = call copy _4() -> [bb1]; @@ -237,7 +236,7 @@ fn user.test_bound_mapper() -> string[] { let _4: (string) -> string throws never bb0: { - _1 = Formatter { const ">> " }; + _1 = user.Formatter { const ">> " }; _2 = make_bound_method user.Formatter.format(copy _1); _3 = [const "hello", const "world"]; _4 = copy _2; @@ -258,7 +257,7 @@ fn user.test_bound_validator() -> bool[] { let _4: (int) -> bool throws never bb0: { - _1 = RangeCheck { const 10_i64, const 50_i64 }; + _1 = user.RangeCheck { const 10_i64, const 50_i64 }; _2 = make_bound_method user.RangeCheck.is_valid(copy _1); _3 = [const 5_i64, const 15_i64, const 25_i64, const 75_i64]; _4 = copy _2; @@ -298,7 +297,7 @@ fn user.test_generic_bind() -> int { let _3: () -> void throws never bb0: { - _1 = Box { const 42_i64 }; + _1 = user.Box { const 42_i64 }; _2 = make_bound_method user.Box.unwrap(copy _1); _3 = copy _2; _0 = call copy _3() -> [bb1]; @@ -317,7 +316,7 @@ fn user.test_mutation_after_bind() -> int { let _3: () -> int throws never bb0: { - _1 = Counter { const 0_i64 }; + _1 = user.Counter { const 0_i64 }; _2 = make_bound_method user.Counter.increment(copy _1); _1.0 = const 100_i64; _3 = copy _2; @@ -341,7 +340,7 @@ fn user.test_repeated_bound_calls() -> int { let _7: () -> int throws never bb0: { - _1 = Counter { const 0_i64 }; + _1 = user.Counter { const 0_i64 }; _2 = make_bound_method user.Counter.increment(copy _1); _4 = copy _2; _3 = call copy _4() -> [bb1]; @@ -375,8 +374,8 @@ fn user.test_strategy() -> int[] { let _8: (int, int) -> int throws never bb0: { - _1 = Calculator { const "add" }; - _2 = Calculator { const "mul" }; + _1 = user.Calculator { const "add" }; + _2 = user.Calculator { const "mul" }; _3 = make_bound_method user.Calculator.compute(copy _1); _4 = make_bound_method user.Calculator.compute(copy _2); _6 = copy _3; @@ -406,7 +405,7 @@ fn user.test_unbound_higher_order() -> string[] { let _3: Employee[] bb0: { - _2 = Employee { const "Alice", const "Smith" }; + _2 = user.Employee { const "Alice", const "Smith" }; _1 = [copy _2]; _3 = copy _1; _0 = call const fn user.apply_to_each(copy _3, const fn user.Employee.full_name) -> [bb1]; @@ -425,8 +424,8 @@ fn user.test_unbound_in_map() -> string[] { let _3: Employee bb0: { - _2 = Employee { const "Alice", const "Smith" }; - _3 = Employee { const "Bob", const "Jones" }; + _2 = user.Employee { const "Alice", const "Smith" }; + _3 = user.Employee { const "Bob", const "Jones" }; _1 = [copy _2, copy _3]; _0 = call const fn baml.Array.map(copy _1, const fn user.Employee.full_name) -> [bb1]; } diff --git a/baml_language/crates/baml_tests/snapshots/closures/baml_tests__closures__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/closures/baml_tests__closures__06_codegen.snap index d4c91e2b4f..9d1708f0bd 100644 --- a/baml_language/crates/baml_tests/snapshots/closures/baml_tests__closures__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/closures/baml_tests__closures__06_codegen.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 7641 --- function user.Box.unwrap(self: null) -> void { load_var self @@ -119,7 +118,7 @@ function user.test_bound_in_lambda() -> string { load_var ?1 make_cell store_var ?1 - alloc_instance Employee + alloc_instance user.Employee load_const "Alice" init_field .first load_const "Smith" @@ -139,7 +138,7 @@ function user.test_bound_mapper() -> string[] { load_const "hello" load_const "world" alloc_array 2 - alloc_instance Formatter + alloc_instance user.Formatter load_const ">> " init_field .prefix make_bound_method user.Formatter.format @@ -153,7 +152,7 @@ function user.test_bound_validator() -> bool[] { load_const 25 load_const 75 alloc_array 4 - alloc_instance RangeCheck + alloc_instance user.RangeCheck load_const 10 init_field .min load_const 50 @@ -173,7 +172,7 @@ function user.test_field_chain_bind(cfg: Config) -> string { } function user.test_generic_bind() -> int { - alloc_instance Box + alloc_instance user.Box load_const 42 init_field .value make_bound_method user.Box.unwrap @@ -182,7 +181,7 @@ function user.test_generic_bind() -> int { } function user.test_mutation_after_bind() -> int { - alloc_instance Counter + alloc_instance user.Counter load_const 0 init_field .value store_var c @@ -198,7 +197,7 @@ function user.test_mutation_after_bind() -> int { } function user.test_repeated_bound_calls() -> int { - alloc_instance Counter + alloc_instance user.Counter load_const 0 init_field .value make_bound_method user.Counter.increment @@ -215,7 +214,7 @@ function user.test_repeated_bound_calls() -> int { } function user.test_strategy() -> int[] { - alloc_instance Calculator + alloc_instance user.Calculator load_const "add" init_field .op make_bound_method user.Calculator.compute @@ -223,7 +222,7 @@ function user.test_strategy() -> int[] { load_const 4 call user.apply store_var _5 - alloc_instance Calculator + alloc_instance user.Calculator load_const "mul" init_field .op make_bound_method user.Calculator.compute @@ -238,7 +237,7 @@ function user.test_strategy() -> int[] { } function user.test_unbound_higher_order() -> string[] { - alloc_instance Employee + alloc_instance user.Employee load_const "Alice" init_field .first load_const "Smith" @@ -250,12 +249,12 @@ function user.test_unbound_higher_order() -> string[] { } function user.test_unbound_in_map() -> string[] { - alloc_instance Employee + alloc_instance user.Employee load_const "Alice" init_field .first load_const "Smith" init_field .last - alloc_instance Employee + alloc_instance user.Employee load_const "Bob" init_field .first load_const "Jones" diff --git a/baml_language/crates/baml_tests/snapshots/comment_after_string_in_config/baml_tests__comment_after_string_in_config__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/comment_after_string_in_config/baml_tests__comment_after_string_in_config__04_5_mir.snap index 7be160ec86..6b9c835113 100644 --- a/baml_language/crates/baml_tests/snapshots/comment_after_string_in_config/baml_tests__comment_after_string_in_config__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/comment_after_string_in_config/baml_tests__comment_after_string_in_config__04_5_mir.snap @@ -5,7 +5,7 @@ source: crates/baml_tests/src/generated_tests.rs fn user.OpenRouterMistralSmall3_1_24b$new() -> null { // Locals: let _0: null // _0 // return - let _1: void + let _1: baml.llm.PrimitiveClientOptions let _2: string let _3: map let _4: map diff --git a/baml_language/crates/baml_tests/snapshots/comment_after_string_in_config/baml_tests__comment_after_string_in_config__04_tir.snap b/baml_language/crates/baml_tests/snapshots/comment_after_string_in_config/baml_tests__comment_after_string_in_config__04_tir.snap index e00a32c461..01005e909c 100644 --- a/baml_language/crates/baml_tests/snapshots/comment_after_string_in_config/baml_tests__comment_after_string_in_config__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/comment_after_string_in_config/baml_tests__comment_after_string_in_config__04_tir.snap @@ -3,5 +3,5 @@ source: crates/baml_tests/src/generated_tests.rs --- === TIR2 === function user.OpenRouterMistralSmall3_1_24b$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "OpenRouterMistral...", provider: "openai-generic", options: baml.llm.PrimitiveClientOptions { model: "mistralai/mistral...", base_url: "https://openroute...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: baml.env.get_or_panic("OPENROUTER_API_KEY"), provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "temperature": 0.1 } } } : unknown + baml.llm.PrimitiveClient { name: "OpenRouterMistral...", provider: "openai-generic", options: baml.llm.PrimitiveClientOptions { model: "mistralai/mistral...", base_url: "https://openroute...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: baml.env.get_or_panic("OPENROUTER_API_KEY"), provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "temperature": 0.1 } } } : baml.llm.PrimitiveClient } diff --git a/baml_language/crates/baml_tests/snapshots/comment_in_type/baml_tests__comment_in_type__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/comment_in_type/baml_tests__comment_in_type__04_5_mir.snap index 4eb0fa8613..7ff91e5237 100644 --- a/baml_language/crates/baml_tests/snapshots/comment_in_type/baml_tests__comment_in_type__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/comment_in_type/baml_tests__comment_in_type__04_5_mir.snap @@ -161,7 +161,7 @@ fn user.FunctionWithComments$render_prompt(a: string, b: int) -> baml.llm.Prompt fn user.TestClient$new() -> null { // Locals: let _0: null // _0 // return - let _1: void + let _1: baml.llm.PrimitiveClientOptions let _2: map let _3: map let _4: map diff --git a/baml_language/crates/baml_tests/snapshots/comment_in_type/baml_tests__comment_in_type__04_tir.snap b/baml_language/crates/baml_tests/snapshots/comment_in_type/baml_tests__comment_in_type__04_tir.snap index dce7b90134..079163f52a 100644 --- a/baml_language/crates/baml_tests/snapshots/comment_in_type/baml_tests__comment_in_type__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/comment_in_type/baml_tests__comment_in_type__04_tir.snap @@ -3,7 +3,7 @@ source: crates/baml_tests/src/generated_tests.rs --- === TIR2 === function user.TestClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "TestClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: null, base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "TestClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: null, base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.FunctionWithComments(a: string, b: int) -> string throws never { baml.llm.call_llm_function(TestClient, "FunctionWithComments", map { "a": a, "b": b }) : string diff --git a/baml_language/crates/baml_tests/snapshots/compiler2_mir/baml_tests__compiler2_mir__object_construction.snap b/baml_language/crates/baml_tests/snapshots/compiler2_mir/baml_tests__compiler2_mir__object_construction.snap index 8c9cb95c54..a49f77ac3f 100644 --- a/baml_language/crates/baml_tests/snapshots/compiler2_mir/baml_tests__compiler2_mir__object_construction.snap +++ b/baml_language/crates/baml_tests/snapshots/compiler2_mir/baml_tests__compiler2_mir__object_construction.snap @@ -6,7 +6,7 @@ fn user.f() -> Point { let _0: Point // _0 // return bb0: { - _0 = Point { const 1_i64, const 2_i64 }; + _0 = user.Point { const 1_i64, const 2_i64 }; goto -> bb1; } diff --git a/baml_language/crates/baml_tests/snapshots/config_dictionary/baml_tests__config_dictionary__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/config_dictionary/baml_tests__config_dictionary__04_5_mir.snap index 8aa3c560b4..52edc0043f 100644 --- a/baml_language/crates/baml_tests/snapshots/config_dictionary/baml_tests__config_dictionary__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/config_dictionary/baml_tests__config_dictionary__04_5_mir.snap @@ -5,7 +5,7 @@ source: crates/baml_tests/src/generated_tests.rs fn user.MyClient$new() -> null { // Locals: let _0: null // _0 // return - let _1: void + let _1: baml.llm.PrimitiveClientOptions let _2: map let _3: map let _4: map | void[]> diff --git a/baml_language/crates/baml_tests/snapshots/config_dictionary/baml_tests__config_dictionary__04_tir.snap b/baml_language/crates/baml_tests/snapshots/config_dictionary/baml_tests__config_dictionary__04_tir.snap index d110cb8cb1..5d88d3fcb9 100644 --- a/baml_language/crates/baml_tests/snapshots/config_dictionary/baml_tests__config_dictionary__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/config_dictionary/baml_tests__config_dictionary__04_tir.snap @@ -3,5 +3,5 @@ source: crates/baml_tests/src/generated_tests.rs --- === TIR2 === function user.MyClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "MyClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: null, base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100, "array_key_with_qu...": ["abc", "abc", "ccc"], "key2": "somerandomvalue", "hello": "world", "thing": "hello", "block_string": "#hellotheremyfriend#", "inline_raw_string": "#inlinerawstring,,#", "booleanValue": true, "stringKey": true, "array1": ["one", "two"], "array2": ["one", "two"], "array3Numbers": [null, null, null], "nestedKey": map { "key": "value", "key2": "value2", "nestedArray": ["yes", "queen"], "number": 10 }, "oneMoreValueToTes...": "value", "myInteger": 100, "tools": [], "block_string": "#hellotheremyfrie..." } } } : unknown + baml.llm.PrimitiveClient { name: "MyClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: null, base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100, "array_key_with_qu...": ["abc", "abc", "ccc"], "key2": "somerandomvalue", "hello": "world", "thing": "hello", "block_string": "#hellotheremyfriend#", "inline_raw_string": "#inlinerawstring,,#", "booleanValue": true, "stringKey": true, "array1": ["one", "two"], "array2": ["one", "two"], "array3Numbers": [null, null, null], "nestedKey": map { "key": "value", "key2": "value2", "nestedArray": ["yes", "queen"], "number": 10 }, "oneMoreValueToTes...": "value", "myInteger": 100, "tools": [], "block_string": "#hellotheremyfrie..." } } } : baml.llm.PrimitiveClient } diff --git a/baml_language/crates/baml_tests/snapshots/config_model_string/baml_tests__config_model_string__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/config_model_string/baml_tests__config_model_string__04_5_mir.snap index 86eb9fc9d0..2bea4b8e2c 100644 --- a/baml_language/crates/baml_tests/snapshots/config_model_string/baml_tests__config_model_string__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/config_model_string/baml_tests__config_model_string__04_5_mir.snap @@ -5,8 +5,8 @@ source: crates/baml_tests/src/generated_tests.rs fn user.MyAwsClient$new() -> null { // Locals: let _0: null // _0 // return - let _1: void - let _2: void + let _1: baml.llm.PrimitiveClientOptions + let _2: baml.llm.BedrockOptions let _3: map let _4: map let _5: map diff --git a/baml_language/crates/baml_tests/snapshots/config_model_string/baml_tests__config_model_string__04_tir.snap b/baml_language/crates/baml_tests/snapshots/config_model_string/baml_tests__config_model_string__04_tir.snap index 95ddc4c8d7..16fecc6322 100644 --- a/baml_language/crates/baml_tests/snapshots/config_model_string/baml_tests__config_model_string__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/config_model_string/baml_tests__config_model_string__04_tir.snap @@ -3,5 +3,5 @@ source: crates/baml_tests/src/generated_tests.rs --- === TIR2 === function user.MyAwsClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "MyAwsClient", provider: "aws-bedrock", options: baml.llm.PrimitiveClientOptions { model: "anthropic.claude-...", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: "sk-1234", provider_options: baml.llm.BedrockOptions { region: null, endpoint_url: null, access_key_id: null, secret_access_key: null, session_token: null, profile: null, stop_sequences: null, max_tokens: 100, temperature: 0.7, top_p: null }, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "MyAwsClient", provider: "aws-bedrock", options: baml.llm.PrimitiveClientOptions { model: "anthropic.claude-...", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: "sk-1234", provider_options: baml.llm.BedrockOptions { region: null, endpoint_url: null, access_key_id: null, secret_access_key: null, session_token: null, profile: null, stop_sequences: null, max_tokens: 100, temperature: 0.7, top_p: null }, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } diff --git a/baml_language/crates/baml_tests/snapshots/control_flow/baml_tests__control_flow__04_tir.snap b/baml_language/crates/baml_tests/snapshots/control_flow/baml_tests__control_flow__04_tir.snap index 5bc7658674..5959e8a109 100644 --- a/baml_language/crates/baml_tests/snapshots/control_flow/baml_tests__control_flow__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/control_flow/baml_tests__control_flow__04_tir.snap @@ -119,7 +119,7 @@ function user.NestedControlFlow(x: int) -> string throws never { } } function user.TestClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "TestClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "TestClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.LlmFunction(input: string) -> string throws never { baml.llm.call_llm_function(TestClient, "LlmFunction", map { "input": input }) : string diff --git a/baml_language/crates/baml_tests/snapshots/event_system/baml_tests__event_system__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/event_system/baml_tests__event_system__04_5_mir.snap index f1e0836be6..d919c03f71 100644 --- a/baml_language/crates/baml_tests/snapshots/event_system/baml_tests__event_system__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/event_system/baml_tests__event_system__04_5_mir.snap @@ -154,7 +154,7 @@ fn user.test_logging() -> void { let _6: map bb0: { - _1 = User { const 123_i64, const "Alice", const "alice@example.com" }; + _1 = user.User { const 123_i64, const "Alice", const "alice@example.com" }; _2 = { const "message": const "Starting process" }; intrinsic log_debug(copy _2); goto -> bb1; diff --git a/baml_language/crates/baml_tests/snapshots/event_system/baml_tests__event_system__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/event_system/baml_tests__event_system__06_codegen.snap index 9c8808810f..b367ac4224 100644 --- a/baml_language/crates/baml_tests/snapshots/event_system/baml_tests__event_system__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/event_system/baml_tests__event_system__06_codegen.snap @@ -98,7 +98,7 @@ function user.simple_function() -> int { } function user.test_logging() -> void { - alloc_instance User + alloc_instance user.User load_const 123 init_field .id load_const "Alice" diff --git a/baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__04_tir.snap b/baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__04_tir.snap index 16e3cb55c9..389b46882e 100644 --- a/baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__04_tir.snap @@ -577,73 +577,73 @@ class user.SemicolonTrivia$stream { age: null | int } function user.BasicClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "BasicClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "BasicClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.FullClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "FullClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100, "temperature": 0.7, "top_p": 0.9 } } } : unknown + baml.llm.PrimitiveClient { name: "FullClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100, "temperature": 0.7, "top_p": 0.9 } } } : baml.llm.PrimitiveClient } function user.StringProviderClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "StringProviderClient", provider: "openai-generic", options: baml.llm.PrimitiveClientOptions { model: "mistralai/mistral...", base_url: "https://openroute...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "StringProviderClient", provider: "openai-generic", options: baml.llm.PrimitiveClientOptions { model: "mistralai/mistral...", base_url: "https://openroute...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.NestedConfigClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "NestedConfigClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "NestedConfigClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.ArrayConfigClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "ArrayConfigClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "stop_sequences": ["END", "STOP", "DONE"] } } } : unknown + baml.llm.PrimitiveClient { name: "ArrayConfigClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "stop_sequences": ["END", "STOP", "DONE"] } } } : baml.llm.PrimitiveClient } function user.LongOptionClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "LongOptionClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "some-extremely-lo...", base_url: "https://some-real...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "LongOptionClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "some-extremely-lo...", base_url: "https://some-real...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.TypedValuesClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "TypedValuesClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "temperature": 0.5, "max_tokens": 2048, "stream": true } } } : unknown + baml.llm.PrimitiveClient { name: "TypedValuesClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "temperature": 0.5, "max_tokens": 2048, "stream": true } } } : baml.llm.PrimitiveClient } function user.EnvClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "EnvClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: baml.env.get_or_panic("OPENAI_API_KEY"), provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "EnvClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: baml.env.get_or_panic("OPENAI_API_KEY"), provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.ArrayOfObjectsClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "ArrayOfObjectsClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "tools": [] } } } : unknown + baml.llm.PrimitiveClient { name: "ArrayOfObjectsClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "tools": [] } } } : baml.llm.PrimitiveClient } function user.RawStringConfigClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "RawStringConfigCl...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "system_prompt": "#Youareahelpfulas..." } } } : unknown + baml.llm.PrimitiveClient { name: "RawStringConfigCl...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "system_prompt": "#Youareahelpfulas..." } } } : baml.llm.PrimitiveClient } function user.MixedValuesClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "MixedValuesClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100, "temperature": 0.7, "stream": true, "stop": ["END"], "inline_string": "#inlineraw#" } } } : unknown + baml.llm.PrimitiveClient { name: "MixedValuesClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100, "temperature": 0.7, "stream": true, "stop": ["END"], "inline_string": "#inlineraw#" } } } : baml.llm.PrimitiveClient } function user.TriviaClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "TriviaClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "TriviaClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.TriviaClientBlock$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "TriviaClientBlock", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "TriviaClientBlock", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.ThisIsAnExtremelyLongClientNameThatDefinitelyExceedsTheDefaultLineLimitOfOneHundredColumns$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "ThisIsAnExtremely...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "ThisIsAnExtremely...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.DeeplyNestedClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "DeeplyNestedClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { "custom_config": map { "retry_on_failure": true, "timeout_ms": 30000, "metadata": map { "team": "platform", "environment": "production" } } }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "DeeplyNestedClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { "custom_config": map { "retry_on_failure": true, "timeout_ms": 30000, "metadata": map { "team": "platform", "environment": "production" } } }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.LongNestedValuesClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "LongNestedValuesC...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "anthropic/claude-...", base_url: "https://some-extr...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "LongNestedValuesC...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "anthropic/claude-...", base_url: "https://some-extr...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.ManyOptionsClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "ManyOptionsClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: "https://api.opena...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: baml.env.get_or_panic("OPENAI_API_KEY"), provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 4096, "temperature": 0.7, "top_p": 0.95, "frequency_penalty": 0.5, "presence_penalty": 0.3, "stream": true, "stop_sequences": ["END", "STOP", "DONE", "COMPLETE", "FINISHED"] } } } : unknown + baml.llm.PrimitiveClient { name: "ManyOptionsClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: "https://api.opena...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: baml.env.get_or_panic("OPENAI_API_KEY"), provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 4096, "temperature": 0.7, "top_p": 0.95, "frequency_penalty": 0.5, "presence_penalty": 0.3, "stream": true, "stop_sequences": ["END", "STOP", "DONE", "COMPLETE", "FINISHED"] } } } : baml.llm.PrimitiveClient } function user.LongArrayClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "LongArrayClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "stop_sequences": ["STOP_GENERATION_NOW", "END_OF_RESPONSE_M...", "COMPLETION_FINISH...", "TERMINATE_OUTPUT_...", "FINAL_ANSWER_DELI..."] } } } : unknown + baml.llm.PrimitiveClient { name: "LongArrayClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "stop_sequences": ["STOP_GENERATION_NOW", "END_OF_RESPONSE_M...", "COMPLETION_FINISH...", "TERMINATE_OUTPUT_...", "FINAL_ANSWER_DELI..."] } } } : baml.llm.PrimitiveClient } function user.LongArrayOfObjectsClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "LongArrayOfObject...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "tools": [] } } } : unknown + baml.llm.PrimitiveClient { name: "LongArrayOfObject...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "tools": [] } } } : baml.llm.PrimitiveClient } function user.TriviaDeeplyNestedClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "TriviaDeeplyNeste...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "TriviaDeeplyNeste...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.TriviaDeeplyNestedClientBlock$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "TriviaDeeplyNeste...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "TriviaDeeplyNeste...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.TriviaLongValueClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "TriviaLongValueCl...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "some-extremely-lo...", base_url: "https://some-real...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "TriviaLongValueCl...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "some-extremely-lo...", base_url: "https://some-real...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.TriviaLongValueClientBlock$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "TriviaLongValueCl...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "some-extremely-lo...", base_url: "https://some-real...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "TriviaLongValueCl...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "some-extremely-lo...", base_url: "https://some-real...", allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.TestTarget() -> string throws never { baml.llm.call_llm_function(BasicClient, "TestTarget", map { }) : string @@ -661,16 +661,16 @@ function user.TestTarget$parse(json: string) -> string throws never { baml.llm.parse("TestTarget", json) : string } function user.C$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "C", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "C", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.ExtraWhitespaceClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "ExtraWhitespaceCl...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "ExtraWhitespaceCl...", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.CommaClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "CommaClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100 } } } : unknown + baml.llm.PrimitiveClient { name: "CommaClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "max_tokens": 100 } } } : baml.llm.PrimitiveClient } function user.SameLineClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "SameLineClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "SameLineClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.TestTarget$stream() -> baml.llm.Stream throws never { baml.llm.stream_llm_function(BasicClient, "TestTarget", map { }) : baml.llm.Stream @@ -1106,7 +1106,7 @@ function user.LlmStringClient$stream(text: string) -> baml.llm.Stream } function user.LlmStringClient$parse_stream(sse: baml.http.SseStream) -> baml.llm.Stream throws never { - baml.llm.Client { name: "openai/gpt-4o", client_type: baml.llm.ClientType.Primitive, sub_clients: [], retry: null, counter: 0 }.__make_stream(sse, "LlmStringClient") : unknown + baml.llm.Client { name: "openai/gpt-4o", client_type: baml.llm.ClientType.Primitive, sub_clients: [], retry: null, counter: 0 }.__make_stream(sse, "LlmStringClient") : baml.llm.Stream } function user.LlmReversedOrder$stream(text: string) -> baml.llm.Stream throws never { baml.llm.stream_llm_function(GPT4, "LlmReversedOrder", map { "text": text }) : baml.llm.Stream diff --git a/baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__06_codegen.snap index 55fbe65809..7d0db30527 100644 --- a/baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/format_checks/baml_tests__format_checks__06_codegen.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 12006 --- function $init() -> null { call $init_let_0 @@ -1553,10 +1552,21 @@ function user.LlmStringClient$parse(json: string) -> string { } function user.LlmStringClient$parse_stream(sse: baml.http.SseStream) -> baml.llm.Stream { + alloc_instance baml.llm.Client + load_const "openai/gpt-4o" + init_field .name + load_const baml.llm.ClientType.Primitive + alloc_variant baml.llm.ClientType + init_field .client_type + alloc_array 0 + init_field .sub_clients + load_const null + init_field .retry + load_const 0 + init_field .counter load_var sse load_const "LlmStringClient" - load_const null - call_indirect + call baml.llm.Client.__make_stream return } diff --git a/baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__04_5_mir.snap index acd3a4b2fa..61704afe16 100644 --- a/baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__04_5_mir.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 12886 --- === MIR2 === fn user.array_length() -> int { @@ -61,7 +60,7 @@ fn user.GreetBaz(n: string) -> string { let _2: Baz // baz bb0: { - _2 = Baz { copy _1 }; + _2 = user.Baz { copy _1 }; _0 = call const fn user.Baz.Greeting(copy _2) -> [bb1]; } diff --git a/baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__06_codegen.snap index 3ebc24012f..afa0e982ed 100644 --- a/baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/function_call/baml_tests__function_call__06_codegen.snap @@ -25,7 +25,7 @@ function user.Foo(x: int) -> int { } function user.GreetBaz(n: string) -> string { - alloc_instance Baz + alloc_instance user.Baz load_var n init_field .name call user.Baz.Greeting diff --git a/baml_language/crates/baml_tests/snapshots/function_type_throws/baml_tests__function_type_throws__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/function_type_throws/baml_tests__function_type_throws__06_codegen.snap index 0b0167fdce..7a91cca951 100644 --- a/baml_language/crates/baml_tests/snapshots/function_type_throws/baml_tests__function_type_throws__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/function_type_throws/baml_tests__function_type_throws__06_codegen.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 13489 --- function user.Worker.scale(self: null, value: int) -> int { load_var self @@ -49,7 +48,7 @@ function user.fail_returned() -> (int) -> int throws never { } function user.fail_stored() -> Holder { - alloc_instance Holder + alloc_instance user.Holder load_global user.risky init_field .cb return diff --git a/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__03_hir.snap b/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__03_hir.snap index 56b09c8988..4bc87c732c 100644 --- a/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__03_hir.snap @@ -127,5 +127,5 @@ class user.Todo { userId: int } function user.GetTodo() -> user.Todo [expr] { - { } (HttpRequest { method: baml.HttpMethod.Get, url: "dummyjson.com/tod..." }) + { } (baml.HttpRequest { method: baml.HttpMethod.Get, url: "dummyjson.com/tod..." }) } diff --git a/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__04_tir.snap b/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__04_tir.snap index c7fb3ecd6a..1d737119ec 100644 --- a/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__04_tir.snap @@ -239,7 +239,7 @@ class user.Todo { } function user.GetTodo() -> user.Todo throws never { { : unknown - (HttpRequest { method: baml.HttpMethod.Get, url: "dummyjson.com/tod..." }) : unknown + (baml.HttpRequest { method: baml.HttpMethod.Get, url: "dummyjson.com/tod..." }) : unknown } !! 165..185: unresolved name: HttpMethod } diff --git a/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__06_codegen.snap index b184ede1a0..fe230d1183 100644 --- a/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/generics/baml_tests__generics__06_codegen.snap @@ -15,7 +15,7 @@ function user.Container.unwrap(self: null) -> void { } function user.Factory.create(value: void) -> Factory { - alloc_instance Factory + alloc_instance user.Factory load_var value init_field .data return @@ -44,14 +44,14 @@ function user.Holder.get_data(self: null) -> void { } function user.Maker.from_string(params: string) -> Maker { - alloc_instance Maker + alloc_instance user.Maker load_var params init_field .data return } function user.Maker.from_value(params: void) -> Maker { - alloc_instance Maker + alloc_instance user.Maker load_var params init_field .data return @@ -94,7 +94,7 @@ function user.Pair.get_second(self: null) -> void { } function user.Pair.swap(self: null) -> Pair { - alloc_instance Pair + alloc_instance user.Pair load_var self load_field .second init_field .first @@ -118,14 +118,14 @@ function user.Stack.peek(self: null) -> void { } function user.Wrapper.of(value: void) -> Wrapper { - alloc_instance Wrapper + alloc_instance user.Wrapper load_var value init_field .data return } function user.use_box() -> int { - alloc_instance Box + alloc_instance user.Box load_const 42 init_field .value call user.Box.get @@ -140,7 +140,7 @@ function user.use_factory() -> int { } function user.use_holder() -> int { - alloc_instance Holder + alloc_instance user.Holder load_const "hello" init_field .data call user.Holder.get_data @@ -154,7 +154,7 @@ function user.use_maker_static() -> Maker { } function user.use_maybe_box() -> int { - alloc_instance MaybeBox + alloc_instance user.MaybeBox load_const null init_field .value load_const 0 @@ -163,8 +163,8 @@ function user.use_maybe_box() -> int { } function user.use_nested() -> int { - alloc_instance Container - alloc_instance Box + alloc_instance user.Container + alloc_instance user.Box load_const 10 init_field .value init_field .inner @@ -173,7 +173,7 @@ function user.use_nested() -> int { } function user.use_pair() -> string { - alloc_instance Pair + alloc_instance user.Pair load_const 1 init_field .first load_const "two" @@ -183,7 +183,7 @@ function user.use_pair() -> string { } function user.use_pair_swap() -> Pair { - alloc_instance Pair + alloc_instance user.Pair load_const 1 init_field .first load_const "two" @@ -193,7 +193,7 @@ function user.use_pair_swap() -> Pair { } function user.use_stack() -> string { - alloc_instance Stack + alloc_instance user.Stack load_const "a" load_const "b" load_const "c" @@ -210,28 +210,28 @@ function user.use_wrapper() -> Wrapper { } function user.wrong_arity_extra() -> Box { - alloc_instance Box + alloc_instance user.Box load_const 42 init_field .value return } function user.wrong_arity_missing() -> Box { - alloc_instance Box + alloc_instance user.Box load_const 42 init_field .value return } function user.wrong_arity_on_non_generic() -> Plain { - alloc_instance Plain + alloc_instance user.Plain load_const "hello" init_field .name return } function user.wrong_arity_partial() -> Pair { - alloc_instance Pair + alloc_instance user.Pair load_const 1 init_field .first load_const "two" diff --git a/baml_language/crates/baml_tests/snapshots/header_in_llm_function/baml_tests__header_in_llm_function__04_tir.snap b/baml_language/crates/baml_tests/snapshots/header_in_llm_function/baml_tests__header_in_llm_function__04_tir.snap index c83962a364..6738aa789c 100644 --- a/baml_language/crates/baml_tests/snapshots/header_in_llm_function/baml_tests__header_in_llm_function__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/header_in_llm_function/baml_tests__header_in_llm_function__04_tir.snap @@ -6,7 +6,7 @@ class user.Hi { name: string } function user.VertexGCP$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "VertexGCP", provider: "vertex-ai", options: baml.llm.PrimitiveClientOptions { model: "gemini-2", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "flash": "" } } } : unknown + baml.llm.PrimitiveClient { name: "VertexGCP", provider: "vertex-ai", options: baml.llm.PrimitiveClientOptions { model: "gemini-2", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { "flash": "" } } } : baml.llm.PrimitiveClient } function user.FetchDatax(user_id: string) -> user.Hi throws never { baml.llm.call_llm_function(VertexGCP, "FetchDatax", map { "user_id": user_id }) : user.Hi diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_bare_name_rejected/baml_tests__namespaces_bare_name_rejected__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/namespaces_bare_name_rejected/baml_tests__namespaces_bare_name_rejected__06_codegen.snap index 4274c149b3..eedb94458e 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_bare_name_rejected/baml_tests__namespaces_bare_name_rejected__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_bare_name_rejected/baml_tests__namespaces_bare_name_rejected__06_codegen.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- function user.llm.UseConfig(cfg: void) -> llm.Response { - alloc_instance Response + alloc_instance user.llm.Response load_const null init_field .text return diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__03_hir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__03_hir.snap index 285ce07016..6fe3c80bf5 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__03_hir.snap @@ -7,7 +7,7 @@ class user.Config { model: string } function user.GetResponse(cfg: user.Config) -> root.llm.Response [expr] { - { } Response { text: "hello", model: cfg.model } + { } root.llm.Response { text: "hello", model: cfg.model } } class user.llm.Response { text: string diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__04_5_mir.snap index da4eea7342..2f6181c685 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__04_5_mir.snap @@ -10,7 +10,7 @@ fn user.GetResponse(cfg: Config) -> llm.Response { bb0: { _2 = copy _1.1; - _0 = Response { const "hello", copy _2 }; + _0 = user.llm.Response { const "hello", copy _2 }; goto -> bb1; } @@ -27,7 +27,7 @@ fn user.llm.MakeResponse(cfg: Config) -> llm.Response { bb0: { _2 = copy _1.1; - _0 = Response { const "ok", copy _2 }; + _0 = user.llm.Response { const "ok", copy _2 }; goto -> bb1; } diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__04_tir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__04_tir.snap index f12e97e663..28162aaf6c 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__04_tir.snap @@ -8,7 +8,7 @@ class user.Config { } function user.GetResponse(cfg: user.Config) -> user.llm.Response throws never { { : user.llm.Response - Response { text: "hello", model: cfg.model } : user.llm.Response + root.llm.Response { text: "hello", model: cfg.model } : user.llm.Response } } class user.Config$stream { diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__06_codegen.snap index decbeac780..ed0535bbfd 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_basic/baml_tests__namespaces_basic__06_codegen.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- function user.GetResponse(cfg: Config) -> llm.Response { - alloc_instance Response + alloc_instance user.llm.Response load_const "hello" init_field .text load_var cfg @@ -12,7 +12,7 @@ function user.GetResponse(cfg: Config) -> llm.Response { } function user.llm.MakeResponse(cfg: Config) -> llm.Response { - alloc_instance Response + alloc_instance user.llm.Response load_const "ok" init_field .text load_var cfg diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__03_hir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__03_hir.snap index 211700dfdb..6f228a350b 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__03_hir.snap @@ -6,7 +6,7 @@ class user.AppConfig { api_key: string } function user.CallOpenAI(cfg: user.AppConfig) -> root.llm.openai.OpenAIResponse [expr] { - { } OpenAIResponse { text: "response", model: "gpt-4" } + { } root.llm.openai.OpenAIResponse { text: "response", model: "gpt-4" } } class user.llm.openai.OpenAIResponse { text: string diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__04_5_mir.snap index 4d0b7ce50b..db9de2438d 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__04_5_mir.snap @@ -8,7 +8,7 @@ fn user.CallOpenAI(cfg: AppConfig) -> llm.openai.OpenAIResponse { let _1: AppConfig // cfg // param bb0: { - _0 = OpenAIResponse { const "response", const "gpt-4" }; + _0 = user.llm.openai.OpenAIResponse { const "response", const "gpt-4" }; goto -> bb1; } diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__04_tir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__04_tir.snap index 06d8e4f8c8..00086c28da 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__04_tir.snap @@ -7,7 +7,7 @@ class user.AppConfig { } function user.CallOpenAI(cfg: user.AppConfig) -> user.llm.openai.OpenAIResponse throws never { { : user.llm.openai.OpenAIResponse - OpenAIResponse { text: "response", model: "gpt-4" } : user.llm.openai.OpenAIResponse + root.llm.openai.OpenAIResponse { text: "response", model: "gpt-4" } : user.llm.openai.OpenAIResponse } } class user.AppConfig$stream { diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__06_codegen.snap index f99a79aa23..fa58e892ed 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_nested/baml_tests__namespaces_nested__06_codegen.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- function user.CallOpenAI(cfg: AppConfig) -> llm.openai.OpenAIResponse { - alloc_instance OpenAIResponse + alloc_instance user.llm.openai.OpenAIResponse load_const "response" init_field .text load_const "gpt-4" diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_root_fallback/baml_tests__namespaces_root_fallback__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_root_fallback/baml_tests__namespaces_root_fallback__04_5_mir.snap index 046c50bfe9..4fbba6758d 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_root_fallback/baml_tests__namespaces_root_fallback__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_root_fallback/baml_tests__namespaces_root_fallback__04_5_mir.snap @@ -10,7 +10,7 @@ fn user.llm.UseConfig(cfg: Config) -> llm.Response { bb0: { _2 = copy _1.0; - _0 = Response { copy _2 }; + _0 = user.llm.Response { copy _2 }; goto -> bb1; } diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_root_fallback/baml_tests__namespaces_root_fallback__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/namespaces_root_fallback/baml_tests__namespaces_root_fallback__06_codegen.snap index 9038823f96..14c7085686 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_root_fallback/baml_tests__namespaces_root_fallback__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_root_fallback/baml_tests__namespaces_root_fallback__06_codegen.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- function user.llm.UseConfig(cfg: Config) -> llm.Response { - alloc_instance Response + alloc_instance user.llm.Response load_var cfg load_field .key init_field .text diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__03_hir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__03_hir.snap index f0b90797db..cad0d78c2a 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__03_hir.snap @@ -3,10 +3,10 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === function user.GetHttpStatus() -> root.http.Response [expr] { - { } Response { status: 200, body: "ok" } + { } root.http.Response { status: 200, body: "ok" } } function user.GetLlmText() -> root.llm.Response [expr] { - { } Response { text: "hello", tokens: 5 } + { } root.llm.Response { text: "hello", tokens: 5 } } class user.http.Response { status: int diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__04_5_mir.snap index 42a758da4b..c4d5fa4c9b 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__04_5_mir.snap @@ -7,7 +7,7 @@ fn user.GetHttpStatus() -> http.Response { let _0: http.Response // _0 // return bb0: { - _0 = Response { const 200_i64, const "ok" }; + _0 = user.http.Response { const 200_i64, const "ok" }; goto -> bb1; } @@ -21,7 +21,7 @@ fn user.GetLlmText() -> llm.Response { let _0: llm.Response // _0 // return bb0: { - _0 = Response { const "hello", const 5_i64 }; + _0 = user.llm.Response { const "hello", const 5_i64 }; goto -> bb1; } diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__04_tir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__04_tir.snap index 000ac81e45..13d8904181 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__04_tir.snap @@ -4,12 +4,12 @@ source: crates/baml_tests/src/generated_tests.rs === TIR2 === function user.GetLlmText() -> user.llm.Response throws never { { : user.llm.Response - Response { text: "hello", tokens: 5 } : user.llm.Response + root.llm.Response { text: "hello", tokens: 5 } : user.llm.Response } } function user.GetHttpStatus() -> user.http.Response throws never { { : user.http.Response - Response { status: 200, body: "ok" } : user.http.Response + root.http.Response { status: 200, body: "ok" } : user.http.Response } } class user.http.Response { diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__06_codegen.snap index 06eb6bdc43..33c5db7a91 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_same_name/baml_tests__namespaces_same_name__06_codegen.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- function user.GetHttpStatus() -> http.Response { - alloc_instance Response + alloc_instance user.http.Response load_const 200 init_field .status load_const "ok" @@ -11,10 +11,10 @@ function user.GetHttpStatus() -> http.Response { } function user.GetLlmText() -> llm.Response { - alloc_instance Response + alloc_instance user.llm.Response load_const "hello" - init_field .status + init_field .text load_const 5 - init_field .body + init_field .tokens return } diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__03_hir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__03_hir.snap index ec6e58b92e..e52d358d63 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__03_hir.snap @@ -118,7 +118,7 @@ function user.auth.AuthThrowEnum(x: int) -> string [expr] { { } match (x) { 0 => throw Role.Guest, _ => "ok" } } function user.auth.AuthThrowsRootError(x: int) -> string [expr] { - { } match (x) { 0 => throw user.auth.Error { code: 403, message: "forbidden" }, _ => "ok" } + { } match (x) { 0 => throw root.Error { code: 403, message: "forbidden" }, _ => "ok" } } function user.auth.AuthUsesLlmConfig(cfg: root.llm.Config) -> string [expr] { { } cfg.model @@ -203,7 +203,7 @@ function user.llm.LlmThrowsRootEnum(x: int) -> string [expr] { { } match (x) { 0 => throw root.Status.Failed, _ => "ok" } } function user.llm.LlmThrowsRootError(x: int) -> string [expr] { - { } match (x) { 0 => throw user.llm.Error { code: 404, message: "not found" }, _ => "ok" } + { } match (x) { 0 => throw root.Error { code: 404, message: "not found" }, _ => "ok" } } function user.llm.LlmUsesAuthConfig(cfg: root.auth.Config) -> string [expr] { { } cfg.provider diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__04_5_mir.snap index c2fbd77d6b..a1c3cabb45 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__04_5_mir.snap @@ -23,7 +23,7 @@ fn user.RootConstruct(key: string) -> Config { let _1: string // key // param bb0: { - _0 = Config { copy _1, const "prod" }; + _0 = user.Config { copy _1, const "prod" }; goto -> bb1; } @@ -134,7 +134,7 @@ fn user.RootThrowClass(x: int) -> string { } bb3: { - _2 = Error { const 500_i64, const "root error" }; + _2 = user.Error { const 500_i64, const "root error" }; throw copy _2; } } @@ -272,7 +272,7 @@ fn user.auth.AuthConstruct(provider: string) -> auth.Config { let _1: string // provider // param bb0: { - _0 = Config { copy _1, const "s3cret" }; + _0 = user.auth.Config { copy _1, const "s3cret" }; goto -> bb1; } @@ -351,7 +351,7 @@ fn user.auth.AuthMakeToken(v: string) -> auth.Token { let _1: string // v // param bb0: { - _0 = Token { copy _1, const user.auth.Role.User }; + _0 = user.auth.Token { copy _1, const user.auth.Role.User }; goto -> bb1; } @@ -486,7 +486,7 @@ fn user.auth.AuthThrowClass(x: int) -> string { } bb3: { - _2 = Error { const "auth failed", const true }; + _2 = user.auth.Error { const "auth failed", const true }; throw copy _2; } } @@ -518,7 +518,7 @@ fn user.auth.AuthThrowsRootError(x: int) -> string { // Locals: let _0: string // _0 // return let _1: int // x // param - let _2: auth.Error + let _2: Error bb0: { switch copy _1 [0: bb3, otherwise: bb1]; @@ -534,7 +534,7 @@ fn user.auth.AuthThrowsRootError(x: int) -> string { } bb3: { - _2 = Error { const 403_i64, const "forbidden" }; + _2 = user.Error { const 403_i64, const "forbidden" }; throw copy _2; } } @@ -648,7 +648,7 @@ fn user.llm.LlmConstruct(model: string) -> llm.Config { let _1: string // model // param bb0: { - _0 = Config { copy _1, const 0.7_f64 }; + _0 = user.llm.Config { copy _1, const 0.7_f64 }; goto -> bb1; } @@ -781,7 +781,7 @@ fn user.llm.LlmResponseConstruct(text: string) -> llm.Response { let _1: string // text // param bb0: { - _0 = Response { copy _1, const 42_i64 }; + _0 = user.llm.Response { copy _1, const 42_i64 }; goto -> bb1; } @@ -810,7 +810,7 @@ fn user.llm.LlmThrowClass(x: int) -> string { } bb3: { - _2 = Error { const "llm failed", const true }; + _2 = user.llm.Error { const "llm failed", const true }; throw copy _2; } } @@ -865,7 +865,7 @@ fn user.llm.LlmThrowsRootError(x: int) -> string { // Locals: let _0: string // _0 // return let _1: int // x // param - let _2: llm.Error + let _2: Error bb0: { switch copy _1 [0: bb3, otherwise: bb1]; @@ -881,7 +881,7 @@ fn user.llm.LlmThrowsRootError(x: int) -> string { } bb3: { - _2 = Error { const 404_i64, const "not found" }; + _2 = user.Error { const 404_i64, const "not found" }; throw copy _2; } } @@ -1010,7 +1010,7 @@ fn user.llm.openai.OpenAIConstruct(key: string) -> llm.openai.Client { let _1: string // key // param bb0: { - _0 = Client { copy _1, const "org-123" }; + _0 = user.llm.openai.Client { copy _1, const "org-123" }; goto -> bb1; } @@ -1264,7 +1264,7 @@ fn user.llm.openai.OpenAIThrowClass(x: int) -> string { } bb3: { - _2 = Error { const 429_i64, const "rate limited" }; + _2 = user.llm.openai.Error { const 429_i64, const "rate limited" }; throw copy _2; } } diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__04_tir.snap b/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__04_tir.snap index 9c45ee294b..dcba28a885 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__04_tir.snap @@ -224,7 +224,7 @@ function user.auth.AuthThrowsRootError(x: int) -> string throws never { { : "ok" match (x : int) : "ok" 0 => - throw Error { code: 403, message: "forbidden" } : never + throw root.Error { code: 403, message: "forbidden" } : never _ => "ok" : "ok" } @@ -388,7 +388,7 @@ function user.llm.LlmThrowsRootError(x: int) -> string throws never { { : "ok" match (x : int) : "ok" 0 => - throw Error { code: 404, message: "not found" } : never + throw root.Error { code: 404, message: "not found" } : never _ => "ok" : "ok" } diff --git a/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__06_codegen.snap index ab7e5f90be..12c2b66a73 100644 --- a/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/namespaces_type_resolution/baml_tests__namespaces_type_resolution__06_codegen.snap @@ -8,7 +8,7 @@ function user.RootAliasParam(cfg: Config) -> string { } function user.RootConstruct(key: string) -> Config { - alloc_instance Config + alloc_instance user.Config load_var key init_field .key load_const "prod" @@ -76,7 +76,7 @@ function user.RootThrowClass(x: int) -> string { return L1: - alloc_instance Error + alloc_instance user.Error load_const 500 init_field .code load_const "root error" @@ -144,11 +144,11 @@ function user.auth.AuthAliasParam(t: auth.Token) -> string { } function user.auth.AuthConstruct(provider: string) -> auth.Config { - alloc_instance Config + alloc_instance user.auth.Config load_var provider - init_field .key + init_field .provider load_const "s3cret" - init_field .env + init_field .secret return } @@ -195,7 +195,7 @@ function user.auth.AuthIdentity(cfg: auth.Config) -> auth.Config { } function user.auth.AuthMakeToken(v: string) -> auth.Token { - alloc_instance Token + alloc_instance user.auth.Token load_var v init_field .value load_const user.auth.Role.User @@ -290,11 +290,11 @@ function user.auth.AuthThrowClass(x: int) -> string { return L1: - alloc_instance Error + alloc_instance user.auth.Error load_const "auth failed" - init_field .code + init_field .realm load_const true - init_field .message + init_field .expired throw } @@ -327,7 +327,7 @@ function user.auth.AuthThrowsRootError(x: int) -> string { return L1: - alloc_instance Error + alloc_instance user.Error load_const 403 init_field .code load_const "forbidden" @@ -378,11 +378,11 @@ function user.llm.LlmAliasParam(cfg: llm.Config) -> string { } function user.llm.LlmConstruct(model: string) -> llm.Config { - alloc_instance Config + alloc_instance user.llm.Config load_var model - init_field .key + init_field .model load_const 0.7 - init_field .env + init_field .temperature return } @@ -466,7 +466,7 @@ function user.llm.LlmMixedConfigs(llm_cfg: llm.Config, root_cfg: Config, auth_cf } function user.llm.LlmResponseConstruct(text: string) -> llm.Response { - alloc_instance Response + alloc_instance user.llm.Response load_var text init_field .text load_const 42 @@ -486,11 +486,11 @@ function user.llm.LlmThrowClass(x: int) -> string { return L1: - alloc_instance Error + alloc_instance user.llm.Error load_const "llm failed" - init_field .code + init_field .reason load_const true - init_field .message + init_field .retryable throw } @@ -540,7 +540,7 @@ function user.llm.LlmThrowsRootError(x: int) -> string { return L1: - alloc_instance Error + alloc_instance user.Error load_const 404 init_field .code load_const "not found" @@ -597,7 +597,7 @@ function user.llm.LlmUsesRootStatus() -> Status { } function user.llm.openai.OpenAIConstruct(key: string) -> llm.openai.Client { - alloc_instance Client + alloc_instance user.llm.openai.Client load_var key init_field .api_key load_const "org-123" @@ -789,11 +789,11 @@ function user.llm.openai.OpenAIThrowClass(x: int) -> string { return L1: - alloc_instance Error + alloc_instance user.llm.openai.Error load_const 429 - init_field .code + init_field .status_code load_const "rate limited" - init_field .message + init_field .body throw } diff --git a/baml_language/crates/baml_tests/snapshots/o1_allowed_roles/baml_tests__o1_allowed_roles__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/o1_allowed_roles/baml_tests__o1_allowed_roles__04_5_mir.snap index b28e229e6d..1b5dd4d782 100644 --- a/baml_language/crates/baml_tests/snapshots/o1_allowed_roles/baml_tests__o1_allowed_roles__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/o1_allowed_roles/baml_tests__o1_allowed_roles__04_5_mir.snap @@ -5,7 +5,7 @@ source: crates/baml_tests/src/generated_tests.rs fn user.Gpt4oClient$new() -> null { // Locals: let _0: null // _0 // return - let _1: void + let _1: baml.llm.PrimitiveClientOptions let _2: map let _3: map let _4: map @@ -27,7 +27,7 @@ fn user.Gpt4oClient$new() -> null { fn user.O1Client$new() -> null { // Locals: let _0: null // _0 // return - let _1: void + let _1: baml.llm.PrimitiveClientOptions let _2: map let _3: map let _4: map @@ -49,7 +49,7 @@ fn user.O1Client$new() -> null { fn user.O1MiniClient$new() -> null { // Locals: let _0: null // _0 // return - let _1: void + let _1: baml.llm.PrimitiveClientOptions let _2: map let _3: map let _4: map @@ -71,7 +71,7 @@ fn user.O1MiniClient$new() -> null { fn user.O1WithExplicitRoles$new() -> null { // Locals: let _0: null // _0 // return - let _1: void + let _1: baml.llm.PrimitiveClientOptions let _2: string[] let _3: map let _4: map diff --git a/baml_language/crates/baml_tests/snapshots/o1_allowed_roles/baml_tests__o1_allowed_roles__04_tir.snap b/baml_language/crates/baml_tests/snapshots/o1_allowed_roles/baml_tests__o1_allowed_roles__04_tir.snap index 7062c50fab..5ba1a97ec7 100644 --- a/baml_language/crates/baml_tests/snapshots/o1_allowed_roles/baml_tests__o1_allowed_roles__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/o1_allowed_roles/baml_tests__o1_allowed_roles__04_tir.snap @@ -3,14 +3,14 @@ source: crates/baml_tests/src/generated_tests.rs --- === TIR2 === function user.O1Client$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "O1Client", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "o1", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: "sk-test", provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "O1Client", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "o1", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: "sk-test", provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.O1MiniClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "O1MiniClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "o1-mini", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: "sk-test", provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "O1MiniClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "o1-mini", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: "sk-test", provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.Gpt4oClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "Gpt4oClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4o", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: "sk-test", provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "Gpt4oClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4o", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: "sk-test", provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } function user.O1WithExplicitRoles$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "O1WithExplicitRoles", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "o1", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: ["system", "user", "assistant"], remap_roles: null, api_key: "sk-test", provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "O1WithExplicitRoles", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "o1", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: ["system", "user", "assistant"], remap_roles: null, api_key: "sk-test", provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } diff --git a/baml_language/crates/baml_tests/snapshots/parser_constructors/baml_tests__parser_constructors__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/parser_constructors/baml_tests__parser_constructors__06_codegen.snap index d3e43c79b1..776bc9e44d 100644 --- a/baml_language/crates/baml_tests/snapshots/parser_constructors/baml_tests__parser_constructors__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/parser_constructors/baml_tests__parser_constructors__06_codegen.snap @@ -61,7 +61,7 @@ function user.mixedArray() -> (int | string)[] { } function user.point() -> Point { - alloc_instance Point + alloc_instance user.Point load_const 1 init_field .x load_const 2 @@ -70,17 +70,17 @@ function user.point() -> Point { } function user.pointArray() -> Point[] { - alloc_instance Point + alloc_instance user.Point load_const 1 init_field .x load_const 2 init_field .y - alloc_instance Point + alloc_instance user.Point load_const 3 init_field .x load_const 4 init_field .y - alloc_instance Point + alloc_instance user.Point load_const 5 init_field .x load_const 6 @@ -107,14 +107,14 @@ function user.stringValues() -> map { } function user.vec2d() -> Vec2D { - alloc_instance Vec2D - alloc_instance Point + alloc_instance user.Vec2D + alloc_instance user.Point load_const 1 init_field .x load_const 2 init_field .y init_field .p - alloc_instance Point + alloc_instance user.Point load_const 3 init_field .x load_const 4 diff --git a/baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__04_5_mir.snap index 972e80f2eb..95adbc791b 100644 --- a/baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__04_5_mir.snap @@ -178,7 +178,7 @@ fn user.edge_type_then_object() -> int { let _1: EdgeFoo bb0: { - _1 = EdgeFoo { const 1_i64 }; + _1 = user.EdgeFoo { const 1_i64 }; _0 = copy _1.0; goto -> bb1; } @@ -719,7 +719,7 @@ fn user.let_statements() -> int { let _3: int bb0: { - _1 = Point { const 1_i64, const 2_i64 }; + _1 = user.Point { const 1_i64, const 2_i64 }; _2 = copy _1.0; _3 = copy _1.1; _0 = copy _2 + copy _3; diff --git a/baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__06_codegen.snap index 24131dd51e..4a2dc0e85f 100644 --- a/baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/parser_statements/baml_tests__parser_statements__06_codegen.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 28455 --- function user.ConditionalLogic(age: int) -> string { load_var age @@ -206,7 +205,7 @@ function user.edge_semicolon_forces_boundary(bar: () -> int[] throws never) -> i } function user.edge_type_then_object() -> int { - alloc_instance EdgeFoo + alloc_instance user.EdgeFoo load_const 1 init_field .x load_field .x @@ -269,7 +268,7 @@ function user.let_no_semicolons() -> int { } function user.let_statements() -> int { - alloc_instance Point + alloc_instance user.Point load_const 1 init_field .x load_const 2 diff --git a/baml_language/crates/baml_tests/snapshots/retry_policy/baml_tests__retry_policy__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/retry_policy/baml_tests__retry_policy__04_5_mir.snap index d5d7a57fbd..1b66c94a5c 100644 --- a/baml_language/crates/baml_tests/snapshots/retry_policy/baml_tests__retry_policy__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/retry_policy/baml_tests__retry_policy__04_5_mir.snap @@ -5,7 +5,7 @@ source: crates/baml_tests/src/generated_tests.rs fn user.MyClient$new() -> null { // Locals: let _0: null // _0 // return - let _1: void + let _1: baml.llm.PrimitiveClientOptions let _2: map let _3: map let _4: map diff --git a/baml_language/crates/baml_tests/snapshots/retry_policy/baml_tests__retry_policy__04_tir.snap b/baml_language/crates/baml_tests/snapshots/retry_policy/baml_tests__retry_policy__04_tir.snap index 33e7fdc849..503eafcd5a 100644 --- a/baml_language/crates/baml_tests/snapshots/retry_policy/baml_tests__retry_policy__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/retry_policy/baml_tests__retry_policy__04_tir.snap @@ -3,5 +3,5 @@ source: crates/baml_tests/src/generated_tests.rs --- === TIR2 === function user.MyClient$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "MyClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "MyClient", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: null, provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__03_hir.snap index 31a5c607ba..f1b5e1e68c 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__03_hir.snap @@ -2,6 +2,6 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("simple test", () -> void { { let x = 1 Add 2 } assert.equal(x, 3) }, null); registry.register_test("with not_null", () -> void { { let result = "hello" } assert.not_null(result) }, null) } null } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__04_5_mir.snap index fd990b7e23..7af5df80b5 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 33962 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -33,7 +32,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .() -> null { +fn .() -> null { // Locals: let _0: null // _0 // return @@ -47,7 +46,7 @@ fn .() -> null { } // lambda[1] -fn .() -> null { +fn .() -> null { // Locals: let _0: null // _0 // return diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__04_tir.snap index d9d23627eb..b73e2ff6e5 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__04_tir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 33921 --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("simple test", () -> void { ... }, null) : void () -> void { ... } : () -> void throws unknown @@ -20,7 +19,7 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__06_codegen.snap index 9ccae9a3d2..51e65eea45 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_basic/baml_tests__test_expr_basic__06_codegen.snap @@ -9,16 +9,16 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "simple test" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 load_var registry load_const "with not_null" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__03_hir.snap index a52905b0eb..c7a1ac0da8 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__03_hir.snap @@ -2,6 +2,6 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test_set("concat names", (testset: testing.TestCollector) -> void { { testset.register_test("prefix_" Add "suffix", () -> { { } null }, null); testset.register_test_set("nested_" Add "group", (testset: testing.TestCollector) -> { { testset.register_test("inner", () -> { { } null }, null) } null }, null) } null }, null) } null } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__04_5_mir.snap index 4d05e0ea0b..341ed15464 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 34287 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -26,7 +25,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .(testset: testing.TestCollector) -> null { +fn .(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -56,7 +55,7 @@ fn .(testset: testing.TestCollector) -> null { } // lambda[0] -fn ., 1)>() -> null { +fn ., 1)>() -> null { // Locals: let _0: null // _0 // return @@ -71,7 +70,7 @@ fn ., 1)>() -> null { } // lambda[1] -fn ., 2)>(testset: testing.TestCollector) -> null { +fn ., 2)>(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -94,7 +93,7 @@ fn ., 2)>(testset: testing.TestCollector) -> n } // lambda[0] -fn ., 2)>, 3)>() -> null { +fn ., 2)>, 3)>() -> null { // Locals: let _0: null // _0 // return diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__04_tir.snap index 5d216ae97f..12a489ee30 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__04_tir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 34246 --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test_set("concat names", (testset: testing.TestCollector) -> void { ... }, null) : void (testset: testing.TestCollector) -> void { ... } : (testset: testing.TestCollector) -> void throws unknown @@ -15,11 +14,11 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__06_codegen.snap index 571ae64c46..68dba0f289 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_name_concat/baml_tests__test_expr_name_concat__06_codegen.snap @@ -9,10 +9,10 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "concat names" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__03_hir.snap index e0bc0ff03a..88ab855660 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__03_hir.snap @@ -2,6 +2,6 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("a" Add 1, () -> void { { } null }, null); registry.register_test(42, () -> void { { } null }, null); registry.register_test_set("int_name", (testset: testing.TestCollector) -> void { { for i in [1, 2, 3] { testset.register_test(5 Add i, () -> { { } null }, null) } } null }, null) } null } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__04_tir.snap index cce359b6f7..aebd0bcead 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__04_tir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 34571 --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("a" + 1, () -> void { ... }, null) : void () -> void { ... } : () -> void throws unknown @@ -29,12 +28,12 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { !! 106..108: type mismatch: expected string, got 42 !! 0..0: type mismatch: expected string, got int } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { !! 177..182: type mismatch: expected string, got int } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__06_codegen.snap index 2b5e704761..17b8b58976 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_name_type_error/baml_tests__test_expr_name_type_error__06_codegen.snap @@ -9,24 +9,24 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "a" load_const 1 bin_op + - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 load_var registry load_const 42 - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 load_var registry load_const "int_name" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__03_hir.snap index 83787a83c2..05ed1c6e2f 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__03_hir.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("throwing body bec...", () -> void { { } risky() }, null) } null } function user.risky() -> void [expr] { diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__04_5_mir.snap index 4a2799e964..df01a5cdb1 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 34937 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -26,7 +25,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .() -> null { +fn .() -> null { // Locals: let _0: null // _0 // return diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__04_tir.snap index 051137fe98..87f6154f24 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__04_tir.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 34896 --- === TIR2 === function user.risky() -> void throws string { @@ -8,7 +7,7 @@ function user.risky() -> void throws string { throw "boom" : "boom" } } -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("throwing body bec...", () -> void { ... }, null) : void () -> void { ... } : () -> void throws unknown @@ -18,5 +17,5 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__06_codegen.snap index c67b557f1a..1e3c8c0f03 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_throwing_body/baml_tests__test_expr_throwing_body__06_codegen.snap @@ -9,10 +9,10 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "throwing body becomes failure" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__03_hir.snap index e1ac52b6a1..e4a066a934 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__03_hir.snap @@ -2,6 +2,6 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("with quorum", () -> void { { let result = "hello" } assert.not_null(result) }, testing.Quorum(5, 3)) } null } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__04_tir.snap index 02bba46922..fae7da4f81 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__04_tir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 35221 --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("with quorum", () -> void { ... }, testing.Quorum(5, 3)) : void () -> void { ... } : () -> void throws unknown @@ -15,5 +14,5 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { } !! 23..38: unresolved name: Quorum } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__06_codegen.snap index 340cc51b3d..5167693757 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_with_runner/baml_tests__test_expr_with_runner__06_codegen.snap @@ -9,7 +9,7 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_const 5 load_const 3 load_const null @@ -17,7 +17,7 @@ function user.$init_test_24(registry: testing.TestCollector) -> null { store_var _4 load_var registry load_const "with quorum" - make_closure ., 0 + make_closure ., 0 load_var _4 call testing.TestCollector.register_test pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__03_hir.snap index e75671c62c..875fba56b6 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__03_hir.snap @@ -2,6 +2,6 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("wrong runner type", () -> void { { } assert.is_true(true) }, 42); registry.register_test("string as runner", () -> void { { } assert.is_true(true) }, "not a runner"); registry.register_test_set("wrong testset runner", (testset: testing.TestCollector) -> void { { testset.register_test("inner", () -> { { } assert.is_true(true) }, null) } null }, 42) } null } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__04_tir.snap index 732b3f3f73..50cf40ed40 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__04_tir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 35546 --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("wrong runner type", () -> void { ... }, 42) : void () -> void { ... } : () -> void throws unknown @@ -27,11 +26,11 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { !! 237..251: type mismatch: expected testing.TestRunner?, got "not a runner" !! 316..318: type mismatch: expected testing.TestSetRunner?, got 42 } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__06_codegen.snap index d0b69cfbe9..34409ad8eb 100644 --- a/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_expr_wrong_runner/baml_tests__test_expr_wrong_runner__06_codegen.snap @@ -9,22 +9,22 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "wrong runner type" - make_closure ., 0 + make_closure ., 0 load_const 42 call testing.TestCollector.register_test pop 1 load_var registry load_const "string as runner" - make_closure ., 0 + make_closure ., 0 load_const "not a runner" call testing.TestCollector.register_test pop 1 load_var registry load_const "wrong testset runner" - make_closure ., 0 + make_closure ., 0 load_const 42 call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__03_hir.snap index a70f571dd4..cc2c18975f 100644 --- a/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__03_hir.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("top level is fine", () -> void { { } assert.is_true(true) }, null); registry.register_test_set("top level set is ...", (testset: testing.TestCollector) -> void { { testset.register_test("nested is fine", () -> { { } assert.is_true(true) }, null) } null }, null) } null } function user.another() -> null [expr] { diff --git a/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__04_tir.snap index 4117641116..3467c314d5 100644 --- a/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__04_tir.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 35871 --- === TIR2 === function user.helper() -> null throws never { @@ -15,7 +14,7 @@ function user.another() -> null throws never { } !! 178..273: missing return: expected `null` } -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("top level is fine", () -> void { ... }, null) : void () -> void { ... } : () -> void throws unknown @@ -31,9 +30,9 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__06_codegen.snap index 62bf8e00c3..5b6ca01e35 100644 --- a/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_invalid_contexts/baml_tests__test_invalid_contexts__06_codegen.snap @@ -9,16 +9,16 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "top level is fine" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 load_var registry load_const "top level set is fine" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__03_hir.snap index bf62c774d9..922b0fae70 100644 --- a/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__03_hir.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("new style", () -> void { { let result = "hello" } assert.not_null(result) }, null) } null } function user.Greet(name: string) -> string [expr] { diff --git a/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__04_5_mir.snap index 03b0ea8535..e63f9d429a 100644 --- a/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 36237 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -26,7 +25,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .() -> null { +fn .() -> null { // Locals: let _0: null // _0 // return diff --git a/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__04_tir.snap index d9cd312028..fda52867b9 100644 --- a/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__04_tir.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 36196 --- === TIR2 === function user.Greet(name: string) -> string throws never { @@ -8,7 +7,7 @@ function user.Greet(name: string) -> string throws never { "Hello, {name}!" : "Hello, {name}!" } } -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("new style", () -> void { ... }, null) : void () -> void { ... } : () -> void throws unknown @@ -19,5 +18,5 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__06_codegen.snap index bfb71eb8b1..f628a371fd 100644 --- a/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_old_and_new/baml_tests__test_old_and_new__06_codegen.snap @@ -9,10 +9,10 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "new style" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__03_hir.snap index 32c76beb65..489d1b20e9 100644 --- a/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__03_hir.snap @@ -2,6 +2,6 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("raw string name", () -> void { { } assert.is_true(true) }, null); registry.register_test("has \"quotes\" inside", () -> void { { } assert.is_true(true) }, null); registry.register_test_set("raw testset name", (testset: testing.TestCollector) -> void { { testset.register_test("nested raw name", () -> { { } assert.is_true(true) }, null) } null }, null) } null } diff --git a/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__04_5_mir.snap index 2da51a0d0f..0a4d24a28d 100644 --- a/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 36562 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -40,7 +39,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .() -> null { +fn .() -> null { // Locals: let _0: null // _0 // return @@ -54,7 +53,7 @@ fn .() -> null { } // lambda[1] -fn .() -> null { +fn .() -> null { // Locals: let _0: null // _0 // return @@ -68,7 +67,7 @@ fn .() -> null { } // lambda[2] -fn .(testset: testing.TestCollector) -> null { +fn .(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -91,7 +90,7 @@ fn .(testset: testing.TestCollector) -> null { } // lambda[0] -fn ., 3)>() -> null { +fn ., 3)>() -> null { // Locals: let _0: null // _0 // return diff --git a/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__04_tir.snap index 6185c12cf7..90122ec977 100644 --- a/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__04_tir.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("raw string name", () -> void { ... }, null) : void () -> void { ... } : () -> void throws unknown @@ -23,11 +23,11 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__06_codegen.snap index 3cfe2a1edc..762b8876f7 100644 --- a/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_raw_string_name/baml_tests__test_raw_string_name__06_codegen.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 36997 --- function $init_test() -> null { load_var ?1 @@ -10,22 +9,22 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "raw string name" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 load_var registry load_const "has \"quotes\" inside" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 load_var registry load_const "raw testset name" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__03_hir.snap index b7bf14fed5..6d466d0184 100644 --- a/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__03_hir.snap @@ -8,7 +8,7 @@ class user.Foo { class user.HasWith { with: int } -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("with as field", () -> void { { let h = user.HasWith { with: 1 } } assert.equal(h.with, 1) }, null) } null } function user.make_foo() -> user.Foo [expr] { diff --git a/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__04_5_mir.snap index 5013e3caf5..3fad18b432 100644 --- a/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 36887 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -26,14 +25,14 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .() -> null { +fn .() -> null { // Locals: let _0: null // _0 // return let _1: HasWith // h let _2: int bb0: { - _1 = HasWith { const 1_i64 }; + _1 = user.HasWith { const 1_i64 }; _2 = copy _1.0; _0 = call const fn assert.equal(copy _2, const 1_i64) -> [bb1]; } @@ -48,7 +47,7 @@ fn user.make_foo() -> Foo { let _0: Foo // _0 // return bb0: { - _0 = Foo { const 1_i64 }; + _0 = user.Foo { const 1_i64 }; goto -> bb1; } diff --git a/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__04_tir.snap index e48fb3f036..ccc5c31aa8 100644 --- a/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__04_tir.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 36846 --- === TIR2 === class user.Foo { @@ -20,7 +19,7 @@ function user.use_with_as_var() -> int throws never { class user.HasWith { with: int } -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("with as field", () -> void { ... }, null) : void () -> void { ... } : () -> void throws unknown @@ -31,7 +30,7 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } class user.Foo$stream { x: null | int diff --git a/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__06_codegen.snap index cd5d53eb69..16d83a8719 100644 --- a/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_with_not_keyword/baml_tests__test_with_not_keyword__06_codegen.snap @@ -9,10 +9,10 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "with as field" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 @@ -21,7 +21,7 @@ function user.$init_test_24(registry: testing.TestCollector) -> null { } function user.make_foo() -> Foo { - alloc_instance Foo + alloc_instance user.Foo load_const 1 init_field .x return diff --git a/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__03_hir.snap b/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__03_hir.snap index edf4a33778..2f1f56af89 100644 --- a/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__03_hir.snap @@ -5,6 +5,6 @@ source: crates/baml_tests/src/generated_tests.rs class user.MyRunner { threshold: float } -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test("simple runner", () -> void { { } assert.is_true(true) }, my_runner); registry.register_test("call runner", () -> void { { } assert.is_true(true) }, testing.Quorum(5, 3)); registry.register_test("constructor runner", () -> void { { } assert.is_true(true) }, user.MyRunner { threshold: 0.5 }) } null } diff --git a/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__04_tir.snap b/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__04_tir.snap index 5ecc2c2cd5..9af4d46ee1 100644 --- a/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__04_tir.snap @@ -1,12 +1,11 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 37171 --- === TIR2 === class user.MyRunner { threshold: float } -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test("simple runner", () -> void { ... }, my_runner) : void () -> void { ... } : () -> void throws unknown @@ -28,11 +27,11 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { !! 384..393: unresolved name: my_runner !! 512..527: unresolved name: Quorum } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } class user.MyRunner$stream { threshold: null | float diff --git a/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__06_codegen.snap index bea06cc864..b363123918 100644 --- a/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/test_with_runner_ambiguity/baml_tests__test_with_runner_ambiguity__06_codegen.snap @@ -9,10 +9,10 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "simple runner" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test pop 1 @@ -23,14 +23,14 @@ function user.$init_test_24(registry: testing.TestCollector) -> null { store_var _6 load_var registry load_const "call runner" - make_closure ., 0 + make_closure ., 0 load_var _6 call testing.TestCollector.register_test pop 1 load_var registry load_const "constructor runner" - make_closure ., 0 - alloc_instance MyRunner + make_closure ., 0 + alloc_instance user.MyRunner load_const 0.5 init_field .threshold call testing.TestCollector.register_test diff --git a/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__03_hir.snap b/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__03_hir.snap index b10d213c70..a36ce08753 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__03_hir.snap @@ -2,6 +2,6 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test_set("basic group", (testset: testing.TestCollector) -> void { { testset.register_test("first", () -> { { } assert.is_true(true) }, null); testset.register_test("second", () -> { { } assert.is_true(true) }, null) } null }, null) } null } diff --git a/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__04_5_mir.snap index 26fb936a69..3ace765218 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 37537 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -26,7 +25,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .(testset: testing.TestCollector) -> null { +fn .(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -56,7 +55,7 @@ fn .(testset: testing.TestCollector) -> null { } // lambda[0] -fn ., 1)>() -> null { +fn ., 1)>() -> null { // Locals: let _0: null // _0 // return @@ -70,7 +69,7 @@ fn ., 1)>() -> null { } // lambda[1] -fn ., 2)>() -> null { +fn ., 2)>() -> null { // Locals: let _0: null // _0 // return diff --git a/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__04_tir.snap b/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__04_tir.snap index 7fd7d6fa78..ef9a485d89 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__04_tir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 37496 --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test_set("basic group", (testset: testing.TestCollector) -> void { ... }, null) : void (testset: testing.TestCollector) -> void { ... } : (testset: testing.TestCollector) -> void throws unknown @@ -15,9 +14,9 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__06_codegen.snap index 97f9fc1e15..19c97ee73e 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_basic/baml_tests__testset_basic__06_codegen.snap @@ -9,10 +9,10 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "basic group" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__03_hir.snap b/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__03_hir.snap index c39d898cef..c6ef3028c7 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__03_hir.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test_set("dynamic tests", (testset: testing.TestCollector) -> void { { let cases = ["hello", "world", "foo"]; for case in cases { testset.register_test("check case", () -> { { } assert.not_null(case) }, null) } } null }, null); registry.register_test_set("conditional tests", (testset: testing.TestCollector) -> void { { { let run_slow = false; testset.register_test("always runs", () -> { { } assert.is_true(true) }, null) } if (run_slow) { testset.register_test("only when slow", () -> { { } assert.is_true(true) }, null) } } null }, null) } null } diff --git a/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__04_5_mir.snap index 58644e6cd3..3c0b0ba42d 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 38844 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -33,7 +32,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .(testset: testing.TestCollector) -> null { +fn .(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -84,7 +83,7 @@ fn .(testset: testing.TestCollector) -> null { } // lambda[0] -fn ., 1)>() -> null { +fn ., 1)>() -> null { // Locals: let _0: null // _0 // return let _1: string @@ -100,7 +99,7 @@ fn ., 1)>() -> null { } // lambda[1] -fn .(testset: testing.TestCollector) -> null { +fn .(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -138,7 +137,7 @@ fn .(testset: testing.TestCollector) -> null { } // lambda[0] -fn ., 3)>() -> null { +fn ., 3)>() -> null { // Locals: let _0: null // _0 // return @@ -152,7 +151,7 @@ fn ., 3)>() -> null { } // lambda[1] -fn ., 4)>() -> null { +fn ., 4)>() -> null { // Locals: let _0: null // _0 // return diff --git a/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__04_tir.snap b/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__04_tir.snap index b982cad36f..a42edca9b8 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__04_tir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 37821 --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test_set("dynamic tests", (testset: testing.TestCollector) -> void { ... }, null) : void (testset: testing.TestCollector) -> void { ... } : (testset: testing.TestCollector) -> void throws unknown @@ -31,13 +30,13 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__06_codegen.snap index 59874c614a..e9dec74096 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_dynamic/baml_tests__testset_dynamic__06_codegen.snap @@ -9,16 +9,16 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "dynamic tests" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 load_var registry load_const "conditional tests" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__03_hir.snap b/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__03_hir.snap index 38436babaa..bb98b97308 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__03_hir.snap @@ -2,6 +2,6 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test_set("all evals", (testset: testing.TestCollector) -> void { { testset.register_test_set("normal cases", (testset: testing.TestCollector) -> { { testset.register_test("case one", () -> { { } assert.is_true(true) }, null) } null }, null); testset.register_test_set("hard cases", (testset: testing.TestCollector) -> { { testset.register_test("case two", () -> { { } assert.is_true(true) }, null) } null }, null) } null }, null) } null } diff --git a/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__04_5_mir.snap index b09287820c..f02fd0d206 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 38187 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -26,7 +25,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .(testset: testing.TestCollector) -> null { +fn .(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -56,7 +55,7 @@ fn .(testset: testing.TestCollector) -> null { } // lambda[0] -fn ., 1)>(testset: testing.TestCollector) -> null { +fn ., 1)>(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -79,7 +78,7 @@ fn ., 1)>(testset: testing.TestCollector) -> n } // lambda[0] -fn ., 1)>, 2)>() -> null { +fn ., 1)>, 2)>() -> null { // Locals: let _0: null // _0 // return @@ -93,7 +92,7 @@ fn ., 1)>, 2)>() -> null { } // lambda[1] -fn ., 3)>(testset: testing.TestCollector) -> null { +fn ., 3)>(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -116,7 +115,7 @@ fn ., 3)>(testset: testing.TestCollector) -> n } // lambda[0] -fn ., 3)>, 4)>() -> null { +fn ., 3)>, 4)>() -> null { // Locals: let _0: null // _0 // return diff --git a/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__04_tir.snap b/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__04_tir.snap index 96c36d0fec..f7443bd35e 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__04_tir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 38146 --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test_set("all evals", (testset: testing.TestCollector) -> void { ... }, null) : void (testset: testing.TestCollector) -> void { ... } : (testset: testing.TestCollector) -> void throws unknown @@ -15,13 +14,13 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__06_codegen.snap index 170338bf53..f203fab51e 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_nested/baml_tests__testset_nested__06_codegen.snap @@ -9,10 +9,10 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "all evals" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__03_hir.snap b/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__03_hir.snap index eb4c19d4f9..7c510d6b79 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__03_hir.snap @@ -7,7 +7,7 @@ class user.Sentiment { confidence: float reasoning: string } -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test_set("test", (testset: testing.TestCollector) -> void { { let topics = ["happy", "sad"]; for sentiments in topics { testset.register_test_set(sentiments, (testset: testing.TestCollector) -> { { let req = baml.http.fetch("http://localhost:..." Add sentiments); let data = req.text(); let tests = GenerateTests$parse(data); for ex in tests { testset.register_test(ex, () -> { { let result = ClassifySentiment("hi"); assert.equal(result.feeling, "positive") } }, null) } } null }, null) }; testset.register_test_set("vibes", (testset: testing.TestCollector) -> { { let topics = ["happy", "sad"]; for sentiments in topics { testset.register_test_set(sentiments, (testset: testing.TestCollector) -> { { let tests = GenerateTests(5, sentiments); for ex in tests { testset.register_test(ex, () -> { { let result = ClassifySentiment("hi"); assert.equal(result.feeling, "positive") } }, null) } } null }, null) } } null }, null) } null }, null) } null } function user.ClassifySentiment(text: string) -> user.Sentiment [llm] { diff --git a/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__04_5_mir.snap index da4bb034b8..06d7ff3673 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 39494 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -26,7 +25,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .(testset: testing.TestCollector) -> null { +fn .(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -86,7 +85,7 @@ fn .(testset: testing.TestCollector) -> null { } // lambda[0] -fn ., 1)>(testset: testing.TestCollector) -> null { +fn ., 1)>(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -168,7 +167,7 @@ fn ., 1)>(testset: testing.TestCollector) -> n } // lambda[0] -fn ., 1)>, 2)>() -> null { +fn ., 1)>, 2)>() -> null { // Locals: let _0: null // _0 // return let _1: Sentiment // result @@ -195,7 +194,7 @@ fn ., 1)>, 2)>() -> null { } // lambda[1] -fn ., 3)>(testset: testing.TestCollector) -> null { +fn ., 3)>(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -248,7 +247,7 @@ fn ., 3)>(testset: testing.TestCollector) -> n } // lambda[0] -fn ., 3)>, 4)>(testset: testing.TestCollector) -> null { +fn ., 3)>, 4)>(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -306,7 +305,7 @@ fn ., 3)>, 4)>(testset: testing.TestCo } // lambda[0] -fn ., 3)>, 4)>, 5)>() -> null { +fn ., 3)>, 4)>, 5)>() -> null { // Locals: let _0: null // _0 // return let _1: Sentiment // result @@ -537,7 +536,7 @@ fn user.Foo() -> string | image { fn user.GPT4o$new() -> null { // Locals: let _0: null // _0 // return - let _1: void + let _1: baml.llm.PrimitiveClientOptions let _2: string let _3: map let _4: map diff --git a/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__04_tir.snap b/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__04_tir.snap index a4a182bf79..5fa84a9ff1 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__04_tir.snap @@ -3,7 +3,7 @@ source: crates/baml_tests/src/generated_tests.rs --- === TIR2 === function user.GPT4o$new() -> ? throws never { - baml.llm.PrimitiveClient { name: "GPT4o", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4o", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: baml.env.get_or_panic("OPENAI_API_KEY"), provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : unknown + baml.llm.PrimitiveClient { name: "GPT4o", provider: "openai", options: baml.llm.PrimitiveClientOptions { model: "gpt-4o", base_url: null, allowed_role_metadata: null, finish_reason_allow_list: null, finish_reason_deny_list: null, supports_streaming: null, default_role: null, allowed_roles: null, remap_roles: null, api_key: baml.env.get_or_panic("OPENAI_API_KEY"), provider_options: null, media_url_handler: null, headers: map { }, query_params: map { }, request_body: map { } } } : baml.llm.PrimitiveClient } class user.Sentiment { feeling: string @@ -69,7 +69,7 @@ function user.ClassifySentiment2$build_request_stream(text: string) -> baml.http function user.ClassifySentiment2$parse(json: string) -> string throws never { baml.llm.parse("ClassifySentiment2", json) : string } -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test_set("test", (testset: testing.TestCollector) -> void { ... }, null) : void (testset: testing.TestCollector) -> void { ... } : (testset: testing.TestCollector) -> void throws unknown @@ -85,17 +85,17 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } class user.Sentiment$stream { feeling: null | string diff --git a/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__06_codegen.snap index 236a24855c..8f76f01490 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_vibes_nested/baml_tests__testset_vibes_nested__06_codegen.snap @@ -16,10 +16,10 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "test" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__03_hir.snap b/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__03_hir.snap index 0a24d13a76..3e35766299 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__03_hir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__03_hir.snap @@ -2,7 +2,7 @@ source: crates/baml_tests/src/generated_tests.rs --- === HIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? [expr] { +function user.$init_test_25(registry: testing.TestCollector) -> ? [expr] { { registry.register_test_set("with shared setup", (testset: testing.TestCollector) -> void { { let base_url = "https://api.examp..."; let timeout = 5000; testset.register_test("uses setup vars", () -> { { assert.not_null(base_url) } assert.equal(timeout, 5000) }, null); testset.register_test("also uses setup", () -> { { } assert.contains(base_url, "example") }, null) } null }, null) } null } diff --git a/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__04_5_mir.snap b/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__04_5_mir.snap index 19a5436613..5c97d0c476 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__04_5_mir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__04_5_mir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 39819 --- === MIR2 === -fn user.$init_test_24(registry: testing.TestCollector) -> null { +fn user.$init_test_25(registry: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // registry // param @@ -26,7 +25,7 @@ fn user.$init_test_24(registry: testing.TestCollector) -> null { } // lambda[0] -fn .(testset: testing.TestCollector) -> null { +fn .(testset: testing.TestCollector) -> null { // Locals: let _0: null // _0 // return let _1: testing.TestCollector // testset // param @@ -60,7 +59,7 @@ fn .(testset: testing.TestCollector) -> null { } // lambda[0] -fn ., 1)>() -> null { +fn ., 1)>() -> null { // Locals: let _0: null // _0 // return let _1: null @@ -83,7 +82,7 @@ fn ., 1)>() -> null { } // lambda[1] -fn ., 2)>() -> null { +fn ., 2)>() -> null { // Locals: let _0: null // _0 // return let _1: string diff --git a/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__04_tir.snap b/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__04_tir.snap index c0e9f9526c..e1299af788 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__04_tir.snap @@ -1,9 +1,8 @@ --- source: crates/baml_tests/src/generated_tests.rs -assertion_line: 38796 --- === TIR2 === -function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { +function user.$init_test_25(registry: testing.TestCollector) -> ? throws never { { : null registry.register_test_set("with shared setup", (testset: testing.TestCollector) -> void { ... }, null) : void (testset: testing.TestCollector) -> void { ... } : (testset: testing.TestCollector) -> void throws unknown @@ -17,9 +16,9 @@ function user.$init_test_24(registry: testing.TestCollector) -> ? throws never { null : null } } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } -lambda user.$init_test_24 { +lambda user.$init_test_25 { } diff --git a/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__06_codegen.snap index dc1197b00f..d79a38363b 100644 --- a/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/testset_with_setup/baml_tests__testset_with_setup__06_codegen.snap @@ -9,10 +9,10 @@ function $init_test() -> null { return } -function user.$init_test_24(registry: testing.TestCollector) -> null { +function user.$init_test_25(registry: testing.TestCollector) -> null { load_var registry load_const "with shared setup" - make_closure ., 0 + make_closure ., 0 load_const null call testing.TestCollector.register_test_set pop 1 diff --git a/baml_language/crates/baml_tests/snapshots/type_aliases/baml_tests__type_aliases__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/type_aliases/baml_tests__type_aliases__06_codegen.snap index fe077ad249..80004e1639 100644 --- a/baml_language/crates/baml_tests/snapshots/type_aliases/baml_tests__type_aliases__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/type_aliases/baml_tests__type_aliases__06_codegen.snap @@ -12,7 +12,7 @@ function user.Baz() -> Json { } function user.EchoJSON(i: JSON) -> JSON { - alloc_instance NotJSON + alloc_instance user.NotJSON load_const "Whoops" init_field .inner return diff --git a/baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_tir.snap b/baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_tir.snap index d7ec58aaac..b120c2e078 100644 --- a/baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__04_tir.snap @@ -24,7 +24,7 @@ function user.TypeBuilderFn$stream(from_text: string) -> baml.llm.Stream } function user.TypeBuilderFn$parse_stream(sse: baml.http.SseStream) -> baml.llm.Stream throws never { - baml.llm.Client { name: "openai/gpt-4o-mini", client_type: baml.llm.ClientType.Primitive, sub_clients: [], retry: null, counter: 0 }.__make_stream(sse, "TypeBuilderFn") : unknown + baml.llm.Client { name: "openai/gpt-4o-mini", client_type: baml.llm.ClientType.Primitive, sub_clients: [], retry: null, counter: 0 }.__make_stream(sse, "TypeBuilderFn") : baml.llm.Stream } class user.Resume$stream { name: null | string diff --git a/baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__06_codegen.snap index b5a2722378..b1569d2cc4 100644 --- a/baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/type_builder_errors/baml_tests__type_builder_errors__06_codegen.snap @@ -72,10 +72,21 @@ function user.TypeBuilderFn$parse(json: string) -> Resume { } function user.TypeBuilderFn$parse_stream(sse: baml.http.SseStream) -> baml.llm.Stream { + alloc_instance baml.llm.Client + load_const "openai/gpt-4o-mini" + init_field .name + load_const baml.llm.ClientType.Primitive + alloc_variant baml.llm.ClientType + init_field .client_type + alloc_array 0 + init_field .sub_clients + load_const null + init_field .retry + load_const 0 + init_field .counter load_var sse load_const "TypeBuilderFn" - load_const null - call_indirect + call baml.llm.Client.__make_stream return } diff --git a/baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__04_tir.snap b/baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__04_tir.snap index b3c25ded1c..293f7cdf4e 100644 --- a/baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__04_tir.snap +++ b/baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__04_tir.snap @@ -25,7 +25,7 @@ function user.Fn$stream() -> baml.llm.Stream throws never baml.llm.stream_llm_function(baml.llm.Client { name: "openai/gpt-4o", client_type: baml.llm.ClientType.Primitive, sub_clients: [], retry: null, counter: 0 }, "Fn", map { }) : baml.llm.Stream } function user.Fn$parse_stream(sse: baml.http.SseStream) -> baml.llm.Stream throws never { - baml.llm.Client { name: "openai/gpt-4o", client_type: baml.llm.ClientType.Primitive, sub_clients: [], retry: null, counter: 0 }.__make_stream(sse, "Fn") : unknown + baml.llm.Client { name: "openai/gpt-4o", client_type: baml.llm.ClientType.Primitive, sub_clients: [], retry: null, counter: 0 }.__make_stream(sse, "Fn") : baml.llm.Stream } class user.TopLevelClass$stream { a: null | string diff --git a/baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__06_codegen.snap b/baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__06_codegen.snap index 2ea99c9800..4f6c46a152 100644 --- a/baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__06_codegen.snap +++ b/baml_language/crates/baml_tests/snapshots/type_builder_test/baml_tests__type_builder_test__06_codegen.snap @@ -66,10 +66,21 @@ function user.Fn$parse(json: string) -> string { } function user.Fn$parse_stream(sse: baml.http.SseStream) -> baml.llm.Stream { + alloc_instance baml.llm.Client + load_const "openai/gpt-4o" + init_field .name + load_const baml.llm.ClientType.Primitive + alloc_variant baml.llm.ClientType + init_field .client_type + alloc_array 0 + init_field .sub_clients + load_const null + init_field .retry + load_const 0 + init_field .counter load_var sse load_const "Fn" - load_const null - call_indirect + call baml.llm.Client.__make_stream return } diff --git a/baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap b/baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap index e7aaccd248..606d5ec47e 100644 --- a/baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap +++ b/baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap @@ -28,14 +28,22 @@ namespace baml.errors: namespace baml.events: function send namespace baml.fs: + class DirEntry { methods: [] } class File { methods: [text, bytes, read, read_bytes, close, seek_from, write, write_bytes] } + class MkdirOptions { methods: [] } function exists + function mkdir function open function read + function read_dir function remove function size function write function write_bytes +namespace baml.glob: + class Glob { methods: [scan, matches] } + class ScanOptions { methods: [] } + function new namespace baml.http: class Request { methods: [] } class Response { methods: [text, bytes, ok] } diff --git a/baml_language/crates/baml_tests/tests/assignments.rs b/baml_language/crates/baml_tests/tests/assignments.rs index d475ddd1f6..d0196f87f6 100644 --- a/baml_language/crates/baml_tests/tests/assignments.rs +++ b/baml_language/crates/baml_tests/tests/assignments.rs @@ -276,7 +276,7 @@ async fn field_assignment_add_assign() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Counter + alloc_instance user.Counter load_const 10 init_field .value store_var c @@ -312,7 +312,7 @@ async fn field_assignment_sub_assign() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Counter + alloc_instance user.Counter load_const 20 init_field .value store_var c @@ -348,7 +348,7 @@ async fn field_assignment_mul_assign() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Counter + alloc_instance user.Counter load_const 7 init_field .value store_var c @@ -384,7 +384,7 @@ async fn field_assignment_div_assign() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Counter + alloc_instance user.Counter load_const 24 init_field .value store_var c @@ -420,7 +420,7 @@ async fn field_assignment_mod_assign() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Counter + alloc_instance user.Counter load_const 17 init_field .value store_var c @@ -457,7 +457,7 @@ async fn field_assignment_simple() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Data + alloc_instance user.Data load_const 100 init_field .value load_const true @@ -495,7 +495,7 @@ async fn field_assignment_multiple_ops() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Stats + alloc_instance user.Stats load_const 10 init_field .score store_var s @@ -553,8 +553,8 @@ async fn nested_field_assignment_simple() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 10 init_field .value init_field .inner @@ -594,8 +594,8 @@ async fn nested_field_assignment_compound() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 10 init_field .value init_field .inner @@ -638,12 +638,12 @@ async fn field_assignment_object_field() { insta::assert_snapshot!(output.bytecode, @" function main() -> bool { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 10 init_field .value init_field .inner - alloc_instance Inner + alloc_instance user.Inner load_const 20 init_field .value store_field .inner @@ -679,13 +679,13 @@ async fn array_element_field_assignment() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Item + alloc_instance user.Item load_const 10 init_field .count - alloc_instance Item + alloc_instance user.Item load_const 20 init_field .count - alloc_instance Item + alloc_instance user.Item load_const 30 init_field .count alloc_array 3 @@ -974,8 +974,8 @@ async fn method_call_field_assignment_with_copy() { } function main() -> int { - alloc_instance Factory - alloc_instance Counter + alloc_instance user.Factory + alloc_instance user.Counter load_const 10 init_field .value init_field .counter diff --git a/baml_language/crates/baml_tests/tests/builtins.rs b/baml_language/crates/baml_tests/tests/builtins.rs index df27cda7b6..77a14bfd1a 100644 --- a/baml_language/crates/baml_tests/tests/builtins.rs +++ b/baml_language/crates/baml_tests/tests/builtins.rs @@ -88,12 +88,12 @@ async fn any_value_to_string() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> string { - alloc_instance Person + alloc_instance user.Person load_const "Alice" init_field .name load_const 25 init_field .age - alloc_instance Point + alloc_instance user.Point load_const 10 init_field .x load_const 20 diff --git a/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded.snap b/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded.snap index d8d6bf398c..4811928a01 100644 --- a/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded.snap +++ b/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded.snap @@ -113,7 +113,7 @@ function testing.TestCollector.find_testset(self: null, name: string) -> testing } function testing.TestCollector.new(prefix: string) -> testing.TestCollector { - 23 0 alloc_instance 117 (TestCollector) + 23 0 alloc_instance 125 (testing.TestCollector) 1 load_var 1 (prefix) 2 init_field 0 (prefix) 3 alloc_array 0 @@ -176,7 +176,7 @@ function testing.TestCollector.register_test(self: null, name: string, body: () 45 load_var 6 (count) 46 load_const 5 (1) 47 bin_op + - 48 call 114 (baml.unstable.string) + 48 call 119 (baml.unstable.string) 49 store_var 13 (_30) 50 load_var 12 (_28) 51 load_var 13 (_30) @@ -185,7 +185,7 @@ function testing.TestCollector.register_test(self: null, name: string, body: () 34 54 load_var 1 (self) 55 load_field 1 (tests) - 56 alloc_instance 109 (TestRegistration) + 56 alloc_instance 117 (testing.TestRegistration) 57 load_var 11 (final_name) 58 init_field 0 (name) 59 load_var 3 (body) @@ -280,7 +280,7 @@ function testing.TestCollector.register_test_set(self: null, name: string, colle 45 load_var 6 (count) 46 load_const 5 (1) 47 bin_op + - 48 call 114 (baml.unstable.string) + 48 call 119 (baml.unstable.string) 49 store_var 13 (_30) 50 load_var 12 (_28) 51 load_var 13 (_30) @@ -289,7 +289,7 @@ function testing.TestCollector.register_test_set(self: null, name: string, colle 45 54 load_var 1 (self) 55 load_field 2 (testsets) - 56 alloc_instance 111 (TestSetRegistration) + 56 alloc_instance 119 (testing.TestSetRegistration) 57 load_var 11 (final_name) 58 init_field 0 (name) 59 load_var 3 (collector) @@ -392,7 +392,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S 164 49 load_var 12 (sub) 50 load_var 2 (name) - 51 call 157 (testing.TestRegistry.expand_set) + 51 call 162 (testing.TestRegistry.expand_set) 52 jump +49 (to 101) 144 53 load_var 3 (_3) @@ -416,7 +416,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S 147 68 call 67 (baml.sys.now_ms) 69 store_var 6 (start) - 148 70 alloc_instance 117 (TestCollector) + 148 70 alloc_instance 125 (testing.TestCollector) 71 load_var 2 (name) 72 init_field 0 (prefix) 73 alloc_array 0 @@ -438,7 +438,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S 86 load_field 1 (expansions) 87 load_var 2 (name) - 151 88 alloc_instance 116 (TestRegistry) + 151 88 alloc_instance 124 (testing.TestRegistry) 152 89 load_var 7 (sub_collector) 90 init_field 0 (collector) @@ -454,12 +454,12 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S 98 pop 1 157 99 load_var 1 (self) - 100 call 165 (testing.TestRegistry.serialize) + 100 call 170 (testing.TestRegistry.serialize) 101 return } function testing.TestRegistry.new(collector: testing.TestCollector) -> testing.TestRegistry { - 87 0 alloc_instance 116 (TestRegistry) + 87 0 alloc_instance 124 (testing.TestRegistry) 1 load_var 1 (collector) 2 init_field 0 (collector) @@ -532,7 +532,7 @@ function testing.TestRegistry.run_test(self: null, name: string) -> testing.Test 135 49 load_var 9 (sub) 50 load_var 2 (name) - 51 call 167 (testing.TestRegistry.run_test) + 51 call 172 (testing.TestRegistry.run_test) 52 jump +21 (to 73) 124 53 load_var 3 (_3) @@ -557,7 +557,7 @@ function testing.TestRegistry.run_test(self: null, name: string) -> testing.Test 69 load_field 1 (body) 70 load_var 5 (t) 71 load_field 2 (runner) - 72 call 166 (testing.run_test) + 72 call 171 (testing.run_test) 73 return } @@ -616,7 +616,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | 45 pop_jump_if_false +30 (to 75) 115 46 load_var 2 (items) - 47 alloc_instance 110 (SerializedTest) + 47 alloc_instance 118 (testing.SerializedTest) 48 load_const 3 ("lazyTestSet") 49 init_field 0 (type) 50 load_var 7 (ts) @@ -634,11 +634,11 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | 60 store_var 10 (_25) 110 61 load_var 9 (sub) - 62 call 165 (testing.TestRegistry.serialize) + 62 call 170 (testing.TestRegistry.serialize) 63 store_var 11 (_26) 108 64 load_var 2 (items) - 65 alloc_instance 108 (SerializedTestSet) + 65 alloc_instance 116 (testing.SerializedTestSet) 66 load_var 10 (_25) 67 init_field 0 (name) 68 load_var 11 (_26) @@ -657,7 +657,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | 79 jump -59 (to 20) 102 80 load_var 2 (items) - 81 alloc_instance 110 (SerializedTest) + 81 alloc_instance 118 (testing.SerializedTest) 82 load_const 5 ("test") 83 init_field 0 (type) @@ -681,7 +681,7 @@ function testing.run_test(body: () -> void throws unknown, runner: ((() -> testi 2 store_var 1 173 3 load_var 1 (body) - 4 make_closure 333 1 + 4 make_closure 346 1 5 store_var 3 (base_run) 188 6 load_var 2 (runner) @@ -740,7 +740,7 @@ function user.User.promote(self: null, bonus: int) -> Report { 8 call 0 (user.score) 9 store_var 3 (base) - 12 10 alloc_instance 5 (Report) + 12 10 alloc_instance 5 (user.Report) 11 11 load_var 3 (base) 12 load_field 0 (score) @@ -930,7 +930,7 @@ function user.score(input: User | ErrorInfo, threshold: int) -> Report { 93 load_var 8 (total) 94 store_array_element - 85 95 alloc_instance 5 (Report) + 85 95 alloc_instance 5 (user.Report) 81 96 load_var 10 (scores) 97 load_const 6 (0) diff --git a/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded_unoptimized.snap b/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded_unoptimized.snap index a9036e778d..281a1d729d 100644 --- a/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded_unoptimized.snap +++ b/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded_unoptimized.snap @@ -115,7 +115,7 @@ function testing.TestCollector.find_testset(self: null, name: string) -> testing } function testing.TestCollector.new(prefix: string) -> testing.TestCollector { - 23 0 alloc_instance 117 (TestCollector) + 23 0 alloc_instance 125 (testing.TestCollector) 1 load_var 1 (prefix) 2 init_field 0 (prefix) 3 alloc_array 0 @@ -180,7 +180,7 @@ function testing.TestCollector.register_test(self: null, name: string, body: () 45 load_var 7 (count) 46 load_const 5 (1) 47 bin_op + - 48 call 114 (baml.unstable.string) + 48 call 119 (baml.unstable.string) 49 store_var 14 (_30) 50 load_var 13 (_28) 51 load_var 14 (_30) @@ -189,7 +189,7 @@ function testing.TestCollector.register_test(self: null, name: string, body: () 34 54 load_var 1 (self) 55 load_field 1 (tests) - 56 alloc_instance 109 (TestRegistration) + 56 alloc_instance 117 (testing.TestRegistration) 57 load_var 12 (final_name) 58 init_field 0 (name) 59 load_var 3 (body) @@ -286,7 +286,7 @@ function testing.TestCollector.register_test_set(self: null, name: string, colle 45 load_var 7 (count) 46 load_const 5 (1) 47 bin_op + - 48 call 114 (baml.unstable.string) + 48 call 119 (baml.unstable.string) 49 store_var 14 (_30) 50 load_var 13 (_28) 51 load_var 14 (_30) @@ -295,7 +295,7 @@ function testing.TestCollector.register_test_set(self: null, name: string, colle 45 54 load_var 1 (self) 55 load_field 2 (testsets) - 56 alloc_instance 111 (TestSetRegistration) + 56 alloc_instance 119 (testing.TestSetRegistration) 57 load_var 12 (final_name) 58 init_field 0 (name) 59 load_var 3 (collector) @@ -400,7 +400,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S 164 49 load_var 13 (sub) 50 load_var 2 (name) - 51 call 157 (testing.TestRegistry.expand_set) + 51 call 162 (testing.TestRegistry.expand_set) 52 jump +51 (to 103) 144 53 load_var 3 (_3) @@ -424,7 +424,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S 147 68 call 67 (baml.sys.now_ms) 69 store_var 6 (start) - 148 70 alloc_instance 117 (TestCollector) + 148 70 alloc_instance 125 (testing.TestCollector) 71 load_var 2 (name) 72 init_field 0 (prefix) 73 alloc_array 0 @@ -444,7 +444,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S 85 bin_op - 86 store_var 8 (elapsed) - 151 87 alloc_instance 116 (TestRegistry) + 151 87 alloc_instance 124 (testing.TestRegistry) 152 88 load_var 7 (sub_collector) 89 init_field 0 (collector) @@ -464,12 +464,12 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S 100 pop 1 157 101 load_var 1 (self) - 102 call 165 (testing.TestRegistry.serialize) + 102 call 170 (testing.TestRegistry.serialize) 103 return } function testing.TestRegistry.new(collector: testing.TestCollector) -> testing.TestRegistry { - 87 0 alloc_instance 116 (TestRegistry) + 87 0 alloc_instance 124 (testing.TestRegistry) 1 load_var 1 (collector) 2 init_field 0 (collector) @@ -544,7 +544,7 @@ function testing.TestRegistry.run_test(self: null, name: string) -> testing.Test 135 49 load_var 9 (sub) 50 load_var 2 (name) - 51 call 167 (testing.TestRegistry.run_test) + 51 call 172 (testing.TestRegistry.run_test) 52 jump +21 (to 73) 124 53 load_var 3 (_3) @@ -569,7 +569,7 @@ function testing.TestRegistry.run_test(self: null, name: string) -> testing.Test 69 load_field 1 (body) 70 load_var 5 (t) 71 load_field 2 (runner) - 72 call 166 (testing.run_test) + 72 call 171 (testing.run_test) 73 return } @@ -630,7 +630,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | 47 pop_jump_if_false +30 (to 77) 115 48 load_var 3 (items) - 49 alloc_instance 110 (SerializedTest) + 49 alloc_instance 118 (testing.SerializedTest) 50 load_const 3 ("lazyTestSet") 51 init_field 0 (type) 52 load_var 9 (ts) @@ -648,11 +648,11 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | 62 store_var 12 (_25) 110 63 load_var 11 (sub) - 64 call 165 (testing.TestRegistry.serialize) + 64 call 170 (testing.TestRegistry.serialize) 65 store_var 13 (_26) 108 66 load_var 3 (items) - 67 alloc_instance 108 (SerializedTestSet) + 67 alloc_instance 116 (testing.SerializedTestSet) 68 load_var 12 (_25) 69 init_field 0 (name) 70 load_var 13 (_26) @@ -676,7 +676,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | 85 store_var 6 (t) 102 86 load_var 3 (items) - 87 alloc_instance 110 (SerializedTest) + 87 alloc_instance 118 (testing.SerializedTest) 88 load_const 5 ("test") 89 init_field 0 (type) 90 load_var 6 (t) @@ -698,7 +698,7 @@ function testing.run_test(body: () -> void throws unknown, runner: ((() -> testi 2 store_var 1 173 3 load_var 1 (body) - 4 make_closure 333 1 + 4 make_closure 346 1 5 store_var 3 (base_run) 188 6 load_var 2 (runner) @@ -767,7 +767,7 @@ function user.User.promote(self: null, bonus: int) -> Report { 13 bin_op + 14 store_var 5 (new_score) - 12 15 alloc_instance 5 (Report) + 12 15 alloc_instance 5 (user.Report) 13 16 load_var 5 (new_score) 17 init_field 0 (score) @@ -985,7 +985,7 @@ function user.score(input: User | ErrorInfo, threshold: int) -> Report { 117 alloc_map 2 118 store_var 18 (breakdown) - 85 119 alloc_instance 5 (Report) + 85 119 alloc_instance 5 (user.Report) 86 120 load_var 17 (top) 121 init_field 0 (score) diff --git a/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_textual.snap b/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_textual.snap index b060567b03..1747c99685 100644 --- a/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_textual.snap +++ b/baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_textual.snap @@ -1,6 +1,5 @@ --- source: crates/baml_tests/tests/bytecode_format/main.rs -assertion_line: 41 --- function assert.contains(haystack: string, needle: string) -> null { load_var haystack @@ -131,7 +130,7 @@ function testing.TestCollector.find_testset(self: null, name: string) -> testing } function testing.TestCollector.new(prefix: string) -> testing.TestCollector { - alloc_instance TestCollector + alloc_instance testing.TestCollector load_var prefix init_field .prefix alloc_array 0 @@ -214,7 +213,7 @@ function testing.TestCollector.register_test(self: null, name: string, body: () L7: load_var self load_field .tests - alloc_instance TestRegistration + alloc_instance testing.TestRegistration load_var final_name init_field .name load_var body @@ -333,7 +332,7 @@ function testing.TestCollector.register_test_set(self: null, name: string, colle L7: load_var self load_field .testsets - alloc_instance TestSetRegistration + alloc_instance testing.TestSetRegistration load_var final_name init_field .name load_var collector @@ -470,7 +469,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S L9: call baml.sys.now_ms store_var start - alloc_instance TestCollector + alloc_instance testing.TestCollector load_var name init_field .prefix alloc_array 0 @@ -488,7 +487,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S load_var self load_field .expansions load_var name - alloc_instance TestRegistry + alloc_instance testing.TestRegistry load_var sub_collector init_field .collector alloc_map 0 @@ -507,7 +506,7 @@ function testing.TestRegistry.expand_set(self: null, name: string) -> (testing.S } function testing.TestRegistry.new(collector: testing.TestCollector) -> testing.TestRegistry { - alloc_instance TestRegistry + alloc_instance testing.TestRegistry load_var collector init_field .collector alloc_map 0 @@ -676,7 +675,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | cmp_op == pop_jump_if_false L7 load_var items - alloc_instance SerializedTest + alloc_instance testing.SerializedTest load_const "lazyTestSet" init_field .type load_var ts @@ -696,7 +695,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | call testing.TestRegistry.serialize store_var _26 load_var items - alloc_instance SerializedTestSet + alloc_instance testing.SerializedTestSet load_var _25 init_field .name load_var _26 @@ -716,7 +715,7 @@ function testing.TestRegistry.serialize(self: null) -> (testing.SerializedTest | L8: load_var items - alloc_instance SerializedTest + alloc_instance testing.SerializedTest load_const "test" init_field .type load_var _3 @@ -800,7 +799,7 @@ function user.User.promote(self: null, bonus: int) -> Report { load_var bonus call user.score store_var base - alloc_instance Report + alloc_instance user.Report load_var base load_field .score load_var bonus @@ -995,7 +994,7 @@ function user.score(input: User | ErrorInfo, threshold: int) -> Report { load_const 0 load_var total store_array_element - alloc_instance Report + alloc_instance user.Report load_var scores load_const 0 load_array_element diff --git a/baml_language/crates/baml_tests/tests/classes.rs b/baml_language/crates/baml_tests/tests/classes.rs index 97256f6134..5e9f1a8520 100644 --- a/baml_language/crates/baml_tests/tests/classes.rs +++ b/baml_language/crates/baml_tests/tests/classes.rs @@ -26,7 +26,7 @@ async fn class_constructor() { insta::assert_snapshot!(output.bytecode, @" function main() -> Point { - alloc_instance Point + alloc_instance user.Point load_const 1 init_field .x load_const 2 @@ -64,7 +64,7 @@ async fn class_constructor_return_directly() { insta::assert_snapshot!(output.bytecode, @" function main() -> Point { - alloc_instance Point + alloc_instance user.Point load_const 1 init_field .x load_const 2 @@ -106,7 +106,7 @@ async fn constructor_with_preceding_variables() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance MyClass + alloc_instance user.MyClass load_const 100 init_field .x load_const 200 @@ -187,8 +187,8 @@ async fn nested_construction_field_access() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 10 init_field .x load_const 20 @@ -229,8 +229,8 @@ async fn nested_construction_inner_field_access() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 10 init_field .x load_const 20 @@ -267,8 +267,8 @@ async fn nested_field_read() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 42 init_field .value init_field .inner @@ -302,8 +302,8 @@ async fn nested_field_read_separate_construction() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 42 init_field .value init_field .inner @@ -342,8 +342,8 @@ async fn nested_constructor_with_preceding_variables() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 100 init_field .val init_field .inner @@ -395,7 +395,7 @@ async fn spread_before_named_fields() { insta::assert_snapshot!(output.bytecode, @" function default_point() -> Point { - alloc_instance Point + alloc_instance user.Point load_const 0 init_field .x load_const 0 @@ -410,7 +410,7 @@ async fn spread_before_named_fields() { function main() -> Point { call user.default_point store_var _2 - alloc_instance Point + alloc_instance user.Point load_const 1 init_field .x load_const 2 @@ -463,7 +463,7 @@ async fn spread_after_named_fields() { insta::assert_snapshot!(output.bytecode, @" function default_point() -> Point { - alloc_instance Point + alloc_instance user.Point load_const 0 init_field .x load_const 0 @@ -478,7 +478,7 @@ async fn spread_after_named_fields() { function main() -> Point { call user.default_point store_var _2 - alloc_instance Point + alloc_instance user.Point load_var _2 load_field .0 init_field .x @@ -541,7 +541,7 @@ async fn multiple_spreads() { pop 1 call user.xy_one store_var _3 - alloc_instance Point + alloc_instance user.Point load_var _3 load_field .0 init_field .x @@ -558,7 +558,7 @@ async fn multiple_spreads() { } function x_one() -> Point { - alloc_instance Point + alloc_instance user.Point load_const 1 init_field .x load_const 0 @@ -571,7 +571,7 @@ async fn multiple_spreads() { } function xy_one() -> Point { - alloc_instance Point + alloc_instance user.Point load_const 1 init_field .x load_const 1 @@ -623,7 +623,7 @@ async fn spread_does_not_break_locals() { insta::assert_snapshot!(output.bytecode, @" function default_point() -> Point { - alloc_instance Point + alloc_instance user.Point load_const 0 init_field .x load_const 0 @@ -668,7 +668,7 @@ async fn field_assignment() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Data + alloc_instance user.Data load_const 0 init_field .value store_var d @@ -702,7 +702,7 @@ async fn field_compound_assignment() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Counter + alloc_instance user.Counter load_const 5 init_field .value store_var c @@ -742,8 +742,8 @@ async fn nested_field_assignment() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 0 init_field .value init_field .inner @@ -783,8 +783,8 @@ async fn nested_field_compound_assignment() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Outer - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Inner load_const 5 init_field .value init_field .inner @@ -834,7 +834,7 @@ async fn method_call() { insta::assert_snapshot!(output.bytecode, @" function Number.add(self: null, other: Number) -> Number { - alloc_instance Number + alloc_instance user.Number load_var self load_field .value load_var other @@ -845,10 +845,10 @@ async fn method_call() { } function main() -> int { - alloc_instance Number + alloc_instance user.Number load_const 1 init_field .value - alloc_instance Number + alloc_instance user.Number load_const 2 init_field .value call user.Number.add @@ -896,12 +896,12 @@ async fn mutable_self_method() { } function main() -> int { - alloc_instance Number + alloc_instance user.Number load_const 1 init_field .value store_var a load_var a - alloc_instance Number + alloc_instance user.Number load_const 2 init_field .value call user.Number.add diff --git a/baml_language/crates/baml_tests/tests/deep_copy.rs b/baml_language/crates/baml_tests/tests/deep_copy.rs index 4bd0c9a721..7376a0963e 100644 --- a/baml_language/crates/baml_tests/tests/deep_copy.rs +++ b/baml_language/crates/baml_tests/tests/deep_copy.rs @@ -27,15 +27,15 @@ async fn deep_copy_object() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> Tree { - alloc_instance Tree + alloc_instance user.Tree load_const "1" init_field .value - alloc_instance Tree + alloc_instance user.Tree load_const "2" init_field .value alloc_array 0 init_field .children - alloc_instance Tree + alloc_instance user.Tree load_const "3" init_field .value alloc_array 0 @@ -82,15 +82,15 @@ async fn deep_copy_independence() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Node + alloc_instance user.Node load_const 1 init_field .value - alloc_instance Node + alloc_instance user.Node load_const 2 init_field .value alloc_array 0 init_field .children - alloc_instance Node + alloc_instance user.Node load_const 3 init_field .value alloc_array 0 @@ -140,7 +140,7 @@ async fn deep_copy_nested_arrays_in_class() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Matrix + alloc_instance user.Matrix load_const 1 load_const 2 alloc_array 2 @@ -196,7 +196,7 @@ async fn deep_copy_map_in_class() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> int { - alloc_instance Container + alloc_instance user.Container load_const 1 load_const 2 load_const "a" @@ -267,25 +267,25 @@ async fn deep_copy_complex_nested_structure() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> int { - alloc_instance Outer - alloc_instance Middle - alloc_instance Inner + alloc_instance user.Outer + alloc_instance user.Middle + alloc_instance user.Inner load_const 1 init_field .value init_field .inner - alloc_instance Inner + alloc_instance user.Inner load_const 2 init_field .value - alloc_instance Inner + alloc_instance user.Inner load_const 3 init_field .value alloc_array 2 init_field .list init_field .middle - alloc_instance Inner + alloc_instance user.Inner load_const 4 init_field .value - alloc_instance Inner + alloc_instance user.Inner load_const 5 init_field .value load_const "first" @@ -367,14 +367,14 @@ async fn deep_copy_circular_reference() { insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Node + alloc_instance user.Node load_const 1 init_field .value alloc_array 0 init_field .children store_var a load_var a - alloc_instance Node + alloc_instance user.Node load_const 2 init_field .value load_var a @@ -464,12 +464,12 @@ async fn deep_equals_simple_objects() { insta::assert_snapshot!(output.bytecode, @" function main() -> bool { - alloc_instance Point + alloc_instance user.Point load_const 10 init_field .x load_const 20 init_field .y - alloc_instance Point + alloc_instance user.Point load_const 10 init_field .x load_const 20 @@ -501,12 +501,12 @@ async fn deep_equals_different_objects() { insta::assert_snapshot!(output.bytecode, @" function main() -> bool { - alloc_instance Point + alloc_instance user.Point load_const 10 init_field .x load_const 20 init_field .y - alloc_instance Point + alloc_instance user.Point load_const 10 init_field .x load_const 21 @@ -546,30 +546,30 @@ async fn deep_equals_nested_objects() { insta::assert_snapshot!(output.bytecode, @" function main() -> bool { - alloc_instance Node + alloc_instance user.Node load_const 1 init_field .value - alloc_instance Node + alloc_instance user.Node load_const 2 init_field .value alloc_array 0 init_field .children - alloc_instance Node + alloc_instance user.Node load_const 3 init_field .value alloc_array 0 init_field .children alloc_array 2 init_field .children - alloc_instance Node + alloc_instance user.Node load_const 1 init_field .value - alloc_instance Node + alloc_instance user.Node load_const 2 init_field .value alloc_array 0 init_field .children - alloc_instance Node + alloc_instance user.Node load_const 3 init_field .value alloc_array 0 @@ -611,30 +611,30 @@ async fn deep_equals_nested_objects_different() { insta::assert_snapshot!(output.bytecode, @" function main() -> bool { - alloc_instance Node + alloc_instance user.Node load_const 1 init_field .value - alloc_instance Node + alloc_instance user.Node load_const 2 init_field .value alloc_array 0 init_field .children - alloc_instance Node + alloc_instance user.Node load_const 3 init_field .value alloc_array 0 init_field .children alloc_array 2 init_field .children - alloc_instance Node + alloc_instance user.Node load_const 1 init_field .value - alloc_instance Node + alloc_instance user.Node load_const 2 init_field .value alloc_array 0 init_field .children - alloc_instance Node + alloc_instance user.Node load_const 4 init_field .value alloc_array 0 @@ -667,14 +667,14 @@ async fn deep_equals_with_arrays() { insta::assert_snapshot!(output.bytecode, @" function main() -> bool { - alloc_instance Container + alloc_instance user.Container load_const 1 load_const 2 load_const 3 load_const 4 alloc_array 4 init_field .data - alloc_instance Container + alloc_instance user.Container load_const 1 load_const 2 load_const 3 @@ -707,14 +707,14 @@ async fn deep_equals_with_maps() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> bool { - alloc_instance MapContainer + alloc_instance user.MapContainer load_const 1 load_const 2 load_const "a" load_const "b" alloc_map 2 init_field .values - alloc_instance MapContainer + alloc_instance user.MapContainer load_const 1 load_const 2 load_const "a" @@ -747,7 +747,7 @@ async fn deep_equals_same_reference() { insta::assert_snapshot!(output.bytecode, @" function main() -> bool { - alloc_instance Node + alloc_instance user.Node load_const 1 init_field .value alloc_array 0 @@ -789,14 +789,14 @@ async fn deep_equals_circular_structure() { insta::assert_snapshot!(output.bytecode, @" function main() -> bool { - alloc_instance Node + alloc_instance user.Node load_const 1 init_field .value alloc_array 0 init_field .children store_var a1 load_var a1 - alloc_instance Node + alloc_instance user.Node load_const 2 init_field .value load_var a1 @@ -804,14 +804,14 @@ async fn deep_equals_circular_structure() { init_field .children alloc_array 1 store_field .children - alloc_instance Node + alloc_instance user.Node load_const 1 init_field .value alloc_array 0 init_field .children store_var a2 load_var a2 - alloc_instance Node + alloc_instance user.Node load_const 2 init_field .value load_var a2 diff --git a/baml_language/crates/baml_tests/tests/exceptions.rs b/baml_language/crates/baml_tests/tests/exceptions.rs index 9d9a38aa25..1bab34d489 100644 --- a/baml_language/crates/baml_tests/tests/exceptions.rs +++ b/baml_language/crates/baml_tests/tests/exceptions.rs @@ -660,7 +660,7 @@ async fn catch_user_class_single_arm() { ); insta::assert_snapshot!(output.bytecode, @r#" function fails() -> int { - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://example.com" init_field .url throw @@ -717,13 +717,13 @@ async fn catch_two_user_classes_dispatch_first() { jump L1 L0: - alloc_instance ParseError + alloc_instance user.ParseError load_const "bad json" init_field .message throw L1: - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://x" init_field .url throw @@ -818,7 +818,7 @@ async fn catch_user_class_plus_wildcard() { throw L1: - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://x" init_field .url throw @@ -901,19 +901,19 @@ async fn catch_three_user_classes_plus_wildcard() { throw L3: - alloc_instance RateLimit + alloc_instance user.RateLimit load_const 30 init_field .retryAfter throw L4: - alloc_instance NotFound + alloc_instance user.NotFound load_const "/users" init_field .path throw L5: - alloc_instance AuthError + alloc_instance user.AuthError load_const "expired" init_field .reason throw @@ -987,7 +987,7 @@ async fn named_class_binding_access_field() { ); insta::assert_snapshot!(output.bytecode, @r#" function fails() -> string { - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://example.com" init_field .url throw @@ -1048,13 +1048,13 @@ async fn named_class_binding_dispatch_access_fields() { jump L1 L0: - alloc_instance ParseError + alloc_instance user.ParseError load_const "bad json" init_field .message throw L1: - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://x" init_field .url throw @@ -1121,7 +1121,7 @@ async fn bare_class_single_arm() { ); insta::assert_snapshot!(output.bytecode, @r#" function fails() -> int { - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://example.com" init_field .url throw @@ -1178,13 +1178,13 @@ async fn bare_class_dispatch_first() { jump L1 L0: - alloc_instance ParseError + alloc_instance user.ParseError load_const "bad" init_field .message throw L1: - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://x" init_field .url throw @@ -1279,7 +1279,7 @@ async fn bare_class_plus_wildcard() { throw L1: - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://x" init_field .url throw @@ -2085,7 +2085,7 @@ async fn user_class_plus_panic_plus_wildcard_class_fires() { throw L2: - alloc_instance AppError + alloc_instance user.AppError load_const 500 init_field .code throw @@ -2180,7 +2180,7 @@ async fn user_class_plus_panic_plus_wildcard_panic_fires() { return L3: - alloc_instance AppError + alloc_instance user.AppError load_const 500 init_field .code throw @@ -2644,7 +2644,7 @@ async fn four_arms_division_by_zero_fires() { throw L3: - alloc_instance AppError + alloc_instance user.AppError load_const 404 init_field .code throw @@ -2871,7 +2871,7 @@ async fn four_arms_no_error() { throw L5: - alloc_instance AppError + alloc_instance user.AppError load_const 404 init_field .code throw @@ -3456,7 +3456,7 @@ async fn catch_four_typed_arms_jump_table() { "# ); - insta::assert_snapshot!(output.bytecode, @r" + insta::assert_snapshot!(output.bytecode, @" function main() -> int { load_const 2 call user.risky @@ -3510,25 +3510,25 @@ async fn catch_four_typed_arms_jump_table() { jump L3 L2: - alloc_instance ErrD + alloc_instance user.ErrD load_const 4 init_field .x throw L3: - alloc_instance ErrC + alloc_instance user.ErrC load_const 3 init_field .x throw L4: - alloc_instance ErrB + alloc_instance user.ErrB load_const 2 init_field .x throw L5: - alloc_instance ErrA + alloc_instance user.ErrA load_const 1 init_field .x throw @@ -3634,25 +3634,25 @@ async fn catch_four_typed_arms_plus_wildcard_jump_table() { throw L4: - alloc_instance ErrD + alloc_instance user.ErrD load_const 4 init_field .x throw L5: - alloc_instance ErrC + alloc_instance user.ErrC load_const 3 init_field .x throw L6: - alloc_instance ErrB + alloc_instance user.ErrB load_const 2 init_field .x throw L7: - alloc_instance ErrA + alloc_instance user.ErrA load_const 1 init_field .x throw @@ -3692,13 +3692,13 @@ async fn catch_two_typed_arms_sequential_chain() { jump L1 L0: - alloc_instance ParseError + alloc_instance user.ParseError load_const "bad" init_field .msg throw L1: - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://x" init_field .url throw @@ -3768,7 +3768,7 @@ async fn catch_mixed_literal_and_typed_no_switch() { jump L1 L0: - alloc_instance AppError + alloc_instance user.AppError load_const 404 init_field .code throw @@ -4076,25 +4076,25 @@ async fn catch_four_user_classes_instanceof_chain() { throw L4: - alloc_instance Timeout + alloc_instance user.Timeout load_const 5000 init_field .ms throw L5: - alloc_instance RateLimit + alloc_instance user.RateLimit load_const 30 init_field .retryAfter throw L6: - alloc_instance NotFound + alloc_instance user.NotFound load_const "/users" init_field .path throw L7: - alloc_instance AuthError + alloc_instance user.AuthError load_const "expired" init_field .reason throw @@ -4287,7 +4287,7 @@ async fn catch_mixed_named_and_anonymous_bindings() { insta::assert_snapshot!(output.bytecode, @r#" function fails() -> string { - alloc_instance NetworkError + alloc_instance user.NetworkError load_const "http://example.com" init_field .url throw diff --git a/baml_language/crates/baml_tests/tests/fs.rs b/baml_language/crates/baml_tests/tests/fs.rs index 21bfc059f7..af056d54df 100644 --- a/baml_language/crates/baml_tests/tests/fs.rs +++ b/baml_language/crates/baml_tests/tests/fs.rs @@ -21,33 +21,6 @@ fn stabilize(s: &str, root: &str) -> String { s.replace(root, "{TMPDIR}") } -#[tokio::test] -async fn fs_open_only() { - let (_tmp, root) = tmp(indexmap! { "hello.txt" => "Hello from BAML!" }); - - let output = baml_test!(&format!( - r#" - function main() -> int {{ - let file = baml.fs.open("{root}/hello.txt", "r"); - 42 - }} - "# - )); - - insta::assert_snapshot!(stabilize(&output.bytecode, &root), @r#" - function main() -> int { - load_const "{TMPDIR}/hello.txt" - load_const "r" - dispatch_future baml.fs.open - await - store_var file - load_const 42 - return - } - "#); - assert_eq!(output.result, Ok(BexExternalValue::Int(42))); -} - #[tokio::test] async fn fs_open_and_read() { let (_tmp, root) = tmp(indexmap! { "hello.txt" => "Hello from BAML!" }); @@ -932,3 +905,297 @@ async fn fs_open_w_creates_parent_dirs() { "nested" ); } + +// ============================================================================ +// read_dir tests +// ============================================================================ + +#[tokio::test] +async fn fs_read_dir_returns_entries() { + let (_tmp, root) = tmp(indexmap! { + "a.txt" => "aaa", + "b.txt" => "bbb", + }); + std::fs::create_dir(format!("{root}/subdir")).unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> baml.fs.DirEntry[] {{ + baml.fs.read_dir("{root}") + }} + "# + )); + + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array, got: {:?}", output.result); + }; + assert_eq!(items.len(), 3); + let mut names: Vec = items + .iter() + .map(|item| { + let BexExternalValue::Instance { fields, .. } = item else { + panic!("expected instance, got: {item:?}"); + }; + let BexExternalValue::String(name) = &fields["name"] else { + panic!("expected string name"); + }; + name.clone() + }) + .collect(); + names.sort(); + assert_eq!(names, vec!["a.txt", "b.txt", "subdir"]); +} + +#[tokio::test] +async fn fs_read_dir_type_flags() { + let (_tmp, root) = tmp(indexmap! { "file.txt" => "content" }); + std::fs::create_dir(format!("{root}/dir")).unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> baml.fs.DirEntry[] {{ + baml.fs.read_dir("{root}") + }} + "# + )); + + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array, got: {:?}", output.result); + }; + assert_eq!(items.len(), 2); + for item in items { + let BexExternalValue::Instance { fields, .. } = item else { + panic!("expected instance"); + }; + let BexExternalValue::String(name) = &fields["name"] else { + panic!("expected string name"); + }; + let BexExternalValue::Bool(is_dir) = &fields["is_dir"] else { + panic!("expected bool is_dir"); + }; + let BexExternalValue::Bool(is_file) = &fields["is_file"] else { + panic!("expected bool is_file"); + }; + let BexExternalValue::Bool(is_symlink) = &fields["is_symlink"] else { + panic!("expected bool is_symlink"); + }; + match name.as_str() { + "file.txt" => { + assert!(!is_dir, "file.txt should not be a dir"); + assert!(is_file, "file.txt should be a file"); + assert!(!is_symlink, "file.txt should not be a symlink"); + } + "dir" => { + assert!(is_dir, "dir should be a dir"); + assert!(!is_file, "dir should not be a file"); + assert!(!is_symlink, "dir should not be a symlink"); + } + _ => panic!("unexpected entry: {name}"), + } + } +} + +#[cfg(unix)] +#[tokio::test] +async fn fs_read_dir_reports_symlink_flag() { + let (_tmp, root) = tmp(indexmap! { "target.txt" => "content" }); + std::os::unix::fs::symlink(format!("{root}/target.txt"), format!("{root}/link.txt")).unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> baml.fs.DirEntry[] {{ + baml.fs.read_dir("{root}") + }} + "# + )); + + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array, got: {:?}", output.result); + }; + let link = items + .iter() + .find_map(|item| { + let BexExternalValue::Instance { fields, .. } = item else { + return None; + }; + match &fields["name"] { + BexExternalValue::String(name) if name == "link.txt" => Some(fields), + _ => None, + } + }) + .expect("expected link.txt entry"); + + assert_eq!(link["is_symlink"], BexExternalValue::Bool(true)); +} + +#[tokio::test] +async fn fs_read_dir_nonexistent_errors() { + let (_tmp, root) = tmp(indexmap! {}); + + let output = baml_test!(&format!( + r#" + function main() -> baml.fs.DirEntry[] {{ + baml.fs.read_dir("{root}/no_such_dir") + }} + "# + )); + + assert!(output.result.is_err()); +} + +#[tokio::test] +async fn fs_read_dir_empty_dir() { + let (_tmp, root) = tmp(indexmap! {}); + std::fs::create_dir(format!("{root}/empty")).unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> baml.fs.DirEntry[] {{ + baml.fs.read_dir("{root}/empty") + }} + "# + )); + + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array, got: {:?}", output.result); + }; + assert_eq!(items.len(), 0); +} + +// ============================================================================ +// mkdir tests +// ============================================================================ + +#[tokio::test] +async fn fs_mkdir_creates_directory() { + let (_tmp, root) = tmp(indexmap! {}); + + let output = baml_test!(&format!( + r#" + function main() -> null {{ + baml.fs.mkdir("{root}/newdir", baml.fs.MkdirOptions {{ recursive: false }}) + }} + "# + )); + + assert_eq!(output.result, Ok(BexExternalValue::Null)); + assert!( + std::path::Path::new(&format!("{root}/newdir")).is_dir(), + "expected {root}/newdir to be a directory" + ); +} + +#[tokio::test] +async fn fs_mkdir_recursive_creates_parents() { + let (_tmp, root) = tmp(indexmap! {}); + + let output = baml_test!(&format!( + r#" + function main() -> null {{ + baml.fs.mkdir("{root}/a/b/c", baml.fs.MkdirOptions {{ recursive: true }}) + }} + "# + )); + + assert_eq!(output.result, Ok(BexExternalValue::Null)); + assert!( + std::path::Path::new(&format!("{root}/a/b/c")).is_dir(), + "expected {root}/a/b/c to be a directory" + ); +} + +#[tokio::test] +async fn fs_mkdir_non_recursive_errors_when_parent_missing() { + let (_tmp, root) = tmp(indexmap! {}); + + let output = baml_test!(&format!( + r#" + function main() -> null {{ + baml.fs.mkdir("{root}/no/parent", baml.fs.MkdirOptions {{ recursive: false }}) + }} + "# + )); + + assert!(output.result.is_err()); +} + +#[tokio::test] +async fn fs_mkdir_recursive_is_idempotent() { + let (_tmp, root) = tmp(indexmap! {}); + std::fs::create_dir(format!("{root}/existing")).unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> null {{ + baml.fs.mkdir("{root}/existing", baml.fs.MkdirOptions {{ recursive: true }}) + }} + "# + )); + + assert_eq!(output.result, Ok(BexExternalValue::Null)); +} + +#[tokio::test] +async fn fs_mkdir_non_recursive_errors_when_dir_exists() { + // BEP-037: non-recursive mkdir on a path that already exists must error. + let (_tmp, root) = tmp(indexmap! {}); + std::fs::create_dir(format!("{root}/existing")).unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> null {{ + baml.fs.mkdir("{root}/existing", baml.fs.MkdirOptions {{ recursive: false }}) + }} + "# + )); + + assert!( + output.result.is_err(), + "expected error creating an already-existing dir, got: {:?}", + output.result + ); +} + +#[tokio::test] +async fn fs_mkdir_recursive_errors_when_leaf_is_file() { + // BEP-037: even with recursive=true, mkdir must error if the leaf path + // exists as a regular file. Idempotency only applies when the leaf is + // already a directory. + let (_tmp, root) = tmp(indexmap! { "leaf.txt" => "im a file" }); + + let output = baml_test!(&format!( + r#" + function main() -> null {{ + baml.fs.mkdir("{root}/leaf.txt", baml.fs.MkdirOptions {{ recursive: true }}) + }} + "# + )); + + assert!( + output.result.is_err(), + "expected error: leaf path exists as a file, got: {:?}", + output.result + ); +} + +#[tokio::test] +async fn fs_read_dir_on_file_errors() { + // BEP-037: read_dir on a path that exists but isn't a directory must + // throw Io. Without this, callers couldn't distinguish "empty dir" from + // "you pointed at a file". + let (_tmp, root) = tmp(indexmap! { "not_a_dir.txt" => "x" }); + + let output = baml_test!(&format!( + r#" + function main() -> baml.fs.DirEntry[] {{ + baml.fs.read_dir("{root}/not_a_dir.txt") + }} + "# + )); + + assert!( + output.result.is_err(), + "expected error reading_dir on a regular file, got: {:?}", + output.result + ); +} diff --git a/baml_language/crates/baml_tests/tests/glob.rs b/baml_language/crates/baml_tests/tests/glob.rs new file mode 100644 index 0000000000..513477bef0 --- /dev/null +++ b/baml_language/crates/baml_tests/tests/glob.rs @@ -0,0 +1,555 @@ +//! Tests for baml.glob namespace. + +use baml_tests::baml_test; +use bex_external_types::BexExternalValue; +use indexmap::indexmap; + +fn tmp(files: indexmap::IndexMap<&str, &str>) -> (tempfile::TempDir, String) { + let tmp = tempfile::TempDir::new().unwrap(); + for (name, contents) in files { + let path = tmp.path().join(name); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent).unwrap(); + } + std::fs::write(path, contents).unwrap(); + } + let root = tmp.path().display().to_string().replace('\\', "/"); + (tmp, root) +} + +fn string_items(value: &BexExternalValue) -> Vec { + let BexExternalValue::Array { items, .. } = value else { + panic!("expected array, got: {value:?}"); + }; + let mut strings: Vec = items + .iter() + .map(|v| { + let BexExternalValue::String(s) = v else { + panic!("expected string, got: {v:?}"); + }; + s.clone() + }) + .collect(); + strings.sort(); + strings +} + +// ============================================================================ +// baml.glob.new + Glob.matches +// ============================================================================ + +#[tokio::test] +async fn glob_matches_basic() { + let output = baml_test!( + r#" + function main() -> bool { + let g = baml.glob.new("*.txt"); + g.matches("hello.txt") + } + "# + ); + + assert_eq!(output.result, Ok(BexExternalValue::Bool(true))); +} + +#[tokio::test] +async fn glob_matches_no_match() { + let output = baml_test!( + r#" + function main() -> bool { + let g = baml.glob.new("*.txt"); + g.matches("hello.rs") + } + "# + ); + + assert_eq!(output.result, Ok(BexExternalValue::Bool(false))); +} + +#[tokio::test] +async fn glob_matches_recursive_wildcard() { + let output = baml_test!( + r#" + function main() -> bool { + let g = baml.glob.new("**/*.ts"); + g.matches("src/index.ts") + } + "# + ); + + assert_eq!(output.result, Ok(BexExternalValue::Bool(true))); +} + +#[tokio::test] +async fn glob_matches_question_mark() { + let output = baml_test!( + r#" + function main() -> bool { + let g = baml.glob.new("file?.txt"); + g.matches("fileA.txt") + } + "# + ); + + assert_eq!(output.result, Ok(BexExternalValue::Bool(true))); +} + +#[tokio::test] +async fn glob_matches_question_mark_no_match() { + let output = baml_test!( + r#" + function main() -> bool { + let g = baml.glob.new("file?.txt"); + g.matches("file.txt") + } + "# + ); + + assert_eq!(output.result, Ok(BexExternalValue::Bool(false))); +} + +#[tokio::test] +async fn glob_matches_bracket_character_class() { + // [abc] matches a single character from the set. Exercised through the + // BAML surface to catch any wiring regression between the parser's + // string-literal handling, codegen for Glob.matches, and GlobPattern. + let output = baml_test!( + r#" + function main() -> bool[] { + let g = baml.glob.new("[abc].txt"); + [g.matches("a.txt"), g.matches("b.txt"), g.matches("c.txt"), g.matches("d.txt")] + } + "# + ); + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array, got: {:?}", output.result); + }; + let bools: Vec = items + .iter() + .map(|v| match v { + BexExternalValue::Bool(b) => *b, + _ => panic!("expected bool"), + }) + .collect(); + assert_eq!(bools, vec![true, true, true, false]); +} + +#[tokio::test] +async fn glob_matches_bracket_range() { + let output = baml_test!( + r#" + function main() -> bool[] { + let g = baml.glob.new("[a-c].txt"); + [g.matches("a.txt"), g.matches("c.txt"), g.matches("d.txt")] + } + "# + ); + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array"); + }; + let bools: Vec = items + .iter() + .map(|v| match v { + BexExternalValue::Bool(b) => *b, + _ => panic!(), + }) + .collect(); + assert_eq!(bools, vec![true, true, false]); +} + +#[tokio::test] +async fn glob_matches_negated_bracket() { + // [^abc] matches a single character NOT in the set. + let output = baml_test!( + r#" + function main() -> bool[] { + let g = baml.glob.new("[^abc].txt"); + [g.matches("a.txt"), g.matches("d.txt")] + } + "# + ); + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array"); + }; + let bools: Vec = items + .iter() + .map(|v| match v { + BexExternalValue::Bool(b) => *b, + _ => panic!(), + }) + .collect(); + assert_eq!(bools, vec![false, true]); +} + +#[tokio::test] +async fn glob_matches_alternation() { + let output = baml_test!( + r#" + function main() -> bool[] { + let g = baml.glob.new("*.{ts,tsx}"); + [g.matches("app.ts"), g.matches("app.tsx"), g.matches("app.js")] + } + "# + ); + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array"); + }; + let bools: Vec = items + .iter() + .map(|v| match v { + BexExternalValue::Bool(b) => *b, + _ => panic!(), + }) + .collect(); + assert_eq!(bools, vec![true, true, false]); +} + +#[tokio::test] +async fn glob_matches_negated_pattern() { + // `!index.ts` — match everything except index.ts. + let output = baml_test!( + r#" + function main() -> bool[] { + let g = baml.glob.new("!index.ts"); + [g.matches("main.ts"), g.matches("index.ts")] + } + "# + ); + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array"); + }; + let bools: Vec = items + .iter() + .map(|v| match v { + BexExternalValue::Bool(b) => *b, + _ => panic!(), + }) + .collect(); + assert_eq!(bools, vec![true, false]); +} + +// ============================================================================ +// baml.glob.new + Glob.scan +// ============================================================================ + +#[tokio::test] +async fn glob_scan_finds_txt_files() { + let (_tmp, root) = tmp(indexmap! { + "a.txt" => "a", + "b.txt" => "b", + "c.rs" => "c", + }); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("*.txt"); + g.scan("{root}") + }} + "# + )); + + assert_eq!( + string_items(output.result.as_ref().unwrap()), + vec!["a.txt", "b.txt"] + ); +} + +#[tokio::test] +async fn glob_scan_returns_empty_for_no_match() { + let (_tmp, root) = tmp(indexmap! { + "a.rs" => "rust", + "b.rs" => "rust", + }); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("*.txt"); + g.scan("{root}") + }} + "# + )); + + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array, got: {:?}", output.result); + }; + assert_eq!(items.len(), 0); +} + +#[tokio::test] +async fn glob_scan_only_files_by_default() { + // With only_files=true (default), scan should return only files, not dirs. + // We create a directory that also matches *.txt pattern name-wise, + // but it should be excluded. + let (_tmp, root) = tmp(indexmap! { + "file.txt" => "content", + }); + // Create a directory named "dir.txt" to ensure it's excluded + std::fs::create_dir(format!("{root}/dir.txt")).unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("*.txt"); + g.scan("{root}") + }} + "# + )); + + let Ok(BexExternalValue::Array { items, .. }) = &output.result else { + panic!("expected array, got: {:?}", output.result); + }; + // By default only_files=true, so "dir.txt/" directory should not appear + for item in items { + let BexExternalValue::String(s) = item else { + panic!("expected string") + }; + // only files should be returned + assert_eq!(s.as_str(), "file.txt", "unexpected entry: {s}"); + } + assert_eq!(items.len(), 1); +} + +#[tokio::test] +async fn glob_scan_options_include_dot_absolute_and_directories() { + let (_tmp, root) = tmp(indexmap! { + "file.txt" => "content", + ".hidden.txt" => "hidden", + }); + std::fs::create_dir(format!("{root}/dir.txt")).unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("**/*.txt"); + g.scan(baml.glob.ScanOptions {{ cwd: "{root}", dot: true, absolute: true, only_files: false }}) + }} + "# + )); + + assert_eq!( + string_items(output.result.as_ref().unwrap()), + vec![ + format!("{root}/.hidden.txt"), + format!("{root}/dir.txt"), + format!("{root}/file.txt"), + ] + ); +} + +#[tokio::test] +async fn glob_scan_matches_dot_slash_pattern() { + let (_tmp, root) = tmp(indexmap! { "file.txt" => "content" }); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("./*.txt"); + g.scan("{root}") + }} + "# + )); + + assert_eq!( + string_items(output.result.as_ref().unwrap()), + vec!["file.txt"] + ); +} + +#[tokio::test] +async fn glob_scan_matches_absolute_pattern() { + let (_tmp, root) = tmp(indexmap! { "file.txt" => "content" }); + let pattern = format!("{root}/**/*.txt"); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("{pattern}"); + g.scan(baml.glob.ScanOptions {{ cwd: "{root}", absolute: true }}) + }} + "# + )); + + assert_eq!( + string_items(output.result.as_ref().unwrap()), + vec![format!("{root}/file.txt")] + ); +} + +#[tokio::test] +async fn glob_scan_dot_pattern_matches_only_dot_files() { + // Regression for the OR-against-three-forms strategy: a plain pattern + // like `.*` would match every file because the `./` form always + // starts with `.`. The fix makes a plain pattern match only the relative + // form, so `.*` matches `.hidden` but not `regular.txt`. + let (_tmp, root) = tmp(indexmap! { + ".hidden" => "h", + "regular.txt" => "r", + }); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new(".*"); + g.scan(baml.glob.ScanOptions {{ cwd: "{root}", dot: true }}) + }} + "# + )); + + assert_eq!( + string_items(output.result.as_ref().unwrap()), + vec![".hidden"] + ); +} + +#[tokio::test] +async fn glob_scan_default_prunes_dot_directories() { + // dot=false (default) must skip files inside dot directories. Beyond + // correctness, this also locks in the walker-side pruning so we don't + // descend into trees like `.git/`. + let (_tmp, root) = tmp(indexmap! { + "visible.txt" => "visible", + }); + std::fs::create_dir_all(format!("{root}/.git/objects")).unwrap(); + std::fs::write(format!("{root}/.git/objects/secret.txt"), "x").unwrap(); + std::fs::write(format!("{root}/.git/HEAD"), "x").unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("**/*.txt"); + g.scan("{root}") + }} + "# + )); + + assert_eq!( + string_items(output.result.as_ref().unwrap()), + vec!["visible.txt"] + ); +} + +#[cfg(unix)] +#[tokio::test] +async fn glob_scan_follows_symlinked_directory_when_enabled() { + // follow_symlinks=true: a symlinked directory under the scan root should + // be traversed and its contents matched, just like a real directory. + let outer = tempfile::TempDir::new().unwrap(); + let target = tempfile::TempDir::new().unwrap(); + std::fs::write(target.path().join("hidden_via_link.txt"), "x").unwrap(); + let outer_root = outer.path().display().to_string().replace('\\', "/"); + std::os::unix::fs::symlink(target.path(), outer.path().join("link_dir")).unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("**/*.txt"); + g.scan(baml.glob.ScanOptions {{ cwd: "{outer_root}", follow_symlinks: true }}) + }} + "# + )); + + assert_eq!( + string_items(output.result.as_ref().unwrap()), + vec!["link_dir/hidden_via_link.txt"] + ); +} + +#[cfg(unix)] +#[tokio::test] +async fn glob_scan_skips_broken_symlinks_by_default() { + // follow_symlinks=true makes walkdir try to stat the symlink target. With a + // broken link present, the default (throw_error_on_broken_symlink=false) + // must silently skip it and still return the real files. + let (_tmp, root) = tmp(indexmap! { "real.txt" => "content" }); + std::os::unix::fs::symlink( + format!("{root}/missing.txt"), + format!("{root}/dangling.txt"), + ) + .unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("*.txt"); + g.scan(baml.glob.ScanOptions {{ cwd: "{root}", follow_symlinks: true }}) + }} + "# + )); + + assert_eq!( + string_items(output.result.as_ref().unwrap()), + vec!["real.txt"] + ); +} + +#[cfg(unix)] +#[tokio::test] +async fn glob_scan_throws_on_broken_symlink_when_opted_in() { + let (_tmp, root) = tmp(indexmap! { "real.txt" => "content" }); + std::os::unix::fs::symlink( + format!("{root}/missing.txt"), + format!("{root}/dangling.txt"), + ) + .unwrap(); + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("*.txt"); + g.scan(baml.glob.ScanOptions {{ + cwd: "{root}", + follow_symlinks: true, + throw_error_on_broken_symlink: true, + }}) + }} + "# + )); + + assert!( + output.result.is_err(), + "expected error for broken symlink with throw_error_on_broken_symlink=true, got: {:?}", + output.result + ); +} + +#[cfg(unix)] +#[tokio::test] +async fn glob_scan_propagates_permission_errors() { + // A directory the walker can enter the parent of but not read should + // surface as an Io error, not be silently swallowed. throw_on_broken is + // scoped to broken symlinks only — real I/O errors propagate by default. + use std::os::unix::fs::PermissionsExt; + + let (_tmp, root) = tmp(indexmap! { "ok.txt" => "ok" }); + let unreadable = format!("{root}/locked"); + std::fs::create_dir(&unreadable).unwrap(); + std::fs::write(format!("{unreadable}/inner.txt"), "x").unwrap(); + // Mode 0 → no permissions. Root can still read, so probe first and skip + // under root (CI containers); the assertion isn't meaningful there. + std::fs::set_permissions(&unreadable, std::fs::Permissions::from_mode(0o000)).unwrap(); + let still_readable = std::fs::read_dir(&unreadable).is_ok(); + if still_readable { + std::fs::set_permissions(&unreadable, std::fs::Permissions::from_mode(0o755)).unwrap(); + return; + } + + let output = baml_test!(&format!( + r#" + function main() -> string[] {{ + let g = baml.glob.new("**/*.txt"); + g.scan("{root}") + }} + "# + )); + + // Restore permissions so the temp dir can be cleaned up. + std::fs::set_permissions(&unreadable, std::fs::Permissions::from_mode(0o755)).unwrap(); + + assert!( + output.result.is_err(), + "expected permission error to propagate, got: {:?}", + output.result + ); +} diff --git a/baml_language/crates/baml_tests/tests/match_basics.rs b/baml_language/crates/baml_tests/tests/match_basics.rs index 156c1dcbbf..63419fe343 100644 --- a/baml_language/crates/baml_tests/tests/match_basics.rs +++ b/baml_language/crates/baml_tests/tests/match_basics.rs @@ -2277,9 +2277,9 @@ async fn match_mixed_instanceof_and_literal() { "# ); - insta::assert_snapshot!(output.bytecode, @r" + insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Result + alloc_instance user.Result load_const 200 init_field .code store_var x diff --git a/baml_language/crates/baml_tests/tests/match_types.rs b/baml_language/crates/baml_tests/tests/match_types.rs index c99d9b6ae1..2842ee3256 100644 --- a/baml_language/crates/baml_tests/tests/match_types.rs +++ b/baml_language/crates/baml_tests/tests/match_types.rs @@ -96,7 +96,7 @@ async fn match_typed_pattern_second_arm() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> string { - alloc_instance Failure + alloc_instance user.Failure load_const "error" init_field .reason store_var result @@ -282,7 +282,7 @@ async fn match_guard_true() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> string { - alloc_instance Score + alloc_instance user.Score load_const 95 init_field .value store_var s @@ -353,7 +353,7 @@ async fn match_guard_fallthrough() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> string { - alloc_instance Score + alloc_instance user.Score load_const 75 init_field .value store_var s @@ -424,7 +424,7 @@ async fn match_guard_all_fail() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> string { - alloc_instance Score + alloc_instance user.Score load_const 50 init_field .value store_var s @@ -907,7 +907,7 @@ async fn match_guard_on_typed_pattern_field_access() { } function main() -> string { - alloc_instance Success + alloc_instance user.Success load_const "hello" init_field .data call user.classify @@ -979,7 +979,7 @@ async fn match_guard_on_typed_pattern_field_access_fails() { } function main() -> string { - alloc_instance Success + alloc_instance user.Success load_const "" init_field .data call user.classify @@ -1411,7 +1411,7 @@ async fn match_class_types_exhaustive_first() { } function main() -> string { - alloc_instance Cat + alloc_instance user.Cat load_const "Whiskers" init_field .name call user.classify @@ -1487,7 +1487,7 @@ async fn match_class_types_exhaustive_last() { } function main() -> string { - alloc_instance Bird + alloc_instance user.Bird load_const "Tweety" init_field .name call user.classify @@ -1557,7 +1557,7 @@ async fn match_class_types_non_exhaustive_wildcard() { } function main() -> string { - alloc_instance Bird + alloc_instance user.Bird load_const "Tweety" init_field .name call user.classify @@ -1627,7 +1627,7 @@ async fn match_class_types_non_exhaustive_matched() { } function main() -> string { - alloc_instance Dog + alloc_instance user.Dog load_const "Rex" init_field .name call user.classify @@ -1773,7 +1773,7 @@ async fn match_multiple_typed_patterns_with_guards() { } function main() -> string { - alloc_instance Success + alloc_instance user.Success load_const 301 init_field .code load_const false @@ -1862,7 +1862,7 @@ async fn match_class_type_tag_jump_table() { } function main() -> string { - alloc_instance Dog + alloc_instance user.Dog load_const "Rex" init_field .name call user.describe @@ -1918,7 +1918,7 @@ async fn match_class_type_is_type_chain() { } function main() -> string { - alloc_instance Cat + alloc_instance user.Cat load_const "Whiskers" init_field .name call user.describe @@ -1983,7 +1983,7 @@ async fn match_mixed_class_primitive_type_tag_switch() { } function main() -> string { - alloc_instance MyClass + alloc_instance user.MyClass load_const 42 init_field .value call user.classify diff --git a/baml_language/crates/baml_tests/tests/optimization.rs b/baml_language/crates/baml_tests/tests/optimization.rs index 3835d69326..4ebcc4738c 100644 --- a/baml_language/crates/baml_tests/tests/optimization.rs +++ b/baml_language/crates/baml_tests/tests/optimization.rs @@ -239,7 +239,7 @@ fn combined_constant_fold_and_struct() { "#; insta::assert_snapshot!(unoptimized(source), @r#" function main() -> Result { - alloc_instance Result + alloc_instance user.Result load_const 2 load_const 3 bin_op + @@ -251,7 +251,7 @@ fn combined_constant_fold_and_struct() { "#); insta::assert_snapshot!(optimized(source), @r#" function main() -> Result { - alloc_instance Result + alloc_instance user.Result load_const 5 init_field .value load_const "sum" diff --git a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_1d_array_read_through_field.snap b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_1d_array_read_through_field.snap index 1adf14caf9..6ed9c9a256 100644 --- a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_1d_array_read_through_field.snap +++ b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_1d_array_read_through_field.snap @@ -11,7 +11,7 @@ function Container.get(self: null, idx: int) -> string { } function main() -> string { - alloc_instance Container + alloc_instance user.Container load_const "a" load_const "b" load_const "c" diff --git a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_1d_array_write_through_field.snap b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_1d_array_write_through_field.snap index bf0df6537a..013dd1d753 100644 --- a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_1d_array_write_through_field.snap +++ b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_1d_array_write_through_field.snap @@ -13,7 +13,7 @@ function Container.set(self: null, idx: int, val: string) -> null { } function main() -> null { - alloc_instance Container + alloc_instance user.Container load_const "a" load_const "b" load_const "c" diff --git a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_2d_array_write_through_field.snap b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_2d_array_write_through_field.snap index c75e92a51a..c4e8438faf 100644 --- a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_2d_array_write_through_field.snap +++ b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_2d_array_write_through_field.snap @@ -15,7 +15,7 @@ function Grid.set(self: null, row: int, col: int, val: string) -> null { } function main() -> null { - alloc_instance Grid + alloc_instance user.Grid load_const "a" load_const "b" alloc_array 2 diff --git a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_map_write_through_field.snap b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_map_write_through_field.snap index 5d340f354e..b7be70dc33 100644 --- a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_map_write_through_field.snap +++ b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_map_write_through_field.snap @@ -13,7 +13,7 @@ function Scores.set(self: null, key: string, val: int) -> null { } function main() -> null { - alloc_instance Scores + alloc_instance user.Scores alloc_map 0 init_field .data load_const "alice" diff --git a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_non_self_param_array_write.snap b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_non_self_param_array_write.snap index 3d918c8fc2..bf19a82d6b 100644 --- a/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_non_self_param_array_write.snap +++ b/baml_language/crates/baml_tests/tests/snapshots/type_error_repro__bytecode_non_self_param_array_write.snap @@ -3,7 +3,7 @@ source: crates/baml_tests/tests/type_error_repro.rs expression: output.bytecode --- function main() -> null { - alloc_instance Container + alloc_instance user.Container load_const "a" load_const "b" load_const "c" diff --git a/baml_language/crates/baml_tests/tests/soundness.rs b/baml_language/crates/baml_tests/tests/soundness.rs index 206f6b81b4..bc9d966c86 100644 --- a/baml_language/crates/baml_tests/tests/soundness.rs +++ b/baml_language/crates/baml_tests/tests/soundness.rs @@ -98,9 +98,9 @@ async fn cross_block_field_mutation() { "# ); - insta::assert_snapshot!(output.bytecode, @r" + insta::assert_snapshot!(output.bytecode, @" function main() -> int { - alloc_instance Box + alloc_instance user.Box load_const 1 init_field .v store_var b diff --git a/baml_language/crates/baml_tests/tests/watch.rs b/baml_language/crates/baml_tests/tests/watch.rs index a9fe1ca705..aaf0f07fe6 100644 --- a/baml_language/crates/baml_tests/tests/watch.rs +++ b/baml_language/crates/baml_tests/tests/watch.rs @@ -234,7 +234,7 @@ async fn watch_alias() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> int { - alloc_instance Point + alloc_instance user.Point load_const 0 init_field .x load_const 0 @@ -276,7 +276,7 @@ async fn watch_alias_nested_scope() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> int { - alloc_instance Point + alloc_instance user.Point load_const 0 init_field .x load_const 0 @@ -324,7 +324,7 @@ async fn watch_scope_exit() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> int { - alloc_instance Point + alloc_instance user.Point load_const 0 init_field .x load_const 0 @@ -1308,7 +1308,7 @@ async fn watch_function_call_modifications() { } function main() -> int { - alloc_instance Point + alloc_instance user.Point load_const 0 init_field .x load_const 0 @@ -1360,23 +1360,23 @@ async fn watch_nested_object_added() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> int { - alloc_instance Vec2D - alloc_instance Point - alloc_instance Value + alloc_instance user.Vec2D + alloc_instance user.Point + alloc_instance user.Value load_const 0 init_field .value init_field .x - alloc_instance Value + alloc_instance user.Value load_const 0 init_field .value init_field .y init_field .p - alloc_instance Point - alloc_instance Value + alloc_instance user.Point + alloc_instance user.Value load_const 0 init_field .value init_field .x - alloc_instance Value + alloc_instance user.Value load_const 0 init_field .value init_field .y @@ -1385,12 +1385,12 @@ async fn watch_nested_object_added() { load_const "vec" load_const null watch vec - alloc_instance Point - alloc_instance Value + alloc_instance user.Point + alloc_instance user.Value load_const 1 init_field .value init_field .x - alloc_instance Value + alloc_instance user.Value load_const 1 init_field .value init_field .y @@ -1440,23 +1440,23 @@ async fn watch_nested_object_removed() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> int { - alloc_instance Vec2D - alloc_instance Point - alloc_instance Value + alloc_instance user.Vec2D + alloc_instance user.Point + alloc_instance user.Value load_const 0 init_field .value init_field .x - alloc_instance Value + alloc_instance user.Value load_const 0 init_field .value init_field .y init_field .p - alloc_instance Point - alloc_instance Value + alloc_instance user.Point + alloc_instance user.Value load_const 0 init_field .value init_field .x - alloc_instance Value + alloc_instance user.Value load_const 0 init_field .value init_field .y @@ -1469,12 +1469,12 @@ async fn watch_nested_object_removed() { load_field .p store_var p load_var vec - alloc_instance Point - alloc_instance Value + alloc_instance user.Point + alloc_instance user.Value load_const 1 init_field .value init_field .x - alloc_instance Value + alloc_instance user.Value load_const 1 init_field .value init_field .y @@ -1537,31 +1537,31 @@ async fn watch_cyclic_graph() { insta::assert_snapshot!(output.bytecode, @r#" function main() -> int { - alloc_instance Vertex - load_const 1 - init_field .edges + alloc_instance user.Vertex alloc_array 0 + init_field .edges + load_const 1 init_field .value store_var v1 - alloc_instance Vertex - load_const 2 - init_field .edges + alloc_instance user.Vertex alloc_array 0 + init_field .edges + load_const 2 init_field .value store_var v2 load_const "v2" load_const null watch v2 - alloc_instance Vertex - load_const 3 - init_field .edges + alloc_instance user.Vertex alloc_array 0 + init_field .edges + load_const 3 init_field .value store_var v3 - alloc_instance Vertex - load_const 4 - init_field .edges + alloc_instance user.Vertex alloc_array 0 + init_field .edges + load_const 4 init_field .value store_var v4 load_const "v4" diff --git a/baml_language/crates/bex_external_types/src/bex_external_value.rs b/baml_language/crates/bex_external_types/src/bex_external_value.rs index c14b5c80fe..6a9eafbd23 100644 --- a/baml_language/crates/bex_external_types/src/bex_external_value.rs +++ b/baml_language/crates/bex_external_types/src/bex_external_value.rs @@ -404,6 +404,32 @@ impl BexExternalValue { BexExternalValue::Handle(_) => "handle", } } + + /// Return the inner string if this is a `String` value, peeling off any + /// surrounding `Union` wrapper. + /// + /// Useful when reading optional or union-typed fields from an `Instance` + /// (e.g. `ScanOptions { cwd: string? }`): the runtime stores the field as + /// `Union { value: String(...), .. }` for static-typed inputs and as + /// `String(...)` for ad-hoc literals, and consumers don't usually care + /// about that distinction. + pub fn as_string(&self) -> Option { + match self { + BexExternalValue::String(value) => Some(value.clone()), + BexExternalValue::Union { value, .. } => value.as_string(), + _ => None, + } + } + + /// Return the inner bool if this is a `Bool` value, peeling off any + /// surrounding `Union` wrapper. See [`Self::as_string`]. + pub fn as_bool(&self) -> Option { + match self { + BexExternalValue::Bool(value) => Some(*value), + BexExternalValue::Union { value, .. } => value.as_bool(), + _ => None, + } + } } impl From for BexExternalValue { diff --git a/baml_language/crates/bridge_wasm/Cargo.toml b/baml_language/crates/bridge_wasm/Cargo.toml index f203088081..4283eefec8 100644 --- a/baml_language/crates/bridge_wasm/Cargo.toml +++ b/baml_language/crates/bridge_wasm/Cargo.toml @@ -16,6 +16,7 @@ bex_events = { workspace = true } bex_heap = { workspace = true } bex_project = { workspace = true } bridge_ctypes = { workspace = true } +sys_glob = { workspace = true } sys_ops = { workspace = true } sys_types = { workspace = true } async-trait = { workspace = true } @@ -29,6 +30,7 @@ lsp-server = { workspace = true } prost = { workspace = true } reqwest = { workspace = true } serde = { workspace = true, features = [ "derive" ] } +serde-wasm-bindgen = { workspace = true } serde_json = { workspace = true } thiserror = { workspace = true } tsify = { workspace = true } diff --git a/baml_language/crates/bridge_wasm/src/lib.rs b/baml_language/crates/bridge_wasm/src/lib.rs index 81cae5f8a3..fbd71868da 100644 --- a/baml_language/crates/bridge_wasm/src/lib.rs +++ b/baml_language/crates/bridge_wasm/src/lib.rs @@ -51,6 +51,8 @@ mod wasm_env; mod wasm_fs; mod wasm_http; mod wasm_io; +mod wasm_io_fs; +mod wasm_io_glob; mod wasm_lsp; mod wasm_playground; mod wasm_sys; @@ -60,6 +62,7 @@ pub use error::BridgeError; use js_sys::Function; use prost::Message; use wasm_bindgen::prelude::*; +pub use wasm_lsp::LspNotification; static LOGGER_INIT: std::sync::Once = std::sync::Once::new(); @@ -188,11 +191,23 @@ impl BamlWasmRuntime { let make_request_fn = callbacks.make_request(); let playground_send_notification_fn = callbacks.playground_send_notification(); + // Wrap wasm_vfs in Arc so it can be shared across the VFS filesystem, + // the fs IO namespace, and the glob IO namespace without cloning the + // underlying JS value. + #[allow(clippy::arc_with_non_send_sync)] + let wasm_vfs_arc = std::sync::Arc::new(wasm_vfs); + let sys_ops = sys_ops::SysOpsBuilder::new() .with_http_instance(std::sync::Arc::new(wasm_http::WasmHttp::new(fetch_fn))) .with_env_instance(std::sync::Arc::new(wasm_env::WasmEnv::new(env_vars_fn))) .with_io_instance(std::sync::Arc::new(wasm_io::WasmIo::new(input_fn))) .with_sys_instance(std::sync::Arc::new(wasm_sys::WasmSys::new())) + .with_fs_instance(std::sync::Arc::new(wasm_io_fs::WasmIoFs::new( + std::sync::Arc::clone(&wasm_vfs_arc), + ))) + .with_glob_instance(std::sync::Arc::new(wasm_io_glob::WasmIoGlob::new( + std::sync::Arc::clone(&wasm_vfs_arc), + ))) .build(); let sys_ops = std::sync::Arc::new(sys_ops); let sys_op_factory = std::sync::Arc::new(move |_path: &vfs::VfsPath| sys_ops.clone()); @@ -202,7 +217,7 @@ impl BamlWasmRuntime { wasm_playground::WasmPlaygroundSender::new(playground_send_notification_fn.clone()); let event_sink = wasm_playground::WasmEventSink::new(playground_send_notification_fn); - let vfs = wasm_fs::WasmFs::new(wasm_vfs); + let vfs = wasm_fs::WasmFs::new(wasm_vfs_arc); let vfs = std::sync::Arc::new(vfs); let bex = bex_project::new_lsp( diff --git a/baml_language/crates/bridge_wasm/src/wasm_fs.rs b/baml_language/crates/bridge_wasm/src/wasm_fs.rs index bbef5d1cdf..3059333ae6 100644 --- a/baml_language/crates/bridge_wasm/src/wasm_fs.rs +++ b/baml_language/crates/bridge_wasm/src/wasm_fs.rs @@ -24,6 +24,7 @@ fn millis_to_system_time(ms: u64) -> SystemTime { extern "C" { #[wasm_bindgen(typescript_type = r#"{ readDir: (path: string) => string[]; + readDirEntries: (path: string) => WasmVfsDirEntry[]; createDir: (path: string) => void; exists: (path: string) => boolean; readFile: (path: string) => Uint8Array; @@ -43,6 +44,16 @@ extern "C" { #[wasm_bindgen(method, catch, structural, js_name = readDir)] fn read_dir(this: &WasmVfs, path: &str) -> Result; + // readDirEntries(path) -> WasmVfsDirEntry[] + // + // Returns directory entries with type information attached, so callers + // (e.g. baml.fs.read_dir, baml.glob.scan) don't have to issue an + // additional `metadata` round-trip per entry. JS hosts that don't yet + // implement this method cause the `Result` to resolve as an error; the + // Rust-side caller falls back to readDir + per-entry metadata. + #[wasm_bindgen(method, catch, structural, js_name = readDirEntries)] + fn read_dir_entries(this: &WasmVfs, path: &str) -> Result; + // createDir(path) -> void #[wasm_bindgen(method, catch, structural, js_name = createDir)] fn create_dir(this: &WasmVfs, path: &str) -> Result<(), JsValue>; @@ -102,6 +113,56 @@ pub struct WasmVfsMetadata { pub accessed: Option, } +/// One directory entry returned by `readDirEntries`. Carries the same type +/// information `metadata` does, so a directory listing only needs one +/// JS-WASM round-trip total instead of N+1 (where N = number of entries). +#[derive(tsify::Tsify, Serialize, Deserialize)] +#[tsify(into_wasm_abi, from_wasm_abi)] +pub struct WasmVfsDirEntry { + pub name: String, + /// `"file"`, `"directory"`, or any host-specific string. WASM consumers + /// only check for the `"file"`/`"directory"` cases today. + pub file_type: String, + pub is_symlink: bool, +} + +/// Crate-internal accessor methods on `WasmVfs` for use by `wasm_io_fs` and +/// `wasm_io_glob`. The `extern "C"` bindings generated by `wasm_bindgen` are +/// inherently private to this module, so we expose them here. +impl WasmVfs { + pub(crate) fn vfs_read_dir(&self, path: &str) -> Result { + self.read_dir(path) + } + + pub(crate) fn vfs_read_dir_entries(&self, path: &str) -> Result { + self.read_dir_entries(path) + } + + pub(crate) fn vfs_create_dir(&self, path: &str) -> Result<(), JsValue> { + self.create_dir(path) + } + + pub(crate) fn vfs_exists(&self, path: &str) -> Result { + self.exists(path) + } + + pub(crate) fn vfs_read_file(&self, path: &str) -> Result { + self.read_file(path) + } + + pub(crate) fn vfs_write_file(&self, path: &str, data: &Uint8Array) -> Result<(), JsValue> { + self.write_file(path, data) + } + + pub(crate) fn vfs_metadata(&self, path: &str) -> Result { + self.metadata(path) + } + + pub(crate) fn vfs_remove_file(&self, path: &str) -> Result<(), JsValue> { + self.remove_file(path) + } +} + #[derive(Clone)] pub(super) struct WasmFs { vfs: SendWrapper>, @@ -115,9 +176,11 @@ impl std::fmt::Debug for WasmFs { impl WasmFs { #[allow(clippy::new_ret_no_self, clippy::arc_with_non_send_sync)] - pub(super) fn new(wasm_vfs: WasmVfs) -> Box { + pub(super) fn new( + wasm_vfs: std::sync::Arc, + ) -> Box { Box::new(Self { - vfs: SendWrapper::new(std::sync::Arc::new(wasm_vfs)), + vfs: SendWrapper::new(wasm_vfs), }) } } diff --git a/baml_language/crates/bridge_wasm/src/wasm_io_fs.rs b/baml_language/crates/bridge_wasm/src/wasm_io_fs.rs new file mode 100644 index 0000000000..a06c9ee2f3 --- /dev/null +++ b/baml_language/crates/bridge_wasm/src/wasm_io_fs.rs @@ -0,0 +1,437 @@ +//! WASM `baml.fs` namespace implementation via `WasmVfs` JS callbacks. +//! +//! `WasmIoFs` wraps an `Arc` (itself wrapped in `SendWrapper` to +//! satisfy `Send + Sync` bounds on single-threaded wasm32) and implements +//! `IoNamespaceFs` by delegating each operation to the corresponding JS method +//! on the VFS object passed at runtime creation. +//! +//! File handle operations (`IoClassFsFile`) are not supported in WASM — they +//! all return `Unsupported` because the native tokio file-handle model doesn't +//! translate to the browser sandbox. + +use std::sync::Arc; + +use js_sys::Uint8Array; +use sys_ops::io::{self, BexExternalValue, CallId, OpErrorKind, SysOpContext, SysOpOutput, owned}; +use sys_types::BexHeap; + +use crate::{send_wrapper::SendWrapper, wasm_fs::WasmVfs}; + +/// WASM implementation of `baml.fs` namespace ops. +/// +/// Holds a shared `Arc` (created once in `BamlWasmRuntime::create`) +/// wrapped in `SendWrapper` to satisfy `Send + Sync` in the generated trait +/// bounds while keeping WASM's single-threaded model safe. +pub(crate) struct WasmIoFs { + vfs: SendWrapper>, +} + +impl WasmIoFs { + /// Create a new `WasmIoFs` from a shared VFS reference. + pub(crate) fn new(vfs: Arc) -> Self { + Self { + vfs: SendWrapper::new(vfs), + } + } + + fn vfs(&self) -> &WasmVfs { + self.vfs.as_ref() + } +} + +fn join_path(parent: &str, name: &str) -> String { + if parent == "/" { + format!("/{name}") + } else { + format!("{}/{}", parent.trim_end_matches('/'), name) + } +} + +fn parent_path(path: &str) -> Option { + let trimmed = path.trim_end_matches('/'); + let (parent, _) = trimmed.rsplit_once('/')?; + if parent.is_empty() { + Some("/".to_string()) + } else { + Some(parent.to_string()) + } +} + +fn ancestor_paths(path: &str) -> Vec { + let absolute = path.starts_with('/'); + let parts: Vec<&str> = path + .trim_matches('/') + .split('/') + .filter(|part| !part.is_empty()) + .collect(); + let mut ancestors = Vec::new(); + for len in 1..parts.len() { + let joined = parts[..len].join("/"); + ancestors.push(if absolute { + format!("/{joined}") + } else { + joined + }); + } + ancestors +} + +fn js_err(e: &wasm_bindgen::JsValue) -> OpErrorKind { + OpErrorKind::Other(e.as_string().unwrap_or_else(|| format!("{e:?}"))) +} + +// ============================================================================ +// IoClassFsFile — all File handle methods return Unsupported in WASM. +// The native tokio file-handle model (open/read/write/seek/close) cannot be +// mapped to the browser sandbox. +// ============================================================================ + +impl io::IoClassFsFile for WasmIoFs { + fn text( + &self, + _h: &Arc, + _c: CallId, + _f: owned::fs::File, + _ctx: &SysOpContext, + ) -> SysOpOutput { + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn bytes( + &self, + _h: &Arc, + _c: CallId, + _f: owned::fs::File, + _ctx: &SysOpContext, + ) -> SysOpOutput> { + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn read( + &self, + _h: &Arc, + _c: CallId, + _f: owned::fs::File, + _n: i64, + _ctx: &SysOpContext, + ) -> SysOpOutput { + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn read_bytes( + &self, + _h: &Arc, + _c: CallId, + _f: owned::fs::File, + _n: i64, + _ctx: &SysOpContext, + ) -> SysOpOutput> { + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn close( + &self, + _h: &Arc, + _c: CallId, + _f: owned::fs::File, + _ctx: &SysOpContext, + ) -> SysOpOutput<()> { + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn seek_from( + &self, + _h: &Arc, + _c: CallId, + _f: owned::fs::File, + _w: BexExternalValue, + _o: i64, + _ctx: &SysOpContext, + ) -> SysOpOutput { + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn write( + &self, + _h: &Arc, + _c: CallId, + _f: owned::fs::File, + _d: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn write_bytes( + &self, + _h: &Arc, + _c: CallId, + _f: owned::fs::File, + _d: Vec, + _ctx: &SysOpContext, + ) -> SysOpOutput { + SysOpOutput::err(OpErrorKind::Unsupported) + } +} + +// ============================================================================ +// IoNamespaceFs — delegates to WasmVfs JS callbacks. +// ============================================================================ + +impl io::IoNamespaceFs for WasmIoFs { + fn open( + &self, + _h: &Arc, + _c: CallId, + _path: String, + _mode: BexExternalValue, + _ctx: &SysOpContext, + ) -> SysOpOutput { + // File handle operations not supported in WASM. + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn exists( + &self, + _h: &Arc, + _c: CallId, + path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + match self.vfs().vfs_exists(&path) { + Ok(v) => SysOpOutput::ok(v), + Err(e) => SysOpOutput::err(OpErrorKind::Other(format!("{e:?}"))), + } + } + + fn remove( + &self, + _h: &Arc, + _c: CallId, + path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput<()> { + match self.vfs().vfs_remove_file(&path) { + Ok(()) => SysOpOutput::ok(()), + Err(e) => SysOpOutput::err(OpErrorKind::Other(format!("{e:?}"))), + } + } + + fn size( + &self, + _h: &Arc, + _c: CallId, + path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + match self.vfs().vfs_metadata(&path) { + Ok(meta) => match i64::try_from(meta.len) { + Ok(n) => SysOpOutput::ok(n), + Err(_) => SysOpOutput::err(OpErrorKind::Other(format!( + "File '{path}' size exceeds i64::MAX" + ))), + }, + Err(e) => SysOpOutput::err(OpErrorKind::Other(format!("{e:?}"))), + } + } + + fn read( + &self, + _h: &Arc, + _c: CallId, + path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + match self.vfs().vfs_read_file(&path) { + Ok(bytes) => match String::from_utf8(bytes.to_vec()) { + Ok(s) => SysOpOutput::ok(s), + Err(e) => SysOpOutput::err(OpErrorKind::Other(format!("UTF-8 error: {e}"))), + }, + Err(e) => SysOpOutput::err(OpErrorKind::Other(format!("{e:?}"))), + } + } + + fn write( + &self, + _h: &Arc, + _c: CallId, + path: String, + content: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + let data = content.into_bytes(); + let len = i64::try_from(data.len()).unwrap_or(i64::MAX); + let uint8 = Uint8Array::from(data.as_slice()); + match self.vfs().vfs_write_file(&path, &uint8) { + Ok(()) => SysOpOutput::ok(len), + Err(e) => SysOpOutput::err(OpErrorKind::Other(format!("{e:?}"))), + } + } + + fn write_bytes( + &self, + _h: &Arc, + _c: CallId, + path: String, + content: Vec, + _ctx: &SysOpContext, + ) -> SysOpOutput { + let len = i64::try_from(content.len()).unwrap_or(i64::MAX); + let uint8 = Uint8Array::from(content.as_slice()); + match self.vfs().vfs_write_file(&path, &uint8) { + Ok(()) => SysOpOutput::ok(len), + Err(e) => SysOpOutput::err(OpErrorKind::Other(format!("{e:?}"))), + } + } + + fn read_dir( + &self, + _h: &Arc, + _c: CallId, + path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput> { + // Try the rich `readDirEntries` JS method first — one round-trip + // returns names + types + symlink info for the whole directory. Hosts + // that haven't implemented it yet error here, and we fall back to the + // legacy `readDir` (string[]) path that probes `metadata` per entry. + match self.vfs().vfs_read_dir_entries(&path) { + Ok(arr) => { + let mut entries = Vec::with_capacity(arr.length() as usize); + for v in arr.iter() { + let entry: crate::wasm_fs::WasmVfsDirEntry = + match serde_wasm_bindgen::from_value(v) { + Ok(e) => e, + Err(e) => { + return SysOpOutput::err(OpErrorKind::Other(format!( + "readDirEntries returned invalid entry: {e}" + ))); + } + }; + entries.push(owned::fs::DirEntry { + is_dir: entry.file_type == "directory", + is_file: entry.file_type == "file", + name: entry.name, + is_symlink: entry.is_symlink, + }); + } + return SysOpOutput::ok(entries); + } + Err(_) => { /* fall through to legacy path */ } + } + + match self.vfs().vfs_read_dir(&path) { + Ok(arr) => { + let mut entries = Vec::with_capacity(arr.length() as usize); + for v in arr.iter() { + let Some(name) = v.as_string() else { + return SysOpOutput::err(OpErrorKind::Other( + "readDir entry is not a string".into(), + )); + }; + // Legacy readDir doesn't expose type info. Probe metadata + // per entry. Hosts that care about read_dir performance + // should implement `readDirEntries`. + let full = join_path(&path, &name); + let (is_dir, is_file) = match self.vfs().vfs_metadata(&full) { + Ok(meta) => (meta.file_type == "directory", meta.file_type == "file"), + Err(e) => return SysOpOutput::err(js_err(&e)), + }; + entries.push(owned::fs::DirEntry { + name, + is_dir, + is_file, + is_symlink: false, + }); + } + SysOpOutput::ok(entries) + } + Err(e) => SysOpOutput::err(OpErrorKind::Other(format!("{e:?}"))), + } + } + + fn mkdir( + &self, + _h: &Arc, + _c: CallId, + path: String, + options: owned::fs::MkdirOptions, + _ctx: &SysOpContext, + ) -> SysOpOutput<()> { + if !options.recursive { + match self.vfs().vfs_exists(&path) { + Ok(true) => { + return SysOpOutput::err(OpErrorKind::Other(format!( + "Directory already exists: {path}" + ))); + } + Ok(false) => {} + Err(e) => return SysOpOutput::err(js_err(&e)), + } + + if let Some(parent) = parent_path(&path) { + match self.vfs().vfs_exists(&parent) { + Ok(true) => {} + Ok(false) => { + return SysOpOutput::err(OpErrorKind::Other(format!( + "Parent directory does not exist: {parent}" + ))); + } + Err(e) => return SysOpOutput::err(js_err(&e)), + } + } + + return match self.vfs().vfs_create_dir(&path) { + Ok(()) => SysOpOutput::ok(()), + Err(e) => SysOpOutput::err(js_err(&e)), + }; + } + + match self.vfs().vfs_exists(&path) { + Ok(true) => match self.vfs().vfs_metadata(&path) { + Ok(meta) if meta.file_type == "directory" => return SysOpOutput::ok(()), + Ok(_) => { + return SysOpOutput::err(OpErrorKind::Other(format!( + "Path exists and is not a directory: {path}" + ))); + } + Err(e) => return SysOpOutput::err(js_err(&e)), + }, + Ok(false) => {} + Err(e) => return SysOpOutput::err(js_err(&e)), + } + + for ancestor in ancestor_paths(&path) { + match self.vfs().vfs_exists(&ancestor) { + Ok(true) => continue, + Ok(false) => {} + Err(e) => return SysOpOutput::err(js_err(&e)), + } + if let Err(e) = self.vfs().vfs_create_dir(&ancestor) { + return SysOpOutput::err(js_err(&e)); + } + } + + match self.vfs().vfs_create_dir(&path) { + Ok(()) => SysOpOutput::ok(()), + Err(e) => { + // Idempotency: only swallow the create error if the path + // already exists *as a directory* (e.g. an external concurrent + // mutator beat us to it). If something else exists at that + // path — a regular file, a symlink, anything non-directory — + // this is a real failure and we propagate. The previous code + // checked `vfs_exists` and returned Ok on any existing entry, + // turning real `mkdir` failures into silent success when + // something happened to occupy the path. + // + // Long-term: the JS VFS contract should grow `createDir(path, + // { recursive: bool })` so the host handles this atomically + // and we don't need this many round-trips at all. + match self.vfs().vfs_metadata(&path) { + Ok(meta) if meta.file_type == "directory" => SysOpOutput::ok(()), + _ => SysOpOutput::err(js_err(&e)), + } + } + } + } +} diff --git a/baml_language/crates/bridge_wasm/src/wasm_io_glob.rs b/baml_language/crates/bridge_wasm/src/wasm_io_glob.rs new file mode 100644 index 0000000000..881bfa16b4 --- /dev/null +++ b/baml_language/crates/bridge_wasm/src/wasm_io_glob.rs @@ -0,0 +1,343 @@ +//! WASM `baml.glob` namespace implementation via `WasmVfs` JS callbacks. +//! +//! `WasmIoGlob` implements `IoNamespaceGlob` and `IoClassGlobGlob` for WASM: +//! +//! - `new(pattern)` — compiles the pattern via `sys_glob::GlobPattern` and +//! stores the resulting compiled regex in the glob handle so subsequent +//! `scan` and `matches` calls reuse it without recompilation. +//! - `Glob.scan(root)` — walks the VFS via `WasmVfs.readDir` and filters with +//! the compiled `GlobPattern` from the handle. +//! - `Glob.matches(path)` — pure-Rust glob matching via the compiled +//! `GlobPattern` from the handle. + +use std::sync::Arc; + +use sys_glob::GlobPattern; +use sys_ops::io::{self, BexExternalValue, CallId, OpErrorKind, SysOpContext, SysOpOutput, owned}; +use sys_types::BexHeap; + +use crate::{send_wrapper::SendWrapper, wasm_fs::WasmVfs}; + +/// WASM implementation of `baml.glob` namespace + `Glob` class. +pub(crate) struct WasmIoGlob { + vfs: SendWrapper>, +} + +impl WasmIoGlob { + /// Create a new `WasmIoGlob` from a shared VFS reference. + pub(crate) fn new(vfs: Arc) -> Self { + Self { + vfs: SendWrapper::new(vfs), + } + } + + fn vfs(&self) -> &WasmVfs { + self.vfs.as_ref() + } +} + +// ============================================================================ +// IoNamespaceGlob — `baml.glob.new(pattern)` creates a Glob handle. +// ============================================================================ + +type GlobHandle = GlobPattern; + +fn downcast_glob_handle(glob: &owned::glob::Glob) -> Result, OpErrorKind> { + glob._handle + .clone() + .downcast::() + .map_err(|_| OpErrorKind::Other("Invalid glob handle type".into())) +} + +impl io::IoNamespaceGlob for WasmIoGlob { + fn new( + &self, + _h: &Arc, + _c: CallId, + pattern: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + match GlobPattern::new(&pattern) { + Ok(compiled) => { + let handle: Arc = Arc::new(compiled); + SysOpOutput::ok(owned::glob::Glob { _handle: handle }) + } + Err(e) => SysOpOutput::err(OpErrorKind::Other(e)), + } + } +} + +// ============================================================================ +// IoClassGlobGlob — `Glob.scan` and `Glob.matches` method implementations. +// ============================================================================ + +impl io::IoClassGlobGlob for WasmIoGlob { + fn scan( + &self, + _h: &Arc, + _c: CallId, + glob: owned::glob::Glob, + root: BexExternalValue, + _ctx: &SysOpContext, + ) -> SysOpOutput> { + let compiled = match downcast_glob_handle(&glob) { + Ok(c) => c, + Err(e) => return SysOpOutput::err(e), + }; + let scan_args = match ScanArgs::from_root(&root) { + Ok(args) => args, + Err(e) => return SysOpOutput::err(OpErrorKind::Other(e)), + }; + + let mut scanned_paths = Vec::new(); + if let Err(e) = collect_scan_paths( + self.vfs(), + &scan_args.cwd, + scan_args.dot, + scan_args.only_files, + &mut scanned_paths, + ) { + return SysOpOutput::err(OpErrorKind::Other(e)); + } + + let mut paths = Vec::new(); + for path in scanned_paths { + let Some(rel_path) = relative_to_root(&path, &scan_args.cwd) else { + continue; + }; + if rel_path.is_empty() { + continue; + } + if !scan_args.dot && rel_path.split('/').any(|seg| seg.starts_with('.')) { + continue; + } + + if !compiled.is_match_entry(&rel_path, &path) { + continue; + } + + if scan_args.absolute { + paths.push(absolute_path(&scan_args.cwd, &path)); + } else { + paths.push(rel_path); + } + } + SysOpOutput::ok(paths) + } + + fn matches( + &self, + _h: &Arc, + _c: CallId, + glob: owned::glob::Glob, + path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + match downcast_glob_handle(&glob) { + Ok(compiled) => SysOpOutput::ok(compiled.is_match(&path)), + Err(e) => SysOpOutput::err(e), + } + } +} + +struct ScanArgs { + cwd: String, + dot: bool, + absolute: bool, + only_files: bool, +} + +impl ScanArgs { + fn from_root(root: &BexExternalValue) -> Result { + match root { + BexExternalValue::String(cwd) => Ok(Self { + cwd: normalize_cwd(cwd), + dot: false, + absolute: false, + only_files: true, + }), + BexExternalValue::Instance { fields, .. } => { + let cwd = get_string_field(fields, "cwd", ".")?; + let dot = get_bool_field(fields, "dot", false)?; + let absolute = get_bool_field(fields, "absolute", false)?; + let only_files = get_bool_field(fields, "only_files", true)?; + let _follow_symlinks = get_bool_field(fields, "follow_symlinks", false)?; + let _throw_on_broken = + get_bool_field(fields, "throw_error_on_broken_symlink", false)?; + Ok(Self { + cwd: normalize_cwd(&cwd), + dot, + absolute, + only_files, + }) + } + _ => Err("scan argument must be a string or ScanOptions".into()), + } + } +} + +/// WASM has no process-cwd concept, so a relative `cwd` like `.` or `""` +/// has no natural anchor. The pragmatic interpretation: treat them as the +/// VFS root (`/`). Without this, `Glob.scan(ScanOptions { cwd: ".", absolute: +/// true })` would silently return paths that aren't absolute, and the +/// underlying VFS calls (`readDir(".")`) would also miss any host that +/// serves paths under `/`. +fn normalize_cwd(cwd: &str) -> String { + if cwd == "." || cwd.is_empty() { + "/".to_string() + } else { + cwd.to_string() + } +} + +fn join_path(parent: &str, name: &str) -> String { + if parent == "/" { + format!("/{name}") + } else { + format!("{}/{}", parent.trim_end_matches('/'), name) + } +} + +fn js_err(e: &wasm_bindgen::JsValue) -> String { + e.as_string().unwrap_or_else(|| format!("{e:?}")) +} + +fn collect_scan_paths( + vfs: &WasmVfs, + path: &str, + dot: bool, + only_files: bool, + out: &mut Vec, +) -> Result<(), String> { + // Prefer the rich `readDirEntries` method so we get name + type info in + // one JS round-trip per directory. Hosts that haven't implemented it + // surface an error from the binding; in that case fall back to the + // legacy readDir + per-entry metadata loop. + if let Ok(entries) = vfs.vfs_read_dir_entries(path) { + for v in entries.iter() { + let entry: crate::wasm_fs::WasmVfsDirEntry = serde_wasm_bindgen::from_value(v) + .map_err(|e| format!("readDirEntries returned invalid entry: {e}"))?; + if !dot && entry.name.starts_with('.') { + continue; + } + let full_path = join_path(path, &entry.name); + match entry.file_type.as_str() { + "file" => out.push(full_path), + "directory" => { + if !only_files { + out.push(full_path.clone()); + } + collect_scan_paths(vfs, &full_path, dot, only_files, out)?; + } + _ => {} + } + } + return Ok(()); + } + + let entries = vfs.vfs_read_dir(path).map_err(|e| js_err(&e))?; + for entry in entries.iter() { + let name = entry + .as_string() + .ok_or_else(|| "readDir entry is not a string".to_string())?; + if !dot && name.starts_with('.') { + continue; + } + + let full_path = join_path(path, &name); + let meta = vfs.vfs_metadata(&full_path).map_err(|e| js_err(&e))?; + match meta.file_type.as_str() { + "file" => out.push(full_path), + "directory" => { + if !only_files { + out.push(full_path.clone()); + } + collect_scan_paths(vfs, &full_path, dot, only_files, out)?; + } + _ => {} + } + } + Ok(()) +} + +fn get_string_field( + fields: &indexmap::IndexMap, + key: &str, + default: &str, +) -> Result { + match fields.get(key) { + None | Some(BexExternalValue::Null) => Ok(default.to_string()), + Some(value) => value.as_string().ok_or_else(|| { + format!( + "ScanOptions.{key} must be a string, got {}", + value.type_name() + ) + }), + } +} + +fn get_bool_field( + fields: &indexmap::IndexMap, + key: &str, + default: bool, +) -> Result { + match fields.get(key) { + None | Some(BexExternalValue::Null) => Ok(default), + Some(value) => value.as_bool().ok_or_else(|| { + format!( + "ScanOptions.{key} must be a bool, got {}", + value.type_name() + ) + }), + } +} + +fn normalize_path(path: &str) -> String { + let path = path.replace('\\', "/"); + if path == "/" { + path + } else { + path.trim_end_matches('/').to_string() + } +} + +fn relative_to_root(path: &str, root: &str) -> Option { + let path = normalize_path(path); + let root = normalize_path(root); + + if root == "." || root.is_empty() { + return Some(path.strip_prefix("./").unwrap_or(&path).to_string()); + } + if root == "/" { + return Some(path.strip_prefix('/').unwrap_or(&path).to_string()); + } + if path == root { + return Some(String::new()); + } + + let prefix = format!("{root}/"); + path.strip_prefix(&prefix).map(ToString::to_string) +} + +fn absolute_path(root: &str, path: &str) -> String { + let path = normalize_path(path); + if path.starts_with('/') { + return path; + } + + let root = normalize_path(root); + if root.starts_with('/') { + if root == "/" { + format!("/{path}") + } else { + format!("{root}/{path}") + } + } else { + // Unreachable in practice — `ScanArgs::from_root` normalizes `.` + // and `""` to `/`, so the only way we'd get here is a relative + // cwd like `foo/bar` that the caller built directly. There's no + // process cwd in WASM to resolve it against; anchor to the VFS + // root rather than silently returning a non-absolute path. + format!("/{path}") + } +} diff --git a/baml_language/crates/bridge_wasm/tests/wasm_fs_glob.rs b/baml_language/crates/bridge_wasm/tests/wasm_fs_glob.rs new file mode 100644 index 0000000000..6ef1e8e31a --- /dev/null +++ b/baml_language/crates/bridge_wasm/tests/wasm_fs_glob.rs @@ -0,0 +1,585 @@ +// WASM integration tests for `baml.fs` and `baml.glob` operations. +// +// These tests verify that the `bridge_wasm` crate correctly wires up the +// fs and glob IO namespaces via mock JS objects under Node's WASM runtime. +// +// Run with: +// cd baml_language/crates/bridge_wasm && wasm-pack test --node + +use bridge_wasm::{ + BamlWasmRuntime, LspNotification, + baml::cffi::{ + BamlOutboundValue, CallFunctionArgs, baml_outbound_value::Value as OutboundValue, + }, +}; +use prost::Message; +use wasm_bindgen::{JsCast, prelude::*}; +use wasm_bindgen_test::*; + +wasm_bindgen_test_configure!(run_in_node_experimental); + +/// Helper: build a mock VFS JS object with all required methods. +/// +/// Implements an in-memory filesystem backed by a JS object so we can test +/// that the Rust WASM bridge correctly calls through to the JS VFS layer. +fn mock_vfs(files: &[(&str, &str)], dirs: &[&str]) -> JsValue { + let obj = js_sys::Object::new(); + + let files_obj = js_sys::Object::new(); + for (path, content) in files { + js_sys::Reflect::set( + &files_obj, + &JsValue::from_str(path), + &JsValue::from_str(content), + ) + .unwrap(); + } + + let dirs_arr = js_sys::Array::new(); + for d in dirs { + dirs_arr.push(&JsValue::from_str(d)); + } + + js_sys::Reflect::set(&obj, &JsValue::from_str("_files"), &files_obj).unwrap(); + js_sys::Reflect::set(&obj, &JsValue::from_str("_dirs"), &dirs_arr).unwrap(); + // Tests that need to mark specific paths as symlinks set + // `vfs._symlinks[path] = true` after the mock is built. Default empty + // so non-symlink tests see is_symlink=false everywhere. + js_sys::Reflect::set( + &obj, + &JsValue::from_str("_symlinks"), + &js_sys::Object::new(), + ) + .unwrap(); + + // readDir(path) -> string[] + js_sys::Reflect::set( + &obj, + &JsValue::from_str("readDir"), + &js_sys::Function::new_with_args( + "path", + r#" + var result = []; + var files = this._files; + var dirs = this._dirs; + var prefix = path.endsWith('/') ? path : path + '/'; + var keys = Object.keys(files); + for (var i = 0; i < keys.length; i++) { + if (keys[i].startsWith(prefix)) { + var rest = keys[i].slice(prefix.length); + if (rest.indexOf('/') === -1) result.push(rest); + } + } + for (var j = 0; j < dirs.length; j++) { + if (dirs[j].startsWith(prefix)) { + var rest = dirs[j].slice(prefix.length); + if (rest.indexOf('/') === -1 && rest.length > 0) result.push(rest); + } + } + return result; + "#, + ), + ) + .unwrap(); + + // readDirEntries(path) -> Array<{ name, fileType, isSymlink }> + // Rich form preferred by baml.fs.read_dir / baml.glob.scan; one + // round-trip per directory instead of N+1. + js_sys::Reflect::set( + &obj, + &JsValue::from_str("readDirEntries"), + &js_sys::Function::new_with_args( + "path", + r#" + var result = []; + var files = this._files; + var dirs = this._dirs; + var symlinks = this._symlinks || {}; + var prefix = path.endsWith('/') ? path : path + '/'; + var keys = Object.keys(files); + for (var i = 0; i < keys.length; i++) { + if (keys[i].startsWith(prefix)) { + var rest = keys[i].slice(prefix.length); + if (rest.indexOf('/') === -1) { + result.push({ + name: rest, + file_type: 'file', + is_symlink: !!symlinks[keys[i]], + }); + } + } + } + for (var j = 0; j < dirs.length; j++) { + if (dirs[j].startsWith(prefix)) { + var rest2 = dirs[j].slice(prefix.length); + if (rest2.indexOf('/') === -1 && rest2.length > 0) { + result.push({ + name: rest2, + file_type: 'directory', + is_symlink: !!symlinks[dirs[j]], + }); + } + } + } + return result; + "#, + ), + ) + .unwrap(); + + // createDir(path) -> void + js_sys::Reflect::set( + &obj, + &JsValue::from_str("createDir"), + &js_sys::Function::new_with_args("path", "this._dirs.push(path);"), + ) + .unwrap(); + + // exists(path) -> boolean + js_sys::Reflect::set( + &obj, + &JsValue::from_str("exists"), + &js_sys::Function::new_with_args( + "path", + r#" + if (this._files.hasOwnProperty(path)) return true; + for (var i = 0; i < this._dirs.length; i++) { + if (this._dirs[i] === path) return true; + } + return false; + "#, + ), + ) + .unwrap(); + + // readFile(path) -> Uint8Array + js_sys::Reflect::set( + &obj, + &JsValue::from_str("readFile"), + &js_sys::Function::new_with_args( + "path", + r#" + var content = this._files[path]; + if (content === undefined) throw new Error('File not found: ' + path); + return new TextEncoder().encode(content); + "#, + ), + ) + .unwrap(); + + // writeFile(path, data) -> void + js_sys::Reflect::set( + &obj, + &JsValue::from_str("writeFile"), + &js_sys::Function::new_with_args( + "path, data", + "this._files[path] = new TextDecoder().decode(data);", + ), + ) + .unwrap(); + + // metadata(path) -> { fileType, len, ... } + js_sys::Reflect::set( + &obj, + &JsValue::from_str("metadata"), + &js_sys::Function::new_with_args( + "path", + r#" + if (this._files.hasOwnProperty(path)) { + var len = new TextEncoder().encode(this._files[path]).length; + return { fileType: 'file', file_type: 'file', len: len }; + } + for (var i = 0; i < this._dirs.length; i++) { + if (this._dirs[i] === path) { + return { fileType: 'directory', file_type: 'directory', len: 0 }; + } + } + throw new Error('Not found: ' + path); + "#, + ), + ) + .unwrap(); + + // removeFile(path) -> void + js_sys::Reflect::set( + &obj, + &JsValue::from_str("removeFile"), + &js_sys::Function::new_with_args("path", "delete this._files[path];"), + ) + .unwrap(); + + // removeDir(path) -> void + js_sys::Reflect::set( + &obj, + &JsValue::from_str("removeDir"), + &js_sys::Function::new_with_args( + "path", + "this._dirs = this._dirs.filter(function(d) { return d !== path; });", + ), + ) + .unwrap(); + + // setTime, copyFile, moveFile, moveDir — stubs + let noop2 = js_sys::Function::new_with_args("a, b", ""); + let noop3 = js_sys::Function::new_with_args("a, b, c", ""); + js_sys::Reflect::set(&obj, &JsValue::from_str("setTime"), &noop3).unwrap(); + js_sys::Reflect::set(&obj, &JsValue::from_str("copyFile"), &noop2).unwrap(); + js_sys::Reflect::set(&obj, &JsValue::from_str("moveFile"), &noop2).unwrap(); + js_sys::Reflect::set(&obj, &JsValue::from_str("moveDir"), &noop2).unwrap(); + + // readMany(glob) -> [string, Uint8Array][] + js_sys::Reflect::set( + &obj, + &JsValue::from_str("readMany"), + &js_sys::Function::new_with_args( + "glob", + r#" + function matches(path) { + if (glob === '/workspace/baml_src/**/*.baml') { + return path.startsWith('/workspace/baml_src/') && path.endsWith('.baml'); + } + return true; + } + var result = []; + var keys = Object.keys(this._files); + for (var i = 0; i < keys.length; i++) { + if (!matches(keys[i])) continue; + result.push([keys[i], new TextEncoder().encode(this._files[keys[i]])]); + } + return result; + "#, + ), + ) + .unwrap(); + + obj.into() +} + +fn callbacks() -> JsValue { + let obj = js_sys::Object::new(); + js_sys::Reflect::set( + &obj, + &JsValue::from_str("fetch"), + &js_sys::Function::new_with_args( + "callId, method, url, headersJson, body", + "return Promise.reject(new Error('fetch is not available in this test'));", + ), + ) + .unwrap(); + js_sys::Reflect::set( + &obj, + &JsValue::from_str("env"), + &js_sys::Function::new_with_args("variable", "return undefined;"), + ) + .unwrap(); + js_sys::Reflect::set( + &obj, + &JsValue::from_str("input"), + &js_sys::Function::new_with_args("callId, prompt", "return '';"), + ) + .unwrap(); + + let noop = js_sys::Function::new_with_args("value", ""); + js_sys::Reflect::set(&obj, &JsValue::from_str("lsp_send_notification"), &noop).unwrap(); + js_sys::Reflect::set(&obj, &JsValue::from_str("lsp_send_response"), &noop).unwrap(); + js_sys::Reflect::set(&obj, &JsValue::from_str("lsp_make_request"), &noop).unwrap(); + js_sys::Reflect::set( + &obj, + &JsValue::from_str("playground_send_notification"), + &noop, + ) + .unwrap(); + + obj.into() +} + +fn open_project(runtime: &BamlWasmRuntime, source: &str) { + runtime.handle_notification(LspNotification { + method: "textDocument/didOpen".to_string(), + params: serde_json::json!({ + "textDocument": { + "uri": "file:///workspace/baml_src/main.baml", + "languageId": "baml", + "version": 1, + "text": source, + } + }), + }); +} + +fn runtime(files: &[(&str, &str)], dirs: &[&str], source: &str) -> BamlWasmRuntime { + runtime_with_symlinks(files, dirs, &[], source) +} + +fn runtime_with_symlinks( + files: &[(&str, &str)], + dirs: &[&str], + symlinks: &[&str], + source: &str, +) -> BamlWasmRuntime { + let vfs = mock_vfs(files, dirs); + if !symlinks.is_empty() { + let map = js_sys::Reflect::get(&vfs, &JsValue::from_str("_symlinks")).unwrap(); + for path in symlinks { + js_sys::Reflect::set(&map, &JsValue::from_str(path), &JsValue::TRUE).unwrap(); + } + } + let callbacks = callbacks(); + let runtime = BamlWasmRuntime::create(callbacks.unchecked_ref(), vfs.unchecked_into()).unwrap(); + open_project(&runtime, source); + runtime +} + +async fn call_no_args(runtime: &BamlWasmRuntime, call_id: u32, name: &str) -> BamlOutboundValue { + let args = CallFunctionArgs::default().encode_to_vec(); + let bytes = runtime + .call_function(call_id, "/workspace/baml_src".to_string(), name, &args) + .await + .unwrap(); + BamlOutboundValue::decode(bytes.as_slice()).unwrap() +} + +async fn call_no_args_result( + runtime: &BamlWasmRuntime, + call_id: u32, + name: &str, +) -> Result { + let args = CallFunctionArgs::default().encode_to_vec(); + let bytes = runtime + .call_function(call_id, "/workspace/baml_src".to_string(), name, &args) + .await?; + Ok(BamlOutboundValue::decode(bytes.as_slice()).unwrap()) +} + +fn bool_value(value: BamlOutboundValue) -> bool { + match value.value { + Some(OutboundValue::BoolValue(v)) => v, + other => panic!("expected bool result, got {other:?}"), + } +} + +fn string_list(value: BamlOutboundValue) -> Vec { + let Some(OutboundValue::ListValue(list)) = value.value else { + panic!("expected list result, got {:?}", value.value); + }; + list.items + .into_iter() + .map(|item| match item.value { + Some(OutboundValue::StringValue(s)) => s, + other => panic!("expected string list item, got {other:?}"), + }) + .collect() +} + +const FS_GLOB_SOURCE: &str = r#" +function MkdirRecursive() -> bool { + baml.fs.mkdir("/generated/nested", baml.fs.MkdirOptions { recursive: true }); + baml.fs.exists("/generated/nested") +} + +function MkdirRecursiveExistingFile() -> null { + baml.fs.mkdir("/workspace/data/a.txt", baml.fs.MkdirOptions { recursive: true }) +} + +function ReadDirNames() -> string[] { + let entries = baml.fs.read_dir("/workspace/data"); + entries.map((entry) -> { entry.name }) +} + +function ReadDirSymlinkFlags() -> bool[] { + let entries = baml.fs.read_dir("/workspace/data"); + entries.map((entry) -> { entry.is_symlink }) +} + +function ReadDirNamesAndSymlinks() -> string[] { + let entries = baml.fs.read_dir("/workspace/data"); + entries.map((entry) -> { + if (entry.is_symlink) { "L:" + entry.name } else { "F:" + entry.name } + }) +} + +function GlobMatchesTxt() -> bool { + let glob = baml.glob.new("**/*.txt"); + glob.matches("/workspace/data/a.txt") && !glob.matches("/workspace/data/b.rs") +} + +function GlobScanTxt() -> string[] { + let glob = baml.glob.new("**/*.txt"); + glob.scan("/workspace/data") +} + +function GlobScanAbsoluteOptions() -> string[] { + let glob = baml.glob.new("**/*.txt"); + glob.scan(baml.glob.ScanOptions { cwd: "/workspace/data", absolute: true }) +} + +function GlobScanDotCwdAbsolute() -> string[] { + let glob = baml.glob.new("workspace/data/*.txt"); + glob.scan(baml.glob.ScanOptions { cwd: ".", absolute: true }) +} + +function GlobScanDotOptions() -> string[] { + let glob = baml.glob.new("**/*.txt"); + glob.scan(baml.glob.ScanOptions { cwd: "/workspace/data", dot: true }) +} + +function GlobScanDirectoryOptions() -> string[] { + let glob = baml.glob.new("**/*.txt"); + glob.scan(baml.glob.ScanOptions { cwd: "/workspace/data", only_files: false }) +} +"#; + +fn runtime_files() -> Vec<(&'static str, &'static str)> { + vec![ + ("/workspace/baml_src/main.baml", FS_GLOB_SOURCE), + ("/workspace/data/a.txt", "aaa"), + ("/workspace/data/b.rs", "bbb"), + ("/workspace/data/.hidden.txt", "hidden"), + ("/workspace/data/sub/c.txt", "ccc"), + ] +} + +fn runtime_dirs() -> Vec<&'static str> { + vec![ + "/workspace", + "/workspace/baml_src", + "/workspace/data", + "/workspace/data/dir.txt", + "/workspace/data/sub", + ] +} + +#[wasm_bindgen_test] +async fn wasm_runtime_mkdir_recursive_then_exists() { + let files = runtime_files(); + let dirs = runtime_dirs(); + let runtime = runtime(&files, &dirs, FS_GLOB_SOURCE); + + let result = call_no_args(&runtime, 1, "MkdirRecursive").await; + assert!(bool_value(result)); +} + +#[wasm_bindgen_test] +async fn wasm_runtime_mkdir_recursive_errors_on_existing_file() { + let files = runtime_files(); + let dirs = runtime_dirs(); + let runtime = runtime(&files, &dirs, FS_GLOB_SOURCE); + + let result = call_no_args_result(&runtime, 2, "MkdirRecursiveExistingFile").await; + assert!(result.is_err()); +} + +#[wasm_bindgen_test] +async fn wasm_runtime_read_dir_returns_entries() { + let files = runtime_files(); + let dirs = runtime_dirs(); + let runtime = runtime(&files, &dirs, FS_GLOB_SOURCE); + + let result = call_no_args(&runtime, 3, "ReadDirNames").await; + let mut names = string_list(result); + names.sort(); + assert_eq!( + names, + vec![".hidden.txt", "a.txt", "b.rs", "dir.txt", "sub"] + ); +} + +#[wasm_bindgen_test] +async fn wasm_runtime_read_dir_surfaces_symlink_flag() { + // Mark `/workspace/data/a.txt` as a symlink in the mock VFS. The new + // readDirEntries path returns the flag in one round-trip; baml.fs.read_dir + // must propagate it through to the DirEntry.is_symlink field. Previously + // is_symlink was hard-coded to false in the WASM bridge. + let files = runtime_files(); + let dirs = runtime_dirs(); + let symlinks = vec!["/workspace/data/a.txt"]; + let runtime = runtime_with_symlinks(&files, &dirs, &symlinks, FS_GLOB_SOURCE); + + let result = call_no_args(&runtime, 9, "ReadDirNamesAndSymlinks").await; + let mut tagged = string_list(result); + tagged.sort(); + // a.txt is the only entry tagged as a symlink. + assert_eq!( + tagged, + vec!["F:.hidden.txt", "F:b.rs", "F:dir.txt", "F:sub", "L:a.txt",] + ); +} + +#[wasm_bindgen_test] +async fn wasm_runtime_glob_matches_paths() { + let files = runtime_files(); + let dirs = runtime_dirs(); + let runtime = runtime(&files, &dirs, FS_GLOB_SOURCE); + + let result = call_no_args(&runtime, 4, "GlobMatchesTxt").await; + assert!(bool_value(result)); +} + +#[wasm_bindgen_test] +async fn wasm_runtime_glob_scan_filters_paths() { + let files = runtime_files(); + let dirs = runtime_dirs(); + let runtime = runtime(&files, &dirs, FS_GLOB_SOURCE); + + let result = call_no_args(&runtime, 5, "GlobScanTxt").await; + let mut paths = string_list(result); + paths.sort(); + assert_eq!(paths, vec!["a.txt", "sub/c.txt"]); +} + +#[wasm_bindgen_test] +async fn wasm_runtime_glob_scan_absolute_options() { + let files = runtime_files(); + let dirs = runtime_dirs(); + let runtime = runtime(&files, &dirs, FS_GLOB_SOURCE); + + let result = call_no_args(&runtime, 6, "GlobScanAbsoluteOptions").await; + let mut paths = string_list(result); + paths.sort(); + assert_eq!( + paths, + vec!["/workspace/data/a.txt", "/workspace/data/sub/c.txt"] + ); +} + +#[wasm_bindgen_test] +async fn wasm_runtime_glob_scan_dot_cwd_absolute() { + // `cwd: "."` has no process-cwd in WASM; it must be normalized to the + // VFS root so that `absolute: true` produces actual absolute paths + // (previously this silently returned relative-looking strings). + let files = runtime_files(); + let dirs = runtime_dirs(); + let runtime = runtime(&files, &dirs, FS_GLOB_SOURCE); + + let result = call_no_args(&runtime, 10, "GlobScanDotCwdAbsolute").await; + let mut paths = string_list(result); + paths.sort(); + assert_eq!(paths, vec!["/workspace/data/a.txt"]); + for p in &paths { + assert!(p.starts_with('/'), "expected absolute path, got: {p}"); + } +} + +#[wasm_bindgen_test] +async fn wasm_runtime_glob_scan_dot_options() { + let files = runtime_files(); + let dirs = runtime_dirs(); + let runtime = runtime(&files, &dirs, FS_GLOB_SOURCE); + + let result = call_no_args(&runtime, 7, "GlobScanDotOptions").await; + let mut paths = string_list(result); + paths.sort(); + assert_eq!(paths, vec![".hidden.txt", "a.txt", "sub/c.txt"]); +} + +#[wasm_bindgen_test] +async fn wasm_runtime_glob_scan_directory_options() { + let files = runtime_files(); + let dirs = runtime_dirs(); + let runtime = runtime(&files, &dirs, FS_GLOB_SOURCE); + + let result = call_no_args(&runtime, 8, "GlobScanDirectoryOptions").await; + let mut paths = string_list(result); + paths.sort(); + assert_eq!(paths, vec!["a.txt", "dir.txt", "sub/c.txt"]); +} diff --git a/baml_language/crates/sys_glob/Cargo.toml b/baml_language/crates/sys_glob/Cargo.toml new file mode 100644 index 0000000000..fb81d70a9c --- /dev/null +++ b/baml_language/crates/sys_glob/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "sys_glob" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +authors.workspace = true +license.workspace = true + +[dependencies] +regex = { workspace = true } + +[lints] +workspace = true + +[package.metadata.ci] +wasm_support = true diff --git a/baml_language/crates/sys_glob/src/lib.rs b/baml_language/crates/sys_glob/src/lib.rs new file mode 100644 index 0000000000..8eb39e4c2e --- /dev/null +++ b/baml_language/crates/sys_glob/src/lib.rs @@ -0,0 +1,324 @@ +//! Bun-compatible glob pattern matcher shared by `sys_native` and `bridge_wasm`. +//! +//! Supports: `*` (any non-separator chars), `**` (any chars including separators), +//! `?` (single non-separator char), `[...]` (character classes), `{a,b}` (alternations), +//! `!` prefix (negation), `\` (escape). + +use regex::Regex; + +pub struct GlobPattern { + re: Regex, + negated: bool, + target: MatchTarget, +} + +/// Which path representation a glob pattern is meant to be tested against. +/// +/// Decided once at compile time from the pattern's leading characters. Picking +/// a canonical form avoids the false positives an OR-against-three-forms +/// strategy produces: e.g. `.*` would match every file via the `./` +/// form, even files that don't actually start with a dot. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum MatchTarget { + /// Plain pattern (`foo.txt`, `**/*.ts`) — match against the entry's + /// path relative to the scan root (e.g. `src/foo.ts`). + Relative, + /// `./`-prefixed pattern (`./*.txt`) — match against `./`. + DotRelative, + /// Absolute pattern (`/abs/*.ts`) — match against the entry's absolute + /// path. + Absolute, +} + +impl GlobPattern { + pub fn new(pattern: &str) -> Result { + // Negation is `!` followed by an inner pattern; classify by the inner + // pattern's shape, not the leading `!`. + let inner = pattern.strip_prefix('!').unwrap_or(pattern); + let target = if inner.starts_with('/') { + MatchTarget::Absolute + } else if inner.starts_with("./") { + MatchTarget::DotRelative + } else { + MatchTarget::Relative + }; + let (re, negated) = glob_to_regex(pattern)?; + Ok(Self { + re, + negated, + target, + }) + } + + pub fn target(&self) -> MatchTarget { + self.target + } + + /// Test a single arbitrary path string against the compiled pattern. + /// Used by `Glob.matches(path)` where the caller decides what to pass. + pub fn is_match(&self, path: &str) -> bool { + let matched = self.re.is_match(path); + if self.negated { !matched } else { matched } + } + + /// Test a directory-walk entry, picking the canonical path form based on + /// the pattern's shape. Used by `Glob.scan` so callers don't have to + /// reimplement the form-selection rule. + pub fn is_match_entry(&self, rel: &str, abs: &str) -> bool { + let dot_rel; + let path = match self.target { + MatchTarget::Relative => rel, + MatchTarget::DotRelative => { + dot_rel = format!("./{rel}"); + &dot_rel + } + MatchTarget::Absolute => abs, + }; + let matched = self.re.is_match(path); + if self.negated { !matched } else { matched } + } +} + +fn glob_to_regex(glob: &str) -> Result<(Regex, bool), String> { + let (negated, glob) = if let Some(rest) = glob.strip_prefix('!') { + (true, rest) + } else { + (false, glob) + }; + + let mut re = String::from("^"); + let bytes = glob.as_bytes(); + let mut i = 0; + while i < bytes.len() { + match bytes[i] { + b'\\' if i + 1 < bytes.len() => { + let ch = bytes[i + 1] as char; + re.push_str(®ex::escape(&ch.to_string())); + i += 2; + } + b'*' if i + 1 < bytes.len() && bytes[i + 1] == b'*' => { + i += 2; + // Consume trailing slash after `**` so `**/foo` matches `foo` at root too + if i < bytes.len() && bytes[i] == b'/' { + re.push_str("(?:.*/)?"); + i += 1; + } else { + re.push_str(".*"); + } + } + b'*' => { + re.push_str("[^/]*"); + i += 1; + } + b'?' => { + re.push_str("[^/]"); + i += 1; + } + b'[' => { + let start = i; + i += 1; + let mut class = String::from("["); + if i < bytes.len() && (bytes[i] == b'^' || bytes[i] == b'!') { + class.push('^'); + i += 1; + } + // Allow ] as first char in class + if i < bytes.len() && bytes[i] == b']' { + class.push(']'); + i += 1; + } + while i < bytes.len() && bytes[i] != b']' { + class.push(bytes[i] as char); + i += 1; + } + if i < bytes.len() { + class.push(']'); + i += 1; + re.push_str(&class); + } else { + // Unterminated bracket — treat as literal + re.push_str(®ex::escape( + String::from_utf8_lossy(&bytes[start..]).as_ref(), + )); + } + } + b'{' => { + if let Some((alts, next)) = parse_brace_alternation(bytes, i + 1) { + re.push_str(&alts); + i = next; + } else { + re.push_str("\\{"); + i += 1; + } + } + ch => { + let c = ch as char; + push_regex_literal(&mut re, c); + i += 1; + } + } + } + re.push('$'); + + let regex = Regex::new(&re).map_err(|e| format!("Invalid glob pattern '{glob}': {e}"))?; + Ok((regex, negated)) +} + +fn parse_brace_alternation(bytes: &[u8], mut i: usize) -> Option<(String, usize)> { + let mut alts = String::from("(?:"); + while i < bytes.len() { + match bytes[i] { + b'\\' if i + 1 < bytes.len() => { + push_regex_literal(&mut alts, bytes[i + 1] as char); + i += 2; + } + b'{' => { + let (nested, next) = parse_brace_alternation(bytes, i + 1)?; + alts.push_str(&nested); + i = next; + } + b'}' => { + alts.push(')'); + return Some((alts, i + 1)); + } + b',' => { + alts.push('|'); + i += 1; + } + ch => { + push_regex_literal(&mut alts, ch as char); + i += 1; + } + } + } + None +} + +fn push_regex_literal(re: &mut String, c: char) { + if ".+^${}()|[]\\".contains(c) { + re.push('\\'); + } + re.push(c); +} + +#[cfg(test)] +mod tests { + use super::GlobPattern; + + #[test] + fn star_matches_file() { + let g = GlobPattern::new("*.txt").unwrap(); + assert!(g.is_match("hello.txt")); + assert!(!g.is_match("hello.rs")); + assert!(!g.is_match("dir/hello.txt")); // * doesn't cross separators + } + + #[test] + fn double_star_crosses_separator() { + let g = GlobPattern::new("**/*.ts").unwrap(); + assert!(g.is_match("src/index.ts")); + assert!(g.is_match("src/deep/file.ts")); + assert!(!g.is_match("src/index.rs")); + } + + #[test] + fn double_star_slash_preserves_separator_boundary() { + let g = GlobPattern::new("foo/**/bar").unwrap(); + assert!(g.is_match("foo/bar")); + assert!(g.is_match("foo/a/bar")); + assert!(g.is_match("foo/a/b/bar")); + assert!(!g.is_match("foo/xbar")); + } + + #[test] + fn question_mark() { + let g = GlobPattern::new("file?.txt").unwrap(); + assert!(g.is_match("fileA.txt")); + assert!(!g.is_match("file.txt")); + assert!(!g.is_match("fileAB.txt")); + } + + #[test] + fn alternation() { + let g = GlobPattern::new("*.{ts,tsx}").unwrap(); + assert!(g.is_match("app.ts")); + assert!(g.is_match("app.tsx")); + assert!(!g.is_match("app.js")); + } + + #[test] + fn nested_alternation() { + let g = GlobPattern::new("{a,{b,c}}.txt").unwrap(); + assert!(g.is_match("a.txt")); + assert!(g.is_match("b.txt")); + assert!(g.is_match("c.txt")); + assert!(!g.is_match("d.txt")); + } + + #[test] + fn negation() { + let g = GlobPattern::new("!index.ts").unwrap(); + assert!(g.is_match("main.ts")); + assert!(!g.is_match("index.ts")); + } + + #[test] + fn classify_target_by_pattern_shape() { + use super::MatchTarget; + assert_eq!( + GlobPattern::new("*.ts").unwrap().target(), + MatchTarget::Relative + ); + assert_eq!( + GlobPattern::new("foo/bar.ts").unwrap().target(), + MatchTarget::Relative + ); + assert_eq!( + GlobPattern::new("./*.ts").unwrap().target(), + MatchTarget::DotRelative + ); + assert_eq!( + GlobPattern::new("/abs/*.ts").unwrap().target(), + MatchTarget::Absolute + ); + // Negation classifies by the inner pattern's shape. + assert_eq!( + GlobPattern::new("!*.ts").unwrap().target(), + MatchTarget::Relative + ); + assert_eq!( + GlobPattern::new("!./*.ts").unwrap().target(), + MatchTarget::DotRelative + ); + assert_eq!( + GlobPattern::new("!/abs/*.ts").unwrap().target(), + MatchTarget::Absolute + ); + } + + #[test] + fn match_entry_picks_relative_form_for_plain_pattern() { + // Pattern `.*` (literal dot, then `*`) under the OR-against-three-forms + // strategy would falsely match every file via the `./` form. + // With canonical-by-shape, plain patterns match against rel only. + let g = GlobPattern::new(".*").unwrap(); + assert!(!g.is_match_entry("regular.txt", "/scan/regular.txt")); + assert!(g.is_match_entry(".hidden", "/scan/.hidden")); + } + + #[test] + fn match_entry_dot_relative_uses_dot_form() { + let g = GlobPattern::new("./*.txt").unwrap(); + // Pattern wants to match `./`, so against rel `foo.txt` it must + // hit the `./foo.txt` form internally. + assert!(g.is_match_entry("foo.txt", "/scan/foo.txt")); + assert!(!g.is_match_entry("foo.rs", "/scan/foo.rs")); + } + + #[test] + fn match_entry_absolute_uses_abs_form() { + let g = GlobPattern::new("/scan/*.txt").unwrap(); + assert!(g.is_match_entry("foo.txt", "/scan/foo.txt")); + assert!(!g.is_match_entry("foo.txt", "/other/foo.txt")); + } +} diff --git a/baml_language/crates/sys_native/Cargo.toml b/baml_language/crates/sys_native/Cargo.toml index 71e07fbf8b..fe7a3ff966 100644 --- a/baml_language/crates/sys_native/Cargo.toml +++ b/baml_language/crates/sys_native/Cargo.toml @@ -16,6 +16,7 @@ bundle-http = [ "dep:reqwest" ] baml_type = { workspace = true } bex_heap = { workspace = true } bex_resource_types = { workspace = true } +sys_glob = { workspace = true } sys_ops = { workspace = true } sys_types = { workspace = true } futures = { workspace = true } @@ -31,6 +32,7 @@ tokio = { workspace = true, features = [ "io-std", "time", ] } +walkdir = { workspace = true } [lints] workspace = true diff --git a/baml_language/crates/sys_native/src/io_impls.rs b/baml_language/crates/sys_native/src/io_impls.rs index 4d3500b2f5..e1cf8cf866 100644 --- a/baml_language/crates/sys_native/src/io_impls.rs +++ b/baml_language/crates/sys_native/src/io_impls.rs @@ -448,6 +448,56 @@ impl io::IoNamespaceFs for NativeSysOps { ) -> SysOpOutput { SysOpOutput::async_op(async move { write_path(&path, &content).await }) } + + fn read_dir( + &self, + _heap: &Arc, + _call_id: CallId, + path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput> { + SysOpOutput::async_op(async move { + let mut rd = tokio::fs::read_dir(&path).await.map_err(|e| { + OpErrorKind::Other(format!("Failed to read directory '{path}': {e}")) + })?; + let mut entries = Vec::new(); + while let Some(entry) = rd.next_entry().await.map_err(|e| { + OpErrorKind::Other(format!("Failed to read directory entry in '{path}': {e}")) + })? { + let ft = entry.file_type().await.map_err(|e| { + OpErrorKind::Other(format!( + "Failed to get file type for '{}': {e}", + entry.file_name().to_string_lossy() + )) + })?; + entries.push(owned::fs::DirEntry { + name: entry.file_name().to_string_lossy().into_owned(), + is_dir: ft.is_dir(), + is_file: ft.is_file(), + is_symlink: ft.is_symlink(), + }); + } + Ok(entries) + }) + } + + fn mkdir( + &self, + _heap: &Arc, + _call_id: CallId, + path: String, + options: owned::fs::MkdirOptions, + _ctx: &SysOpContext, + ) -> SysOpOutput<()> { + SysOpOutput::async_op(async move { + if options.recursive { + tokio::fs::create_dir_all(&path).await + } else { + tokio::fs::create_dir(&path).await + } + .map_err(|e| OpErrorKind::Other(format!("Failed to create directory '{path}': {e}"))) + }) + } } // Auto-creates missing parent dirs, matching Bun's `Bun.write` behavior. @@ -468,6 +518,187 @@ async fn write_path(path: &str, data: &[u8]) -> Result { .map_err(|_| OpErrorKind::Other(format!("Write size {} exceeds i64::MAX", data.len()))) } +// ============================================================================ +// Glob +// ============================================================================ + +use sys_glob::GlobPattern; + +type GlobHandle = GlobPattern; + +fn downcast_glob_handle(glob: &owned::glob::Glob) -> Result, OpErrorKind> { + glob._handle + .clone() + .downcast::() + .map_err(|_| OpErrorKind::Other("Invalid glob handle type".into())) +} + +impl io::IoNamespaceGlob for NativeSysOps { + fn new( + &self, + _heap: &Arc, + _call_id: CallId, + pattern: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + match GlobPattern::new(&pattern) { + Ok(gp) => { + let handle: Arc = Arc::new(gp); + SysOpOutput::ok(owned::glob::Glob { _handle: handle }) + } + Err(e) => SysOpOutput::err(OpErrorKind::Other(e)), + } + } +} + +impl io::IoClassGlobGlob for NativeSysOps { + fn scan( + &self, + _heap: &Arc, + _call_id: CallId, + glob: owned::glob::Glob, + root: BexExternalValue, + _ctx: &SysOpContext, + ) -> SysOpOutput> { + SysOpOutput::async_op(async move { + let handle = downcast_glob_handle(&glob)?; + + let (cwd, dot, absolute, follow_symlinks, throw_on_broken, only_files) = match &root { + BexExternalValue::String(s) => (s.clone(), false, false, false, false, true), + BexExternalValue::Instance { fields, .. } => { + let get_string = |key: &str, default: &str| { + fields + .get(key) + .and_then(BexExternalValue::as_string) + .unwrap_or_else(|| default.to_string()) + }; + let get_bool = |key: &str, default: bool| { + fields + .get(key) + .and_then(BexExternalValue::as_bool) + .unwrap_or(default) + }; + let cwd = get_string("cwd", "."); + let dot = get_bool("dot", false); + let absolute = get_bool("absolute", false); + let follow_symlinks = get_bool("follow_symlinks", false); + let throw_on_broken = get_bool("throw_error_on_broken_symlink", false); + let only_files = get_bool("only_files", true); + ( + cwd, + dot, + absolute, + follow_symlinks, + throw_on_broken, + only_files, + ) + } + _ => { + return Err(OpErrorKind::Other( + "scan argument must be a string or ScanOptions".into(), + )); + } + }; + + let cwd_path = std::path::Path::new(&cwd); + let abs_cwd = if cwd_path.is_absolute() { + cwd_path.to_path_buf() + } else { + std::env::current_dir() + .map_err(|e| OpErrorKind::Other(format!("Failed to get cwd: {e}")))? + .join(cwd_path) + }; + + // Prune dot directories during the walk when `dot=false` so we + // never descend into trees like `.git/`. The previous post-walk + // filter still discarded those entries but only after walkdir + // had paid the I/O to enumerate them. Depth 0 is always kept so + // the user can scan a dot-prefixed root they explicitly point + // at (e.g. `Glob.scan(".config")`). + let walker = walkdir::WalkDir::new(&abs_cwd) + .follow_links(follow_symlinks) + .into_iter() + .filter_entry(move |entry| { + dot || entry.depth() == 0 + || !entry.file_name().to_string_lossy().starts_with('.') + }); + + let mut results = Vec::new(); + for entry in walker { + let entry = match entry { + Ok(e) => e, + Err(e) => { + // Classify: broken symlink vs. other I/O error. A broken + // symlink surfaces as NotFound on a path whose lstat + // identifies it as a symlink. The `throw_on_broken` + // option is scoped to broken symlinks only — every + // other walk error (permission denied, transient I/O, + // symlink loop) is a real failure and propagates + // regardless. Silently swallowing real errors hides + // problems users want to know about. + let is_broken_symlink = e + .io_error() + .is_some_and(|io_err| io_err.kind() == std::io::ErrorKind::NotFound) + && e.path() + .and_then(|p| std::fs::symlink_metadata(p).ok()) + .is_some_and(|m| m.file_type().is_symlink()); + + if is_broken_symlink { + if throw_on_broken { + return Err(OpErrorKind::Other(format!("Broken symlink: {e}"))); + } + continue; + } + return Err(OpErrorKind::Other(format!("Walk error: {e}"))); + } + }; + + // Skip the root itself + if entry.depth() == 0 { + continue; + } + + let ft = entry.file_type(); + if only_files && !ft.is_file() { + continue; + } + + let rel = entry.path().strip_prefix(&abs_cwd).unwrap_or(entry.path()); + let rel_str = rel.to_string_lossy().replace('\\', "/"); + let abs_str = entry.path().to_string_lossy().replace('\\', "/"); + + // Dot filtering is handled by `filter_entry` above; no need + // to re-check here. + + if !handle.is_match_entry(&rel_str, &abs_str) { + continue; + } + + if absolute { + results.push(abs_str); + } else { + results.push(rel_str); + } + } + Ok(results) + }) + } + + fn matches( + &self, + _heap: &Arc, + _call_id: CallId, + glob: owned::glob::Glob, + path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + match downcast_glob_handle(&glob) { + Ok(handle) => SysOpOutput::ok(handle.is_match(&path)), + Err(e) => SysOpOutput::err(e), + } + } +} + // ============================================================================ // System // ============================================================================ diff --git a/baml_language/crates/sys_ops/src/lib.rs b/baml_language/crates/sys_ops/src/lib.rs index 459e4fa5f2..fa0e8ad8a0 100644 --- a/baml_language/crates/sys_ops/src/lib.rs +++ b/baml_language/crates/sys_ops/src/lib.rs @@ -857,6 +857,27 @@ impl io::IoNamespaceFs for DefaultIoOps { ) -> SysOpOutput { SysOpOutput::err(OpErrorKind::Unsupported) } + + fn read_dir( + &self, + _h: &Arc, + _c: CallId, + _path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput> { + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn mkdir( + &self, + _h: &Arc, + _c: CallId, + _path: String, + _options: io::owned::fs::MkdirOptions, + _ctx: &SysOpContext, + ) -> SysOpOutput<()> { + SysOpOutput::err(OpErrorKind::Unsupported) + } } impl io::IoClassHttpResponse for DefaultIoOps { @@ -1009,6 +1030,42 @@ impl io::IoNamespaceSys for DefaultIoOps { } } +impl io::IoClassGlobGlob for DefaultIoOps { + fn scan( + &self, + _h: &Arc, + _c: CallId, + _glob: io::owned::glob::Glob, + _root: BexExternalValue, + _ctx: &SysOpContext, + ) -> SysOpOutput> { + SysOpOutput::err(OpErrorKind::Unsupported) + } + + fn matches( + &self, + _h: &Arc, + _c: CallId, + _glob: io::owned::glob::Glob, + _path: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + SysOpOutput::err(OpErrorKind::Unsupported) + } +} + +impl io::IoNamespaceGlob for DefaultIoOps { + fn new( + &self, + _h: &Arc, + _c: CallId, + _pattern: String, + _ctx: &SysOpContext, + ) -> SysOpOutput { + SysOpOutput::err(OpErrorKind::Unsupported) + } +} + impl io::IoPackageBaml for DefaultIoOps {} /// Builder for composing an [`io::SysOps`] table by overriding namespaces. @@ -1173,11 +1230,23 @@ impl IoSysOpsBuilder { }) }; self.inner.baml_fs_file_write_bytes = { - let t = instance; + let t = instance.clone(); Arc::new(move |heap, permit, args, ctx, call_id| { t.__glue_baml_fs_file_write_bytes(heap, permit, args, ctx, call_id) }) }; + self.inner.baml_fs_read_dir = { + let t = instance.clone(); + Arc::new(move |heap, permit, args, ctx, call_id| { + t.__glue_baml_fs_read_dir(heap, permit, args, ctx, call_id) + }) + }; + self.inner.baml_fs_mkdir = { + let t = instance; + Arc::new(move |heap, permit, args, ctx, call_id| { + t.__glue_baml_fs_mkdir(heap, permit, args, ctx, call_id) + }) + }; self } @@ -1187,6 +1256,39 @@ impl IoSysOpsBuilder { self.with_fs_instance(Arc::new(T::default())) } + /// Override the `glob` namespace (including `glob.Glob` methods) with a pre-built instance. + #[must_use] + pub fn with_glob_instance( + mut self, + instance: Arc, + ) -> Self { + self.inner.baml_glob_new = { + let t = instance.clone(); + Arc::new(move |heap, permit, args, ctx, call_id| { + t.__glue_baml_glob_new(heap, permit, args, ctx, call_id) + }) + }; + self.inner.baml_glob_glob_scan = { + let t = instance.clone(); + Arc::new(move |heap, permit, args, ctx, call_id| { + t.__glue_baml_glob_glob_scan(heap, permit, args, ctx, call_id) + }) + }; + self.inner.baml_glob_glob_matches = { + let t = instance; + Arc::new(move |heap, permit, args, ctx, call_id| { + t.__glue_baml_glob_glob_matches(heap, permit, args, ctx, call_id) + }) + }; + self + } + + /// Override the `glob` namespace with a default-constructible type. + #[must_use] + pub fn with_glob(self) -> Self { + self.with_glob_instance(Arc::new(T::default())) + } + /// Override the `http` namespace (including `http.Response` methods) with a pre-built instance. #[must_use] pub fn with_http_instance( diff --git a/baml_language/crates/sys_types/src/lib.rs b/baml_language/crates/sys_types/src/lib.rs index 533a37aea0..8d0ac78d22 100644 --- a/baml_language/crates/sys_types/src/lib.rs +++ b/baml_language/crates/sys_types/src/lib.rs @@ -334,6 +334,26 @@ impl SysOpOutput { } } +impl SysOpOutput { + /// Convert to [`SysOpResult`] using a custom value mapping function. + /// + /// Used by generated glue code for return types that don't implement + /// [`AsBexExternalValue`] directly (e.g. `Vec`). + pub fn into_result_mapped( + self, + op: SysOp, + f: impl Fn(T) -> BexExternalValue + Send + 'static, + ) -> SysOpResult { + match self { + Self::Ready(Ok(v)) => SysOpResult::Ready(Ok(f(v))), + Self::Ready(Err(kind)) => SysOpResult::Ready(Err(OpError::new(op, kind))), + Self::Async(fut) => SysOpResult::Async(Box::pin(async move { + fut.await.map(f).map_err(|kind| OpError::new(op, kind)) + })), + } + } +} + // ============================================================================ // System Operations Table // ============================================================================