FoxIR v1.0.15
FoxIR v1.0.15 — The Built-in Browser Gets Reliable, and Elements Get Addressed by Number
Heads-up on scope: this is the first published release since v1.0.8. Tags v1.0.9 … v1.0.14
were cut but never packaged, so this zip carries everything up to 3fb33cc — 51 commits of
history since the download you may have now. The short version of that gap, by release commit:
P0 security work + multi-session (v1.0.10), per-session mode/STOP (v1.0.11), main-chat
protection and language rules (v1.0.12–13), the Tools-page capability center and the first
browser launch fix (v1.0.14).
This round: browser_cdp reliability
Every item below was reproduced on the real machine (Edge 154) before it was changed, and each
has a test that fails on the old behaviour.
- Browser state is sharded per agent — one page per invocation inside one shared browser, so
a finished run can no longer close the browser another session is using. In visible-window
mode it is one page per chat session, so a login page stops multiplying into tabs. - A browser that outlived its own launcher is now adopted, not mourned. Edge's launcher
process hands the work to the real browser process and exits 0; the pipe transport then reports
"browser exited before the websocket URL could be resolved", while a live browser keeps owning
the profile — every later launch failed the same way. The port is recovered from
<profile>/DevToolsActivePort, verified against/json/version(same browser family, headless
UA) and connected. fetch_targets()is gone. In chromiumoxide 0.9.1 it replayson_target_created, which
replaces every registered target and silently kills all held page handles — the source of the
channel disconnectederrors. Listing goes through a plain CDP command now.- Shutdown waits. Every path that drops a browser now waits for the process to exit before
re-launching, because Chromium's single-instance mutex is peruser-data-dir. - Memory can no longer declare a tool dead. The fact curator refuses "the built-in browser is
broken, use Edge headless instead", and the prompt states that memory is authoritative about the
past, not about whether a tool works right now. (A stale fact had been making the model skip the
tool entirely, then improvise withshell_execand write evidence outside the case directory.) - Launch failures name the actual cause, and the profile stays inside the case directory.
Three action-level bugs, with their measurements
- Default
max_charscollapsed to 1 character.unwrap_or(0).min(budget).max(1)turned "not
provided" into "give me one character", soget_text/get_html/execute_jsreturned".
A field test: 30 characters came back as 1; now the context budget is used and
max_chars: 1still truncates withnext_offset. - A page that never finishes loading was reported as a failed navigation. On a local server
that stalls mid-body,Page.navigateanswers after 30.0s withRequest timed outwhile the
page had already arrived — the caller retried four times and burned two minutes. A late reply
now returnsloaded: falseplusrequested_url, andurlonly ever says what the browser
itself will admit to. - A rejected selector was reported as a missing element after an 8s poll (real text:
Error -32000: DOM Error while queryingat 4.7ms). Bad syntax now fails fast and says so;
genuinely absent elements keep the old message.navigatealso stopped claiming the browser's
staleabout:blankas the destination.
New: snapshot + index addressing
CSS cannot match visible text, and that is the thing the agent keeps needing: on four real pages,
0 of 4 text targets could be written as a legal CSS selector, and only 15–16% had an id to
hang one on — so the model wrote a:contains('设置'), failed, and re-scanned the DOM by hand.
snapshotnumbers the visible interactive elements and returns[N]<button 第一个按钮/>
lines (measured: 25–27 elements ≈ 1.0–1.7 KB; 300 elements ≈ 10 KB; the pass itself is
7–48 ms).click/type_textacceptindex, resolved through the existing element path.- Stale indices say "re-snapshot, don't guess another number" and return in ~2.2s instead of
polling for 8s. - Known cost: numbering writes a
data-fxattribute into the page (attributes only), which can
trip a site's own MutationObserver; iframe and shadow-DOM contents are not numbered.
Verification
Real machine (Edge 154): 15 #[ignore] browser tests pass, including the handoff-adoption,
visible-window switch and bounded-click cases. cargo test --lib 376 passed; the 2 failures are
pre-existing environment tests that read live Prefetch/Recent folders.
Not covered / known gaps
- The Tools and Settings pages have not been re-clicked by a human after this version bump; the
visible-window login path is verified by tests and by confirming a real window appears, not
end-to-end by a person. Element::click()on a link that navigates still never gets a reply from Chromium — actions are
bounded around it and report "delivered, result unknown", which is honest but not the same as a
confirmed click.- Iframes, shadow DOM and file uploads remain unimplemented in
browser_cdp. - Windows only for the browser path; Linux browser discovery is still a stub.