fix(webui): show a version on Hub cards for not-yet-installed agents - #3878
Conversation
Browsing the Agent Hub showed no version anywhere for an agent you have not installed yet — not on its card, not in its Details panel — even though the catalog sends `latest_version` for exactly that case. The Available lane renders raw catalog entries, and both surfaces read `version`, a key only `mergeCatalogStatus` writes and only for installed agents, so the branch was dead for every catalog card. A shared `displayVersion` helper now derives the value from the fields the wire actually carries (`installed_version` -> `version` -> `latest_version`), and the card badge drops its installed-only gate: installed cards show what you have, catalog cards show what you'd get. Deriving it from the wire instead of a post-merge field also means neither surface depends on the merge pass having run. The installed-card path #3819 fixed keeps working and now has a HubPage test pinning it, built from the real wire shape rather than a hand-set `version`. Refs #2970
|
Revived this and got a real test run on it — the full Agent UI suite passes on the rebased branch. It is now out of draft with What still needs a human: the live-app check. Nothing automated here can open the Hub with an agent not installed and look at the card, so the two unchecked boxes in the test plan are the merge gate. 🔍 Technical detailsReproduced (executed). Shape matches (static, not executed) against
|
Verdict: Approve with suggestionsHub cards for agents you haven't installed finally show a version, and the fix is built on the fields the backend actually sends rather than one the UI invented — which is why this bug survived two "fixed" attempts. Tests pin the real wire shape, and the evidence run confirms the behaviour against a live catalog. One thing worth a second look before merge: the new "which version do I show?" helper falls back to the catalog's latest when it can't find an installed version. For an agent that's present locally but wasn't installed through the Hub (a pip-installed agent wheel, or a dev checkout), its Installed card will now badge the newest version in the catalog as if you already had it — where today it just shows nothing. A one-line change keeps the badge blank in that case instead of stating a version the user doesn't have. Not a blocker in my view — every other path is strictly better than the blank badge it replaces — but it's the one place this PR can say something untrue. Real-world evidencePresent and matched to the surface — A post-install check ( 🔍 Technical details🟡
|
Resolves the conflict with main's removal of the never-sent `compatibility` field (#3846) and tightens the version badge so it can't advertise a version the user doesn't actually have. Main deleted `compatLevel`/`compatLabel` and the compatibility dot along with the dead wire field, so this branch's imports and locals for them go too. The version badge itself keeps this branch's behaviour: it now renders on both tabs, derived from the fields the catalog really sends. The badge rule also gained a guard. An agent installed from a registry entry point or an editable dev checkout reports no installed version, and the old chain fell through to the catalog's `latest_version` — badging a card with a version that isn't on disk. Those cards now show no badge at all, while a not-yet-installed catalog card still shows what's on offer. Both the card and the details modal read the single helper, so they can't drift apart, and the modal's scorecard line says "latest" instead of "current" for an agent the reader hasn't installed.
|
Rebased onto main and fixed the case you flagged: a Hub card could show a version the user doesn't actually have. An agent installed from a registry entry point or an editable dev checkout reports no installed version, and the old fallback chain dropped through to the catalog's latest — so the card badged a version that was never on disk. Those cards now show no badge at all. A not-yet-installed catalog card still shows the version on offer, unchanged. The card and the details modal now both read one helper instead of each deciding for themselves, so they can't drift apart again. The modal's scorecard line also says "latest" rather than "current" when the reader hasn't installed the agent. Merging main was the other half of this: main removed the compatibility dot, so this branch's leftovers for it are gone too. Verified in 🔍 Technical details
export function displayVersion(agent: AgentInfo): string | undefined {
const installed = agent.installed_version ?? agent.version;
if (installed) return installed;
// Never badge an installed card with a version the user doesn't have —
// ``latest_version`` is what's on offer, not what's on disk.
return isInstalledStatus(agent) ? undefined : agent.latest_version;
}The
Three new cases in Conflict resolution. Conflicts were in Commands run: |
|
Verified in the real app on Linux: an Agent Hub card for an agent you have not installed now shows its version badge, and its Details panel now has a Version row. Before this change both were blank — the card showed only the security-tier and language badges, and the Details panel had no Details section at all. Checked against the live 🔍 Technical detailsBuilt the frontend from this branch (head Catalog payload from Before/after was captured by reverting only the three changed source files to The reason the old code came up blank is in the payload above: the catalog never sends |
itomek
left a comment
There was a problem hiding this comment.
The fallback is gated on status now, so an installed agent with no recorded version shows a blank badge rather than the catalog's latest. Verified in the real app: an uninstalled Hub card renders its version badge and Details shows a Version row, with the before/after taken in the same checkout. Full suite green on the rebased branch.
Browsing the Agent Hub, an agent you have not installed yet shows no version anywhere — not on its card, not in its Details panel — even though the catalog already knows which version it would install you. After this change every Hub card carries a version badge: an installed card shows the version you have, a catalog card shows the version you would get, and Details shows a Version row in both cases.
One correction to the latest reopen on the issue: the installed card badge does already work on current
mainafter #3819. A HubPage test driven by the real catalog payload rendersv0.6.0for the installed Email agent with none of this PR's source changes applied — that test ships here as a regression pin. The path that was genuinely dead is the not-yet-installed one.Refs #2970
Test plan
npx vitest runinsrc/gaia/apps/webui— 349/349 pass (the two new not-yet-installed cases fail without this PR's source change; verified by stashing it)npx tsc --noEmit— cleanpython -m gaia.ui.server, open the Agent Hub — an uninstalled catalog agent's card shows av<x.y.z>badge, and its Details panel shows a Version rowv0.6.0and Details still shows Version 0.6.0🔍 Technical details
Root cause. The Available lane passes raw
GET /api/agents/catalogentries straight toAgentHubCard/AgentDetailModal(HubPage.tsx:236), with nomergeCatalogStatuspass. Both components readagent.version— a key the backend never sends and that onlymergeCatalogStatuswrites, only for installed agents (agentHub.ts:74, added by #3819). So for every catalog card the badge condition and the modal's Version row were unreachable, whilelatest_versionsat unused on the object.Change.
utils/agentHub.ts— newdisplayVersion(agent)returninginstalled_version ?? version ?? latest_version, i.e. derived from what the wire actually carries rather than from a post-merge field. Neither surface now depends on the merge having run.AgentHubCard.tsx:95—const version = isAvailable ? agent.latest_version : displayVersion(agent), and the badge drops its!isAvailablegate. The split keeps the semantics honest: a catalog card advertises the version on offer, never an installed one.AgentDetailModal.tsx:44—versionfrom the helper, used by the Version row, thehasDetailsgate that decides whether the DETAILS section renders at all, and the#2965"measured on vX (current: vY)" scorecard line.Verification. Fixtures use the exact wire shape (
installed_version/latest_version, neverversion), which is the mock-validity gap that let this through twice:HubPage.test.tsx— three cases through the real component tree: installed card badge (passes pre-change, pins fix(webui): make the Hub Details modal actually show an agent's version #3819), available card badge and available Details Version row (both fail pre-change, confirmed by stashing the source diff).agentHub.test.ts— fourdisplayVersionprecedence cases.tsc --noEmitclean.pytestinstalled.util/lint.py --allreports the same two pre-existing failures (Import Validation, Bandit) with and without this branch.Relation to #3820. That PR predates #3819 and now overlaps it on three of its five files. This branch is the non-overlapping remainder rewritten against current
main; #3820 can be closed.