| 1 | //! Adaptive reasoning-effort tier selection for `Auto` mode (#663). |
| 2 | //! |
| 3 | //! When the user sets `reasoning_effort = "auto"`, the engine calls |
| 4 | //! [`select`] before each turn-level request to pick the actual tier |
| 5 | //! based on the current message. |
| 6 | |
| 7 | use crate::tui::app::ReasoningEffort; |
| 8 | |
| 9 | /// Choose a concrete `ReasoningEffort` tier for the next API request. |
| 10 | /// |
| 11 | /// Rules: |
| 12 | /// - Sub-agent contexts (`is_subagent == true`) → `Low` |
| 13 | /// - Last user message contains `"debug"` or `"error"` → `Max` |
| 14 | /// - Last user message contains `"search"` or `"lookup"` → `Low` |
| 15 | /// - Everything else → `High` |
| 16 | #[must_use] |
| 17 | pub fn select(is_subagent: bool, last_msg: &str) -> ReasoningEffort { |
| 18 | if is_subagent { |
| 19 | return ReasoningEffort::Low; |
| 20 | } |
| 21 | |
| 22 | let lower = last_msg.to_ascii_lowercase(); |
| 23 | |
| 24 | if lower.contains("debug") || lower.contains("error") { |
| 25 | return ReasoningEffort::Max; |
| 26 | } |
| 27 | |
| 28 | if lower.contains("search") || lower.contains("lookup") { |
| 29 | return ReasoningEffort::Low; |
| 30 | } |
| 31 | |
| 32 | ReasoningEffort::High |
| 33 | } |
| 34 | |
| 35 | #[cfg(test)] |
| 36 | mod tests { |
| 37 | use super::*; |
| 38 | |
| 39 | #[test] |
| 40 | fn subagent_returns_low() { |
| 41 | assert_eq!(select(true, "anything"), ReasoningEffort::Low); |
| 42 | assert_eq!(select(true, "debug this"), ReasoningEffort::Low); |
| 43 | assert_eq!(select(true, "search query"), ReasoningEffort::Low); |
| 44 | } |
| 45 | |
| 46 | #[test] |
| 47 | fn debug_or_error_returns_max() { |
| 48 | assert_eq!(select(false, "find a bug"), ReasoningEffort::High); |
| 49 | assert_eq!(select(false, "debug crash"), ReasoningEffort::Max); |
| 50 | assert_eq!(select(false, "Error: timeout"), ReasoningEffort::Max); |
| 51 | assert_eq!(select(false, "fix this error"), ReasoningEffort::Max); |
| 52 | assert_eq!(select(false, "DEBUG output"), ReasoningEffort::Max); |
| 53 | } |
| 54 | |
| 55 | #[test] |
| 56 | fn search_or_lookup_returns_low() { |
| 57 | assert_eq!(select(false, "search for the file"), ReasoningEffort::Low); |
| 58 | assert_eq!(select(false, "lookup docs"), ReasoningEffort::Low); |
| 59 | assert_eq!(select(false, "SearchQuery"), ReasoningEffort::Low); |
| 60 | assert_eq!(select(false, "lookup_user"), ReasoningEffort::Low); |
| 61 | } |
| 62 | |
| 63 | #[test] |
| 64 | fn default_returns_high() { |
| 65 | assert_eq!(select(false, "hello"), ReasoningEffort::High); |
| 66 | assert_eq!(select(false, "write a test"), ReasoningEffort::High); |
| 67 | assert_eq!(select(false, "refactor this module"), ReasoningEffort::High); |
| 68 | assert_eq!(select(false, ""), ReasoningEffort::High); |
| 69 | } |
| 70 | } |
| 71 |