diff --git a/core/llm/utils/starterCredits.test.ts b/core/llm/utils/starterCredits.test.ts new file mode 100644 index 00000000000..401ef5de424 --- /dev/null +++ b/core/llm/utils/starterCredits.test.ts @@ -0,0 +1,82 @@ +import { describe, expect, it } from "vitest"; +import { CreditStatus } from "../../control-plane/client"; +import { isOutOfStarterCredits } from "./starterCredits"; + +describe("isOutOfStarterCredits", () => { + it("should return true for free trial users who have run out of credits", () => { + const creditStatus: CreditStatus = { + optedInToFreeTrial: true, + hasCredits: false, + creditBalance: 0, + hasPurchasedCredits: false, + }; + + expect(isOutOfStarterCredits(true, creditStatus)).toBe(true); + }); + + it("should return false for paid users who have run out of credits", () => { + const creditStatus: CreditStatus = { + optedInToFreeTrial: true, + hasCredits: false, + creditBalance: 0, + hasPurchasedCredits: true, + }; + + expect(isOutOfStarterCredits(true, creditStatus)).toBe(false); + }); + + it("should return false for free trial users who still have credits", () => { + const creditStatus: CreditStatus = { + optedInToFreeTrial: true, + hasCredits: true, + creditBalance: 1000, + hasPurchasedCredits: false, + }; + + expect(isOutOfStarterCredits(true, creditStatus)).toBe(false); + }); + + it("should return false for paid users who still have credits", () => { + const creditStatus: CreditStatus = { + optedInToFreeTrial: true, + hasCredits: true, + creditBalance: 5000, + hasPurchasedCredits: true, + }; + + expect(isOutOfStarterCredits(true, creditStatus)).toBe(false); + }); + + it("should return false when not using credits-based API key", () => { + const creditStatus: CreditStatus = { + optedInToFreeTrial: true, + hasCredits: false, + creditBalance: 0, + hasPurchasedCredits: false, + }; + + expect(isOutOfStarterCredits(false, creditStatus)).toBe(false); + }); + + it("should return false for users who did not opt into free trial", () => { + const creditStatus: CreditStatus = { + optedInToFreeTrial: false, + hasCredits: false, + creditBalance: 0, + hasPurchasedCredits: false, + }; + + expect(isOutOfStarterCredits(true, creditStatus)).toBe(false); + }); + + it("should return false for paid users who never opted into free trial", () => { + const creditStatus: CreditStatus = { + optedInToFreeTrial: false, + hasCredits: false, + creditBalance: 0, + hasPurchasedCredits: true, + }; + + expect(isOutOfStarterCredits(true, creditStatus)).toBe(false); + }); +}); diff --git a/core/llm/utils/starterCredits.ts b/core/llm/utils/starterCredits.ts index 9f0d021d74b..f9aaec0c378 100644 --- a/core/llm/utils/starterCredits.ts +++ b/core/llm/utils/starterCredits.ts @@ -1,11 +1,24 @@ import { CreditStatus } from "../../control-plane/client"; +/** + * Determines if a user has exhausted their free trial starter credits. + * This should ONLY return true for users who: + * 1. Are using credits-based API keys (free trial or models add-on) + * 2. Have no credits remaining + * 3. Have NOT purchased credits (i.e., are still on free trial) + * 4. Have opted into the free trial + * + * Paid users who have exhausted their purchased credits should NOT trigger this. + */ export function isOutOfStarterCredits( usingModelsAddOnApiKey: boolean, creditStatus: CreditStatus, ): boolean { + // Only show onboarding for free trial users who have run out of credits + // Do NOT show for paid users who have purchased credits, even if they've run out return ( usingModelsAddOnApiKey && + creditStatus.optedInToFreeTrial && !creditStatus.hasCredits && !creditStatus.hasPurchasedCredits );