Agent marketplace on the catalog page

Task 12300 · Queued · Coder · created · updated

Epic 12251, child C8. Needs C3b (`router_eligibility`, `ledger_stats` NullLedgerStats). ## Original requirement (verbatim, epic ask 6) "Marketplace: the agent catalog (built-in providers, org SDK agents, operator-published catalog connectors from the ACP registry) rendered with its ledger profile, eligibility per persona, cost band and availability; an org enables a catalog agent and the router may pick it. No vendor self-reporting: a listing's numbers are only the ledger's." Epic Done means (verbatim): "The marketplace page shows each catalog agent with ledger numbers only and no self-reported figure." ## Settled decisions D8: extend the existing Agents › Catalog page (`/agents/catalog`, `apps/web/src/pages/agents/CatalogPage.tsx`) for all orgs; "the router may pick it" requires `intelligent_routing`. A11: cost band from `model_prices.py`, $/$$/$$$ with dollar range on hover, "No price" when none. R10: ledger numbers from epic 12243's metrics with intervals, or "Insufficient data" / "No ledger data yet"; enable/disable via the existing `agent_enablements` flow (`routes/agents.py:673-722`); publish/edit API refuses any performance, cost or quality field. AD9: the route leaves `RequirePlanSwitch name="agents"` (`App.tsx:281-289`) and sits only under `RequireFeature permission="agents:view"`; SDK-backed enable controls stay disabled with the reason shown when the grid cell is off (`agent_resolution.cell_refusal`). ## Approach (Architect §4.8) - `GET /api/agent-marketplace` in new `routes/agent_marketplace.py` (org-scoped, `agents:view`), entries of kind `builtin` (`agent_providers.PROVIDERS`), `org_agent`, `catalog`, `registry`: `{kind, id|provider, display_name, description, personas, cost_band:{band, low_usd, high_usd}|null, availability:{enabled, capable_nodes_online, quota_state}, router:{eligible, reason}, ledger:{state:'no_ledger'|'insufficient'|'ok', n, metrics|null}}`. Built-in personas from `persona_registry`; cost band from `model_prices.prices_by_model` (`model_prices.py:178`) with thresholds defined once in the module; ledger through `agent_router.ledger_stats` (`no_ledger` until C9). - No self-reporting: manifest denylist check in the bundle validation used by `publish_catalog_agent`/`register_agent`/refresh, refusing keys matching `success*`, `*_rate`, `score*`, `benchmark*`, `cost*`, `price*`, `quality*`, `latency*` with a named reason (publish → 422; background refresh → `resolve_error`). Serializer whitelists fields. - Page: CatalogPage rebuilt as a list archetype with sections Built-in, Your agents, Catalog, Registry; names never truncated; 390px; enable/disable reuses `routes/agents.py:685-722`. Credentials & reach: - Dev UI (AC14): `me/jaah/debug/main/operator-login` and `org/console/dev-login` — verified. - AC14 422 and whitelist API tests: the worktree only — verified. Out of scope: changing account quota semantics or spillover; training a model from scratch; routing analysis personas before coder tasks have data; public marketplace billing; any ledger metric definition (owned by the outcome ledger epic). MUST NOT add paid listings or vendor revenue flows. MUST NOT render or accept any vendor-self-reported number. Free-text description claims are accepted (publishing is operator-only). Done means: - AC14 Marketplace (all orgs; pre-ledger part). → Verify: on dev as any org member, open `/agents/catalog` and observe every built-in provider, org SDK agent and catalog connector with persona eligibility, cost band, availability and enable state. The ledger numbers read "No ledger data yet" or "Insufficient data" before §6 … Names and labels are never truncated to a few characters, and the layout holds at 390px. An API test asserts that publishing or editing a catalog entry with any performance, cost or quality field is refused with 422, and that the page renders no such field. - AC15 display: router eligibility per entry shown in words (eligible / why not), consistent with `router_eligibility`. - Tightened (R4c): a whitelist test stores a manifest containing `success_rate` directly and asserts it never appears in the API response or page; an org without the `agents` plan switch can open the page. - Gates (AC16): `./dc check quick` green; changed-area suites green; merge lane `./dc check full` green.

Activity

  • Draft
  • Ready