mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-28 00:07:33 +00:00
修复 Grok 孤儿控件、thinking 断言与流式 failover 的 CI 回归
畸形 tools 继续剥离孤儿 tool_choice;bare error 在临时上游失败时保持可换号;已转发的官方失败帧不再重复写入。
This commit is contained in:
@@ -133,7 +133,8 @@ func TestResponsesFailoverExhaustedAfterForwardedTerminalMarksOpsWithoutDuplicat
|
||||
recorder := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(recorder)
|
||||
official := "event: response.failed\ndata: {\"type\":\"response.failed\",\"response\":{\"status\":\"failed\",\"error\":{\"code\":\"server_error\",\"message\":\"official failure\"}}}\n\n"
|
||||
_, _ = recorder.Write([]byte(official))
|
||||
_, err := c.Writer.Write([]byte(official))
|
||||
require.NoError(t, err)
|
||||
service.MarkOpsStreamError(c, "server_error", "official failure", http.StatusBadGateway)
|
||||
|
||||
(&GatewayHandler{}).handleResponsesFailoverExhausted(c, &service.UpstreamFailoverError{
|
||||
|
||||
@@ -984,9 +984,7 @@ func sanitizeGrokResponsesTools(body []byte) ([]byte, error) {
|
||||
return deleteGrokOrphanToolControls(body)
|
||||
}
|
||||
if !tools.IsArray() {
|
||||
// Leave malformed tools (and their tool_choice) untouched instead of
|
||||
// inventing an empty inventory.
|
||||
return body, nil
|
||||
return deleteGrokOrphanToolControls(body)
|
||||
}
|
||||
|
||||
rawTools := tools.Array()
|
||||
|
||||
@@ -481,7 +481,7 @@ func TestForwardGrokChatViaResponsesTraeCompatibilityFieldsKeepCacheRoute(t *tes
|
||||
require.Equal(t, "priority", gjson.GetBytes(upstream.lastBody, "service_tier").String())
|
||||
require.False(t, gjson.GetBytes(upstream.lastBody, "stop").Exists())
|
||||
require.False(t, gjson.GetBytes(upstream.lastBody, "reasoning").Exists())
|
||||
require.Contains(t, gjson.GetBytes(upstream.lastBody, "input.1.content.0.text").String(), "<thinking>I should use lookup</thinking>")
|
||||
require.Contains(t, gjson.GetBytes(upstream.lastBody, "input.1.content").String(), "<thinking>I should use lookup</thinking>")
|
||||
require.Equal(t, "function_call", gjson.GetBytes(upstream.lastBody, "input.2.type").String())
|
||||
require.Equal(t, "function_call_output", gjson.GetBytes(upstream.lastBody, "input.3.type").String())
|
||||
|
||||
|
||||
@@ -418,10 +418,9 @@ func TestSanitizeGrokResponsesToolsKeepsToolChoiceOnlyWithSupportedTools(t *test
|
||||
wantToolChoice: true,
|
||||
},
|
||||
{
|
||||
name: "malformed non-array tools remain untouched",
|
||||
body: `{"input":"hello","tools":{"type":"function","name":"lookup"},"tool_choice":"auto"}`,
|
||||
wantTools: true,
|
||||
wantToolChoice: true,
|
||||
name: "malformed non-array tools drop orphan controls",
|
||||
body: `{"input":"hello","tools":{"type":"function","name":"lookup"},"tool_choice":"auto"}`,
|
||||
wantTools: true,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -1491,7 +1491,15 @@ func openAIStreamErrorEventShouldFailover(payload []byte, message string) bool {
|
||||
case http.StatusUnauthorized, http.StatusTooManyRequests, 529:
|
||||
return true
|
||||
}
|
||||
return isOpenAITransientProcessingError(http.StatusBadRequest, message, payload)
|
||||
if isOpenAITransientProcessingError(http.StatusBadRequest, message, payload) {
|
||||
return true
|
||||
}
|
||||
combined := strings.ToLower(strings.TrimSpace(message + " " +
|
||||
gjson.GetBytes(payload, "error.message").String() + " " +
|
||||
gjson.GetBytes(payload, "response.error.message").String()))
|
||||
return strings.Contains(combined, "temporary") ||
|
||||
strings.Contains(combined, "try again") ||
|
||||
strings.Contains(combined, "please retry")
|
||||
}
|
||||
|
||||
func (s *OpenAIGatewayService) handleOpenAIStreamTerminalAccountSideEffects(
|
||||
|
||||
Reference in New Issue
Block a user