feat(media-use): derive provider cost tier from the registry (#3155)

The provider registry already declares whether a provider is local, free over
the network, or paid over the network via its A/N/P constructors, but nothing
downstream could read that, so anything needing to know whether resolving
through a provider can spend the user's credit had to re-derive it by
string-matching provider names.

Expose it as providerTierFor(name) over the same table and carry the derived
value on the resolve event alongside the provider it came from. Sparse: absent
when the record carries no provider or the name is not declared. A name declared
under two media types must carry one tier; the index throws at import rather
than silently picking one.

Covered by unit tests on the lookup and by end-to-end cases that spawn the real
CLI and read the value off the payload a local server receives, one per tier.
This commit is contained in:
Miguel Ángel
2026-08-10 13:35:25 -04:00
committed by GitHub
parent bd1c1af291
commit 6de29f5bea
5 changed files with 181 additions and 13 deletions
@@ -8,6 +8,8 @@ import {
providerNamesFor,
runProviders,
runCapability,
providerTierFor,
buildProviderTierIndex,
} from "./registry.mjs";
// --- registry shape -------------------------------------------------------
@@ -185,6 +187,60 @@ test("runCapability('bgm','process') is null — process slot is graceful when u
assert.equal(await runCapability("bgm", "process", "x", {}), null);
});
// --- provider cost tier (telemetry) ---------------------------------------
test("providerTierFor reports the registry's own A/N/P declaration", () => {
assert.equal(providerTierFor("heygen.tts"), "network_paid");
assert.equal(providerTierFor("heygen.video"), "network_paid");
assert.equal(providerTierFor("heygen.audio.sounds"), "network_free");
assert.equal(providerTierFor("heygen.asset.search"), "network_free");
assert.equal(providerTierFor("codex.image_gen"), "network_free");
assert.equal(providerTierFor("bundled.sfx"), "local");
assert.equal(providerTierFor("kokoro.local"), "local");
});
test("providerTierFor agrees across every type that declares the same name", () => {
// heygen.audio.sounds serves both bgm and sfx; heygen.asset.search serves both
// image and icon. A name whose tier depended on the media type would make the
// telemetry property meaningless.
const byName = new Map();
for (const type of listTypes()) {
for (const name of providerNamesFor(type)) {
const tier = providerTierFor(name);
assert.ok(tier, `every declared provider has a tier (${type}/${name})`);
const prior = byName.get(name);
if (prior) assert.equal(tier, prior, `${name} must carry one tier across types`);
byName.set(name, tier);
}
}
});
test("providerTierFor returns undefined for a name the registry does not declare", () => {
assert.equal(providerTierFor("does.not.exist"), undefined);
assert.equal(providerTierFor(undefined), undefined);
assert.equal(providerTierFor(null), undefined);
assert.equal(providerTierFor(""), undefined);
});
test("buildProviderTierIndex throws when one name carries two tiers", () => {
assert.throws(
() =>
buildProviderTierIndex([
[{ name: "dual", network: true }],
[{ name: "dual", network: true, paid: true }],
]),
/declared network_free under one media type and network_paid under another/,
);
});
test("buildProviderTierIndex accepts the same name repeated at the same tier", () => {
const index = buildProviderTierIndex([
[{ name: "same", network: true }],
[{ name: "same", network: true }],
]);
assert.equal(index.get("same"), "network_free");
});
test("--local-only skips every network provider (even free remote ones)", async () => {
let remoteRan = false;
const providers = [