From f06ee7df9f77fc43bf67c90c66d1de27632dfffb Mon Sep 17 00:00:00 2001 From: ShawnKung Date: Sun, 6 Sep 2026 19:04:01 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BB=8E=20Chat=20=E5=BF=AB=E7=85=A7?= =?UTF-8?q?=E8=AF=BB=E5=8F=96=E4=BC=9A=E8=AF=9D=E6=AD=A3=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 适配新版 DSH 的会话数据归属,避免模型完成后 GAL 视图丢失最终回复,并让 smoke 覆盖独立的 session 与 chat 数据源。 Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com --- .dsh-plugin/client.js | 8 ++++---- .dsh-plugin/client/GalView.jsx | 13 +++++++------ scripts/smoke.mjs | 30 ++++++++++++++++++++++++------ 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/.dsh-plugin/client.js b/.dsh-plugin/client.js index 506f241..c7c1373 100644 --- a/.dsh-plugin/client.js +++ b/.dsh-plugin/client.js @@ -2678,17 +2678,17 @@ function useFillSessionArea(rootRef) { }; }, [rootRef]); } -function GalView({ useSession, inputActions, useScene, useHistory, useAssets, useFonts, useStore, actions, api }) { +function GalView({ useSession, useChat, inputActions, useScene, useHistory, useAssets, useFonts, useStore, actions, api }) { const scene = useScene((s) => s); const history = useHistory((h) => h); const assets = useAssets((a) => a); const fonts = useFonts((f) => f); const readState = useStore((s) => s); - const nodes = useSession((s) => s.nodes); - const partial = useSession((s) => s.partial); + const nodes = useChat((s) => s.legacy.nodes); + const partial = useChat((s) => s.legacy.partial); + const runningCalls = useChat((s) => s.legacy.runningCalls); const running = useSession((s) => s.running); const blank = useSession((s) => s.blank); - const runningCalls = useSession((s) => s.runningCalls); const pending = useSession((s) => s.pending); const promptError = useSession((s) => s.promptError); const [mode, setMode] = (0, import_react3.useState)("game"); diff --git a/.dsh-plugin/client/GalView.jsx b/.dsh-plugin/client/GalView.jsx index 5108303..5fcfac2 100644 --- a/.dsh-plugin/client/GalView.jsx +++ b/.dsh-plugin/client/GalView.jsx @@ -1,5 +1,6 @@ /** GAL 视窗顶层:模式切换 + 游戏模式(舞台/控制条/输入/历史/设置)+ 编辑模式。 - * 数据来源:useSession(会话快照 nodes/partial/running/blank)、useScene(场景)、 + * 数据来源:useChat(对话快照 legacy nodes/partial/runningCalls)、 + * useSession(会话生命周期 running/blank/pending/promptError)、useScene(场景)、 * inputActions(发送走宿主输入机,与普通输入框同一管线)。 */ @@ -152,19 +153,19 @@ function useFillSessionArea(rootRef) { /** * GAL 视窗组件(conversation.view 槽位条目)。 - * @param props - 槽位框架注入:sessionId/useSession/useInput/inputActions + inject 面的 useScene/useHistory/api。 + * @param props - 槽位框架注入:sessionId/useSession/useChat/useInput/inputActions + inject 面的 useScene/useHistory/api。 */ -export function GalView({ useSession, inputActions, useScene, useHistory, useAssets, useFonts, useStore, actions, api }) { +export function GalView({ useSession, useChat, inputActions, useScene, useHistory, useAssets, useFonts, useStore, actions, api }) { const scene = useScene(s => s) const history = useHistory(h => h) const assets = useAssets(a => a) const fonts = useFonts(f => f) const readState = useStore(s => s) - const nodes = useSession(s => s.nodes) - const partial = useSession(s => s.partial) + const nodes = useChat(s => s.legacy.nodes) + const partial = useChat(s => s.legacy.partial) + const runningCalls = useChat(s => s.legacy.runningCalls) const running = useSession(s => s.running) const blank = useSession(s => s.blank) - const runningCalls = useSession(s => s.runningCalls) const pending = useSession(s => s.pending) const promptError = useSession(s => s.promptError) diff --git a/scripts/smoke.mjs b/scripts/smoke.mjs index 8047be2..5fd72ec 100644 --- a/scripts/smoke.mjs +++ b/scripts/smoke.mjs @@ -108,23 +108,40 @@ async function pageTestPhase1() { const sessionState = { current: { sessionId: 'session-1', - nodes: [ - { kind: 'user', seq: 1, content: [{ type: 'text', text: '你好' }], source: null }, - { kind: 'assistant', seq: 2, turn: 1, step: 1, blocks: [{ kind: 'text', text: '……你终于来了。欢迎回来。' }] }, - ], - partial: null, running: false, blank: false, + pending: [], + promptError: null, + }, + } + const chatState = { + current: { + legacy: { + nodes: [ + { kind: 'user', seq: 1, content: [{ type: 'text', text: '你好' }], source: null }, + { kind: 'assistant', seq: 2, turn: 1, step: 1, blocks: [{ kind: 'text', text: '……你终于来了。欢迎回来。' }] }, + ], + partial: null, + runningCalls: [], + }, }, } const sessionListeners = new Set() + const chatListeners = new Set() const sessionSource = { getSnapshot: () => sessionState.current, subscribe(fn) { sessionListeners.add(fn); return () => { sessionListeners.delete(fn) } }, } + const chatSource = { + getSnapshot: () => chatState.current, + subscribe(fn) { chatListeners.add(fn); return () => { chatListeners.delete(fn) } }, + } window.__setSession = next => { - sessionState.current = next + const { nodes = [], partial = null, runningCalls = [], ...session } = next + sessionState.current = session + chatState.current = { legacy: { nodes, partial, runningCalls } } for (const fn of [...sessionListeners]) fn() + for (const fn of [...chatListeners]) fn() } const React = window.React @@ -142,6 +159,7 @@ async function pageTestPhase1() { const props = { sessionId: 'session-1', useSession: bindHook(sessionSource), + useChat: bindHook(chatSource), useInput: bindHook({ getSnapshot: () => ({ draft: '' }), subscribe: () => () => {} }), inputActions, useScene: bindHook(sceneSource),