fix(agent): 画布助手 - 避免未支持节点阻断整张画布
This commit is contained in:
@@ -462,10 +462,13 @@ func cloudAgentCanvasSummary(canvas *model.CanvasProject) (string, error) {
|
||||
break
|
||||
}
|
||||
descriptor, known := cloudAgentNodeCapabilityForType(node.Type)
|
||||
if !known {
|
||||
return "", BadAuthRequest("画布包含当前 Agent 不支持的节点类型")
|
||||
}
|
||||
item := map[string]any{"id": truncateRunes(node.ID, 100), "type": truncateRunes(node.Type, 40), "title": truncateRunes(node.Title, 300)}
|
||||
if !known {
|
||||
item["agentSupported"] = false
|
||||
item["agentUnsupportedReason"] = "仅展示基础信息;当前 Agent 不支持操作此类型节点"
|
||||
nodes = append(nodes, item)
|
||||
continue
|
||||
}
|
||||
projected, err := cloudAgentProjectNodeFields(map[string]any{"title": node.Title}, node.Metadata, descriptor, descriptor.SummaryFields, 600, false, 0)
|
||||
if err != nil {
|
||||
return "", err
|
||||
|
||||
@@ -86,7 +86,12 @@ func cloudAgentCanvasState(repo *repository.Repository, userID string, doc map[s
|
||||
}
|
||||
capability, known := cloudAgentNodeCapabilityForType(stringValue(node["type"]))
|
||||
if !known {
|
||||
return nil, BadAuthRequest("画布包含当前 Agent 不支持的节点类型")
|
||||
// Read visibility is not permission to mutate or use a node as a media reference.
|
||||
item["agentSupported"] = false
|
||||
item["agentUnsupportedReason"] = "仅展示基础信息;当前 Agent 不支持操作此类型节点"
|
||||
nodes = append(nodes, item)
|
||||
included[id] = true
|
||||
continue
|
||||
}
|
||||
fields := capability.SummaryFields
|
||||
if len(ids) > 0 {
|
||||
|
||||
@@ -1,13 +1,58 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"infinite-canvas/backend/internal/canvas/capability"
|
||||
"infinite-canvas/backend/internal/model"
|
||||
)
|
||||
|
||||
func TestCloudAgentMixedCanvasReadsUnsupportedNodesWithoutGrantingCapabilities(t *testing.T) {
|
||||
nodes := []map[string]any{{"id": "text", "type": "text", "metadata": map[string]any{"content": "readable"}}}
|
||||
for _, kind := range []string{"ai-art-critique", "config", "drawing", "future-plugin"} {
|
||||
nodes = append(nodes, map[string]any{"id": kind, "type": kind, "title": "插件节点", "position": map[string]any{"x": 10.0, "y": 20.0}, "metadata": map[string]any{"content": "PRIVATE_SENTINEL", "apiKey": "PRIVATE_SENTINEL"}})
|
||||
if _, supported := cloudAgentNodeCapabilityForType(kind); supported {
|
||||
t.Fatalf("unsupported type gained write capability: %s", kind)
|
||||
}
|
||||
if err := validateCreationOps([]CreationCanvasOp{{Type: "add_node", ID: "new", NodeType: kind}}); err == nil {
|
||||
t.Fatalf("unsupported creation accepted: %s", kind)
|
||||
}
|
||||
if _, _, err := cloudAgentReferenceDescriptor(nodes[len(nodes)-1]); err == nil {
|
||||
t.Fatalf("unsupported media reference accepted: %s", kind)
|
||||
}
|
||||
if err := validateCloudAgentConnection(nodes, kind, "text"); err == nil {
|
||||
t.Fatalf("unsupported connection accepted: %s", kind)
|
||||
}
|
||||
}
|
||||
doc := map[string]any{"nodes": nodes, "connections": []map[string]any{{"id": "edge", "fromNodeId": "drawing", "toNodeId": "text"}}}
|
||||
raw, _ := json.Marshal(doc)
|
||||
summary, err := cloudAgentCanvasSummary(&model.CanvasProject{PayloadJSON: string(raw)})
|
||||
if err != nil || strings.Contains(summary, "PRIVATE_SENTINEL") || !strings.Contains(summary, `"agentSupported":false`) {
|
||||
t.Fatalf("mixed summary failed or leaked metadata: %v", err)
|
||||
}
|
||||
for _, ids := range [][]string{nil, {"drawing", "config"}} {
|
||||
view, err := cloudAgentCanvasState(nil, "user", doc, 0, ids, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
result := view.(map[string]any)
|
||||
encoded, _ := json.Marshal(result)
|
||||
if strings.Contains(string(encoded), "PRIVATE_SENTINEL") || result["snapshotHash"] != cloudAgentCanvasHash(doc) || len(result["connections"].([]any)) != 1 {
|
||||
t.Fatal("unsafe projection or lost snapshot/connection")
|
||||
}
|
||||
want := len(nodes)
|
||||
if ids != nil {
|
||||
want = len(ids)
|
||||
}
|
||||
if len(result["nodes"].([]any)) != want {
|
||||
t.Fatal("nodes silently omitted")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCloudAgentToolsFollowCanvasCapabilityRegistry(t *testing.T) {
|
||||
req := agentTestRequest()
|
||||
req.PermissionMode = "auto"
|
||||
|
||||
Reference in New Issue
Block a user