1use crate::provider::{ContentBlock, Msg};
2
3pub mod inference_scaling;
7pub use inference_scaling::{ReasoningBudget, best_of_n, reason_max, self_refine_from};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
12pub enum ReasoningDepth {
13 Fast,
14 Adaptive,
15 Deep,
16}
17
18impl Default for ReasoningDepth {
19 fn default() -> Self {
20 ReasoningDepth::Adaptive
21 }
22}
23
24pub struct AntiSimulationGuard;
31
32impl AntiSimulationGuard {
33 const CLAIM_KEYWORDS: &'static [&'static str] = &[
35 "all tests pass",
36 "tests pass",
37 "build succeeds",
38 "build successful",
39 "output:",
40 "returns:",
41 "returned:",
42 "the result is",
43 "got:",
44 "passed",
45 "succeeded",
46 "compiled",
47 "ran successfully",
48 "no errors",
49 "0 errors",
50 "zero failures",
51 "green",
52 ];
53
54 pub fn check(turn_messages: &[Msg], tool_outputs_in_turn: bool) -> Option<String> {
56 if tool_outputs_in_turn {
57 return None; }
59
60 for msg in turn_messages.iter().filter(|m| m.role == "assistant") {
61 for block in &msg.content {
62 if let ContentBlock::Text { text } = block {
63 let lower = text.to_lowercase();
64 for kw in Self::CLAIM_KEYWORDS {
65 if lower.contains(kw) {
66 return Some(format!(
67 "anti-simulation: assistant claimed result (matched '{}') without executing a tool. Execute the tool first, then report the RAW output.",
68 kw
69 ));
70 }
71 }
72 }
73 }
74 }
75 None
76 }
77
78 pub fn check_code_claim(text: &str, had_fs_read: bool, had_search: bool) -> Option<String> {
80 if had_fs_read || had_search {
81 return None;
82 }
83 let lower = text.to_lowercase();
84 let code_claims = [
85 "function", "struct", "impl", "trait", "fn ", "pub fn", "mod ", "class ",
86 ];
87 let assertion_patterns = [
88 "exists",
89 "is defined",
90 "takes",
91 "returns",
92 "has a",
93 "contains",
94 ];
95
96 let has_code_ref = code_claims.iter().any(|c| lower.contains(c));
97 let has_assertion = assertion_patterns.iter().any(|a| lower.contains(a));
98
99 if has_code_ref && has_assertion {
100 return Some(
101 "hallucination-guard: you made an assertion about the code without reading it first. Use fs_read or search to verify before claiming.".into()
102 );
103 }
104 None
105 }
106}
107
108pub struct HallucinationGuard;
111
112impl HallucinationGuard {
113 pub fn verify(text: &str, tools_called: &[String]) -> Option<String> {
116 let has_read = tools_called.iter().any(|t| t == "fs_read" || t == "search");
117 AntiSimulationGuard::check_code_claim(text, has_read, has_read)
118 }
119}
120
121pub struct SelfCritique;
124
125impl SelfCritique {
126 pub fn pre_mutation_review(diffs: &[crate::event::FileDiff], spec: Option<&str>) -> String {
128 let mut review = String::from("## Self-critique (pre-mutation review)\n\n");
129
130 if diffs.is_empty() {
131 review.push_str("No diffs to review.\n");
132 return review;
133 }
134
135 review.push_str(&format!("Files to change: {}\n", diffs.len()));
136 for d in diffs {
137 review.push_str(&format!("- {} (+{} -{})\n", d.file, d.plus, d.minus));
138 }
139
140 review.push_str("\n### Checklist\n");
141 review.push_str("- [ ] Each change addresses the spec/requirement\n");
142 review.push_str("- [ ] No unnecessary formatting changes\n");
143 review.push_str("- [ ] Tests still pass after changes\n");
144 review.push_str("- [ ] No secrets or credentials exposed\n");
145 review.push_str("- [ ] Edge cases considered\n");
146
147 if let Some(s) = spec {
148 review.push_str(&format!("\nRefer to spec: {}\n", s));
149 }
150
151 review
152 }
153}
154
155pub struct UncertaintyEstimator;
158
159impl UncertaintyEstimator {
160 pub fn confidence(has_read_files: bool, has_run_tests: bool, task_complexity: &str) -> f64 {
162 let mut confidence: f64 = 0.3;
163
164 if has_read_files {
165 confidence += 0.3;
166 }
167 if has_run_tests {
168 confidence += 0.3;
169 }
170
171 match task_complexity {
172 "trivial" => confidence += 0.1,
173 "small" => confidence += 0.05,
174 "medium" => confidence += 0.0,
175 "hard" => confidence -= 0.1,
176 "vision" => confidence -= 0.05,
177 _ => {}
178 }
179
180 confidence.max(0.0).min(1.0)
181 }
182
183 pub fn uncertain_message() -> &'static str {
185 "I'm not sure about this — let me verify before proceeding."
186 }
187}
188
189pub struct StopAndAsk;
192
193impl StopAndAsk {
194 pub fn should_ask(
196 ambiguity_level: f64,
197 is_irreversible: bool,
198 autonomy_allows: bool,
199 constraints_missing: bool,
200 ) -> Option<String> {
201 if ambiguity_level > 0.7 && !autonomy_allows {
202 return Some(
203 "High ambiguity detected. Could you clarify:\n- What exact behavior do you expect?\n- Are there specific constraints I should know?".into()
204 );
205 }
206
207 if is_irreversible && !autonomy_allows {
208 return Some(
209 "This action is irreversible. Before proceeding, please confirm:\n- Is this the expected outcome?\n- Are there any backups or safeguards in place?".into()
210 );
211 }
212
213 if constraints_missing {
214 return Some(
215 "Missing constraints. Could you specify:\n- Target environment/OS?\n- Performance requirements?\n- Compatibility constraints?".into()
216 );
217 }
218
219 None
220 }
221
222 pub fn ask_single(question: &str) -> String {
224 format!("❓ {}", question)
225 }
226}
227
228pub struct ReasoningEngine {
231 pub depth: ReasoningDepth,
232 pub anti_simulation: bool,
233 pub hallucination_guard: bool,
234 pub self_critique: bool,
235}
236
237impl Default for ReasoningEngine {
238 fn default() -> Self {
239 Self {
240 depth: ReasoningDepth::Adaptive,
241 anti_simulation: true,
242 hallucination_guard: true,
243 self_critique: true,
244 }
245 }
246}
247
248impl ReasoningEngine {
249 pub fn plan_depth(&self, task: &str) -> usize {
251 let tier = crate::router::TaskTier::from_str(if task.len() > 100 {
252 "hard"
253 } else if task.len() > 30 {
254 "medium"
255 } else {
256 "small"
257 });
258 match self.depth {
259 ReasoningDepth::Fast => 1,
260 ReasoningDepth::Deep => 5,
261 ReasoningDepth::Adaptive => match tier {
262 crate::router::TaskTier::Trivial => 1,
263 crate::router::TaskTier::Small => 2,
264 crate::router::TaskTier::Medium => 3,
265 crate::router::TaskTier::Hard => 4,
266 crate::router::TaskTier::Vision => 3,
267 },
268 }
269 }
270
271 pub fn guard_turn(&self, messages: &[Msg], tool_outputs_in_turn: bool) -> Option<String> {
273 if self.anti_simulation {
274 AntiSimulationGuard::check(messages, tool_outputs_in_turn)
275 } else {
276 None
277 }
278 }
279}
280
281#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
285pub enum ReasoningEvent {
286 Planning { steps: Vec<String> },
288 SelfCritique { review: String },
290 UncertaintyCheck { message: String },
292 AskUser { question: String },
294 FabricationRejected { reason: String },
296 ClaimRejected { reason: String },
298}