lash-remote-protocol 0.1.0-alpha.103

Versioned remote embedding protocol DTOs for Lash sessions, turns, activities, tools, and LLM calls.
Documentation
//! Transport-neutral foreground-turn cancellation envelopes.

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

use crate::registry_errors::{RemoteProtocolError, require_non_empty};
use crate::{REMOTE_PROTOCOL_VERSION, ensure_protocol_version};

#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum RemoteTurnControlDurabilityTier {
    Inline,
    Durable,
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct RemoteTurnCancellationEvidence {
    pub request_id: String,
    /// Opaque host-domain data; Lash records and returns it unchanged.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub origin: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reason: Option<String>,
}

impl RemoteTurnCancellationEvidence {
    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
        require_non_empty(
            "RemoteTurnCancellationEvidence",
            "request_id",
            &self.request_id,
        )
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct RemoteTurnCancelRequest {
    pub protocol_version: u32,
    pub session_id: String,
    pub turn_id: String,
    pub request_id: String,
    /// Opaque host-domain data; Lash never interprets this value.
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub origin: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub reason: Option<String>,
}

impl RemoteTurnCancelRequest {
    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
        ensure_protocol_version(self.protocol_version)?;
        require_non_empty("RemoteTurnCancelRequest", "session_id", &self.session_id)?;
        require_non_empty("RemoteTurnCancelRequest", "turn_id", &self.turn_id)?;
        require_non_empty("RemoteTurnCancelRequest", "request_id", &self.request_id)
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "outcome", rename_all = "snake_case")]
pub enum RemoteTurnCancelOutcome {
    Requested {
        cancellation: RemoteTurnCancellationEvidence,
    },
    AlreadyRequested {
        cancellation: RemoteTurnCancellationEvidence,
    },
    CompletionWonRace,
    UnknownOrRevoked,
}

impl RemoteTurnCancelOutcome {
    fn validate(&self) -> Result<(), RemoteProtocolError> {
        match self {
            Self::Requested { cancellation } | Self::AlreadyRequested { cancellation } => {
                cancellation.validate()
            }
            Self::CompletionWonRace | Self::UnknownOrRevoked => Ok(()),
        }
    }
}

#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct RemoteTurnCancelReceipt {
    pub protocol_version: u32,
    pub session_id: String,
    pub turn_id: String,
    pub durability_tier: RemoteTurnControlDurabilityTier,
    pub outcome: RemoteTurnCancelOutcome,
}

impl RemoteTurnCancelReceipt {
    pub fn new(
        session_id: impl Into<String>,
        turn_id: impl Into<String>,
        durability_tier: RemoteTurnControlDurabilityTier,
        outcome: RemoteTurnCancelOutcome,
    ) -> Self {
        Self {
            protocol_version: REMOTE_PROTOCOL_VERSION,
            session_id: session_id.into(),
            turn_id: turn_id.into(),
            durability_tier,
            outcome,
        }
    }

    pub fn validate(&self) -> Result<(), RemoteProtocolError> {
        ensure_protocol_version(self.protocol_version)?;
        require_non_empty("RemoteTurnCancelReceipt", "session_id", &self.session_id)?;
        require_non_empty("RemoteTurnCancelReceipt", "turn_id", &self.turn_id)?;
        self.outcome.validate()
    }
}