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