feat(*): 云端 Agent - 增强画布上下文读取并接入 Gemini 缓存

This commit is contained in:
ddcat666 committed 2026-09-26 02:21:47 +08:00
1 parent 2ce50bbb9d
commit 2cedc4c66b
35 files changed
+1927 -266

No files matched your search

@@ -95,6 +95,40 @@ func TestCloudAgentCanvasSummaryIsACatalogNotNodeBodies(t *testing.T) {
}
}
func TestCloudAgentCanvasSummaryUsesSelectedNodeNeighborhood(t *testing.T) {
doc := map[string]any{
"nodes": []map[string]any{
{"id": "focus", "type": "text", "title": "主体"},
{"id": "neighbor", "type": "image", "title": "关联素材"},
{"id": "unrelated", "type": "text", "title": "无关内容"},
},
"connections": []map[string]any{{"fromNodeId": "focus", "toNodeId": "neighbor"}},
}
raw, err := json.Marshal(doc)
if err != nil {
t.Fatal(err)
}
summary, err := cloudAgentCanvasSummary(&model.CanvasProject{PayloadJSON: string(raw)}, "focus")
if err != nil {
t.Fatal(err)
}
var result map[string]any
if err := json.Unmarshal([]byte(summary), &result); err != nil {
t.Fatal(err)
}
encoded, _ := json.Marshal(result["nodes"])
if strings.Contains(string(encoded), "unrelated") || !strings.Contains(string(encoded), "focus") || !strings.Contains(string(encoded), "neighbor") {
t.Fatalf("focused catalog did not include exactly the local graph neighborhood: %s", encoded)
}
selection := result["selection"].(map[string]any)
if selection["includedNeighbors"] != float64(1) || selection["nextReadDepth"] != float64(1) {
t.Fatalf("focused catalog metadata is incorrect: %+v", selection)
}
if _, err := cloudAgentCanvasSummary(&model.CanvasProject{PayloadJSON: string(raw)}, "deleted"); err == nil {
t.Fatal("stale selected node was accepted")
}
}
func TestCloudAgentToolsFollowCanvasCapabilityRegistry(t *testing.T) {
req := agentTestRequest()
req.PermissionMode = "auto"
@@ -369,3 +403,60 @@ func TestCloudAgentDurablePolicySnapshotRejectsMissingOrUnsupportedContracts(t *
})
}
}
func TestCloudAgentCanvasStateIncludesBoundedRelatedComponent(t *testing.T) {
doc := map[string]any{
"nodes": []map[string]any{
{"id": "upstream", "type": "text", "title": "上游"},
{"id": "focus", "type": "text", "title": "焦点"},
{"id": "downstream", "type": "text", "title": "下游"},
{"id": "unrelated", "type": "text", "title": "无关"},
},
"connections": []map[string]any{
{"id": "e1", "fromNodeId": "upstream", "toNodeId": "focus"},
{"id": "e2", "fromNodeId": "focus", "toNodeId": "downstream"},
},
}
view, err := cloudAgentCanvasStateWithRelated(nil, "user", "canvas", doc, 0, []string{"focus"}, 0)
if err != nil {
t.Fatal(err)
}
result := view.(map[string]any)
selection := result["selection"].(map[string]any)
if selection["relationMode"] != "all" || selection["truncated"] != false || selection["selectedNodes"] != 3.0 && selection["selectedNodes"] != 3 {
t.Fatalf("unexpected related selection: %#v", selection)
}
ids := map[string]bool{}
for _, raw := range result["nodes"].([]any) {
ids[raw.(map[string]any)["id"].(string)] = true
}
if ids["focus"] == false || ids["upstream"] == false || ids["downstream"] == false || ids["unrelated"] {
t.Fatalf("related component selected wrong nodes: %#v", ids)
}
if len(result["connections"].([]any)) != 2 {
t.Fatalf("related component lost edges: %#v", result["connections"])
}
}
func TestCloudAgentCanvasStateRelatedComponentIsBounded(t *testing.T) {
nodes := make([]map[string]any, 0, cloudAgentRelatedNodeLimit+32)
edges := make([]map[string]any, 0, cloudAgentRelatedNodeLimit+32)
nodes = append(nodes, map[string]any{"id": "focus", "type": "text", "title": "焦点"})
for index := 0; index < cloudAgentRelatedNodeLimit+32; index++ {
id := fmt.Sprintf("child-%d", index)
nodes = append(nodes, map[string]any{"id": id, "type": "text", "title": id})
edges = append(edges, map[string]any{"id": fmt.Sprintf("edge-%d", index), "fromNodeId": "focus", "toNodeId": id})
}
view, err := cloudAgentCanvasStateWithRelated(nil, "user", "canvas", map[string]any{"nodes": nodes, "connections": edges}, 0, []string{"focus"}, 0)
if err != nil {
t.Fatal(err)
}
result := view.(map[string]any)
selection := result["selection"].(map[string]any)
if selection["truncated"] != true || selection["selectedNodes"] != float64(cloudAgentRelatedNodeLimit) && selection["selectedNodes"] != cloudAgentRelatedNodeLimit {
t.Fatalf("related component should be truncated at %d: %#v", cloudAgentRelatedNodeLimit, selection)
}
if len(result["nodes"].([]any)) != cloudAgentRelatedNodeLimit {
t.Fatalf("related component returned too many nodes: %d", len(result["nodes"].([]any)))
}
}