DocsProviders & desktop
Providers & desktop
Markdown ↗

Labels, icons & quotas

On this pageProvider and account identityAccount-scoped quota freshnessServe reviewed Usagestat assetsVerification

AgenticDriver reuses Usagestat's catalog and account quota API. It does not add provider probes, copy the logo collection into this package, or turn quota differences into per-run usage. The same helpers support Brandstorm's account picker, LitAgent's provider settings and AI Workspace's connection/account UI. Each application keeps its own layout, authenticated sessions, account bindings and workflows.

EntryWhere it runsResponsibility
@agenticdriver/sdk/catalogBrowser or serverPure provider and quota presentation, accessible names and fallback states
@agenticdriver/sdk/usagestatTrusted application serverExisting metadata and explicitly bound quota reads; optional per-run capture
@agenticdriver/sdk/provider-assetsTrusted Node.js startup/buildLoad approved existing icons/notices into an immutable asset cache

Provider and account identity

Use a provider from the authenticated driver's discovery response. Match its explicit usageStatId to Usagestat's provider ID; do not join names, guess vendor aliases or use an account quota ID as a branding ID. The helper rejects mismatched metadata.

ts
import { providerPresentation } from "@agenticdriver/sdk/catalog";

// providers: authorized driver discovery; metadata: server-side Usagestat catalog.
const selected = providers.find((p) => p.id === selectedProviderId)!;
const card = providerPresentation(selected, {
  metadata: metadata.find((p) => p.id === selected.usageStatId),
  account: { id: binding.accountId, label: binding.displayName },
  assets: assetCache.manifest,
  variant: "monochrome", // or explicitly "color"
});

binding is the application's trusted mapping for this provider and user. Never infer it from a provider logo, email address in a usage message, or request metadata. The result keeps the driver instance ID, account ID/label and provider identity separate. accessibleName includes the account label and instance ID so two Codex accounts remain distinguishable. Missing account labels display “Account not linked”; the helper does not invent an account.

Render names, labels and attribution as text. For card.icon.kind === "asset", use an <img> with src={card.icon.asset.src} and alt={card.icon.alt}; include the license notice link in your app's attribution UI. A fallback contains an initial, accessible name and reason (metadata-missing, icon-missing, or variant-missing). An unavailable requested variant does not silently switch styles. When adjacent text already names the provider, the app may mark the icon decorative and put accessibleName on the enclosing choice.

monochrome and supportsCurrentColor preserve source metadata. An external SVG loaded with <img> does not inherit the page's currentColor; these flags do not promise automatic tinting. Prefer the reviewed color variant or an app-owned neutral background. Do not inject raw SVG as HTML. The returned card omits local source paths, upstream image URLs, raw metadata and quota credentials.

Account-scoped quota freshness

Configure Usagestat account bindings on the trusted server. Only pass accountLimits(identity) results to the presentation helper. Raw usage() and limits() are administrative data and must not be sent wholesale to browsers.

ts
import { quotaPresentation } from "@agenticdriver/sdk/catalog";
import type { UsageStatAccountQuota } from "@agenticdriver/sdk/catalog";

// Derive all four values from the authenticated session and host configuration.
const identity = {
  hostId,
  provider: selected.id,
  accountId,
  subject: session.userId,
};
let quota: UsageStatAccountQuota | undefined;
let error: unknown;
try {
  quota = await usagestat.accountLimits(identity);
} catch (failure) {
  error = failure;
}
const display = quotaPresentation(identity, quota, {
  maxAgeMs: 5 * 60_000, // Explicit application display policy, not a run timeout.
  error,
});

The helper verifies the full host/provider/account/subject identity before showing any metrics. It is a display helper, not an authorization boundary: the server must enforce the session and bindings before lookup. Send the resulting display to that user only. A failed refresh suppresses an older successful result; exceptions are converted to fixed labels without exposing upstream error messages.

StateDisplay behavior
freshSnapshot age is below the application's limit and its reported reset windows have not ended
staleShow the previous values as historical; refresh is required
unboundNo account binding, or a receipt belongs to another identity; no metrics
unavailableNo snapshot or quota metrics reported; no fabricated zeros
errorQuota refresh failed; no metrics or private error details
unknownInvalid/future timestamp or invalid metrics; no metrics

