use crate::error::Result;
use crate::tools::{Tool, ToolContext, ToolResult};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct CloseTabParams {}
#[derive(Default)]
pub struct CloseTabTool;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct CloseTabOutput {
pub index: usize,
pub title: String,
pub url: String,
pub message: String,
}
impl Tool for CloseTabTool {
type Params = CloseTabParams;
type Output = CloseTabOutput;
fn name(&self) -> &str {
"close_tab"
}
fn execute_typed(
&self,
_params: CloseTabParams,
context: &mut ToolContext,
) -> Result<ToolResult> {
let active_tab = context.session.tab()?;
let tab_title = active_tab.get_title().unwrap_or_default();
let tab_url = active_tab.get_url();
let tabs = context.session.get_tabs()?;
let current_index = tabs
.iter()
.position(|tab| std::sync::Arc::ptr_eq(tab, &active_tab))
.unwrap_or(0);
context.session.clear_active_tab_hint()?;
active_tab.close(true).map_err(|e| {
crate::error::BrowserError::TabOperationFailed(format!("Failed to close tab: {}", e))
})?;
let message = close_tab_message(current_index, &tab_title, &tab_url);
Ok(ToolResult::success_with(CloseTabOutput {
index: current_index,
message,
title: tab_title,
url: tab_url,
}))
}
}
fn close_tab_message(index: usize, title: &str, url: &str) -> String {
format!("Closed tab [{}]: {} ({})", index, title, url)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_close_tab_message_includes_index_title_and_url() {
assert_eq!(
close_tab_message(3, "Docs", "https://example.com"),
"Closed tab [3]: Docs (https://example.com)"
);
}
}