#![allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::indexing_slicing,
reason = "test code"
)]
use kernel::model::message_payload;
use kernel::{
Address, AxError, B3Hash, BuildingPolicy, ContentBlock, EventDraft, EventRef, GENESIS_PREV,
Ledger, Locator, Model, ModelRequest, ModelReturn, ModelUsage, Payload, RunId, Seq, TimeMs,
Tokens, ToolCall, ToolName, ToolOutcome,
};
use runtime::handoff::Handoff;
use runtime::prefix::{FrozenPrefix, FrozenSegment, SegmentSlot};
use runtime::run::{RunHooks, RunPlan, drive};
use runtime::turn::CallShape;
use runtime::{Interrupt, SafePoint};
struct SinkLedger {
seq: u64,
}
impl Ledger for SinkLedger {
fn append(&mut self, draft: EventDraft) -> Result<EventRef, AxError> {
let record = kernel::EventRecord::from_draft(draft, Seq::new(self.seq), GENESIS_PREV);
self.seq = self.seq.saturating_add(1);
Ok(record.to_ref())
}
}
struct MeteredModel {
reported: Vec<u64>,
seen: std::rc::Rc<std::cell::RefCell<Vec<String>>>,
}
impl Model for MeteredModel {
fn call(&mut self, req: &ModelRequest) -> Result<ModelReturn, AxError> {
self.seen
.borrow_mut()
.push(format!("{:?}", req.chat.messages));
let input = self.reported.remove(0);
let calls = if self.reported.is_empty() {
Vec::new()
} else {
vec![ToolCall {
id: format!("t-{input}"),
name: ToolName::parse("status").unwrap(),
args: Payload::empty(),
}]
};
let mut returned = ModelReturn::bare(
message_payload(&[ContentBlock::Text {
text: "working".to_owned(),
}])
.unwrap(),
calls,
);
returned.usage = Some(ModelUsage {
input_tokens: Tokens::new(input),
..ModelUsage::default()
});
Ok(returned)
}
}
fn plan(window: u64) -> RunPlan {
let addr = Address::parse("lab/room1").unwrap();
RunPlan {
run: RunId::from_bytes([9; 16]),
who: "resident".to_owned(),
addr: addr.clone(),
task: "fill the window".to_owned(),
goal: "until told".to_owned(),
opening: runtime::Opening::FromJob,
job: Locator::parse(&format!("file:{}/JOB.md@{}", addr.as_str(), "a".repeat(40))).unwrap(),
parent: None,
predecessor: None,
dispatched_by: kernel::event::Who::Person,
run_policy: kernel::RunPolicy::of(kernel::Mode::Work),
naming: None,
inherited: Vec::new(),
shape: CallShape {
model: "metered".to_owned(),
max_tokens: kernel::Ceiling::new(4096),
effort: None,
context_tokens: window,
},
second_threshold: None,
context: runtime::ContextReading::default(),
prefix: FrozenPrefix::assemble(
FrozenSegment::new(SegmentSlot::City, b"city".to_vec()),
FrozenSegment::new(SegmentSlot::Building, b"building".to_vec()),
FrozenSegment::new(SegmentSlot::Resident, b"resident".to_vec()),
FrozenSegment::new(SegmentSlot::Run, b"run".to_vec()),
)
.unwrap(),
policy: BuildingPolicy::default(),
tools: Vec::new(),
skills: Vec::new(),
retries: kernel::Retries::UntilHalted,
}
}
fn handoff() -> Handoff {
Handoff::new(
vec![Locator::parse(&format!("cas:b3-{}", B3Hash::digest(b"x"))).unwrap()],
String::new(),
String::new(),
String::new(),
String::new(),
)
.unwrap()
}
fn windows_for(reported: Vec<u64>) -> Vec<String> {
let seen = std::rc::Rc::new(std::cell::RefCell::new(Vec::new()));
let mut model = MeteredModel {
reported,
seen: std::rc::Rc::clone(&seen),
};
let mut ledger = SinkLedger { seq: 1 };
let mut tick = 0u64;
let mut now = move || {
tick = tick.saturating_add(1);
Ok(TimeMs::new(tick))
};
let mut interrupt = |_: SafePoint| Interrupt::None;
let mut invoke = |_: &ToolCall, _: TimeMs| {
Ok(ToolOutcome {
result: Payload::empty(),
attachments: Vec::new(),
})
};
let mut hooks = RunHooks {
now: &mut now,
interrupt: &mut interrupt,
checkpoint: None,
writes: &|_: &kernel::ToolCall| kernel::Writes::Domain,
invoke: &mut invoke,
wait: &mut |_: TimeMs| runtime::NextCall::Allowed,
deltas: None,
};
drive(plan(1_000), &mut ledger, &mut model, &mut hooks, &handoff()).unwrap();
seen.borrow().clone()
}
#[test]
fn the_first_rung_reports_usage_once_and_the_handover_mark_says_what_is_left() {
let windows = windows_for(vec![100, 300, 400, 700, 800]);
assert_eq!(windows.len(), 5);
assert!(
!windows[1].contains("[context]"),
"10% says nothing: {}",
windows[1]
);
assert!(
windows[2].contains("30% of the window used (300 of 1000 input tokens)"),
"at the first rung, the usage is reported as the provider counted it: {}",
windows[2]
);
assert!(
windows[4].contains("70% of the window used")
&& windows[4].contains("still enough to write a handoff and `succeed`"),
"past two thirds, the run is told the budget left is still enough to hand over: {}",
windows[4]
);
let last = &windows[4];
assert_eq!(
last.matches("of the window used").count(),
2,
"each threshold sounds exactly once per run: {last}"
);
}
#[test]
fn a_jump_past_both_thresholds_sounds_the_higher_one_only() {
let windows = windows_for(vec![700, 900]);
let last = &windows[1];
assert!(last.contains("still enough to write a handoff"), "{last}");
assert_eq!(last.matches("of the window used").count(), 1, "{last}");
}
#[test]
fn a_model_with_no_stated_window_is_never_reminded() {
let seen = std::rc::Rc::new(std::cell::RefCell::new(Vec::new()));
let mut model = MeteredModel {
reported: vec![900, 950],
seen: std::rc::Rc::clone(&seen),
};
let mut ledger = SinkLedger { seq: 1 };
let mut now = || Ok(TimeMs::new(1));
let mut interrupt = |_: SafePoint| Interrupt::None;
let mut invoke = |_: &ToolCall, _: TimeMs| {
Ok(ToolOutcome {
result: Payload::empty(),
attachments: Vec::new(),
})
};
let mut hooks = RunHooks {
now: &mut now,
interrupt: &mut interrupt,
checkpoint: None,
writes: &|_: &kernel::ToolCall| kernel::Writes::Domain,
invoke: &mut invoke,
wait: &mut |_: TimeMs| runtime::NextCall::Allowed,
deltas: None,
};
drive(plan(0), &mut ledger, &mut model, &mut hooks, &handoff()).unwrap();
assert!(
!seen.borrow()[1].contains("[context]"),
"no denominator, no percentage: {}",
seen.borrow()[1]
);
}
#[test]
fn status_reports_the_count_of_the_call_that_asked() {
let seen = std::rc::Rc::new(std::cell::RefCell::new(Vec::new()));
let mut model = MeteredModel {
reported: vec![300, 400, 500],
seen,
};
let plan = plan(1_000);
let status = runtime::StatusTool::new(runtime::StatusSnapshot {
who: "resident".to_owned(),
addr: Address::parse("lab/room1").unwrap(),
policy: kernel::RunPolicy::of(kernel::Mode::Work),
ctx_limit: Tokens::new(1_000),
trust: "trusted".to_owned(),
write_domain: "lab/room1".to_owned(),
locks: Vec::new(),
worktree_path: "lab/room1".to_owned(),
worktree_disk: kernel::ByteLen::new(0),
signals_pending: 0,
provider_mode: runtime::ProviderMode::Normal,
neighbours: 0,
})
.unwrap()
.metering(plan.context.clone());
let heard = std::rc::Rc::new(std::cell::RefCell::new(Vec::new()));
let lines = std::rc::Rc::clone(&heard);
let mut ledger = SinkLedger { seq: 1 };
let mut tick = 0u64;
let mut now = move || {
tick = tick.saturating_add(1);
Ok(TimeMs::new(tick))
};
let mut interrupt = |_: SafePoint| Interrupt::None;
let mut invoke = |call: &ToolCall, _: TimeMs| {
let outcome = kernel::Tool::invoke(&status, call)?;
let text = serde_json::to_value(&outcome.result).unwrap()["text"]
.as_str()
.unwrap()
.to_owned();
lines.borrow_mut().extend(
text.lines()
.filter(|line| line.starts_with("ctx:"))
.map(str::to_owned),
);
Ok(outcome)
};
let mut hooks = RunHooks {
now: &mut now,
interrupt: &mut interrupt,
checkpoint: None,
invoke: &mut invoke,
writes: &|_: &kernel::ToolCall| kernel::Writes::Domain,
wait: &mut |_: TimeMs| runtime::NextCall::Allowed,
deltas: None,
};
drive(plan, &mut ledger, &mut model, &mut hooks, &handoff()).unwrap();
assert_eq!(
*heard.borrow(),
vec!["ctx: 300/1000".to_owned(), "ctx: 400/1000".to_owned()]
);
}