doum_cli/llm/
parser.rs

1use anyhow::{Context, Result};
2use serde::{Deserialize, Serialize};
3
4/// Select Mode Response
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct AutoResponse {
7    pub mode: String,
8    pub reason: String,
9}
10
11/// Ask Mode Response
12pub type AskResponse = String;
13
14/// Command Suggestion
15#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
16pub struct CommandSuggestion {
17    pub cmd: String,
18    pub description: String,
19}
20
21/// Suggest Mode Response
22#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct SuggestResponse {
24    pub suggestions: Vec<CommandSuggestion>,
25}
26
27/// parse Auto Mode response
28pub fn parse_auto_mode(json_str: &str) -> Result<AutoResponse> {
29    let cleaned = extract_json(json_str);
30
31    serde_json::from_str(&cleaned).context("Failed to parse Auto Mode response")
32}
33
34/// parse Suggest response
35pub fn parse_suggest(json_str: &str) -> Result<SuggestResponse> {
36    let cleaned = extract_json(json_str);
37
38    serde_json::from_str(&cleaned).context("Failed to parse Suggest response")
39}
40
41/// Extract JSON content from text (handles code blocks and surrounding text)
42fn extract_json(text: &str) -> String {
43    let text = text.trim();
44
45    // ```json ... ``` or ``` ... ```
46    if let Some(start) = text.find("```")
47        && let Some(end) = text[start + 3..].find("```")
48    {
49        let json_block = &text[start + 3..start + 3 + end];
50        let json_content = if let Some(newline) = json_block.find('\n') {
51            &json_block[newline + 1..]
52        } else {
53            json_block
54        };
55        return json_content.trim().to_string();
56    }
57
58    // Find first { ... } block
59    if let Some(start) = text.find('{')
60        && let Some(end) = text.rfind('}')
61        && end > start
62    {
63        return text[start..=end].to_string();
64    }
65
66    // Return original text if no JSON found
67    text.to_string()
68}