From 282b9186c6f48fcdbf0c81c49f739e5e9ed2df23 Mon Sep 17 00:00:00 2001 From: Altay Date: Sun, 8 Mar 2026 10:17:29 +0300 Subject: [PATCH] fix(agents): keep upgrade-plan 402s in billing --- src/agents/failover-error.test.ts | 15 +++++++++++++++ ...embedded-helpers.isbillingerrormessage.test.ts | 6 ++++++ src/agents/pi-embedded-helpers/errors.ts | 7 +++++++ 3 files changed, 28 insertions(+) diff --git a/src/agents/failover-error.test.ts b/src/agents/failover-error.test.ts index 656aee7c066..a99cfb5c4b2 100644 --- a/src/agents/failover-error.test.ts +++ b/src/agents/failover-error.test.ts @@ -241,6 +241,21 @@ describe("failover-error", () => { ).toBe("rate_limit"); }); + it("keeps plan-upgrade 402 wrappers aligned with status-split billing payloads", () => { + const message = "Your usage limit has been reached. Please upgrade your plan."; + expect( + resolveFailoverReasonFromError({ + message: `HTTP 402 Payment Required: ${message}`, + }), + ).toBe("billing"); + expect( + resolveFailoverReasonFromError({ + status: 402, + message, + }), + ).toBe("billing"); + }); + it("infers format errors from error messages", () => { expect( resolveFailoverReasonFromError({ diff --git a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts index ddc0edee636..8649f46f871 100644 --- a/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts +++ b/src/agents/pi-embedded-helpers.isbillingerrormessage.test.ts @@ -579,6 +579,12 @@ describe("classifyFailoverReasonFromHttpStatus – 402 temporary limits", () => ); expect(classifyFailoverReasonFromHttpStatus(402, transientMessage)).toBe("rate_limit"); }); + + it("keeps plan-upgrade 402 limit messages in billing", () => { + const billingMessage = "Your usage limit has been reached. Please upgrade your plan."; + expect(classifyFailoverReason(`HTTP 402 Payment Required: ${billingMessage}`)).toBe("billing"); + expect(classifyFailoverReasonFromHttpStatus(402, billingMessage)).toBe("billing"); + }); }); describe("classifyFailoverReason", () => { diff --git a/src/agents/pi-embedded-helpers/errors.ts b/src/agents/pi-embedded-helpers/errors.ts index 0cedd829cea..cd4701c9db9 100644 --- a/src/agents/pi-embedded-helpers/errors.ts +++ b/src/agents/pi-embedded-helpers/errors.ts @@ -219,6 +219,12 @@ const BILLING_402_HINTS = [ "add more credits", "top up", ] as const; +const BILLING_402_PLAN_HINTS = [ + "upgrade your plan", + "upgrade plan", + "current plan", + "subscription", +] as const; const PERIODIC_402_HINTS = ["daily", "weekly", "monthly"] as const; const RETRYABLE_402_RETRY_HINTS = ["try again", "retry", "temporary", "cooldown"] as const; @@ -242,6 +248,7 @@ function includesAnyHint(text: string, hints: readonly string[]): boolean { function hasExplicit402BillingSignal(text: string): boolean { return ( includesAnyHint(text, BILLING_402_HINTS) || + (includesAnyHint(text, BILLING_402_PLAN_HINTS) && text.includes("limit")) || text.includes("billing hard limit") || text.includes("hard limit reached") || (text.includes("maximum allowed") && text.includes("limit"))