Skip to content

Remove legacy Jinja prompt support - #4367

Merged
codeshaunted merged 6 commits into
canaryfrom
codeshaunted/remove-jinja-clean
Aug 12, 2026
Merged

Remove legacy Jinja prompt support#4367
codeshaunted merged 6 commits into
canaryfrom
codeshaunted/remove-jinja-clean

Conversation

@codeshaunted

@codeshaunted codeshaunted commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • remove the Jinja runtime, type checker, parser nodes, and prompt metadata
  • migrate Jinja prompt fixtures and renderer coverage to backtick strings
  • preserve raw hash strings outside LLM prompts
  • add targeted migration errors for template_string declarations and Jinja prompt strings

Migration errors

template_string declarations:

`template_string` declarations are no longer supported. Use a function returning a backtick string instead.

Jinja LLM prompts:

Jinja `#"..."#` prompts are no longer supported. Use a backtick prompt with `${...}` interpolation instead.

Testing

  • cargo test -p baml_tests --lib
  • cargo test -p baml_compiler_parser
  • cargo test -p baml_compiler_lexer -p baml_compiler2_emit -p baml_fmt -p sys_llm
  • cargo test -p bex_engine --test llm_render
  • cargo test -p baml_lsp2_actions_tests
  • repository commit hooks, including cargo clippy

Summary by CodeRabbit

  • Breaking Changes
    • Removed legacy Jinja prompt rendering and validation.
    • Removed template_string declarations; use regular functions returning backtick strings instead.
    • Backtick prompts now use ${...} interpolation, while raw strings preserve content literally.
    • Added diagnostics for unsupported legacy prompt and template-string syntax.
  • Bug Fixes
    • Improved generic type handling in generated prompt and streaming functions.
    • Improved multiline backtick-string dedenting and formatting consistency.

@vercel

vercel Bot commented Aug 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
beps Ready Ready Preview Aug 12, 2026 3:53am
promptfiddle2 Ready Ready Preview Aug 12, 2026 3:53am

Request Review

@github-actions

Copy link
Copy Markdown

⏭️ Performance benchmarks were skipped

Perf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to canary/main.

To run them on this PR, do any of the following, then push a commit (or re-run CI):

  • Add RUN_CODSPEED=1 to the PR description, or
  • Include run-perf or /perf in the PR title or any commit message.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 468b31c1-0486-4307-8e3e-ffd02dc86c72

📥 Commits

Reviewing files that changed from the base of the PR and between 80a4c3d and d20b864.

