From 5c4ed5be99d63410bbad9a528588b87e32a23721 Mon Sep 17 00:00:00 2001 From: CaIon Date: Thu, 23 Apr 2026 18:59:48 +0800 Subject: [PATCH] fix(billing): use tieredQuota fallback in composeTieredTextQuota error path Remove the intermediate branch that recomputed quota from EstimatedQuotaBeforeGroup when tieredResult is nil. This discarded the FinalPreConsumedQuota fallback that TryTieredSettle already selected. Now the error path simply adds tool surcharges to the passed-in tieredQuota, preserving the existing fallback semantics. Also removes unrelated mise.toml and adds a test covering the error fallback with a pre-consumed quota that differs from the estimate. --- mise.toml | 2 -- service/text_quota.go | 8 -------- service/text_quota_test.go | 39 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 10 deletions(-) delete mode 100644 mise.toml diff --git a/mise.toml b/mise.toml deleted file mode 100644 index a94d1edc..00000000 --- a/mise.toml +++ /dev/null @@ -1,2 +0,0 @@ -[tools] -bun = "latest" diff --git a/service/text_quota.go b/service/text_quota.go index 07017ad1..e2ec87b2 100644 --- a/service/text_quota.go +++ b/service/text_quota.go @@ -151,14 +151,6 @@ func composeTieredTextQuota(relayInfo *relaycommon.RelayInfo, summary textQuotaS } } - if snap := relayInfo.TieredBillingSnapshot; snap != nil { - return int(decimal.NewFromFloat(snap.EstimatedQuotaBeforeGroup). - Mul(decimal.NewFromFloat(snap.GroupRatio)). - Add(summary.ToolCallSurchargeQuota). - Round(0). - IntPart()) - } - return tieredQuota + int(summary.ToolCallSurchargeQuota.Round(0).IntPart()) } diff --git a/service/text_quota_test.go b/service/text_quota_test.go index deeb1189..37ce1877 100644 --- a/service/text_quota_test.go +++ b/service/text_quota_test.go @@ -400,3 +400,42 @@ func TestComposeTieredTextQuotaFallbackKeepsToolCallSurcharges(t *testing.T) { require.Equal(t, int64(12500), summary.ToolCallSurchargeQuota.Round(0).IntPart()) require.Equal(t, 13750, quota) } + +func TestComposeTieredTextQuotaErrorFallbackUsesPreConsumedQuota(t *testing.T) { + gin.SetMode(gin.TestMode) + w := httptest.NewRecorder() + ctx, _ := gin.CreateTestContext(w) + ctx.Set("claude_web_search_requests", 2) + + relayInfo := &relaycommon.RelayInfo{ + OriginModelName: "claude-3-7-sonnet", + PriceData: types.PriceData{ + ModelRatio: 1, + CompletionRatio: 1, + GroupRatioInfo: types.GroupRatioInfo{GroupRatio: 1.25}, + }, + TieredBillingSnapshot: &billingexpr.BillingSnapshot{ + BillingMode: "tiered_expr", + GroupRatio: 1.25, + EstimatedQuotaBeforeGroup: 1000, + }, + StartTime: time.Now(), + } + + usage := &dto.Usage{ + PromptTokens: 100, + CompletionTokens: 50, + TotalTokens: 150, + } + + summary := calculateTextQuotaSummary(ctx, relayInfo, usage) + + // tieredResult=nil simulates a settlement error where TryTieredSettle + // falls back to FinalPreConsumedQuota (2000), which differs from + // EstimatedQuotaBeforeGroup * GroupRatio (1250). + preConsumedFallback := 2000 + quota := composeTieredTextQuota(relayInfo, summary, preConsumedFallback, nil) + + require.Equal(t, int64(12500), summary.ToolCallSurchargeQuota.Round(0).IntPart()) + require.Equal(t, 14500, quota) +}