kcode-k1-chat-codex-codec 0.2.0

Concrete Codex wrapper validator and K1 chat-box JSON projector
Documentation
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"
    );
}