⛔ Files ignored due to path filters (4)
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/template_string_removed/baml_tests__diagnostic_errors__template_string_removed__03_ppir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/template_string_removed/baml_tests__diagnostic_errors__template_string_removed__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/template_string_removed/baml_tests__diagnostic_errors__template_string_removed__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/template_string_removed/baml_tests__diagnostic_errors__template_string_removed__10_formatter__main.snap is excluded by !**/*.snap
📒 Files selected for processing (4)
  • baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
  • baml_language/crates/baml_compiler2_ast/src/lowering_diagnostic.rs
  • baml_language/crates/baml_compiler_parser/src/parser.rs
  • baml_language/crates/baml_tests/projects/diagnostic_errors/template_string_removed/main.baml
🚧 Files skipped from review as they are similar to previous changes (4)
  • baml_language/crates/baml_tests/projects/diagnostic_errors/template_string_removed/main.baml
  • baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
  • baml_language/crates/baml_compiler2_ast/src/lowering_diagnostic.rs
  • baml_language/crates/baml_compiler_parser/src/parser.rs

📝 Walkthrough

Walkthrough

This change removes legacy Jinja and template_string support from the compiler, runtime, diagnostics, language server, metadata, and fixtures. Raw strings are now literal. Prompts use backtick interpolation. Generic companion synthesis preserves explicit type arguments.

Changes

Legacy Jinja removal and backtick migration

Layer / File(s) Summary
Parser and diagnostic contracts
baml_compiler_parser/*, baml_compiler_syntax/*, baml_compiler2_ast/*, baml_compiler_diagnostics/*
Raw strings no longer parse Jinja constructs. Legacy syntax nodes, diagnostics, and prompt interpolation storage were removed. template_string declarations now produce a dedicated diagnostic.
Compiler and runtime metadata
baml_compiler2_emit/*, baml_type/*, bex_vm*, sys_types/*, bex_cache/*
Template macros and serialized prompt-template fields were removed from compiler output, VM programs, execution contexts, and function metadata.
Runtime rendering replacement
sys_llm/*, bex_engine/*
Jinja rendering APIs and modules were removed. Engine tests now execute compiler-generated $render_prompt functions for interpolation, roles, and enums.
Language server migration
baml_lsp2_actions/*, baml_lsp2_actions_tests/*
Jinja validation and template_string completions were removed. Fixtures and semantic-token expectations now use functions with backtick interpolation.
Formatter and project migration coverage
baml_fmt/*, baml_project/*, baml_tests/*, baml_surface/*
Formatter, compiler, incremental, parser, project, and integration fixtures were migrated to backtick strings and regular functions.

Generic companion synthesis

Layer / File(s) Summary
Generic companion synthesis
baml_compiler2_ast/*, baml_compiler2_ppir/*
Generated $spec, render, agent, and stream companion calls now receive type arguments derived from parent generic parameters.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • BoundaryML/baml#4360: Removes the same Jinja prompt-support infrastructure across compiler, runtime, language server, and fixtures.
  • BoundaryML/baml#4229: Overlaps in Jinja removal, prompt AST changes, diagnostics, runtime rendering, and tests.
  • BoundaryML/baml#3577: Introduces the backtick interpolation system used by the migrated prompts.

Poem

A rabbit nibbles Jinja away,
Backtick prompts now lead the way.
Raw strings keep each mark and space,
Generic types stay in place.
Old templates hop out of sight—
New compiler paths run bright.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: removing legacy Jinja prompt support.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codeshaunted/remove-jinja-clean

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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/bex_vm_types/src/types/function.rs`:
- Line 96: Increment bex_cache::FORMAT_VERSION to reflect the Program layout
change caused by removing prompt_template. Preserve the existing cache header
compatibility check and stale-version rejection test.
🪄 Autofix

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 Plus

Run ID: aed2777b-24b4-4243-b61a-40d483a3d96d

📥 Commits

Reviewing files that changed from the base of the PR and between 5e6edc8 and 8bdd1c0.

⛔ Files ignored due to path filters (34)
  • baml_language/Cargo.lock is excluded by !**/*.lock
  • baml_language/architecture/architecture.svg is excluded by !**/*.svg
  • baml_language/crates/baml_tests/snapshots/broken_syntax/header_in_llm_function/baml_tests__broken_syntax__header_in_llm_function__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/broken_syntax/parser_speculative/baml_tests__broken_syntax__parser_speculative__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/broken_syntax/parser_strings/baml_tests__broken_syntax__parser_strings__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/broken_syntax/pending_greaters_fix/baml_tests__broken_syntax__pending_greaters_fix__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/broken_syntax/template_string_removed/baml_tests__broken_syntax__template_string_removed__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/backtick_decl_slots/baml_tests__compiles__backtick_decl_slots__03_ppir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/backtick_decl_slots/baml_tests__compiles__backtick_decl_slots__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/backtick_decl_slots/baml_tests__compiles__backtick_decl_slots__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/backtick_decl_slots/baml_tests__compiles__backtick_decl_slots__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/backtick_decl_slots/baml_tests__compiles__backtick_decl_slots__10_formatter__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/string_methods/baml_tests__compiles__string_methods__03_ppir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/string_methods/baml_tests__compiles__string_methods__04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/string_methods/baml_tests__compiles__string_methods__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/string_methods/baml_tests__compiles__string_methods__06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/string_methods/baml_tests__compiles__string_methods__10_formatter__string_methods.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/client_option_types/baml_tests__diagnostic_errors__client_option_types__03_ppir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/client_option_types/baml_tests__diagnostic_errors__client_option_types__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/client_option_types/baml_tests__diagnostic_errors__client_option_types__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/client_option_types/baml_tests__diagnostic_errors__client_option_types__10_formatter__client_option_types.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__03_ppir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__10_formatter__config_decls.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/format_checks/baml_tests__diagnostic_errors__format_checks__10_formatter__template_string_decls.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/jinja_prompt_removed/baml_tests__diagnostic_errors__jinja_prompt_removed__03_ppir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/jinja_prompt_removed/baml_tests__diagnostic_errors__jinja_prompt_removed__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/jinja_prompt_removed/baml_tests__diagnostic_errors__jinja_prompt_removed__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/jinja_prompt_removed/baml_tests__diagnostic_errors__jinja_prompt_removed__10_formatter__main.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/optional_parameter_defaults/baml_tests__diagnostic_errors__optional_parameter_defaults__03_ppir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/optional_parameter_defaults/baml_tests__diagnostic_errors__optional_parameter_defaults__04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/optional_parameter_defaults/baml_tests__diagnostic_errors__optional_parameter_defaults__05_diagnostics.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/diagnostic_errors/optional_parameter_defaults/baml_tests__diagnostic_errors__optional_parameter_defaults__10_formatter__unsupported_contexts.snap is excluded by !**/*.snap
