browser_use/tools/
tab_list.rs

1use crate::error::Result;
2use crate::tools::{Tool, ToolContext, ToolResult};
3use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6/// Information about a browser tab
7#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
8pub struct TabInfo {
9    /// Tab index
10    pub index: usize,
11    /// Whether this is the active tab
12    pub active: bool,
13    /// Tab title
14    pub title: String,
15    /// Tab URL
16    pub url: String,
17}
18
19/// Parameters for the tab_list tool (no parameters needed)
20#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
21pub struct TabListParams {}
22
23/// Tool for listing all browser tabs
24#[derive(Default)]
25pub struct TabListTool;
26
27impl Tool for TabListTool {
28    type Params = TabListParams;
29
30    fn name(&self) -> &str {
31        "tab_list"
32    }
33
34    fn execute_typed(
35        &self,
36        _params: TabListParams,
37        context: &mut ToolContext,
38    ) -> Result<ToolResult> {
39        // Get all tabs
40        let tabs = context.session.get_tabs()?;
41        let active_tab = context.session.tab()?;
42
43        // Build tab info list
44        let mut tab_list = Vec::new();
45        for (index, tab) in tabs.iter().enumerate() {
46            // Check if this is the active tab by comparing Arc pointers
47            let is_active = std::sync::Arc::ptr_eq(tab, &active_tab);
48
49            // Get tab title (fallback to empty string on error)
50            let title = tab.get_title().unwrap_or_default();
51
52            // Get tab URL (not a Result, returns String directly)
53            let url = tab.get_url();
54
55            tab_list.push(TabInfo {
56                index,
57                active: is_active,
58                title,
59                url,
60            });
61        }
62
63        // Build summary text
64        let active_index = tab_list.iter().position(|t| t.active).unwrap_or(0);
65        let active_info = &tab_list[active_index];
66
67        let summary = if !tab_list.is_empty() {
68            let all_tabs_str = tab_list
69                .iter()
70                .map(|tab| format!("[{}] Title: {} (URL: {})", tab.index, tab.title, tab.url))
71                .collect::<Vec<_>>()
72                .join("\n");
73
74            format!(
75                "Current Tab: [{}] {}\nAll Tabs:\n{}",
76                active_index, active_info.title, all_tabs_str
77            )
78        } else {
79            "No tabs available".to_string()
80        };
81
82        Ok(ToolResult::success_with(serde_json::json!({
83            "tab_list": tab_list,
84            "count": tab_list.len(),
85            "summary": summary
86        })))
87    }
88}