@agimon-ai/browse-tool 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6214,20 +6214,30 @@ async function listPagesHandler(args, context, tabId) {
6214
6214
  async function newPageHandler(args, context, tabId) {
6215
6215
  try {
6216
6216
  const url = args.url || "about:blank";
6217
- const tab = await globalThis.chrome.tabs.create({ url });
6217
+ const pageIdFromServer = typeof args.pageId === "string" ? args.pageId : void 0;
6218
+ const setAsCurrent = args.setAsCurrent !== false;
6219
+ const tab = await globalThis.chrome.tabs.create({ url, active: setAsCurrent });
6218
6220
  if (!tab.id) {
6219
6221
  return {
6220
6222
  content: [{ type: "text", text: "Failed to create tab" }],
6221
6223
  isError: true
6222
6224
  };
6223
6225
  }
6224
- const pageId = await context.tabRegistry.register(tab.id);
6225
- context.tabRegistry.setActive(pageId);
6226
+ let pageId = pageIdFromServer;
6227
+ if (pageId) {
6228
+ context.tabRegistry.registerPage(pageId, tab.url);
6229
+ context.tabRegistry.mapPageToTab(pageId, tab.id);
6230
+ } else {
6231
+ pageId = await context.tabRegistry.register(tab.id);
6232
+ }
6233
+ if (setAsCurrent) {
6234
+ context.tabRegistry.setActive(pageId);
6235
+ }
6226
6236
  return {
6227
6237
  content: [
6228
6238
  {
6229
6239
  type: "text",
6230
- text: JSON.stringify({ pageId, url: tab.url, title: tab.title })
6240
+ text: JSON.stringify({ pageId, tabId: tab.id, url: tab.url, title: tab.title, isActive: setAsCurrent })
6231
6241
  }
6232
6242
  ]
6233
6243
  };
@@ -6367,7 +6377,14 @@ async function executeToolRequest(request, context) {
6367
6377
  }
6368
6378
  }
6369
6379
  try {
6370
- return await handler(request.arguments, context, tabId);
6380
+ return await handler(
6381
+ {
6382
+ ...request.arguments,
6383
+ ...request.pageId ? { pageId: request.pageId } : {}
6384
+ },
6385
+ context,
6386
+ tabId
6387
+ );
6371
6388
  } catch (error) {
6372
6389
  const message = error instanceof Error ? error.message : "Unknown error";
6373
6390
  return {
@@ -6771,6 +6788,31 @@ class ExtensionHttpClient {
6771
6788
  };
6772
6789
  }
6773
6790
  }
6791
+ async sendTabMapped(request) {
6792
+ try {
6793
+ const response = await fetch(`${this.serverUrl}/extension/tab-mapped`, {
6794
+ method: "POST",
6795
+ headers: {
6796
+ "Content-Type": "application/json"
6797
+ },
6798
+ body: JSON.stringify(request)
6799
+ });
6800
+ if (!response.ok) {
6801
+ const errorData = await response.json().catch(() => ({}));
6802
+ return {
6803
+ success: false,
6804
+ error: errorData.error || `HTTP ${response.status}: ${response.statusText}`
6805
+ };
6806
+ }
6807
+ return { success: true };
6808
+ } catch (error) {
6809
+ this.lastError = error instanceof Error ? error.message : String(error);
6810
+ return {
6811
+ success: false,
6812
+ error: this.lastError
6813
+ };
6814
+ }
6815
+ }
6774
6816
  /**
6775
6817
  * Request handoff to AI control
6776
6818
  */
@@ -7296,6 +7338,7 @@ class WebSocketClient {
7296
7338
  }
7297
7339
 
7298
7340
  class TaskPollerService {
7341
+ static BROWSER_LANE_KEY = "browser";
7299
7342
  client;
7300
7343
  wsClient = null;
7301
7344
  pollInterval = null;
@@ -7313,6 +7356,8 @@ class TaskPollerService {
7313
7356
  handoffRequested = false;
7314
7357
  useWebSocket = false;
7315
7358
  serverUrl;
7359
+ webSocketTaskLanes = /* @__PURE__ */ new Map();
7360
+ activeWebSocketTasks = 0;
7316
7361
  toolContext = {
7317
7362
  tabRegistry
7318
7363
  };
@@ -7348,15 +7393,7 @@ class TaskPollerService {
7348
7393
  this.handleWebSocketTask(task);
7349
7394
  },
7350
7395
  onPageCreated: async (pageId, _browserId, _url) => {
7351
- try {
7352
- const tabs = await globalThis.chrome.tabs.query({ active: true, currentWindow: true });
7353
- const activeTab = tabs[0];
7354
- if (activeTab?.id) {
7355
- tabRegistry.mapPageToTab(pageId, activeTab.id);
7356
- }
7357
- } catch {
7358
- tabRegistry.registerPage(pageId, _url);
7359
- }
7396
+ await this.mapPageToActiveTab(pageId, _url);
7360
7397
  },
7361
7398
  onPageRemoved: (pageId) => {
7362
7399
  tabRegistry.unregisterPage(pageId);
@@ -7387,12 +7424,6 @@ class TaskPollerService {
7387
7424
  }
7388
7425
  }
7389
7426
  handleWebSocketTask(task) {
7390
- if (this.isExecuting) {
7391
- return;
7392
- }
7393
- this.isExecuting = true;
7394
- const prevStatus = this.status;
7395
- this.status = "executing";
7396
7427
  const serverTask = {
7397
7428
  id: task.payload.taskId,
7398
7429
  tool: task.payload.tool,
@@ -7406,15 +7437,40 @@ class TaskPollerService {
7406
7437
  } : {}
7407
7438
  }
7408
7439
  };
7409
- this.executeTaskWithWebSocket(serverTask).then(() => {
7410
- this.taskCount++;
7411
- this.lastTaskAt = /* @__PURE__ */ new Date();
7412
- this.status = prevStatus;
7413
- this.isExecuting = false;
7414
- }).catch(() => {
7415
- this.status = prevStatus;
7416
- this.isExecuting = false;
7440
+ const laneKey = this.getWebSocketExecutionLane(serverTask);
7441
+ const previous = this.webSocketTaskLanes.get(laneKey) ?? Promise.resolve();
7442
+ const next = previous.catch(() => {
7443
+ }).then(async () => {
7444
+ this.activeWebSocketTasks += 1;
7445
+ this.status = "executing";
7446
+ try {
7447
+ await this.executeTaskWithWebSocket(serverTask);
7448
+ this.taskCount++;
7449
+ this.lastTaskAt = /* @__PURE__ */ new Date();
7450
+ } finally {
7451
+ this.activeWebSocketTasks = Math.max(0, this.activeWebSocketTasks - 1);
7452
+ if (this.activeWebSocketTasks === 0 && this.useWebSocket) {
7453
+ this.status = this.wsClient?.isConnected() ? "websocket" : "error";
7454
+ }
7455
+ }
7417
7456
  });
7457
+ const tracked = next.finally(() => {
7458
+ if (this.webSocketTaskLanes.get(laneKey) === tracked) {
7459
+ this.webSocketTaskLanes.delete(laneKey);
7460
+ }
7461
+ });
7462
+ this.webSocketTaskLanes.set(laneKey, tracked);
7463
+ }
7464
+ getWebSocketExecutionLane(task) {
7465
+ const pageId = typeof task.arguments.pageId === "string" ? task.arguments.pageId : void 0;
7466
+ if (!pageId) {
7467
+ return TaskPollerService.BROWSER_LANE_KEY;
7468
+ }
7469
+ const tab = tabRegistry.get(pageId);
7470
+ if (!tab || tab.tabId < 0) {
7471
+ return TaskPollerService.BROWSER_LANE_KEY;
7472
+ }
7473
+ return `tab:${tab.tabId}`;
7418
7474
  }
7419
7475
  async executeTaskWithWebSocket(task) {
7420
7476
  const result = await this.executeTaskCore(task);
@@ -7498,6 +7554,24 @@ class TaskPollerService {
7498
7554
  return void 0;
7499
7555
  }
7500
7556
  }
7557
+ async mapPageToActiveTab(pageId, url) {
7558
+ try {
7559
+ const tabs = await globalThis.chrome.tabs.query({ active: true, currentWindow: true });
7560
+ const activeTab = tabs[0];
7561
+ if (!activeTab?.id) {
7562
+ tabRegistry.registerPage(pageId, url);
7563
+ return;
7564
+ }
7565
+ tabRegistry.mapPageToTab(pageId, activeTab.id);
7566
+ if (this.useWebSocket) {
7567
+ this.wsClient?.notifyTabMapped(pageId, activeTab.id);
7568
+ return;
7569
+ }
7570
+ await this.client.sendTabMapped({ pageId, tabId: activeTab.id });
7571
+ } catch {
7572
+ tabRegistry.registerPage(pageId, url);
7573
+ }
7574
+ }
7501
7575
  stop() {
7502
7576
  if (this.pollInterval) {
7503
7577
  clearInterval(this.pollInterval);
@@ -7516,6 +7590,8 @@ class TaskPollerService {
7516
7590
  this.controlMode = void 0;
7517
7591
  this.handoffRequested = false;
7518
7592
  this.useWebSocket = false;
7593
+ this.webSocketTaskLanes.clear();
7594
+ this.activeWebSocketTasks = 0;
7519
7595
  this.client.disconnect();
7520
7596
  }
7521
7597
  async pollOnce() {