Merge branch 'IanShaw027/main'
This commit is contained in:
@@ -574,7 +574,17 @@ func isSignatureRelatedError(respBody []byte) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Keep this intentionally broad: different upstreams may use "signature" or "thought_signature".
|
// Keep this intentionally broad: different upstreams may use "signature" or "thought_signature".
|
||||||
return strings.Contains(msg, "thought_signature") || strings.Contains(msg, "signature")
|
if strings.Contains(msg, "thought_signature") || strings.Contains(msg, "signature") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also detect thinking block structural errors:
|
||||||
|
// "Expected `thinking` or `redacted_thinking`, but found `text`"
|
||||||
|
if strings.Contains(msg, "expected") && (strings.Contains(msg, "thinking") || strings.Contains(msg, "redacted_thinking")) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractAntigravityErrorMessage(body []byte) string {
|
func extractAntigravityErrorMessage(body []byte) string {
|
||||||
|
|||||||
@@ -99,13 +99,22 @@ func FilterThinkingBlocks(body []byte) []byte {
|
|||||||
// - Remove `redacted_thinking` blocks (cannot be converted to text).
|
// - Remove `redacted_thinking` blocks (cannot be converted to text).
|
||||||
// - Ensure no message ends up with empty content.
|
// - Ensure no message ends up with empty content.
|
||||||
func FilterThinkingBlocksForRetry(body []byte) []byte {
|
func FilterThinkingBlocksForRetry(body []byte) []byte {
|
||||||
// Fast path: check for presence of thinking-related keys in messages or top-level thinking config.
|
hasThinkingContent := bytes.Contains(body, []byte(`"type":"thinking"`)) ||
|
||||||
if !bytes.Contains(body, []byte(`"type":"thinking"`)) &&
|
bytes.Contains(body, []byte(`"type": "thinking"`)) ||
|
||||||
!bytes.Contains(body, []byte(`"type": "thinking"`)) &&
|
bytes.Contains(body, []byte(`"type":"redacted_thinking"`)) ||
|
||||||
!bytes.Contains(body, []byte(`"type":"redacted_thinking"`)) &&
|
bytes.Contains(body, []byte(`"type": "redacted_thinking"`)) ||
|
||||||
!bytes.Contains(body, []byte(`"type": "redacted_thinking"`)) &&
|
bytes.Contains(body, []byte(`"thinking":`)) ||
|
||||||
!bytes.Contains(body, []byte(`"thinking":`)) &&
|
bytes.Contains(body, []byte(`"thinking" :`))
|
||||||
!bytes.Contains(body, []byte(`"thinking" :`)) {
|
|
||||||
|
// Also check for empty content arrays that need fixing.
|
||||||
|
// Note: This is a heuristic check; the actual empty content handling is done below.
|
||||||
|
hasEmptyContent := bytes.Contains(body, []byte(`"content":[]`)) ||
|
||||||
|
bytes.Contains(body, []byte(`"content": []`)) ||
|
||||||
|
bytes.Contains(body, []byte(`"content" : []`)) ||
|
||||||
|
bytes.Contains(body, []byte(`"content" :[]`))
|
||||||
|
|
||||||
|
// Fast path: nothing to process
|
||||||
|
if !hasThinkingContent && !hasEmptyContent {
|
||||||
return body
|
return body
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,20 +204,20 @@ func FilterThinkingBlocksForRetry(body []byte) []byte {
|
|||||||
newContent = append(newContent, block)
|
newContent = append(newContent, block)
|
||||||
}
|
}
|
||||||
|
|
||||||
if modifiedThisMsg {
|
// Handle empty content: either from filtering or originally empty
|
||||||
|
if len(newContent) == 0 {
|
||||||
modified = true
|
modified = true
|
||||||
// Handle empty content after filtering
|
placeholder := "(content removed)"
|
||||||
if len(newContent) == 0 {
|
if role == "assistant" {
|
||||||
// Always add a placeholder to avoid upstream "non-empty content" errors.
|
placeholder = "(assistant content removed)"
|
||||||
placeholder := "(content removed)"
|
|
||||||
if role == "assistant" {
|
|
||||||
placeholder = "(assistant content removed)"
|
|
||||||
}
|
|
||||||
newContent = append(newContent, map[string]any{
|
|
||||||
"type": "text",
|
|
||||||
"text": placeholder,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
newContent = append(newContent, map[string]any{
|
||||||
|
"type": "text",
|
||||||
|
"text": placeholder,
|
||||||
|
})
|
||||||
|
msgMap["content"] = newContent
|
||||||
|
} else if modifiedThisMsg {
|
||||||
|
modified = true
|
||||||
msgMap["content"] = newContent
|
msgMap["content"] = newContent
|
||||||
}
|
}
|
||||||
newMessages = append(newMessages, msgMap)
|
newMessages = append(newMessages, msgMap)
|
||||||
|
|||||||
@@ -91,6 +91,11 @@ services:
|
|||||||
- GEMINI_OAUTH_CLIENT_SECRET=${GEMINI_OAUTH_CLIENT_SECRET:-}
|
- GEMINI_OAUTH_CLIENT_SECRET=${GEMINI_OAUTH_CLIENT_SECRET:-}
|
||||||
- GEMINI_OAUTH_SCOPES=${GEMINI_OAUTH_SCOPES:-}
|
- GEMINI_OAUTH_SCOPES=${GEMINI_OAUTH_SCOPES:-}
|
||||||
- GEMINI_QUOTA_POLICY=${GEMINI_QUOTA_POLICY:-}
|
- GEMINI_QUOTA_POLICY=${GEMINI_QUOTA_POLICY:-}
|
||||||
|
|
||||||
|
# =======================================================================
|
||||||
|
# Security Configuration
|
||||||
|
# =======================================================================
|
||||||
|
- SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS=${SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS:-}
|
||||||
depends_on:
|
depends_on:
|
||||||
postgres:
|
postgres:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|||||||
@@ -1522,7 +1522,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
<div class="mt-2 flex flex-wrap gap-2">
|
<div class="mt-2 flex flex-wrap gap-2">
|
||||||
<a
|
<a
|
||||||
href="https://gemini.google.com/faq#location"
|
href="https://policies.google.com/terms"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||||
@@ -1531,7 +1531,16 @@
|
|||||||
</a>
|
</a>
|
||||||
<span class="text-gray-400">·</span>
|
<span class="text-gray-400">·</span>
|
||||||
<a
|
<a
|
||||||
href="https://gemini.google.com"
|
href="https://policies.google.com/country-association-form"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||||
|
>
|
||||||
|
修改归属地
|
||||||
|
</a>
|
||||||
|
<span class="text-gray-400">·</span>
|
||||||
|
<a
|
||||||
|
href="https://gemini.google.com/gems/create?hl=en-US&pli=1"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
class="text-sm text-blue-600 hover:underline dark:text-blue-400"
|
||||||
@@ -1869,8 +1878,9 @@ const geminiHelpLinks = {
|
|||||||
apiKey: 'https://aistudio.google.com/app/apikey',
|
apiKey: 'https://aistudio.google.com/app/apikey',
|
||||||
aiStudioPricing: 'https://ai.google.dev/pricing',
|
aiStudioPricing: 'https://ai.google.dev/pricing',
|
||||||
gcpProject: 'https://console.cloud.google.com/welcome/new',
|
gcpProject: 'https://console.cloud.google.com/welcome/new',
|
||||||
geminiWebActivation: 'https://gemini.google.com/gems/create?hl=en-US',
|
geminiWebActivation: 'https://gemini.google.com/gems/create?hl=en-US&pli=1',
|
||||||
countryCheck: 'https://policies.google.com/country-association-form'
|
countryCheck: 'https://policies.google.com/terms',
|
||||||
|
countryChange: 'https://policies.google.com/country-association-form'
|
||||||
}
|
}
|
||||||
|
|
||||||
// Computed: current preset mappings based on platform
|
// Computed: current preset mappings based on platform
|
||||||
|
|||||||
Reference in New Issue
Block a user