📒 Files selected for processing (90)
  • baml_language/Cargo.toml
  • baml_language/crates/baml_base/src/dedent.rs
  • baml_language/crates/baml_builtins2/keyword_docs/baml_keywords.yaml
  • baml_language/crates/baml_compiler2_ast/src/ast.rs
  • baml_language/crates/baml_compiler2_ast/src/lower_cst.rs
  • baml_language/crates/baml_compiler2_ast/src/lowering_diagnostic.rs
  • baml_language/crates/baml_compiler2_emit/src/lib.rs
  • baml_language/crates/baml_compiler2_hir/src/item_tree/template_strings.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/functions.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/template_strings.rs
  • baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs
  • baml_language/crates/baml_compiler_diagnostics/src/errors/type_error.rs
  • baml_language/crates/baml_compiler_diagnostics/src/to_diagnostic.rs
  • baml_language/crates/baml_compiler_lexer/src/tokens.rs
  • baml_language/crates/baml_compiler_parser/src/parser.rs
  • baml_language/crates/baml_compiler_syntax/src/ast.rs
  • baml_language/crates/baml_compiler_syntax/src/syntax_kind.rs
  • baml_language/crates/baml_fmt/src/lib.rs
  • baml_language/crates/baml_lsp2_actions/Cargo.toml
  • baml_language/crates/baml_lsp2_actions/src/actions.rs
  • baml_language/crates/baml_lsp2_actions/src/annotations.rs
  • baml_language/crates/baml_lsp2_actions/src/check.rs
  • baml_language/crates/baml_lsp2_actions/src/completions.rs
  • baml_language/crates/baml_lsp2_actions/src/type_info.rs
  • baml_language/crates/baml_lsp2_actions_tests/src/lsp_issues_authoring.rs
  • baml_language/crates/baml_lsp2_actions_tests/test_files/completion/top_level_keywords.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/template_string.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/semantic_tokens/template_string_calls.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/client/remap_role_valid.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/client/remap_role_with_default_fallback.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/dictionary/valid_dictionary.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/functions_v2/prompt_errors/prompt1.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/template_string/bad_calls.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/template_string/good_calls.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/template_string/invalid.baml
  • baml_language/crates/baml_lsp2_actions_tests/test_files/syntax/template_string/valid.baml
  • baml_language/crates/baml_project/src/client_codegen.rs
  • baml_language/crates/baml_project/src/db.rs
  • baml_language/crates/baml_surface/src/handles_tests.rs
  • baml_language/crates/baml_tests/projects/broken_syntax/header_in_llm_function/test.baml
  • baml_language/crates/baml_tests/projects/broken_syntax/parser_speculative/ambiguous_function.baml
  • baml_language/crates/baml_tests/projects/broken_syntax/parser_speculative/llm_function.baml
  • baml_language/crates/baml_tests/projects/broken_syntax/parser_speculative/mixed_functions.baml
  • baml_language/crates/baml_tests/projects/broken_syntax/parser_strings/nested_quotes.baml
  • baml_language/crates/baml_tests/projects/broken_syntax/parser_strings/raw_strings.baml
  • baml_language/crates/baml_tests/projects/broken_syntax/parser_strings/unicode_strings.baml
  • baml_language/crates/baml_tests/projects/broken_syntax/pending_greaters_fix/extra_greater.baml
  • baml_language/crates/baml_tests/projects/broken_syntax/template_string_removed/main.baml
  • baml_language/crates/baml_tests/projects/compiles/backtick_decl_slots/main.baml
  • baml_language/crates/baml_tests/projects/compiles/string_methods/string_methods.baml
  • baml_language/crates/baml_tests/projects/diagnostic_errors/client_option_types/client_option_types.baml
  • baml_language/crates/baml_tests/projects/diagnostic_errors/format_checks/config_decls.baml
  • baml_language/crates/baml_tests/projects/diagnostic_errors/format_checks/template_string_decls.baml
  • baml_language/crates/baml_tests/projects/diagnostic_errors/jinja_prompt_removed/main.baml
  • baml_language/crates/baml_tests/projects/diagnostic_errors/optional_parameter_defaults/unsupported_contexts.baml
  • baml_language/crates/baml_tests/projects/parser_stress/large_file.baml
  • baml_language/crates/baml_tests/src/compiler2_hir.rs
  • baml_language/crates/baml_tests/src/incremental/scenarios.rs
  • baml_language/crates/baml_tests/tests/backtick_fmt_value_preservation.rs
  • baml_language/crates/baml_tests/tests/convert_boundary_regressions.rs
  • baml_language/crates/baml_tests/tests/incremental_typing_repro.rs
  • baml_language/crates/baml_tests/tests/interfaces.rs
  • baml_language/crates/baml_tests/tests/prompt_tag_e2e.rs
  • baml_language/crates/baml_type/src/defs.rs
  • baml_language/crates/bex_engine/src/lib.rs
  • baml_language/crates/bex_engine/tests/llm_render.rs
  • baml_language/crates/bex_vm/src/vm.rs
  • baml_language/crates/bex_vm_types/src/link.rs
  • baml_language/crates/bex_vm_types/src/types.rs
  • baml_language/crates/bex_vm_types/src/types/function.rs
  • baml_language/crates/bex_vm_types/src/unit.rs
  • baml_language/crates/sys_jinja/Cargo.toml
  • baml_language/crates/sys_jinja/src/lib.rs
  • baml_language/crates/sys_jinja_types/Cargo.toml
  • baml_language/crates/sys_jinja_types/src/evaluate_type/expr.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/mod.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/pretty_print.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/stmt.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/test_expr.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/test_stmt.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/types.rs
  • baml_language/crates/sys_jinja_types/src/lib.rs
  • baml_language/crates/sys_llm/Cargo.toml
  • baml_language/crates/sys_llm/src/jinja/error.rs
  • baml_language/crates/sys_llm/src/jinja/mod.rs
  • baml_language/crates/sys_llm/src/jinja/output_format_object.rs
  • baml_language/crates/sys_llm/src/jinja/render.rs
  • baml_language/crates/sys_llm/src/jinja/value_conversion.rs
  • baml_language/crates/sys_llm/src/lib.rs
  • baml_language/crates/sys_types/src/lib.rs
