Skip to content

feat: show agent side panel in every tab the agent interacts with#461

Open
felarof99 wants to merge 2 commits intomainfrom
feat/show_agent_in_every_tab
Open

feat: show agent side panel in every tab the agent interacts with#461
felarof99 wants to merge 2 commits intomainfrom
feat/show_agent_in_every_tab

Conversation

@felarof99
Copy link
Contributor

Summary

  • When the agent executes a tool that targets a new tab (e.g., new_page), the side panel now automatically opens on that tab
  • The existing useNotifyActiveTab hook tracks which tabs the agent has touched and relays new ones to the background script via chrome.runtime.sendMessage
  • The background script maintains an in-memory map of conversationId → Set<tabId> and calls openSidePanel(tabId) for each new tab

Design

The solution extends the existing useNotifyActiveTab hook with a Set<number> ref that accumulates all tab IDs seen during the current conversation. When a tool's tabId is new, the hook sends an open-sidepanel-on-tab message to the background script, which calls openSidePanel(tabId). Since Chrome's side panel is a single instance per extension, the same conversation renders regardless of which tab the user switches to. Tab tracking is cleaned up on conversation reset and when tabs are closed.

Changed files

  • apps/agent/entrypoints/sidepanel/index/useNotifyActiveTab.tsx — Track seen tabs, send open-sidepanel-on-tab message to background
  • apps/agent/entrypoints/background/index.ts — Handle open-sidepanel-on-tab and clear-agent-tabs messages, maintain tab tracking map with cleanup
  • apps/agent/entrypoints/sidepanel/index/useChatSession.ts — Send clear-agent-tabs on conversation reset

Test plan

  • Open BrowserOS agent side panel on any tab
  • Ask the agent to perform a task that opens new tabs (e.g., "search for BrowserOS news")
  • Verify the side panel appears on each newly opened tab
  • Switch between agent-opened tabs and confirm the side panel shows the same conversation
  • Reset the conversation and verify no side effects on previously opened tabs
  • Open tabs manually while agent is running — verify side panel does NOT open on those

🤖 Generated with Claude Code

felarof99 and others added 2 commits March 10, 2026 15:24
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Mar 10, 2026

Greptile Summary

This PR automatically opens the agent side panel on every tab the agent interacts with during a conversation. It does so by extending useNotifyActiveTab with a Set-based ref that tracks seen tab IDs, sending an open-sidepanel-on-tab message to the background script on first contact, and having the background call openSidePanel(tabId). Cleanup is handled on conversation reset (clear-agent-tabs) and on tab closure (chrome.tabs.onRemoved).

Key changes:

  • useNotifyActiveTab — adds knownTabsRef to deduplicate tab-open requests per conversation; resets on conversationId change.
  • background/index.ts — adds agentTabSets Map, handles the two new message types, and prunes stale entries via onRemoved.
  • useChatSession.ts — dispatches clear-agent-tabs before generating a new conversationId during reset.

Issues found:

  • useNotifyActiveTab is called with conversationId: conversationIdRef.current (a stale-on-first-render ref value) rather than the conversationId state variable. This can delay the knownTabsRef reset effect by one render cycle. The fix is to pass conversationId directly.
  • agentTabSets entries are only cleared by clear-agent-tabs (reset) or onRemoved (tab close). If the side panel is closed/reloaded without an explicit reset, previous-conversation entries accumulate indefinitely until their tabs are closed, which could become a memory issue in long-lived service worker sessions.

Confidence Score: 4/5

  • PR is safe to merge; the two flagged issues are non-critical style/memory concerns with no functional regressions.
  • The core flow (detect new tab → message background → open side panel → cleanup on reset/close) is logically sound and correctly deduplicates at both layers. The conversationIdRef.current prop issue causes at most a one-render delay in resetting knownTabsRef, which has no observable impact because streaming is stopped before reset. The agentTabSets memory concern is real but minor for typical usage patterns.
  • apps/agent/entrypoints/sidepanel/index/useChatSession.ts — consider passing conversationId state instead of conversationIdRef.current to useNotifyActiveTab.

Important Files Changed

Filename Overview
apps/agent/entrypoints/background/index.ts Adds in-memory agentTabSets map, two new message handlers (open-sidepanel-on-tab, clear-agent-tabs), and a chrome.tabs.onRemoved listener. Logic is correct; minor memory-leak risk if the side panel unloads without triggering clear-agent-tabs.
apps/agent/entrypoints/sidepanel/index/useNotifyActiveTab.tsx Adds knownTabsRef Set and an effect to send open-sidepanel-on-tab for unseen tabs. Reset effect is correct in intent but may fire one render late due to stale conversationIdRef.current being passed as a prop from the call-site.
apps/agent/entrypoints/sidepanel/index/useChatSession.ts Adds clear-agent-tabs message dispatch during resetConversation. Correctly uses conversationIdRef.current for the cleanup message, but passes the same ref snapshot to useNotifyActiveTab, which can delay the knownTabsRef reset by one render.

Sequence Diagram

sequenceDiagram
    participant Agent as Agent (streaming)
    participant Hook as useNotifyActiveTab
    participant BG as Background index.ts
    participant Chrome as chrome.sidePanel

    Agent->>Hook: tool result with tabId
    Hook->>Hook: check knownTabsRef
    alt First time seeing tabId
        Hook->>BG: open-sidepanel-on-tab (tabId, conversationId)
        BG->>BG: check agentTabSets
        alt Not tracked yet
            BG->>BG: agentTabSets.add(tabId)
            BG->>Chrome: openSidePanel(tabId)
        end
    end

    Note over Hook,BG: On conversation reset
    Hook->>BG: clear-agent-tabs (conversationId)
    BG->>BG: agentTabSets.delete(conversationId)

    Note over BG,Chrome: On tab close
    Chrome-->>BG: onRemoved(tabId)
    BG->>BG: remove tabId from all sets
Loading

Last reviewed commit: dc3e7de

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant