-
Notifications
You must be signed in to change notification settings - Fork 9.7k
feat: support Claude messages token counting #5596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -79,10 +79,15 @@ func SubscriptionRequestWaffoPancakePay(c *gin.Context) { | |
| // dispatch in WaffoPancakeWebhook. | ||
| tradeNo := fmt.Sprintf("WAFFO_PANCAKE_SUB-%d-%d-%s", userId, time.Now().UnixMilli(), randstr.String(6)) | ||
|
|
||
| payMoney := getWaffoPancakePayMoney(int64(plan.PriceAmount), user.Group) | ||
| if payMoney < 0.01 { | ||
| c.JSON(http.StatusOK, gin.H{"message": "error", "data": "套餐金额过低"}) | ||
| return | ||
| } | ||
|
Comment on lines
+82
to
+86
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same
Additionally, the comparison 🤖 Prompt for AI Agents |
||
| order := &model.SubscriptionOrder{ | ||
| UserId: userId, | ||
| PlanId: plan.Id, | ||
| Money: plan.PriceAmount, | ||
| Money: payMoney, | ||
| TradeNo: tradeNo, | ||
| PaymentMethod: model.PaymentMethodWaffoPancake, | ||
| PaymentProvider: model.PaymentProviderWaffoPancake, | ||
|
|
@@ -100,7 +105,7 @@ func SubscriptionRequestWaffoPancakePay(c *gin.Context) { | |
| ProductID: plan.WaffoPancakeProductId, | ||
| BuyerIdentity: service.WaffoPancakeBuyerIdentityFromUserID(user.Id), | ||
| PriceSnapshot: &service.WaffoPancakePriceSnapshot{ | ||
| Amount: decimal.NewFromFloat(plan.PriceAmount).StringFixed(2), | ||
| Amount: decimal.NewFromFloat(payMoney).StringFixed(2), | ||
| TaxCategory: "saas", | ||
| }, | ||
| BuyerEmail: getWaffoPancakeBuyerEmail(user), | ||
|
|
@@ -114,7 +119,7 @@ func SubscriptionRequestWaffoPancakePay(c *gin.Context) { | |
| c.JSON(http.StatusOK, gin.H{"message": "error", "data": "拉起支付失败"}) | ||
| return | ||
| } | ||
| logger.LogInfo(c.Request.Context(), fmt.Sprintf("Waffo Pancake 订阅订单创建成功 user_id=%d plan_id=%d trade_no=%s session_id=%s money=%.2f", userId, plan.Id, tradeNo, session.SessionID, plan.PriceAmount)) | ||
| logger.LogInfo(c.Request.Context(), fmt.Sprintf("Waffo Pancake 订阅订单创建成功 user_id=%d plan_id=%d trade_no=%s session_id=%s money=%.2f", userId, plan.Id, tradeNo, session.SessionID, payMoney)) | ||
|
|
||
| c.JSON(http.StatusOK, gin.H{ | ||
| "message": "success", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| package claude | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| relaycommon "github.com/QuantumNous/new-api/relay/common" | ||
| relayconstant "github.com/QuantumNous/new-api/relay/constant" | ||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestGetRequestURLUsesMessagesCountTokensPath(t *testing.T) { | ||
| adaptor := &Adaptor{} | ||
| info := &relaycommon.RelayInfo{ | ||
| ChannelBaseUrl: "https://api.anthropic.com", | ||
| RelayMode: relayconstant.RelayModeClaudeCountTokens, | ||
| } | ||
|
Comment on lines
+14
to
+16
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "== RelayInfo and ChannelMeta declarations =="
rg -n --type=go 'type RelayInfo struct|type ChannelMeta struct|ChannelBaseUrl' relay/common/relay_info.go relay/common/channel_meta.go || true
echo
echo "== Invalid test literal usage =="
rg -nPU --type=go 'RelayInfo\s*{(?s).*?ChannelBaseUrl\s*:' relay/channel/claude/adaptor_test.goRepository: QuantumNous/new-api Length of output: 952 🏁 Script executed: # View the RelayInfo and ChannelMeta struct definitions
sed -n '64,115p' relay/common/relay_info.goRepository: QuantumNous/new-api Length of output: 1580 🏁 Script executed: # View the full test context around the problematic lines
sed -n '10,35p' relay/channel/claude/adaptor_test.goRepository: QuantumNous/new-api Length of output: 818 🏁 Script executed: sed -n '89,120p' relay/common/relay_info.goRepository: QuantumNous/new-api Length of output: 1084 🏁 Script executed: sed -n '120,150p' relay/common/relay_info.goRepository: QuantumNous/new-api Length of output: 1502 🏁 Script executed: sed -n '150,180p' relay/common/relay_info.goRepository: QuantumNous/new-api Length of output: 1502 🏁 Script executed: sed -n '180,210p' relay/common/relay_info.goRepository: QuantumNous/new-api Length of output: 1474 Fix invalid Lines 14 and 26 attempt to initialize Proposed fix func TestGetRequestURLUsesMessagesCountTokensPath(t *testing.T) {
adaptor := &Adaptor{}
info := &relaycommon.RelayInfo{
- ChannelBaseUrl: "https://api.anthropic.com",
- RelayMode: relayconstant.RelayModeClaudeCountTokens,
+ ChannelMeta: &relaycommon.ChannelMeta{
+ ChannelBaseUrl: "https://api.anthropic.com",
+ },
+ RelayMode: relayconstant.RelayModeClaudeCountTokens,
}
@@
func TestGetRequestURLKeepsMessagesPathForClaudeMessages(t *testing.T) {
adaptor := &Adaptor{}
info := &relaycommon.RelayInfo{
- ChannelBaseUrl: "https://api.anthropic.com",
- RequestURLPath: "/v1/messages",
+ ChannelMeta: &relaycommon.ChannelMeta{
+ ChannelBaseUrl: "https://api.anthropic.com",
+ },
+ RequestURLPath: "/v1/messages",
}🧰 Tools🪛 golangci-lint (2.12.2)[error] 14-14: : # github.com/QuantumNous/new-api/relay/channel/claude [github.com/QuantumNous/new-api/relay/channel/claude.test] (typecheck) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
|
|
||
| requestURL, err := adaptor.GetRequestURL(info) | ||
| require.NoError(t, err) | ||
| require.Equal(t, "https://api.anthropic.com/v1/messages/count_tokens", requestURL) | ||
| } | ||
|
|
||
| func TestGetRequestURLKeepsMessagesPathForClaudeMessages(t *testing.T) { | ||
| adaptor := &Adaptor{} | ||
| info := &relaycommon.RelayInfo{ | ||
| ChannelBaseUrl: "https://api.anthropic.com", | ||
| RequestURLPath: "/v1/messages", | ||
| } | ||
|
|
||
| requestURL, err := adaptor.GetRequestURL(info) | ||
| require.NoError(t, err) | ||
| require.Equal(t, "https://api.anthropic.com/v1/messages", requestURL) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package constant | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "github.com/stretchr/testify/require" | ||
| ) | ||
|
|
||
| func TestPath2RelayModeClaudeCountTokens(t *testing.T) { | ||
| require.Equal(t, RelayModeClaudeCountTokens, Path2RelayMode("/v1/messages/count_tokens")) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: QuantumNous/new-api
Length of output: 5059
🏁 Script executed:
Repository: QuantumNous/new-api
Length of output: 1651
🏁 Script executed:
Repository: QuantumNous/new-api
Length of output: 252
🏁 Script executed:
Repository: QuantumNous/new-api
Length of output: 1689
🏁 Script executed:
Repository: QuantumNous/new-api
Length of output: 1532
🏁 Script executed:
Repository: QuantumNous/new-api
Length of output: 5439
🏁 Script executed:
Repository: QuantumNous/new-api
Length of output: 1132
int64()truncation loses fractional price amounts—affects billing accuracyplan.PriceAmountisfloat64(stored asdecimal(10,6)in the database), but casting toint64truncates decimals. A plan priced at$9.99becomes$9, undercharging by$0.99.The issue appears in both subscription payment methods:
subscription_payment_epay.goline 92subscription_payment_waffo_pancake.go(similar pattern)Other payment methods (Stripe, Creem) avoid this by using
plan.PriceAmountdirectly without conversion.Consider either:
int64(plan.PriceAmount * 100)and adjustinggetPayMoneyto work in cents, or🤖 Prompt for AI Agents