1use crate::compact::{self, CompactState};
2use crate::config::HarnessConfig;
3use crate::harness::{
4 AgentRunState, HarnessPolicy, ToolLoopDecision, compact_tool_observation, record_tool_call,
5 record_tool_result,
6};
7use crate::model::{ModelMessage, ModelProvider};
8use crate::prompt::{PromptCache, RenderedPrompt, SystemPromptInput, SystemPromptRenderer};
9use crate::security::{SecurityDecision, SecurityPolicy};
10use crate::tool::{ToolDefinition, ToolInvocation, ToolResult};
11use anyhow::Result;
12use async_trait::async_trait;
13use std::sync::Arc;
14
15#[derive(Clone)]
16pub struct RuntimeComponents {
17 pub security: Arc<dyn ToolSecurityPolicy>,
18 pub harness: Arc<dyn HarnessDriver>,
19 pub prompt: Arc<dyn PromptBuilder>,
20 pub compaction: Arc<dyn CompactionStrategy>,
21 pub hooks: Arc<dyn SessionHooks>,
22}
23
24impl Default for RuntimeComponents {
25 fn default() -> Self {
26 Self {
27 security: Arc::new(DefaultToolSecurityPolicy),
28 harness: Arc::new(DefaultHarnessDriver),
29 prompt: Arc::new(DefaultPromptBuilder),
30 compaction: Arc::new(DefaultCompactionStrategy),
31 hooks: Arc::new(NoopSessionHooks),
32 }
33 }
34}
35
36pub trait ToolSecurityPolicy: Send + Sync {
37 fn validate_tool(
38 &self,
39 base_policy: &SecurityPolicy,
40 definition: &ToolDefinition,
41 invocation: &ToolInvocation,
42 ) -> SecurityDecision;
43}
44
45#[derive(Debug, Default)]
46pub struct DefaultToolSecurityPolicy;
47
48impl ToolSecurityPolicy for DefaultToolSecurityPolicy {
49 fn validate_tool(
50 &self,
51 base_policy: &SecurityPolicy,
52 definition: &ToolDefinition,
53 invocation: &ToolInvocation,
54 ) -> SecurityDecision {
55 base_policy.validate_tool_invocation(definition, invocation)
56 }
57}
58
59#[derive(Debug, Default)]
60pub struct PermissiveSecurityPolicy;
61
62impl ToolSecurityPolicy for PermissiveSecurityPolicy {
63 fn validate_tool(
64 &self,
65 _base_policy: &SecurityPolicy,
66 _definition: &ToolDefinition,
67 _invocation: &ToolInvocation,
68 ) -> SecurityDecision {
69 SecurityDecision::Allow
70 }
71}
72
73pub trait HarnessDriver: Send + Sync {
74 fn filter_tools(
75 &self,
76 tools: Vec<ToolDefinition>,
77 allowed_tool_names: Option<&[String]>,
78 ) -> Vec<ToolDefinition>;
79
80 fn record_tool_call(
81 &self,
82 state: &mut AgentRunState,
83 policy: HarnessPolicy,
84 invocation: &ToolInvocation,
85 ) -> ToolLoopDecision;
86
87 fn record_tool_result(
88 &self,
89 state: &mut AgentRunState,
90 policy: HarnessPolicy,
91 invocation: &ToolInvocation,
92 result: &ToolResult,
93 ) -> ToolLoopDecision;
94
95 fn compact_tool_observation(
96 &self,
97 invocation: &ToolInvocation,
98 result: &ToolResult,
99 policy: HarnessPolicy,
100 ) -> String;
101}
102
103#[derive(Debug, Default)]
104pub struct DefaultHarnessDriver;
105
106impl HarnessDriver for DefaultHarnessDriver {
107 fn filter_tools(
108 &self,
109 tools: Vec<ToolDefinition>,
110 allowed_tool_names: Option<&[String]>,
111 ) -> Vec<ToolDefinition> {
112 let Some(whitelist) = allowed_tool_names else {
113 return tools;
114 };
115 tools
116 .into_iter()
117 .filter(|tool| whitelist.contains(&tool.name))
118 .collect()
119 }
120
121 fn record_tool_call(
122 &self,
123 state: &mut AgentRunState,
124 policy: HarnessPolicy,
125 invocation: &ToolInvocation,
126 ) -> ToolLoopDecision {
127 record_tool_call(state, policy, invocation)
128 }
129
130 fn record_tool_result(
131 &self,
132 state: &mut AgentRunState,
133 policy: HarnessPolicy,
134 invocation: &ToolInvocation,
135 result: &ToolResult,
136 ) -> ToolLoopDecision {
137 record_tool_result(state, policy, invocation, result)
138 }
139
140 fn compact_tool_observation(
141 &self,
142 invocation: &ToolInvocation,
143 result: &ToolResult,
144 policy: HarnessPolicy,
145 ) -> String {
146 compact_tool_observation(invocation, result, policy)
147 }
148}
149
150pub trait PromptBuilder: Send + Sync {
151 fn build(&self, input: SystemPromptInput, cache: Arc<PromptCache>) -> RenderedPrompt;
152}
153
154#[derive(Debug, Default)]
155pub struct DefaultPromptBuilder;
156
157impl PromptBuilder for DefaultPromptBuilder {
158 fn build(&self, input: SystemPromptInput, cache: Arc<PromptCache>) -> RenderedPrompt {
159 SystemPromptRenderer::new(cache).render(input)
160 }
161}
162
163#[async_trait]
164pub trait CompactionStrategy: Send + Sync {
165 fn micro_compact(&self, messages: &mut Vec<ModelMessage>, gap_threshold_minutes: u64) -> usize;
166
167 async fn auto_compact(
168 &self,
169 state: &mut CompactState,
170 messages: &mut Vec<ModelMessage>,
171 provider: &dyn ModelProvider,
172 model: &str,
173 config: &HarnessConfig,
174 ) -> Result<Option<compact::CompactOutcome>>;
175
176 async fn force_compact(
178 &self,
179 state: &mut CompactState,
180 messages: &mut Vec<ModelMessage>,
181 provider: &dyn ModelProvider,
182 model: &str,
183 config: &HarnessConfig,
184 ) -> Result<Option<compact::CompactOutcome>> {
185 state.force_compact(messages, provider, model, config).await
187 }
188}
189
190#[derive(Debug, Default)]
191pub struct DefaultCompactionStrategy;
192
193#[async_trait]
194impl CompactionStrategy for DefaultCompactionStrategy {
195 fn micro_compact(&self, messages: &mut Vec<ModelMessage>, gap_threshold_minutes: u64) -> usize {
196 compact::micro_compact(messages, gap_threshold_minutes)
197 }
198
199 async fn auto_compact(
200 &self,
201 state: &mut CompactState,
202 messages: &mut Vec<ModelMessage>,
203 provider: &dyn ModelProvider,
204 model: &str,
205 config: &HarnessConfig,
206 ) -> Result<Option<compact::CompactOutcome>> {
207 state.auto_compact(messages, provider, model, config).await
208 }
209
210 async fn force_compact(
211 &self,
212 state: &mut CompactState,
213 messages: &mut Vec<ModelMessage>,
214 provider: &dyn ModelProvider,
215 model: &str,
216 config: &HarnessConfig,
217 ) -> Result<Option<compact::CompactOutcome>> {
218 state.force_compact(messages, provider, model, config).await
219 }
220}
221
222pub trait SessionHooks: Send + Sync {
223 fn on_session_start(&self, _session_id: &str) {}
224 fn on_turn_start(&self, _session_id: &str, _task: &str) {}
225 fn on_tool_call(&self, _invocation: &ToolInvocation) {}
226 fn on_tool_result(&self, _result: &ToolResult) {}
227 fn on_turn_end(&self, _session_id: &str, _output: &str) {}
228 fn on_session_end(&self, _session_id: &str) {}
229}
230
231#[derive(Debug, Default)]
232pub struct NoopSessionHooks;
233
234impl SessionHooks for NoopSessionHooks {}