use super::*;
fn tid(n: u64) -> ToolCallId {
ToolCallId::new([n as u8; 12], n)
}
fn call(n: u64) -> ProviderCall {
ProviderCall {
tool_call_id: tid(n),
name: format!("t{n}"),
arguments: format!("{{\"n\":{n}}}"),
}
}
#[test]
fn familiar_constants_and_open_boxes_round_trip() {
assert_eq!(SYSTEM_MESSAGE_TYPE, "System Message");
assert_eq!(USER_MESSAGE_TYPE, "User Message");
assert_eq!(AGENT_MESSAGE_TYPE, "Agent Message");
assert_eq!(USER_ATTACHMENT_TYPE, "User Attachment");
assert_eq!(AGENT_ATTACHMENT_TYPE, "Agent Attachment");
assert_eq!(TOOL_CALL_TYPE, "Tool Call");
assert_eq!(TOOL_MESSAGE_TYPE, "Tool Message");
assert_eq!(TOOL_ATTACHMENT_TYPE, "Tool Attachment");
assert_eq!(TOOL_RESULT_TYPE, "Tool Result");
assert_eq!(ATTACHMENT_TYPE, USER_ATTACHMENT_TYPE);
let mut chat = Chatend::new();
chat.accept_box(
"Future Kind".into(),
"opaque\ncontents".into(),
"future/v9".into(),
"hidden bytes".into(),
)
.unwrap();
chat.accept_attachment(
"Object ID: abc\nName: report.pdf".into(),
"k1.attachment/v1".into(),
"{\"mime\":\"application/pdf\"}".into(),
)
.unwrap();
let boxes = chat.boxes().to_vec();
assert_eq!(
(
boxes[0].id().get(),
boxes[0].box_type(),
boxes[0].contents()
),
(1, "Future Kind", "opaque\ncontents")
);
assert_eq!(
(boxes[0].hidden_type(), boxes[0].hidden_contents()),
("future/v9", "hidden bytes")
);
assert_eq!(boxes[1].box_type(), USER_ATTACHMENT_TYPE);
assert!(boxes[1].contents().contains("report.pdf"));
assert_eq!(Chatend::recover(boxes.clone()).unwrap().boxes(), boxes);
}
#[test]
fn owner_tool_boxes_expose_complete_plain_text_metadata() {
let call = call(7);
let call_box = tool_call_box(&call);
assert_eq!(
call_box.contents(),
"Call ID: 070707070707070707070707/7\nCall Name: t7\nArguments:\n{\"n\":7}"
);
assert_eq!(call_box.tool_call_metadata().unwrap(), Some(call));
let ok = tool_result_box(tid(7), BoxId::new(12), Ok("done".into()));
assert_eq!(
ok.contents(),
"Call ID: 070707070707070707070707/7\nOriginating Call Box ID: 12\nStatus: ok\nResult:\ndone"
);
assert_eq!(
ok.tool_result_metadata().unwrap().unwrap().result,
Ok("done".into())
);
let error = tool_result_box(tid(7), BoxId::new(12), Err("failed\nfully".into()));
assert_eq!(
error.contents(),
"Call ID: 070707070707070707070707/7\nOriginating Call Box ID: 12\nStatus: error\nResult:\nfailed\nfully"
);
assert_eq!(
error.tool_result_metadata().unwrap().unwrap().result,
Err("failed\nfully".into())
);
}
#[test]
fn stages_queue_flush_and_results_remain_transactional() {
let mut chat = Chatend::new();
chat.accept_system("prior".into()).unwrap();
assert_eq!(chat.start_round().unwrap().unwrap().get(), 1);
let dispatched = chat
.append_stage("thinking".into(), vec![call(1), call(2)])
.unwrap();
assert_eq!(
dispatched
.iter()
.map(|value| value.call_box_id.get())
.collect::<Vec<_>>(),
[3, 4]
);
let before = chat.boxes().to_vec();
assert_eq!(
chat.append_stage("bad".into(), vec![call(1)]),
Err(TransitionError::DuplicateToolCall)
);
assert_eq!(chat.boxes(), before);
chat.accept_user("queued".into()).unwrap();
chat.accept_async_return(tid(2), Ok("two".into())).unwrap();
let flushed = chat.flush_active_arrivals().unwrap();
assert_eq!(
flushed
.iter()
.map(|value| value.id().get())
.collect::<Vec<_>>(),
[5, 6]
);
assert_eq!(flushed[0].box_type(), USER_MESSAGE_TYPE);
assert_eq!(
flushed[1]
.tool_result_metadata()
.unwrap()
.unwrap()
.originating_call
.get(),
4
);
assert_eq!(
chat.accept_async_return(tid(2), Ok("again".into())),
Err(TransitionError::DuplicateReturn)
);
chat.done("final".into()).unwrap();
assert_eq!(chat.boxes().last().unwrap().box_type(), AGENT_MESSAGE_TYPE);
assert_eq!(
chat.accept_async_return(tid(9), Ok("x".into())),
Err(TransitionError::UnknownToolCall)
);
}
#[test]
fn recognized_tools_validate_but_unknown_conventions_are_inert() {
let call = call(7);
let call_box = tool_call_box(&call);
assert_eq!(call_box.tool_call_metadata().unwrap(), Some(call));
let result_box = tool_result_box(tid(7), BoxId::new(1), Err("failed\nfully".into()));
assert_eq!(
result_box.tool_result_metadata().unwrap().unwrap().result,
Err("failed\nfully".into())
);
let unknown = ChatBox::new(
BoxId::new(1),
"Tool Call".into(),
"visible".into(),
"future/tool".into(),
"anything".into(),
);
assert_eq!(
Chatend::recover(vec![unknown.clone()]).unwrap().boxes(),
&[unknown]
);
let malformed = ChatBox::new(
BoxId::new(1),
TOOL_CALL_TYPE.into(),
"visible".into(),
TOOL_CALL_HIDDEN_TYPE.into(),
"bad".into(),
);
assert!(matches!(
Chatend::recover(vec![malformed]),
Err(RecoveryError::MalformedToolConvention)
));
}
#[test]
fn recovery_enforces_order_and_exact_tool_correlation() {
let call_box = {
let mut value = tool_call_box(&call(1));
value.id = BoxId::new(1);
value
};
let result_box = {
let mut value = tool_result_box(tid(1), BoxId::new(1), Ok("yes".into()));
value.id = BoxId::new(2);
value
};
let mut recovered = Chatend::recover(vec![call_box.clone(), result_box.clone()]).unwrap();
assert_eq!(
recovered.accept_user("next".into()).unwrap().unwrap().get(),
3
);
let duplicate = {
let mut value = call_box.clone();
value.id = BoxId::new(2);
value
};
assert!(matches!(
Chatend::recover(vec![call_box.clone(), duplicate]),
Err(RecoveryError::DuplicateToolCall)
));
let wrong = {
let mut value = tool_result_box(tid(1), BoxId::new(2), Ok("x".into()));
value.id = BoxId::new(2);
value
};
assert!(matches!(
Chatend::recover(vec![call_box.clone(), wrong]),
Err(RecoveryError::WrongOriginatingCall)
));
let gap = ChatBox::new(
BoxId::new(2),
"Future".into(),
String::new(),
String::new(),
String::new(),
);
assert!(matches!(
Chatend::recover(vec![gap]),
Err(RecoveryError::NonContiguousBoxId)
));
}