use kcode_k1_chat_chatend::{ActionId, Chatend, DispatchOutcome};
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_provider_output_and_terminal_returns() {
let mut chat = Chatend::new();
let ok = ActionId::new([0xab; 12], 7);
let error = ActionId::new([0xcd; 12], 8);
chat.start_round().unwrap();
chat.append_kennedy_text("done").unwrap();
chat.collect_provider_call("run".into(), "{}".into())
.unwrap();
chat.collect_provider_call("fail".into(), "null".into())
.unwrap();
chat.complete_provider_output(&[ok, error]).unwrap();
chat.complete_dispatch(vec![
DispatchOutcome::Terminal(Ok("yes".into())),
DispatchOutcome::Terminal(Err("no".into())),
])
.unwrap();
let boxes = chat.boxes();
assert_eq!(
project(&boxes[0]),
BoxValue::History(
"{\"box_id\":1,\"kind\":\"kennedy\",\"text\":\"done\",\"complete\":true}".into()
)
);
assert_eq!(project(&boxes[1]), BoxValue::History("{\"box_id\":2,\"kind\":\"ktool_call\",\"action_id\":{\"session\":\"abababababababababababab\",\"sequence\":7},\"name\":\"run\",\"arguments\":\"{}\"}".into()));
assert_eq!(project(&boxes[3]), BoxValue::History("{\"box_id\":4,\"kind\":\"ktool_return\",\"action_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\",\"action_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"
);
}