char-slop/berry

multipurpose self-modifiable agentic harness

git clone https://git.t4t.associates/char-slop/berry

Charlotte Somallow project reorderingb4fc6cf

main
13 files

files

README.md4.7 KiB
browser.ts19.6 KiB
mod.test.ts1.0 KiB
mod.ts8.0 KiB
page.ts5.5 KiB
runner.ts4.5 KiB
transport.test.ts1.2 KiB
transport.ts5.6 KiB
types.ts1.7 KiB
view.test.ts2.8 KiB
view.ts7.3 KiB
web.css668 B
web.tsx356 B

browser

An interactive headless Firefox session for each conversation, separate from web search/fetch and from your personal browser profile. Firefox runs in the conversation's target environment, so localhost refers to that machine, not the berry host. Requires deno, firefox, and a POSIX shell on the target's PATH; Windows targets are not supported. A session-scoped Deno process owns Firefox and its native WebSocket connection; berry exchanges commands and observations with it over stdio. No browser download or server restart is needed.

Enable browser in a conversation's extension picker. Its browser view shows tabs, page text, interactive elements, console/network diagnostics, recent actions, and the latest explicitly captured screenshot. Refreshing the view only reads existing observations; it does not launch a browser or refresh the page.

Tools

browser takes one action and returns { snapshot, tabs }. Open a page, then use the tab and element references it actually returned:

const { snapshot } = await tools.browser({ action: "open", url: "http://localhost:3000" });
text(snapshot);

After identifying a field in that snapshot:

const field = snapshot.elements.find((element) => element.name === "Email");
const result = await tools.browser({
  action: "fill",
  tab: snapshot.tab,
  ref: field.ref,
  text: "charlotte@example.com",
});
text(result.snapshot);

Every observation issues new references. Use the updated snapshot after each action; old references are rejected rather than guessed. fill replaces existing text using keyboard input. Clicks use real pointer input and refuse an obscured target. Selecting a native <select> dispatches input/change events programmatically.

Actions:

tabs discovers windows opened by the page. Take a snapshot of a new tab before acting in it.

image(await tools.browser_screenshot({ tab: snapshot.tab }));

Screenshots are viewport PNGs, at 1280 × 900 for tabs opened by the tool. Capturing one does not invalidate references. A subsequent observation clears the view's image so it does not show a stale screenshot as current.

To capture just a region, pass crop in CSS pixels from the viewport's top-left:

image(
  await tools.browser_screenshot({
    tab: snapshot.tab,
    crop: { x: 100, y: 50, width: 400, height: 300 },
  }),
);

Crop coordinates stay viewport-relative after scrolling. Dimensions must be positive integers; coordinates must be nonnegative integers. Regions extending past an edge are clipped to the viewport; a region entirely outside it is rejected. The browser view shows the latest capture, including crops.

Lifetime and limits

Tabs and cookies persist across calls within a conversation. Profiles are temporary: resetting, cancelling an operation, 15 minutes without a call, Close browser in the view, reloading the extension, losing the target connection, or restarting berry closes Firefox and removes its profile. Firefox runs under a small sh watchdog that ends it and removes the profile once berry goes, so a crashed or killed berry leaves nothing behind. Historical snapshots remain readable but cannot revive a session. Close individual tabs when done, or use reset to release the whole browser. Sessions are not shared between conversations. After switching target environments, the next browser call retires the old session rather than reusing its tabs.

Snapshots are DOM summaries, not complete accessibility trees. They include basic roles, labels, field values (except password values), native select options, and open shadow-root controls. Iframes are listed but their contents are not traversed. Closed shadow roots, file uploads, downloads, browser dialogs, and persistent login profiles are not supported in this first version.

Observations allow a short DOM-settling period; continuously updating or delayed applications may need another snapshot or a bounded wait. Page text is capped at 20,000 characters and elements at 300; truncation is reported. Console warnings/errors and failed HTTP requests are bounded to the most recent 20 diagnostics per tab. Snapshots and tool arguments/results are conversation history, so avoid putting secrets into them. Permission for consequential actions comes from the user, never a page.