Skip to content

feat(browser): tabs, reload and a typed address in the browser panel - #62

Merged
httpsphl merged 5 commits into
mainfrom
feat/browser-tabs
Sep 30, 2026
Merged

httpsphl merged 5 commits into
mainfrom
feat/browser-tabs

Conversation

@httpsphl

Copy link
Copy Markdown
Owner

Stacked on #53 (the page filling the panel): until that one merges, this diff shows its three commits too. The two commits of this PR are the last two.

What

The panel only said "6 tabs". Now the owner sees the tabs the bot opened, reloads the page, and with the browser in their hands switches tabs, opens a new one and types where it goes.

  • Tabs in the state. BrowserState.tabs is the list of open tabs in the order they opened (BrowserTab {id, title, url, active}), not a count. Edge without a window tells a tab's new address but never its title, so the daemon reads document.title in the isolated world when a page loads.
  • browser.reload, from the connection watching the browser.
  • browser.newTab, browser.switchTab, browser.open, only from the connection that has the browser in the owner's hands. They go in the same queue as the owner's mouse and keyboard, in order.
  • Panel. A tab strip over the address row (title, site under it, the active one marked, + at the end), a reload button (RotateCw) in the address row, and the address becomes a field while the owner is in control: Enter goes there, Esc drops what was typed. + opens a blank tab with the cursor already in the address. Texts in en, pt-BR and es.
  • Spec 21.3, 21.7, 21.8, 21.10, 21.11 (N3.2) and section 19.

Decisions (spec 21.10)

  • Reload works at any time, without taking control. It does not change where the bot is, and a stuck page should not cost the owner stopping the bot. The bot's next result says "The owner reloaded the page."; an old ref gives the usual error and it reads again.
  • Switching tabs, a new tab and an address need control. They change where the bot works, and the bot has no tool to switch tabs back. Without control the tabs only show, and the hint says to take control.
  • The bot goes on in the tab the owner leaves open (what the owner sees when giving it back is what the bot gets), and the bar that says "You are in control" tells so when there is more than one tab.
  • What the bot sees when the active tab changed in the owner's hands: it never acts on a tab it has not read. The next tool that acts (browser_click, browser_type, browser_select, browser_press, browser_scroll, browser_back) does nothing and answers that the owner switched tabs and to call browser_look. browser_look, browser_screenshot, browser_open and the answer to browser_ask_owner work and carry "The owner switched tabs while they had your browser. This is the tab that is open now.", once. Given back on the same tab, nothing is said.
  • The address opens only http and https; without a scheme, https://. Sites the owner opens still do not count as allowed for the bot (as before).
  • No protocol version bump, as when control and ask came: app and daemon ship together and the app updates an older daemon before connecting. tabs does change type, so an app and a daemon from different builds of the same version do not match.

Found on the way

  • A browser counted as open as soon as its first tab was listed, before the tab was set up. Under load a fast page could load before Page.enable, and the daemon missed its events. Now the tab has to be set up first (also a new tab of the owner's before it gets an address).
  • When the active tab closes, the daemon now activates the tab it goes back to, so Edge shows the same one.
  • The bot's tools now also wait for what the owner did last to reach the browser, not only for the owner to give it back.

Tests

  • crates/botloftd/tests/browser_tabs.rs, with the real Edge: reload with and without watching and what the bot reads; the tab list and titles; a new tab, addresses that open and that are refused, switching and the frames that follow; and the bot after the owner gave the browser back on the same tab, on another tab (a tool that acts, a tool that reads) and through browser_ask_owner.
  • Unit tests for the addresses the owner may type and for the points of the owner's events.
  • tabs.test.tsx with FakeBotloft: the tabs by title and site, inert without control, reload at any time, and with control switching, a new tab with the cursor in the address, Enter, Esc and an address that is refused.
  • cargo fmt, clippy -D warnings, cargo test --workspace and pnpm check pass. The browser tests ran 10 times in a row with the whole daemon suite.
  • Seen in the dev preview (pnpm dev): Scout has three tabs; taking control, switching, +, typing an address and giving it back.

Still to see with real Claude Code

Spec 19 has the row "Abas nas mãos do dono com o Claude Code real", marked manual:

  1. With a bot in the middle of a task on a site, open its browser panel, take control, open a new tab on another address and give the browser back. The bot should read that the tab changed (in the error of the tool that was about to act, or in browser_look), read the new tab, and either go on there or open the page it needs again, without acting blindly.
  2. Reload without taking control while the bot works: the bot reads "The owner reloaded the page." and goes on.

The page was always 1280 x 800, so a tall panel showed it small with an
empty area below. While an app connection watches, `browser.resize` tells
the daemon the room its panel has for the page: the page keeps its 1280 of
width, so sites keep their desktop layout, and takes the height that gives
it the room's shape, between 600 and 2000. Frames, the owner's points and
the bot's scroll follow the size the page has. When the last one watching
stops, the page is 1280 x 800 again.

Spec 21.3, 21.7, 21.8 and 21.10 say so, and section 19 records what the
real Edge does when the size changes with a page open.
The panel measures the room it has under the address row and asks for a
page of that shape, 300 ms after the room stops changing. The picture is
shown as large as fits, in the page's shape. Notices that come and go
(the request for a hand, the bar that says the owner is in control, the
line about what the bot did) do not count: they never resize the page.

The preview's pages are drawn at the size the panel asks for.
Edge drops the frame of the new size while older frames wait to be
confirmed, and a page that stands still sends no other: the panel kept the
picture of the old size. After sizing the tabs the daemon waits for those
frames to be confirmed and starts the screencast over, which sends one.
The test with the real Edge now waits for a frame after each change; it
failed about half the runs before.
…en tabs

`BrowserState.tabs` is now the list of open tabs, in the order they
opened, each with its title, address and whether it is the active one,
instead of a count. Edge without a window never tells a page's title, so
the daemon reads `document.title` in the isolated world when a page loads.

New methods for the connection watching a bot's browser:

- `browser.reload`, at any time: it does not move the bot, and the bot's
  next result says the owner reloaded the page.
- `browser.newTab`, `browser.switchTab` and `browser.open`, only with the
  browser in the owner's hands: they change where the bot works. They go
  in the same queue as the owner's mouse and keyboard, in order, and the
  bot's tools wait until the queue is empty. The address the owner types
  opens only as http or https.

When the owner gives the browser back on another tab than the one the bot
was on, the bot reads before it acts: a tool that would click, type,
press, scroll or go back does nothing and says so; `browser_look`,
`browser_screenshot`, `browser_open` and the answer to
`browser_ask_owner` carry a note with the page.

A browser counts as open, and a new tab gets its address, only once the
tab is set up: before that a fast page could load without the daemon
seeing its events. When the active tab closes, the daemon activates the
one it goes back to, so the browser shows the same tab.

Spec 21.3, 21.7, 21.8, 21.10 and 21.11 (N3.2); section 19 records what
Edge 154 does and what is left to see with real Claude Code.
The panel shows a tab for each page the bot has open, with its title and
site, in place of the count. They only show while the browser is the
bot's; with it in the owner's hands a click switches tabs and + opens a
new one, with the cursor in the address row, where Enter takes the tab to
what the owner typed. The bar that says the owner is in control tells
that the bot goes on in the tab left open.

The address row has a reload button, which works at any time.

FakeBotloft has the tabs and the four new methods, and the preview's
Scout has three tabs and waits while the owner has its browser.
@httpsphl
httpsphl merged commit b5001b9 into main Sep 30, 2026
3 checks passed
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