Skip to main content

steer_tui/tui/handlers/
approval.rs

1use crate::error::Error;
2use crate::error::Result;
3use crate::tui::Tui;
4use ratatui::crossterm::event::{KeyCode, KeyEvent};
5use steer_grpc::client_api::ApprovalDecision;
6use steer_tools::tools::BASH_TOOL_NAME;
7use steer_tools::tools::bash::BashParams;
8use tracing::debug;
9
10impl Tui {
11    pub async fn handle_approval_mode(&mut self, key: KeyEvent) -> Result<bool> {
12        if let Some((request_id, tool_call)) = self.current_tool_approval.take() {
13            match key.code {
14                KeyCode::Char('y' | 'Y') => {
15                    self.client
16                        .approve_tool(request_id.to_string(), ApprovalDecision::Once)
17                        .await?;
18                    self.input_mode = self.default_input_mode();
19                }
20                KeyCode::Char('a' | 'A') => {
21                    debug!(target: "handle_approval_mode", "Approving tool call with request_id '{:?}' and name '{}'", request_id, tool_call.name);
22                    if tool_call.name == BASH_TOOL_NAME {
23                        debug!(target: "handle_approval_mode", "(Always) Approving bash command with request_id '{:?}'", request_id);
24                        let bash_params: BashParams =
25                            serde_json::from_value(tool_call.parameters.clone()).map_err(|e| {
26                                Error::CommandProcessing(format!(
27                                    "Invalid bash params for approval: {e}"
28                                ))
29                            })?;
30                        self.client
31                            .approve_tool(
32                                request_id.to_string(),
33                                ApprovalDecision::AlwaysBashPattern(bash_params.command.clone()),
34                            )
35                            .await?;
36                    } else {
37                        self.client
38                            .approve_tool(request_id.to_string(), ApprovalDecision::AlwaysTool)
39                            .await?;
40                    }
41                    self.input_mode = self.default_input_mode();
42                }
43                KeyCode::Char('l' | 'L') => {
44                    if tool_call.name == BASH_TOOL_NAME {
45                        self.client
46                            .approve_tool(request_id.to_string(), ApprovalDecision::AlwaysTool)
47                            .await?;
48                        self.input_mode = self.default_input_mode();
49                    } else {
50                        self.current_tool_approval = Some((request_id, tool_call));
51                    }
52                }
53                KeyCode::Char('n' | 'N') | KeyCode::Esc => {
54                    self.client
55                        .approve_tool(request_id.to_string(), ApprovalDecision::Deny)
56                        .await?;
57                    self.input_mode = self.default_input_mode();
58                }
59                _ => {
60                    self.current_tool_approval = Some((request_id, tool_call));
61                }
62            }
63        } else {
64            self.input_mode = self.default_input_mode();
65        }
66        Ok(false)
67    }
68}