diff --git a/backend/internal/app/cloud_agent_batch_table.go b/backend/internal/app/cloud_agent_batch_table.go index b0aa9c02c..ab84ba3b5 100644 --- a/backend/internal/app/cloud_agent_batch_table.go +++ b/backend/internal/app/cloud_agent_batch_table.go @@ -12,7 +12,7 @@ import ( const ( maxCloudAgentBatchRows = 500 - maxCloudAgentBatchReferences = 6 + maxCloudAgentBatchReferences = 10 maxCloudAgentBatchPromptRunes = 20000 ) @@ -96,7 +96,7 @@ func batchTableNodeFromDocument(doc map[string]any, nodeID string) (map[string]a } columns := creationMaps(table["referenceColumns"]) if len(columns) < 1 || len(columns) > maxCloudAgentBatchReferences { - return nil, nil, nil, nil, BadAuthRequest("批量创作表必须包含 1 到 6 个参考图列") + return nil, nil, nil, nil, BadAuthRequest("批量创作表必须包含 1 到 10 个参考图列") } columnIDs := map[string]bool{} for _, column := range columns { @@ -299,7 +299,7 @@ func prepareCloudAgentBatchTableEdit(repo *repository.Repository, userID, canvas fields = []string{"并发数"} case "add_reference_column": if len(columns) >= maxCloudAgentBatchReferences { - return nil, BadAuthRequest("批量创作表最多支持6组参考图") + return nil, BadAuthRequest("批量创作表最多支持10组参考图") } if args.RowID != "" || len(args.Patch) != 0 || args.Operation != "" || args.Concurrency != 0 { return nil, BadAuthRequest("新增参考图列不接受其他修改参数") diff --git a/backend/internal/app/cloud_agent_batch_table_test.go b/backend/internal/app/cloud_agent_batch_table_test.go index 94f46686c..09a3b8b3d 100644 --- a/backend/internal/app/cloud_agent_batch_table_test.go +++ b/backend/internal/app/cloud_agent_batch_table_test.go @@ -2,12 +2,29 @@ package app import ( "encoding/json" + "fmt" "strings" "testing" "infinite-canvas/backend/internal/model" ) +func TestCloudAgentBatchTableReferenceLimit(t *testing.T) { + for _, count := range []int{10, 11} { + t.Run(fmt.Sprint(count), func(t *testing.T) { + columns := make([]any, count) + for i := range columns { + columns[i] = map[string]any{"id": fmt.Sprintf("reference-%d", i+1), "label": fmt.Sprintf("参考图 %d", i+1)} + } + doc := map[string]any{"nodes": []any{map[string]any{"id": "batch", "type": "batch-table", "metadata": map[string]any{"batchTable": map[string]any{"operation": "creative", "concurrency": float64(1), "referenceColumns": columns, "rows": []any{}}}}}} + _, _, _, _, err := batchTableNodeFromDocument(doc, "batch") + if (err == nil) != (count == 10) { + t.Fatalf("reference count %d: unexpected validation result %v", count, err) + } + }) + } +} + func cloudAgentBatchTableCall(t *testing.T, name, callID string, args any) cloudAgentCall { t.Helper() raw, err := json.Marshal(args) diff --git a/docs/content/docs/progress/pending-test.mdx b/docs/content/docs/progress/pending-test.mdx index ec138bf49..607194f42 100644 --- a/docs/content/docs/progress/pending-test.mdx +++ b/docs/content/docs/progress/pending-test.mdx @@ -5,6 +5,14 @@ description: 当前项目已实现功能的手工验证清单与未确认边界 # 待测试 +## 多模态列表与分镜表合并回归 + +- [x] 合入 PR #549 的图片 / 视频列表分析、动态表格、视频脚本转换和批量生成设置;参考图上限前后端统一为 10。保留本地主分支表格布局、参考图提及、删除列、结果定位、手工行增量同步及单行重新生成。 +- [x] 不采用按模型名称猜测多模态能力或自动切换模型的逻辑;保持能力强校验。数据库迁移仍为主分支版本 31,未重编号历史迁移,也未操作实际数据库。 +- [x] 修复完成结果的批量跳过 / 显式重生成边界、设置弹窗提交前状态复核、分镜行身份和编辑内容保留、抽帧排序 / 去重 / 部分失败时按来源与时间绑定。 +- [x] 77 项前端专项测试通过,包含真实表格组件明暗主题静态渲染、只读边界、列表解析、分镜转换、参考图同步和生成筛选;类型检查及生产构建通过。后端数据库、协议以及批量表 / 模型能力相关专项测试通过;插件归档与源清单一致。构建仍有大于 500 kB 的 chunk 警告。 +- [ ] 真实浏览器检查列表模式切换、动态列编辑、参考图拖拽 / 提及、设置弹窗和结果定位;使用明确配置多模态能力的真实模型验证图片 / 视频分析、分镜关键帧抽取与后续图片 / 视频生成,覆盖跨域视频和部分抽帧失败。本轮未启动开发服务、调用真实上游或部署,静态渲染和构建不代表端到端验收完成。 + ## Agent 任务诊断与模型选择强校验 - 已修复:成功任务不再由空错误文本生成“任务未完成”;执行失败与回写失败独立保留。模型选择缺失、不完整、混用、`null` 和空白值在读画布及产生草稿 / 审批 / 收费任务前拒绝,返回字段级修正信息;未知字段继续拒绝,不自动选择模型或重放收费任务。 diff --git a/plugin-packages/a6api.yingce-plugin b/plugin-packages/a6api.yingce-plugin index cd70adef5..1414493ce 100644 Binary files a/plugin-packages/a6api.yingce-plugin and b/plugin-packages/a6api.yingce-plugin differ diff --git a/plugin-packages/antigravity-proxy.yingce-plugin b/plugin-packages/antigravity-proxy.yingce-plugin index f5ad9ab1f..d7ed5de73 100644 Binary files a/plugin-packages/antigravity-proxy.yingce-plugin and b/plugin-packages/antigravity-proxy.yingce-plugin differ diff --git a/plugin-packages/metaso-h3.yingce-plugin b/plugin-packages/metaso-h3.yingce-plugin index 6b4ece702..f2aea8239 100644 Binary files a/plugin-packages/metaso-h3.yingce-plugin and b/plugin-packages/metaso-h3.yingce-plugin differ diff --git a/plugin-packages/src-a6api/README.md b/plugin-packages/src-a6api/README.md index 7bb76ee60..afeacbe92 100644 --- a/plugin-packages/src-a6api/README.md +++ b/plugin-packages/src-a6api/README.md @@ -17,4 +17,4 @@ A6api 模型网关协议插件。统一入口 `https://api.a6api.com`,OpenAI - 模型名以 A6api 模型市场当前列表为准。 - 图像编辑(带参考图)走 `/images/edits` multipart 请求。 -- 错误体为 OpenAI 风格,携带 `request_id`。 \ No newline at end of file +- 错误体为 OpenAI 风格,携带 `request_id`。 diff --git a/plugin-packages/src-a6api/docs/interface.md b/plugin-packages/src-a6api/docs/interface.md index 48bade060..d50b716d3 100644 --- a/plugin-packages/src-a6api/docs/interface.md +++ b/plugin-packages/src-a6api/docs/interface.md @@ -26,4 +26,497 @@ POST `https://api.a6api.com/images/edits`(multipart,带参考图时使用) ## 模型列表 -GET `https://api.a6api.com/models` \ No newline at end of file +GET `https://api.a6api.com/models` + + +## Manifest 完整接口定义 + +以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。 + +```json +{ + "apiVersion": "yingce.plugin/v2", + "id": "a6api", + "name": "A6api", + "version": "1.0.0", + "author": "A6api", + "description": "A6api 模型网关协议插件:OpenAI 兼容对话与图像生成。", + "permissions": [ + "generation.run", + "media.read" + ], + "configuration": { + "fields": [ + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } + ] + }, + "contributes": { + "providers": [ + { + "id": "a6api-chat", + "label": "A6api Chat", + "capabilities": [ + "text" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "https://api.a6api.com", + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "A6api 模型市场中的模型 ID。" + }, + { + "name": "messages", + "type": "message[]", + "required": true, + "mapping": "provider message container", + "description": "包含历史消息和当前用户输入。" + }, + { + "name": "instructions", + "type": "string", + "required": false, + "mapping": "system/instructions", + "description": "系统指令。" + }, + { + "name": "temperature", + "type": "number", + "required": false, + "mapping": "temperature", + "description": "采样温度。" + }, + { + "name": "top_p", + "type": "number", + "required": false, + "mapping": "top_p", + "description": "核采样参数。" + }, + { + "name": "max_tokens", + "type": "integer", + "required": false, + "mapping": "max_tokens/max_output_tokens", + "description": "最大输出 token。" + }, + { + "name": "tools", + "type": "array", + "required": false, + "mapping": "tools/toolConfig", + "description": "工具定义。" + }, + { + "name": "tool_choice", + "type": "object|string", + "required": false, + "mapping": "tool_choice", + "description": "工具选择策略。" + }, + { + "name": "response_format", + "type": "object", + "required": false, + "mapping": "response_format/text", + "description": "结构化输出配置。" + }, + { + "name": "stream", + "type": "boolean", + "required": false, + "mapping": "stream", + "description": "流式开关;后台任务当前以最终响应归一。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } + ], + "create": { + "method": "POST", + "path": "/chat/completions", + "contentType": "application/json", + "body": { + "model": { + "$ref": "request.model" + }, + "messages": { + "$ref": "request.messages" + }, + "temperature": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.temperature" + } + }, + "top_p": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.top_p" + } + }, + "max_tokens": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.extra.max_tokens" + }, + { + "$ref": "request.providerOptions.a6api-chat.max_tokens" + } + ] + } + }, + "tools": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.tools" + } + }, + "tool_choice": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.tool_choice" + } + }, + "response_format": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.response_format" + } + }, + "stream": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.stream" + } + }, + "stop": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.stop" + } + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.seed" + } + }, + "frequency_penalty": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.frequency_penalty" + } + }, + "presence_penalty": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.presence_penalty" + } + }, + "user": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.user" + } + } + } + }, + "response": { + "status": "succeeded", + "textPaths": [ + "choices.0.message.content", + "choices.0.text" + ], + "reasoningPaths": [ + "choices.0.message.reasoning_content" + ], + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "messagePaths": [ + "error.message" + ] + } + }, + { + "id": "a6api-image", + "label": "A6api Image", + "capabilities": [ + "image" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "https://api.a6api.com", + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "A6api 模型市场中的图像模型 ID。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "prompt", + "description": "图片提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "provider image/reference fields", + "description": "参考图或编辑源图,role 由业务层确定。" + }, + { + "name": "imageCount", + "type": "integer", + "required": false, + "mapping": "n/sample_count", + "description": "输出数量。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "size/aspect_ratio", + "description": "比例或尺寸,语义按协议说明。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution/imageSize", + "description": "分辨率档位。" + }, + { + "name": "quality", + "type": "string", + "required": false, + "mapping": "quality", + "description": "质量档位。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } + ], + "create": { + "method": "POST", + "path": "/images/generations", + "pathTemplate": { + "$if": { + "condition": { + "$gt": [ + { + "$len": { + "$ref": "request.images" + } + }, + 0 + ] + }, + "then": "/images/edits", + "else": "/images/generations" + } + }, + "contentType": "application/json", + "contentTypeTemplate": { + "$if": { + "condition": { + "$gt": [ + { + "$len": { + "$ref": "request.images" + } + }, + 0 + ] + }, + "then": "multipart/form-data", + "else": "application/json" + } + }, + "body": { + "model": { + "$ref": "request.model" + }, + "prompt": { + "$ref": "request.prompt" + }, + "n": { + "$omitEmpty": { + "$if": { + "condition": { + "$gt": [ + { + "$ref": "request.imageCount" + }, + 0 + ] + }, + "then": { + "$ref": "request.imageCount" + }, + "else": 1 + } + } + }, + "size": { + "$omitEmpty": { + "$ref": "request.aspectRatio" + } + }, + "quality": { + "$omitEmpty": { + "$ref": "request.quality" + } + }, + "output_format": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.providerOptions.a6api-image.output_format" + }, + "png" + ] + } + }, + "response_format": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.providerOptions.a6api-image.response_format" + }, + "b64_json" + ] + } + }, + "user": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-image.user" + } + } + }, + "files": [ + { + "name": "image", + "source": { + "$filter": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "where": { + "$ne": [ + { + "$ref": "media.role" + }, + "mask" + ] + } + } + }, + "filename": "source.png" + }, + { + "name": "mask", + "source": { + "$filter": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "where": { + "$eq": [ + { + "$ref": "media.role" + }, + "mask" + ] + } + } + }, + "filename": "mask.png" + } + ] + }, + "response": { + "status": "succeeded", + "images": { + "$map": { + "from": { + "$ref": "response.data" + }, + "as": "item", + "in": { + "url": { + "$omitEmpty": { + "$ref": "item.url" + } + }, + "dataUrl": { + "$if": { + "condition": { + "$ref": "item.b64_json" + }, + "then": { + "$concat": [ + "data:image/png;base64,", + { + "$ref": "item.b64_json" + } + ] + }, + "else": null + } + } + } + } + }, + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "messagePaths": [ + "error.message" + ] + } + } + ] + }, + "documentation": "<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>" +} +``` + diff --git a/plugin-packages/src-a6api/manifest.json b/plugin-packages/src-a6api/manifest.json index 8bb12ca02..2278f2780 100644 --- a/plugin-packages/src-a6api/manifest.json +++ b/plugin-packages/src-a6api/manifest.json @@ -5,10 +5,18 @@ "version": "1.0.0", "author": "A6api", "description": "A6api 模型网关协议插件:OpenAI 兼容对话与图像生成。", - "permissions": ["generation.run", "media.read"], + "permissions": [ + "generation.run", + "media.read" + ], "configuration": { "fields": [ - { "name": "apiKey", "type": "secret", "label": "API Key", "required": true } + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } ] }, "contributes": { @@ -16,76 +24,291 @@ { "id": "a6api-chat", "label": "A6api Chat", - "capabilities": ["text"], - "scopes": ["admin.system-channel", "user.custom-channel", "canvas", "creation", "agent"], + "capabilities": [ + "text" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], "baseUrl": "https://api.a6api.com", - "auth": { "type": "bearer", "field": "apiKey" }, + "auth": { + "type": "bearer", + "field": "apiKey" + }, "parameters": [ - { "name": "model", "type": "string", "required": true, "mapping": "model", "description": "A6api 模型市场中的模型 ID。" }, - { "name": "messages", "type": "message[]", "required": true, "mapping": "provider message container", "description": "包含历史消息和当前用户输入。" }, - { "name": "instructions", "type": "string", "required": false, "mapping": "system/instructions", "description": "系统指令。" }, - { "name": "temperature", "type": "number", "required": false, "mapping": "temperature", "description": "采样温度。" }, - { "name": "top_p", "type": "number", "required": false, "mapping": "top_p", "description": "核采样参数。" }, - { "name": "max_tokens", "type": "integer", "required": false, "mapping": "max_tokens/max_output_tokens", "description": "最大输出 token。" }, - { "name": "tools", "type": "array", "required": false, "mapping": "tools/toolConfig", "description": "工具定义。" }, - { "name": "tool_choice", "type": "object|string", "required": false, "mapping": "tool_choice", "description": "工具选择策略。" }, - { "name": "response_format", "type": "object", "required": false, "mapping": "response_format/text", "description": "结构化输出配置。" }, - { "name": "stream", "type": "boolean", "required": false, "mapping": "stream", "description": "流式开关;后台任务当前以最终响应归一。" }, - { "name": "providerOptions", "type": "object", "required": false, "mapping": "provider-specific fields", "description": "插件命名空间内的厂商扩展字段。" } + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "A6api 模型市场中的模型 ID。" + }, + { + "name": "messages", + "type": "message[]", + "required": true, + "mapping": "provider message container", + "description": "包含历史消息和当前用户输入。" + }, + { + "name": "instructions", + "type": "string", + "required": false, + "mapping": "system/instructions", + "description": "系统指令。" + }, + { + "name": "temperature", + "type": "number", + "required": false, + "mapping": "temperature", + "description": "采样温度。" + }, + { + "name": "top_p", + "type": "number", + "required": false, + "mapping": "top_p", + "description": "核采样参数。" + }, + { + "name": "max_tokens", + "type": "integer", + "required": false, + "mapping": "max_tokens/max_output_tokens", + "description": "最大输出 token。" + }, + { + "name": "tools", + "type": "array", + "required": false, + "mapping": "tools/toolConfig", + "description": "工具定义。" + }, + { + "name": "tool_choice", + "type": "object|string", + "required": false, + "mapping": "tool_choice", + "description": "工具选择策略。" + }, + { + "name": "response_format", + "type": "object", + "required": false, + "mapping": "response_format/text", + "description": "结构化输出配置。" + }, + { + "name": "stream", + "type": "boolean", + "required": false, + "mapping": "stream", + "description": "流式开关;后台任务当前以最终响应归一。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } ], "create": { "method": "POST", "path": "/chat/completions", "contentType": "application/json", "body": { - "model": { "$ref": "request.model" }, - "messages": { "$ref": "request.messages" }, - "temperature": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.temperature" } }, - "top_p": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.top_p" } }, - "max_tokens": { "$omitEmpty": { "$coalesce": [ { "$ref": "request.extra.max_tokens" }, { "$ref": "request.providerOptions.a6api-chat.max_tokens" } ] } }, - "tools": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.tools" } }, - "tool_choice": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.tool_choice" } }, - "response_format": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.response_format" } }, - "stream": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.stream" } }, - "stop": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.stop" } }, - "seed": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.seed" } }, - "frequency_penalty": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.frequency_penalty" } }, - "presence_penalty": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.presence_penalty" } }, - "user": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-chat.user" } } + "model": { + "$ref": "request.model" + }, + "messages": { + "$ref": "request.messages" + }, + "temperature": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.temperature" + } + }, + "top_p": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.top_p" + } + }, + "max_tokens": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.extra.max_tokens" + }, + { + "$ref": "request.providerOptions.a6api-chat.max_tokens" + } + ] + } + }, + "tools": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.tools" + } + }, + "tool_choice": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.tool_choice" + } + }, + "response_format": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.response_format" + } + }, + "stream": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.stream" + } + }, + "stop": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.stop" + } + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.seed" + } + }, + "frequency_penalty": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.frequency_penalty" + } + }, + "presence_penalty": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.presence_penalty" + } + }, + "user": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-chat.user" + } + } } }, "response": { "status": "succeeded", - "textPaths": ["choices.0.message.content", "choices.0.text"], - "reasoningPaths": ["choices.0.message.reasoning_content"], - "usage": { "$ref": "response.usage" }, - "errorPaths": ["error.code"], - "messagePaths": ["error.message"] + "textPaths": [ + "choices.0.message.content", + "choices.0.text" + ], + "reasoningPaths": [ + "choices.0.message.reasoning_content" + ], + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "messagePaths": [ + "error.message" + ] } }, { "id": "a6api-image", "label": "A6api Image", - "capabilities": ["image"], - "scopes": ["admin.system-channel", "user.custom-channel", "canvas", "creation", "agent"], + "capabilities": [ + "image" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], "baseUrl": "https://api.a6api.com", - "auth": { "type": "bearer", "field": "apiKey" }, + "auth": { + "type": "bearer", + "field": "apiKey" + }, "parameters": [ - { "name": "model", "type": "string", "required": true, "mapping": "model", "description": "A6api 模型市场中的图像模型 ID。" }, - { "name": "prompt", "type": "string", "required": true, "mapping": "prompt", "description": "图片提示词。" }, - { "name": "images", "type": "media[]", "required": false, "mapping": "provider image/reference fields", "description": "参考图或编辑源图,role 由业务层确定。" }, - { "name": "imageCount", "type": "integer", "required": false, "mapping": "n/sample_count", "description": "输出数量。" }, - { "name": "aspectRatio", "type": "string", "required": false, "mapping": "size/aspect_ratio", "description": "比例或尺寸,语义按协议说明。" }, - { "name": "resolution", "type": "string", "required": false, "mapping": "resolution/imageSize", "description": "分辨率档位。" }, - { "name": "quality", "type": "string", "required": false, "mapping": "quality", "description": "质量档位。" }, - { "name": "providerOptions", "type": "object", "required": false, "mapping": "provider-specific fields", "description": "插件命名空间内的厂商扩展字段。" } + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "A6api 模型市场中的图像模型 ID。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "prompt", + "description": "图片提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "provider image/reference fields", + "description": "参考图或编辑源图,role 由业务层确定。" + }, + { + "name": "imageCount", + "type": "integer", + "required": false, + "mapping": "n/sample_count", + "description": "输出数量。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "size/aspect_ratio", + "description": "比例或尺寸,语义按协议说明。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution/imageSize", + "description": "分辨率档位。" + }, + { + "name": "quality", + "type": "string", + "required": false, + "mapping": "quality", + "description": "质量档位。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } ], "create": { "method": "POST", "path": "/images/generations", "pathTemplate": { "$if": { - "condition": { "$gt": [ { "$len": { "$ref": "request.images" } }, 0 ] }, + "condition": { + "$gt": [ + { + "$len": { + "$ref": "request.images" + } + }, + 0 + ] + }, "then": "/images/edits", "else": "/images/generations" } @@ -93,30 +316,120 @@ "contentType": "application/json", "contentTypeTemplate": { "$if": { - "condition": { "$gt": [ { "$len": { "$ref": "request.images" } }, 0 ] }, + "condition": { + "$gt": [ + { + "$len": { + "$ref": "request.images" + } + }, + 0 + ] + }, "then": "multipart/form-data", "else": "application/json" } }, "body": { - "model": { "$ref": "request.model" }, - "prompt": { "$ref": "request.prompt" }, - "n": { "$omitEmpty": { "$if": { "condition": { "$gt": [ { "$ref": "request.imageCount" }, 0 ] }, "then": { "$ref": "request.imageCount" }, "else": 1 } } }, - "size": { "$omitEmpty": { "$ref": "request.aspectRatio" } }, - "quality": { "$omitEmpty": { "$ref": "request.quality" } }, - "output_format": { "$omitEmpty": { "$coalesce": [ { "$ref": "request.providerOptions.a6api-image.output_format" }, "png" ] } }, - "response_format": { "$omitEmpty": { "$coalesce": [ { "$ref": "request.providerOptions.a6api-image.response_format" }, "b64_json" ] } }, - "user": { "$omitEmpty": { "$ref": "request.providerOptions.a6api-image.user" } } + "model": { + "$ref": "request.model" + }, + "prompt": { + "$ref": "request.prompt" + }, + "n": { + "$omitEmpty": { + "$if": { + "condition": { + "$gt": [ + { + "$ref": "request.imageCount" + }, + 0 + ] + }, + "then": { + "$ref": "request.imageCount" + }, + "else": 1 + } + } + }, + "size": { + "$omitEmpty": { + "$ref": "request.aspectRatio" + } + }, + "quality": { + "$omitEmpty": { + "$ref": "request.quality" + } + }, + "output_format": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.providerOptions.a6api-image.output_format" + }, + "png" + ] + } + }, + "response_format": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.providerOptions.a6api-image.response_format" + }, + "b64_json" + ] + } + }, + "user": { + "$omitEmpty": { + "$ref": "request.providerOptions.a6api-image.user" + } + } }, "files": [ { "name": "image", - "source": { "$filter": { "from": { "$ref": "request.images" }, "as": "media", "where": { "$ne": [ { "$ref": "media.role" }, "mask" ] } } }, + "source": { + "$filter": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "where": { + "$ne": [ + { + "$ref": "media.role" + }, + "mask" + ] + } + } + }, "filename": "source.png" }, { "name": "mask", - "source": { "$filter": { "from": { "$ref": "request.images" }, "as": "media", "where": { "$eq": [ { "$ref": "media.role" }, "mask" ] } } }, + "source": { + "$filter": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "where": { + "$eq": [ + { + "$ref": "media.role" + }, + "mask" + ] + } + } + }, "filename": "mask.png" } ] @@ -125,19 +438,47 @@ "status": "succeeded", "images": { "$map": { - "from": { "$ref": "response.data" }, + "from": { + "$ref": "response.data" + }, "as": "item", "in": { - "url": { "$omitEmpty": { "$ref": "item.url" } }, - "dataUrl": { "$if": { "condition": { "$ref": "item.b64_json" }, "then": { "$concat": [ "data:image/png;base64,", { "$ref": "item.b64_json" } ] }, "else": null } } + "url": { + "$omitEmpty": { + "$ref": "item.url" + } + }, + "dataUrl": { + "$if": { + "condition": { + "$ref": "item.b64_json" + }, + "then": { + "$concat": [ + "data:image/png;base64,", + { + "$ref": "item.b64_json" + } + ] + }, + "else": null + } + } } } }, - "usage": { "$ref": "response.usage" }, - "errorPaths": ["error.code"], - "messagePaths": ["error.message"] + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "messagePaths": [ + "error.message" + ] } } ] - } -} \ No newline at end of file + }, + "documentation": "# A6api\n\nA6api 模型网关协议插件。统一入口 `https://api.a6api.com`,OpenAI 兼容(`Authorization: Bearer `)。\n\n## Providers\n\n| Provider | 能力 | 端点 |\n|---|---|---|\n| a6api-chat | text | POST /chat/completions |\n| a6api-image | image | POST /images/generations、POST /images/edits |\n\n## 配置\n\n在渠道中填写 API Key(A6api 控制台创建,形如 `sk-xxxxxxxx`),baseUrl 使用 `https://api.a6api.com`。\n\n## 说明\n\n- 模型名以 A6api 模型市场当前列表为准。\n- 图像编辑(带参考图)走 `/images/edits` multipart 请求。\n- 错误体为 OpenAI 风格,携带 `request_id`。\n\n---\n\n# A6api 接口说明\n\n## 鉴权\n\n`Authorization: Bearer sk-xxxxxxxxxxxxxxxxxxxxxxxx`\n\n## 文本对话\n\nPOST `https://api.a6api.com/chat/completions`\n\n请求体 OpenAI Chat Completions 格式:`model`、`messages`、`temperature`、`max_tokens`、`tools`、`tool_choice`、`response_format`、`stream` 等。\n\n响应 `choices[0].message.content` 为正文,`choices[0].message.reasoning_content` 为推理内容,`usage` 为用量。\n\n## 图像生成\n\nPOST `https://api.a6api.com/images/generations`\n\n请求体:`model`、`prompt`、`n`、`size`、`quality`、`response_format`。\n\n响应 `data[].url` 或 `data[].b64_json`。\n\n## 图像编辑\n\nPOST `https://api.a6api.com/images/edits`(multipart,带参考图时使用)\n\n## 模型列表\n\nGET `https://api.a6api.com/models`\n\n\n## Manifest 完整接口定义\n\n以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。\n\n```json\n{\n \"apiVersion\": \"yingce.plugin/v2\",\n \"id\": \"a6api\",\n \"name\": \"A6api\",\n \"version\": \"1.0.0\",\n \"author\": \"A6api\",\n \"description\": \"A6api 模型网关协议插件:OpenAI 兼容对话与图像生成。\",\n \"permissions\": [\n \"generation.run\",\n \"media.read\"\n ],\n \"configuration\": {\n \"fields\": [\n {\n \"name\": \"apiKey\",\n \"type\": \"secret\",\n \"label\": \"API Key\",\n \"required\": true\n }\n ]\n },\n \"contributes\": {\n \"providers\": [\n {\n \"id\": \"a6api-chat\",\n \"label\": \"A6api Chat\",\n \"capabilities\": [\n \"text\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"https://api.a6api.com\",\n \"auth\": {\n \"type\": \"bearer\",\n \"field\": \"apiKey\"\n },\n \"parameters\": [\n {\n \"name\": \"model\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"model\",\n \"description\": \"A6api 模型市场中的模型 ID。\"\n },\n {\n \"name\": \"messages\",\n \"type\": \"message[]\",\n \"required\": true,\n \"mapping\": \"provider message container\",\n \"description\": \"包含历史消息和当前用户输入。\"\n },\n {\n \"name\": \"instructions\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"system/instructions\",\n \"description\": \"系统指令。\"\n },\n {\n \"name\": \"temperature\",\n \"type\": \"number\",\n \"required\": false,\n \"mapping\": \"temperature\",\n \"description\": \"采样温度。\"\n },\n {\n \"name\": \"top_p\",\n \"type\": \"number\",\n \"required\": false,\n \"mapping\": \"top_p\",\n \"description\": \"核采样参数。\"\n },\n {\n \"name\": \"max_tokens\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"max_tokens/max_output_tokens\",\n \"description\": \"最大输出 token。\"\n },\n {\n \"name\": \"tools\",\n \"type\": \"array\",\n \"required\": false,\n \"mapping\": \"tools/toolConfig\",\n \"description\": \"工具定义。\"\n },\n {\n \"name\": \"tool_choice\",\n \"type\": \"object|string\",\n \"required\": false,\n \"mapping\": \"tool_choice\",\n \"description\": \"工具选择策略。\"\n },\n {\n \"name\": \"response_format\",\n \"type\": \"object\",\n \"required\": false,\n \"mapping\": \"response_format/text\",\n \"description\": \"结构化输出配置。\"\n },\n {\n \"name\": \"stream\",\n \"type\": \"boolean\",\n \"required\": false,\n \"mapping\": \"stream\",\n \"description\": \"流式开关;后台任务当前以最终响应归一。\"\n },\n {\n \"name\": \"providerOptions\",\n \"type\": \"object\",\n \"required\": false,\n \"mapping\": \"provider-specific fields\",\n \"description\": \"插件命名空间内的厂商扩展字段。\"\n }\n ],\n \"create\": {\n \"method\": \"POST\",\n \"path\": \"/chat/completions\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"messages\": {\n \"$ref\": \"request.messages\"\n },\n \"temperature\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.temperature\"\n }\n },\n \"top_p\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.top_p\"\n }\n },\n \"max_tokens\": {\n \"$omitEmpty\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.extra.max_tokens\"\n },\n {\n \"$ref\": \"request.providerOptions.a6api-chat.max_tokens\"\n }\n ]\n }\n },\n \"tools\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.tools\"\n }\n },\n \"tool_choice\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.tool_choice\"\n }\n },\n \"response_format\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.response_format\"\n }\n },\n \"stream\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.stream\"\n }\n },\n \"stop\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.stop\"\n }\n },\n \"seed\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.seed\"\n }\n },\n \"frequency_penalty\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.frequency_penalty\"\n }\n },\n \"presence_penalty\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.presence_penalty\"\n }\n },\n \"user\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-chat.user\"\n }\n }\n }\n },\n \"response\": {\n \"status\": \"succeeded\",\n \"textPaths\": [\n \"choices.0.message.content\",\n \"choices.0.text\"\n ],\n \"reasoningPaths\": [\n \"choices.0.message.reasoning_content\"\n ],\n \"usage\": {\n \"$ref\": \"response.usage\"\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"messagePaths\": [\n \"error.message\"\n ]\n }\n },\n {\n \"id\": \"a6api-image\",\n \"label\": \"A6api Image\",\n \"capabilities\": [\n \"image\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"https://api.a6api.com\",\n \"auth\": {\n \"type\": \"bearer\",\n \"field\": \"apiKey\"\n },\n \"parameters\": [\n {\n \"name\": \"model\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"model\",\n \"description\": \"A6api 模型市场中的图像模型 ID。\"\n },\n {\n \"name\": \"prompt\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"prompt\",\n \"description\": \"图片提示词。\"\n },\n {\n \"name\": \"images\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"provider image/reference fields\",\n \"description\": \"参考图或编辑源图,role 由业务层确定。\"\n },\n {\n \"name\": \"imageCount\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"n/sample_count\",\n \"description\": \"输出数量。\"\n },\n {\n \"name\": \"aspectRatio\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"size/aspect_ratio\",\n \"description\": \"比例或尺寸,语义按协议说明。\"\n },\n {\n \"name\": \"resolution\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"resolution/imageSize\",\n \"description\": \"分辨率档位。\"\n },\n {\n \"name\": \"quality\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"quality\",\n \"description\": \"质量档位。\"\n },\n {\n \"name\": \"providerOptions\",\n \"type\": \"object\",\n \"required\": false,\n \"mapping\": \"provider-specific fields\",\n \"description\": \"插件命名空间内的厂商扩展字段。\"\n }\n ],\n \"create\": {\n \"method\": \"POST\",\n \"path\": \"/images/generations\",\n \"pathTemplate\": {\n \"$if\": {\n \"condition\": {\n \"$gt\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 0\n ]\n },\n \"then\": \"/images/edits\",\n \"else\": \"/images/generations\"\n }\n },\n \"contentType\": \"application/json\",\n \"contentTypeTemplate\": {\n \"$if\": {\n \"condition\": {\n \"$gt\": [\n {\n \"$len\": {\n \"$ref\": \"request.images\"\n }\n },\n 0\n ]\n },\n \"then\": \"multipart/form-data\",\n \"else\": \"application/json\"\n }\n },\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"prompt\": {\n \"$ref\": \"request.prompt\"\n },\n \"n\": {\n \"$omitEmpty\": {\n \"$if\": {\n \"condition\": {\n \"$gt\": [\n {\n \"$ref\": \"request.imageCount\"\n },\n 0\n ]\n },\n \"then\": {\n \"$ref\": \"request.imageCount\"\n },\n \"else\": 1\n }\n }\n },\n \"size\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.aspectRatio\"\n }\n },\n \"quality\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.quality\"\n }\n },\n \"output_format\": {\n \"$omitEmpty\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.providerOptions.a6api-image.output_format\"\n },\n \"png\"\n ]\n }\n },\n \"response_format\": {\n \"$omitEmpty\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.providerOptions.a6api-image.response_format\"\n },\n \"b64_json\"\n ]\n }\n },\n \"user\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.a6api-image.user\"\n }\n }\n },\n \"files\": [\n {\n \"name\": \"image\",\n \"source\": {\n \"$filter\": {\n \"from\": {\n \"$ref\": \"request.images\"\n },\n \"as\": \"media\",\n \"where\": {\n \"$ne\": [\n {\n \"$ref\": \"media.role\"\n },\n \"mask\"\n ]\n }\n }\n },\n \"filename\": \"source.png\"\n },\n {\n \"name\": \"mask\",\n \"source\": {\n \"$filter\": {\n \"from\": {\n \"$ref\": \"request.images\"\n },\n \"as\": \"media\",\n \"where\": {\n \"$eq\": [\n {\n \"$ref\": \"media.role\"\n },\n \"mask\"\n ]\n }\n }\n },\n \"filename\": \"mask.png\"\n }\n ]\n },\n \"response\": {\n \"status\": \"succeeded\",\n \"images\": {\n \"$map\": {\n \"from\": {\n \"$ref\": \"response.data\"\n },\n \"as\": \"item\",\n \"in\": {\n \"url\": {\n \"$omitEmpty\": {\n \"$ref\": \"item.url\"\n }\n },\n \"dataUrl\": {\n \"$if\": {\n \"condition\": {\n \"$ref\": \"item.b64_json\"\n },\n \"then\": {\n \"$concat\": [\n \"data:image/png;base64,\",\n {\n \"$ref\": \"item.b64_json\"\n }\n ]\n },\n \"else\": null\n }\n }\n }\n }\n },\n \"usage\": {\n \"$ref\": \"response.usage\"\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"messagePaths\": [\n \"error.message\"\n ]\n }\n }\n ]\n },\n \"documentation\": \"<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>\"\n}\n```\n\n" +} diff --git a/plugin-packages/src-antigravity-proxy/docs/interface.md b/plugin-packages/src-antigravity-proxy/docs/interface.md index 5a19a4f61..66f7d83c9 100644 --- a/plugin-packages/src-antigravity-proxy/docs/interface.md +++ b/plugin-packages/src-antigravity-proxy/docs/interface.md @@ -68,3 +68,236 @@ ## 兼容边界 该包只代表 Antigravity 中转渠道的 OpenAI Chat Completions 线协议;其他端点或网关包装必须使用独立插件。 + + +## Manifest 完整接口定义 + +以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。 + +```json +{ + "apiVersion": "yingce.plugin/v2", + "id": "antigravity-proxy", + "name": "Antigravity Proxy", + "version": "1.0.0", + "author": "Yingce", + "description": "Antigravity 中转渠道插件:OpenAI 兼容对话(gemini-3.8-flash-high / gemini-pro-agent)。", + "permissions": [ + "generation.run", + "media.read" + ], + "configuration": { + "fields": [ + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } + ] + }, + "contributes": { + "providers": [ + { + "id": "antigravity-chat", + "label": "Antigravity Chat", + "capabilities": [ + "text" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "http://103.242.14.110:8317", + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "模型 ID(gemini-3.8-flash-high / gemini-pro-agent)。" + }, + { + "name": "messages", + "type": "message[]", + "required": true, + "mapping": "provider message container", + "description": "包含历史消息和当前用户输入。" + }, + { + "name": "instructions", + "type": "string", + "required": false, + "mapping": "system/instructions", + "description": "系统指令。" + }, + { + "name": "temperature", + "type": "number", + "required": false, + "mapping": "temperature", + "description": "采样温度。" + }, + { + "name": "top_p", + "type": "number", + "required": false, + "mapping": "top_p", + "description": "核采样参数。" + }, + { + "name": "max_tokens", + "type": "integer", + "required": false, + "mapping": "max_tokens/max_output_tokens", + "description": "最大输出 token。" + }, + { + "name": "tools", + "type": "array", + "required": false, + "mapping": "tools/toolConfig", + "description": "工具定义。" + }, + { + "name": "tool_choice", + "type": "object|string", + "required": false, + "mapping": "tool_choice", + "description": "工具选择策略。" + }, + { + "name": "response_format", + "type": "object", + "required": false, + "mapping": "response_format/text", + "description": "结构化输出配置。" + }, + { + "name": "stream", + "type": "boolean", + "required": false, + "mapping": "stream", + "description": "流式开关;后台任务当前以最终响应归一。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } + ], + "create": { + "method": "POST", + "path": "/chat/completions", + "contentType": "application/json", + "body": { + "model": { + "$ref": "request.model" + }, + "messages": { + "$ref": "request.messages" + }, + "temperature": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.temperature" + } + }, + "top_p": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.top_p" + } + }, + "max_tokens": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.extra.max_tokens" + }, + { + "$ref": "request.providerOptions.antigravity-chat.max_tokens" + } + ] + } + }, + "tools": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.tools" + } + }, + "tool_choice": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.tool_choice" + } + }, + "response_format": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.response_format" + } + }, + "stream": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.stream" + } + }, + "stop": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.stop" + } + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.seed" + } + }, + "frequency_penalty": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.frequency_penalty" + } + }, + "presence_penalty": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.presence_penalty" + } + }, + "user": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.user" + } + } + } + }, + "response": { + "status": "succeeded", + "textPaths": [ + "choices.0.message.content", + "choices.0.text" + ], + "reasoningPaths": [ + "choices.0.message.reasoning_content" + ], + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "messagePaths": [ + "error.message" + ] + } + } + ] + }, + "documentation": "<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>" +} +``` + diff --git a/plugin-packages/src-antigravity-proxy/manifest.json b/plugin-packages/src-antigravity-proxy/manifest.json index 290fd46b2..e914d6856 100644 --- a/plugin-packages/src-antigravity-proxy/manifest.json +++ b/plugin-packages/src-antigravity-proxy/manifest.json @@ -5,10 +5,18 @@ "version": "1.0.0", "author": "Yingce", "description": "Antigravity 中转渠道插件:OpenAI 兼容对话(gemini-3.8-flash-high / gemini-pro-agent)。", - "permissions": ["generation.run", "media.read"], + "permissions": [ + "generation.run", + "media.read" + ], "configuration": { "fields": [ - { "name": "apiKey", "type": "secret", "label": "API Key", "required": true } + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } ] }, "contributes": { @@ -16,53 +24,201 @@ { "id": "antigravity-chat", "label": "Antigravity Chat", - "capabilities": ["text"], - "scopes": ["admin.system-channel", "user.custom-channel", "canvas", "creation", "agent"], + "capabilities": [ + "text" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], "baseUrl": "http://103.242.14.110:8317", - "auth": { "type": "bearer", "field": "apiKey" }, + "auth": { + "type": "bearer", + "field": "apiKey" + }, "parameters": [ - { "name": "model", "type": "string", "required": true, "mapping": "model", "description": "模型 ID(gemini-3.8-flash-high / gemini-pro-agent)。" }, - { "name": "messages", "type": "message[]", "required": true, "mapping": "provider message container", "description": "包含历史消息和当前用户输入。" }, - { "name": "instructions", "type": "string", "required": false, "mapping": "system/instructions", "description": "系统指令。" }, - { "name": "temperature", "type": "number", "required": false, "mapping": "temperature", "description": "采样温度。" }, - { "name": "top_p", "type": "number", "required": false, "mapping": "top_p", "description": "核采样参数。" }, - { "name": "max_tokens", "type": "integer", "required": false, "mapping": "max_tokens/max_output_tokens", "description": "最大输出 token。" }, - { "name": "tools", "type": "array", "required": false, "mapping": "tools/toolConfig", "description": "工具定义。" }, - { "name": "tool_choice", "type": "object|string", "required": false, "mapping": "tool_choice", "description": "工具选择策略。" }, - { "name": "response_format", "type": "object", "required": false, "mapping": "response_format/text", "description": "结构化输出配置。" }, - { "name": "stream", "type": "boolean", "required": false, "mapping": "stream", "description": "流式开关;后台任务当前以最终响应归一。" }, - { "name": "providerOptions", "type": "object", "required": false, "mapping": "provider-specific fields", "description": "插件命名空间内的厂商扩展字段。" } + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "模型 ID(gemini-3.8-flash-high / gemini-pro-agent)。" + }, + { + "name": "messages", + "type": "message[]", + "required": true, + "mapping": "provider message container", + "description": "包含历史消息和当前用户输入。" + }, + { + "name": "instructions", + "type": "string", + "required": false, + "mapping": "system/instructions", + "description": "系统指令。" + }, + { + "name": "temperature", + "type": "number", + "required": false, + "mapping": "temperature", + "description": "采样温度。" + }, + { + "name": "top_p", + "type": "number", + "required": false, + "mapping": "top_p", + "description": "核采样参数。" + }, + { + "name": "max_tokens", + "type": "integer", + "required": false, + "mapping": "max_tokens/max_output_tokens", + "description": "最大输出 token。" + }, + { + "name": "tools", + "type": "array", + "required": false, + "mapping": "tools/toolConfig", + "description": "工具定义。" + }, + { + "name": "tool_choice", + "type": "object|string", + "required": false, + "mapping": "tool_choice", + "description": "工具选择策略。" + }, + { + "name": "response_format", + "type": "object", + "required": false, + "mapping": "response_format/text", + "description": "结构化输出配置。" + }, + { + "name": "stream", + "type": "boolean", + "required": false, + "mapping": "stream", + "description": "流式开关;后台任务当前以最终响应归一。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } ], "create": { "method": "POST", "path": "/chat/completions", "contentType": "application/json", "body": { - "model": { "$ref": "request.model" }, - "messages": { "$ref": "request.messages" }, - "temperature": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.temperature" } }, - "top_p": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.top_p" } }, - "max_tokens": { "$omitEmpty": { "$coalesce": [ { "$ref": "request.extra.max_tokens" }, { "$ref": "request.providerOptions.antigravity-chat.max_tokens" } ] } }, - "tools": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.tools" } }, - "tool_choice": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.tool_choice" } }, - "response_format": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.response_format" } }, - "stream": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.stream" } }, - "stop": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.stop" } }, - "seed": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.seed" } }, - "frequency_penalty": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.frequency_penalty" } }, - "presence_penalty": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.presence_penalty" } }, - "user": { "$omitEmpty": { "$ref": "request.providerOptions.antigravity-chat.user" } } + "model": { + "$ref": "request.model" + }, + "messages": { + "$ref": "request.messages" + }, + "temperature": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.temperature" + } + }, + "top_p": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.top_p" + } + }, + "max_tokens": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.extra.max_tokens" + }, + { + "$ref": "request.providerOptions.antigravity-chat.max_tokens" + } + ] + } + }, + "tools": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.tools" + } + }, + "tool_choice": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.tool_choice" + } + }, + "response_format": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.response_format" + } + }, + "stream": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.stream" + } + }, + "stop": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.stop" + } + }, + "seed": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.seed" + } + }, + "frequency_penalty": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.frequency_penalty" + } + }, + "presence_penalty": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.presence_penalty" + } + }, + "user": { + "$omitEmpty": { + "$ref": "request.providerOptions.antigravity-chat.user" + } + } } }, "response": { "status": "succeeded", - "textPaths": ["choices.0.message.content", "choices.0.text"], - "reasoningPaths": ["choices.0.message.reasoning_content"], - "usage": { "$ref": "response.usage" }, - "errorPaths": ["error.code"], - "messagePaths": ["error.message"] + "textPaths": [ + "choices.0.message.content", + "choices.0.text" + ], + "reasoningPaths": [ + "choices.0.message.reasoning_content" + ], + "usage": { + "$ref": "response.usage" + }, + "errorPaths": [ + "error.code" + ], + "messagePaths": [ + "error.message" + ] } } ] - } + }, + "documentation": "# Antigravity Proxy\n\nAntigravity 中转渠道插件:OpenAI Chat Completions 兼容对话协议。\n\n## 协议身份\n\n- 插件 ID:`antigravity-proxy`\n- Provider ID:`antigravity-chat`\n- 能力:`text`\n- 默认 Base URL:`http://103.242.14.110:8317`\n- 鉴权驱动:`bearer`\n- 创建:`POST /chat/completions`\n- 生命周期:同步响应\n\n## 配置字段\n\n| 字段 | 类型 | 必填 | 含义 |\n| --- | --- | --- | --- |\n| `apiKey` | secret | 是 | 中转渠道 API Key |\n\n## 模型\n\n- `gemini-3.8-flash-high`\n- `gemini-pro-agent`\n\n## 统一字段映射\n\n| 统一字段 | 类型 | 必填 | 上游映射 |\n| --- | --- | --- | --- |\n| `model` | string | 是 | `model` |\n| `messages` | message[] | 是 | `messages` |\n| `instructions` | string | 否 | `system/instructions` |\n| `temperature` | number | 否 | `temperature` |\n| `top_p` | number | 否 | `top_p` |\n| `max_tokens` | integer | 否 | `max_tokens` |\n| `tools` | array | 否 | `tools` |\n| `tool_choice` | object\\|string | 否 | `tool_choice` |\n| `response_format` | object | 否 | `response_format` |\n| `stream` | boolean | 否 | `stream` |\n\n完整接口见 [docs/interface.md](docs/interface.md)。\n\n---\n\n# Antigravity Proxy 接口字段\n\n## 协议身份\n\n- 插件 ID:`antigravity-proxy`\n- Provider ID:`antigravity-chat`\n- 能力:`text`\n- 默认 Base URL:`http://103.242.14.110:8317`\n- 鉴权驱动:`bearer`\n- 创建:`POST /chat/completions`\n- 生命周期:同步响应\n\n## 配置字段\n\n| 字段 | 类型 | 必填 | 含义 |\n| --- | --- | --- | --- |\n| `apiKey` | secret | 是 | 中转渠道 API Key |\n\n## 统一字段映射\n\n| 统一字段 | 类型 | 必填 | 上游映射 | 说明 |\n| --- | --- | --- | --- | --- |\n| `model` | string | 是 | `model` | 上游模型 ID。 |\n| `messages` | message[] | 是 | `messages` | 包含历史消息和当前用户输入。 |\n| `instructions` | string | 否 | `system/instructions` | 系统指令。 |\n| `temperature` | number | 否 | `temperature` | 采样温度。 |\n| `top_p` | number | 否 | `top_p` | 核采样参数。 |\n| `max_tokens` | integer | 否 | `max_tokens/max_output_tokens` | 最大输出 token。 |\n| `tools` | array | 否 | `tools/toolConfig` | 工具定义。 |\n| `tool_choice` | object\\|string | 否 | `tool_choice` | 工具选择策略。 |\n| `response_format` | object | 否 | `response_format/text` | 结构化输出配置。 |\n| `stream` | boolean | 否 | `stream` | 流式开关。 |\n\n## 上游请求模板\n\n| 上游位置 | 值或转换表达式 |\n| --- | --- |\n| `create.method` | `\"POST\"` |\n| `create.path` | `\"/chat/completions\"` |\n| `create.contentType` | `\"application/json\"` |\n| `create.body.model` | `{\"$ref\":\"request.model\"}` |\n| `create.body.messages` | `{\"$ref\":\"request.messages\"}` |\n| `create.body.temperature` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.temperature\"}}` |\n| `create.body.top_p` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.top_p\"}}` |\n| `create.body.max_tokens` | `{\"$omitEmpty\":{\"$coalesce\":[{\"$ref\":\"request.extra.max_tokens\"},{\"$ref\":\"request.providerOptions.antigravity-chat.max_tokens\"}]}}` |\n| `create.body.tools` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.tools\"}}` |\n| `create.body.tool_choice` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.tool_choice\"}}` |\n| `create.body.response_format` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.response_format\"}}` |\n| `create.body.stream` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.stream\"}}` |\n| `create.body.stop` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.stop\"}}` |\n| `create.body.seed` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.seed\"}}` |\n| `create.body.frequency_penalty` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.frequency_penalty\"}}` |\n| `create.body.presence_penalty` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.presence_penalty\"}}` |\n| `create.body.user` | `{\"$omitEmpty\":{\"$ref\":\"request.providerOptions.antigravity-chat.user\"}}` |\n\n## 响应映射\n\n| 映射位置 | 上游路径或转换表达式 |\n| --- | --- |\n| `response.status` | `\"succeeded\"` |\n| `response.textPaths[0]` | `\"choices.0.message.content\"` |\n| `response.textPaths[1]` | `\"choices.0.text\"` |\n| `response.reasoningPaths[0]` | `\"choices.0.message.reasoning_content\"` |\n| `response.usage` | `{\"$ref\":\"response.usage\"}` |\n| `response.errorPaths[0]` | `\"error.code\"` |\n| `response.messagePaths[0]` | `\"error.message\"` |\n\n## 兼容边界\n\n该包只代表 Antigravity 中转渠道的 OpenAI Chat Completions 线协议;其他端点或网关包装必须使用独立插件。\n\n\n## Manifest 完整接口定义\n\n以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。\n\n```json\n{\n \"apiVersion\": \"yingce.plugin/v2\",\n \"id\": \"antigravity-proxy\",\n \"name\": \"Antigravity Proxy\",\n \"version\": \"1.0.0\",\n \"author\": \"Yingce\",\n \"description\": \"Antigravity 中转渠道插件:OpenAI 兼容对话(gemini-3.8-flash-high / gemini-pro-agent)。\",\n \"permissions\": [\n \"generation.run\",\n \"media.read\"\n ],\n \"configuration\": {\n \"fields\": [\n {\n \"name\": \"apiKey\",\n \"type\": \"secret\",\n \"label\": \"API Key\",\n \"required\": true\n }\n ]\n },\n \"contributes\": {\n \"providers\": [\n {\n \"id\": \"antigravity-chat\",\n \"label\": \"Antigravity Chat\",\n \"capabilities\": [\n \"text\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"http://103.242.14.110:8317\",\n \"auth\": {\n \"type\": \"bearer\",\n \"field\": \"apiKey\"\n },\n \"parameters\": [\n {\n \"name\": \"model\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"model\",\n \"description\": \"模型 ID(gemini-3.8-flash-high / gemini-pro-agent)。\"\n },\n {\n \"name\": \"messages\",\n \"type\": \"message[]\",\n \"required\": true,\n \"mapping\": \"provider message container\",\n \"description\": \"包含历史消息和当前用户输入。\"\n },\n {\n \"name\": \"instructions\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"system/instructions\",\n \"description\": \"系统指令。\"\n },\n {\n \"name\": \"temperature\",\n \"type\": \"number\",\n \"required\": false,\n \"mapping\": \"temperature\",\n \"description\": \"采样温度。\"\n },\n {\n \"name\": \"top_p\",\n \"type\": \"number\",\n \"required\": false,\n \"mapping\": \"top_p\",\n \"description\": \"核采样参数。\"\n },\n {\n \"name\": \"max_tokens\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"max_tokens/max_output_tokens\",\n \"description\": \"最大输出 token。\"\n },\n {\n \"name\": \"tools\",\n \"type\": \"array\",\n \"required\": false,\n \"mapping\": \"tools/toolConfig\",\n \"description\": \"工具定义。\"\n },\n {\n \"name\": \"tool_choice\",\n \"type\": \"object|string\",\n \"required\": false,\n \"mapping\": \"tool_choice\",\n \"description\": \"工具选择策略。\"\n },\n {\n \"name\": \"response_format\",\n \"type\": \"object\",\n \"required\": false,\n \"mapping\": \"response_format/text\",\n \"description\": \"结构化输出配置。\"\n },\n {\n \"name\": \"stream\",\n \"type\": \"boolean\",\n \"required\": false,\n \"mapping\": \"stream\",\n \"description\": \"流式开关;后台任务当前以最终响应归一。\"\n },\n {\n \"name\": \"providerOptions\",\n \"type\": \"object\",\n \"required\": false,\n \"mapping\": \"provider-specific fields\",\n \"description\": \"插件命名空间内的厂商扩展字段。\"\n }\n ],\n \"create\": {\n \"method\": \"POST\",\n \"path\": \"/chat/completions\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$ref\": \"request.model\"\n },\n \"messages\": {\n \"$ref\": \"request.messages\"\n },\n \"temperature\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.temperature\"\n }\n },\n \"top_p\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.top_p\"\n }\n },\n \"max_tokens\": {\n \"$omitEmpty\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.extra.max_tokens\"\n },\n {\n \"$ref\": \"request.providerOptions.antigravity-chat.max_tokens\"\n }\n ]\n }\n },\n \"tools\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.tools\"\n }\n },\n \"tool_choice\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.tool_choice\"\n }\n },\n \"response_format\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.response_format\"\n }\n },\n \"stream\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.stream\"\n }\n },\n \"stop\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.stop\"\n }\n },\n \"seed\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.seed\"\n }\n },\n \"frequency_penalty\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.frequency_penalty\"\n }\n },\n \"presence_penalty\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.presence_penalty\"\n }\n },\n \"user\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.antigravity-chat.user\"\n }\n }\n }\n },\n \"response\": {\n \"status\": \"succeeded\",\n \"textPaths\": [\n \"choices.0.message.content\",\n \"choices.0.text\"\n ],\n \"reasoningPaths\": [\n \"choices.0.message.reasoning_content\"\n ],\n \"usage\": {\n \"$ref\": \"response.usage\"\n },\n \"errorPaths\": [\n \"error.code\"\n ],\n \"messagePaths\": [\n \"error.message\"\n ]\n }\n }\n ]\n },\n \"documentation\": \"<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>\"\n}\n```\n\n" } diff --git a/plugin-packages/src-metaso-h3/docs/interface.md b/plugin-packages/src-metaso-h3/docs/interface.md index 85cdb615a..57f64e02c 100644 --- a/plugin-packages/src-metaso-h3/docs/interface.md +++ b/plugin-packages/src-metaso-h3/docs/interface.md @@ -59,3 +59,379 @@ status 取值:queued / running / succeeded / failed / cancelled。 ## 错误 创建与查询均返回 OpenAI 风格错误体,含 `error.type` / `error.message` / `request_id`;余额不足为 402,速率限制为 429。 + + +## Manifest 完整接口定义 + +以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。 + +```json +{ + "apiVersion": "yingce.plugin/v2", + "id": "metaso-h3", + "name": "METASO MiniMax H3", + "version": "1.0.0", + "author": "METASO", + "description": "秘塔 METASO MiniMax H3 文生视频/图生视频协议插件(异步任务)。", + "permissions": [ + "generation.run", + "media.read" + ], + "configuration": { + "fields": [ + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } + ] + }, + "contributes": { + "providers": [ + { + "id": "metaso-h3", + "label": "METASO MiniMax H3", + "capabilities": [ + "video" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], + "baseUrl": "https://metaso.cn", + "auth": { + "type": "bearer", + "field": "apiKey" + }, + "requiresPublicMediaUrls": true, + "parameters": [ + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "视频模型 ID(MiniMax-H3 / MiniMax-H3-Max)。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "prompt/content/input", + "description": "视频提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "first/last/reference image", + "description": "显式 role 图片输入(首帧/尾帧/参考图)。" + }, + { + "name": "videos", + "type": "media[]", + "required": false, + "mapping": "reference video", + "description": "参考视频。" + }, + { + "name": "audios", + "type": "media[]", + "required": false, + "mapping": "reference audio/voice", + "description": "参考音频或音色。" + }, + { + "name": "duration", + "type": "integer", + "required": false, + "mapping": "duration/seconds", + "description": "时长秒数(4-15)。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "ratio/aspect_ratio/size", + "description": "画幅比例(16:9 等)。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution", + "description": "分辨率档位(768P / 2K)。" + }, + { + "name": "watermark", + "type": "boolean", + "required": false, + "mapping": "watermark", + "description": "AIGC 水印开关。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } + ], + "create": { + "method": "POST", + "path": "/api/minimax/v2/video_generation", + "contentType": "application/json", + "body": { + "model": { + "$coalesce": [ + { + "$ref": "request.model" + }, + "MiniMax-H3" + ] + }, + "content": { + "$concatArrays": [ + { + "$if": { + "condition": { + "$gt": [ + { + "$len": { + "$ref": "request.prompt" + } + }, + 0 + ] + }, + "then": [ + { + "type": "text", + "text": { + "$ref": "request.prompt" + } + } + ], + "else": [] + } + }, + { + "$map": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "in": { + "type": "image_url", + "image_url": { + "url": { + "$coalesce": [ + { + "$ref": "media.url" + }, + { + "$ref": "media.dataUrl" + } + ] + } + }, + "role": { + "$omitEmpty": { + "$ref": "media.role" + } + } + } + } + }, + { + "$map": { + "from": { + "$ref": "request.videos" + }, + "as": "media", + "in": { + "type": "video_url", + "video_url": { + "url": { + "$coalesce": [ + { + "$ref": "media.url" + }, + { + "$ref": "media.dataUrl" + } + ] + } + }, + "role": { + "$omitEmpty": { + "$ref": "media.role" + } + } + } + } + }, + { + "$map": { + "from": { + "$ref": "request.audios" + }, + "as": "media", + "in": { + "type": "audio_url", + "audio_url": { + "url": { + "$coalesce": [ + { + "$ref": "media.url" + }, + { + "$ref": "media.dataUrl" + } + ] + } + }, + "role": { + "$omitEmpty": { + "$ref": "media.role" + } + } + } + } + } + ] + }, + "resolution": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.resolution" + }, + { + "$ref": "request.providerOptions.metaso-h3.resolution" + }, + "768P" + ] + } + }, + "duration": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.duration" + }, + { + "$ref": "request.providerOptions.metaso-h3.duration" + }, + 5 + ] + } + }, + "ratio": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.aspectRatio" + }, + { + "$ref": "request.providerOptions.metaso-h3.ratio" + }, + "16:9" + ] + } + }, + "aigc_watermark": { + "$omitEmpty": { + "$ref": "request.providerOptions.metaso-h3.aigc_watermark" + } + } + } + }, + "poll": { + "method": "GET", + "path": "/api/minimax/v2/query/video_generation/{{taskId}}" + }, + "response": { + "taskId": { + "$coalesce": [ + { + "$ref": "response.task_id" + }, + { + "$ref": "response.taskId" + }, + { + "$ref": "response.data.task_id" + } + ] + }, + "status": { + "$coalesce": [ + { + "$ref": "response.task.status" + }, + { + "$ref": "response.status" + }, + { + "$ref": "response.data.status" + }, + "pending" + ] + }, + "message": { + "$coalesce": [ + { + "$ref": "response.task.error.message" + }, + { + "$ref": "response.task.fail_reason" + }, + { + "$ref": "response.error.message" + }, + { + "$ref": "response.message" + } + ] + }, + "videos": { + "$coalesce": [ + { + "$ref": "response.task.content.url" + }, + { + "$ref": "response.task.content.video_url" + }, + { + "$ref": "response.content.url" + }, + { + "$ref": "response.data.url" + } + ] + }, + "usage": { + "$ref": "response.task.usage" + }, + "errorPaths": [ + "task.error.type", + "error.type", + "error.code" + ], + "resultEphemeral": true, + "messagePaths": [ + "task.error.message", + "error.message" + ] + } + } + ] + }, + "documentation": "<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>" +} +``` + diff --git a/plugin-packages/src-metaso-h3/manifest.json b/plugin-packages/src-metaso-h3/manifest.json index 1a051962a..0e70020df 100644 --- a/plugin-packages/src-metaso-h3/manifest.json +++ b/plugin-packages/src-metaso-h3/manifest.json @@ -5,10 +5,18 @@ "version": "1.0.0", "author": "METASO", "description": "秘塔 METASO MiniMax H3 文生视频/图生视频协议插件(异步任务)。", - "permissions": ["generation.run", "media.read"], + "permissions": [ + "generation.run", + "media.read" + ], "configuration": { "fields": [ - { "name": "apiKey", "type": "secret", "label": "API Key", "required": true } + { + "name": "apiKey", + "type": "secret", + "label": "API Key", + "required": true + } ] }, "contributes": { @@ -16,41 +24,262 @@ { "id": "metaso-h3", "label": "METASO MiniMax H3", - "capabilities": ["video"], - "scopes": ["admin.system-channel", "user.custom-channel", "canvas", "creation", "agent"], + "capabilities": [ + "video" + ], + "scopes": [ + "admin.system-channel", + "user.custom-channel", + "canvas", + "creation", + "agent" + ], "baseUrl": "https://metaso.cn", - "auth": { "type": "bearer", "field": "apiKey" }, + "auth": { + "type": "bearer", + "field": "apiKey" + }, "requiresPublicMediaUrls": true, "parameters": [ - { "name": "model", "type": "string", "required": true, "mapping": "model", "description": "视频模型 ID(MiniMax-H3 / MiniMax-H3-Max)。" }, - { "name": "prompt", "type": "string", "required": true, "mapping": "prompt/content/input", "description": "视频提示词。" }, - { "name": "images", "type": "media[]", "required": false, "mapping": "first/last/reference image", "description": "显式 role 图片输入(首帧/尾帧/参考图)。" }, - { "name": "videos", "type": "media[]", "required": false, "mapping": "reference video", "description": "参考视频。" }, - { "name": "audios", "type": "media[]", "required": false, "mapping": "reference audio/voice", "description": "参考音频或音色。" }, - { "name": "duration", "type": "integer", "required": false, "mapping": "duration/seconds", "description": "时长秒数(4-15)。" }, - { "name": "aspectRatio", "type": "string", "required": false, "mapping": "ratio/aspect_ratio/size", "description": "画幅比例(16:9 等)。" }, - { "name": "resolution", "type": "string", "required": false, "mapping": "resolution", "description": "分辨率档位(768P / 2K)。" }, - { "name": "watermark", "type": "boolean", "required": false, "mapping": "watermark", "description": "AIGC 水印开关。" }, - { "name": "providerOptions", "type": "object", "required": false, "mapping": "provider-specific fields", "description": "插件命名空间内的厂商扩展字段。" } + { + "name": "model", + "type": "string", + "required": true, + "mapping": "model", + "description": "视频模型 ID(MiniMax-H3 / MiniMax-H3-Max)。" + }, + { + "name": "prompt", + "type": "string", + "required": true, + "mapping": "prompt/content/input", + "description": "视频提示词。" + }, + { + "name": "images", + "type": "media[]", + "required": false, + "mapping": "first/last/reference image", + "description": "显式 role 图片输入(首帧/尾帧/参考图)。" + }, + { + "name": "videos", + "type": "media[]", + "required": false, + "mapping": "reference video", + "description": "参考视频。" + }, + { + "name": "audios", + "type": "media[]", + "required": false, + "mapping": "reference audio/voice", + "description": "参考音频或音色。" + }, + { + "name": "duration", + "type": "integer", + "required": false, + "mapping": "duration/seconds", + "description": "时长秒数(4-15)。" + }, + { + "name": "aspectRatio", + "type": "string", + "required": false, + "mapping": "ratio/aspect_ratio/size", + "description": "画幅比例(16:9 等)。" + }, + { + "name": "resolution", + "type": "string", + "required": false, + "mapping": "resolution", + "description": "分辨率档位(768P / 2K)。" + }, + { + "name": "watermark", + "type": "boolean", + "required": false, + "mapping": "watermark", + "description": "AIGC 水印开关。" + }, + { + "name": "providerOptions", + "type": "object", + "required": false, + "mapping": "provider-specific fields", + "description": "插件命名空间内的厂商扩展字段。" + } ], "create": { "method": "POST", "path": "/api/minimax/v2/video_generation", "contentType": "application/json", "body": { - "model": { "$coalesce": [ { "$ref": "request.model" }, "MiniMax-H3" ] }, - "content": { - "$concatArrays": [ - { "$if": { "condition": { "$gt": [ { "$len": { "$ref": "request.prompt" } }, 0 ] }, "then": [ { "type": "text", "text": { "$ref": "request.prompt" } } ], "else": [] } }, - { "$map": { "from": { "$ref": "request.images" }, "as": "media", "in": { "type": "image_url", "image_url": { "url": { "$coalesce": [ { "$ref": "media.url" }, { "$ref": "media.dataUrl" } ] } }, "role": { "$omitEmpty": { "$ref": "media.role" } } } } }, - { "$map": { "from": { "$ref": "request.videos" }, "as": "media", "in": { "type": "video_url", "video_url": { "url": { "$coalesce": [ { "$ref": "media.url" }, { "$ref": "media.dataUrl" } ] } }, "role": { "$omitEmpty": { "$ref": "media.role" } } } } }, - { "$map": { "from": { "$ref": "request.audios" }, "as": "media", "in": { "type": "audio_url", "audio_url": { "url": { "$coalesce": [ { "$ref": "media.url" }, { "$ref": "media.dataUrl" } ] } }, "role": { "$omitEmpty": { "$ref": "media.role" } } } } } + "model": { + "$coalesce": [ + { + "$ref": "request.model" + }, + "MiniMax-H3" ] }, - "resolution": { "$omitEmpty": { "$coalesce": [ { "$ref": "request.resolution" }, { "$ref": "request.providerOptions.metaso-h3.resolution" }, "768P" ] } }, - "duration": { "$omitEmpty": { "$coalesce": [ { "$ref": "request.duration" }, { "$ref": "request.providerOptions.metaso-h3.duration" }, 5 ] } }, - "ratio": { "$omitEmpty": { "$coalesce": [ { "$ref": "request.aspectRatio" }, { "$ref": "request.providerOptions.metaso-h3.ratio" }, "16:9" ] } }, - "aigc_watermark": { "$omitEmpty": { "$ref": "request.providerOptions.metaso-h3.aigc_watermark" } } + "content": { + "$concatArrays": [ + { + "$if": { + "condition": { + "$gt": [ + { + "$len": { + "$ref": "request.prompt" + } + }, + 0 + ] + }, + "then": [ + { + "type": "text", + "text": { + "$ref": "request.prompt" + } + } + ], + "else": [] + } + }, + { + "$map": { + "from": { + "$ref": "request.images" + }, + "as": "media", + "in": { + "type": "image_url", + "image_url": { + "url": { + "$coalesce": [ + { + "$ref": "media.url" + }, + { + "$ref": "media.dataUrl" + } + ] + } + }, + "role": { + "$omitEmpty": { + "$ref": "media.role" + } + } + } + } + }, + { + "$map": { + "from": { + "$ref": "request.videos" + }, + "as": "media", + "in": { + "type": "video_url", + "video_url": { + "url": { + "$coalesce": [ + { + "$ref": "media.url" + }, + { + "$ref": "media.dataUrl" + } + ] + } + }, + "role": { + "$omitEmpty": { + "$ref": "media.role" + } + } + } + } + }, + { + "$map": { + "from": { + "$ref": "request.audios" + }, + "as": "media", + "in": { + "type": "audio_url", + "audio_url": { + "url": { + "$coalesce": [ + { + "$ref": "media.url" + }, + { + "$ref": "media.dataUrl" + } + ] + } + }, + "role": { + "$omitEmpty": { + "$ref": "media.role" + } + } + } + } + } + ] + }, + "resolution": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.resolution" + }, + { + "$ref": "request.providerOptions.metaso-h3.resolution" + }, + "768P" + ] + } + }, + "duration": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.duration" + }, + { + "$ref": "request.providerOptions.metaso-h3.duration" + }, + 5 + ] + } + }, + "ratio": { + "$omitEmpty": { + "$coalesce": [ + { + "$ref": "request.aspectRatio" + }, + { + "$ref": "request.providerOptions.metaso-h3.ratio" + }, + "16:9" + ] + } + }, + "aigc_watermark": { + "$omitEmpty": { + "$ref": "request.providerOptions.metaso-h3.aigc_watermark" + } + } } }, "poll": { @@ -60,41 +289,79 @@ "response": { "taskId": { "$coalesce": [ - { "$ref": "response.task_id" }, - { "$ref": "response.taskId" }, - { "$ref": "response.data.task_id" } + { + "$ref": "response.task_id" + }, + { + "$ref": "response.taskId" + }, + { + "$ref": "response.data.task_id" + } ] }, "status": { "$coalesce": [ - { "$ref": "response.task.status" }, - { "$ref": "response.status" }, - { "$ref": "response.data.status" }, + { + "$ref": "response.task.status" + }, + { + "$ref": "response.status" + }, + { + "$ref": "response.data.status" + }, "pending" ] }, "message": { "$coalesce": [ - { "$ref": "response.task.error.message" }, - { "$ref": "response.task.fail_reason" }, - { "$ref": "response.error.message" }, - { "$ref": "response.message" } + { + "$ref": "response.task.error.message" + }, + { + "$ref": "response.task.fail_reason" + }, + { + "$ref": "response.error.message" + }, + { + "$ref": "response.message" + } ] }, "videos": { "$coalesce": [ - { "$ref": "response.task.content.url" }, - { "$ref": "response.task.content.video_url" }, - { "$ref": "response.content.url" }, - { "$ref": "response.data.url" } + { + "$ref": "response.task.content.url" + }, + { + "$ref": "response.task.content.video_url" + }, + { + "$ref": "response.content.url" + }, + { + "$ref": "response.data.url" + } ] }, - "usage": { "$ref": "response.task.usage" }, - "errorPaths": ["task.error.type", "error.type", "error.code"], + "usage": { + "$ref": "response.task.usage" + }, + "errorPaths": [ + "task.error.type", + "error.type", + "error.code" + ], "resultEphemeral": true, - "messagePaths": ["task.error.message", "error.message"] + "messagePaths": [ + "task.error.message", + "error.message" + ] } } ] - } + }, + "documentation": "# METASO MiniMax H3\n\n秘塔 METASO MiniMax H3 文生视频 / 图生视频协议插件(异步任务模式)。\n\n## Provider\n\n| Provider | 能力 | 端点 |\n|---|---|---|\n| metaso-h3 | video | POST /api/minimax/v2/video_generation(创建)
GET /api/minimax/v2/query/video_generation/{taskId}(轮询) |\n\n## 配置\n\n在渠道中填写 API Key(METASO 控制台创建,形如 `mk-xxxxxxxx`),baseUrl 使用 `https://metaso.cn`。\n\n## 说明\n\n- 模型:`MiniMax-H3`(支持 768P / 2K,4-15 秒,文生图/图生视频/多模态参考),`MiniMax-H3-Max`(480P / 768P,5-15 秒)。\n- 文生视频:仅文本提示词,ratio 必填(21:9 / 16:9 / 4:3 / 1:1 / 3:4 / 9:16)。\n- 图生视频:图片 role 为 first_frame / last_frame(首尾帧)。\n- 多模态参考:图片 reference_image / 视频 reference_video / 音频 reference_audio。\n- 异步任务:创建后返回 task_id,轮询查询接口直到 status=succeeded,成片 URL 在 task.content.url。\n- 鉴权:`Authorization: Bearer mk-xxx`。\n\n---\n\n# METASO MiniMax H3 接口说明\n\n## 鉴权\n\n`Authorization: Bearer mk-xxxxxxxxxxxxxxxxxxxxxxxx`\n\n## 创建视频生成任务\n\nPOST `https://metaso.cn/api/minimax/v2/video_generation`\n\n请求体:\n\n```json\n{\n \"model\": \"MiniMax-H3\",\n \"content\": [\n { \"type\": \"text\", \"text\": \"视频描述\" },\n { \"type\": \"image_url\", \"image_url\": { \"url\": \"https://...\" }, \"role\": \"first_frame\" },\n { \"type\": \"video_url\", \"video_url\": { \"url\": \"https://...\" }, \"role\": \"reference_video\" },\n { \"type\": \"audio_url\", \"audio_url\": { \"url\": \"https://...\" }, \"role\": \"reference_audio\" }\n ],\n \"resolution\": \"768P\",\n \"duration\": 5,\n \"ratio\": \"16:9\"\n}\n```\n\n- content 必须包含一个非空 text 项。\n- 首尾帧(first_frame/last_frame)与多模态参考(reference_*)互斥。\n- 图片 ≤ 9 张、视频 ≤ 3 段、音频 ≤ 3 段;请求体总大小 ≤ 64 MB。\n\n响应:\n\n```json\n{ \"task_id\": \"424010985738629\" }\n```\n\n## 查询任务\n\nGET `https://metaso.cn/api/minimax/v2/query/video_generation/{task_id}`\n\n响应:\n\n```json\n{\n \"task\": {\n \"id\": \"424010985738629\",\n \"status\": \"succeeded\",\n \"content\": { \"url\": \"https://.../output.mp4\" },\n \"resolution\": \"2K\",\n \"duration\": 5,\n \"usage\": { \"total_seconds\": 5, \"output_seconds\": 5 }\n }\n}\n```\n\nstatus 取值:queued / running / succeeded / failed / cancelled。\n\n## 错误\n\n创建与查询均返回 OpenAI 风格错误体,含 `error.type` / `error.message` / `request_id`;余额不足为 402,速率限制为 429。\n\n\n## Manifest 完整接口定义\n\n以下 JSON 与插件包内实际 `manifest.json` 逐字段一致,覆盖插件身份、权限、配置、鉴权、参数、校验、创建、Agent、查询、取消、结果下载、响应和 Agent 响应映射。`documentation` 字段的值就是当前完整文档;为避免文档在自身内部无限递归,JSON 中仅用等义占位文本表示正文。\n\n```json\n{\n \"apiVersion\": \"yingce.plugin/v2\",\n \"id\": \"metaso-h3\",\n \"name\": \"METASO MiniMax H3\",\n \"version\": \"1.0.0\",\n \"author\": \"METASO\",\n \"description\": \"秘塔 METASO MiniMax H3 文生视频/图生视频协议插件(异步任务)。\",\n \"permissions\": [\n \"generation.run\",\n \"media.read\"\n ],\n \"configuration\": {\n \"fields\": [\n {\n \"name\": \"apiKey\",\n \"type\": \"secret\",\n \"label\": \"API Key\",\n \"required\": true\n }\n ]\n },\n \"contributes\": {\n \"providers\": [\n {\n \"id\": \"metaso-h3\",\n \"label\": \"METASO MiniMax H3\",\n \"capabilities\": [\n \"video\"\n ],\n \"scopes\": [\n \"admin.system-channel\",\n \"user.custom-channel\",\n \"canvas\",\n \"creation\",\n \"agent\"\n ],\n \"baseUrl\": \"https://metaso.cn\",\n \"auth\": {\n \"type\": \"bearer\",\n \"field\": \"apiKey\"\n },\n \"requiresPublicMediaUrls\": true,\n \"parameters\": [\n {\n \"name\": \"model\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"model\",\n \"description\": \"视频模型 ID(MiniMax-H3 / MiniMax-H3-Max)。\"\n },\n {\n \"name\": \"prompt\",\n \"type\": \"string\",\n \"required\": true,\n \"mapping\": \"prompt/content/input\",\n \"description\": \"视频提示词。\"\n },\n {\n \"name\": \"images\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"first/last/reference image\",\n \"description\": \"显式 role 图片输入(首帧/尾帧/参考图)。\"\n },\n {\n \"name\": \"videos\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"reference video\",\n \"description\": \"参考视频。\"\n },\n {\n \"name\": \"audios\",\n \"type\": \"media[]\",\n \"required\": false,\n \"mapping\": \"reference audio/voice\",\n \"description\": \"参考音频或音色。\"\n },\n {\n \"name\": \"duration\",\n \"type\": \"integer\",\n \"required\": false,\n \"mapping\": \"duration/seconds\",\n \"description\": \"时长秒数(4-15)。\"\n },\n {\n \"name\": \"aspectRatio\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"ratio/aspect_ratio/size\",\n \"description\": \"画幅比例(16:9 等)。\"\n },\n {\n \"name\": \"resolution\",\n \"type\": \"string\",\n \"required\": false,\n \"mapping\": \"resolution\",\n \"description\": \"分辨率档位(768P / 2K)。\"\n },\n {\n \"name\": \"watermark\",\n \"type\": \"boolean\",\n \"required\": false,\n \"mapping\": \"watermark\",\n \"description\": \"AIGC 水印开关。\"\n },\n {\n \"name\": \"providerOptions\",\n \"type\": \"object\",\n \"required\": false,\n \"mapping\": \"provider-specific fields\",\n \"description\": \"插件命名空间内的厂商扩展字段。\"\n }\n ],\n \"create\": {\n \"method\": \"POST\",\n \"path\": \"/api/minimax/v2/video_generation\",\n \"contentType\": \"application/json\",\n \"body\": {\n \"model\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.model\"\n },\n \"MiniMax-H3\"\n ]\n },\n \"content\": {\n \"$concatArrays\": [\n {\n \"$if\": {\n \"condition\": {\n \"$gt\": [\n {\n \"$len\": {\n \"$ref\": \"request.prompt\"\n }\n },\n 0\n ]\n },\n \"then\": [\n {\n \"type\": \"text\",\n \"text\": {\n \"$ref\": \"request.prompt\"\n }\n }\n ],\n \"else\": []\n }\n },\n {\n \"$map\": {\n \"from\": {\n \"$ref\": \"request.images\"\n },\n \"as\": \"media\",\n \"in\": {\n \"type\": \"image_url\",\n \"image_url\": {\n \"url\": {\n \"$coalesce\": [\n {\n \"$ref\": \"media.url\"\n },\n {\n \"$ref\": \"media.dataUrl\"\n }\n ]\n }\n },\n \"role\": {\n \"$omitEmpty\": {\n \"$ref\": \"media.role\"\n }\n }\n }\n }\n },\n {\n \"$map\": {\n \"from\": {\n \"$ref\": \"request.videos\"\n },\n \"as\": \"media\",\n \"in\": {\n \"type\": \"video_url\",\n \"video_url\": {\n \"url\": {\n \"$coalesce\": [\n {\n \"$ref\": \"media.url\"\n },\n {\n \"$ref\": \"media.dataUrl\"\n }\n ]\n }\n },\n \"role\": {\n \"$omitEmpty\": {\n \"$ref\": \"media.role\"\n }\n }\n }\n }\n },\n {\n \"$map\": {\n \"from\": {\n \"$ref\": \"request.audios\"\n },\n \"as\": \"media\",\n \"in\": {\n \"type\": \"audio_url\",\n \"audio_url\": {\n \"url\": {\n \"$coalesce\": [\n {\n \"$ref\": \"media.url\"\n },\n {\n \"$ref\": \"media.dataUrl\"\n }\n ]\n }\n },\n \"role\": {\n \"$omitEmpty\": {\n \"$ref\": \"media.role\"\n }\n }\n }\n }\n }\n ]\n },\n \"resolution\": {\n \"$omitEmpty\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.resolution\"\n },\n {\n \"$ref\": \"request.providerOptions.metaso-h3.resolution\"\n },\n \"768P\"\n ]\n }\n },\n \"duration\": {\n \"$omitEmpty\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.duration\"\n },\n {\n \"$ref\": \"request.providerOptions.metaso-h3.duration\"\n },\n 5\n ]\n }\n },\n \"ratio\": {\n \"$omitEmpty\": {\n \"$coalesce\": [\n {\n \"$ref\": \"request.aspectRatio\"\n },\n {\n \"$ref\": \"request.providerOptions.metaso-h3.ratio\"\n },\n \"16:9\"\n ]\n }\n },\n \"aigc_watermark\": {\n \"$omitEmpty\": {\n \"$ref\": \"request.providerOptions.metaso-h3.aigc_watermark\"\n }\n }\n }\n },\n \"poll\": {\n \"method\": \"GET\",\n \"path\": \"/api/minimax/v2/query/video_generation/{{taskId}}\"\n },\n \"response\": {\n \"taskId\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.task_id\"\n },\n {\n \"$ref\": \"response.taskId\"\n },\n {\n \"$ref\": \"response.data.task_id\"\n }\n ]\n },\n \"status\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.task.status\"\n },\n {\n \"$ref\": \"response.status\"\n },\n {\n \"$ref\": \"response.data.status\"\n },\n \"pending\"\n ]\n },\n \"message\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.task.error.message\"\n },\n {\n \"$ref\": \"response.task.fail_reason\"\n },\n {\n \"$ref\": \"response.error.message\"\n },\n {\n \"$ref\": \"response.message\"\n }\n ]\n },\n \"videos\": {\n \"$coalesce\": [\n {\n \"$ref\": \"response.task.content.url\"\n },\n {\n \"$ref\": \"response.task.content.video_url\"\n },\n {\n \"$ref\": \"response.content.url\"\n },\n {\n \"$ref\": \"response.data.url\"\n }\n ]\n },\n \"usage\": {\n \"$ref\": \"response.task.usage\"\n },\n \"errorPaths\": [\n \"task.error.type\",\n \"error.type\",\n \"error.code\"\n ],\n \"resultEphemeral\": true,\n \"messagePaths\": [\n \"task.error.message\",\n \"error.message\"\n ]\n }\n }\n ]\n },\n \"documentation\": \"<当前插件的完整 documentation,由 README.md 与 docs/interface.md 拼接而成;为避免 JSON 递归,此处不重复展开正文。>\"\n}\n```\n\n" } diff --git a/web/src/components/canvas/batch-generation-settings-dialog.tsx b/web/src/components/canvas/batch-generation-settings-dialog.tsx new file mode 100644 index 000000000..57d50c467 --- /dev/null +++ b/web/src/components/canvas/batch-generation-settings-dialog.tsx @@ -0,0 +1,118 @@ +import { useEffect, useState } from "react"; +import { Button } from "antd"; +import { AppModal } from "@/components/ui/product/app-modal"; +import { WandSparkles, X } from "lucide-react"; + +import { ImageSettingsPanel } from "@/components/image-settings-panel"; +import { ModelPicker } from "@/components/model-picker"; +import { canvasThemes } from "@/lib/canvas-theme"; +import { defaultImageParamsForModel } from "@/lib/model-selection"; +import { CanvasCameraControlPopover } from "./canvas-camera-control-popover"; +import type { CameraControlOptions } from "@/lib/canvas/camera-prompt-library"; +import { useActiveTheme } from "@/stores/canvas/use-canvas-theme-store"; +import type { AiConfig } from "@/stores/use-config-store"; + +export type BatchGenerationSettings = Pick & { cameraControl?: CameraControlOptions }; + +type BatchGenerationSettingsDialogProps = { + open: boolean; + config: AiConfig; + rowCount: number; + concurrency: number; + onClose: () => void; + onConfirm: (settings: BatchGenerationSettings) => void; +}; + +export function BatchGenerationSettingsDialog({ open, config, rowCount, concurrency, onClose, onConfirm }: BatchGenerationSettingsDialogProps) { + const theme = canvasThemes[useActiveTheme()]; + const [generationConfig, setGenerationConfig] = useState(config); + const [cameraControl, setCameraControl] = useState(undefined); + + useEffect(() => { + if (open) { + setGenerationConfig(config); + setCameraControl(undefined); + } + }, [config, open]); + + const handleConfigChange = (key: "quality" | "size" | "transparentBackground" | "count", value: string) => { + setGenerationConfig((current) => ({ ...current, [key]: value })); + }; + + const handleModelChange = (model: string) => { + setGenerationConfig((current) => ({ ...current, model, imageModel: model, ...defaultImageParamsForModel(current, model) })); + }; + + const imageModel = generationConfig.imageModel || generationConfig.model; + + return ( + +
+
+ 共 {rowCount} 个任务(每行 1 张) · 并发上限 {concurrency} +
确认后将提交生成任务,可能消耗积分或产生外部模型费用。
+
+ +
+
生成模型
+ +
+ +
+ +
+ +
+
+
摄像机控制
+
为本批次统一应用镜头、焦段和光圈设置
+
+ +
+ +
+ + +
+
+
+ ); +} diff --git a/web/src/components/canvas/canvas-batch-table-node.tsx b/web/src/components/canvas/canvas-batch-table-node.tsx index 178df7586..fdb1b2b17 100644 --- a/web/src/components/canvas/canvas-batch-table-node.tsx +++ b/web/src/components/canvas/canvas-batch-table-node.tsx @@ -1,6 +1,6 @@ import { useCallback, useEffect, useMemo, useRef, useState, type PointerEvent as ReactPointerEvent, type ReactNode } from "react"; import { Button, Switch, Tooltip } from "antd"; -import { Image as ImageIcon, LoaderCircle, Minus, Play, Plus, Rows3, Trash2, Upload } from "lucide-react"; +import { Film, Image as ImageIcon, LoaderCircle, Minus, Play, Plus, Rows3, Trash2, Upload } from "lucide-react"; import { CachedResourceImage } from "@/components/cached-resource-image"; import { CanvasResourceMentionTextarea } from "@/components/canvas/canvas-resource-mention-textarea"; @@ -13,6 +13,8 @@ import { batchReferenceColumns, batchReferenceHandleId, batchReferenceMentionToken, + batchTextColumns, + batchRowReady as rowReady, } from "@/lib/canvas/canvas-batch-table"; import type { CanvasResourceReference } from "@/lib/canvas/canvas-resource-references"; import type { CanvasTheme } from "@/lib/canvas-theme"; @@ -32,6 +34,7 @@ type Props = { onUpdateRow: (rowId: string, patch: Partial) => void; onFillRows: () => void; onGenerate: (rowIds?: string[]) => void; + onCreateStoryboard?: () => void; onRetryItem: (batchId: string, itemId: string) => void; onAddReferenceColumn: () => void; onRemoveReferenceColumn?: () => void; @@ -51,9 +54,10 @@ const OPERATION_OPTIONS = [ const CONCURRENCY_OPTIONS = [1, 5, 10] as const; -export function CanvasBatchTableNodeContent({ node, nodes, connections, batch, theme, onPatchTable, onAddRow, onRemoveRow, onUpdateRow, onFillRows, onGenerate, onRetryItem, onAddReferenceColumn, onRemoveReferenceColumn, onReorderReferenceColumns, onMoveReferenceCell, onUploadReference, onFocusOutput, onConnectStart, onConnectDrop, readOnly = false }: Props) { +export function CanvasBatchTableNodeContent({ node, nodes, connections, batch, theme, onPatchTable, onAddRow, onRemoveRow, onUpdateRow, onFillRows, onGenerate, onCreateStoryboard, onRetryItem, onAddReferenceColumn, onRemoveReferenceColumn, onReorderReferenceColumns, onMoveReferenceCell, onUploadReference, onFocusOutput, onConnectStart, onConnectDrop, readOnly = false }: Props) { const table = node.metadata?.batchTable || { operation: "try_on" as const, concurrency: 10, rows: [] }; const referenceColumns = batchReferenceColumns(table); + const textColumns = batchTextColumns(table); const globalPrompt = table.globalPrompt || ""; const hasGlobalPrompt = Boolean(globalPrompt.trim()); const nodeById = useMemo(() => new Map(nodes.map((item) => [item.id, item])), [nodes]); @@ -61,7 +65,7 @@ export function CanvasBatchTableNodeContent({ node, nodes, connections, batch, t const connectedImageCount = useMemo(() => new Set(connections.filter((connection) => connection.toNodeId === node.id && connection.relation !== "batch-output").map((connection) => connection.fromNodeId)).size, [connections, node.id]); const completed = table.rows.filter((row) => hasNodeMedia(row.outputNodeId ? nodeById.get(row.outputNodeId) : undefined)).length; const unfinishedReadyCount = table.rows.filter((row) => rowReady(row, table, nodeById) && !hasNodeMedia(row.outputNodeId ? nodeById.get(row.outputNodeId) : undefined)).length; - const gridTemplateColumns = `64px repeat(${referenceColumns.length}, 88px) minmax(280px, 1fr) 88px 80px`; + const gridTemplateColumns = `64px repeat(${referenceColumns.length}, 88px) ${textColumns.length ? `repeat(${textColumns.length}, minmax(168px, 0.75fr)) ` : ""}minmax(280px, 1fr) 88px 80px`; const subtleSurface = `color-mix(in srgb, ${theme.node.text} 4%, transparent)`; const inputSurface = theme.node.panel; const fileInputRef = useRef(null); @@ -165,7 +169,7 @@ export function CanvasBatchTableNodeContent({ node, nodes, connections, batch, t - = MAX_BATCH_REFERENCE_COLUMNS ? "最多支持 6 组参考图" : `新增参考图 ${referenceColumns.length + 1}`}> + = MAX_BATCH_REFERENCE_COLUMNS ? `最多支持 ${MAX_BATCH_REFERENCE_COLUMNS} 组参考图` : `新增参考图 ${referenceColumns.length + 1}`}> @@ -181,6 +185,7 @@ export function CanvasBatchTableNodeContent({ node, nodes, connections, batch, t + {table.contentKind === "storyboard" && onCreateStoryboard ? : null} @@ -219,6 +224,7 @@ export function CanvasBatchTableNodeContent({ node, nodes, connections, batch, t {column.label} ))} + {textColumns.map((column) => {column.label})} 任务提示词 生成结果 操作 @@ -256,6 +262,18 @@ export function CanvasBatchTableNodeContent({ node, nodes, connections, batch, t /> ))} + {textColumns.map((column, columnIndex) => ( +
+ {table.aiGenerated ?