Skip to content

Rng interface - #4094

Merged
2kai2kai2 merged 7 commits into
canaryfrom
kai/rng
Jul 20, 2026
Merged

2kai2kai2 merged 7 commits into
canaryfrom
kai/rng

Conversation

@2kai2kai2

@2kai2kai2 2kai2kai2 commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

Adds the baml.random.Rng interface which represents a randomness source.
Includes three standard library implementors:

  • baml.random.SystemRandom fetches a secure random value from the OS/browser/etc (typically requires leaving the process but is secure; good for seeding PRNGs)
  • baml.random.Xoshiro256PlusPlus is a widely used fast PRNG (not suitable for security-dependent uses)
  • baml.random.ChaCha20 is a widely used cryptographically secure PRNG

Also makes sysop $rust_io_functions work in implements blocks including for indirect/virtual calls.

Summary by CodeRabbit

  • New Features

    • Added a standard random module with secure system randomness and seedable Xoshiro and ChaCha20 generators.
    • Added byte generation and uniformly distributed integer generation.
    • Added native and WebAssembly runtime support for secure randomness.
    • Added interface-based random generator dispatch.
  • Bug Fixes

    • Improved method dispatch for interface implementations.
    • Added diagnostics for unsupported generic system-operation methods in interface implementations.
  • Tests

    • Added coverage for deterministic output, entropy-backed randomness, interface dispatch, and boundary values.

The virtual call currently cannot handle the sysop for the system
randomness source
This will allow indirect/virtual calls to execute sysops (WIP)
- Allocation failure on large RNG buffers now raises `AllocFailure` BAML
  panic
- Negative buffer size now consistentily raises a user panic
- Doc fixes
- Bump diagnostic number to deconflict
Native `$rust_function`s currently don't support default args. For now
we have to make the `new` static method a bytecode function that just
wraps the native `_new`.
@vercel

vercel Bot commented Jul 20, 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, Comment Jul 20, 2026 11:50pm
promptfiddle Ready Ready Preview, Comment Jul 20, 2026 11:50pm
promptfiddle2 Ready Ready Preview, Comment Jul 20, 2026 11:50pm

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.

@2kai2kai2
2kai2kai2 enabled auto-merge July 20, 2026 23:29
@coderabbitai

coderabbitai Bot commented Jul 20, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds the baml.random standard library with deterministic and OS-backed generators, native/WASM providers, interface-aware builtin dispatch, VM sys-op yielding, compiler diagnostics, and end-to-end tests.

Changes

Random namespace and dispatch

Layer / File(s) Summary
Random API and builtin registration
baml_language/Cargo.toml, baml_language/crates/baml_builtins2/...
Defines Rng, SystemRandom, Xoshiro256PlusPlus, and ChaCha20, then embeds the new random namespace.
Interface-qualified builtin codegen
baml_language/crates/baml_builtins2_codegen/...
Adds qualified implements paths and receiver-aware glue, dispatch keys, handles, and sys-op argument marshalling.
Generic sys-op interface validation
baml_language/crates/baml_compiler2_tir/..., baml_language/crates/baml_compiler_diagnostics/..., baml_language/crates/baml_lsp2_actions/...
Rejects method-level generics on sys-op methods inside interface implementations and maps the error to diagnostic code E0153.
VM random implementations and sys-op yielding
baml_language/crates/bex_vm/...
Stores seeded PRNG state, implements random operations, and shares sys-op yielding logic across callable and compact dispatch.
Native, WASM, and sys-ops providers
baml_language/crates/sys_ops/..., baml_language/crates/sys_native/..., baml_language/crates/bridge_wasm/...
Wires random providers through the sys-ops builder and supplies entropy-backed native and WASM implementations.
Random runtime coverage
baml_language/crates/bex_engine/tests/random.rs
Tests deterministic output, state advancement, entropy-backed generation, i63 conversion, interface dispatch, and bound sys-op calls.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant BamlProgram
  participant IoSysOpsBuilder
  participant RuntimeProvider
  participant BexVm
  BamlProgram->>BexVm: call baml.random operation
  BexVm->>IoSysOpsBuilder: resolve random sys-op
  IoSysOpsBuilder->>RuntimeProvider: request bytes or random_int
  RuntimeProvider-->>BexVm: return random result
  BexVm-->>BamlProgram: deliver result
Loading

Possibly related PRs

Suggested reviewers: hellovai, codeshaunted, sxlijin

Poem

I’m a rabbit with bytes in my hat,
Seeds hop forward—imagine that!
ChaCha spins, xoshiro gleams,
Sys-ops carry entropy streams.
Interfaces guide each call just right—
Random carrots bloom tonight! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related to the change but too vague to describe the main PR outcome. Use a more specific title such as: "Add baml.random Rng interface and built-in RNG implementations".
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
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 kai/rng

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.

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 July 20, 2026 23:30 Inactive
@2kai2kai2
2kai2kai2 added this pull request to the merge queue Jul 20, 2026
@github-actions

Copy link
Copy Markdown

Binary size checks passed

✅ 7 passed

Artifact Platform File Gzip Gated on Baseline Delta Status
✅ baml-cli Linux 🔒 25.3 MB 10.7 MB file 25.3 MB +12.6 KB (+0.0%) OK
✅ packed-program Linux 🔒 17.0 MB 7.0 MB file 17.0 MB +4.3 KB (+0.0%) OK
✅ baml-cli macOS 🔒 19.6 MB 9.3 MB file 19.5 MB +33.2 KB (+0.2%) OK
✅ packed-program macOS 🔒 13.2 MB 6.2 MB file 13.2 MB +16.7 KB (+0.1%) OK
✅ baml-cli Windows 🔒 21.1 MB 9.5 MB file 21.1 MB +30.2 KB (+0.1%) OK
✅ packed-program Windows 🔒 14.2 MB 6.2 MB file 14.1 MB +11.5 KB (+0.1%) OK
✅ bridge_wasm WASM 16.2 MB 🔒 4.4 MB gzip 4.4 MB +470 B (+0.0%) 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

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle July 20, 2026 23:50 Inactive
Merged via the queue into canary with commit be5e7cd Jul 20, 2026
62 of 63 checks passed
@2kai2kai2
2kai2kai2 deleted the kai/rng branch July 20, 2026 23:52

@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

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_codegen/src/codegen_io.rs (1)

1334-1354: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Disambiguate clean-trait method names for implements-scoped IO builtins

emit_one_class_trait still derives the clean method name from io_method_name(m) only, so two interfaces that declare the same $rust_io_function on one class will emit duplicate fn foo(...) items in the same Rust trait. The interface ambiguity is already handled at call sites; the generated trait needs the same interface qualifier that io_class_dispatch_key and the glue names already use. [codegen_io.rs:1338-1354, 1442-1449]

🤖 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_codegen/src/codegen_io.rs` around lines
1334 - 1354, Update emit_one_class_trait’s clean-method name generation to
include the implements-interface qualifier for methods sharing the same
$rust_io_function, matching the naming scheme used by io_class_dispatch_key and
the generated glue names. Replace the io_method_name-only derivation near
method_ident while preserving receiver handling and return-type generation.
🧹 Nitpick comments (2)
baml_language/crates/bex_engine/tests/random.rs (1)

1-225: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider adding unit tests for the pure helpers alongside this e2e suite.

This file is an integration suite exercising the full VM↔SysOps wiring, which is reasonable for validating cross-crate dispatch, but the pure helpers introduced in bex_vm::package_baml::random (seed_array, byte_count, next_i63) have no dedicated unit tests and are easy to test in isolation (e.g. seed-too-short panic, negative byte-count panic, next_i63's range/determinism given a fixed seed).

As per path instructions: "**/*.rs: 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_engine/tests/random.rs` around lines 1 - 225, The
pure helpers seed_array, byte_count, and next_i63 in
bex_vm::package_baml::random lack isolated unit coverage. Add Rust unit tests
alongside their implementation for short-seed panic behavior, negative
byte-count panic behavior, and deterministic next_i63 results within the signed
range for a fixed seed, while keeping this file focused on end-to-end VM↔SysOps
dispatch.

Source: Path instructions

baml_language/crates/sys_native/src/io_impls.rs (1)

165-220: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate SystemRandom.random/random_int logic across the native and wasm backends. Both implementations repeat byte-count validation, fallible allocation, entropy fill, and HostUnavailable error mapping verbatim, differing only in which getrandom crate/function performs the fill.

  • baml_language/crates/sys_native/src/io_impls.rs#L165-L220: extract the shared byte-count-validate + fallible-alloc + fill + map-to-HostUnavailable sequence into a helper (e.g. in sys_ops) parameterized over a fill(&mut [u8]) -> Result<(), impl Display> closure, and call it here with getrandom::getrandom.
  • baml_language/crates/bridge_wasm/src/wasm_random.rs#L1-L67: call the same shared helper with getrandom_03::fill instead of duplicating the sequence.
🤖 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/sys_native/src/io_impls.rs` around lines 165 - 220,
Extract the shared random-byte validation, fallible allocation, entropy fill,
and HostUnavailable mapping into a helper in sys_ops, parameterized by a fill
closure returning a displayable error. Update
baml_language/crates/sys_native/src/io_impls.rs lines 165-220 to use it with
getrandom::getrandom, and update
baml_language/crates/bridge_wasm/src/wasm_random.rs lines 1-67 to use the same
helper with getrandom_03::fill; preserve each backend’s existing random and
random_int behavior.
🤖 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_compiler2_tir/src/interfaces/impl_rules.rs`:
- Around line 1204-1231: Move the generic sys-op validation in the impl-method
loop to after the `iface_spec` lookup succeeds, or gate it on a successful
interface-member resolution. Ensure `GenericSysOpMethodInInterfaceImpl` is
emitted only for methods that actually override an interface member, while
unknown methods still produce the existing `UnknownInterfaceMember` diagnostic.

---

Outside diff comments:
In `@baml_language/crates/baml_builtins2_codegen/src/codegen_io.rs`:
- Around line 1334-1354: Update emit_one_class_trait’s clean-method name
generation to include the implements-interface qualifier for methods sharing the
same $rust_io_function, matching the naming scheme used by io_class_dispatch_key
and the generated glue names. Replace the io_method_name-only derivation near
method_ident while preserving receiver handling and return-type generation.

---

Nitpick comments:
In `@baml_language/crates/bex_engine/tests/random.rs`:
- Around line 1-225: The pure helpers seed_array, byte_count, and next_i63 in
bex_vm::package_baml::random lack isolated unit coverage. Add Rust unit tests
alongside their implementation for short-seed panic behavior, negative
byte-count panic behavior, and deterministic next_i63 results within the signed
range for a fixed seed, while keeping this file focused on end-to-end VM↔SysOps
dispatch.

In `@baml_language/crates/sys_native/src/io_impls.rs`:
- Around line 165-220: Extract the shared random-byte validation, fallible
allocation, entropy fill, and HostUnavailable mapping into a helper in sys_ops,
parameterized by a fill closure returning a displayable error. Update
baml_language/crates/sys_native/src/io_impls.rs lines 165-220 to use it with
getrandom::getrandom, and update
baml_language/crates/bridge_wasm/src/wasm_random.rs lines 1-67 to use the same
helper with getrandom_03::fill; preserve each backend’s existing random and
random_int behavior.
🪄 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: 23c890c3-03b7-4687-abdf-8fcdfea43a0d

📥 Commits

Reviewing files that changed from the base of the PR and between 68da999 and c91a6fd.

