From d61993459ab5cc62be1fad24f6caedd5f0017af2 Mon Sep 17 00:00:00 2001 From: Ma Date: Tue, 14 Jul 2026 22:19:48 +0800 Subject: [PATCH] fix(studio): stop reviving stale Play choices --- .../chat/__tests__/play-choices.test.ts | 18 ++++++++++++++++++ .../studio/src/components/chat/play-choices.ts | 10 +++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/studio/src/components/chat/__tests__/play-choices.test.ts b/packages/studio/src/components/chat/__tests__/play-choices.test.ts index 0d0ce96d..6366f31f 100644 --- a/packages/studio/src/components/chat/__tests__/play-choices.test.ts +++ b/packages/studio/src/components/chat/__tests__/play-choices.test.ts @@ -46,6 +46,24 @@ describe("latestPlayChoices", () => { }); }); + it("does not revive choices from an older turn when the latest Play result has none", () => { + const messages = [ + { role: "assistant", parts: [{ type: "tool", execution: { id: "turn-1", tool: "play_step", status: "completed", details: { suggestedActions: ["看账本", "问来人"] } } }] }, + { role: "assistant", parts: [{ type: "tool", execution: { id: "turn-2", tool: "play_step", status: "completed", details: { suggestedActions: [] } } }] }, + ] as any; + + expect(latestPlayChoiceSet(messages)).toBeNull(); + }); + + it("hides choices from the previous turn while a new Play turn is running", () => { + const messages = [ + { role: "assistant", parts: [{ type: "tool", execution: { id: "turn-1", tool: "play_step", status: "completed", details: { suggestedActions: ["看账本", "问来人"] } } }] }, + { role: "assistant", parts: [{ type: "tool", execution: { id: "turn-2", tool: "play_step", status: "running" } }] }, + ] as any; + + expect(latestPlayChoiceSet(messages)).toBeNull(); + }); + it("returns [] when there is no play execution", () => { expect(latestPlayChoices([{ role: "user", content: "hi" }] as any)).toEqual([]); }); diff --git a/packages/studio/src/components/chat/play-choices.ts b/packages/studio/src/components/chat/play-choices.ts index f7e7a0b8..e0849eec 100644 --- a/packages/studio/src/components/chat/play-choices.ts +++ b/packages/studio/src/components/chat/play-choices.ts @@ -29,17 +29,17 @@ export function latestPlayChoiceSet(messages: ReadonlyArray): PlayChoic const parts = messages[i]?.parts ?? []; for (let p = parts.length - 1; p >= 0; p--) { const part = parts[p]; - if (part.type !== "tool") continue; - const set = choiceSetFromExecution(part.execution, `message-${i}-part-${p}`); - if (set) return set; + if (part.type !== "tool" || !PLAY_TOOLS.has(part.execution.tool)) continue; + return choiceSetFromExecution(part.execution, `message-${i}-part-${p}`); } // Direct tool executions created by confirmed action buttons may be present // on the flat message before they are rehydrated into chronological parts. const toolExecutions = messages[i]?.toolExecutions ?? []; for (let t = toolExecutions.length - 1; t >= 0; t--) { - const set = choiceSetFromExecution(toolExecutions[t], `message-${i}-execution-${t}`); - if (set) return set; + const execution = toolExecutions[t]; + if (!PLAY_TOOLS.has(execution.tool)) continue; + return choiceSetFromExecution(execution, `message-${i}-execution-${t}`); } } return null;