Skip to content

fix(open_url): reuse active tab when target shares origin - #721

Merged
sonichi merged 1 commit into
mainfrom
fix/open-url-reuse-same-origin-tab
May 15, 2026
Merged

sonichi merged 1 commit into
mainfrom
fix/open-url-reuse-same-origin-tab

Conversation

@sonichi

@sonichi sonichi commented May 15, 2026

Copy link
Copy Markdown
Owner

Summary

Companion to PR #719 (merged as 429de3d). #719 fixed the core-agent / CLAUDE.md path so mcp__claude-in-chrome__navigate reuses same-origin tabs. This PR fixes the voice-agent path: open_url (the inline tool Gemini Live calls for "open X" / "go to that link") previously always spawned a new Chrome tab.

Change

src/browser-tools.ts:openUrlTool:

  • Queries active tab URL via osascript before opening.
  • Parses both URLs to origins (scheme + host + port, matching PR docs(claude-md): default browser automation to reuse the active tab #719's terminology).
  • Reuses active tab if origins match; spawns new tab if cross-origin.
  • Any failure falls back to new-tab behavior — callers never silently lose the open.
  • Tool description updated so Gemini's prompt sees the new behavior.

Why now

Same root cause as the CLAUDE.md fix (PR #719) but on a different surface. Together they cover both navigation paths into Chrome:

Path Tool Fix
Core agent (Claude Code) mcp__claude-in-chrome__navigate PR #719 (CLAUDE.md guidance)
Voice agent (Gemini Live) open_url inline tool This PR (in-tool behavior change)

Per Chi: "for voice what's the solution" (2026-05-15 09:31 PT).

Test plan

  • Voice says "open github.com" → new tab.
  • With github.com active, voice says "open github.com/sonichi/sutando" → same tab reused, tab count unchanged.
  • Voice says "open example.com" with github active → new tab (cross-origin).
  • CI: tsc + tests (clean install) — should pass; only browser-tools.ts changed.

🤖 Generated with Claude Code

`open_url` previously always spawned a new Chrome tab — the voice agent
calling it during a research flow leaves dozens of half-used tabs the
same way `mcp__claude-in-chrome__navigate` did (which PR #719 just
addressed for the core-agent CLAUDE.md path).

This patches the voice-side surface: `open_url` now queries the active
tab's URL, parses both origins (scheme + host + port), and reuses the
active tab when they match. Cross-origin and unparseable URLs fall back
to new-tab. Any osascript failure falls back to new-tab too — callers
never silently lose the open.

Tool description updated to describe the new behavior so Gemini's
prompt sees it.

Companion to PR #719 (which fixed the core-agent / CLAUDE.md path).
Together they cover both navigation surfaces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

@sonichi sonichi left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (cannot --approve own PR).

Logic trace (src/browser-tools.ts:openUrlTool):

  • Target URL parsed via new URL(url).origin with try/catch → falls through to new-tab on bad input (about:blank, chrome:// schemes) ✓
  • Active tab URL queried with 3s timeout; if same-origin, AppleScript set URL of active tab reuses it ✓
  • Any failure on either osascript call falls through to new-tab — caller never silently loses the open ✓
  • Logging + return-status distinguish reused vs opened paths ✓

Security: safeUrl escaping unchanged — still backslash → quote → double-quote sequence for the shell-+-AppleScript double envelope. The new osascript read takes no user input. No new injection vector.

Tool description: description grew from 65 → ~280 chars. That's longer than peers but justified — Gemini's tool-selection reads this; baking the new behavior into the description avoids needing a separate Gemini system-prompt update. Good call.

Edge cases verified by inspection:

  • about:blank / chrome://settings/ → unparseable origin → new-tab fall-through ✓
  • No front window → read errors → new-tab fall-through ✓
  • Origin mismatch (cross-origin nav) → new-tab ✓

CI green, mergeable. Companion to merged PR #719 — both navigation paths into Chrome now respect same-origin tab reuse. Safe to land.

@sonichi
sonichi merged commit 8bb283c into main May 15, 2026
1 check passed
@sonichi
sonichi deleted the fix/open-url-reuse-same-origin-tab branch May 15, 2026 16:45
liususan091219 pushed a commit to liususan091219/sutando-fork that referenced this pull request May 28, 2026
`open_url` previously always spawned a new Chrome tab — the voice agent
calling it during a research flow leaves dozens of half-used tabs the
same way `mcp__claude-in-chrome__navigate` did (which PR sonichi#719 just
addressed for the core-agent CLAUDE.md path).

This patches the voice-side surface: `open_url` now queries the active
tab's URL, parses both origins (scheme + host + port), and reuses the
active tab when they match. Cross-origin and unparseable URLs fall back
to new-tab. Any osascript failure falls back to new-tab too — callers
never silently lose the open.

Tool description updated to describe the new behavior so Gemini's
prompt sees it.

Companion to PR sonichi#719 (which fixed the core-agent / CLAUDE.md path).
Together they cover both navigation surfaces.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant