From 1b40f030e7d1965f43c3c9dabe15b7245379dc04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Thu, 17 Sep 2026 00:05:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E6=8E=89=E8=81=8A=E5=A4=A9=20reducer?= =?UTF-8?q?=20=E9=87=8C=E6=B2=A1=E4=BA=BA=E8=AF=BB=E7=9A=84=E8=AE=A2?= =?UTF-8?q?=E9=98=85=E8=BA=AB=E4=BB=BD=E4=B8=8E=E9=A6=96=E5=B1=8F=E9=94=9A?= =?UTF-8?q?=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DirectThreadChatState 去掉 subscriptionId 与 lastCompletedItemId 两个只写不读的字段 - resolveDirectThreadBootstrap 只把 bootstrap 事件 reduce 进状态,不再顺带写入这两个字段 - directThreadChat 单测改成断言聊天状态里不再出现这两个字段(bootstrap 载荷本身不变) --- .../project-workspace/directThreadChat.ts | 17 +++-------------- .../tests/directThreadChat.test.ts | 5 +++-- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/apps/ai-game-creator-shell/src/features/project-workspace/directThreadChat.ts b/apps/ai-game-creator-shell/src/features/project-workspace/directThreadChat.ts index 37adb0c7e..d9b978db5 100644 --- a/apps/ai-game-creator-shell/src/features/project-workspace/directThreadChat.ts +++ b/apps/ai-game-creator-shell/src/features/project-workspace/directThreadChat.ts @@ -32,9 +32,6 @@ export type DirectChatEntry = { }; export type DirectThreadChatState = { - subscriptionId: string | null; - /** 首屏历史锚点:`subscribe` 给出的最后一条完成条目 id。 */ - lastCompletedItemId: string | null; /** 最新回合是否还在跑;只由生命周期事件的先后决定。 */ turnRunning: boolean; /** 历史切片条目,保持文件顺序。 */ @@ -45,8 +42,6 @@ export type DirectThreadChatState = { export function emptyDirectThreadChatState(): DirectThreadChatState { return { - subscriptionId: null, - lastCompletedItemId: null, turnRunning: false, history: [], live: [], @@ -197,20 +192,14 @@ export function reduceDirectThreadEvents( /** * bootstrap 是运行态的唯一权威:游标已在队尾,返回的事件就是此刻要处理的事件。 * - * 历史窗口保留:bootstrap 不重新回读历史切片,那是 `lastCompletedItemId` 的职责。 + * 订阅身份与首屏历史锚点(`subscriptionId` / `lastCompletedItemId`)是订阅循环自己的局部 + * 事实,不进聊天状态:这里只把 bootstrap 事件 reduce 进现有状态。 */ export function resolveDirectThreadBootstrap( state: DirectThreadChatState, bootstrap: DirectThreadSubscriptionBootstrap, ): DirectThreadChatState { - return reduceDirectThreadEvents( - { - ...state, - subscriptionId: bootstrap.subscriptionId, - lastCompletedItemId: bootstrap.lastCompletedItemId ?? null, - }, - bootstrap.events, - ); + return reduceDirectThreadEvents(state, bootstrap.events); } /** 事件顺序 = 游标顺序;调用方只需要把 `consume` 的结果喂进来。 */ diff --git a/apps/ai-game-creator-shell/tests/directThreadChat.test.ts b/apps/ai-game-creator-shell/tests/directThreadChat.test.ts index e381805dd..d9bb2b82f 100644 --- a/apps/ai-game-creator-shell/tests/directThreadChat.test.ts +++ b/apps/ai-game-creator-shell/tests/directThreadChat.test.ts @@ -80,8 +80,9 @@ describe('DirectProject 聊天 reducer', () => { ], }, ); - expect(bootstrapped.subscriptionId).toBe('sub-1'); - expect(bootstrapped.lastCompletedItemId).toBe('msg-9'); + // 订阅身份与首屏锚点由订阅循环自己持有,不写进聊天 reducer 状态。 + expect(bootstrapped).not.toHaveProperty('subscriptionId'); + expect(bootstrapped).not.toHaveProperty('lastCompletedItemId'); expect(bootstrapped.turnRunning).toBe(true); expect(selectDirectChatEntries(bootstrapped)).toHaveLength(1); });