From 6e1d5120217df9b686afc6223197e9bd50ac5665 Mon Sep 17 00:00:00 2001 From: 134 Date: Tue, 23 Jun 2026 18:00:18 +0800 Subject: [PATCH] fix: focus latest canvas agent result by prompt --- app/(chat)/api/chat/route.ts | 16 ++++++++- lib/canvas/agent-view-intent.ts | 44 ++++++++++++++++++++++++ tests/routes/canvas-chat-helpers.test.ts | 22 ++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/app/(chat)/api/chat/route.ts b/app/(chat)/api/chat/route.ts index e35e28502..dd39dfdb6 100644 --- a/app/(chat)/api/chat/route.ts +++ b/app/(chat)/api/chat/route.ts @@ -76,7 +76,9 @@ import { import { buildCanvasAgentResultViewOperation } from "@/lib/canvas/agent-result-view"; import { buildCanvasAgentComparisonViewPlan, + buildCanvasAgentLatestResultViewPlan, hasCanvasAgentComparisonViewIntent, + hasCanvasAgentLatestResultViewIntent, } from "@/lib/canvas/agent-view-intent"; import { buildCanvasAgentPanViewPlan, @@ -3184,15 +3186,28 @@ export async function POST(request: Request) { const lowerText = text.toLowerCase(); const hasComparisonViewIntent = hasCanvasAgentComparisonViewIntent(text); + const hasLatestResultViewIntent = hasCanvasAgentLatestResultViewIntent(text); const hasPanViewIntent = hasCanvasAgentPanViewIntent(text); const hasViewKeyword = hasComparisonViewIntent || + hasLatestResultViewIntent || hasPanViewIntent || /视角|视野|画布|聚焦|定位|居中|看全局|看整体|看全部|缩小|放大|拉近|拉远|zoom/.test( lowerText ); if (!hasViewKeyword) return null; + const viewOperationId = `${message.id}:canvas-view:${Date.now()}`; + + if (hasLatestResultViewIntent) { + const latestResultViewPlan = buildCanvasAgentLatestResultViewPlan({ + userText: text, + projectId: contextPayload.projectId, + operationId: viewOperationId, + }); + if (latestResultViewPlan) return latestResultViewPlan; + } + const hasMediaMutationKeyword = /生成|出图|做一版|再出|换|改|编辑|抠图|去水印|高清|清晰|扩图|裁剪|删除|替换|背景|视频|模型|洗图|重绘|尺寸|像素|分辨率/.test( lowerText @@ -3216,7 +3231,6 @@ export async function POST(request: Request) { null; const hasSpecificFocusTarget = explicitTargetNodeIds.length > 0 || Boolean(anchorNode?.nodeId); - const viewOperationId = `${message.id}:canvas-view:${Date.now()}`; if (hasComparisonViewIntent) { const comparisonViewPlan = buildCanvasAgentComparisonViewPlan({ diff --git a/lib/canvas/agent-view-intent.ts b/lib/canvas/agent-view-intent.ts index ab85776db..e787aff0b 100644 --- a/lib/canvas/agent-view-intent.ts +++ b/lib/canvas/agent-view-intent.ts @@ -40,6 +40,27 @@ export function hasCanvasAgentComparisonViewIntent(userText: string) { ); } +export function hasCanvasAgentLatestResultViewIntent(userText: string) { + const text = userText.trim().toLowerCase(); + if (!text) return false; + + const hasLatestResultTarget = + /刚生成|刚才生成|最新(?:的)?(?:结果|图片|图|生成)|最近(?:的)?(?:结果|图片|图|生成)|上次生成|最后生成|刚出(?:的)?(?:图|结果)|新结果|新图/.test( + text + ); + if (!hasLatestResultTarget) return false; + + const hasViewVerb = + /聚焦|定位|居中|找到|跳到|看(?:看|一下|清楚)?|放大|拉近|focus|locate|zoom/.test( + text + ); + if (!hasViewVerb) return false; + + return !/生成(?:一|个|张|幅|段)|出图|做一版|再出|换|改|编辑|抠图|去水印|高清|清晰|扩图|裁剪|删除|替换|背景|视频|模型|洗图|重绘|尺寸|像素|分辨率/.test( + text + ); +} + export function resolveCanvasAgentComparisonNodeIds(params: { context: CanvasAgentContext; maxItems?: number; @@ -117,3 +138,26 @@ export function buildCanvasAgentComparisonViewPlan(params: { reason: params.reason || "focus_canvas_comparison_targets", }; } + +export function buildCanvasAgentLatestResultViewPlan(params: { + userText: string; + projectId: string; + operationId: string; + reason?: string; +}): CanvasViewOperationPlan | null { + const projectId = String(params.projectId || "").trim(); + const operationId = String(params.operationId || "").trim(); + if (!projectId || !operationId) return null; + if (!hasCanvasAgentLatestResultViewIntent(params.userText)) return null; + + return { + version: 1, + viewOperationId: `${operationId}:view`, + operation: "focus_latest_result", + projectId, + padding: 120, + durationMs: 360, + persist: false, + reason: params.reason || "focus_latest_canvas_agent_result", + }; +} diff --git a/tests/routes/canvas-chat-helpers.test.ts b/tests/routes/canvas-chat-helpers.test.ts index 55292f8a2..9154ef6b6 100644 --- a/tests/routes/canvas-chat-helpers.test.ts +++ b/tests/routes/canvas-chat-helpers.test.ts @@ -73,7 +73,9 @@ import { resolveCanvasAgentMediaPlacements } from "@/lib/canvas/agent-placement" import { buildCanvasAgentResultViewOperation } from "@/lib/canvas/agent-result-view"; import { buildCanvasAgentComparisonViewPlan, + buildCanvasAgentLatestResultViewPlan, hasCanvasAgentComparisonViewIntent, + hasCanvasAgentLatestResultViewIntent, resolveCanvasAgentComparisonNodeIds, } from "@/lib/canvas/agent-view-intent"; import { @@ -2038,6 +2040,26 @@ test.describe("canvas chat pure helpers", () => { ).toEqual(["image-1", "agent-result-1"]); }); + test("builds latest-result view plans for follow-up focus requests", () => { + expect(hasCanvasAgentLatestResultViewIntent("聚焦刚生成结果")).toBe(true); + expect(hasCanvasAgentLatestResultViewIntent("放大看看最新结果")).toBe(true); + expect(hasCanvasAgentLatestResultViewIntent("生成一张新图")).toBe(false); + + expect( + buildCanvasAgentLatestResultViewPlan({ + userText: "帮我定位到刚生成的图", + projectId: plannerContext.projectId || "", + operationId: "operation-latest", + }) + ).toMatchObject({ + viewOperationId: "operation-latest:view", + operation: "focus_latest_result", + projectId: plannerContext.projectId, + persist: false, + reason: "focus_latest_canvas_agent_result", + }); + }); + test("resolves latest-result and pan canvas view operations", () => { expect( resolveCanvasViewOperationTargetNodeIds({