AgentOS 2026.8.15
A search-and-Web-UI release. web_search gains Tavily as a built-in runtime provider, the Web UI finally tells you when a new release is out — the CLI has done that for several versions — and every sidebar view becomes reachable from the keyboard through Gmail-style g chords.
Added
-
A built-in Tavily provider for
web_search. Tavily was previously reachable only through themulti-search-engineskill, which shells out to a script. It is now a runtime provider registered next tobraveandduckduckgo, so selectingtavilyand settingTAVILY_API_KEYis the whole setup — no skill, no subprocess. Onboarding lists it alongside the other keyed providers, the tool wires the configured key through the same path Brave uses, and errors map onto the shared taxonomy:401/403become non-retryableauth,429becomesrate_limit, timeouts stay retryable, so provider fallback behaves the way it does for every other backend.tvly-keys are redacted in logs and transcripts. -
A "new release available" banner in the Web UI. The CLI has warned about outdated installs for several releases; the browser console said nothing, so anyone who lives in the Web UI never learned an upgrade existed. An
updates.checkRPC method — control audience only — returns the running version, the latest version on PyPI, and a status ofup-to-date,outdatedoroffline; the console renders the banner only onoutdated.-
It reuses the CLI's cached PyPI state rather than adding its own polling. The check writes into the same notice-state file under a separate
webuislot, so opening the console does not put extra traffic on PyPI beyond the interval already in place, and the PyPI call is capped at a 2s timeout on a worker thread so a slow or unreachable index degrades toofflineinstead of hanging the RPC. -
The existing opt-outs keep working.
AGENTOS_NO_UPDATE_NOTICE=1andupdates.notify = falseboth short-circuit the check before any network call, and the handler returnsofflinewith nolatest— the banner stays hidden, and the preference does not have to be set twice for two surfaces. -
pypi_clientandversion_utilsmoved fromagentos.clitoagentos.compat, so the gateway can check versions without importing the CLI. The import-contract test enforces the boundary rather than trusting it.
-
-
g-prefixed navigation chords in the Web UI. Pressg, then a destination key within 1.5s:g cchat,g ooverview,g hhealth,g nchannels,g mMCP,g kskills,g ssessions,g aagents,g uusage,g rcron,g eenv,g llogs,g papprovals,g ,settings — fourteen views, all reachable without the mouse. The pending prefix re-arms on a repeatedgand is cancelled by Escape or any held modifier, so a chord in flight never eats a real shortcut. Each jump closes the mobile drawer and moves focus to#main-content, so keyboard and screen-reader users land where they navigated instead of at the top of the sidebar. The?cheat sheet renders multi-step chords with a localized "then" separator, anddocs/web-ui.mddocuments the full set.
Fixed
-
The per-message hover toolbar could not be clicked. Copy, regenerate and edit sit in the outer gutter at
left: 100%plus an 8px margin — entirely outside the.msgbox that carries the:hoverstate. Moving the pointer from the bubble toward the buttons crossed that dead strip, dropped the hover, and faded the toolbar out before it could be reached; the reveal animation compounded it by sliding the buttons away from the incoming cursor. A transparent 10px pseudo-element now bridges the gutter back to the bubble edge, mirrored per role, and inheritspointer-eventsfrom the toolbar so it stays inert while the toolbar is hidden or the message is still streaming. ThetranslateXreveal is gone, so the target no longer moves. Measured withelementFromPointagainst the built stylesheet: the path from bubble edge to copy button has 0 dead pixels with the bridge and 8 without, on both sides. The bridge is suppressed at≤ 560pxand underhover: none, where the toolbar is already in normal flow and a strip in the margin would only swallow taps. -
A coarse clock could stretch the
x_searchbudget. The per-attempt timeout came fromdeadline - time.monotonic(), wheredeadlineis itselftime.monotonic() + total_timeout_seconds. Linux resolvesmonotonic()to nanoseconds, so the second read is always later and the remainder lands under the budget. Windows resolves it to ~15.6ms, so both reads routinely fall in the same tick and the expression collapses to a rounded(t + 20.0) - t— which for many values oftevaluates just above 20.0, handing one attempt a timeout fractionally larger than the total budget it was supposed to fit inside. The per-attempt timeout is now capped on the total budget as well as on the remainder, so the invariant holds at any clock granularity. The regression test pinsmonotonic()to a value where the sum is known to round up, reproducing on any platform what CI hit only intermittently.
Full changelog: v2026.8.13...v2026.8.15