Consistent Tab IDs & Global Tag Targeting (#892)
Introduces stable per-tab IDs and a global `--tab <id>` flag for scoping individual commands to a specific tab.
Breaking change: response payloads for `tab_list`, `tab_new`, `tab_switch`, `tab_close`, and `window_new` now use `tabId` instead of `index`. `tab_close` returns `{tabId, closed: true}` instead of `{closed, activeIndex}`. `agent-browser tab <unknown>` now errors instead of silently listing tabs.
Follow-up PR to land immediately after this fixes a compile error on the provider direct-page path, clears per-tab daemon state around scoped switches, and implements active-tab restoration so `--tab N` is non-intrusive as intended.
This commit is contained in:
+27
-10
@@ -662,7 +662,9 @@ impl DaemonState {
|
||||
.await;
|
||||
}
|
||||
|
||||
let tab_id = mgr.assign_tab_id();
|
||||
mgr.add_page(super::browser::PageInfo {
|
||||
tab_id,
|
||||
target_id: te.target_info.target_id.clone(),
|
||||
session_id: attach.session_id,
|
||||
url: te.target_info.url.clone(),
|
||||
@@ -1273,6 +1275,20 @@ pub async fn execute_command(cmd: &Value, state: &mut DaemonState) -> Value {
|
||||
);
|
||||
}
|
||||
|
||||
// Pre-dispatch: if tabId is set on a non-tab command, switch to that tab first
|
||||
if !matches!(
|
||||
action,
|
||||
"tab_list" | "tab_new" | "tab_switch" | "tab_close" | "launch" | "close"
|
||||
) {
|
||||
if let Some(tab_id) = cmd.get("tabId").and_then(|v| v.as_u64()) {
|
||||
if let Some(ref mut mgr) = state.browser {
|
||||
if let Err(e) = mgr.tab_switch_by_id(tab_id as u32).await {
|
||||
return error_response(&id, &e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let result = match action {
|
||||
"launch" => handle_launch(cmd, state).await,
|
||||
"navigate" => handle_navigate(cmd, state).await,
|
||||
@@ -3647,14 +3663,14 @@ async fn handle_tab_new(cmd: &Value, state: &mut DaemonState) -> Result<Value, S
|
||||
|
||||
async fn handle_tab_switch(cmd: &Value, state: &mut DaemonState) -> Result<Value, String> {
|
||||
let mgr = state.browser.as_mut().ok_or("Browser not launched")?;
|
||||
let index = cmd
|
||||
.get("index")
|
||||
let tab_id = cmd
|
||||
.get("tabId")
|
||||
.and_then(|v| v.as_u64())
|
||||
.ok_or("Missing 'index' parameter")? as usize;
|
||||
.ok_or("Missing 'tabId' parameter")? as u32;
|
||||
state.ref_map.clear();
|
||||
state.iframe_sessions.clear();
|
||||
state.active_frame_id = None;
|
||||
let result = mgr.tab_switch(index).await?;
|
||||
let result = mgr.tab_switch_by_id(tab_id).await?;
|
||||
|
||||
if let Some(ref server) = state.stream_server {
|
||||
if let Ok(dims) = mgr
|
||||
@@ -3679,14 +3695,11 @@ async fn handle_tab_switch(cmd: &Value, state: &mut DaemonState) -> Result<Value
|
||||
|
||||
async fn handle_tab_close(cmd: &Value, state: &mut DaemonState) -> Result<Value, String> {
|
||||
let mgr = state.browser.as_mut().ok_or("Browser not launched")?;
|
||||
let index = cmd
|
||||
.get("index")
|
||||
.and_then(|v| v.as_u64())
|
||||
.map(|i| i as usize);
|
||||
let tab_id = cmd.get("tabId").and_then(|v| v.as_u64()).map(|i| i as u32);
|
||||
state.ref_map.clear();
|
||||
state.iframe_sessions.clear();
|
||||
state.active_frame_id = None;
|
||||
mgr.tab_close(index).await
|
||||
mgr.tab_close_by_id(tab_id).await
|
||||
}
|
||||
|
||||
async fn handle_viewport(cmd: &Value, state: &mut DaemonState) -> Result<Value, String> {
|
||||
@@ -4065,7 +4078,9 @@ async fn handle_recording_start(cmd: &Value, state: &mut DaemonState) -> Result<
|
||||
}
|
||||
|
||||
// Add page and switch to it
|
||||
let tab_id = mgr.assign_tab_id();
|
||||
mgr.add_page(super::browser::PageInfo {
|
||||
tab_id,
|
||||
target_id: create_result.target_id,
|
||||
session_id: new_session_id.clone(),
|
||||
url: nav_url.clone(),
|
||||
@@ -5976,7 +5991,9 @@ async fn handle_window_new(cmd: &Value, state: &mut DaemonState) -> Result<Value
|
||||
)
|
||||
.await?;
|
||||
|
||||
let tab_id = mgr.assign_tab_id();
|
||||
mgr.add_page(super::browser::PageInfo {
|
||||
tab_id,
|
||||
target_id: create_result.target_id,
|
||||
session_id: attach.session_id,
|
||||
url: "about:blank".to_string(),
|
||||
@@ -6004,7 +6021,7 @@ async fn handle_window_new(cmd: &Value, state: &mut DaemonState) -> Result<Value
|
||||
let total = mgr.page_count();
|
||||
state.ref_map.clear();
|
||||
|
||||
Ok(json!({ "index": total - 1, "total": total }))
|
||||
Ok(json!({ "tabId": tab_id, "total": total }))
|
||||
}
|
||||
|
||||
async fn handle_diff_screenshot(cmd: &Value, state: &DaemonState) -> Result<Value, String> {
|
||||
|
||||
Reference in New Issue
Block a user