use kcode_k1_chat_chatend::{Chatend, ProviderCall, ToolCallId};
use kcode_k1_chat_codex_codec::{BoxValue, Call, Codec, project};
use kcode_k1_codex_adapter::{BoxCodec, ToolCall};
use serde_json::json;
fn call(name: &str, arguments: serde_json::Value) -> ToolCall {
ToolCall {
call_id: "call".into(),
name: name.into(),
arguments,
}
}
#[test]
fn validates_exact_wrapper_and_serializes_nested_arguments() {
let mut codec = Codec;
assert_eq!(
codec.tool_call_box(&call(
"call_ktool",
json!({"name":"run","arguments":{"b":[2,1],"a":true}}),
)),
BoxValue::Call(Ok(Call {
name: "run".into(),
arguments: "{\"a\":true,\"b\":[2,1]}".into(),
}))
);
for arguments in [
json!({"name":"x"}),
json!({"arguments":null}),
json!({"name":"x","arguments":1,"extra":true}),
json!({"name":1,"arguments":null}),
json!([]),
] {
assert!(matches!(
codec.tool_call_box(&call("call_ktool", arguments)),
BoxValue::Call(Err(_))
));
}
assert!(matches!(
codec.tool_call_box(&call("other", json!({"name":"x","arguments":null}))),
BoxValue::Call(Err(_))
));
}
#[test]
fn projects_arrivals_with_escaped_text() {
let mut chat = Chatend::new();
chat.accept_system("s\n".into()).unwrap();
chat.accept_user("u\"".into()).unwrap();
chat.accept_attachment().unwrap();
let boxes = chat.boxes();
assert_eq!(
project(&boxes[0]),
BoxValue::History("{\"box_id\":1,\"kind\":\"system\",\"text\":\"s\\n\"}".into())
);
assert_eq!(
project(&boxes[1]),
BoxValue::History("{\"box_id\":2,\"kind\":\"user\",\"text\":\"u\\\"\"}".into())
);
assert_eq!(
project(&boxes[2]),
BoxValue::History("{\"box_id\":3,\"kind\":\"attachment\"}".into())
);
}
#[test]
fn projects_staged_output_and_async_returns() {
let mut chat = Chatend::new();
let ok = ToolCallId::new([0xab; 12], 7);
let error = ToolCallId::new([0xcd; 12], 8);
chat.start_round().unwrap();
chat.append_stage(
"done".into(),
vec![
ProviderCall {
tool_call_id: ok,
name: "run".into(),
arguments: "{}".into(),
},
ProviderCall {
tool_call_id: error,
name: "fail".into(),
arguments: "null".into(),
},
],
)
.unwrap();
chat.accept_async_return(ok, Ok("yes".into())).unwrap();
chat.accept_async_return(error, Err("no".into())).unwrap();
chat.done(String::new()).unwrap();
let boxes = chat.boxes();
assert_eq!(
project(&boxes[0]),
BoxValue::History("{\"box_id\":1,\"kind\":\"kennedy\",\"text\":\"done\"}".into())
);
assert_eq!(project(&boxes[1]), BoxValue::History("{\"box_id\":2,\"kind\":\"ktool_call\",\"tool_call_id\":{\"session\":\"abababababababababababab\",\"sequence\":7},\"name\":\"run\",\"arguments\":\"{}\"}".into()));
assert_eq!(project(&boxes[3]), BoxValue::History("{\"box_id\":4,\"kind\":\"ktool_return\",\"tool_call_id\":{\"session\":\"abababababababababababab\",\"sequence\":7},\"originating_call_box_id\":2,\"result\":{\"status\":\"ok\",\"value\":\"yes\"}}".into()));
assert_eq!(project(&boxes[4]), BoxValue::History("{\"box_id\":5,\"kind\":\"ktool_return\",\"tool_call_id\":{\"session\":\"cdcdcdcdcdcdcdcdcdcdcdcd\",\"sequence\":8},\"originating_call_box_id\":3,\"result\":{\"status\":\"error\",\"value\":\"no\"}}".into()));
}
#[test]
fn calls_are_terminal_text() {
assert_eq!(Codec.box_text(&BoxValue::Call(Err("bad".into()))), "");
assert_eq!(
Codec.box_text(&BoxValue::History("history".into())),
"history"
);
}