kcode-k1-chat-chatend 0.5.1

Append-only open-format ChatBox state transitions for K1 chat
Documentation
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)
    ));
}