💤 Files with no reviewable changes (35)
  • baml_language/crates/baml_lsp2_actions/Cargo.toml
  • baml_language/crates/sys_llm/Cargo.toml
  • baml_language/crates/sys_jinja_types/Cargo.toml
  • baml_language/crates/sys_jinja/Cargo.toml
  • baml_language/crates/baml_builtins2/keyword_docs/baml_keywords.yaml
  • baml_language/crates/sys_llm/src/jinja/value_conversion.rs
  • baml_language/crates/sys_jinja_types/src/lib.rs
  • baml_language/crates/baml_compiler_syntax/src/syntax_kind.rs
  • baml_language/crates/bex_vm_types/src/types.rs
  • baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/pretty_print.rs
  • baml_language/crates/bex_vm_types/src/unit.rs
  • baml_language/crates/baml_lsp2_actions/src/completions.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/stmt.rs
  • baml_language/crates/sys_llm/src/jinja/error.rs
  • baml_language/crates/sys_llm/src/jinja/mod.rs
  • baml_language/crates/baml_compiler2_ast/src/ast.rs
  • baml_language/crates/baml_compiler2_ppir/src/item_data/functions.rs
  • baml_language/crates/sys_llm/src/jinja/render.rs
  • baml_language/crates/baml_surface/src/handles_tests.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/mod.rs
  • baml_language/Cargo.toml
  • baml_language/crates/sys_jinja_types/src/evaluate_type/test_stmt.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/test_expr.rs
  • baml_language/crates/bex_vm_types/src/link.rs
  • baml_language/crates/baml_tests/tests/prompt_tag_e2e.rs
  • baml_language/crates/bex_vm/src/vm.rs
  • baml_language/crates/baml_compiler_diagnostics/src/to_diagnostic.rs
  • baml_language/crates/baml_lsp2_actions_tests/src/lsp_issues_authoring.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/types.rs
  • baml_language/crates/sys_jinja_types/src/evaluate_type/expr.rs
  • baml_language/crates/sys_types/src/lib.rs
  • baml_language/crates/baml_compiler_diagnostics/src/errors/type_error.rs
  • baml_language/crates/sys_llm/src/jinja/output_format_object.rs
  • baml_language/crates/sys_jinja/src/lib.rs

Comment thread baml_language/crates/bex_vm_types/src/types/function.rs
@github-actions

github-actions Bot commented Aug 12, 2026

Copy link
Copy Markdown

Binary size checks passed

7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
baml-cli Linux 🔒 26.1 MB 11.1 MB file 27.4 MB -1.2 MB (-4.5%) OK
packed-program Linux 🔒 16.9 MB 6.8 MB file 18.6 MB -1.7 MB (-9.1%) OK
baml-cli macOS 🔒 20.4 MB 9.7 MB file 21.3 MB -913.9 KB (-4.3%) OK
packed-program macOS 🔒 13.3 MB 6.0 MB file 14.5 MB -1.2 MB (-8.2%) OK
baml-cli Windows 🔒 21.9 MB 9.9 MB file 23.0 MB -1.1 MB (-4.7%) OK
packed-program Windows 🔒 14.1 MB 6.1 MB file 15.5 MB -1.4 MB (-9.3%) OK
bridge_wasm WASM 15.5 MB 🔒 4.2 MB gzip 4.6 MB -441.8 KB (-9.6%) OK

🔒 = the size this artifact is GATED on (ceiling + delta). Binaries gate on file size (installed binary); WASM gates on gzip (download size). The other size is shown for information only.


Generated by cargo size-gate · workflow run

@codeshaunted
codeshaunted added this pull request to the merge queue Aug 12, 2026
Merged via the queue into canary with commit 3085fcf Aug 12, 2026
83 checks passed
@codeshaunted
codeshaunted deleted the codeshaunted/remove-jinja-clean branch August 12, 2026 04:48
hellovai added a commit that referenced this pull request Aug 12, 2026
Resolves one conflict in `baml_base/src/dedent.rs`, in the module doc.

