diff --git a/backend/internal/app/cloud_agent_approval_preview.go b/backend/internal/app/cloud_agent_approval_preview.go index bfa1e69d8..57bcd3163 100644 --- a/backend/internal/app/cloud_agent_approval_preview.go +++ b/backend/internal/app/cloud_agent_approval_preview.go @@ -153,7 +153,10 @@ func applyCloudAgentCanvasPlan(doc map[string]any, ops []agentCanvasOp) ([]cloud }) case "update_node": if len(op.Patch) == 0 { - return nil, BadAuthRequest("更新节点必须提供 patch") + // 漏字段是模型照 schema 就能自己修好的参数错误:当成工具结果回给它重试, + // 而不是判整轮失败(用户只在失败提示里看到一句"必须提供 patch")。 + // 未知操作类型仍按准入失败终止(cloud_agent_test.go 有用例断言这一行为)。 + return nil, &cloudAgentArgumentError{BadAuthRequest("更新节点必须提供 patch")} } if index < 0 { return nil, BadAuthRequest("只能更新现有且受 Agent 支持的节点") diff --git a/backend/internal/app/cloud_agent_approval_preview_test.go b/backend/internal/app/cloud_agent_approval_preview_test.go index 844b17ae9..033f9582c 100644 --- a/backend/internal/app/cloud_agent_approval_preview_test.go +++ b/backend/internal/app/cloud_agent_approval_preview_test.go @@ -2,6 +2,7 @@ package app import ( "encoding/json" + "errors" "strings" "testing" ) @@ -81,3 +82,25 @@ func TestCloudAgentCanvasApprovalPreviewRejectsUnknownTargetInsteadOfFallingBack t.Fatalf("unknown target was not rejected: %v", err) } } + +// 漏 patch 必须是**可恢复的参数错误**:运行期会把它当工具结果回给模型重试, +// 而不是把整轮判死;未知操作类型(例如删除)仍按准入失败终止。 +func TestCloudAgentCanvasApprovalPreviewTreatsMissingPatchAsArgumentError(t *testing.T) { + doc, err := creationDocument(`{"nodes":[{"id":"image-1","type":"image","title":"参考图"}],"connections":[]}`) + if err != nil { + t.Fatal(err) + } + _, err = applyCloudAgentCanvasPlan(doc, []agentCanvasOp{{Type: "update_node", ID: "image-1"}}) + var argumentErr *cloudAgentArgumentError + if !errors.As(err, &argumentErr) { + t.Fatalf("漏 patch 应当是可恢复的参数错误,实际:%v", err) + } + + _, err = applyCloudAgentCanvasPlan(doc, []agentCanvasOp{{Type: "delete_node", ID: "image-1"}}) + if err == nil { + t.Fatal("未知画布写操作必须仍然报错") + } + if errors.As(err, &argumentErr) { + t.Fatalf("未知画布写操作不能被当成可恢复的参数错误:%v", err) + } +}