fix(runner): 修复转存后残留二进制误判

统一结果二进制探测与上传规则,避免将 thinking_bytes 等上游元数据误判为待转存媒体,同时保留显式媒体字段和签名识别。\n\n补充不含原始内容的安全诊断,并兼容对象存储前缀旧字段;修正真实 OSS 验收脚本使用的正式字段。\n\n验证:Go 全量测试、go vet、迁移安全检查、真实 Gemini 上游响应及阿里云 OSS 转存均通过。
This commit is contained in:
2026-08-04 14:33:04 +08:00
parent 394cc6288f
commit 5c7d6ac9aa
7 changed files with 142 additions and 22 deletions
+20 -17
View File
@@ -306,9 +306,17 @@ func (s *Service) finalizeGeneratedAssets(
if !TaskResultHasInlineBinary(next) {
return next, nil
}
diagnostics := taskResultInlineBinaryDiagnostics(next)
if s.logger != nil {
s.logger.Error("generated result still contains inline binary after object storage materialization",
"taskID", taskID,
"remainingInlineBinary", diagnostics,
)
}
return nil, &clients.ClientError{
Code: "storage_write_failed",
Message: "generated binary result could not be written to object storage",
Details: map[string]any{"scope": "gateway_result_storage", "remainingInlineBinary": diagnostics},
StatusCode: http.StatusServiceUnavailable,
Retryable: true,
}
@@ -417,24 +425,19 @@ func (s *Service) uploadGeneratedBinaryValue(ctx context.Context, taskID string,
}
func generatedRawInlineMediaAsset(key string, value string, siblings map[string]any, taskKind string) (*generatedInlineAsset, bool) {
raw := strings.TrimSpace(value)
if raw == "" {
return nil, false
}
keyLooksLikeMediaPayload := generatedRawDataMediaPayloadKey(key)
contentType := firstNonEmptyString(mediaContentTypeFromItem(siblings), defaultContentTypeForRawMediaKey(key))
if !keyLooksLikeMediaPayload && !generatedContentTypeIsMedia(contentType) && !generatedContentTypeIsDocument(contentType) &&
!strings.HasPrefix(strings.ToLower(raw), "data:") && len(raw) < localBinaryGenericBase64MinLength {
return nil, false
}
payload, payloadContentType, ok, err := inlineMediaPayload(raw, keyLooksLikeMediaPayload)
if err != nil || !ok || len(payload) == 0 {
return nil, false
}
contentType = firstNonEmptyString(payloadContentType, contentType, detectGeneratedAssetContentType(payload))
if !generatedContentTypeIsMedia(contentType) && !generatedContentTypeIsDocument(contentType) {
return nil, false
payload, contentType, _, ok := localBinaryStringBytes(key, value, siblings)
if !ok {
contentType = firstNonEmptyString(mediaContentTypeFromItem(siblings), defaultContentTypeForRawMediaKey(key))
if !generatedContentTypeIsMedia(contentType) && !generatedContentTypeIsDocument(contentType) {
return nil, false
}
var err error
payload, _, ok, err = inlineMediaPayload(value, false)
if err != nil || !ok || len(payload) == 0 {
return nil, false
}
}
contentType = firstNonEmptyString(contentType, detectGeneratedAssetContentType(payload))
kind := mediaKindForAsset(taskKind, siblings, key, contentType)
return &generatedInlineAsset{
Bytes: payload,