The l3-jouleclaw binding gains HybridBackend — the wave
57/58 hybrid surface as a Joule Code L3 stage:
point it at a snapshot directory; the family is
auto-detected from config.json's model_type
(nemotron_h | granitemoehybrid | falcon_h1), the BF16
checkpoint mmaps, and hybrid_lm::generate drives it —
batched prefill (bit-identical to sequential by the
loader's parity guarantees), greedy or seeded sampling,
EOS stop ids read from the config (int or list).
Same LlmBackend trait as every other backend; it drops
into jouleclaw_l3_stage unchanged. Energy stays honest:
no per-call meter on this path → energy_joules: None,
the receipt carries the catalog Estimator figure.
Verified on the real Falcon-H1-0.5B checkpoint
(opt-in --ignored, JOULE_HYBRID env to point elsewhere):
backend: "The capital of France is"
→ " Paris. It is known for"
cascade: L0 cache miss → closes at L3 with a
content-addressed CodingOp
(op_id b3:23u9…, estimated_uj 1000000)
Also: repair the example for the jouleclaw-llm-cheap →
jouleclaw-llm crate rename (the example was unbuildable at
HEAD; same API, new name, all refs fixed).
A Mamba2/attention hybrid running on the family's own
from-scratch tensor code now closes the standard's
cascade end to end: tokenize → prefill → decode →
CodingOp → JCR-1-ready receipt, no llama.cpp, no FFI,
no Python.
Co-Authored-By: Claude Fable 5 <[email protected]>
80 lines
3.1 KiB
Rust
80 lines
3.1 KiB
Rust
//! L3 on JouleClaw's **own from-scratch GGUF runtime** — the in-process path.
|
|
//!
|
|
//! Proves the headline of this binding: a real local GGUF model, executed on
|
|
//! `jouleclaw-runtime` (no llama.cpp, no FFI), closes a Joule Code cascade at
|
|
//! tier L3 with a content-addressed `CodingOp` and a joules-class receipt.
|
|
//!
|
|
//! `#[ignore]` because it needs a real model on disk. Run with:
|
|
//!
|
|
//! JOULE_BONSAI=/path/to/model.gguf \
|
|
//! cargo test -p l3-jouleclaw-binding --release --test runtime_l3 -- --ignored --nocapture
|
|
//!
|
|
//! (defaults to `../../../pattern-lang/models/ternary-bonsai-1.7b-q2_0.gguf`).
|
|
|
|
use joule_code_cascade::{Cascade, L0Cache, Request, Stage};
|
|
use joule_code_schema::Tier;
|
|
use jouleclaw_llm::{LlmBackend, LlmRequest};
|
|
|
|
use l3_jouleclaw_binding::jouleclaw_l3_stage;
|
|
use l3_jouleclaw_binding::runtime_backend::JouleclawRuntimeBackend;
|
|
|
|
fn model_path() -> String {
|
|
std::env::var("JOULE_BONSAI").unwrap_or_else(|_| {
|
|
"../../../pattern-lang/models/ternary-bonsai-1.7b-q2_0.gguf".to_string()
|
|
})
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn runtime_backend_completes_in_process() {
|
|
let backend =
|
|
JouleclawRuntimeBackend::from_path(model_path()).expect("load model on jouleclaw-runtime");
|
|
eprintln!("model: {}", backend.model_name());
|
|
|
|
// Greedy, short — keep the reference-backend forward passes bounded.
|
|
let mut req = LlmRequest::from_prompt("The capital of France is", 4);
|
|
req.temperature = 0.0;
|
|
let resp = backend.complete(&req).expect("complete");
|
|
|
|
eprintln!(" in={} out={} text={:?}", resp.input_tokens, resp.output_tokens, resp.text);
|
|
assert!(resp.input_tokens > 0, "prompt tokenized");
|
|
assert!(resp.output_tokens > 0, "produced output tokens");
|
|
assert!(!resp.text.is_empty(), "produced text");
|
|
// No per-call meter on the generate path — honestly None (the run binary
|
|
// meters host energy around the call).
|
|
assert!(resp.energy_joules.is_none());
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn cascade_closes_at_l3_on_jouleclaw_runtime() {
|
|
let backend =
|
|
JouleclawRuntimeBackend::from_path(model_path()).expect("load model on jouleclaw-runtime");
|
|
let model_name = backend.model_name().to_string();
|
|
|
|
// Empty L0 cache in front of the in-process L3 model stage: L0 misses, the
|
|
// from-scratch runtime closes the request at L3.
|
|
let cascade = Cascade::new([
|
|
Box::new(L0Cache::new()) as Box<dyn Stage>,
|
|
Box::new(jouleclaw_l3_stage(Box::new(backend))) as Box<dyn Stage>,
|
|
]);
|
|
|
|
let res = cascade
|
|
.resolve(&Request {
|
|
prior: "b3:scratch".into(),
|
|
intent: "Write a Rust function add(a,b).".into(),
|
|
})
|
|
.expect("cascade resolved");
|
|
|
|
eprintln!("model: {model_name}");
|
|
eprintln!("tier : {}", res.receipt.tier);
|
|
eprintln!("op_id: {}", res.op.as_ref().unwrap().op_id().unwrap());
|
|
eprintln!("answer:\n{}", res.answer.as_deref().unwrap_or(""));
|
|
|
|
assert_eq!(res.receipt.tier, Tier::L3, "closed at L3");
|
|
assert!(res.op.is_some(), "produced a coding op");
|
|
assert!(
|
|
res.answer.map(|a| !a.is_empty()).unwrap_or(false),
|
|
"the from-scratch runtime produced an answer"
|
|
);
|
|
}
|