use crate::llm::content_hash::{fingerprint_computations, redacted_content_computations};
const TURNS: usize = 24;
fn request(messages: &[serde_json::Value]) -> crate::llm::api::LlmCallOptions {
let mut opts = crate::llm::api::options::base_opts("openai");
opts.model = "gpt-test".to_string();
opts.system = Some("System policy".to_string());
opts.context_manifest = crate::llm::prompt::ContextAssemblyManifest::internal(
"test:system",
"test",
"agent_loop",
opts.system.as_deref(),
);
opts.messages = messages.to_vec();
opts.session_id = Some("request-growth-session".to_string());
opts
}
fn turn(run: &str, index: usize) -> [serde_json::Value; 2] {
let call_id = format!("call_{run}_{index}");
[
serde_json::json!({
"role": "assistant",
"content": "",
"tool_calls": [{"id": call_id, "type": "function",
"function": {"name": "read", "arguments": format!("{{\"line\":{index}}}")}}],
}),
serde_json::json!({
"role": "tool",
"tool_call_id": call_id,
"content": format!("{run} read {index}\n{}", "fn example() -> int { 1 }\n".repeat(40)),
}),
]
}
fn hashing_work_for_growing_transcript() -> (usize, usize, usize) {
let run = uuid::Uuid::now_v7().to_string();
let mut messages = vec![serde_json::json!({"role": "user", "content": format!("task {run}")})];
let fingerprints_before = fingerprint_computations();
let redactions_before = redacted_content_computations();
for index in 0..TURNS {
messages.extend(turn(&run, index));
let opts = request(&messages);
for _ in 0..3 {
let _ = crate::llm::cost::project_llm_call_cost(&opts, 0.0);
}
super::dump_llm_request(index, &format!("call-{index}"), "native", &opts)
.expect("observable request");
}
(
messages.len(),
fingerprint_computations() - fingerprints_before,
redacted_content_computations() - redactions_before,
)
}
#[test]
fn per_call_request_work_hashes_and_redacts_only_new_messages() {
let _guard = crate::llm::env_guard();
let saved_ambient = super::transcript_ambient::swap_llm_transcript_ambient(Default::default());
let saved_log = crate::event_log::swap_active_event_log(None);
let _log = crate::event_log::install_memory_for_current_thread(4096);
let (messages, fingerprints, redactions) = hashing_work_for_growing_transcript();
crate::event_log::swap_active_event_log(saved_log);
let _ = super::transcript_ambient::swap_llm_transcript_ambient(saved_ambient);
assert!(
fingerprints >= messages && redactions >= messages,
"{fingerprints} fingerprints and {redactions} redactions for {messages} messages"
);
assert!(
fingerprints <= 2 * messages,
"{fingerprints} fingerprints for {messages} messages over {TURNS} calls: \
the request is being re-hashed on every call"
);
assert!(
redactions <= messages,
"{redactions} redactions for {messages} messages over {TURNS} calls: \
the request is being re-redacted on every call"
);
}
#[test]
fn an_observed_attempt_projects_context_tokens_once() {
use crate::llm::fake::{
install_fake_llm_script, FakeLlmEvent, FakeLlmScript, FakeLlmTurn, FakeStopReason,
};
let _guard = crate::llm::env_guard();
let transcript_dir = tempfile::tempdir().expect("transcript tempdir");
let run = uuid::Uuid::now_v7().to_string();
let mut messages = vec![serde_json::json!({"role": "user", "content": format!("task {run}")})];
messages.extend(turn(&run, 0));
let mut opts = request(&messages);
opts.provider = "fake".to_string();
opts.model = "fake-stream".to_string();
opts.native_tools = None;
opts.tools = None;
opts.tool_choice = None;
opts.provider_overrides = None;
let _script = install_fake_llm_script(FakeLlmScript::new().push(FakeLlmTurn::stream(vec![
FakeLlmEvent::Token("done".into()),
FakeLlmEvent::Done(FakeStopReason::EndTurn),
])));
super::push_llm_transcript_dir(transcript_dir.path().to_str().expect("utf8 tempdir"));
let before = crate::llm::cost_context::context_breakdown_projections();
let result = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("runtime")
.block_on(super::observed_llm_call(
&opts, None, None, None, false, false, None, None,
));
let projections = crate::llm::cost_context::context_breakdown_projections() - before;
super::pop_llm_transcript_dir();
assert_eq!(result.expect("scripted call").text, "done");
let transcript = std::fs::read_to_string(transcript_dir.path().join("llm_transcript.jsonl"))
.expect("request receipt");
assert!(
transcript.contains("\"context_token_breakdown\""),
"the attempt reached the request receipt that reports the projection"
);
assert_eq!(
projections, 1,
"{projections} context-token projections for one provider attempt"
);
}