Skip to content

Add provider registry seam for third-provider readiness #5

@TheKrush

Description

@TheKrush

Summary

PromptFuel currently treats providers as a mostly closed Claude/Codex pair. That works for the current product, but it makes the next provider expensive because provider identity, labels, pricing, scanning, dashboard rendering, status formatting, and snapshot handling are spread across many modules.

Add a provider registry seam so future providers can be introduced through descriptors instead of copy-pasting another Claude/Codex branch across the codebase.

Current behavior

Provider identity is modeled as a closed union in many places.

Dashboard and history surfaces contain paired Claude/Codex functions with similar logic. Provider labels, short labels, pricing callbacks, model shortening, scanner behavior, quota readers, and snapshot mapping are not consistently described in one place.

Unknown or future providers are not represented cleanly.

Desired behavior

PromptFuel should have a central provider descriptor registry that owns provider metadata and extension points.

Adding a third provider should primarily involve registering a descriptor and implementing provider-specific scanner/quota/pricing hooks, not editing many unrelated dashboard/status/snapshot modules.

Requirements

  • Introduce a provider descriptor concept or design document.

  • Descriptor should be able to represent:

    • provider id
    • display label
    • short label
    • model shortening/normalization
    • pricing estimator/lookup
    • local scanner hooks, if applicable
    • authenticated quota hooks, if applicable
    • status/dashboard rendering capabilities
    • snapshot import/export behavior
  • Replace or reduce duplicated Claude/Codex dashboard/history/model distribution builder logic where practical.

  • Avoid coercing unknown providers into an existing provider.

  • Unknown providers should be skipped, displayed as unsupported, or reported with a clear validation error.

  • Preserve current Claude/Codex behavior.

Non-goals / constraints

  • Do not add a new provider in this issue.
  • Do not implement UsagePool in this issue.
  • Do not rewrite the entire dashboard at once.
  • Do not change user-facing behavior for Claude/Codex unless directly required.
  • Do not modify CHANGELOG unless this is part of an explicit release-prep task.
  • Do not break existing settings, snapshots, or source labels.

Suggested implementation

Suggested phased approach:

  1. Add a ProviderDescriptor type and registry for existing Claude/Codex metadata.
  2. Move labels, short labels, model shortening, and pricing lookup callbacks into descriptors.
  3. Update dashboard builders to accept provider descriptors where they currently branch on Claude/Codex.
  4. Fix unknown provider handling so unknown snapshot providers are not coerced to Codex.
  5. Add tests proving current Claude/Codex rendering and pricing behavior is unchanged.
  6. Add a synthetic test descriptor to prove a third provider can flow through the generic path without adding bespoke branches.

Possible descriptor shape:

interface ProviderDescriptor {
  id: string;
  label: string;
  shortLabel: string;
  normalizeModelId?: (modelId: string) => string;
  shortenModelId?: (modelId: string) => string;
  estimateCostUsd?: (usage: ModelUsageInput) => number | undefined;
  supportsLocalHistory?: boolean;
  supportsAuthenticatedQuota?: boolean;
  supportsSnapshots?: boolean;
}

Acceptance criteria

  • Claude and Codex provider metadata are registered through descriptors.
  • Existing Claude/Codex dashboard/status behavior remains unchanged.
  • Unknown snapshot providers are not silently coerced to Codex.
  • At least one duplicated Claude/Codex dashboard or model-distribution path is parameterized through descriptor data.
  • Tests cover descriptor lookup for Claude and Codex.
  • A test or fixture demonstrates that a synthetic third provider can be represented without adding a new closed-union branch.
  • Existing validation passes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions