Latest Results
feat(rust-sdk): Add on_tick streaming callback with FunctionLog support (#3333)
## Summary
- Adds `on_tick` callback support to the Rust SDK streaming API,
matching Go/Python behavior
- The callback receives `&FunctionLog` on each SSE chunk, giving access
to thinking tokens, SSE responses, usage, and timing data
- Calling `.with_on_tick(|log| { ... })` automatically creates an
internal collector (just like Go's `WithOnTick`) — no manual collector
setup needed
## Design
The callback and its auto-created collector are bundled into `OnTickData
{ callback, collector }`, which flows through the system as a single
unit:
1. **Generated code** (`with_on_tick` in `FunctionOptions`) creates a
collector, adds it to the collectors list, and wraps both into
`OnTickData`
2. **SDK** (`FunctionArgs`) carries the `OnTickData` to the runtime
3. **FFI callbacks** (`callbacks.rs`) on each SSE chunk, queries the
collector for the latest `FunctionLog` and passes it to the user's
callback
The collector is never exposed to the user.
## Usage
```rust
let mut stream = B.MyFunction
.with_on_tick(|log: &baml::FunctionLog| {
for call in log.calls() {
if let Some(stream_call) = call.as_stream() {
if let Some(chunks) = stream_call.sse_chunks() {
for chunk in &chunks {
println!("thinking token: {}", chunk.text());
}
}
}
}
})
.stream(args)
.expect("Failed to start stream");
```
## Files Changed
**Rust SDK (`languages/rust/baml/src/`)**
- `ffi/callbacks.rs` — New `OnTickData` struct bundling callback +
collector; simplified `create_callback_with_on_tick` to take single
`Option<OnTickData>`
- `args.rs` — `FunctionArgs.on_tick` is now `Option<OnTickData>`;
removed separate `on_tick_collector` field
- `runtime.rs` — Passes single `on_tick` to callback registration
- `lib.rs` — Exports `OnTickData`
**Code Generator (`engine/generators/languages/rust/src/_templates/`)**
- `runtime.rs.j2` — `FunctionOptions.with_on_tick()` auto-creates
collector and bundles into `OnTickData`; removed `on_tick_collector`
field
- `sync_client.rs.j2` / `async_client.rs.j2` — Convenience macro
delegates to `FunctionOptions.with_on_tick()`
**Tests (`engine/generators/data/sample/rust/main.rs`)**
- 4 on_tick tests (sync/async, with/without explicit collector) — all
print thinking tokens from `FunctionLog`
## Test plan
- [x] `cargo test --lib` passes for `baml` crate (SDK unit tests)
- [x] `RUN_GENERATOR_TESTS=1 cargo test -p generators-rust --lib --
sample_evaluate` passes (generated code compiles and on_tick tests work)
- [x] Tests demonstrate printing thinking tokens from SSE chunks via
`FunctionLog`
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Streaming "on-tick" callbacks: user callbacks are invoked for each SSE
streaming chunk.
* Builder methods to configure per-call tick callbacks on both sync and
async client APIs.
* Automatic collector injection when tick callbacks are used, enabling
per-chunk logs.
* **Tests**
* Added sync and async streaming tests validating tick callbacks,
partial stream handling, final responses, and collector integration.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: hellovai <hellovai@users.noreply.github.com> Latest Branches
0%
vbv/record-replay-system-for-playground-http-calls -14%
-45%
vbv/dynamic-test-definition-syntax-for-baml © 2026 CodSpeed Technology