agent-runtime-kernel-api 0.1.1

Internal Kernel contract for Agent Runtime
Documentation
//! Stable Link to Kernel contract.

use std::{collections::BTreeSet, sync::Arc};

use async_trait::async_trait;
use runtime_extension_api::AgentDefinition;
use runtime_ports::{
    CommitDisposition, ConversationMessage, ExecutionSessions, ModelFinish, ModelGenerationOptions,
    OperationContext, ResolvedExecutionContext, TokenUsage,
};
use runtime_types::{ConversationId, ExecutionId};
use thiserror::Error;

#[derive(Debug, Clone)]
pub struct KernelLimits {
    pub max_model_turns: usize,
    pub max_tool_calls: usize,
    pub context: ContextLimits,
    pub max_tool_output_bytes: usize,
}

/// Complete model-context limits. `max_input_tokens` is the hard context
/// window available to input, protocol framing, and the reserved model output.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContextLimits {
    pub max_messages: usize,
    pub max_input_tokens: u64,
    pub reserved_output_tokens: u32,
    pub protocol_overhead_tokens: u64,
    pub auto_compact: bool,
    pub compaction: ContextCompactionLimits,
}

impl Default for ContextLimits {
    fn default() -> Self {
        Self {
            max_messages: 128,
            max_input_tokens: 128 * 1024,
            reserved_output_tokens: 8 * 1024,
            protocol_overhead_tokens: 256,
            auto_compact: true,
            compaction: ContextCompactionLimits::default(),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ContextCompactionLimits {
    pub trigger_percent: u8,
    pub target_percent: u8,
    pub emergency_percent: u8,
    pub min_reclaim_percent: u8,
    pub min_turns_between: usize,
    pub checkpoint_max_chars: usize,
}

impl Default for ContextCompactionLimits {
    fn default() -> Self {
        Self {
            trigger_percent: 82,
            target_percent: 60,
            emergency_percent: 95,
            min_reclaim_percent: 10,
            min_turns_between: 4,
            checkpoint_max_chars: 8_000,
        }
    }
}

#[derive(Clone)]
pub struct KernelSpec {
    pub execution_id: ExecutionId,
    pub conversation_id: Option<ConversationId>,
    pub user_prompt: String,
    /// Request-supplied text messages with their original roles. `user_prompt`
    /// remains the active goal used by hooks and compaction; it must not replace
    /// this transcript when provider adapters supplied multiple turns.
    pub request_messages: Vec<ConversationMessage>,
    pub model: String,
    pub generation: ModelGenerationOptions,
    pub definition: Arc<AgentDefinition>,
    pub granted_capabilities: BTreeSet<String>,
    pub limits: KernelLimits,
}

#[derive(Debug, Clone)]
pub enum KernelEvent {
    Started,
    ModelStarted {
        turn: usize,
        invocation_id: String,
    },
    ModelCompleted {
        turn: usize,
        invocation_id: String,
        finish: ModelFinish,
        usage: TokenUsage,
    },
    ToolStarted {
        call_id: String,
        name: String,
    },
    ToolCompleted {
        call_id: String,
        name: String,
        failed: bool,
    },
    Warning {
        code: String,
        message: String,
    },
}

#[async_trait]
pub trait KernelEventSink: Send + Sync {
    async fn emit(&self, event: KernelEvent) -> Result<(), KernelFailure>;
}

#[derive(Debug, Clone)]
pub struct KernelOutcome {
    pub answer: String,
    pub model_turns: usize,
    pub tool_calls: usize,
    pub usage: TokenUsage,
}

#[derive(Debug, Error, Clone)]
#[error("{code}: {message}")]
pub struct KernelFailure {
    pub code: String,
    pub message: String,
    pub retryable: bool,
    pub commit: CommitDisposition,
}

impl KernelFailure {
    pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
        Self {
            code: code.into(),
            message: message.into(),
            retryable: false,
            commit: CommitDisposition::NotCommitted,
        }
    }
}

#[async_trait]
pub trait RuntimeKernel: Send + Sync {
    async fn execute(
        &self,
        operation: OperationContext,
        spec: KernelSpec,
        sessions: ExecutionSessions,
        events: Arc<dyn KernelEventSink>,
    ) -> Result<KernelOutcome, KernelFailure>;
}

#[async_trait]
pub trait AgentDefinitionResolver: Send + Sync {
    async fn resolve(
        &self,
        operation: &OperationContext,
        resolved: &ResolvedExecutionContext,
    ) -> Result<Arc<AgentDefinition>, KernelFailure>;
}