Skip to content

G9BrowserAgent 3.4.0

Latest

Choose a tag to compare

@ImanKari ImanKari released this 07 Oct 05:36

Download

System File Updates
Windows 10/11 (x64) G9BrowserAgent-Setup-3.4.0.exe — per user, no administrator rights Automatic: G9BrowserAgent checks these releases, downloads in the background and asks before installing
macOS 12+ (Apple silicon) G9BrowserAgent-3.4.0-mac-arm64.dmg G9BrowserAgent tells you when a release is out; download it and replace the app (the app is not signed with an Apple Developer ID yet, so macOS cannot install updates into it)
macOS 12+ (Intel) G9BrowserAgent-3.4.0-mac-x64.dmg As above
Linux (x64) G9BrowserAgent-x86_64.AppImage — keep this file name: updates replace the file in place Automatic, like Windows
Debian/Ubuntu (x64) G9BrowserAgent_3.4.0_amd64.deb G9BrowserAgent tells you; install the new .deb with your package manager

The installers are not code-signed: Windows SmartScreen and macOS Gatekeeper ask once before the first start. See the README for what to click, and for the browser extension (loaded once, updated by G9BrowserAgent itself).

latest.yml, latest-mac.yml and latest-linux.yml are the update metadata G9BrowserAgent reads; the .zip and .blockmap files are for the updater.

What changed in 3.4.0

Why. Agents now run long jobs unattended through G9BrowserAgent: social-media business tools, a
music service, renders that take minutes inside the page. A field incident on a browser node showed
how such a job dies. An evaluate on a background tab Engine 1 had just opened hung for 120 s. After
that even browser_tabs close timed out, and only a container restart helped. A panel gate, whose
every request is a fresh MCP session, was told "No session named n-bs" on the call right after it
opened that session, and its own tabs were refused as "owned by agent-N". And every step re-read the
whole page. One release fixes all three, in seven parts.

1. Hang-proofing.

  • Nothing before a command is unbounded any more (lib/cdp.js): the debugger attach (10 s), each
    domain enable (5 s, sent together), Target.setAutoAttach (5 s) and the state write (5 s). A domain
    that did not answer is not marked enabled, and is asked for again when a tool needs it. One attach
    per tab runs at a time. platform-extension now honours timeoutMs on attach, detach and
    sendCommand; it used to ignore it.
  • CSS left the attach set. No capture needs it, and it is the enable most likely to block on a
    background page; inspect styles enables it when used. Engine 2's list (engine/stealth.js) lost it
    too.
  • The watchdog (§4.10, DAEMON_PROTOCOL §3). A cancelled call still running 1.5 s later has its tab
    recovered (recoverTab): every CDP command waiting there is abandoned, so the call ends at once with
    [recovered] …. In the extension the debugger is then detached and attached again; a launched
    engine re-enables its domains. The extension answers a cancelled call within 5 s whatever happens,
    and the daemon waits 8 s for that answer before it frees the tab's queue anyway. browser_status
    shows a tab's slow CDP commands under debugger.
  • close and focus bypass the tab's queue. Close ends every call on the tab first (cancelled in
    its engine too) and abandons stuck CDP commands in the engine, so it works while a call is stuck.
  • The state chain cannot hold a reply. A step longer than WRITE_STEP_MS (5 s) no longer blocks
    the next one. The activity line is written after the reply.
  • Background tabs. Reads, evaluate and snapshots on hidden tabs are covered by tests, and
    keepAwake:true on open, or browser_tabs action:"keep_awake", keeps a tab working: focus
    emulation plus Page.setWebLifecycleState active, applied again after any re-attach. Timer
    throttling of a hidden page is a browser switch, not a command, and the result says so. Engine 2
    already launches with --disable-background-timer-throttling; Engine 1 relies on the
    IntensiveWakeUpThrottlingEnabled=0 policy.
  • Found by the tests: a launched engine's recovery returned early from its re-attach, because the
    tab was still listed as attached. Its domains and keep-awake were therefore never applied again. It
    now forgets the attachment on both engines.

2. Stateless clients.

  • Session names. The daemon's session names were never per agent. The report came from open
    reading only name, so open session:"n-bs" never named the tab. open now takes session too.
  • Agent identity. An agent hello may carry client.identity. Over HTTP that is the X-G9-Agent
    header, else the MCP client's name (G9_MCP_AGENT_IDENTITY name|header|off). The stdio shim sends
    only G9_AGENT_ID, because two editors on one machine may share a client name.
  • Takeover. A new connection with an identity takes over the claims, leases and current tab of
    the older connection with the same identity. If that connection is gone, it takes back what it
    owned and nobody has claimed since (remembered 10 min; a departed owner never blocks anyone). The
    HTTP endpoint ends the idle older sessions of that identity at once, which releases their claims
    instead of after 30 idle minutes.

