diff --git a/README.md b/README.md index 9aa175ff4358..c870342d1228 100644 --- a/README.md +++ b/README.md @@ -218,7 +218,7 @@ curl http://localhost:20128/v1/chat/completions \

- + Kimi K3 — Open Frontier Intelligence · 2.8T parameters · 1M-token context

@@ -228,7 +228,7 @@ curl http://localhost:20128/v1/chat/completions \
- + Kimi (Moonshot AI) diff --git a/src/app/(dashboard)/dashboard/KimiSponsorBanner.tsx b/src/app/(dashboard)/dashboard/KimiSponsorBanner.tsx index 13ce4272455e..50291dc19951 100644 --- a/src/app/(dashboard)/dashboard/KimiSponsorBanner.tsx +++ b/src/app/(dashboard)/dashboard/KimiSponsorBanner.tsx @@ -7,14 +7,18 @@ import { APP_CONFIG } from "@/shared/constants/appConfig"; import { shouldShowKimiSponsorBanner } from "./kimiSponsorBannerGate"; // Official Kimi partnership tracking link — keep in sync with README.md's -// Sponsors section and the aff links wired in the providers onboarding UI -// (ProviderPageHeader.tsx). -const KIMI_CODING_AFF_URL = "https://www.kimi.com/code?aff=omniroute"; +// Open Source Friends section and the aff links wired in the providers +// onboarding UI (ProviderPageHeader.tsx). Retargeted 2026-08 from the coding +// plan (kimi.com/code) to the API platform at Moonshot's request: coding plan +// subscriptions are closed to most new users, so that traffic could not +// convert. +const KIMI_PLATFORM_AFF_URL = "https://platform.kimi.ai?aff=omniroute"; -// Versioned dismissal key — bump the suffix (e.g. `-v2`) if the banner's +// Versioned dismissal key — bump the suffix (e.g. `-v3`) if the banner's // offer/copy ever changes materially enough to warrant re-showing it to -// users who already dismissed the previous version. -const DISMISS_STORAGE_KEY = "omniroute-kimi-sponsor-banner-dismissed-v1"; +// users who already dismissed the previous version. `-v2` = the 2026-08 CTA +// retarget to the API platform (new destination + new copy). +const DISMISS_STORAGE_KEY = "omniroute-kimi-sponsor-banner-dismissed-v2"; // Same-tab signal for the dismiss button, since writing localStorage doesn't // fire a "storage" event in the tab that wrote it. const DISMISS_EVENT = "omniroute:kimi-sponsor-banner-dismissed"; @@ -69,7 +73,7 @@ export default function KimiSponsorBanner() { return (
@@ -77,7 +81,7 @@ export default function KimiSponsorBanner() {
-

{t("title")}

+

{t("foundingFriendTitle")}

{t("description")}

@@ -85,7 +89,7 @@ export default function KimiSponsorBanner() {
({ useTranslations: () => (k: string) => k })); vi.mock("@/shared/components/ProviderIcon", () => ({ default: () => null })); @@ -21,9 +22,8 @@ async function renderBanner(version: string): Promise { vi.doMock("@/shared/constants/appConfig", () => ({ APP_CONFIG: { name: "OmniRoute", description: "AI Gateway", version }, })); - const { default: KimiSponsorBanner } = await import( - "../../../src/app/(dashboard)/dashboard/KimiSponsorBanner" - ); + const { default: KimiSponsorBanner } = + await import("../../../src/app/(dashboard)/dashboard/KimiSponsorBanner"); const container = document.createElement("div"); document.body.appendChild(container); @@ -48,13 +48,13 @@ describe("KimiSponsorBanner", () => { vi.doUnmock("@/shared/constants/appConfig"); }); - it("renders with the CTA pointing at the Kimi Coding aff link inside the version window", async () => { + it("renders with the CTA pointing at the Kimi API Platform aff link inside the version window", async () => { const container = await renderBanner("3.8.49"); - expect(container.textContent).toContain("title"); + expect(container.textContent).toContain("foundingFriendTitle"); expect(container.textContent).toContain("cta"); const link = container.querySelector("a[href]"); expect(link).not.toBeNull(); - expect(link?.getAttribute("href")).toBe(KIMI_CODING_AFF_URL); + expect(link?.getAttribute("href")).toBe(KIMI_PLATFORM_AFF_URL); expect(link?.getAttribute("target")).toBe("_blank"); expect(link?.getAttribute("rel")).toContain("noopener"); }); @@ -98,4 +98,13 @@ describe("KimiSponsorBanner", () => { const container = await renderBanner("3.8.49"); expect(container.querySelector("[role='complementary']")).toBeNull(); }); + + it("re-shows the retargeted banner to users who dismissed the v1 (Get Kimi Code) version", async () => { + // 2026-08 CTA retarget (coding plan -> API platform) bumped the dismissal + // key to -v2 so the whole install base gets one fresh impression. + localStorage.setItem(LEGACY_V1_STORAGE_KEY, "true"); + const container = await renderBanner("3.8.50"); + expect(container.querySelector("[role='complementary']")).not.toBeNull(); + localStorage.removeItem(LEGACY_V1_STORAGE_KEY); + }); }); diff --git a/vitest.config.ts b/vitest.config.ts index d602eecb71ef..49856274a5b0 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -40,7 +40,6 @@ export default defineConfig({ "tests/e2e/protocol-clients.test.ts", // ── Pre-existing failures tracked by #8618 ─────────────────────────────── "open-sse/services/autoCombo/__tests__/providerDiversity.test.ts", // #8618 — pre-existing failure; remove this exclusion when fixed - "tests/unit/ui/kimiSponsorBanner.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed "tests/unit/ui/compareView.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed "tests/unit/ui/model-select-modal-keep-open.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed "tests/unit/ui/model-select-field-6540.test.tsx", // #8618 — pre-existing failure; remove this exclusion when fixed