aboutsummaryrefslogtreecommitdiffstats
path: root/crates/atuin-ai/src/fsm/tools.rs
diff options
context:
space:
mode:
authorMichelle Tilley <michelle@michelletilley.net>2026-04-21 15:30:46 -0700
committerGitHub <noreply@github.com>2026-04-21 15:30:46 -0700
commit8dec33f5f9a972a38978b5600fde5bc292fb6401 (patch)
tree19708731284c8ba810a5acede4720d3396f9e5a2 /crates/atuin-ai/src/fsm/tools.rs
parentfix: shell tool preview stuck as Running after completion (#3436) (diff)
downloadatuin-8dec33f5f9a972a38978b5600fde5bc292fb6401.zip
feat: shell tool execution timeouts (#3437)
Diffstat (limited to 'crates/atuin-ai/src/fsm/tools.rs')
-rw-r--r--crates/atuin-ai/src/fsm/tools.rs17
1 files changed, 15 insertions, 2 deletions
diff --git a/crates/atuin-ai/src/fsm/tools.rs b/crates/atuin-ai/src/fsm/tools.rs
index a6b2e9ae..96348672 100644
--- a/crates/atuin-ai/src/fsm/tools.rs
+++ b/crates/atuin-ai/src/fsm/tools.rs
@@ -7,6 +7,15 @@
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 {
@@ -29,7 +38,7 @@ pub(crate) enum ToolPreviewData {
Shell {
lines: Vec<String>,
exit_code: Option<i32>,
- interrupted: bool,
+ interrupted: Option<InterruptReason>,
},
/// File edit diff preview.
Edit(EditPreview),
@@ -45,6 +54,9 @@ pub(crate) struct TrackedTool {
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 {
@@ -63,7 +75,7 @@ impl TrackedTool {
}) => Some(crate::tools::ToolPreview {
lines: lines.clone(),
exit_code: *exit_code,
- interrupted: *interrupted,
+ interrupted: interrupted.clone(),
}),
_ => None,
}
@@ -109,6 +121,7 @@ impl ToolManager {
tool,
state: ToolState::CheckingPermission,
preview: None,
+ interrupt_reason: None,
});
}