diff --git a/backend/internal/app/cloud_agent_test.go b/backend/internal/app/cloud_agent_test.go index c666f9e1c..bc6a54b2f 100644 --- a/backend/internal/app/cloud_agent_test.go +++ b/backend/internal/app/cloud_agent_test.go @@ -620,7 +620,7 @@ func TestCloudAgentToolLoopPersistsApprovalAndAppliesCanvasWrite(t *testing.T) { func TestCloudAgentNodeTypesExposeExecutableAllowList(t *testing.T) { result := cloudAgentNodeTypes() nodes, ok := result["nodes"].([]map[string]any) - if !ok || len(nodes) != 9 { + if !ok || len(nodes) != 10 { t.Fatalf("unexpected node registry: %#v", result) } var character map[string]any diff --git a/backend/internal/app/cloud_agent_tools.go b/backend/internal/app/cloud_agent_tools.go index a2aa079b0..4cb055d5d 100644 --- a/backend/internal/app/cloud_agent_tools.go +++ b/backend/internal/app/cloud_agent_tools.go @@ -266,7 +266,7 @@ func compileCloudAgentTools(req CloudAgentRequest, includeProfileTool bool) []ma {"properties": map[string]any{"type": map[string]any{"const": "connect_nodes"}}, "required": []string{"fromNodeId", "toNodeId"}}, }, } - add("canvas_apply_ops", "创建空白节点、编辑或连线,不生成、不收费;先读画布传 snapshotHash。生成用 generate_media。每次最多20项,禁止删除、任意 metadata 和媒体 URL。操作必填字段见 schema;add_node 可用 x/y 定位,省略时自动排位;update_node 按节点能力填写 patch,可用 x/y 移动或设置视频首尾帧。镜头绑定示例:{\"fromNodeId\":\"<资产ID>\",\"toNodeId\":\"<分镜ID>\",\"toHandleId\":\"row:\"};输出示例:{\"fromNodeId\":\"<分镜ID>\",\"toNodeId\":\"<图片/视频ID>\",\"fromHandleId\":\"row:\"}。rowId 必须取自读取结果,不是镜头编号;整表引用用 storyboard:context。连线是生成输入关系,不会改变已提交任务的输入;来源须 canSource,目标须 canTarget 且接受来源 inputKind,能力以注册表为准。批量排位用 canvas_arrange_nodes。", map[string]any{"snapshotHash": str("canvas_get_state返回的snapshotHash"), "ops": map[string]any{"type": "array", "maxItems": 20, "items": opItem}}, "snapshotHash", "ops") + add("canvas_apply_ops", "创建空白节点、编辑或连线;先读画布传 snapshotHash,生成用 generate_media。每次最多20项,禁止删除、任意 metadata 和媒体 URL。必填字段见 schema;add_node 可用 x/y,省略自动排位;update_node 按能力填 patch,可用 x/y 或视频首尾帧。镜头绑定示例:资产→分镜 {\"toHandleId\":\"row:\"};输出示例:分镜→图片/视频 {\"fromHandleId\":\"row:\"};rowId 取读取结果,不是镜头编号;整表用 storyboard:context。连线不会改变已提交任务的输入;来源须 canSource,目标须 canTarget 且接受来源 inputKind。批量排位用 canvas_arrange_nodes。", map[string]any{"snapshotHash": str("canvas_get_state返回的snapshotHash"), "ops": map[string]any{"type": "array", "maxItems": 20, "items": opItem}}, "snapshotHash", "ops") add("canvas_arrange_nodes", "整理画布节点位置:只改坐标,不改内容、不建连线、不增删节点,先读画布并传 snapshotHash。mode 省略即 auto(有连线按依赖分层,否则按媒体类型分区)。groups 为横向分带(label 展示名,可覆盖整组 mode)。nodeIds 省略则整理全部可整理节点(跳过锁定节点、容器、批次子节点与已归属背板者)。align 对齐/等距,dryRun 只预演;一次最多 50 个节点,只挪单个节点用 update_node 的 x/y。", map[string]any{ "snapshotHash": str("最近一次画布读取的 snapshotHash"), "nodeIds": map[string]any{"type": "array", "maxItems": cloudAgentArrangeMaxNodes, "items": str("节点ID;省略=全部可整理")},