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(&self, _params: TabListParams, context: &mut ToolContext) -> Result<ToolResult> {
35        // Get all tabs
36        let tabs = context.session.get_tabs()?;
37        let active_tab = context.session.tab();
38
39        // Build tab info list
40        let mut tab_list = Vec::new();
41        for (index, tab) in tabs.iter().enumerate() {
42            // Check if this is the active tab by comparing Arc pointers
43            let is_active = std::sync::Arc::ptr_eq(tab, active_tab);
44
45            // Get tab title (fallback to empty string on error)
46            let title = tab.get_title().unwrap_or_default();
47
48            // Get tab URL (not a Result, returns String directly)
49            let url = tab.get_url();
50
51            tab_list.push(TabInfo {
52                index,
53                active: is_active,
54                title,
55                url,
56            });
57        }
58
59        // Build summary text
60        let active_index = tab_list.iter().position(|t| t.active).unwrap_or(0);
61        let active_info = &tab_list[active_index];
62        
63        let summary = if !tab_list.is_empty() {
64            let all_tabs_str = tab_list
65                .iter()
66                .map(|tab| format!("[{}] Title: {} (URL: {})", tab.index, tab.title, tab.url))
67                .collect::<Vec<_>>()
68                .join("\n");
69            
70            format!(
71                "Current Tab: [{}] {}\nAll Tabs:\n{}",
72                active_index, active_info.title, all_tabs_str
73            )
74        } else {
75            "No tabs available".to_string()
76        };
77
78        Ok(ToolResult::success_with(serde_json::json!({
79            "tab_list": tab_list,
80            "count": tab_list.len(),
81            "summary": summary
82        })))
83    }
84}