fix(media): 支持大尺寸图像响应并补齐迁移契约

- 为图像协议放宽 JSON 响应上限并显式处理读取与超限错误
- 合并基础模型与平台能力,避免运行时丢失分辨率和比例约束
- 固化稳定 Gemini 图像模型的能力、计价和 preview 兼容别名
This commit is contained in:
2026-07-24 08:40:30 +08:00
parent fb7e08fe5c
commit 8b8e09cc22
4 changed files with 259 additions and 3 deletions
+40 -1
View File
@@ -13,6 +13,11 @@ import (
"time"
)
const (
defaultMaxJSONResponseBytes int64 = 16 << 20
mediaMaxJSONResponseBytes int64 = 128 << 20
)
func credential(candidate map[string]any, keys ...string) string {
for _, key := range keys {
if value, ok := candidate[key].(string); ok && strings.TrimSpace(value) != "" {
@@ -50,7 +55,12 @@ func decodeHTTPResponse(resp *http.Response) (map[string]any, error) {
func decodeHTTPResponseForProtocol(resp *http.Response, protocol string) (map[string]any, *WireResponse, error) {
defer resp.Body.Close()
raw, _ := io.ReadAll(io.LimitReader(resp.Body, 16*1024*1024))
maxBytes := maxJSONResponseBytesForProtocol(protocol)
raw, readErr := io.ReadAll(io.LimitReader(resp.Body, maxBytes+1))
tooLarge := int64(len(raw)) > maxBytes
if tooLarge {
raw = raw[:maxBytes]
}
wire := &WireResponse{
Protocol: strings.TrimSpace(protocol),
StatusCode: resp.StatusCode,
@@ -60,6 +70,26 @@ func decodeHTTPResponseForProtocol(resp *http.Response, protocol string) (map[st
if len(raw) > 0 {
_ = json.Unmarshal(raw, &wire.Body)
}
if readErr != nil {
return nil, wire, &ClientError{
Code: "response_read_error",
Message: readErr.Error(),
StatusCode: resp.StatusCode,
RequestID: requestIDFromHTTPResponse(resp),
Retryable: true,
Wire: wire,
}
}
if tooLarge {
return nil, wire, &ClientError{
Code: "response_too_large",
Message: fmt.Sprintf("upstream JSON response exceeds %d bytes", maxBytes),
StatusCode: resp.StatusCode,
RequestID: requestIDFromHTTPResponse(resp),
Retryable: false,
Wire: wire,
}
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, wire, &ClientError{
Code: statusCodeName(resp.StatusCode),
@@ -82,6 +112,15 @@ func decodeHTTPResponseForProtocol(resp *http.Response, protocol string) (map[st
return out, wire, nil
}
func maxJSONResponseBytesForProtocol(protocol string) int64 {
switch strings.TrimSpace(protocol) {
case ProtocolGeminiGenerateContent, ProtocolOpenAIImages:
return mediaMaxJSONResponseBytes
default:
return defaultMaxJSONResponseBytes
}
}
func compatibleResponseHeaders(source http.Header) map[string][]string {
if len(source) == 0 {
return nil