Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
陈曦
sub2api
Commits
25cb5e75
Commit
25cb5e75
authored
Mar 12, 2026
by
haruka
Browse files
fix 第一次 400,第二次触发切账号信号
parent
f44927b9
Changes
2
Show whitespace changes
Inline
Side-by-side
backend/internal/service/antigravity_gateway_service.go
View file @
25cb5e75
...
...
@@ -2241,6 +2241,20 @@ func (s *AntigravityGatewayService) ForwardGemini(ctx context.Context, c *gin.Co
contentType
=
resp
.
Header
.
Get
(
"Content-Type"
)
}
}
else
{
if
switchErr
,
ok
:=
IsAntigravityAccountSwitchError
(
retryErr
);
ok
{
appendOpsUpstreamError
(
c
,
OpsUpstreamErrorEvent
{
Platform
:
account
.
Platform
,
AccountID
:
account
.
ID
,
AccountName
:
account
.
Name
,
UpstreamStatusCode
:
http
.
StatusServiceUnavailable
,
Kind
:
"failover"
,
Message
:
sanitizeUpstreamErrorMessage
(
retryErr
.
Error
()),
})
return
nil
,
&
UpstreamFailoverError
{
StatusCode
:
http
.
StatusServiceUnavailable
,
ForceCacheBilling
:
switchErr
.
IsStickySession
,
}
}
appendOpsUpstreamError
(
c
,
OpsUpstreamErrorEvent
{
Platform
:
account
.
Platform
,
AccountID
:
account
.
ID
,
...
...
backend/internal/service/antigravity_gateway_service_test.go
View file @
25cb5e75
...
...
@@ -139,6 +139,7 @@ type queuedHTTPUpstreamStub struct {
errors
[]
error
requestBodies
[][]
byte
callCount
int
onCall
func
(
*
http
.
Request
,
*
queuedHTTPUpstreamStub
)
}
func
(
s
*
queuedHTTPUpstreamStub
)
Do
(
req
*
http
.
Request
,
_
string
,
_
int64
,
_
int
)
(
*
http
.
Response
,
error
)
{
...
...
@@ -152,6 +153,9 @@ func (s *queuedHTTPUpstreamStub) Do(req *http.Request, _ string, _ int64, _ int)
idx
:=
s
.
callCount
s
.
callCount
++
if
s
.
onCall
!=
nil
{
s
.
onCall
(
req
,
s
)
}
var
resp
*
http
.
Response
if
idx
<
len
(
s
.
responses
)
{
...
...
@@ -679,6 +683,91 @@ func TestAntigravityGatewayService_ForwardGemini_RetriesCorruptedThoughtSignatur
require
.
Equal
(
t
,
"signature_error"
,
events
[
0
]
.
Kind
)
}
func
TestAntigravityGatewayService_ForwardGemini_SignatureRetryPropagatesFailover
(
t
*
testing
.
T
)
{
gin
.
SetMode
(
gin
.
TestMode
)
writer
:=
httptest
.
NewRecorder
()
c
,
_
:=
gin
.
CreateTestContext
(
writer
)
body
,
err
:=
json
.
Marshal
(
map
[
string
]
any
{
"contents"
:
[]
map
[
string
]
any
{
{
"role"
:
"user"
,
"parts"
:
[]
map
[
string
]
any
{{
"text"
:
"hello"
}}},
{
"role"
:
"model"
,
"parts"
:
[]
map
[
string
]
any
{{
"text"
:
"thinking"
,
"thought"
:
true
,
"thoughtSignature"
:
"sig_bad_1"
}}},
},
})
require
.
NoError
(
t
,
err
)
req
:=
httptest
.
NewRequest
(
http
.
MethodPost
,
"/antigravity/v1beta/models/gemini-3.1-pro-preview:streamGenerateContent"
,
bytes
.
NewReader
(
body
))
c
.
Request
=
req
firstRespBody
:=
[]
byte
(
`{"response":{"error":{"code":400,"message":"Corrupted thought signature.","status":"INVALID_ARGUMENT"}}}`
)
const
originalModel
=
"gemini-3.1-pro-preview"
const
mappedModel
=
"gemini-3.1-pro-high"
account
:=
&
Account
{
ID
:
8
,
Name
:
"acc-gemini-signature-failover"
,
Platform
:
PlatformAntigravity
,
Type
:
AccountTypeOAuth
,
Status
:
StatusActive
,
Concurrency
:
1
,
Credentials
:
map
[
string
]
any
{
"access_token"
:
"token"
,
"model_mapping"
:
map
[
string
]
any
{
originalModel
:
mappedModel
,
},
},
}
upstream
:=
&
queuedHTTPUpstreamStub
{
responses
:
[]
*
http
.
Response
{
{
StatusCode
:
http
.
StatusBadRequest
,
Header
:
http
.
Header
{
"Content-Type"
:
[]
string
{
"application/json"
},
"X-Request-Id"
:
[]
string
{
"req-sig-failover-1"
},
},
Body
:
io
.
NopCloser
(
bytes
.
NewReader
(
firstRespBody
)),
},
},
onCall
:
func
(
_
*
http
.
Request
,
stub
*
queuedHTTPUpstreamStub
)
{
if
stub
.
callCount
!=
1
{
return
}
futureResetAt
:=
time
.
Now
()
.
Add
(
30
*
time
.
Second
)
.
Format
(
time
.
RFC3339
)
account
.
Extra
=
map
[
string
]
any
{
modelRateLimitsKey
:
map
[
string
]
any
{
mappedModel
:
map
[
string
]
any
{
"rate_limit_reset_at"
:
futureResetAt
,
},
},
}
},
}
svc
:=
&
AntigravityGatewayService
{
settingService
:
NewSettingService
(
&
antigravitySettingRepoStub
{},
&
config
.
Config
{
Gateway
:
config
.
GatewayConfig
{
MaxLineSize
:
defaultMaxLineSize
}}),
tokenProvider
:
&
AntigravityTokenProvider
{},
httpUpstream
:
upstream
,
}
result
,
err
:=
svc
.
ForwardGemini
(
context
.
Background
(),
c
,
account
,
originalModel
,
"streamGenerateContent"
,
true
,
body
,
true
)
require
.
Nil
(
t
,
result
)
var
failoverErr
*
UpstreamFailoverError
require
.
ErrorAs
(
t
,
err
,
&
failoverErr
,
"signature retry should propagate failover instead of falling back to the original 400"
)
require
.
Equal
(
t
,
http
.
StatusServiceUnavailable
,
failoverErr
.
StatusCode
)
require
.
True
(
t
,
failoverErr
.
ForceCacheBilling
)
require
.
Len
(
t
,
upstream
.
requestBodies
,
1
,
"retry should stop at preflight failover and not issue a second upstream request"
)
raw
,
ok
:=
c
.
Get
(
OpsUpstreamErrorsKey
)
require
.
True
(
t
,
ok
)
events
,
ok
:=
raw
.
([]
*
OpsUpstreamErrorEvent
)
require
.
True
(
t
,
ok
)
require
.
Len
(
t
,
events
,
2
)
require
.
Equal
(
t
,
"signature_error"
,
events
[
0
]
.
Kind
)
require
.
Equal
(
t
,
"failover"
,
events
[
1
]
.
Kind
)
}
// TestStreamUpstreamResponse_UsageAndFirstToken
// 验证:usage 字段可被累积/覆盖更新,并且能记录首 token 时间
func
TestStreamUpstreamResponse_UsageAndFirstToken
(
t
*
testing
.
T
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment