agent_engine/session/
view.rs1use agent_core::reasoning::ReasoningLevel;
9use serde::{Deserialize, Serialize};
10
11use super::types::reasoning_level_serde;
12
13#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
16pub struct RuntimeView {
17 pub model: String,
18 pub thinking_level: String,
19 #[serde(with = "reasoning_level_serde")]
20 pub reasoning_level: ReasoningLevel,
21 pub is_reasoning_explicit: bool,
22 pub thinking_budget: u32,
23 pub context_window: u64,
24 pub system_prompt: Option<String>,
25 pub compaction_model: String,
26 pub api_retries: u32,
27 pub subagent_timeout: u64,
28 pub max_tool_output: usize,
29 pub bash_timeout: u64,
30 pub bash_max_timeout: u64,
31 pub prompt_generation: u64,
32 pub hook_handler_count: usize,
33 pub prompt_inspection: Option<String>,
36}
37
38impl RuntimeView {
39 pub fn snapshot(runtime: &crate::Runtime, hook_handler_count: usize) -> Self {
42 Self {
43 model: runtime.model().to_string(),
44 thinking_level: runtime.thinking_level().to_string(),
45 reasoning_level: runtime.reasoning_level(),
46 is_reasoning_explicit: runtime.is_reasoning_explicit(),
47 thinking_budget: runtime.thinking_budget(),
48 context_window: runtime.context_window(),
49 system_prompt: runtime.system_prompt().map(str::to_string),
50 compaction_model: runtime.compaction_model().to_string(),
51 api_retries: runtime.api_retries(),
52 subagent_timeout: runtime.subagent_timeout(),
53 max_tool_output: runtime.max_tool_output(),
54 bash_timeout: runtime.bash_timeout(),
55 bash_max_timeout: runtime.bash_max_timeout(),
56 prompt_generation: runtime.prompt_generation(),
57 hook_handler_count,
58 prompt_inspection: runtime.prompt_inspection_json(),
59 }
60 }
61
62 pub async fn from_runtime(runtime: &crate::Runtime) -> Self {
64 let n = runtime.hook_bus().handler_count().await;
65 Self::snapshot(runtime, n)
66 }
67}
68
69pub trait RuntimeRead {
73 fn model(&self) -> &str;
74 fn thinking_level(&self) -> &str;
75 fn reasoning_level(&self) -> ReasoningLevel;
76 fn is_reasoning_explicit(&self) -> bool;
77 fn thinking_budget(&self) -> u32;
78 fn context_window(&self) -> u64;
79 fn system_prompt(&self) -> Option<&str>;
80 fn compaction_model(&self) -> &str;
81 fn api_retries(&self) -> u32;
82 fn subagent_timeout(&self) -> u64;
83 fn max_tool_output(&self) -> usize;
84 fn bash_timeout(&self) -> u64;
85 fn bash_max_timeout(&self) -> u64;
86 fn prompt_inspection_json(&self) -> Option<String>;
88}
89
90impl RuntimeRead for crate::Runtime {
91 fn model(&self) -> &str {
92 crate::Runtime::model(self)
93 }
94 fn thinking_level(&self) -> &str {
95 crate::Runtime::thinking_level(self)
96 }
97 fn reasoning_level(&self) -> ReasoningLevel {
98 crate::Runtime::reasoning_level(self)
99 }
100 fn is_reasoning_explicit(&self) -> bool {
101 crate::Runtime::is_reasoning_explicit(self)
102 }
103 fn thinking_budget(&self) -> u32 {
104 crate::Runtime::thinking_budget(self)
105 }
106 fn context_window(&self) -> u64 {
107 crate::Runtime::context_window(self)
108 }
109 fn system_prompt(&self) -> Option<&str> {
110 crate::Runtime::system_prompt(self)
111 }
112 fn compaction_model(&self) -> &str {
113 crate::Runtime::compaction_model(self)
114 }
115 fn api_retries(&self) -> u32 {
116 crate::Runtime::api_retries(self)
117 }
118 fn subagent_timeout(&self) -> u64 {
119 crate::Runtime::subagent_timeout(self)
120 }
121 fn max_tool_output(&self) -> usize {
122 crate::Runtime::max_tool_output(self)
123 }
124 fn bash_timeout(&self) -> u64 {
125 crate::Runtime::bash_timeout(self)
126 }
127 fn bash_max_timeout(&self) -> u64 {
128 crate::Runtime::bash_max_timeout(self)
129 }
130 fn prompt_inspection_json(&self) -> Option<String> {
131 crate::Runtime::prompt_inspection_json(self)
132 }
133}
134
135impl RuntimeRead for RuntimeView {
136 fn model(&self) -> &str {
137 &self.model
138 }
139 fn thinking_level(&self) -> &str {
140 &self.thinking_level
141 }
142 fn reasoning_level(&self) -> ReasoningLevel {
143 self.reasoning_level
144 }
145 fn is_reasoning_explicit(&self) -> bool {
146 self.is_reasoning_explicit
147 }
148 fn thinking_budget(&self) -> u32 {
149 self.thinking_budget
150 }
151 fn context_window(&self) -> u64 {
152 self.context_window
153 }
154 fn system_prompt(&self) -> Option<&str> {
155 self.system_prompt.as_deref()
156 }
157 fn compaction_model(&self) -> &str {
158 &self.compaction_model
159 }
160 fn api_retries(&self) -> u32 {
161 self.api_retries
162 }
163 fn subagent_timeout(&self) -> u64 {
164 self.subagent_timeout
165 }
166 fn max_tool_output(&self) -> usize {
167 self.max_tool_output
168 }
169 fn bash_timeout(&self) -> u64 {
170 self.bash_timeout
171 }
172 fn bash_max_timeout(&self) -> u64 {
173 self.bash_max_timeout
174 }
175 fn prompt_inspection_json(&self) -> Option<String> {
176 self.prompt_inspection.clone()
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use super::*;
183
184 fn view() -> RuntimeView {
185 RuntimeView {
186 model: "m".into(),
187 thinking_level: "high".into(),
188 reasoning_level: ReasoningLevel::High,
189 is_reasoning_explicit: false,
190 thinking_budget: 1024,
191 context_window: 200_000,
192 system_prompt: Some("sys".into()),
193 compaction_model: "c".into(),
194 api_retries: 3,
195 subagent_timeout: 60,
196 max_tool_output: 4096,
197 bash_timeout: 30,
198 bash_max_timeout: 300,
199 prompt_generation: 1,
200 hook_handler_count: 0,
201 prompt_inspection: None,
202 }
203 }
204
205 #[test]
206 fn view_json_round_trip() {
207 let v = view();
208 let json = serde_json::to_string(&v).unwrap();
209 let back: RuntimeView = serde_json::from_str(&json).unwrap();
210 assert_eq!(v, back);
211 assert!(json.contains(r#""reasoning_level":"high""#));
212 }
213
214 #[test]
215 fn view_reads_through_trait() {
216 fn read(r: &impl RuntimeRead) -> (String, u64) {
217 (r.model().to_string(), r.context_window())
218 }
219 assert_eq!(read(&view()), ("m".to_string(), 200_000));
220 }
221
222 #[test]
223 fn headless_runtime_snapshot_matches_getters() {
224 let rt = crate::Runtime::new_headless();
225 let v = RuntimeView::snapshot(&rt, 0);
226 assert_eq!(v.model, crate::Runtime::model(&rt));
227 assert_eq!(v.thinking_level, crate::Runtime::thinking_level(&rt));
228 assert_eq!(v.context_window, crate::Runtime::context_window(&rt));
229 assert_eq!(v.bash_timeout, crate::Runtime::bash_timeout(&rt));
230 assert_eq!(RuntimeRead::model(&v), RuntimeRead::model(&rt));
231 }
232}