3. Token economy.

  • Snapshot options. browser_snapshot takes scope (a ref or a CSS selector), roles/name
    (regex) filters, interactiveOnly and includeText:false, with maxNodes as before.
  • Diff. diff:true returns only + added, ~ changed (with what it was) and - removed nodes,
    against the caller's previous diff:true snapshot of the page with the same options.
  • Stable refs (§4.2). An element keeps its ref across snapshots of a page.
  • find. browser_inspect what:"find" (a role and/or a name regex) returns just the matching lines
    with refs.
  • Compact results (mcp/mcp.js, default on, G9_MCP_COMPACT=0 restores the old shape). JSON
    carries no indentation, and a tree or long text comes as a plain-text block of its own instead of
    an escaped string. resultFromContent reverses this for the runner and the harnesses.

4. Waiting and jobs.

  • Waits. browser_navigate wait takes a predicate (a page expression, polled until truthy; the
    final value comes back) and ref+state (visible, hidden, enabled, disabled, checked, unchecked,
    gone, present), up to 2 h. The engine polls every 250 ms, then every 1 s after 10 s and every 2 s
    after 5 min.
  • Evaluate. browser_console evaluate takes timeoutMs up to 4 h.
  • Jobs. job:true answers at once with a jobId (tools/jobs.js). The job lives in the page
    (window.__g9jobs), so it outlives the caller, its MCP session and a worker restart, but not a
    navigation (state:"lost"). Page code reports progress with __g9job.progress(fraction, note).
    job_status (waitMs waits up to 10 min), job_cancel (aborts __g9job.signal) and jobs read
    and manage it. Values are bounded at 256 KiB of JSON.

5. Files on the browser's machine (the daemon runs there for both engines; router #finishFiles).

  • fetch. browser_network fetch runs from G9's isolated world, which has universal access: it
    sends the browser's cookies for the URL and is not refused by CORS. The method, headers and body are
    the caller's; the limit is 40 MiB. The daemon hashes the body and writes savePath (relative paths
    go under <G9_HOME>/files/), or returns a body bounded by maxBytes.
  • Screenshots. browser_screenshot savePath writes the image and returns its path, size and
    sha256. With thumbnail:true it also returns a small JPEG of the viewport, or a scaled copy of the
    capture when there is no time for a second one.
  • Engine 1 downloads now report the final path and, when the daemon can read the file, its sha256.

6. Batch.

  • The action. browser_recording action:"batch" (tools/batch.js) runs a list of steps in one
    call: navigate; input by ref or role+name with nth; wait; evaluate; extract. Values saved with
    saveAs feed {{name}} in later steps.
  • Results. The list is validated before anything runs. Each step gets one compact line, and the
    batch stops at the first failure with an excerpt: the same-role elements when a role+name matched
    nothing.
  • FlowSpec. FlowSpec gained evaluate and extract steps (flowspec, replay, outline, Playwright
    export; runner/README.md). A FlowSpec evaluate runs through cdp.evaluateUserExpression, the one
    named main-world helper the interaction suite's scan allows.

7. EXT-04 is done (§8.5). The call's deadline travels with it (caller.deadlineAt), so the
screenshot's two attempts are budgeted from the time left. When both stall, the call ends with the
cause before its deadline. The relay-timeout text no longer guesses a dialog, and both the late-reply
and both-attempts-stall cases are tested. EXT-13 stays open: its probed capability model and a
measured worker restart were not part of this work.

Tests.

  • New: daemon 112 (+12: identity, the session alias, close past a stuck call, the recovered relay,
    files, the deadlines, compact results, a late reply); seam 23 (+7 through the real runtime, with a
    node:vm main world for jobs); extension suite 111 (+4 Engine 1 hang tests, +7 FlowSpec
    value steps); mcp-http 9 (+1).
  • Changed: one seam assertion — your own fifth snapshot no longer retires your first ref; it is
    the same element's stable ref. One F7 test now waits for the activity line, which is written after
    the reply.
  • The new live suite setup/longwork-livetest.mjs runs inside the Engine 1 harness:
    G9_TIMEOUT_MS=10000 G9_LIVE_SCRIPT=setup/longwork-livetest.mjs node setup/isolated-livetest.mjs, or
    check.mjs --live, which learned a per-check env.

