diff options
Diffstat (limited to 'crates/atuin-ai/src/fsm/tools.rs')
| -rw-r--r-- | crates/atuin-ai/src/fsm/tools.rs | 178 |
1 files changed, 0 insertions, 178 deletions
diff --git a/crates/atuin-ai/src/fsm/tools.rs b/crates/atuin-ai/src/fsm/tools.rs deleted file mode 100644 index 96348672..00000000 --- a/crates/atuin-ai/src/fsm/tools.rs +++ /dev/null @@ -1,178 +0,0 @@ -//! Tool lifecycle management within the FSM. -//! -//! Each tool call goes through an independent lifecycle. The ToolManager -//! tracks all tools in the current turn and provides the "all resolved" -//! check that gates turn completion. - -use crate::diff::{EditPreview, WritePreview}; -use crate::tools::ClientToolCall; - -/// Why a tool execution was interrupted. -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum InterruptReason { - /// User pressed Ctrl+C or Esc during execution. - User, - /// The LLM-specified execution timeout expired. - Timeout(u64), -} - -/// Per-tool lifecycle state. -#[derive(Debug, Clone, PartialEq, Eq)] -pub(crate) enum ToolState { - /// Permission resolver is running asynchronously. - CheckingPermission, - /// Waiting for user to grant/deny via the permission dialog. - AwaitingPermission, - /// Actively executing. - Executing, - /// Execution completed (result injected into conversation). - Completed, - /// User denied permission (error result injected into conversation). - Denied, -} - -/// Cached preview data for rendering tool output. -#[derive(Debug, Clone)] -pub(crate) enum ToolPreviewData { - /// Shell command VT100 output lines. - Shell { - lines: Vec<String>, - exit_code: Option<i32>, - interrupted: Option<InterruptReason>, - }, - /// File edit diff preview. - Edit(EditPreview), - /// File write content preview. - Write(WritePreview), -} - -/// A tracked tool call with its current lifecycle state. -#[derive(Debug, Clone)] -pub(crate) struct TrackedTool { - pub id: String, - pub tool: ClientToolCall, - pub state: ToolState, - /// Cached preview data for rendering (populated during/after execution). - pub preview: Option<ToolPreviewData>, - /// Set by the FSM when it emits AbortTool, so that ToolExecutionDone - /// can distinguish user interrupts from timeouts. - pub interrupt_reason: Option<InterruptReason>, -} - -impl TrackedTool { - /// Whether this tool has reached a terminal state. - pub fn is_resolved(&self) -> bool { - matches!(self.state, ToolState::Completed | ToolState::Denied) - } - - /// Extract shell preview data (for TurnBuilder compatibility). - pub fn shell_preview(&self) -> Option<crate::tools::ToolPreview> { - match &self.preview { - Some(ToolPreviewData::Shell { - lines, - exit_code, - interrupted, - }) => Some(crate::tools::ToolPreview { - lines: lines.clone(), - exit_code: *exit_code, - interrupted: interrupted.clone(), - }), - _ => None, - } - } - - /// Extract edit diff preview (for TurnBuilder compatibility). - pub fn edit_preview(&self) -> Option<&EditPreview> { - match &self.preview { - Some(ToolPreviewData::Edit(p)) => Some(p), - _ => None, - } - } - - /// Extract write content preview (for TurnBuilder compatibility). - pub fn write_preview(&self) -> Option<&WritePreview> { - match &self.preview { - Some(ToolPreviewData::Write(p)) => Some(p), - _ => None, - } - } -} - -/// Manages tool call lifecycles for a single turn. -/// -/// Tools are inserted when received from the stream and progress through -/// their lifecycle independently. The manager provides aggregate queries -/// (all resolved, any awaiting permission, etc.) that the FSM uses for -/// state transitions. -#[derive(Debug, Clone, Default)] -pub(crate) struct ToolManager { - tools: Vec<TrackedTool>, -} - -impl ToolManager { - pub fn new() -> Self { - Self { tools: Vec::new() } - } - - /// Insert a new tool in CheckingPermission state. - pub fn insert(&mut self, id: String, tool: ClientToolCall) { - self.tools.push(TrackedTool { - id, - tool, - state: ToolState::CheckingPermission, - preview: None, - interrupt_reason: None, - }); - } - - /// Look up a tool by ID. - pub fn get(&self, id: &str) -> Option<&TrackedTool> { - self.tools.iter().find(|t| t.id == id) - } - - /// Look up a tool mutably by ID. - pub fn get_mut(&mut self, id: &str) -> Option<&mut TrackedTool> { - self.tools.iter_mut().find(|t| t.id == id) - } - - /// True if all tools from the given set of IDs have reached a terminal state. - /// Returns true for an empty set (vacuously — no tools to wait for). - pub fn all_resolved(&self, tool_ids: &[String]) -> bool { - tool_ids - .iter() - .all(|id| self.get(id).is_some_and(|t| t.is_resolved())) - } - - /// Find the first tool awaiting user permission. - pub fn awaiting_permission(&self) -> Option<&TrackedTool> { - self.tools - .iter() - .find(|t| t.state == ToolState::AwaitingPermission) - } - - /// Get IDs of all non-resolved tools (for cancel). - pub fn pending_ids(&self) -> Vec<String> { - self.tools - .iter() - .filter(|t| !t.is_resolved()) - .map(|t| t.id.clone()) - .collect() - } - - /// Get IDs of all currently executing tools (for interrupt/abort). - pub fn executing_ids(&self) -> Vec<String> { - self.tools - .iter() - .filter(|t| t.state == ToolState::Executing) - .map(|t| t.id.clone()) - .collect() - } - - /// True if any tool has a shell preview with live output. - pub fn has_executing_preview(&self) -> bool { - self.tools.iter().any(|t| { - t.state == ToolState::Executing - && matches!(t.preview, Some(ToolPreviewData::Shell { .. })) - }) - } -} |
