agent-context-contract 0.1.1

Transport-neutral contracts for Agent Infra context APIs
Documentation
use serde::{Deserialize, Serialize};
use serde_json::Value;

use crate::{AuthorizedScope, ConversationScope};

pub const SNAPSHOTS_PATH: &str = "/internal/v1/context/snapshots";
pub const SNAPSHOT_GET_PATH: &str = "/internal/v1/context/snapshots/get";
pub const DERIVATIONS_PATH: &str = "/internal/v1/context/derivations";
pub const MODEL_INVOCATIONS_PATH: &str = "/internal/v1/context/model-invocations";
pub const MODEL_INVOCATION_GET_PATH: &str = "/internal/v1/context/model-invocations/get";
pub const MAX_SNAPSHOT_ITEMS: usize = 2_000;
pub const MAX_SNAPSHOT_BYTES: usize = 16 * 1024 * 1024;

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ContextSnapshotStage {
    Original,
    Assembled,
    Compressed,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ContextSnapshotItemKind {
    Message,
    ToolResult,
    ContextInsight,
    KnowledgeEvidence,
}

/// The smallest replayable external-knowledge record. References are opaque to
/// Context Infra and never imply ownership of the provider's source document.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct KnowledgeEvidence {
    pub provider: String,
    pub resource_ref: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub revision_ref: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub segment_ref: Option<String>,
    pub excerpt: String,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub citation: Option<String>,
    #[serde(default, skip_serializing_if = "Value::is_null")]
    pub metadata: Value,
}

/// One ordered item that was actually visible to the model.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ContextSnapshotItem {
    pub id: String,
    pub ordinal: u32,
    pub kind: ContextSnapshotItemKind,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub role: Option<String>,
    pub content: Value,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub source_record_id: Option<String>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub knowledge_evidence: Option<KnowledgeEvidence>,
    #[serde(default, skip_serializing_if = "Value::is_null")]
    pub metadata: Value,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ContextSnapshot {
    pub id: String,
    pub scope: AuthorizedScope,
    pub conversation: ConversationScope,
    pub stage: ContextSnapshotStage,
    pub purpose: String,
    pub token_count: u64,
    pub items: Vec<ContextSnapshotItem>,
    pub created_at_ms: i64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct CreateContextSnapshotRequest {
    pub id: String,
    pub conversation: ConversationScope,
    pub stage: ContextSnapshotStage,
    pub purpose: String,
    pub token_count: u64,
    pub items: Vec<ContextSnapshotItem>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct GetContextSnapshotRequest {
    pub snapshot_id: String,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ContextDerivationKind {
    Assemble,
    Compress,
    Trim,
    Reorder,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ContextDerivation {
    pub id: String,
    pub scope: AuthorizedScope,
    pub source_snapshot_id: String,
    pub target_snapshot_id: String,
    pub kind: ContextDerivationKind,
    pub strategy: String,
    pub strategy_version: String,
    pub input_token_count: u64,
    pub output_token_count: u64,
    pub input_item_count: u32,
    pub output_item_count: u32,
    #[serde(default, skip_serializing_if = "Value::is_null")]
    pub metadata: Value,
    pub created_at_ms: i64,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct CreateContextDerivationRequest {
    pub id: String,
    pub source_snapshot_id: String,
    pub target_snapshot_id: String,
    pub kind: ContextDerivationKind,
    pub strategy: String,
    pub strategy_version: String,
    pub input_token_count: u64,
    pub output_token_count: u64,
    pub input_item_count: u32,
    pub output_item_count: u32,
    #[serde(default, skip_serializing_if = "Value::is_null")]
    pub metadata: Value,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ModelInvocationState {
    Prepared,
    Succeeded,
    Failed,
}

/// Audit record for the exact request snapshot supplied to one model call.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct ModelInvocation {
    pub id: String,
    pub scope: AuthorizedScope,
    pub conversation_id: String,
    pub request_snapshot_id: String,
    pub model: String,
    pub provider: String,
    pub state: ModelInvocationState,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub response: Option<Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub error_code: Option<String>,
    #[serde(default, skip_serializing_if = "Value::is_null")]
    pub usage: Value,
    pub created_at_ms: i64,
    pub completed_at_ms: Option<i64>,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PutModelInvocationRequest {
    pub id: String,
    pub conversation_id: String,
    pub request_snapshot_id: String,
    pub model: String,
    pub provider: String,
    pub state: ModelInvocationState,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub response: Option<Value>,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub error_code: Option<String>,
    #[serde(default, skip_serializing_if = "Value::is_null")]
    pub usage: Value,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub completed_at_ms: Option<i64>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct GetModelInvocationRequest {
    pub invocation_id: String,
}