mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-14 12:02:27 +08:00
补齐 Grok CC 重试与 compaction 恢复
This commit is contained in:
@@ -200,11 +200,15 @@ func (s *OpenAIGatewayService) forwardAsRawChatCompletions(
|
||||
})
|
||||
s.handleGrokAccountUpstreamError(withGrokTeamRateLimitModel(ctx, upstreamModel), account, resp.StatusCode, resp.Header, respBody)
|
||||
if s.shouldFailoverGrokUpstreamError(resp.StatusCode, respBody) {
|
||||
retryable, retryDelay, retryDeadline := grokSameAccountRetryMetadata(account, resp.StatusCode, respBody)
|
||||
return nil, &UpstreamFailoverError{
|
||||
StatusCode: resp.StatusCode,
|
||||
ResponseBody: respBody,
|
||||
ResponseHeaders: resp.Header.Clone(),
|
||||
RetryableOnSameAccount: account.IsPoolMode() && account.IsPoolModeRetryableStatus(resp.StatusCode),
|
||||
StatusCode: resp.StatusCode,
|
||||
ResponseBody: respBody,
|
||||
ResponseHeaders: resp.Header.Clone(),
|
||||
RetryableOnSameAccount: retryable,
|
||||
RequestScopedTransient: retryable && resp.StatusCode == http.StatusTooManyRequests,
|
||||
SameAccountRetryDelay: retryDelay,
|
||||
SameAccountRetryDeadline: retryDeadline,
|
||||
}
|
||||
}
|
||||
return s.handleChatCompletionsErrorResponse(resp, c, account, billingModel)
|
||||
|
||||
@@ -258,7 +258,7 @@ func (s *OpenAIGatewayService) forwardGrokResponses(
|
||||
}
|
||||
|
||||
func isGrokInvalidEncryptedContentResponse(statusCode int, body []byte) bool {
|
||||
if statusCode != http.StatusBadRequest {
|
||||
if statusCode != http.StatusBadRequest && statusCode != http.StatusUnprocessableEntity {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ func isGrokInvalidEncryptedContentResponse(statusCode int, body []byte) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
if strings.EqualFold(code, "invalid_encrypted_content") {
|
||||
if strings.EqualFold(code, "invalid_encrypted_content") || strings.EqualFold(code, "invalid_compaction") || strings.EqualFold(code, "compaction_decode_error") {
|
||||
return true
|
||||
}
|
||||
// Keep the official xAI flat-code gate so unrelated 400s are not retried.
|
||||
@@ -292,12 +292,13 @@ func isGrokInvalidEncryptedContentResponse(statusCode int, body []byte) bool {
|
||||
return false
|
||||
}
|
||||
// Nested OpenAI-style envelopes may omit top-level code; require decrypt text.
|
||||
if code == "" && !strings.Contains(normalizedMessage, "decrypt") {
|
||||
if code == "" && !strings.Contains(normalizedMessage, "decrypt") && !strings.Contains(normalizedMessage, "decode the compaction blob") {
|
||||
return false
|
||||
}
|
||||
return strings.Contains(normalizedMessage, "encrypted_content") &&
|
||||
return (strings.Contains(normalizedMessage, "encrypted_content") &&
|
||||
(strings.Contains(normalizedMessage, "decrypt") ||
|
||||
strings.Contains(normalizedMessage, "unmodified"))
|
||||
strings.Contains(normalizedMessage, "unmodified"))) ||
|
||||
strings.Contains(normalizedMessage, "decode the compaction blob")
|
||||
}
|
||||
|
||||
// requestHasGrokEncryptedReasoning reports whether the outbound Responses body
|
||||
@@ -392,7 +393,8 @@ func trimGrokInvalidEncryptedContentRetryBody(body []byte) ([]byte, bool, error)
|
||||
|
||||
hasEncryptedReasoning := false
|
||||
for _, item := range items {
|
||||
if strings.TrimSpace(item.Get("type").String()) == "reasoning" && item.Get("encrypted_content").Exists() {
|
||||
if (strings.TrimSpace(item.Get("type").String()) == "reasoning" && item.Get("encrypted_content").Exists()) ||
|
||||
(isOpenAICompactionType(strings.TrimSpace(item.Get("type").String())) && item.Get("encrypted_content").Exists()) {
|
||||
hasEncryptedReasoning = true
|
||||
break
|
||||
}
|
||||
|
||||
@@ -2053,6 +2053,16 @@ func TestForwardGrokResponsesInvalidEncryptedContentRecoveryDoesNotOvermatch(t *
|
||||
}
|
||||
}
|
||||
|
||||
func TestGrokCompactionBlobRecoveryStripsCompactionItem(t *testing.T) {
|
||||
body := []byte(`{"model":"grok","input":[{"type":"compaction","id":"cmp_1","encrypted_content":"blob"},{"type":"message","role":"user","content":"hi"}]}`)
|
||||
require.True(t, isGrokInvalidEncryptedContentResponse(http.StatusUnprocessableEntity, []byte(`{"code":"invalid_compaction","error":"could not decode the compaction blob"}`)))
|
||||
retry, changed, err := trimGrokInvalidEncryptedContentRetryBody(body)
|
||||
require.NoError(t, err)
|
||||
require.True(t, changed)
|
||||
require.Equal(t, "message", gjson.GetBytes(retry, "input.0.type").String())
|
||||
require.False(t, gjson.GetBytes(retry, "input.#(type==\"compaction\")").Exists())
|
||||
}
|
||||
|
||||
func TestForwardGrokResponsesInvalidEncryptedContentRecoveryNestedErrorShape(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user