feat(image): 以插件声明统一图片参数、尺寸选择与定价合同 (#760)

* feat(image): 图片参数 - 统一插件声明配置与生成合同

* docs(image): 图片参数 - 说明声明合同与验证边界

* fix(plugins): 图片声明 - 保留内联素材支持并同步制品文档

* fix(image): 参数合同 - 对齐审批意图和尺寸预检调用方

* fix(image): 调用链 - 保留公开意图并接通独立分辨率

* fix(image): 图片参数 - 补齐分辨率接线与目录价格投影
This commit is contained in:
huiku authored and GitHub committed 2026-10-13 19:18:21 +08:00
1 parent 88de4ce422
commit 7466119867
104 files changed
+6013 -568

No files matched your search

@@ -22,6 +22,9 @@ import (
func protocolRequestFromInput(input canvasGenerationInput) protocol.GenerationRequest {
resolution := strings.TrimSpace(input.Config.VQuality)
if input.Mode == "image" {
resolution = strings.TrimSpace(input.Config.ImageResolution)
}
if input.Mode == "video" {
if declared := videoResolutionNameRequest(input.VideoCapability, resolution); declared != "" {
resolution = declared
@@ -32,19 +35,20 @@ func protocolRequestFromInput(input canvasGenerationInput) protocol.GenerationRe
aspectRatio = normalizePixelSize(aspectRatio)
}
request := protocol.GenerationRequest{
Capability: protocol.Capability(input.Mode),
Model: input.Config.Model,
Prompt: input.Prompt,
Instructions: strings.TrimSpace(input.Config.SystemPrompt),
Images: protocolImageReferences(input),
Videos: protocolMediaReferences(input.ReferenceVideos, "video"),
Audios: protocolMediaReferences(input.ReferenceAudios, "audio"),
AspectRatio: aspectRatio,
Resolution: resolution,
Quality: input.Config.Quality,
GenerateAudio: parseBool(input.Config.VideoGenerateAudio, false),
Watermark: parseBool(input.Config.VideoWatermark, false),
Operation: firstNonEmpty(metadataString(input.Metadata, "videoEditOperation"), metadataString(input.Metadata, "videoOperation")),
ImageParameters: protocolImageParameterValues(input.Config.ImageParameters),
Capability: protocol.Capability(input.Mode),
Model: input.Config.Model,
Prompt: input.Prompt,
Instructions: strings.TrimSpace(input.Config.SystemPrompt),
Images: protocolImageReferences(input),
Videos: protocolMediaReferences(input.ReferenceVideos, "video"),
Audios: protocolMediaReferences(input.ReferenceAudios, "audio"),
AspectRatio: aspectRatio,
Resolution: resolution,
Quality: input.Config.Quality,
GenerateAudio: parseBool(input.Config.VideoGenerateAudio, false),
Watermark: parseBool(input.Config.VideoWatermark, false),
Operation: firstNonEmpty(metadataString(input.Metadata, "videoEditOperation"), metadataString(input.Metadata, "videoOperation")),
Extra: map[string]any{
"videoSeconds": input.Config.VideoSeconds,
"audioVoice": input.Config.AudioVoice,
@@ -84,7 +88,7 @@ func protocolRequestFromInput(input canvasGenerationInput) protocol.GenerationRe
Watermark: request.Watermark, Format: input.Config.AudioFormat,
}
request.ProviderOptions = make(map[string]map[string]any)
if configured, ok := input.Metadata["providerOptions"].(map[string]any); ok {
if configured, ok := input.Metadata["providerOptions"].(map[string]any); ok && input.Config.ImageParameters == nil {
for namespace, raw := range configured {
if options, ok := raw.(map[string]any); ok {
request.ProviderOptions[strings.TrimSpace(namespace)] = options
@@ -102,6 +106,22 @@ func protocolRequestFromInput(input canvasGenerationInput) protocol.GenerationRe
return request
}
func protocolImageParameterValues(values map[string]any) map[string]any {
if values == nil {
return nil
}
result := make(map[string]any, len(values))
for name, value := range values {
// These fields are already encoded from the same validated intent. In
// particular size must retain the route's explicit pixel conversion.
if name == "size" {
continue
}
result[name] = value
}
return result
}
func protocolImageReferences(input canvasGenerationInput) []protocol.MediaReference {
if input.Mode == "video" {
return protocolVideoImageReferences(input)