kcode-k1-chat-thread-web-code-open-targets 0.2.0

Pure source presentation and target classification for K1 Chat WebCode
Documentation
#![forbid(unsafe_code)]

use kcode_k1_chat_boxes::{BoxId, ChatBox, ToolCallId};
use kcode_k1_chat_web_code_output::{DocumentPart, WebCodeOutput, create, open};
use kcode_k1_web_code_document::CodeDocument;
use std::fmt::{Display, Formatter};

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct SourceLayout {
    originating_call: BoxId,
    tool_call_id: ToolCallId,
    code_message_count: u64,
}

impl SourceLayout {
    pub const fn originating_call(self) -> BoxId {
        self.originating_call
    }
    pub const fn tool_call_id(self) -> ToolCallId {
        self.tool_call_id
    }
    pub const fn code_message_count(self) -> u64 {
        self.code_message_count
    }
}

pub type OpenLayout = SourceLayout;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SourcePresentation {
    pub output: WebCodeOutput,
    pub layout: SourceLayout,
}

pub type OpenPresentation = SourcePresentation;

pub fn present_create(
    originating_call: BoxId,
    tool_call_id: ToolCallId,
    document: &CodeDocument,
    version: &str,
) -> SourcePresentation {
    present(originating_call, tool_call_id, document, version, true)
}

pub fn present_open(
    originating_call: BoxId,
    tool_call_id: ToolCallId,
    document: &CodeDocument,
    version: &str,
) -> SourcePresentation {
    present(originating_call, tool_call_id, document, version, false)
}

fn present(
    originating_call: BoxId,
    tool_call_id: ToolCallId,
    document: &CodeDocument,
    version: &str,
    creating: bool,
) -> SourcePresentation {
    let ranges = document.chunk_ranges();
    let code_message_count = u64::try_from(ranges.len()).expect("code chunk count fits u64");
    let mut messages = Vec::with_capacity(ranges.len() + 1);
    messages.push(text(document.documentation()));
    messages.extend(
        ranges
            .iter()
            .map(|range| text(&document.code()[range.clone()])),
    );
    let name = document.family().logical_name();
    let result = if creating {
        Ok(format!("Created {version}."))
    } else {
        Ok(format!("Opened {version}."))
    };
    let output = if creating {
        create(
            tool_call_id,
            messages,
            result,
            name,
            version,
            document.language(),
            code_message_count,
        )
    } else {
        open(
            tool_call_id,
            messages,
            result,
            name,
            version,
            document.language(),
            code_message_count,
        )
    };
    SourcePresentation {
        output,
        layout: SourceLayout {
            originating_call,
            tool_call_id,
            code_message_count,
        },
    }
}

fn text(bytes: &[u8]) -> String {
    std::str::from_utf8(bytes)
        .expect("CodeDocument retains UTF-8")
        .to_owned()
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TargetRejection {
    HistoryAbsent,
    HistoryDuplicate,
    MalformedPayload,
    DifferentOpen,
    MessageOutOfLayout,
    NotSourceMessage,
}

impl TargetRejection {
    pub const fn code(self) -> &'static str {
        match self {
            Self::HistoryAbsent => "history_absent",
            Self::HistoryDuplicate => "history_duplicate",
            Self::MalformedPayload => "malformed_payload",
            Self::DifferentOpen => "different_open",
            Self::MessageOutOfLayout => "message_out_of_layout",
            Self::NotSourceMessage => "not_source_message",
        }
    }
}

impl Display for TargetRejection {
    fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result {
        formatter.write_str(match self {
            Self::HistoryAbsent => "target box is absent from history",
            Self::HistoryDuplicate => "target box ID occurs more than once in history",
            Self::MalformedPayload => "target has malformed tool metadata",
            Self::DifferentOpen => "target belongs to a different source Open",
            Self::MessageOutOfLayout => "target message index is outside the source layout",
            Self::NotSourceMessage => "target is not an editable source message",
        })
    }
}
impl std::error::Error for TargetRejection {}

pub fn classify_original_target(
    history: &[ChatBox],
    target_id: BoxId,
    layout: SourceLayout,
) -> Result<DocumentPart, TargetRejection> {
    let mut matching = history.iter().filter(|value| value.id() == target_id);
    let target = matching.next().ok_or(TargetRejection::HistoryAbsent)?;
    if matching.next().is_some() {
        return Err(TargetRejection::HistoryDuplicate);
    }
    let message = target
        .tool_message_metadata()
        .map_err(|_| TargetRejection::MalformedPayload)?
        .ok_or(TargetRejection::NotSourceMessage)?;
    if message.tool_call_id != layout.tool_call_id
        || message.originating_call != layout.originating_call
    {
        return Err(TargetRejection::DifferentOpen);
    }
    match message.message_index {
        1 => Ok(DocumentPart::Documentation),
        index if (2..=layout.code_message_count + 1).contains(&index) => Ok(DocumentPart::Code),
        _ => Err(TargetRejection::MessageOutOfLayout),
    }
}