agent_runtime_kernel_api/
lib.rs1use 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#[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 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}