kcode-k1-chat-thread-web-code-errors 0.2.0

Pure model-facing error outputs for K1 Chat WebCode tasks
Documentation
#![forbid(unsafe_code)]

use kcode_k1_chat_boxes::ToolCallId;
use kcode_k1_chat_web_code_output::{self as output, Operation, WebCodeOutput};
use kcode_k1_web_code_ktool_service::{ServiceError, ServiceFailure};

pub fn service_error(
    tool_call_id: ToolCallId,
    operation: Operation,
    service_error: ServiceError,
) -> WebCodeOutput {
    let code = match service_error.failure() {
        ServiceFailure::State => "state",
        ServiceFailure::Authorization => "authorization",
        ServiceFailure::WorkspaceDenied => "workspace_denied",
        ServiceFailure::FamilyExists => "family_exists",
        ServiceFailure::SourceUnavailable => "source_unavailable",
        ServiceFailure::VersionUsed => "version_used",
        ServiceFailure::ForeignHandle => "foreign_handle",
        ServiceFailure::StaleSource => "stale_source",
        ServiceFailure::InvalidDocument => "invalid_document",
        ServiceFailure::CheckFailed => "check_failed",
        ServiceFailure::SourcePreservation => "source_preservation",
        ServiceFailure::PublicReleaseDenied => "public_release_denied",
        ServiceFailure::Publication => "publication",
        ServiceFailure::Dependency => "dependency",
    };
    let source_object = service_error.source_object().map(|value| value.to_string());
    error(
        tool_call_id,
        operation,
        code,
        service_error.to_string(),
        source_object.as_deref(),
    )
}

pub fn error(
    tool_call_id: ToolCallId,
    operation: Operation,
    code: &str,
    message: String,
    source_object: Option<&str>,
) -> WebCodeOutput {
    output::error(
        tool_call_id,
        Vec::new(),
        Err(message),
        operation,
        code,
        source_object,
    )
}

pub fn simple_error(
    tool_call_id: ToolCallId,
    operation: Operation,
    code: &'static str,
) -> WebCodeOutput {
    error(tool_call_id, operation, code, code.replace('_', " "), None)
}

#[cfg(test)]
mod tests {
    use super::*;

    fn tool_call_id() -> ToolCallId {
        ToolCallId::new([0x3c; 12], 17)
    }

    #[test]
    fn generic_error_preserves_safe_text_object_and_v2_metadata() {
        let value = error(
            tool_call_id(),
            Operation::Publish,
            "publication",
            "complete safe text\nwith details".to_owned(),
            Some("abcdef0123456789abcdef01"),
        );
        assert_eq!(value.tool_call_id, tool_call_id());
        assert!(value.messages.is_empty());
        assert_eq!(
            value.result,
            Err("complete safe text\nwith details".to_owned())
        );
        assert_eq!(value.metadata_type, "k1.web-code-publish/v2");
        assert_eq!(
            value.metadata_contents,
            r#"{"status":"error","code":"publication","source_object":"abcdef0123456789abcdef01"}"#
        );
    }

    #[test]
    fn simple_error_has_no_source_object() {
        let value = simple_error(tool_call_id(), Operation::Publish, "public_release_denied");
        assert_eq!(value.result, Err("public release denied".to_owned()));
        assert_eq!(
            value.metadata_contents,
            r#"{"status":"error","code":"public_release_denied","source_object":null}"#
        );
    }
}