补齐历史失败气泡的正文缺失标记

覆盖等待模型回执、通道连接、流式协议等旧通用失败句

补充历史错误回归测试与排障口径
This commit is contained in:
kdletters
2026-10-06 11:38:02 +08:00
parent d22e8071be
commit 3c1b9d9a96
3 changed files with 23 additions and 10 deletions
@@ -513,16 +513,18 @@ export function sanitizeDirectThreadText(
const withoutAbsolutePaths = redactAbsolutePaths(withoutProjectRoot);
const withoutSecrets = redactSecretTokens(withoutAbsolutePaths);
const sanitized = sanitizeSensitiveLines(withoutSecrets);
// 旧版已经落盘的失败条目无法凭空恢复被删掉的原因;把它们明确标成“宿主未提供正文”,
// 旧版已经落盘的失败条目无法凭空恢复被删掉的原因;把它们明确标成“历史事件未记录正文”,
// 避免历史记录继续伪装成当前仍在吞错的完整兜底句。新事件带 detail 时不命中这里。
const legacyGenericFailure =
'陶泥儿智能创作 执行通道中断,本轮未完成;请重试,若持续失败请检查项目诊断';
// 旧版本有的写入路径把连续空格 / 换行归一化方式不同;按空白折叠识别同一条历史
// 兜底文案,避免截图里的旧消息继续以“完整原因”伪装展示。新事件带正文时不命中这里。
// 旧版本把多个失败变体直接写成固定句,历史条目里没有可恢复的 detail。按空白折叠
// 识别所有已知旧兜底句,避免“等待模型回执超时”这类截图继续伪装成完整原因;新事件
// 带 typed failure/detail 时不经过这条历史兼容分支。
const normalizedLegacyFailure = sanitized.trim().replace(/\s+/gu, ' ');
const isLegacyGenericFailure =
sanitized.trim().replace(/\s+/gu, ' ') === legacyGenericFailure;
/^陶泥儿智能创作 (?:等待模型回执超时(?:(已尝试 \d+ 次))?,本轮未完成;请稍后重试|执行通道连接失败,本轮未完成;请重试,若持续失败请检查项目诊断|执行通道中断,本轮未完成;请重试,若持续失败请检查项目诊断|流式响应协议不可用,本轮未完成;请检查项目诊断后重试)$/u.test(
normalizedLegacyFailure,
);
return isLegacyGenericFailure
? `${sanitized}:宿主未提供具体错误正文`
? `${sanitized}:历史错误事件未记录具体错误正文`
: sanitized;
}
@@ -99,7 +99,7 @@ describe('directThreadSanitize', () => {
'陶泥儿智能创作 执行通道中断,本轮未完成;请重试,若持续失败请检查项目诊断',
),
).toBe(
'陶泥儿智能创作 执行通道中断,本轮未完成;请重试,若持续失败请检查项目诊断:宿主未提供具体错误正文',
'陶泥儿智能创作 执行通道中断,本轮未完成;请重试,若持续失败请检查项目诊断:历史错误事件未记录具体错误正文',
);
});
@@ -110,7 +110,18 @@ describe('directThreadSanitize', () => {
'陶泥儿智能创作 执行通道中断,本轮未完成;请重试,若持续失败请检查项目诊断',
),
).toBe(
'陶泥儿智能创作 执行通道中断,本轮未完成;请重试,若持续失败请检查项目诊断:宿主未提供具体错误正文',
'陶泥儿智能创作 执行通道中断,本轮未完成;请重试,若持续失败请检查项目诊断:历史错误事件未记录具体错误正文',
);
});
it('旧版等待模型回执超时条目也明确标记历史正文缺失', () => {
expect(
sanitizeDirectThreadText(
ROOT,
'陶泥儿智能创作 等待模型回执超时,本轮未完成;请稍后重试',
),
).toBe(
'陶泥儿智能创作 等待模型回执超时,本轮未完成;请稍后重试:历史错误事件未记录具体错误正文',
);
});
@@ -5,7 +5,7 @@
## 2026-10-06 AGC 失败终态与 CC/MCP 边界不能吞掉协议、清理和 I/O 错误
- **现象**:DirectProject 的 `turn.completed(status=failed)` 若跨 IPC 丢失 `failure` 载荷,前端会只收口回合而不显示任何说明;Claude Code sidecar 的非 UTF-8 stderr、进程树清理失败、会话表锁损坏,以及 MCP loopback 服务退出、插件能力桥超时、损坏 manifest,会分别被压成空 detail、继续成功取消、伪造 hash projectId 或静默不广告插件。
- **现行口径**:失败载荷缺失显示明确的协议错误;CC 清理、stderr 解码、会话锁都保留原始正文;MCP server / capability bridge 失败写入统一应用日志,MCP manifest / journal / 时间 / metadata 读取失败返回具体错误;完成判定在把素材缺失归因于“未引用平台图”前先验证源码、manifest 和已登记图片的 I/O/PNG 错误。切片文件是可选投影,完整 spritesheet 不因无切片而误失败。
- **现行口径**:失败载荷缺失显示明确的协议错误;旧历史里的已知通用失败句明确标成“历史错误事件未记录具体错误正文”,不伪装成当前仍在吞错;CC 清理、stderr 解码、会话锁都保留原始正文;MCP server / capability bridge 失败写入统一应用日志,MCP manifest / journal / 时间 / metadata 读取失败返回具体错误;完成判定在把素材缺失归因于“未引用平台图”前先验证源码、manifest 和已登记图片的 I/O/PNG 错误。切片文件是可选投影,完整 spritesheet 不因无切片而误失败。
- **验证**:`cargo test agent::claude_code_cli::tests::` 14 passed;`cargo test agent::direct_tools_mcp::tests::` 34 passed;`cargo test agent::direct_runtime::tests::` 92 passed;`npx vitest run tests/directThreadChat.test.ts tests/directTurnFailure.test.ts` 64 passed;另有损坏 manifest 回归用例 1 passed。新失败正文仍经既有脱敏边界处理。
- **关联**:`agent/claude_code_cli.rs`、`agent/direct_tools_mcp.rs`、`agent/direct_runtime/mod.rs`、`agent/thread_manager/dispatch.rs`、`chat/conversation/directThreadChat.ts`。