use crate::llm::agent_session_host::{
assistant_message_from_llm_result_for_test, dict_get, list_items, record_tool_results_for_test,
reset_agent_session_host_state, seed_host_session_provider_model, vm_to_json,
};
use serde_json::json;
#[test]
fn producer_histories_admit_for_openai_and_anthropic_and_keep_failure_egress() {
for (provider, model) in [
("openai", "gpt-5.6-luna"),
("anthropic", "claude-sonnet-4-5"),
] {
reset_agent_session_host_state();
let session_id = crate::agent_sessions::open_or_create_for_test(Some(format!(
"recorded-tool-error-admission-{provider}-{}",
uuid::Uuid::now_v7()
)));
seed_host_session_provider_model(&session_id, provider, model);
crate::agent_sessions::claim_tool_format(&session_id, "native")
.expect("native tool format claims");
crate::agent_sessions::inject_message(
&session_id,
crate::schema::json_to_vm_value(&json!({"role": "user", "content": "inspect"})),
)
.expect("user turn injects");
let llm_result_json = if provider == "anthropic" {
json!({
"provider": provider,
"model": model,
"text": "Checking the requested file.",
"thinking": "Private continuation stays in transcript.",
"blocks": [{
"type": "thinking",
"thinking": "Signed continuation.",
"signature": "signed-thinking",
}],
"_agent_tool_format": "native",
"native_tool_calls": [{
"id": "call_failed",
"name": "inspect",
"arguments": {"path": "README.md"},
}],
})
} else {
json!({
"provider": provider,
"model": model,
"text": "Checking the requested file.",
"_agent_tool_format": "native",
"native_tool_calls": [{
"id": "call_failed",
"name": "inspect",
"arguments": {"path": "README.md"},
}],
})
};
let llm_result = crate::schema::json_to_vm_value(&llm_result_json);
crate::agent_sessions::inject_message(
&session_id,
assistant_message_from_llm_result_for_test(&llm_result),
)
.expect("assistant tool call injects");
record_tool_results_for_test(
&session_id,
crate::schema::json_to_vm_value(&json!([{
"tool_name": "inspect",
"tool_call_id": "call_failed",
"observation": "inspection failed",
"ok": false,
}])),
);
let transcript = crate::agent_sessions::transcript(&session_id).expect("transcript");
let messages = list_items(
&dict_get(&transcript, "messages")
.cloned()
.unwrap_or(crate::value::VmValue::Nil),
);
let assistant = vm_to_json(&messages[1]);
let recorded_result = vm_to_json(&messages[2]);
assert_eq!(recorded_result["role"], "tool_result");
assert_eq!(recorded_result["is_error"], true);
assert_eq!(recorded_result["_harn"]["tool_call_id"], "call_failed");
assert_eq!(recorded_result["_harn"]["outcome"], "error");
let mut options = crate::llm::api::options::base_opts(provider);
options.model = model.into();
options.provider_overrides = None;
if provider == "anthropic" {
options.native_tools = Some(vec![json!({
"name": "inspect",
"input_schema": {"type": "object"},
})]);
}
options.budget = Some(crate::llm::cost::LlmBudgetEnvelope {
admission: Some(crate::llm::admission::AdmissionMode::Conservative),
total_budget_usd: Some(1.0),
..Default::default()
});
options.messages = vec![assistant, recorded_result];
let request = crate::llm::api::LlmRequestPayload::from(&options);
assert!(request
.messages
.iter()
.all(|message| message.get("_harn").is_none()));
let previous =
crate::llm::admission::swap_scope(crate::llm::admission::AdmissionScope::default());
let reservation = crate::llm::admission::reserve(
&options,
&request,
crate::llm::cost_context::LlmCallTokenProjection::for_options(&options),
)
.unwrap_or_else(|error| panic!("recorded {provider} tool history refused: {error:?}"));
assert!(
reservation.is_some(),
"the paid {provider} route reserves its bound"
);
drop(reservation);
crate::llm::admission::swap_scope(previous);
if provider == "anthropic" {
assert!(request.messages[0].get("provider_continuation").is_some());
assert_eq!(
request.messages[0]["reasoning"],
"Private continuation stays in transcript."
);
let body = crate::llm::providers::AnthropicProvider::build_request_body(&request);
let assistant_blocks = body["messages"][0]["content"]
.as_array()
.expect("Anthropic assistant blocks");
assert!(assistant_blocks.iter().any(|block| block["type"] == "text"));
assert!(assistant_blocks
.iter()
.any(|block| block["type"] == "thinking"));
assert!(assistant_blocks
.iter()
.any(|block| block["type"] == "tool_use"));
let wire_result = &body["messages"][1]["content"][0];
assert_eq!(wire_result["type"], "tool_result");
assert_eq!(wire_result["tool_use_id"], "call_failed");
assert_eq!(wire_result["is_error"], true);
}
}
}