Skip to main content

agent_runtime_kernel_api/
lib.rs

1//! Stable Link to Kernel contract.
2
3use std::{collections::BTreeSet, sync::Arc};
4
5use async_trait::async_trait;
6use runtime_extension_api::AgentPackage;
7use runtime_ports::{
8    CommitDisposition, ExecutionSessions, OperationContext, ResolvedExecutionContext, TokenUsage,
9};
10use runtime_types::{ConversationId, ExecutionId};
11use thiserror::Error;
12
13#[derive(Debug, Clone)]
14pub struct KernelLimits {
15    pub max_model_turns: usize,
16    pub max_tool_calls: usize,
17    pub context: ContextLimits,
18    pub max_tool_output_bytes: usize,
19}
20
21/// Complete model-context limits. `max_input_tokens` is the hard context
22/// window available to input, protocol framing, and the reserved model output.
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub struct ContextLimits {
25    pub max_messages: usize,
26    pub max_input_tokens: u64,
27    pub reserved_output_tokens: u32,
28    pub protocol_overhead_tokens: u64,
29    pub auto_compact: bool,
30    pub compaction: ContextCompactionLimits,
31}
32
33impl Default for ContextLimits {
34    fn default() -> Self {
35        Self {
36            max_messages: 128,
37            max_input_tokens: 128 * 1024,
38            reserved_output_tokens: 8 * 1024,
39            protocol_overhead_tokens: 256,
40            auto_compact: true,
41            compaction: ContextCompactionLimits::default(),
42        }
43    }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct ContextCompactionLimits {
48    pub trigger_percent: u8,
49    pub target_percent: u8,
50    pub emergency_percent: u8,
51    pub min_reclaim_percent: u8,
52    pub min_turns_between: usize,
53    pub checkpoint_max_chars: usize,
54}
55
56impl Default for ContextCompactionLimits {
57    fn default() -> Self {
58        Self {
59            trigger_percent: 82,
60            target_percent: 60,
61            emergency_percent: 95,
62            min_reclaim_percent: 10,
63            min_turns_between: 4,
64            checkpoint_max_chars: 8_000,
65        }
66    }
67}
68
69#[derive(Clone)]
70pub struct KernelSpec {
71    pub execution_id: ExecutionId,
72    pub conversation_id: Option<ConversationId>,
73    pub user_prompt: String,
74    pub model: String,
75    pub package: Arc<AgentPackage>,
76    pub granted_capabilities: BTreeSet<String>,
77    pub limits: KernelLimits,
78}
79
80#[derive(Debug, Clone)]
81pub enum KernelEvent {
82    Started,
83    ModelStarted {
84        turn: usize,
85    },
86    ModelCompleted {
87        turn: usize,
88    },
89    ToolStarted {
90        call_id: String,
91        name: String,
92    },
93    ToolCompleted {
94        call_id: String,
95        name: String,
96        failed: bool,
97    },
98    Warning {
99        code: String,
100        message: String,
101    },
102}
103
104#[async_trait]
105pub trait KernelEventSink: Send + Sync {
106    async fn emit(&self, event: KernelEvent) -> Result<(), KernelFailure>;
107}
108
109#[derive(Debug, Clone)]
110pub struct KernelOutcome {
111    pub answer: String,
112    pub model_turns: usize,
113    pub tool_calls: usize,
114    pub usage: TokenUsage,
115}
116
117#[derive(Debug, Error, Clone)]
118#[error("{code}: {message}")]
119pub struct KernelFailure {
120    pub code: String,
121    pub message: String,
122    pub retryable: bool,
123    pub commit: CommitDisposition,
124}
125
126impl KernelFailure {
127    pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
128        Self {
129            code: code.into(),
130            message: message.into(),
131            retryable: false,
132            commit: CommitDisposition::NotCommitted,
133        }
134    }
135}
136
137#[async_trait]
138pub trait RuntimeKernel: Send + Sync {
139    async fn execute(
140        &self,
141        operation: OperationContext,
142        spec: KernelSpec,
143        sessions: ExecutionSessions,
144        events: Arc<dyn KernelEventSink>,
145    ) -> Result<KernelOutcome, KernelFailure>;
146}
147
148#[async_trait]
149pub trait AgentPackageResolver: Send + Sync {
150    async fn resolve(
151        &self,
152        operation: &OperationContext,
153        resolved: &ResolvedExecutionContext,
154    ) -> Result<Arc<AgentPackage>, KernelFailure>;
155}