Measured on the owner's workstation (2026-10-07), on headless Edge 154, Engine 1 = the real
extension, Engine 2 = a launched headless browser:
setup/longwork-livetest.mjs 54 passed, 0 failed.

  • Background tab (Engine 1: visibilityState "hidden"): evaluate answered in 35 ms, and a full
    snapshot (125 refs) in 225 ms.

  • Watchdog. A command the page never answers was cut, and its tab recovered, 11.5 s into a call
    with a 10 s deadline, on both engines. The tab then answered in 12 ms (Engine 1) and 3 ms (Engine 2).

  • Close returned in 23 ms (Engine 1) and 5 ms (Engine 2) while a call was stuck on the tab, and
    ended that call.

  • Snapshot bytes the agent receives, on the same page (identical on both engines within 9 bytes):

    Variant Bytes Less than full
    full 14,609 —
    indented JSON (the pre-3.4 shape) 15,396 —
    includeText:false 11,751 −20 %
    interactiveOnly (the page has 125 links and buttons) 11,419 −22 %
    roles:["button"] 245 −98 %
    scope:"form" 293 −98 %
    find "^Save$" 146 −99 %
    diff after a change (+1 ~1 −1) 453 −97 %
    diff with no change 263 −98 %

    Compact JSON alone saved 5 % here: the tree is most of the bytes.

  • Predicate wait. The render, ready after 3 s, was seen after 4.7 s (14 looks) on Engine 1 and
    3.1 s (13 looks) on Engine 2, each in one call.

  • Evaluate jobs of 185 s finished in one tab on each engine (185.0 s, value returned). Progress
    read while they ran: Engine 1 1 % → 7 % → 14 % → 60 % → 92 %; Engine 2 14 % → 17 % → 24 %.

  • Fetch to file. 3,135 bytes, with a sha256 equal to the file served, in an answer of 471 bytes.

  • Screenshot to file. Engine 1: 135 KB on disk, a 200 px PNG thumbnail scaled from the capture,
    because a background tab's second capture did not fit the 10 s deadline; answer 39 KB. Engine 2:
    187 KB on disk, a 320 px JPEG thumbnail; answer 6 KB.

  • Batch. Seven steps ran 5, then stopped at the failing 6th with the page's buttons as the
    excerpt: 545 ms on Engine 1 and 281 ms on Engine 2, in a 759-byte answer. A value one step saved fed
    a later step.

  • MCP over HTTP. A fresh session of the same client found "n-bs" (132 ms) and could act on it;
    owned and current had moved to it, while another client was still refused. A job outlived the
    session that started it.

  • Not clean on the first try. In one earlier run the first tab of a launched browser started at
    that very moment, on a loaded machine, did not answer for about 15 s. The watchdog recovered it, as
    designed. The suite now starts the launched engine before the jobs. Another earlier run lost a
    thumbnail to the short deadline, which led to the time-budgeted thumbnail with its fallback.

Runs on 3.4.0 (2026-10-07). check.mjs --release --keep-going passed 20 of 22 checks in 906 s:

  • Unit: 713 tests in 15 suites (desktop 201, daemon 112, panel 84, interaction 78, engine 56,
    humanize 51, platform-cdp 34, world 26, seam 23, check 13, mcp-http 9, version 8, sites 7, docker 6,
    runtime 5).
  • Other offline checks: self-test 136, extension suite 111, the panel render, links.
  • Live: Engine 1 live 212/0, and the long-work live suite 64/0 (counted with the harness's checks;
    54 of them its own).
  • The two failures:
    • The engine suite's D-a launch: Chrome 154 closed its pipe at start while four checks ran at once.
      Alone, the suite passed, 56 with 1 skip.
    • Engine 2 live 371/1. Its recording replay had been failing since 3.3.0: the recorder no longer
      keeps the password, and the test gave no secret. The test now passes it, as the runner does, and
      that section passed 41/0.
  • Not rebuilt here: the installers. The pipeline builds them and runs the update test.

Version 3.4.0 in package.json, extension/manifest.json, desktop/package.json and
desktop/package-lock.json.

SHA-256

70b2a32bc4cf8cbbc92001884c2e7e22cd6fab856bcf0191dcf964d7bf7c069e  G9BrowserAgent-3.4.0-mac-arm64.dmg
faaff9540846377c6c94f432855ffc07f5fbc69b34fde886204a57e2fb982ad9  G9BrowserAgent-3.4.0-mac-arm64.dmg.blockmap
921b549933cf01b60a3dc374bf67974ce99e80024d2a25d83f61db923d6ae04e  G9BrowserAgent-3.4.0-mac-arm64.zip
e37c6c0ab6503af7c434b6c81dc4135dfa03bdf0e1270325fde243e477129f6e  G9BrowserAgent-3.4.0-mac-arm64.zip.blockmap
33d0fe81eeb4a5f9e78d2814dbee176f8ff44351c4e1e0c89aa15919318f93c3  G9BrowserAgent-3.4.0-mac-x64.dmg
8b80fc7ef16c6b917b26e27b9c6bab6d9191ba8509df21fc881aacb5b0d8ec66  G9BrowserAgent-3.4.0-mac-x64.dmg.blockmap
2ea5c55de8133dfa43d8e6540d68f25515376cef7d5cf8f3689bbfa4f378f5b3  G9BrowserAgent-3.4.0-mac-x64.zip
d8fffa8a8224cdcc050e4fa6f5bf70201f1c47425c3fc2f0e2a6ba629cad932a  G9BrowserAgent-3.4.0-mac-x64.zip.blockmap
fb7c890533f8889068811ec0bb4d20459c226b676dfa56ba007b54c93cb48c2e  G9BrowserAgent-Setup-3.4.0.exe
ae04bb5f29a5c0bf9685cd9c0b7eaae0e3bc6c58127ba99f81f18879805aaf14  G9BrowserAgent-Setup-3.4.0.exe.blockmap
0683bc5de58555045e150361a6ddad6f978e56129d1703548c19efde21c3de43  G9BrowserAgent-x86_64.AppImage
f9976cecef55e0a53e8eba0c88718bb081fbededa7a035b8a86e9f4d4c3fab9b  G9BrowserAgent_3.4.0_amd64.deb