Skip to content

[Feature] Surface the server version and how stale it is from an info affordance in the sidebar header #4254

Description

@randypitcherii

Problem or use case

"What version of Omnigent am I on, and is it old?" has no answer in the web UI's app-level chrome.

The data exists and is already on the client. /api/version returns {"version": ...} (omnigent/server/app.py ~L1688) and the boot capabilities probe carries server_version into lib/capabilities.ts (~L113). But the only place it renders is a footer line inside the per-session agent-info dialog — components/AgentInfo.tsx ~L1301, server ${serverVersion} · host ${hostVersion}. To read your server version you must (a) have a session open, (b) have one whose bound agent passes agentHasInfo, (c) open the header three-dot menu, (d) open agent info, (e) scroll to the footer. On the landing page, Settings, Inbox, or Automations there is no path to it at all.

Settings → Updates doesn't cover this either: it is the Electron auto-updater's preferences for the installed desktop shell (pages/SettingsPage.tsx ~L1553, "Desktop app update preferences for this installed Omnigent shell"). It says nothing about the server you are connected to, and it doesn't exist in a browser.

The staleness half is worse — nothing in the web UI ever says a newer release exists. That check does exist, but only in the terminal: omnigent/update_check.py runs maybe_show_update_notice() on CLI invocation, resolves the configured index (uv.toml / pip.conf, default pypi.org), fetches the latest release via fetch_latest_version(), compares with _is_newer(), and prints a one-time notice per new release. It also already reads install_time_epoch from the installed wheel's dist-info, so "how old is this install" is a resolved quantity today. A web-only user — the desktop app, a phone, a remote server behind a tunnel — never sees any of it.

Practical consequences:

  • Filing a bug means going and finding the version, or guessing.
  • Servers drift. Long-lived remote/tunneled deployments are the ones most likely to be months behind and least likely to have someone watching a terminal.
  • A user hitting a bug fixed three releases ago has no in-app signal that upgrading is the fix.

Proposed solution

Affordance. An info icon next to the Omnigent wordmark in the sidebar header (shell/Sidebar.tsx ~L707, data-testid="sidebar-wordmark"), in the existing sidebar-header-actions cluster styling — Button variant="ghost" size="icon-xs" with a TooltipContent side="bottom", matching the Search and adjacent buttons already there. Do not attach it to the wordmark's own click target: the <Link to="/"> is the app's only way back to the landing composer (its inline comment says so). A sibling icon button, not a hijacked brand mark.

Clicking opens a small popover:

  • Serverserver_version from the capabilities probe, with a staleness line beneath it.
  • Host — for a host-bound session, host_version from useRunnerHealth (host_version is already plumbed there), so the existing agent-info footer's pair is reachable app-wide.
  • Client — the web build version/commit, if it's already available; skip rather than invent a new build stamp.
  • A link to the release notes / GitHub releases.

Staleness. The honest version, in order of increasing cost:

  1. Age of this build. _read_build_info() / install_time_epoch in update_check.py already yields the install timestamp. Expose it alongside the version in /api/version (and the capabilities payload) and render "installed 34 days ago". No network call, no new dependency.
  2. Behind by N releases. Reuse fetch_latest_version() + _is_newer() server-side on the existing cadence and cache (_read_cache / _is_stale), and return latest_version + update_available in the same payload. The UI then reads "0.4.1 — a newer release (0.5.0) is available", with a neutral/amber dot rather than a nag banner.

Doing (1) first is worthwhile on its own; (2) is the one that answers "is that old?" properly, and it is mostly wiring an existing module to an existing endpoint.

Privacy / offline. The PyPI lookup must stay opt-outable and must never block the popover — the module's index resolution already respects corporate mirrors via uv.toml / pip.conf, and an air-gapped server should degrade to showing the version and install age with no error state. A failed check renders nothing extra, not a warning.

Acceptance criteria

  • An info button sits beside the sidebar wordmark on every page, with no session required, and does not disturb the wordmark's "home" link behavior.
  • Its popover shows the server version, and the bound host version when there is one.
  • The popover shows how old the running server build is (install age at minimum).
  • When a newer release is detectable, the popover says so and names the version; when it isn't detectable — offline, air-gapped, opt-out, mirror without the metadata — the popover renders cleanly with no error.
  • The version check never blocks first paint of the popover.
  • The existing agent-info footer keeps working (this doesn't move it).
  • Tests: Vitest for the popover's render states (version present / absent, update available / not / unknown); pytest for whatever /api/version gains.

Alternatives considered

  • Put it in Settings only. Better than today, but Settings → Updates is Electron-specific and browser users have no equivalent page; the sidebar header is visible everywhere and costs one icon.
  • Reuse the wordmark itself as the trigger (click → info). Breaks the only route back to the landing composer, which Sidebar.tsx calls out explicitly.
  • A global "update available" banner or toast. Higher-pressure than warranted for a self-hosted server the user may not control, and impossible to dismiss well. A dot on an info icon is the right volume.
  • Version only, no staleness. Answers half the question. "0.4.1" means nothing to a user who doesn't track the release cadence — the age is the part that's actionable.
  • Client-side call to PyPI/GitHub from the browser. Leaks the deployment to a third party from every user's browser, breaks under CSP and offline installs, and duplicates a check that already exists server-side with a cache.

Harness

Not applicable

Platform or device

Not platform-specific

Harness mode

Not applicable

Expected reach

Most users

Authentication type

Not authentication-related

Metadata

Metadata

Assignees

Labels

FeatureNew feature or requestP2-mediumPriority: bug with workaround, important feature requestcomp:serverComponent: server, API, session managementcomp:web-uiComponent: web frontend (ap-web)help wantedExtra attention is neededtriagedIssue has been triaged by the bot

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions