Repository navigation
feat(baml-toml): configure code generators in baml.toml - #3816
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughGenerator declarations are removed from the compiler/HIR item model, AST, and all downstream symbol surfaces. Legacy ChangesGenerator Configuration Migration to baml.toml
Sequence Diagram(s)sequenceDiagram
participant GenerateArgs
participant discover_generators
participant manifest_parse
participant diagnostics
participant CodeGenerator
GenerateArgs->>discover_generators: project root path
discover_generators->>manifest_parse: read and parse baml.toml
manifest_parse-->>discover_generators: BamlToml with generator sections
discover_generators->>discover_generators: validate output_type, naming_convention
discover_generators->>discover_generators: resolve output_dir relative to root
discover_generators-->>GenerateArgs: resolved generators + diagnostics
alt has diagnostics
GenerateArgs->>diagnostics: inject baml.toml under manifest_file_id
diagnostics-->>GenerateArgs: rendered ariadne spans with toml locations
end
GenerateArgs->>CodeGenerator: run generation for each valid target
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 812c8d3532
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -1,15647 +0,0 @@ | |||
| /** | |||
There was a problem hiding this comment.
Restore the generated Node proto runtime
Deleting this generated runtime leaves the checked-in dist package broken: dist/proto.js and dist/host_value_registry.js both import ./proto/baml_cffi.js, and package.json publishes only dist, so consumers of the Node bridge hit a module-not-found error as soon as those paths load. The updated dist/proto/baml_cffi.d.ts still exists, but the matching JS implementation needs to be kept or regenerated into dist/proto/.
Useful? React with 👍 / 👎.
| let BexExternalValue::Instance { type_args, .. } = value else { | ||
| return Ok(()); | ||
| }; |
There was a problem hiding this comment.
Reject non-instance values after generic substitution
For a generic host call whose _types binding substitutes a parameter to a concrete primitive/container type, this early return accepts every non-Instance value without checking it against expected. For example, identity[int]("oops") reaches the VM with T = int but a string argument and can return a string through a generated int signature; the new structural validation should also reject positive mismatches for primitives/lists/maps/unions instead of only checking class instances.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 7
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
baml_language/crates/bex_engine/src/conversion.rs (1)
423-427:⚠️ Potential issue | 🟠 Major | ⚡ Quick winUse substituted field types when decoding generic instances.
Line 426 passes
class_field.field_typedirectly, so nested conversion ignores the just-decoded instancetype_args. For generic classes, field decoding should use the field template substituted with thosetype_args.Suggested fix
for class_field in class_fields { let ext = fields.get(&class_field.name).ok_or_else(|| { EngineError::TypeMismatch { message: format!( "Missing field `{}` in external Instance for class `{class_name}`", class_field.name ), } })?; + let field_ty = class_field.field_template.substitute(&type_args); values.push(self.convert_external_to_vm_value_with_ty( holder, ext.clone(), - Some(&class_field.field_type), + Some(&field_ty), )?); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@baml_language/crates/bex_engine/src/conversion.rs` around lines 423 - 427, When decoding fields of a generic class instance in the convert_external_to_vm_value_with_ty function call, the code currently passes class_field.field_type directly without accounting for the type_args that were just decoded. Instead of passing the raw class_field.field_type, substitute the field type with the instance's type_args to properly handle generic field types, so that nested conversion respects the concrete types of the generic instance rather than the generic template.baml_language/crates/bridge_cffi/src/ffi/host_value.rs (1)
126-152:⚠️ Potential issue | 🟠 Major | ⚡ Quick winValidate
is_errorbefore constructing the raw byte slice.
from_raw_partsis reached before theis_errorcontract check. On malformed calls with an invalidis_error, this still executes unsafe pointer handling unnecessarily. Move theis_errorvalidation above slice construction.Proposed fix
- // SAFETY: caller promises ptr is valid for `length` bytes; the guard above - // ruled out a null pointer whenever `length > 0`. - let bytes: &[u8] = if length == 0 { - &[] - } else { - unsafe { std::slice::from_raw_parts(content as *const u8, length) } - }; - // Strict 0/1 contract: any other value is a bridge wire-protocol bug @@ if is_error != 0 && is_error != 1 { @@ return; } + + // SAFETY: caller promises ptr is valid for `length` bytes; guards above + // ruled out a null pointer whenever `length > 0`. + let bytes: &[u8] = if length == 0 { + &[] + } else { + unsafe { std::slice::from_raw_parts(content as *const u8, length) } + };🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@baml_language/crates/bridge_cffi/src/ffi/host_value.rs` around lines 126 - 152, Move the is_error validation check (the if statement that validates is_error is either 0 or 1 and calls host_dispatch::complete_with_error) to occur before the byte slice construction using from_raw_parts. Currently the unsafe pointer dereference happens first and then the validation check occurs, but the validation should happen earlier to avoid unnecessary unsafe operations when the call parameters are invalid.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@baml_language/crates/baml_compiler_parser/src/parser.rs`:
- Around line 7605-7615: The brace-matching loop in the generator block parsing
logic exits without emitting an error when reaching EOF (p.at_end()) while depth
is still greater than 0, meaning a closing brace is missing. This silently
accepts malformed generator blocks with unmatched opening braces. After the
while loop completes, add a check that if depth is still greater than 0, emit a
diagnostic error for the missing closing brace to properly report the malformed
input instead of silently consuming the rest of the file into this deprecated
node.
In `@baml_language/crates/bex_engine/src/conversion.rs`:
- Around line 1153-1156: The condition in the class_type_args_compatible
function currently returns true when wire_args or expected_args is empty, or
when their lengths differ, which incorrectly allows arity mismatches to pass
validation. Fix this by changing the logic to return false when there is an
arity mismatch (i.e., when the lengths are not equal), while only returning true
when both are empty (truly compatible) or when both are non-empty with matching
lengths. This ensures that instances with missing or extra generic type
arguments are properly rejected rather than accepted.
In `@baml_language/crates/bex_external_types/src/bex_external_value.rs`:
- Around line 164-171: The type_args field in the external value is not being
validated against the declared class type before being stored in
Object::Instance::class_type_args in the VM, allowing mismatched type arguments
to pass field validation. Add a compatibility check in the class-return
validation path in conversion.rs that validates the supplied type_args against
the declared generic class type parameters before conversion occurs, ensuring
that host values like Box<string> returned where Box<int> is declared will be
rejected. Cover this validation logic with a Rust unit test that demonstrates
the check catches type argument mismatches.
In `@baml_language/crates/bex_sap/src/to_external.rs`:
- Around line 225-227: The BexExternalValue::Instance creation at lines 225-227
and 247-250 both hardcode type_args to an empty vector, which erases generic
type information and makes instances like Foo<int> and Foo<string>
indistinguishable. Since the function receives typed context through the ty
parameter, extract and propagate the concrete class type arguments from ty for
both BexExternalValue::Instance creations instead of using an empty vec![],
ensuring generic instances preserve their identity through the conversion.
In `@baml_language/crates/bridge_ctypes/types/baml_core/cffi/v1/baml_type.proto`:
- Around line 10-14: The multi-line comment block describing type_args is
outdated and references an old wire format where type_args was an ordered Ty
list. Update this comment block to accurately describe the current wire contract
format which uses repeated TyArg entries with named fields (type_var and
type_value) instead of an ordered list. Ensure the updated documentation clearly
explains the named-binding approach to prevent client implementations from using
the incorrect format.
In `@baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rs`:
- Around line 1475-1478: Broaden the type annotation for the _types parameter in
the generated stub files from dict[str, type] to dict[str, object]. This applies
to two locations: first, in the push_str calls around lines 1475-1478 where
typed_params is being updated with the _types parameter (both in the branch with
the keyword-only marker and without), and second, in the similar push_str calls
around lines 1678-1682. This change allows the stub to accurately reflect the
runtime's acceptance of non-type forms like list[int], unions, and None sentinel
values.
In `@baml_language/sdks/python/src/baml_core/proto.py`:
- Around line 423-440: The union type check in the _fill_wire_ty function only
handles typing.Union but misses PEP 604 unions (int | str syntax) which use
types.UnionType instead. Update the condition at the union check (currently
checking only if origin is typing.Union) to also include types.UnionType so both
legacy Union style and modern | style unions are processed by the same union
handling logic. Make sure to import types module if not already imported.
---
Outside diff comments:
In `@baml_language/crates/bex_engine/src/conversion.rs`:
- Around line 423-427: When decoding fields of a generic class instance in the
convert_external_to_vm_value_with_ty function call, the code currently passes
class_field.field_type directly without accounting for the type_args that were
just decoded. Instead of passing the raw class_field.field_type, substitute the
field type with the instance's type_args to properly handle generic field types,
so that nested conversion respects the concrete types of the generic instance
rather than the generic template.
In `@baml_language/crates/bridge_cffi/src/ffi/host_value.rs`:
- Around line 126-152: Move the is_error validation check (the if statement that
validates is_error is either 0 or 1 and calls
host_dispatch::complete_with_error) to occur before the byte slice construction
using from_raw_parts. Currently the unsafe pointer dereference happens first and
then the validation check occurs, but the validation should happen earlier to
avoid unnecessary unsafe operations when the call parameters are invalid.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: ee7ca421-1e27-48d6-a68f-1585b2d62902
⛔ Files ignored due to path filters (8)
baml_language/Cargo.lockis excluded by!**/*.lockbaml_language/crates/baml_tests/snapshots/broken_syntax/generator/baml_tests__broken_syntax__generator__02_parser__valid_generator.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/generator/baml_tests__broken_syntax__generator__05_diagnostics.snapis excluded by!**/*.snapbaml_language/sdks/go/bridge_go/cffi/proto/baml_core/cffi/v1/baml_inbound.pb.gois excluded by!**/*.pb.gobaml_language/sdks/go/bridge_go/cffi/proto/baml_core/cffi/v1/baml_outbound.pb.gois excluded by!**/*.pb.gobaml_language/sdks/go/bridge_go/cffi/proto/baml_core/cffi/v1/baml_type.pb.gois excluded by!**/*.pb.gobaml_language/sdks/nodejs/bridge_nodejs/dist/proto/baml_cffi.d.tsis excluded by!**/dist/**baml_language/sdks/nodejs/bridge_nodejs/dist/proto/baml_cffi.jsis excluded by!**/dist/**
📒 Files selected for processing (104)
baml_language/crates/baml_builtins2_codegen/src/codegen_io.rsbaml_language/crates/baml_cli/Cargo.tomlbaml_language/crates/baml_cli/src/generate.rsbaml_language/crates/baml_cli/src/grep_command.rsbaml_language/crates/baml_cli/src/init_command.rsbaml_language/crates/baml_cli/src/lib.rsbaml_language/crates/baml_cli/src/manifest.rsbaml_language/crates/baml_cli/src/project_load.rsbaml_language/crates/baml_cli/src/run_command.rsbaml_language/crates/baml_cli/src/test_command.rsbaml_language/crates/baml_cli/tests/exit_code_e2e.rsbaml_language/crates/baml_compiler2_ast/src/ast.rsbaml_language/crates/baml_compiler2_ast/src/lower_cst.rsbaml_language/crates/baml_compiler2_ast/src/lowering_diagnostic.rsbaml_language/crates/baml_compiler2_hir/src/builder.rsbaml_language/crates/baml_compiler2_hir/src/contributions.rsbaml_language/crates/baml_compiler2_hir/src/ids.rsbaml_language/crates/baml_compiler2_hir/src/item_tree.rsbaml_language/crates/baml_compiler2_hir/src/loc.rsbaml_language/crates/baml_compiler2_hir/src/namespace.rsbaml_language/crates/baml_compiler2_hir/src/scope.rsbaml_language/crates/baml_compiler2_mir/src/lower.rsbaml_language/crates/baml_compiler_diagnostics/src/diagnostic.rsbaml_language/crates/baml_compiler_lexer/src/tokens.rsbaml_language/crates/baml_compiler_parser/src/parser.rsbaml_language/crates/baml_compiler_syntax/src/ast.rsbaml_language/crates/baml_exec/Cargo.tomlbaml_language/crates/baml_exec/src/dispatch.rsbaml_language/crates/baml_exec/src/output.rsbaml_language/crates/baml_lsp2_actions/src/completions.rsbaml_language/crates/baml_lsp2_actions/src/describe.rsbaml_language/crates/baml_lsp2_actions/src/tokens.rsbaml_language/crates/baml_lsp2_actions/src/type_info.rsbaml_language/crates/baml_lsp2_actions_tests/test_files/completion/top_level_keywords.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/generator.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/generator_keywords1.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/generator_keywords2.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/enum/enum_is_valid.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/generators/error.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/generators/quoted_invalid_value.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/generators/v1.bamlbaml_language/crates/baml_tests/tests/exceptions.rsbaml_language/crates/baml_tests/tests/fs.rsbaml_language/crates/baml_tests/tests/http.rsbaml_language/crates/baml_tests/tests/interfaces.rsbaml_language/crates/baml_tests/tests/parse_companions.rsbaml_language/crates/baml_tests/tests/prompt_tag_runtime.rsbaml_language/crates/bex_engine/src/conversion.rsbaml_language/crates/bex_engine/src/function_call_context.rsbaml_language/crates/bex_engine/src/lib.rsbaml_language/crates/bex_engine/tests/cancellation.rsbaml_language/crates/bex_engine/tests/collect_tests.rsbaml_language/crates/bex_engine/tests/common/mod.rsbaml_language/crates/bex_engine/tests/function_resolution.rsbaml_language/crates/bex_engine/tests/generics_runtime.rsbaml_language/crates/bex_engine/tests/host_value_callable.rsbaml_language/crates/bex_engine/tests/llm_render.rsbaml_language/crates/bex_engine/tests/media_roundtrip.rsbaml_language/crates/bex_engine/tests/orchestration.rsbaml_language/crates/bex_engine/tests/registry.rsbaml_language/crates/bex_external_types/src/bex_external_value.rsbaml_language/crates/bex_external_types/src/host_return.rsbaml_language/crates/bex_heap/src/accessor.rsbaml_language/crates/bex_heap/src/tlab.rsbaml_language/crates/bex_project/src/bex_lsp/multi_project/mod.rsbaml_language/crates/bex_project/src/bex_lsp/multi_project/request.rsbaml_language/crates/bex_sap/src/to_external.rsbaml_language/crates/bex_vm/src/vm.rsbaml_language/crates/bridge_cffi/src/baml_to_host.rsbaml_language/crates/bridge_cffi/src/ffi/host_value.rsbaml_language/crates/bridge_cffi/src/lib.rsbaml_language/crates/bridge_ctypes/src/lib.rsbaml_language/crates/bridge_ctypes/src/ty_decode.rsbaml_language/crates/bridge_ctypes/src/value_decode.rsbaml_language/crates/bridge_ctypes/src/value_encode.rsbaml_language/crates/bridge_ctypes/types/baml_core/cffi/v1/baml_inbound.protobaml_language/crates/bridge_ctypes/types/baml_core/cffi/v1/baml_outbound.protobaml_language/crates/bridge_ctypes/types/baml_core/cffi/v1/baml_type.protobaml_language/crates/bridge_wasm/src/wasm_sys.rsbaml_language/crates/bridge_wasm/tests/host_callable.rsbaml_language/crates/sys_llm/src/jinja/render.rsbaml_language/crates/sys_native/src/io_impls.rsbaml_language/crates/sys_ops/src/lib.rsbaml_language/crates/sys_types/src/lib.rsbaml_language/crates/tools_onionskin/src/compiler.rsbaml_language/sdk_tests/crates/python_pydantic2/function_calls/customizable/test_generic_calls.pybaml_language/sdk_tests/fixtures/function_calls/baml_src/ns_generic_tests/types.bamlbaml_language/sdks/go/bridge_go/build.shbaml_language/sdks/nodejs/bridge_nodejs/typescript_src/proto/baml_cffi.d.tsbaml_language/sdks/nodejs/bridge_nodejs/typescript_src/proto/baml_cffi.jsbaml_language/sdks/python/rust/bridge_python/Cargo.tomlbaml_language/sdks/python/rust/bridge_python/src/host_value.rsbaml_language/sdks/python/rust/bridge_python/src/runtime.rsbaml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rsbaml_language/sdks/python/src/baml_core/__init__.pybaml_language/sdks/python/src/baml_core/cffi/v1/baml_inbound_pb2.pybaml_language/sdks/python/src/baml_core/cffi/v1/baml_inbound_pb2.pyibaml_language/sdks/python/src/baml_core/cffi/v1/baml_outbound_pb2.pybaml_language/sdks/python/src/baml_core/cffi/v1/baml_outbound_pb2.pyibaml_language/sdks/python/src/baml_core/cffi/v1/baml_type_pb2.pybaml_language/sdks/python/src/baml_core/cffi/v1/baml_type_pb2.pyibaml_language/sdks/python/src/baml_core/proto.pybaml_language/sdks/python/tests/test_proto_generics.pytypescript2/pkg-proto/src/encode.ts
💤 Files with no reviewable changes (9)
- baml_language/crates/baml_compiler2_ast/src/ast.rs
- baml_language/crates/baml_lsp2_actions/src/completions.rs
- baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs
- baml_language/crates/baml_lsp2_actions/src/type_info.rs
- baml_language/crates/baml_compiler2_hir/src/ids.rs
- baml_language/crates/baml_compiler2_mir/src/lower.rs
- baml_language/crates/tools_onionskin/src/compiler.rs
- baml_language/crates/baml_compiler_syntax/src/ast.rs
- baml_language/crates/baml_lsp2_actions/src/describe.rs
| fn class_type_args_compatible(wire_args: &[RuntimeTy], expected_args: &[RuntimeTy]) -> bool { | ||
| if wire_args.is_empty() || expected_args.is_empty() || wire_args.len() != expected_args.len() { | ||
| return true; | ||
| } |
There was a problem hiding this comment.
Reject non-empty class type-arg arity mismatches.
Line 1154 currently returns true when arity differs, which allows malformed instances (e.g. extra/missing generic args) to pass compatibility checks instead of being rejected.
Suggested fix
fn class_type_args_compatible(wire_args: &[RuntimeTy], expected_args: &[RuntimeTy]) -> bool {
- if wire_args.is_empty() || expected_args.is_empty() || wire_args.len() != expected_args.len() {
+ if wire_args.is_empty() || expected_args.is_empty() {
return true;
}
+ if wire_args.len() != expected_args.len() {
+ return false;
+ }
wire_args
.iter()
.zip(expected_args)
.all(|(wire, expected)| runtime_ty_compatible(wire, expected))
}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@baml_language/crates/bex_engine/src/conversion.rs` around lines 1153 - 1156,
The condition in the class_type_args_compatible function currently returns true
when wire_args or expected_args is empty, or when their lengths differ, which
incorrectly allows arity mismatches to pass validation. Fix this by changing the
logic to return false when there is an arity mismatch (i.e., when the lengths
are not equal), while only returning true when both are empty (truly compatible)
or when both are non-empty with matching lengths. This ensures that instances
with missing or extra generic type arguments are properly rejected rather than
accepted.
| /// Concrete class type arguments for a generic class instance, in De | ||
| /// Bruijn (declaration) order; empty for non-generic classes. Carries a | ||
| /// `GenericBox<int>` instance's `[int]` across the FFI boundary (the | ||
| /// value-level type channel — distinct from a call's | ||
| /// `CallFunctionArgs.type_args`). Populated inbound from | ||
| /// `InboundClassValue.class_ty`; landed into the VM | ||
| /// `Object::Instance::class_type_args` in Phase 3. | ||
| type_args: Vec<RuntimeTy>, |
There was a problem hiding this comment.
Validate type_args against the declared class type before landing them in the VM.
The new field is later stored into Object::Instance::class_type_args, but the supplied host-return schema path in baml_language/crates/bex_engine/src/conversion.rs matches Instance { class_name, fields, .. } and validates fields using the expected class args while ignoring the wire type_args. A host value like Box<string> returned where Box<int> is declared can pass field validation and still materialize with class_type_args = [string].
Please add a compatibility check in the class-return validation path before conversion, and cover it with a Rust unit test where possible.
As per coding guidelines, prefer writing Rust unit tests over integration tests where possible.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@baml_language/crates/bex_external_types/src/bex_external_value.rs` around
lines 164 - 171, The type_args field in the external value is not being
validated against the declared class type before being stored in
Object::Instance::class_type_args in the VM, allowing mismatched type arguments
to pass field validation. Add a compatibility check in the class-return
validation path in conversion.rs that validates the supplied type_args against
the declared generic class type parameters before conversion occurs, ensuring
that host values like Box<string> returned where Box<int> is declared will be
rejected. Cover this validation logic with a Rust unit test that demonstrates
the check catches type argument mismatches.
Source: Coding guidelines
| BexExternalValue::Instance { | ||
| class_name: c.name.to_string(), | ||
| type_args: vec![], |
There was a problem hiding this comment.
Preserve concrete class type_args instead of zeroing them.
Line 227 and Line 249 hardcode type_args: vec![], which erases generic instance identity on this conversion path (Foo<int> and Foo<string> become indistinguishable). Since this function already receives typed context (ty), please derive and propagate class args here as well.
Also applies to: 247-250
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@baml_language/crates/bex_sap/src/to_external.rs` around lines 225 - 227, The
BexExternalValue::Instance creation at lines 225-227 and 247-250 both hardcode
type_args to an empty vector, which erases generic type information and makes
instances like Foo<int> and Foo<string> indistinguishable. Since the function
receives typed context through the ty parameter, extract and propagate the
concrete class type arguments from ty for both BexExternalValue::Instance
creations instead of using an empty vec![], ensuring generic instances preserve
their identity through the conversion.
| // Primary use: binding a generic function's / generic method's TypeVars at a | ||
| // host call. The host sends an ordered `Ty` list (De Bruijn order — enclosing | ||
| // class params first, then the callee's own params) in | ||
| // `CallFunctionArgs.type_args`; the engine decodes each into a | ||
| // `baml_type::RuntimeTy` and seeds the entry frame's `type_args` slot. |
There was a problem hiding this comment.
Stale wire-contract comment for type_args shape.
This comment still says CallFunctionArgs.type_args is an ordered Ty list, but the transport now uses repeated TyArg { type_var, type_value }. Please update this header text to match the named-binding wire format to avoid incorrect client implementations.
Suggested doc fix
-// Primary use: binding a generic function's / generic method's TypeVars at a
-// host call. The host sends an ordered `Ty` list (De Bruijn order — enclosing
-// class params first, then the callee's own params) in
-// `CallFunctionArgs.type_args`; the engine decodes each into a
-// `baml_type::RuntimeTy` and seeds the entry frame's `type_args` slot.
+// Primary use: binding a generic function's / generic method's TypeVars at a
+// host call. The host sends named bindings in `CallFunctionArgs.type_args`
+// (`TyArg { type_var, type_value }`), with insertion order matching De Bruijn
+// order (enclosing class params first, then the callee's own params). The
+// engine decodes each into `baml_type::RuntimeTy` and seeds the entry frame's
+// `type_args` slot.📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Primary use: binding a generic function's / generic method's TypeVars at a | |
| // host call. The host sends an ordered `Ty` list (De Bruijn order — enclosing | |
| // class params first, then the callee's own params) in | |
| // `CallFunctionArgs.type_args`; the engine decodes each into a | |
| // `baml_type::RuntimeTy` and seeds the entry frame's `type_args` slot. | |
| // Primary use: binding a generic function's / generic method's TypeVars at a | |
| // host call. The host sends named bindings in `CallFunctionArgs.type_args` | |
| // (`TyArg { type_var, type_value }`), with insertion order matching De Bruijn | |
| // order (enclosing class params first, then the callee's own params). The | |
| // engine decodes each into `baml_type::RuntimeTy` and seeds the entry frame's | |
| // `type_args` slot. |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@baml_language/crates/bridge_ctypes/types/baml_core/cffi/v1/baml_type.proto`
around lines 10 - 14, The multi-line comment block describing type_args is
outdated and references an old wire format where type_args was an ordered Ty
list. Update this comment block to accurately describe the current wire contract
format which uses repeated TyArg entries with named fields (type_var and
type_value) instead of an ordered list. Ensure the updated documentation clearly
explains the named-binding approach to prevent client implementations from using
the incorrect format.
| typed_params.push_str(", *, _types: dict[str, type]"); | ||
| } else { | ||
| // optionals already introduced the `*` keyword-only marker. | ||
| typed_params.push_str(", _types: dict[str, type]"); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
rg -n "_types: dict\\[str, type\\]" baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rs
rg -n "def _fill_wire_ty|typing.get_origin|py_type is None|origin in \\(list, typing.List\\)|origin in \\(dict, typing.Dict\\)|origin is typing.Union" baml_language/sdks/python/src/baml_core/proto.pyRepository: BoundaryML/baml
Length of output: 683
🏁 Script executed:
cat -n baml_language/sdks/python/src/baml_core/proto.py | sed -n '403,450p'Repository: BoundaryML/baml
Length of output: 2483
🏁 Script executed:
rg -A 20 "def _fill_wire_ty" baml_language/sdks/python/src/baml_core/proto.pyRepository: BoundaryML/baml
Length of output: 863
🏁 Script executed:
rg -B 5 -A 15 "_types" baml_language/sdks/python/src/baml_core/proto.py | head -80Repository: BoundaryML/baml
Length of output: 3020
🏁 Script executed:
fd -name "*.py" baml_language/sdks/python | xargs rg "_types:" | grep -E "\.(py|pyi):" | head -20Repository: BoundaryML/baml
Length of output: 290
🏁 Script executed:
rg -A 5 "def python_type_to_wire_ty" baml_language/sdks/python/src/baml_core/proto.pyRepository: BoundaryML/baml
Length of output: 265
🏁 Script executed:
fd -name "*.pyi" baml_language/sdks/python | xargs rg "_types" 2>/dev/null | head -30Repository: BoundaryML/baml
Length of output: 3101
🏁 Script executed:
rg -B 3 -A 3 "_types.*=" baml_language/sdks/python | grep -E "(pyi|\.py):" | head -40Repository: BoundaryML/baml
Length of output: 3842
🏁 Script executed:
rg "\.pyi" baml_language/sdks/python | head -5Repository: BoundaryML/baml
Length of output: 760
🏁 Script executed:
find baml_language/sdks/python -name "*.pyi" -type fRepository: BoundaryML/baml
Length of output: 464
🏁 Script executed:
rg "_types.*dict" baml_language/sdks/python/src/baml_core -A 1 -B 1Repository: BoundaryML/baml
Length of output: 715
🏁 Script executed:
rg "_types: dict" baml_language/sdks/python -B 2 -A 2Repository: BoundaryML/baml
Length of output: 1891
🏁 Script executed:
cat baml_language/sdks/python/src/baml_core/baml_py.pyi | grep -A 5 -B 5 "_types"Repository: BoundaryML/baml
Length of output: 41
🏁 Script executed:
rg "python_type_to_wire_ty|_fill_wire_ty" baml_language/sdks/python/src/baml_core/__init__.py -B 3 -A 8Repository: BoundaryML/baml
Length of output: 1325
🏁 Script executed:
cat baml_language/sdks/python/src/baml_core/__init__.py | sed -n '1,50p'Repository: BoundaryML/baml
Length of output: 1236
🏁 Script executed:
rg "from typing import" baml_language/sdks/python/src/baml_core/__init__.py | head -5Repository: BoundaryML/baml
Length of output: 133
🏁 Script executed:
rg -B 5 -A 10 "def resolve_generic_call_wire" baml_language/sdks/python/src/baml_core/__init__.pyRepository: BoundaryML/baml
Length of output: 41
🏁 Script executed:
rg "def resolve_generic_call_wire" baml_language/sdks/python/src/baml_coreRepository: BoundaryML/baml
Length of output: 41
🏁 Script executed:
rg "resolve_generic_call_wire" baml_language/sdks/python/src/baml_core/__init__.py -B 5 -A 15Repository: BoundaryML/baml
Length of output: 41
🏁 Script executed:
cat -n baml_language/sdks/python/src/baml_core/__init__.py | grep -A 20 "def resolve_generic_call_wire"Repository: BoundaryML/baml
Length of output: 41
🏁 Script executed:
rg "def.*generic" baml_language/sdks/python/src/baml_core/__init__.pyRepository: BoundaryML/baml
Length of output: 88
🏁 Script executed:
rg "types_kwarg" baml_language/sdks/python/src/baml_core/__init__.py -B 3 -A 10 | head -60Repository: BoundaryML/baml
Length of output: 2655
🏁 Script executed:
cat -n baml_language/sdks/python/src/baml_core/__init__.py | sed -n '200,300p'Repository: BoundaryML/baml
Length of output: 4664
🏁 Script executed:
rg "def python_type_to_wire_ty" baml_language/sdks/python/src/baml_core/proto.py -A 2Repository: BoundaryML/baml
Length of output: 219
🏁 Script executed:
cat baml_language/sdks/python/tests/test_proto_generics.py | head -80Repository: BoundaryML/baml
Length of output: 2335
🏁 Script executed:
rg "_types=\{" baml_language/sdks/python/tests/test_proto_generics.py -B 2 -A 5Repository: BoundaryML/baml
Length of output: 462
🏁 Script executed:
rg "typing.Any|from typing import Any" baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rsRepository: BoundaryML/baml
Length of output: 205
🏁 Script executed:
rg "dict\[str," baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rs | grep -v "_types"Repository: BoundaryML/baml
Length of output: 41
🏁 Script executed:
cat -n baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rs | sed -n '1470,1490p'Repository: BoundaryML/baml
Length of output: 1313
🏁 Script executed:
rg "typing.Any" baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rs | head -10Repository: BoundaryML/baml
Length of output: 205
🏁 Script executed:
cat -n baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rs | sed -n '1, 100p' | grep -E "import|use"Repository: BoundaryML/baml
Length of output: 617
🏁 Script executed:
rg "def.*_types" baml_language/sdks/python/tests -B 2 -A 10 | head -50Repository: BoundaryML/baml
Length of output: 4439
🏁 Script executed:
rg "def python_type_to_wire_ty" baml_language/sdks/python -B 5 -A 5Repository: BoundaryML/baml
Length of output: 1029
🏁 Script executed:
python3 << 'PY'
# Check if object vs Any matters in Python typing stubs
import typing
# The function accepts these:
examples = [
int, # type
None, # NoneType
list[int], # generic alias
typing.Union[int, str], # union
typing.Optional[int], # optional
]
for ex in examples:
print(f"{ex!r}: isinstance(type)={isinstance(ex, type)}, isinstance(object)={isinstance(ex, object)}")
PYRepository: BoundaryML/baml
Length of output: 376
Broaden _types stub value typing to match runtime-accepted inputs.
The generated .pyi currently enforces _types: dict[str, type], but runtime lowering via python_type_to_wire_ty() accepts non-type forms too (e.g. list[int], unions, and None sentinel). Using object instead avoids static-checker false positives for valid calls.
Proposed fix
-typed_params.push_str(", *, _types: dict[str, type]");
+typed_params.push_str(", *, _types: dict[str, object]");
...
-typed_params.push_str(", _types: dict[str, type]");
+typed_params.push_str(", _types: dict[str, object]");
...
-typed_params.push_str("*, _types: dict[str, type]");
+typed_params.push_str("*, _types: dict[str, object]");Also applies to: lines 1678-1682
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@baml_language/sdks/python/rust/sdkgen_python_pydantic2/src/leaf.rs` around
lines 1475 - 1478, Broaden the type annotation for the _types parameter in the
generated stub files from dict[str, type] to dict[str, object]. This applies to
two locations: first, in the push_str calls around lines 1475-1478 where
typed_params is being updated with the _types parameter (both in the branch with
the keyword-only marker and without), and second, in the similar push_str calls
around lines 1678-1682. This change allows the stub to accurately reflect the
runtime's acceptance of non-type forms like list[int], unions, and None sentinel
values.
| origin = typing.get_origin(py_type) | ||
| if origin is not None: | ||
| targs = typing.get_args(py_type) | ||
| if origin in (list, typing.List): | ||
| _fill_inner(ty.list.item, targs[0] if targs else None) | ||
| return | ||
| if origin in (dict, typing.Dict): | ||
| _fill_inner(ty.map.key, targs[0] if targs else None) | ||
| _fill_inner(ty.map.value, targs[1] if len(targs) > 1 else None) | ||
| return | ||
| if origin is typing.Union: | ||
| non_none = [a for a in targs if a is not type(None)] | ||
| if len(non_none) == 1 and len(non_none) != len(targs): | ||
| _fill_inner(ty.optional.inner, non_none[0]) | ||
| return | ||
| for arg in targs: | ||
| _fill_inner(ty.union.options.add(), arg) | ||
| return |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python - <<'PY'
import typing, types
u = int | str
print("get_origin(int|str):", typing.get_origin(u))
print("typing.Union:", typing.Union)
print("is typing.Union?:", typing.get_origin(u) is typing.Union)
print("has types.UnionType?:", hasattr(types, "UnionType"))
PY
rg -n "origin is typing.Union" baml_language/sdks/python/src/baml_core/proto.pyRepository: BoundaryML/baml
Length of output: 223
🏁 Script executed:
head -50 baml_language/sdks/python/src/baml_core/proto.py | grep -n "^import\|^from"Repository: BoundaryML/baml
Length of output: 450
🏁 Script executed:
sed -n '400,450p' baml_language/sdks/python/src/baml_core/proto.pyRepository: BoundaryML/baml
Length of output: 2187
🏁 Script executed:
rg "int \| str|Union\[" baml_language/sdks/python --type py -n | head -20Repository: BoundaryML/baml
Length of output: 279
Handle PEP 604 unions (|) in _fill_wire_ty.
At line 433, checking only origin is typing.Union misses int | str / T | None forms, which return types.UnionType and will fall through to unknown, losing explicit type bindings.
Proposed fix
+import types
import typing
...
- if origin is typing.Union:
+ if origin in (typing.Union, getattr(types, "UnionType", object)):
non_none = [a for a in targs if a is not type(None)]
if len(non_none) == 1 and len(non_none) != len(targs):
_fill_inner(ty.optional.inner, non_none[0])📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| origin = typing.get_origin(py_type) | |
| if origin is not None: | |
| targs = typing.get_args(py_type) | |
| if origin in (list, typing.List): | |
| _fill_inner(ty.list.item, targs[0] if targs else None) | |
| return | |
| if origin in (dict, typing.Dict): | |
| _fill_inner(ty.map.key, targs[0] if targs else None) | |
| _fill_inner(ty.map.value, targs[1] if len(targs) > 1 else None) | |
| return | |
| if origin is typing.Union: | |
| non_none = [a for a in targs if a is not type(None)] | |
| if len(non_none) == 1 and len(non_none) != len(targs): | |
| _fill_inner(ty.optional.inner, non_none[0]) | |
| return | |
| for arg in targs: | |
| _fill_inner(ty.union.options.add(), arg) | |
| return | |
| origin = typing.get_origin(py_type) | |
| if origin is not None: | |
| targs = typing.get_args(py_type) | |
| if origin in (list, typing.List): | |
| _fill_inner(ty.list.item, targs[0] if targs else None) | |
| return | |
| if origin in (dict, typing.Dict): | |
| _fill_inner(ty.map.key, targs[0] if targs else None) | |
| _fill_inner(ty.map.value, targs[1] if len(targs) > 1 else None) | |
| return | |
| if origin in (typing.Union, getattr(types, "UnionType", object)): | |
| non_none = [a for a in targs if a is not type(None)] | |
| if len(non_none) == 1 and len(non_none) != len(targs): | |
| _fill_inner(ty.optional.inner, non_none[0]) | |
| return | |
| for arg in targs: | |
| _fill_inner(ty.union.options.add(), arg) | |
| return |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@baml_language/sdks/python/src/baml_core/proto.py` around lines 423 - 440, The
union type check in the _fill_wire_ty function only handles typing.Union but
misses PEP 604 unions (int | str syntax) which use types.UnionType instead.
Update the condition at the union check (currently checking only if origin is
typing.Union) to also include types.UnionType so both legacy Union style and
modern | style unions are processed by the same union handling logic. Make sure
to import types module if not already imported.
⏭️ Performance benchmarks were skippedPerf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to To run them on this PR, do any of the following, then push a commit (or re-run CI):
|
|
No description provided. |
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
baml_language/crates/baml_builtins2/keyword_docs/baml_keywords.yaml (1)
139-145:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winGenerator example still uses deprecated
.bamlblock syntax.This now documents
output_typecorrectly, but the surrounding example still points togenerator ... {}instead of the newbaml.toml[generator.<name>]flow from this migration, which can mislead users.Suggested doc update
generator: - summary: "Configures code generation for a target language." + summary: "Deprecated in .baml; configure code generation in baml.toml." syntax: | - generator python { - output_type "python/pydantic2" - output_dir "../generated" - } + [generator.python] + output_type = "python/pydantic2" + output_dir = "../generated"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@baml_language/crates/baml_builtins2/keyword_docs/baml_keywords.yaml` around lines 139 - 145, The generator example in the keyword documentation is showing the deprecated `.baml` block syntax with the `generator python { ... }` format. Update the example in the syntax section to reflect the new `baml.toml` configuration format using `[generator.<name>]` table syntax with the correct key-value pairs (like `output_type` and `output_dir`) to match the current migration and prevent misleading users about the correct way to configure generators.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@baml_language/crates/baml_builtins2/keyword_docs/baml_keywords.yaml`:
- Around line 139-145: The generator example in the keyword documentation is
showing the deprecated `.baml` block syntax with the `generator python { ... }`
format. Update the example in the syntax section to reflect the new `baml.toml`
configuration format using `[generator.<name>]` table syntax with the correct
key-value pairs (like `output_type` and `output_dir`) to match the current
migration and prevent misleading users about the correct way to configure
generators.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: c9317faa-719f-4c53-a885-53fbded22941
⛔ Files ignored due to path filters (4)
baml_language/Cargo.lockis excluded by!**/*.lockbaml_language/crates/baml_tests/snapshots/broken_syntax/generator/baml_tests__broken_syntax__generator__01_lexer__valid_generator.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/generator/baml_tests__broken_syntax__generator__02_parser__valid_generator.snapis excluded by!**/*.snapbaml_language/crates/baml_tests/snapshots/broken_syntax/generator/baml_tests__broken_syntax__generator__05_diagnostics.snapis excluded by!**/*.snap
📒 Files selected for processing (41)
baml_language/crates/baml_builtins2/keyword_docs/baml_keywords.yamlbaml_language/crates/baml_cli/Cargo.tomlbaml_language/crates/baml_cli/src/generate.rsbaml_language/crates/baml_cli/src/grep_command.rsbaml_language/crates/baml_cli/src/init_command.rsbaml_language/crates/baml_cli/src/lib.rsbaml_language/crates/baml_cli/src/manifest.rsbaml_language/crates/baml_cli/src/project_load.rsbaml_language/crates/baml_cli/src/run_command.rsbaml_language/crates/baml_cli/tests/exit_code_e2e.rsbaml_language/crates/baml_codegen_types/src/generator_fields.rsbaml_language/crates/baml_compiler2_ast/src/ast.rsbaml_language/crates/baml_compiler2_ast/src/lower_cst.rsbaml_language/crates/baml_compiler2_ast/src/lowering_diagnostic.rsbaml_language/crates/baml_compiler2_hir/src/builder.rsbaml_language/crates/baml_compiler2_hir/src/contributions.rsbaml_language/crates/baml_compiler2_hir/src/ids.rsbaml_language/crates/baml_compiler2_hir/src/item_tree.rsbaml_language/crates/baml_compiler2_hir/src/loc.rsbaml_language/crates/baml_compiler2_hir/src/namespace.rsbaml_language/crates/baml_compiler2_hir/src/scope.rsbaml_language/crates/baml_compiler2_mir/src/lower.rsbaml_language/crates/baml_compiler_diagnostics/src/diagnostic.rsbaml_language/crates/baml_compiler_lexer/src/tokens.rsbaml_language/crates/baml_compiler_parser/src/parser.rsbaml_language/crates/baml_compiler_syntax/src/ast.rsbaml_language/crates/baml_lsp2_actions/src/completions.rsbaml_language/crates/baml_lsp2_actions/src/describe.rsbaml_language/crates/baml_lsp2_actions/src/tokens.rsbaml_language/crates/baml_lsp2_actions/src/type_info.rsbaml_language/crates/baml_lsp2_actions_tests/test_files/completion/top_level_keywords.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/generator.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/generator_keywords1.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/generator_keywords2.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/enum/enum_is_valid.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/generators/error.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/generators/quoted_invalid_value.bamlbaml_language/crates/baml_lsp2_actions_tests/test_files/syntax/generators/v1.bamlbaml_language/crates/baml_tests/projects/broken_syntax/generator/valid_generator.bamlbaml_language/crates/bex_project/src/bex_lsp/multi_project/request.rsbaml_language/crates/tools_onionskin/src/compiler.rs
💤 Files with no reviewable changes (16)
- baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/generators/quoted_invalid_value.baml
- baml_language/crates/baml_tests/projects/broken_syntax/generator/valid_generator.baml
- baml_language/crates/baml_compiler2_ast/src/ast.rs
- baml_language/crates/baml_lsp2_actions/src/completions.rs
- baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/generator.baml
- baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/enum/enum_is_valid.baml
- baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/generators/error.baml
- baml_language/crates/bex_project/src/bex_lsp/multi_project/request.rs
- baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/generator_keywords2.baml
- baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/generators/v1.baml
- baml_language/crates/baml_lsp2_actions/src/type_info.rs
- baml_language/crates/baml_lsp2_actions/src/describe.rs
- baml_language/crates/baml_compiler2_hir/src/ids.rs
- baml_language/crates/tools_onionskin/src/compiler.rs
- baml_language/crates/baml_compiler_syntax/src/ast.rs
- baml_language/crates/baml_compiler2_mir/src/lower.rs
✅ Files skipped from review due to trivial changes (5)
- baml_language/crates/baml_compiler_lexer/src/tokens.rs
- baml_language/crates/baml_lsp2_actions_tests/test_files/completion/top_level_keywords.baml
- baml_language/crates/baml_compiler2_hir/src/scope.rs
- baml_language/crates/baml_compiler2_hir/src/namespace.rs
- baml_language/crates/baml_cli/src/init_command.rs
🚧 Files skipped from review as they are similar to previous changes (18)
- baml_language/crates/baml_cli/src/lib.rs
- baml_language/crates/baml_cli/Cargo.toml
- baml_language/crates/baml_compiler2_ast/src/lowering_diagnostic.rs
- baml_language/crates/baml_cli/src/grep_command.rs
- baml_language/crates/baml_compiler2_hir/src/contributions.rs
- baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
- baml_language/crates/baml_lsp2_actions/src/tokens.rs
- baml_language/crates/baml_compiler_parser/src/parser.rs
- baml_language/crates/baml_cli/src/project_load.rs
- baml_language/crates/baml_compiler2_hir/src/item_tree.rs
- baml_language/crates/baml_cli/tests/exit_code_e2e.rs
- baml_language/crates/baml_cli/src/generate.rs
- baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/class/generator_keywords1.baml
- baml_language/crates/baml_compiler2_hir/src/builder.rs
- baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs
- baml_language/crates/baml_cli/src/manifest.rs
- baml_language/crates/baml_compiler2_hir/src/loc.rs
- baml_language/crates/baml_cli/src/run_command.rs
Move code-generation config out of `.baml` `generator {}` blocks and into a
typed `[generator.<name>]` section of the project manifest.
- Add typed serde structs for `baml.toml` (baml_cli/src/manifest.rs):
BamlToml/Package/Script/GeneratorManifest. `[package]` and `[scripts]`
now share one deserialization; unknown keys warn instead of silently
no-op'ing.
- `baml generate` reads `[generator.<name>]` (output_type, naming_convention,
output_dir) via toml::Spanned, rendering precise diagnostics into baml.toml.
- `baml init` scaffolds a commented-out generator section.
- Deprecate `generator {}` in `.baml`: the parser still recognizes the block
but consumes its body opaquely (no interior parsing) and emits an
unclosed-brace error on EOF; lowering raises a migration warning (E0017)
pointing to baml.toml. AST/HIR/codegen generator plumbing is removed.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
What
Moves code-generation config out of
.bamlgenerator {}blocks and into a typed[generator.<name>]section of the project manifest (baml.toml). Rebased directly ontocanary— clean baml-toml-only diff.Changes
Phase 1 — typed
baml.toml(baml_cli/src/manifest.rs)BamlToml/Package/Script/GeneratorManifest.[package]and[scripts]parsing now share one deserialization (replacing two ad-hoctoml::Tablesites).#[serde(flatten)]catch-alls), so typos surface but forward-compat manifests still load.Phase 2 — generators in
baml.tomlbaml generatereads[generator.<name>](output_type,naming_convention,output_dir) instead of the HIR item tree. Values usetoml::Spanned, so missing/invalid values render precise ariadne diagnostics pointing intobaml.toml.baml initscaffolds a commented-out[generator.my_client]block.Deprecation of
.bamlgenerator {}generator NAME { … }but consumes its body opaquely (no interior parsing, so stale config never errors) and emits an unclosed-brace diagnostic on EOF. CST→AST lowering emits a migration warning (E0017) pointing tobaml.toml.Item::Generator, HIRGenerator/Definition::Generator/DefinitionKind::Generator, MIR, codegen discovery, and thegeneratorcompletion are removed. The independentbaml_fmtparser is untouched, sobaml fmtstill preserves blocks for migration.Verification
mise run fmt,mise run clippyclean.cargo nextest run— 6396 passed, 0 failed, 41 skipped.🤖 Generated with Claude Code
Summary by CodeRabbit
Changes
New Features
baml.tomlvia[generator.<name>], andbaml generatevalidates and reports issues based on the manifest.baml.toml, and unknown manifest fields produce advisory warnings.Deprecations
generatorblocks in.bamlfiles are deprecated and emit warnings (E0017) to move configuration intobaml.toml.Documentation
[generator.<name>]block in the generatedbaml.toml.