kcode-k1-codex-web-search-protocol-values 0.1.1

Concrete Codex app-server WebSearch inbound protocol values for K1
Documentation
use std::error::Error;
use std::fmt;

#[derive(Debug)]
pub enum ProtocolError {
    Invalid(&'static str),
    Json(serde_json::Error),
}

impl fmt::Display for ProtocolError {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Invalid(message) => formatter.write_str(message),
            Self::Json(error) => error.fmt(formatter),
        }
    }
}

impl Error for ProtocolError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            Self::Invalid(_) => None,
            Self::Json(error) => Some(error),
        }
    }
}

impl From<serde_json::Error> for ProtocolError {
    fn from(error: serde_json::Error) -> Self {
        Self::Json(error)
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RpcResponse<T> {
    Success(T),
    Error(RpcError),
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RpcError {
    pub code: i64,
    pub message: String,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct ChatGptAccount;

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ReasoningEffort {
    pub reasoning_effort: String,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Model {
    pub id: String,
    pub supported_reasoning_efforts: Vec<ReasoningEffort>,
    pub default_reasoning_effort: Option<String>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ModelPage {
    pub data: Vec<Model>,
    pub next_cursor: Option<String>,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Started {
    pub id: String,
}

pub type ThreadStarted = Started;
pub type TurnStarted = Started;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MessagePhase {
    Commentary,
    FinalAnswer,
    Unknown,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct EventScope {
    pub thread_id: String,
    pub turn_id: String,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SourceCandidate {
    pub url: String,
    pub title: String,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum TurnStatus {
    Completed,
    Failed,
    Interrupted,
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Usage {
    pub input_tokens: Option<u64>,
    pub cached_input_tokens: Option<u64>,
    pub output_tokens: Option<u64>,
    pub reasoning_output_tokens: Option<u64>,
}

pub type ProviderError = String;

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum InboundEvent {
    AgentMessage {
        scope: EventScope,
        id: String,
        phase: MessagePhase,
        text: String,
    },
    SourceCandidates {
        scope: EventScope,
        id: String,
        sources: Vec<SourceCandidate>,
    },
    UsageUpdated {
        scope: EventScope,
        usage: Usage,
    },
    TurnTerminal {
        id: String,
        status: TurnStatus,
        usage: Option<Usage>,
        error: Option<ProviderError>,
    },
    ProviderError(ProviderError),
    Ignored {
        method: String,
        item_type: Option<String>,
    },
}

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

    fn assert_value_traits<T: Clone + fmt::Debug + Eq + PartialEq>() {}
    fn assert_scalar_traits<T: Copy>() {}

    #[test]
    fn values_have_expected_traits_and_shape() {
        assert_value_traits::<RpcResponse<ChatGptAccount>>();
        assert_value_traits::<InboundEvent>();
        assert_scalar_traits::<MessagePhase>();
        assert_scalar_traits::<TurnStatus>();
        assert_scalar_traits::<Usage>();

        assert_eq!(
            RpcResponse::Success(ChatGptAccount),
            RpcResponse::Success(ChatGptAccount)
        );
        assert!(matches!(
            InboundEvent::Ignored {
                method: "unknown".to_owned(),
                item_type: None,
            },
            InboundEvent::Ignored {
                method,
                item_type: None,
            } if method == "unknown"
        ));
        assert!(matches!(
            InboundEvent::UsageUpdated {
                scope: EventScope {
                    thread_id: "thread".to_owned(),
                    turn_id: "turn".to_owned(),
                },
                usage: Usage {
                    input_tokens: Some(1),
                    cached_input_tokens: Some(2),
                    output_tokens: Some(3),
                    reasoning_output_tokens: Some(4),
                },
            },
            InboundEvent::UsageUpdated {
                scope: EventScope { thread_id, turn_id },
                usage: Usage {
                    input_tokens: Some(1),
                    cached_input_tokens: Some(2),
                    output_tokens: Some(3),
                    reasoning_output_tokens: Some(4),
                },
            } if thread_id == "thread" && turn_id == "turn"
        ));
    }
}