Compare commits

...
Author SHA1 Message Date
Wesley Liddick 3040209f20 Merge pull request #7813 from kingsleydon/fix/typesafe-upstream-billing-probe
fix(billing): allow upstream billing probe for TypeSafe API-key accounts
2026-10-02 20:02:28 +08:00
Wesley Liddick f5aca74623 Merge pull request #7816 from Wei-Shaw/fix/usage-billing-deleted-key
fix(billing): settle usage when the API key is deleted before billing completes
2026-10-02 20:01:45 +08:00
KingsleyandClaude Opus 5.5 8b9788eeb4 test(billing): drop added comments
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:48:37 +00:00
KingsleyandClaude Opus 5.5 66a9e2e6bb fix(billing): allow upstream billing probe for TypeSafe API-key accounts
The create form shows the upstream billing auto-probe toggle for every
API-key platform and enables it by default. TypeSafe was added as an
API-key platform but not to IsUpstreamBillingProbeIdentity, so creating a
TypeSafe account with the default form state fails with
400 UPSTREAM_BILLING_PROBE_ACCOUNT_INVALID ("account is not an API key
account").

TypeSafe accounts store credentials.api_key/base_url like every other
API-key platform, which is all the probe reads. Add TypeSafe to the probe
identity set, and add typesafe.ai to the official API domains so accounts
on the default https://api.typesafe.ai base URL record "unsupported"
without sending the key to a path that cannot exist, matching the other
official providers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 10:45:53 +00:00
2 changed files with 21 additions and 1 deletions
@@ -1013,7 +1013,8 @@ func IsUpstreamBillingProbeIdentity(platform, accountType string) bool {
}
switch platform {
case PlatformOpenAI, PlatformAnthropic, PlatformGemini, PlatformAntigravity, PlatformGrok,
PlatformKimi, PlatformZhipu, PlatformDeepseek, PlatformMiniMax, PlatformOpenCodeGo:
PlatformKimi, PlatformZhipu, PlatformDeepseek, PlatformMiniMax, PlatformOpenCodeGo,
PlatformTypeSafe:
return true
default:
return false
@@ -1052,6 +1053,7 @@ var upstreamBillingProbeOfficialAPIDomains = []string{
"bigmodel.cn",
"deepseek.com",
"opencode.ai",
"typesafe.ai",
}
func upstreamBillingProbeTargetIsOfficialAPI(baseURL string) bool {
@@ -17,6 +17,7 @@ func TestUpstreamBillingProbeIdentityCoversAllAPIKeyPlatforms(t *testing.T) {
for _, platform := range []string{
PlatformOpenAI, PlatformGrok, PlatformAnthropic, PlatformGemini, PlatformAntigravity,
PlatformKimi, PlatformZhipu, PlatformDeepseek, PlatformMiniMax, PlatformOpenCodeGo,
PlatformTypeSafe,
} {
require.True(t, IsUpstreamBillingProbeIdentity(platform, AccountTypeAPIKey), platform)
require.True(t, isUpstreamBillingProbeAccount(&Account{Platform: platform, Type: AccountTypeAPIKey}), platform)
@@ -174,6 +175,8 @@ func TestUpstreamBillingProbeOfficialAPIBaseURLIsUnsupportedWithoutRequest(t *te
{PlatformDeepseek, "https://api.deepseek.com/anthropic"},
{PlatformOpenCodeGo, "https://opencode.ai/zen/go/v1"},
{PlatformOpenCodeGo, "https://opencode.ai/zen/go"},
{PlatformTypeSafe, "https://api.typesafe.ai"},
{PlatformTypeSafe, "https://api.typesafe.ai/v1"},
}
for i, tc := range cases {
account := &Account{
@@ -217,6 +220,7 @@ func TestUpstreamBillingProbeOfficialAPIHostMatchingIsNormalized(t *testing.T) {
require.True(t, upstreamBillingProbeTargetIsOfficialAPI("https://api.deepseek.com/anthropic"))
require.True(t, upstreamBillingProbeTargetIsOfficialAPI("https://opencode.ai/zen/go/v1"))
require.True(t, upstreamBillingProbeTargetIsOfficialAPI("https://opencode.ai/zen/go"))
require.True(t, upstreamBillingProbeTargetIsOfficialAPI("https://api.typesafe.ai"))
// 相似但不同的注册域不拦:中转完全可能叫 *-x.ai 之外的任何名字。
require.False(t, upstreamBillingProbeTargetIsOfficialAPI("https://relay.example/v1"))
require.False(t, upstreamBillingProbeTargetIsOfficialAPI("https://notx.ai"))
@@ -228,6 +232,7 @@ func TestUpstreamBillingProbeOfficialAPIHostMatchingIsNormalized(t *testing.T) {
require.False(t, upstreamBillingProbeTargetIsOfficialAPI("https://notmoonshot.cn/v1"))
require.False(t, upstreamBillingProbeTargetIsOfficialAPI("https://moonshot.cn.evil.example/v1"))
require.False(t, upstreamBillingProbeTargetIsOfficialAPI("https://kimi.example/v1"))
require.False(t, upstreamBillingProbeTargetIsOfficialAPI("https://nottypesafe.ai"))
require.False(t, upstreamBillingProbeTargetIsOfficialAPI("https://notbigmodel.cn"))
require.False(t, upstreamBillingProbeTargetIsOfficialAPI("https://deepseek.example.com"))
}
@@ -276,3 +281,16 @@ func TestUpstreamBillingProbeSetAccountEnabledAcceptsGrokAPIKey(t *testing.T) {
err := svc.SetAccountEnabled(context.Background(), grokOAuth.ID, true)
require.ErrorIs(t, err, ErrUpstreamBillingProbeAccountInvalid)
}
func TestBuildAccountForCreateAcceptsTypeSafeAPIKeyWithProbeEnabled(t *testing.T) {
enabled := true
account, err := buildAccountForCreate(&CreateAccountInput{
Name: "typesafe",
Platform: PlatformTypeSafe,
Type: AccountTypeAPIKey,
Credentials: map[string]any{"api_key": "ts-key", "base_url": "https://api.typesafe.ai"},
ProbeEnabled: &enabled,
}, map[string]any{})
require.NoError(t, err)
require.Equal(t, true, account.Extra[UpstreamBillingProbeEnabledExtraKey])
}