Also display quality: cached, estimated, reported or unknown. A recently fetched cached or estimated observation remains labelled as such. fresh describes time, not certainty or permission to execute. Use the provided label plus fetchedAt/ageMs; preserve the upstream units and reset timestamps. Passing a reset boundary never fabricates a reset-to-zero balance. Resources remain snapshots, not exact run charges, budget authorization, or guaranteed remaining capacity. Per-run accounting continues through the existing usage contract.

Serve reviewed Usagestat assets

Build the cache on the same trusted filesystem as the selected Usagestat catalog. The allowlist belongs in application/deployment configuration, never in an HTTP request. Review the installed source assets and notices when pinning your Usagestat dependency.

ts
import { createProviderAssetCache } from "@agenticdriver/sdk/provider-assets";

const assetCache = await createProviderAssetCache({
  providers: await usagestat.providers(),
  root: "/opt/usagestat/plugins",
  publicPath: "/assets/usagestat",
  allowlist: ["codex", "claude", "gemini"].flatMap((providerId) =>
    (["monochrome", "color"] as const).map((variant) => ({
      providerId,
      variant,
      license: {
        id: "MIT",
        attribution:
          "Usagestat upstream notices; provider marks belong to their owners.",
        noticePath: "UPSTREAM-LICENSES.md",
      },
    })),
  ),
});

// Mount this in your app's existing same-origin Fetch/Request router.
function providerAssetRoute(request: Request): Response {
  return assetCache.respond(request) ?? new Response(null, { status: 404 });
}

The existing Usagestat plugins/UPSTREAM-LICENSES.md records upstream MIT notices for adapted assets, including CodexBar, OpenUsage and CrossUsage, and notes that provider names/logos belong to their owners. The cache serves the notice bytes unchanged and links them from each approved asset. Approval metadata is supplied by the operator; the SDK cannot establish the provenance of a newly added third-party asset. Supply its actual notice and attribution when expanding the allowlist.

The loader selects paths only from the approved provider/variant catalog entries, resolves symlinks and rejects paths outside the configured plugin root. Images and notices are bounded to 256 KiB each, with at most 256 approved variants. Unsupported, missing or remote-URL icons become explicit missing entries for fallback display. Missing notices, invalid metadata, oversized files and paths outside the root fail cache creation. No remote image URL is fetched.

Assets are read once, hashed and served only through exact manifest URLs. Requests cannot choose filenames, change variants, add queries or trigger filesystem reads. GET/HEAD, ETags, immutable cache headers, MIME types, nosniff, a sandbox CSP and no-referrer are supplied; preserve these headers in your framework/proxy. These are public reviewed branding assets, never account snapshots or credentials. Mount this route narrowly and keep account APIs authenticated.

Use <img> with the resulting URLs. The loader checks image signatures but is not an SVG upload sanitizer. The approved plugin directory and catalog are trusted operator inputs; applications must not let users replace files there. An asset change creates a new content hash after the cache is rebuilt, while existing cache objects keep serving their original bytes. Deploy the matching manifest and cache together.

For a remote Usagestat installation, prepare the cache alongside that installation and expose only its approved asset routes through the application's asset proxy, or stage the reviewed assets/notices through your build pipeline. Preserve the same manifest/hash URLs and headers. A remote catalog's absolute filesystem path is not a usable browser URL or a local file path on another server. Do not implement a ?path= file reader, open image proxy, credential-bearing URL, or browser access to the raw administrative catalog.

Usagestat is optional: if metadata/assets or quotas are unavailable, use the helper's fallback states while the chosen execution provider retains its own availability checks. Application setup work is tracked in AD-033 (Brandstorm), AD-035 (LitAgent) and AD-037 (AI Workspace); these helpers do not migrate their account/session storage.

Verification

tests/catalog.test.ts covers identity, freshness, errors, variants, notices, caching and path boundaries. npm run test:package verifies the actual installed npm artifact. To check actual native metadata and existing assets:

sh
npx tsx scripts/test-usagestat-assets.ts /path/to/usagestatd /path/to/usagestat/plugins

That check copies the native executable and three provider packages into an isolated temporary profile, disables every provider probe, then verifies catalog metadata, icon bytes and upstream notices. It does not use real accounts or certify live quota accuracy.

Maintained with the AgenticDriver SDKSource snapshot ↗