use kcode_k1_chat_chatend::{
AGENT_ATTACHMENT_TYPE, AGENT_MESSAGE_TYPE, BoxId, ChatBox, SYSTEM_MESSAGE_TYPE,
TOOL_ATTACHMENT_TYPE, TOOL_CALL_TYPE, TOOL_MESSAGE_TYPE, TOOL_RESULT_TYPE,
USER_ATTACHMENT_TYPE, USER_MESSAGE_TYPE,
};
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(),
}))
);
assert_eq!(
codec.tool_call_box(&call(
"call_ktool",
json!({"name":"nullable","arguments":null}),
)),
BoxValue::Call(Ok(Call {
name: "nullable".into(),
arguments: "null".into(),
}))
);
}
#[test]
fn malformed_native_calls_retain_validation_behavior() {
let mut codec = Codec;
let cases = [
(
"other",
json!({"name":"x","arguments":null}),
"tool name must be call_ktool",
),
("call_ktool", json!([]), "tool arguments must be an object"),
(
"call_ktool",
json!({"name":"x"}),
"tool arguments must have name and arguments",
),
(
"call_ktool",
json!({"arguments":null}),
"tool arguments must have name and arguments",
),
(
"call_ktool",
json!({"name":"x","arguments":1,"extra":true}),
"tool arguments must have name and arguments",
),
(
"call_ktool",
json!({"name":1,"arguments":null}),
"tool arguments name must be a string",
),
];
for (tool_name, arguments, error) in cases {
assert_eq!(
codec.tool_call_box(&call(tool_name, arguments)),
BoxValue::Call(Err(error.into()))
);
}
}
#[test]
fn projects_all_nine_familiar_string_conventions_generically() {
let box_types = [
SYSTEM_MESSAGE_TYPE,
USER_MESSAGE_TYPE,
AGENT_MESSAGE_TYPE,
USER_ATTACHMENT_TYPE,
AGENT_ATTACHMENT_TYPE,
TOOL_CALL_TYPE,
TOOL_MESSAGE_TYPE,
TOOL_ATTACHMENT_TYPE,
TOOL_RESULT_TYPE,
];
for (index, box_type) in box_types.into_iter().enumerate() {
let id = u64::try_from(index + 1).unwrap();
let contents = format!("visible contents {id}");
let box_ = ChatBox::new(
BoxId::new(id),
box_type.into(),
contents.clone(),
format!("hidden-type-{id}"),
format!("hidden-contents-{id}"),
);
assert_eq!(
project(&box_),
BoxValue::History(format!("[Box {id} | {box_type}]\n{contents}"))
);
}
}
#[test]
fn preserves_unknown_type_and_literal_text_but_omits_hidden_markers() {
let box_type = "Future\n\"Type\"\\v9";
let contents = "first line\n\"quoted\" and \\backslash\nlast line";
let box_ = ChatBox::new(
BoxId::new(10),
box_type.into(),
contents.into(),
"HIDDEN-TYPE-MARKER".into(),
"HIDDEN-CONTENTS-MARKER\nsecret".into(),
);
let projected = project(&box_);
assert_eq!(
projected,
BoxValue::History(format!("[Box 10 | {box_type}]\n{contents}"))
);
let BoxValue::History(text) = projected else {
panic!("projection must be history");
};
assert!(!text.contains("HIDDEN-TYPE-MARKER"));
assert!(!text.contains("HIDDEN-CONTENTS-MARKER"));
}
#[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"
);
}