use super::*;
use crate::agentic::observability::BehaviorSignal;
use agent_harness::forensics::{inspect_from_store, Inspection};
use agent_harness::store::FrameStore;
fn durable_harness(directory: &std::path::Path) -> SmartHarness {
SmartHarness::new(
Session::open(directory, crate::test_guard::unbudgeted_session_config()).unwrap(),
Arc::new(|_| Box::pin(async { panic!("overflow never needs adjudication") })),
Default::default(),
)
.unwrap()
}
fn inspect(store: &FrameStore, id: ContentId) -> Inspection {
inspect_from_store(store, id, Default::default())
.unwrap()
.unwrap()
}
fn signal(projected_tokens: Option<usize>) -> BehaviorSignal {
BehaviorSignal::ContextExceeded {
round: 1,
attempt: 1,
estimated_tokens: 1500,
projected_tokens,
}
}
#[test]
fn context_exceeded_reprojection_survives_restore_with_rejected_request_ancestry() {
for projected_tokens in [Some(1000), None] {
let directory = tempfile::tempdir().unwrap();
let harness = durable_harness(directory.path());
let original = serde_json::json!({"messages":[
{"role":"user","content":"retained operator prompt"},
{"role":"assistant","content":"old material"}
]});
harness
.record_messages(original["messages"].as_array().unwrap())
.unwrap();
let rejected_bytes = harness.request(&original, "openai").unwrap();
let rejected_id = harness.state().unwrap().request.unwrap();
let error_body = br#"{"error":{"message":"Context size has been exceeded"}}"#;
harness.observe(error_body).unwrap();
let rejected_reply = harness.state().unwrap().reply.unwrap();
let reply_head = harness.head().unwrap();
let event = signal(projected_tokens);
harness.context_exceeded(&event).unwrap();
let intervention_head = harness.head().unwrap();
assert!(harness
.state()
.unwrap()
.session
.pending_replies()
.is_empty());
assert!(harness.state().unwrap().reply.is_none());
assert_eq!(
harness
.state()
.unwrap()
.session
.restored_messages()
.unwrap(),
original["messages"].as_array().unwrap().clone(),
"accounting does not fabricate tool output or add a conversation message"
);
let corrected = projected_tokens.map(|_| {
let body = serde_json::json!({"messages":[
{"role":"user","content":"retained operator prompt"}
]});
let bytes = harness.request(&body, "openai").unwrap();
let id = harness.state().unwrap().request.unwrap();
(id, bytes)
});
let head = harness.head().unwrap();
drop(harness);
let restored = Session::restore(directory.path(), head, "local-session").unwrap();
assert_eq!(restored.replay(rejected_id).unwrap(), rejected_bytes);
if let Some((id, bytes)) = corrected {
assert_eq!(restored.replay(id).unwrap(), bytes);
}
assert!(restored.pending_replies().is_empty());
let store = FrameStore::open(directory.path()).unwrap();
let rejected = inspect(&store, reply_head);
assert_eq!(
rejected.record["reply"]["request"],
serde_json::to_value(rejected_id).unwrap()
);
let journal = inspect(&store, intervention_head);
let intervention_id = journal.references[0].cid.parse().unwrap();
let intervention = inspect(&store, intervention_id);
assert_eq!(intervention.parents, vec![rejected_reply]);
assert_eq!(intervention.record["origin"], "harness");
assert_eq!(intervention.record["kind"], "intervention");
let payload = intervention
.references
.iter()
.find(|reference| reference.relation == "payload")
.unwrap();
let payload: Value =
serde_json::from_slice(&store.source(&payload.cid.parse().unwrap()).unwrap()).unwrap();
assert_eq!(
payload["request_cid"],
serde_json::to_value(rejected_id).unwrap()
);
assert_eq!(payload["signal"], serde_json::to_value(event).unwrap());
}
}
#[test]
fn context_exceeded_without_an_observed_rejection_refuses_without_moving_head() {
let directory = tempfile::tempdir().unwrap();
let harness = durable_harness(directory.path());
harness
.request(
&serde_json::json!({"messages":[{"role":"user","content":"task"}]}),
"openai",
)
.unwrap();
let head = harness.head().unwrap();
let error = harness.context_exceeded(&signal(None)).unwrap_err();
assert!(error.to_string().contains("observed rejection"));
assert_eq!(harness.head().unwrap(), head);
}
#[test]
fn context_exceeded_checkpoint_failure_is_returned_and_prevents_another_request() {
let directory = tempfile::tempdir().unwrap();
let harness = durable_harness(directory.path());
harness
.request(
&serde_json::json!({"messages":[{"role":"user","content":"task"}]}),
"openai",
)
.unwrap();
harness.observe(b"Context size has been exceeded").unwrap();
std::fs::rename(
directory.path().join("heads"),
directory.path().join("retained-heads"),
)
.unwrap();
std::fs::write(
directory.path().join("heads"),
b"blocked checkpoint directory",
)
.unwrap();
assert!(harness.context_exceeded(&signal(Some(1000))).is_err());
assert!(harness
.request(
&serde_json::json!({"messages":[{"role":"user","content":"task"}]}),
"openai"
)
.is_err());
}
#[path = "token_count.rs"]
mod token_count;