diff --git a/changelog.d/fixes/provider-assets-provenance-final.md b/changelog.d/fixes/provider-assets-provenance-final.md new file mode 100644 index 0000000000..f278fdbc41 --- /dev/null +++ b/changelog.d/fixes/provider-assets-provenance-final.md @@ -0,0 +1 @@ +Render Nimble Search with the generic provider icon and serve Opper's proven logo locally. diff --git a/public/providers/nimble-search.svg b/public/providers/nimble-search.svg deleted file mode 100644 index aa53f2fe5e..0000000000 --- a/public/providers/nimble-search.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/src/shared/components/ProviderIcon.tsx b/src/shared/components/ProviderIcon.tsx index b0cc297030..448b4c8685 100644 --- a/src/shared/components/ProviderIcon.tsx +++ b/src/shared/components/ProviderIcon.tsx @@ -141,7 +141,6 @@ const KNOWN_SVGS = new Set([ "moonshot", "morph", "nebius", - "nimble-search", "nlpcloud", "nomic", "novita", @@ -152,6 +151,7 @@ const KNOWN_SVGS = new Set([ "openai", "openclaw", "openrouter", + "opper", "orcarouter", "ovhcloud", "perplexity", @@ -240,6 +240,7 @@ const GENERIC_PROVIDER_IDS = new Set([ "leonardo", "modal", "modelscope", + "nimble-search", "nlpcloud", "oauth", "oci", @@ -347,7 +348,9 @@ const ProviderIcon = memo(function ProviderIcon({ : normalizedId; const usesGenericIcon = GENERIC_PROVIDER_IDS.has(normalizedId) || GENERIC_PROVIDER_IDS.has(localSvgId); - const themedSvg = Object.hasOwn(THEMED_SVGS, normalizedId) ? THEMED_SVGS[normalizedId] : undefined; + const themedSvg = Object.hasOwn(THEMED_SVGS, normalizedId) + ? THEMED_SVGS[normalizedId] + : undefined; const hasSvg = KNOWN_SVGS.has(localSvgId); const [failedAssets, setFailedAssets] = useState>({}); diff --git a/tests/unit/check-provider-asset-provenance.test.ts b/tests/unit/check-provider-asset-provenance.test.ts index b4e06c9da2..c91d4daa7f 100644 --- a/tests/unit/check-provider-asset-provenance.test.ts +++ b/tests/unit/check-provider-asset-provenance.test.ts @@ -541,7 +541,7 @@ test("provider asset provenance gate binds auditedCommit to the physical provide } }); -test("repository provider asset manifest covers the audited 142-file snapshot", (t) => { +test("repository provider asset manifest covers the audited 141-file snapshot", (t) => { const manifestPath = join(REPO_ROOT, "config/quality/provider-assets-provenance.jsonl"); const { auditedCommit } = JSON.parse(readFileSync(manifestPath, "utf8").split("\n")[0]); if (!gitHasCommit(auditedCommit) && isShallowRepository()) { @@ -556,7 +556,7 @@ test("repository provider asset manifest covers the audited 142-file snapshot", assert.equal(result.status, 0, `${result.stdout}\n${result.stderr}`); assert.match( result.stdout, - /142\/142 registered; proven=71 probable=69 unresolved=2; duplicate-groups=1/ + /141\/141 registered; proven=72 probable=69 unresolved=0; duplicate-groups=1/ ); }); diff --git a/tests/unit/provider-assets-generic-fallback.test.mjs b/tests/unit/provider-assets-generic-fallback.test.mjs index af9f3299d5..ebce70b080 100644 --- a/tests/unit/provider-assets-generic-fallback.test.mjs +++ b/tests/unit/provider-assets-generic-fallback.test.mjs @@ -35,6 +35,7 @@ const LOCAL_SVG_IDS_WITHOUT_PROVENANCE = [ "leonardo", "modal", "modelscope", + "nimble-search", "nlpcloud", "oauth", "oci", @@ -178,9 +179,9 @@ const AUDITED_REFERENCE_FILES = [ ...referenceRoots.flatMap((directory) => collectTextFiles(join(root, directory))), ]; -test("provider bundle retires exactly the 79 unresolved assets and keeps the generic icon", () => { - assert.equal(retiredAssetNames.length, 79); - assert.equal(new Set(retiredAssetNames).size, 79); +test("provider bundle retires exactly the 80 unresolved assets and keeps the generic icon", () => { + assert.equal(retiredAssetNames.length, 80); + assert.equal(new Set(retiredAssetNames).size, 80); for (const assetName of retiredAssetNames) { assert.equal( @@ -197,8 +198,9 @@ test("provider bundle retires exactly the 79 unresolved assets and keeps the gen // provenance PRs (#11735, #11736, #11711) landed first and independently retired // 6 further unproven files this PR never targeted (freebuff-dark.svg, // freebuff-light.svg, freebuff.png, openvecta.svg, picoclaw.jpg, zoocode.png), - // so the real remaining count is 142, not 148. - assert.equal(distributedAssets.length, 142, "all 142 non-target assets must remain"); + // so the real pre-fix count was 142, not 148. This fix retires the unresolved + // Nimble asset as well, leaving 141 distributed assets. + assert.equal(distributedAssets.length, 141, "all 141 non-target assets must remain"); assert.ok(distributedAssets.includes("cli-generic.svg")); }); diff --git a/tests/unit/ui/ProviderIcon-icon-url.test.tsx b/tests/unit/ui/ProviderIcon-icon-url.test.tsx index 7ce75d2db7..e1e460d888 100644 --- a/tests/unit/ui/ProviderIcon-icon-url.test.tsx +++ b/tests/unit/ui/ProviderIcon-icon-url.test.tsx @@ -54,6 +54,7 @@ const PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE = [ "leonardo", "modal", "modelscope", + "nimble-search", "nlpcloud", "oauth", "oci", @@ -230,6 +231,7 @@ describe("ProviderIcon — local SVG dimensions", () => { it.each([ ["cline", "/providers/cline.svg"], ["kimi-coding", "/providers/kimi-logomark-light.svg"], + ["opper", "/providers/opper.svg"], ])("gives %s a definite square layout size", (providerId, expectedSrc) => { const container = renderIcon({ providerId, size: 24 }); const img = container.querySelector(`img[src="${expectedSrc}"]`); @@ -245,8 +247,8 @@ describe("ProviderIcon — local SVG dimensions", () => { describe("ProviderIcon — unresolved local asset provenance", () => { it("covers the complete provider and alias inventory", () => { - expect(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE).toHaveLength(79); - expect(new Set(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE)).toHaveLength(79); + expect(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE).toHaveLength(80); + expect(new Set(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE)).toHaveLength(80); }); it.each(PROVIDER_IDS_WITHOUT_LOCAL_ASSET_PROVENANCE)(