From 4e8b269816a75ee1608d790a054f5f12473e4e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Wed, 30 Sep 2026 10:39:53 +0800 Subject: [PATCH] =?UTF-8?q?=E5=88=A0=E6=8E=89=20TurnAlreadyRunning?= =?UTF-8?q?=EF=BC=9A=E5=85=A5=E9=98=9F=E5=8C=96=E5=90=8E=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E5=B9=B6=E5=8F=91=E6=92=9E=E5=8D=95=E7=9A=84=E7=94=9F=E4=BA=A7?= =?UTF-8?q?=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删 DirectTurnError::TurnAlreadyRunning 变体,以及 is_reportable / Display 的对应分支与专属用例 - 前端 directTurnEnqueueFailureNotice 删掉 turnAlreadyRunning 分支;ts-rs 绑定同步删除该变体 - 结构化载荷用例的样本换成 queueFull,本地说明用例的文案样本换成队列已满提示 --- .../src-tauri/src/agent/direct_turn_error.rs | 50 ------------------- .../conversation/directCodexConversation.ts | 1 - .../chat/generated/DirectTurnError.ts | 5 -- .../appSurface/project-conversation.suite.ts | 18 +++---- .../tests/directTurnPresentation.test.ts | 4 +- 5 files changed, 9 insertions(+), 69 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_turn_error.rs b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_turn_error.rs index 774fa34aa..80144ee12 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/agent/direct_turn_error.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/agent/direct_turn_error.rs @@ -390,13 +390,6 @@ pub(crate) enum DirectTurnError { ClientTurnIdMissing, /// `clientTurnId` 形状非法:长度与字符集由宿主定,界面按同一份约束生成。 ClientTurnIdMalformed { min_chars: usize, max_chars: usize }, - /// 同一项目已有另一条回合在跑(或同一 `clientTurnId` 并发复用)。 - /// - /// 两个身份都要带上,因为"撞的是哪一轮"决定界面该不该动当前回合。 - TurnAlreadyRunning { - existing_invocation_id: String, - incoming_invocation_id: String, - }, /// 待发消息队列已满:这一条没进队,等前面几条发完再发。 /// /// 上限只落在宿主这一处(`MAX_PENDING_DIRECT_TURNS`),随载荷带出去,界面不自己数一份。 @@ -487,7 +480,6 @@ impl DirectTurnError { Self::ClientTurnIdMissing | Self::ClientTurnIdMalformed { .. } | Self::QueueFull { .. } - | Self::TurnAlreadyRunning { .. } // 项目目录锚不定(符号链接 / 权限 / 目录被删)与目录不存在同类:都是用户能自己修好的 // 文件系统事实,诊断文案不该顶替那句"无法锚定 Direct 调用项目目录:{cause}"。 | Self::ProjectRootUnanchored { .. } @@ -653,23 +645,6 @@ impl fmt::Display for DirectTurnError { formatter, "待发消息已达上限(最多 {limit} 条),请等前面几条发完再发送" ), - Self::TurnAlreadyRunning { - existing_invocation_id, - incoming_invocation_id, - } => { - // 两条文案按身份是否相同分岔,但**不再有机器前缀**:界面按 `error.type` 与其 - // 两个身份字段分流,不解析文案(前缀曾经是协议约定,现在只是噪声)。 - if existing_invocation_id == incoming_invocation_id { - formatter.write_str( - "同一轮消息仍在处理中,已拒绝并发复用同一 clientTurnId;请等它结束或点「终止」后再发送", - ) - } else { - write!( - formatter, - "当前项目已有另一条 Direct 客户端回合正在运行,已拒绝混用付费生成身份;可在输入盒点「终止」结束它,或等它结束后再发送" - ) - } - } Self::ProjectRootUnanchored { cause } => { write!(formatter, "无法锚定 Direct 调用项目目录:{cause}") } @@ -1022,11 +997,6 @@ mod tests { policy_detail: "项目权限策略拒绝执行:conversation.write".into(), } .is_reportable()); - assert!(!DirectTurnError::TurnAlreadyRunning { - existing_invocation_id: "turn-1".into(), - incoming_invocation_id: "turn-2".into(), - } - .is_reportable()); // 回合级失败在上游已经写过诊断。 assert!( !DirectTurnError::turn_failed(DirectCodexFailureStage::CodeGeneration, "模型失败") @@ -1034,26 +1004,6 @@ mod tests { ); } - /// 并发拒绝的两条文案按身份是否相同分岔,身份必须原样带出来。 - #[test] - fn concurrent_rejection_keeps_both_invocations_and_splits_the_copy() { - let same = DirectTurnError::TurnAlreadyRunning { - existing_invocation_id: "turn-1".into(), - incoming_invocation_id: "turn-1".into(), - }; - assert!(same.to_string().contains("同一轮消息仍在处理中")); - let different = DirectTurnError::TurnAlreadyRunning { - existing_invocation_id: "turn-1".into(), - incoming_invocation_id: "turn-2".into(), - }; - assert!(different - .to_string() - .contains("另一条 Direct 客户端回合正在运行")); - assert!(!different - .to_string() - .starts_with("direct-codex-turn-already-running:")); - } - /// 边界序列化:字符串只由 Display 生成,且与改造前的可见文本一致。 #[test] fn boundary_serialization_uses_display() { diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexConversation.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexConversation.ts index 62d80f344..bb1231450 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexConversation.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/conversation/directCodexConversation.ts @@ -102,7 +102,6 @@ export function directTurnEnqueueFailureNotice( case 'clientTurnIdMissing': case 'clientTurnIdMalformed': case 'queueFull': - case 'turnAlreadyRunning': case 'projectRootUnanchored': case 'projectRootUnusable': case 'permissionRejected': diff --git a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/DirectTurnError.ts b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/DirectTurnError.ts index 94d69d66a..22c445d40 100644 --- a/apps/ai-game-creator-shell/src/view/project-development/chat/generated/DirectTurnError.ts +++ b/apps/ai-game-creator-shell/src/view/project-development/chat/generated/DirectTurnError.ts @@ -9,11 +9,6 @@ import type { DirectTurnDeadline } from './DirectTurnDeadline'; export type DirectTurnError = | { type: 'clientTurnIdMissing' } | { type: 'clientTurnIdMalformed'; minChars: number; maxChars: number } - | { - type: 'turnAlreadyRunning'; - existingInvocationId: string; - incomingInvocationId: string; - } | { type: 'queueFull'; limit: number } | { type: 'projectRootUnanchored'; cause: string } | { type: 'projectRootUnusable' } diff --git a/apps/ai-game-creator-shell/tests/appSurface/project-conversation.suite.ts b/apps/ai-game-creator-shell/tests/appSurface/project-conversation.suite.ts index 45745ed82..18ce02538 100644 --- a/apps/ai-game-creator-shell/tests/appSurface/project-conversation.suite.ts +++ b/apps/ai-game-creator-shell/tests/appSurface/project-conversation.suite.ts @@ -23,19 +23,15 @@ import { export function registerProjectConversationTests() { it('splits structured rejections by variant and never by copy', () => { // 入队失败是**结构化**载荷:分流只看 `error.type`,文案不参与任何判断。 - const concurrent = { - error: { - type: 'turnAlreadyRunning' as const, - existingInvocationId: 'turn-1', - incomingInvocationId: 'turn-1', - }, - message: '同一轮消息仍在处理中', + const queueFull = { + error: { type: 'queueFull' as const, limit: 5 }, + message: '待发消息已达上限(最多 5 条),请等前面几条发完再发送', }; - expect(readDirectTurnEnqueueFailure(concurrent)?.error.type).toBe( - 'turnAlreadyRunning', + expect(readDirectTurnEnqueueFailure(queueFull)?.error.type).toBe( + 'queueFull', ); - expect(directTurnEnqueueFailureNotice(concurrent)).toBe( - '同一轮消息仍在处理中', + expect(directTurnEnqueueFailureNotice(queueFull)).toBe( + '待发消息已达上限(最多 5 条),请等前面几条发完再发送', ); // 认得的参数 / 前置条件类都给同级提示。 expect( diff --git a/apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts b/apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts index 06ce3bd38..7dbe863b7 100644 --- a/apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts +++ b/apps/ai-game-creator-shell/tests/directTurnPresentation.test.ts @@ -356,7 +356,7 @@ describe('DirectProject 聊天分区', () => { entries: [userEntry('u1'), assistantEntry('a1', '上一轮答复')], localMessages: [ localNotice( - '同一轮消息仍在处理中', + '待发消息已达上限(最多 5 条),请等前面几条发完再发送', 'direct-codex:turn-9:user:rejected', ), ], @@ -370,7 +370,7 @@ describe('DirectProject 聊天分区', () => { expect(turns[1]?.users).toEqual([]); expect(turns[1]?.startedAt).toBe(0); expect(turns[1]?.finals.map((block) => block.text)).toEqual([ - '同一轮消息仍在处理中', + '待发消息已达上限(最多 5 条),请等前面几条发完再发送', ]); });