⛔ Files ignored due to path filters (9)
  • baml_language/Cargo.lock is excluded by !**/*.lock
  • baml_language/crates/baml_cli/src/snapshots/baml_cli__describe_command_tests__render_builtin_package_listing.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____03_hir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____04_5_mir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____04_tir.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/snapshots/compiles/__baml_std__/baml_tests__compiles____baml_std____06_codegen.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/src/compiler2_tir/snapshots/baml_tests__compiler2_tir__phase5__snapshot_baml_package_items.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded.snap is excluded by !**/*.snap
  • baml_language/crates/baml_tests/tests/bytecode_format/snapshots/bytecode_format__bytecode_display_expanded_unoptimized.snap is excluded by !**/*.snap
📒 Files selected for processing (22)
  • baml_language/Cargo.toml
  • baml_language/crates/baml_builtins2/baml_std/baml/ns_random/random.baml
  • baml_language/crates/baml_builtins2/src/lib.rs
  • baml_language/crates/baml_builtins2_codegen/src/codegen.rs
  • baml_language/crates/baml_builtins2_codegen/src/codegen_io.rs
  • baml_language/crates/baml_builtins2_codegen/src/extract.rs
  • baml_language/crates/baml_compiler2_tir/src/infer_context.rs
  • baml_language/crates/baml_compiler2_tir/src/interfaces/impl_rules.rs
  • baml_language/crates/baml_compiler2_tir/src/lower_type_expr.rs
  • baml_language/crates/baml_compiler_diagnostics/src/diagnostic.rs
  • baml_language/crates/baml_lsp2_actions/src/check.rs
  • baml_language/crates/bex_engine/tests/random.rs
  • baml_language/crates/bex_vm/Cargo.toml
  • baml_language/crates/bex_vm/src/package_baml/mod.rs
  • baml_language/crates/bex_vm/src/package_baml/random.rs
  • baml_language/crates/bex_vm/src/vm.rs
  • baml_language/crates/bridge_wasm/Cargo.toml
  • baml_language/crates/bridge_wasm/src/lib.rs
  • baml_language/crates/bridge_wasm/src/wasm_random.rs
  • baml_language/crates/sys_native/Cargo.toml
  • baml_language/crates/sys_native/src/io_impls.rs
  • baml_language/crates/sys_ops/src/lib.rs

Comment on lines 1204 to +1231
for &method_loc in &data.methods {
let method_name = function_data(db, method_loc).name.clone();

// A `$rust_io_function` (sys-op) override with method-level generics can't
// be dispatched through interface (virtual) dispatch — the only way an
// impl-block method is reached. Virtual dispatch does not reconstruct the
// synthetic type-argument slots a generic sys-op's glue reads off the
// stack, so such a call would fail at runtime; reject it at declaration.
// (A generic sys-op declared directly on a class lowers to a direct
// `SysOp` instruction, which supplies those slots, so it is fine.)
if !function_data(db, method_loc).generic_params.is_empty()
&& matches!(
baml_compiler2_ppir::function_body(db, method_loc).as_ref(),
baml_compiler2_hir::body::FunctionBody::Builtin(
baml_compiler2_ast::BuiltinKind::Io
)
)
{
diags.push((
crate::infer_context::TirTypeError::GenericSysOpMethodInInterfaceImpl {
interface: iface_qtn.clone(),
method: method_name.clone(),
},
ImplDiagnosticLocation::Method(method_name.clone()),
));
continue;
}

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

New generic-sysop check fires before confirming the method is actually an interface member.

The check at lines 1207-1230 runs and continues before the iface_spec lookup at 1233-1247. For a method name that isn't a real member of the interface, this can emit a misleading GenericSysOpMethodInInterfaceImpl (naming the interface as if it declares this method) alongside the correct UnknownInterfaceMember diagnostic from impl_data(). Consider moving this check after (or gating it on) successful iface_spec resolution so it only fires for methods that genuinely override an interface member.

🔧 Sketch of a fix
-        if !function_data(db, method_loc).generic_params.is_empty()
-            && matches!(
-                baml_compiler2_ppir::function_body(db, method_loc).as_ref(),
-                baml_compiler2_hir::body::FunctionBody::Builtin(
-                    baml_compiler2_ast::BuiltinKind::Io
-                )
-            )
-        {
-            diags.push((...));
-            continue;
-        }
-
         // The interface method this override targets: a required sig or a default's function.
         let iface_spec = if let Some(sig) = iface_data.required_methods.iter().find(...) {
             ...
         } else if let Some(&default_loc) = ... {
             ...
         } else {
             continue; // unknown member → E0115 (impl_data)
         };
+
+        if !function_data(db, method_loc).generic_params.is_empty()
+            && matches!(..., FunctionBody::Builtin(BuiltinKind::Io))
+        {
+            diags.push((...));
+            continue;
+        }
🤖 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_compiler2_tir/src/interfaces/impl_rules.rs` around
lines 1204 - 1231, Move the generic sys-op validation in the impl-method loop to
after the `iface_spec` lookup succeeds, or gate it on a successful
interface-member resolution. Ensure `GenericSysOpMethodInInterfaceImpl` is
emitted only for methods that actually override an interface member, while
unknown methods still produce the existing `UnknownInterfaceMember` diagnostic.

This branch was previously deployed

3 inactive deployments
Preview – promptfiddle — c91a6fdb Deployed Jul 20, 2026 by vercel[bot]
Preview – promptfiddle2 — c91a6fdb Deployed Jul 20, 2026 by vercel[bot]
Preview – beps — c91a6fdb Deployed Jul 20, 2026 by vercel[bot]
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