kcode-k1-chat-state 0.6.1

Provider-free open-format chat scheduling state
Documentation
use crate::{ActorState, ChatBox, ProviderCall, StateError, ToolCallId, USER_ATTACHMENT_TYPE};

fn id(n: u64) -> ToolCallId {
    ToolCallId::new([n as u8; 12], n)
}

fn call(n: u64) -> ProviderCall {
    ProviderCall {
        tool_call_id: id(n),
        name: format!("t{n}"),
        arguments: "{}".into(),
    }
}

#[test]
fn begin_adds_no_box() {
    let mut state = ActorState::new(true);
    let start = state.begin_inference().unwrap().unwrap();
    assert_eq!(start.frontier, None);
    assert!(state.boxes().is_empty());
    state.complete_inference(start.job, String::new()).unwrap();
}

#[test]
fn stages_are_canonical_and_launchable_before_done() {
    let mut state = ActorState::new(true);
    let start = state.begin_inference().unwrap().unwrap();
    let first = state
        .append_stage(start.job, "a".into(), vec![call(1), call(2)])
        .unwrap();
    let second = state
        .append_stage(start.job, String::new(), vec![call(3)])
        .unwrap();
    assert_eq!(first.len(), 2);
    assert_eq!(second[0].tool_call_id, id(3));
    assert_eq!(state.boxes()[0].box_type(), "Agent Message");
    assert_eq!(state.boxes()[0].contents(), "a");
    assert_eq!(state.boxes()[1].box_type(), "Tool Call");
    state.complete_inference(start.job, "z".into()).unwrap();
    assert_eq!(state.boxes().last().unwrap().contents(), "z");
}

#[test]
fn generic_unknown_boxes_survive_flush_completion_and_recovery() {
    let mut state = ActorState::new(true);
    let start = state.begin_inference().unwrap().unwrap();
    state
        .accept_box(
            "Future Kind".into(),
            "visible payload".into(),
            "future/v9".into(),
            "hidden payload".into(),
        )
        .unwrap();
    let flushed = state.flush_active_arrivals(start.job).unwrap();
    assert_eq!(flushed.len(), 1);
    assert_eq!(flushed[0].box_type(), "Future Kind");
    assert_eq!(flushed[0].hidden_contents(), "hidden payload");
    state
        .accept_box(
            "Later Future".into(),
            "later visible".into(),
            "future/v10".into(),
            "later hidden".into(),
        )
        .unwrap();
    state.complete_inference(start.job, String::new()).unwrap();
    let boxes = state.boxes().to_vec();
    assert_eq!(boxes[1].box_type(), "Later Future");
    assert_eq!(
        ActorState::recover(boxes.clone(), false).unwrap().boxes(),
        boxes
    );
}

#[test]
fn attachments_require_real_open_fields() {
    let mut state = ActorState::new(false);
    state
        .accept_attachment(
            "Object ID: abc\nName: report.pdf".into(),
            "k1.attachment/v1".into(),
            "{\"mime\":\"application/pdf\"}".into(),
        )
        .unwrap();
    let attachment = &state.boxes()[0];
    assert_eq!(attachment.box_type(), USER_ATTACHMENT_TYPE);
    assert!(attachment.contents().contains("report.pdf"));
    assert_eq!(attachment.hidden_type(), "k1.attachment/v1");
}

#[test]
fn queued_arrivals_are_fifo_and_schedule_one_followup() {
    let mut state = ActorState::new(true);
    let first = state.begin_inference().unwrap().unwrap();
    state.accept_system("s".into()).unwrap();
    state.accept_user("u".into()).unwrap();
    state
        .accept_attachment("a".into(), "attachment/v1".into(), "metadata".into())
        .unwrap();
    state.complete_inference(first.job, String::new()).unwrap();
    assert_eq!(state.boxes()[0].box_type(), "System Message");
    assert_eq!(state.boxes()[1].box_type(), "User Message");
    assert_eq!(state.boxes()[2].contents(), "a");
    let followup = state.begin_inference().unwrap().unwrap();
    assert!(state.begin_inference().unwrap().is_none());
    state
        .complete_inference(followup.job, String::new())
        .unwrap();
    assert!(state.quiet());
}

