From 9e6cf69b45d740ea4a4a20b4b41c992854ecf099 Mon Sep 17 00:00:00 2001 From: 134 Date: Tue, 23 Jun 2026 17:10:44 +0800 Subject: [PATCH] fix: treat canvas view centering as focus intent --- ...框Agent模式升级开发文档-借鉴Cowart-2026-06-22.md | 1 + lib/canvas/agent-model-planner.ts | 16 ++++++++++++++ tests/routes/canvas-chat-helpers.test.ts | 22 +++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/docs/无限画布对话框Agent模式升级开发文档-借鉴Cowart-2026-06-22.md b/docs/无限画布对话框Agent模式升级开发文档-借鉴Cowart-2026-06-22.md index 101c26c67..c1f3ba615 100644 --- a/docs/无限画布对话框Agent模式升级开发文档-借鉴Cowart-2026-06-22.md +++ b/docs/无限画布对话框Agent模式升级开发文档-借鉴Cowart-2026-06-22.md @@ -714,6 +714,7 @@ export interface CanvasViewOperationPlan { - `fit_all`:缩小到画布主要内容范围,适合“看全局”。 - `zoom_in` / `zoom_out` / `zoom_to`:只调缩放。 - `pan_to`:平移到画布坐标或节点附近。 +- “把选中的图移动到视野中央 / 居中显示当前对象”必须归类为视角操作,不是 `move_nodes`;只有整理、排列、把节点放到画布某位置这类会改变节点坐标的请求才进入移动确认门。 持久化边界: diff --git a/lib/canvas/agent-model-planner.ts b/lib/canvas/agent-model-planner.ts index 3c796ffd3..fa226c690 100644 --- a/lib/canvas/agent-model-planner.ts +++ b/lib/canvas/agent-model-planner.ts @@ -150,12 +150,28 @@ function inferHighRiskOperation(userText: string) { if (/覆盖|替换当前|替换原图|直接替换|覆盖原图/.test(text)) { return "replace_node_media"; } + if (hasCanvasViewMovementIntent(text)) { + return ""; + } if (/批量移动|整体移动|移动到|移到|整理|排列|排版/.test(text)) { return "move_nodes"; } return ""; } +function hasCanvasViewMovementIntent(userText: string) { + const text = userText.toLowerCase(); + return ( + /(?:移动|平移|拖动|拖拽|挪动)(?:一下|一点)?(?:画布|视角|视野|镜头|视图|视口)/.test( + text + ) || + /(?:视野|视口|屏幕|画面|镜头|视图|窗口).{0,8}(?:中央|中心|中间)/.test( + text + ) || + /(?:居中显示|居中查看|居中看|聚焦到|定位到|拉近到|带我看)/.test(text) + ); +} + function defaultConfirmationReply(riskOperation: string) { if (riskOperation === "delete_nodes") { return "这个动作会删除画布节点,需要先确认后才能执行。"; diff --git a/tests/routes/canvas-chat-helpers.test.ts b/tests/routes/canvas-chat-helpers.test.ts index 32dcfb866..27a7a89f9 100644 --- a/tests/routes/canvas-chat-helpers.test.ts +++ b/tests/routes/canvas-chat-helpers.test.ts @@ -993,6 +993,28 @@ test.describe("canvas chat pure helpers", () => { ).toBeUndefined(); }); + test("keeps viewport-centering move requests as view operations", () => { + const outcome = normalizeCanvasAgentModelPlannerDecision({ + decision: { + action: "focus_nodes", + nodeIds: ["image-1"], + }, + context: plannerContext, + projectId: plannerContext.projectId || "", + messageId: "message-1", + chatId: "chat-1", + userText: "把选中的图移动到视野中央", + }); + + expect(outcome.kind).toBe("view"); + expect(outcome.kind === "view" ? outcome.viewPlan : null).toMatchObject({ + operation: "focus_selection", + nodeIds: ["image-1"], + anchorNodeId: "image-1", + persist: false, + }); + }); + test("builds pending delete-node operation from model-planned destructive request", () => { const outcome = normalizeCanvasAgentModelPlannerDecision({ decision: {