diff --git a/backend/internal/service/gateway_request.go b/backend/internal/service/gateway_request.go index b385d2dc..aa48d880 100644 --- a/backend/internal/service/gateway_request.go +++ b/backend/internal/service/gateway_request.go @@ -99,13 +99,22 @@ func FilterThinkingBlocks(body []byte) []byte { // - Remove `redacted_thinking` blocks (cannot be converted to text). // - Ensure no message ends up with empty content. func FilterThinkingBlocksForRetry(body []byte) []byte { - // Fast path: check for presence of thinking-related keys in messages or top-level thinking config. - if !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(`"thinking":`)) && - !bytes.Contains(body, []byte(`"thinking" :`)) { + hasThinkingContent := 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(`"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 } @@ -195,20 +204,20 @@ func FilterThinkingBlocksForRetry(body []byte) []byte { newContent = append(newContent, block) } - if modifiedThisMsg { + // Handle empty content: either from filtering or originally empty + if len(newContent) == 0 { modified = true - // Handle empty content after filtering - if len(newContent) == 0 { - // Always add a placeholder to avoid upstream "non-empty content" errors. - placeholder := "(content removed)" - if role == "assistant" { - placeholder = "(assistant content removed)" - } - newContent = append(newContent, map[string]any{ - "type": "text", - "text": placeholder, - }) + placeholder := "(content removed)" + if role == "assistant" { + placeholder = "(assistant content removed)" } + newContent = append(newContent, map[string]any{ + "type": "text", + "text": placeholder, + }) + msgMap["content"] = newContent + } else if modifiedThisMsg { + modified = true msgMap["content"] = newContent } newMessages = append(newMessages, msgMap) diff --git a/deploy/docker-compose.yml b/deploy/docker-compose.yml index fbd79710..9c786d6d 100644 --- a/deploy/docker-compose.yml +++ b/deploy/docker-compose.yml @@ -91,6 +91,11 @@ services: - GEMINI_OAUTH_CLIENT_SECRET=${GEMINI_OAUTH_CLIENT_SECRET:-} - GEMINI_OAUTH_SCOPES=${GEMINI_OAUTH_SCOPES:-} - GEMINI_QUOTA_POLICY=${GEMINI_QUOTA_POLICY:-} + + # ======================================================================= + # Security Configuration + # ======================================================================= + - SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS=${SECURITY_URL_ALLOWLIST_UPSTREAM_HOSTS:-} depends_on: postgres: condition: service_healthy diff --git a/frontend/src/components/account/CreateAccountModal.vue b/frontend/src/components/account/CreateAccountModal.vue index 4c75626e..37ef96f0 100644 --- a/frontend/src/components/account/CreateAccountModal.vue +++ b/frontend/src/components/account/CreateAccountModal.vue @@ -1522,7 +1522,7 @@