#[test]
fn flush_is_fifo_keeps_round_active_and_prevents_duplicate_followup() {
    let mut state = ActorState::new(true);
    let start = state.begin_inference().unwrap().unwrap();
    state
        .append_stage(start.job, String::new(), vec![call(1)])
        .unwrap();
    state.accept_user("u".into()).unwrap();
    state.accept_async_return(id(1), Ok("r".into())).unwrap();
    let arrivals = state.flush_active_arrivals(start.job).unwrap();
    assert_eq!(arrivals.len(), 2);
    assert_eq!(arrivals[0].box_type(), "User Message");
    assert_eq!(arrivals[1].box_type(), "Tool Result");
    assert_eq!(arrivals[1].id().get(), arrivals[0].id().get() + 1);
    assert!(state.flush_active_arrivals(start.job).unwrap().is_empty());
    state
        .append_stage(start.job, "continued".into(), vec![])
        .unwrap();
    state.complete_inference(start.job, String::new()).unwrap();
    assert!(state.quiet());
}

#[test]
fn flush_with_wrong_job_is_transactional() {
    let mut state = ActorState::new(true);
    let start = state.begin_inference().unwrap().unwrap();
    state.accept_user("queued".into()).unwrap();
    assert!(matches!(
        state.flush_active_arrivals(start.job + 1),
        Err(StateError::WrongInference { .. })
    ));
    assert!(state.boxes().is_empty());
    assert_eq!(state.flush_active_arrivals(start.job).unwrap().len(), 1);
}

#[test]
fn arrival_after_flush_restores_exactly_one_followup() {
    let mut state = ActorState::new(true);
    let start = state.begin_inference().unwrap().unwrap();
    state.accept_user("first".into()).unwrap();
    assert_eq!(state.flush_active_arrivals(start.job).unwrap().len(), 1);
    state.accept_system("later".into()).unwrap();
    state.complete_inference(start.job, String::new()).unwrap();
    assert_eq!(state.boxes().last().unwrap().contents(), "later");
    let followup = state.begin_inference().unwrap().unwrap();
    assert!(state.begin_inference().unwrap().is_none());
    state
        .complete_inference(followup.job, String::new())
        .unwrap();
    assert!(state.quiet());
}

#[test]
fn call_only_stage_does_not_schedule_and_returns_are_open_format() {
    let mut state = ActorState::new(true);
    let start = state.begin_inference().unwrap().unwrap();
    assert_eq!(
        state
            .append_stage(start.job, String::new(), vec![call(1)])
            .unwrap()
            .len(),
        1
    );
    state.complete_inference(start.job, String::new()).unwrap();
    assert!(state.quiet());
    state
        .accept_async_return(id(1), Ok("result".into()))
        .unwrap();
    assert_eq!(state.boxes().last().unwrap().box_type(), "Tool Result");
    let followup = state.begin_inference().unwrap().unwrap();
    state
        .complete_inference(followup.job, String::new())
        .unwrap();
    assert!(state.quiet());
}

#[test]
fn recovery_is_idle_and_keeps_box_ids() {
    let mut original = ActorState::new(false);
    original.accept_user("prior".into()).unwrap();
    let boxes = original.boxes().to_vec();
    let mut state = ActorState::recover(boxes, false).unwrap();
    assert!(state.quiet());
    state.accept_system("next".into()).unwrap();
    assert_eq!(state.boxes().last().unwrap().id().get(), 2);
}

#[test]
fn retry_uses_a_fresh_job_and_the_same_frontier() {
    let mut state = ActorState::new(false);
    state.accept_user("ask".into()).unwrap();
    let first = state.begin_inference().unwrap().unwrap();
    state.stall_inference(first.job, "retry".into()).unwrap();
    assert_eq!(state.take_halt(), Some("retry".into()));
    state.restart().unwrap();
    let second = state.begin_inference().unwrap().unwrap();
    assert!(second.job > first.job);
    assert_eq!(second.frontier, first.frontier);
    assert_eq!(state.boxes().len(), 1);
    state.complete_inference(second.job, String::new()).unwrap();
}

#[test]
fn wrong_job_and_halt_are_transactional() {
    let mut state = ActorState::new(true);
    let start = state.begin_inference().unwrap().unwrap();
    assert!(matches!(
        state.append_stage(start.job + 1, String::new(), vec![]),
        Err(StateError::WrongInference { .. })
    ));
    assert!(state.halt("stop".into()));
    assert!(matches!(state.restart(), Err(StateError::Busy)));
    state.complete_inference(start.job, String::new()).unwrap();
    assert_eq!(state.take_halt(), Some("stop".into()));
    assert!(state.quiet());
}

#[test]
fn recovered_unknown_box_is_constructible_as_a_chatbox() {
    let unknown = ChatBox::new(
        crate::BoxId::new(1),
        "Unrecognized".into(),
        "contents".into(),
        "unknown/v1".into(),
        "hidden".into(),
    );
    let state = ActorState::recover(vec![unknown], false).unwrap();
    assert_eq!(state.boxes()[0].hidden_type(), "unknown/v1");
}