The Jinja removal (#4367) took `sys_llm::preprocess_template` with it, and
this branch had already moved backtick literals onto `dedent_backtick`, so
`baml_base::dedent::preprocess_template` was left with no callers. Delete
it: it implements exactly the blanket-trim semantics this branch is
fixing, and leaving it public next to its replacement invites someone to
reach for the wrong one.

Its tests move onto `dedent_backtick`. Two of them now record the new
behavior instead of the old, which is the point of the change:

    "    hello\n  world"  -> "  hello\nworld"   (was "hello\nworld";
                            the common prefix is the shorter indent and
                            no trim follows it)
    "\t- foo\n    - bar"  -> unchanged          (was "- foo\n    - bar";
                            tabs and spaces share no prefix, so both
                            lines keep their own indent)

The NBSP and U+2028 char-boundary regression tests carry over unchanged —
`dedent_backtick` uses the same `leading_whitespace_bytes` and
`strip_leading_indent` helpers they were written to guard.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cvpfs1fyG1RbDpTV3Ye28A
pull Bot pushed a commit to justinlietz93/baml that referenced this pull request Aug 12, 2026
…oundaryML#4365)

Fixes B-1474.

## The bug

A trailing `\n` in a backtick string literal was silently dropped:

```baml
`${id.hostname}\n`   // -> "myhost", no newline, no error
```

This broke generating newline-terminated files (`/etc/hostname`,
`/etc/locale.conf`). It was invisible in test logs, since a value that
differs only by a trailing newline prints identically.

## Why

Two things in the §12 dedent conflated *layout* with *content*.

1. **Escapes were decoded before the dedent ran.** By the time layout
was stripped, an authored `\n` had already become a real newline,
indistinguishable from a line break the author typed to lay the literal
out across lines. This also meant a literal written on a single source
line could be sent down the multi-line path, because the "is this
multi-line?" test ran on the decoded text.
2. **The dedent ended in a blanket `.trim()`**, which removed whatever
whitespace sat at either end. That newline, blank lines the author left
in, and trailing spaces all went.

## The fix

`baml_base::dedent::dedent_backtick` replaces `preprocess_template` on
the backtick path. It strips layout and only layout:

1. Normalize `\r\n` / lone `\r` to `\n`.
2. Drop the line break after the opening delimiter, and the line break
plus indent before the closing one. Those belong to the delimiters.
3. Strip the longest common leading-whitespace prefix.

No trim. It runs on the **raw** source text, before escape decoding, so
`\n` is still two opaque characters while layout is being removed. §13
block-tag whitespace moves ahead of decoding for the same reason: its
line scan would otherwise treat an authored `\n` as a line boundary.

`preprocess_template` is **deleted**. BoundaryML#4367 removed the Jinja runtime
and with it `sys_llm::preprocess_template`, its only other caller, so
once backticks moved onto `dedent_backtick` it had none left. Leaving a
public function that implements exactly the trimming semantics this PR
removes, sitting next to its replacement, is a trap. Its tests move onto
`dedent_backtick`; two of them now record the new behavior:

```
"    hello\n  world"  ->  "  hello\nworld"   was "hello\nworld"
"\t- foo\n    - bar"  ->  unchanged          was "- foo\n    - bar"
```

Both differences are the absent trim. The NBSP and U+2028 char-boundary
regression tests carry over unchanged — `dedent_backtick` uses the same
helpers they were written to guard — and now assert byte-exact
preservation rather than only that nothing panics.

## What changes

Multi-line literals laid out the ordinary way dedent to exactly what
they did before, so the formatter is unchanged and the `compiles/` and
`diagnostic_errors/` snapshots do not move. The differences:

```
`${host}\n`          -> "alpha\n"     was "alpha"
` a\n b\t `          -> " a\n b\t "   leading/trailing spaces no longer mangled
`\n  a\n  b\n\n  `   -> "a\nb\n"      a blank line before the closer now means
                                      a trailing newline
`\n  a  \n  b\n`     -> "a  \nb"      trailing spaces on a line are content
`\n  a\n    b\n`     -> "a\n  b"      relative indent preserved, as before
```

`\n` still decodes to a newline inside backticks. Making it literal
would leave `` \` `` and `\$` decoding while `\n` did not, and `#"..."#`
is already the fully-raw form.

### One behavior change in the stdlib

The three `bytecode_format` snapshots move, and it is the same bug at
the other edge. Two prompt sections in
`claude_code/ns_internal/cli.baml` open with an explicit `\n\n`:

```baml
`\n\nThe output contract is one object with an outcome field. ...`
`\n\nConversation so far:\n${lines.join("\n")}`
```

They are concatenated with nothing between them —
`${instructions}${transcript_text(...)}${tool_protocol(...)}` — so that
leading `\n\n` *is* the blank line separating sections, and `.trim()`
was eating it. Rendered prompts now have the separator the source asks
for. No other bytecode constant moved; I diffed all three snapshots in
full.

The second one is worth a look: `` `\n\nConversation so far:\n${...}` ``
is a single *source* line and should never have been dedented at all.
The old code decided that from the already-decoded text, where the
escapes had become real newlines.

## Tests

- `baml_base`: 17 `dedent_backtick` cases — 9 new (trailing escape,
blank-line-before-closer, trailing spaces, escapes-are-not-indentation,
CRLF) plus the 8 inherited from `preprocess_template`.
- `bex_engine`: 5 new end-to-end cases running the real compiled
program, including the reported `` `${host}\n` `` repro on both
single-line and dedented literals.
- `baml_tests`: a trailing-escape case added to the formatter
value-preservation suite; three `bytecode_format` snapshots updated as
above.
- Unchanged and passing after merging canary: `baml_compiler_parser`
(154), `baml_compiler_syntax` (74), `baml_compiler2_ast`, `baml_fmt`
(124), `bex_engine` backtick (84) and `llm_render` (8), and `baml_tests
--lib` at 1503. `cargo fmt` and `cargo clippy --workspace --all-targets`
clean.

BoundaryML#4367 migrated fixtures from `#"..."#` to backtick strings, straight
into this code path; none of them had edge blank lines the old trim was
absorbing.

Local pre-commit hooks could not run (`cargo-shear` requires rustc 1.95,
this toolchain is 1.93), so fmt and clippy were run directly. CI's
Pre-commit Checks job passes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01Cvpfs1fyG1RbDpTV3Ye28A

---------

Signed-off-by: hellovai <vaibhavtheory@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
meefs pushed a commit to meefs/baml that referenced this pull request Aug 15, 2026
# BEP-066: Evaluation, type construction, and reflection

## Summary

This PR implements BEP-066 across the language, compiler, VM, package
format, and host SDK boundary. BAML programs can inspect values and
types, construct runtime types, compile and mount runtime packages,
invoke reflected callables, and isolate dynamic work in sessions without
weakening the static type system.

The resulting model has four properties:

- Reflection uses one sealed, canonical type algebra for all nine public
reflection kinds. Equivalent types normalize to the same representation
and stable digest.
- Runtime generic arguments retain ordered static/runtime provenance
through HIR, MIR, bytecode, serialization, and invocation. Runtime
occurrences never become unconstrained solver variables.
- Compiled and mounted packages preserve declaration identity, interface
metadata, bounds, associated defaults, `requires` clauses,
implementations, and callable targets without fabricated source
locations.
- Dynamic type information is lexically scoped. It can guide checking
and execution inside its owning body, but values escaping that scope are
erased back to their static occurrence type.

## BEP-066 scenarios

| Scenario | Delivered behavior | Primary evidence |
| --- | --- | --- |
| 1. Runtime enums through an LLM | An enum obtained at runtime can be
supplied to an `ai`/provider call and reflected back with the correct
definition identity. |
`baml_language/crates/baml_tests/tests/reflect_call_any.rs` |
| 2. Saved forms become runtime classes | Stored rows can be converted
into runtime class definitions; returned objects retain those
definitions for extraction and field lookup. |
`baml_language/crates/baml_tests/tests/runtime_classes_and_composites.rs`
|
| 3. Runtime tool unions | Runtime class definitions can be composed
into a tool union, passed through model/tool dispatch, and recovered
without losing member identity. |
`baml_language/crates/baml_tests/tests/runtime_classes_and_composites.rs`
|
| 4a. Bounded generics over runtime classes | Runtime class witnesses
participate in generic bounds and interface dispatch using the same
conformance rules as static types. |
`baml_language/crates/baml_tests/tests/runtime_interface_witnesses.rs` |
| 4b. Package views over runtime definitions | Runtime package
reflection exposes local declarations and their relationships with
package-local identity. |
`baml_language/crates/baml_tests/tests/runtime_type_bindings.rs`,
`runtime_package_api_consistency.rs` |
| 5. Model-written schema compilation | A schema produced as data can be
compiled into a package, inspected, mounted, and used for typed
extraction. |
`baml_language/crates/baml_tests/tests/runtime_package_compile.rs` |
| 6. Current and packed package lookup | `Package.current`, package
enumeration, and `get_function` work for live and packed programs with
loc-free callable targets. |
`baml_language/crates/baml_tests/tests/runtime_package_compile.rs`,
`baml_cli/tests/pack_e2e.rs` |
| 7. Session isolation | Sessions provide isolated runtime definitions
and calls while preserving the lexical lifetime and escape-erasure
rules. | `baml_language/crates/baml_tests/tests/runtime_session.rs` |

## Consistency and audit hardening

The implementation closes the consistency gaps found while auditing the
end-to-end feature:

- Constructor lookup has one behavior across parser, checker, and
runtime: reserved words are rejected as constructor names, enum
constructors retain their precise kind, and removed reader spellings
resolve as ordinary missing names. See
`baml_language/crates/baml_tests/tests/constructor_consistency.rs`.
- Runtime rendering keys definitions by semantic identity, not display
name. Non-equivalent same-name definitions fail before rendering with
E0162; equivalent and recursive definitions remain renderable. See
`runtime_render_identity.rs`.
- Runtime and static failures share diagnostic codes and messages for
bare generics, failed bounds, and duplicate serialized keys.
Runtime-only diagnostics are structured and carry null spans instead of
fake locations. See `runtime_diagnostic_consistency.rs`.
- Package reflection includes `get_enum`, `get_interface`, kind-precise
enumeration, null for wrong-kind or missing lookups, package-local
identity, and distinct identity across packages. See
`runtime_package_api_consistency.rs`.
- Every declaration in a compiled package shares one identity across
direct lookup, enumeration, and reflected function signatures. See
`compiled_package_identity.rs`.
- Runtime definition builders validate atomically, support recursive
groups, and produce definitions identical to map-based construction. See
`builder_witness_parity.rs` and `to_baml_witness_roundtrip.rs`.

## Canary reconciliations

- [BoundaryML#4301](BoundaryML#4301) made `hir_ty`
the production inference engine, removed TIR, and established
`TYPE_SYSTEM.md` as the semantic authority. BEP-066 now lowers, checks,
and reports diagnostics through that path only.
- [BoundaryML#4352](BoundaryML#4352) reorganized the
LLM surface around `ai`, provider namespaces, `@spec`, and agents.
Reflection and model-call coverage targets that current surface rather
than the superseded stdlib layout.
- [BoundaryML#4367](BoundaryML#4367) removed Jinja
prompt interpolation. BEP-066 prompts and fixtures use backtick strings
and `${...}` interpolation, and obsolete Jinja metadata is not carried
into runtime packages.

## `hir_ty` port contract

The `hir_ty` implementation preserves the following invariants from
syntax to execution:

- Each explicit type-argument occurrence is recorded in source order as
either a static type or a runtime operand. Static occurrences are solved
normally; runtime occurrences are checked against their static
occurrence type and never enter the solver as unknown variables.
- The authoritative call metadata carries the resolved callable target,
ordered type-argument slots, realized bindings, deferred dependent
checks, and runtime definition identity through MIR and bytecode. Free
functions, methods, and interface calls use symbolic,
source-location-free targets.
- Only checks that depend on runtime definitions are deferred. Static
arity, ordinary argument types, and independent bounds remain
compile-time errors.
- Runtime type refinements live in an overlay keyed by body owner and
statement identity, respect lexical shadowing, and are erased at scope
escape.
- Mounted package metadata is sufficient for normal generic realization
and interface selection: bounds, associated defaults, `requires`,
implementation registrations, and method resolution are not
reconstructed heuristically at runtime.
- `_` remains an exact contextual hole. Let annotations and constructors
solve permitted holes; declaration signatures and explicit call/upcast
type arguments reject them with E0147. A top-level `throws T | _` is
open and exposes `T` plus inferred throws to callers; plain `throws T`
is closed.

Intentional differences from the retired TIR behavior are part of the
contract:

- Multiple generic bounds are conjunctive end to end. Runtime and static
checking require every bound; the prior single-bound asymmetry is not
preserved.
- Existential interface dispatch permits exactly one `Self` witness.
Ambiguous multi-`Self` shapes are rejected instead of being guessed.
- Associated defaults, `Self` substitution, and `requires` realization
follow the current spec and `hir_ty` rules where TIR behavior differed.
- Current diagnostic codes and normalized types are authoritative;
ignored TIR tests and legacy wording do not override them.

The legacy root `engine/` is not an authority for this work.

## Test evidence map

| Contract surface | Evidence |
| --- | --- |
| Canonical reflection algebra and stable identity | `baml_type`
normalization/type-kind unit tests; type-spec tables for reflection
kinds and canonicalization |
| Syntax, formatting, AST, and HIR preservation | lexer/parser/formatter
tests; HIR tests for ordered static/runtime type-argument occurrences |
| Wildcard and open-throws semantics |
`wildcard_hole_in_let_annotation.baml`,
`wildcard_hole_in_constructor_generic_arg.baml`,
`partial_throws_clause.baml`, `wildcard_type_inference.rs`,
`wildcard_expression_holes.rs` |
| Mounted-package and source-package parity |
`hir_ty_package_interface`, `mounted_package_calls`,
`mounted_package_parity` |
| Runtime reflection scenarios | `reflect_call_any.rs`,
`runtime_classes_and_composites.rs`, `runtime_interface_witnesses.rs`,
`runtime_type_bindings.rs`, `runtime_package_compile.rs`,
`runtime_session.rs` |
| Identity, diagnostics, and API consistency |
`compiled_package_identity.rs`, `constructor_consistency.rs`,
`runtime_diagnostic_consistency.rs`,
`runtime_package_api_consistency.rs`, `runtime_render_identity.rs` |
| Builder and round-trip parity | `builder_witness_parity.rs`,
`to_baml_witness_roundtrip.rs` |
| Host and packed-program boundary | host reflection SDK fixtures and
`baml_cli/tests/pack_e2e.rs` |

## Verification state

- Full pinned gate on the gated head (`rustup run 1.93.0 cargo insta
test --test-runner nextest -p baml_tests -p baml_cli -p
baml_lsp2_actions -p baml_lsp2_actions_tests -p baml_surface
--all-features --unreferenced=reject`): **3,265 passed, 0 failed** (23
skipped), all doctests passed or were intentionally ignored, no
unreferenced snapshots, and no pending `.snap.new`.
- Whole-stdlib type census: 121 files, **62,910 typed nodes, 0
error-channel entries, 0 panics**.
- Session soak: the 500-evaluation pin runs with flat latency (eval BoundaryML#10:
3.32s → eval BoundaryML#500: 2.39s) and 0 KiB measured RSS growth.
- The head commit additionally absorbs a final 4-commit canary drift
(BoundaryML#4431 crypto, BoundaryML#3975 connection pooling, BoundaryML#4432 quote prompts, BoundaryML#4433
string standardization) verified by focused validation (targeted
runtime/stdlib/compiler suites + no-update snapshot replays); the
authoritative final signal is this PR's CI on the head commit.

## Handoff notes (for the next agent or human working on this)

**State:** everything above is on the head commit. No temporary port
constructs remain in the tree — the Phase-A stub
(`E_BEP066_PORT_IN_PROGRESS`), fixture exclusions, and port-era test
ignores are all gone (verified by grep).

**Authoritative documents:**
- `CONTRACTS.md` (repo root, this branch) — the binding data-model
contracts (runtime type slots / `CallPlan`, loc-free
`SymbolicCallableTarget`, scoped generic overlay) plus the 35-fact
acceptance checklist with per-fact conditions.
- TIR→hir_ty migration guide: branch `antoniosarosi/hir-ty-research`
(`TIR_HIRTY_MIGRATION_GUIDE.md`) — the architecture map, worked
examples, and risk register the port followed.
- Wildcard adjudication table: branch
`antoniosarosi/wildcard-adjudication` (`WILDCARD_VERDICTS.md`) —
per-test rulings for the formerly ignored B-230/B-247 cases.
- The full port audit trail (per-slice log with every checkpoint,
decision, and accepted snapshot delta) is posted as a comment on this
PR.

**Deep review findings (resolved):** the adversarial review of the six
port commits (`462dad20b..3c22664`) is complete — [full report in this
comment](BoundaryML#4325 (comment)).
All four ratified blockers landed in `f239a032f` and passed the widened
pinned gate:

1. **Union interface dispatch (report finding 1):** virtual dispatch now
requires every union member to resolve to the same declaring-interface
view; heterogeneous unions take the guarded per-member switch, with
executable coverage.
2. **Written union member order (finding 2):** static call slots retain
a canonical checking type and a written emission type, preserving
runtime coercion order. The audited snapshots restore `audio | image`
and the other written forms.
3. **Deferred runtime bounds (finding 3):** bound registration
substitutes the call frame and defers checks that depend on active
scoped runtime bindings, including no-value-argument calls.
4. **Session top-level-let cycles (finding 5):** inference has an error
cycle seed plus RAII in-flight ownership; resolution order preserves
functions, exported values, and reserved package roots, and recursive
lets diagnose without poisoning the Session.

Canary integration and audited follow-ups are recorded in `55f6318f5`,
`957d4514b`, `4fef90eff`, and `8de2d10bb`. Report findings 4, 6, and 8
remain agreed fast-follow work; finding 9 remains explicitly
pre-existing. The report's clean-area conclusions remain valid.

**CI playbook for this branch:**
- darwin cargo-test: Blacksmith runner evictions ("No active SSH
sessions") are infra flakes; cancelled jobs display as failures — check
each job's `.conclusion`, then `gh run rerun <run-id> --failed` (up to 2
attempts).
- tsweb-macos: same infra treatment. Its one real failure mode (vitest
5s default timeout on the worker `Package.compile` test) is already
fixed with an explicit 30s timeout.
- Size Gate: if it fails with the absolute cap **below** the reported
baseline, the ceiling is stale — re-bake and bump the pinned literal in
`baml_language/crates/tools_size_gate/src/config.rs` to baseline×1.03 as
a single-file commit.
- Local CI mirror (all three matter: toolchain, features, package set):
`rustup run 1.93.0 cargo insta test --test-runner nextest -p baml_tests
-p baml_cli -p baml_lsp2_actions -p baml_lsp2_actions_tests -p
baml_surface --all-features --unreferenced=reject`

**Agreed follow-up PRs (deliberately not in this PR):**
1. Add a nextest serialization group for `sdk_test_typescript_web`
(`max-threads = 1`) — prevents concurrent ~8 GiB transient workerd
import peaks from stacking (measured; this OOM'd a dev machine).
2. Investigate the 82.4 MB `bridge_web_core_bg.wasm` (wasm-opt is
currently disabled in its package metadata); consider splitting
compiler-only code out of the runtime web bridge.
3. Build-time precompiled-stdlib artifact + an `emit_units` variant that
accepts it, so `Package.compile`'s first call skips the ~4–5 s full
90-file stdlib recompile (measured; a lazy in-process cache is not
sufficient for the first-call cost).
4. Address report findings 4, 6, and 8 in focused follow-ups; triage the
pre-existing items under finding 9 separately.

**Coordination items:**
- The two schema decisions living in hir_ty's crate
(`SymbolicCallableTarget` in `callable.rs`; the `PackageInterface` Borsh
expansion) should get a review from the hir_ty owner — they were frozen
unilaterally under time pressure and intentionally invalidate cached
package-interface bytes per compiler build.
- GC: BEP-066's runtime-constructed type declarations live in the moving
heap; the ty-heapptr line of work assumes GC-inert type heads. Alignment
needed before that lands (`visit_heads` hook is reserved for this).

**Semantic authority:** `TYPE_SYSTEM.md` + current hir_ty behavior. Do
not "fix" anything back toward TIR-era snapshots or ignored TIR-era test
expectations — several behavior deltas (conjunctive bounds, one-`Self`
existential dispatch, hole/E0147 handling) are intentional and
contract-pinned.

## Reviewer entry points

- Public language and stdlib surface: `baml_language/TYPE_SYSTEM.md`,
the BEP-066 specification, and
`baml_language/crates/baml_builtins2/baml_std/baml/ns_reflect/`.
- Shared type algebra: `baml_language/crates/baml_type/src/type_kind.rs`
and `normalize.rs`.
- Syntax and HIR preservation: AST/HIR type-argument reference
definitions and lowering in `baml_compiler2_hir` and
`baml_compiler2_hir_ty`.
- Inference and mounted metadata:
`baml_language/crates/baml_compiler2_hir_ty/src/infer.rs`,
`callable.rs`, `package_interface.rs`, `impls.rs`, and interface method
resolution.
- MIR and bytecode handoff: the runtime type-argument lowering/provider
code in `baml_compiler2_mir` and its bytecode emitter.
- Runtime identity, reflection, and builders: the
reflection/runtime-definition modules in `baml_language/crates/bex_vm`.
- Behavioral review: start with the seven scenario tests above, then the
audit-hardening tests, then the host SDK and pack coverage.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant