修文本段被截断:同一 item 的文本按更长优先合并
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 1m47s
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 2m1s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 2m24s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 2m23s
Project CI / Backend tests (pull_request) Failing after 11s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m0s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m59s
Project CI / Frontend tests (pull_request) Failing after 3m54s
Project CI / AI game creator shell web tests (pull_request) Failing after 3m52s
Project CI / Native shell tests (pull_request) Has been cancelled

- 现象:回合正文只剩前缀(如"我来"),后面的完整文本没进对话流
- 根因:文本段快照的 updatedAt 未必单调递增,而合并规则只在 updatedAt 更新(或同刻)时才替换,后到的更长文本被判为"更旧"而丢弃
- Rust(direct_turn_stream.rs):kind=text 时更长文本优先;合并后 updated_at 取两者最大值,不回退顺序元数据
- 前端(App.tsx mergeTurnStreamItems):同规则改为更长优先
- 验证:cargo build 0 error、tsc 0 错误
This commit is contained in:
2026-09-16 00:51:05 +08:00
parent f1632533df
commit cae6006a96
2 changed files with 8 additions and 1 deletions
@@ -211,13 +211,16 @@ fn merge_stream_snapshot(
.map(Iterator::count)
.unwrap_or_default()
};
// 文本段按"更长优先":同一个 item 的文本只会增长,而快照的 updated_at 未必单调递增;
// 只认 updated_at 更新会把后到的完整文本丢掉(实机表现:正文只剩前缀"我来")。
let take_incoming = incoming.updated_at > existing.updated_at
|| (incoming.kind == "text" && text_len(incoming) > text_len(existing))
|| (incoming.updated_at == existing.updated_at && text_len(incoming) > text_len(existing));
let mut merged = existing.clone();
if take_incoming {
merged.text = incoming.text.clone();
merged.updated_at = incoming.updated_at;
}
merged.updated_at = merged.updated_at.max(incoming.updated_at);
if merged.call_id.is_none() {
merged.call_id = incoming.call_id.clone();
}
+4
View File
@@ -550,8 +550,12 @@ function mergeTurnStreamItems(
// 内容只在更新(或同刻更长)的快照上替换;`seq` 取最早,位置不许回退。
const textLength = (value: TurnStreamItem) =>
value.kind === 'text' ? (value.text?.length ?? 0) : 0;
// 文本段按"更长优先":同一个 item 的文本只会增长,而快照的 updatedAt 未必单调递增;
// 只认 updatedAt 更新会把后到的完整文本丢掉(实机表现:正文只剩前缀"我来")。
const takeIncoming =
normalized.updatedAt > previous.updatedAt ||
(normalized.kind === 'text' &&
textLength(normalized) > textLength(previous)) ||
(normalized.updatedAt === previous.updatedAt &&
textLength(normalized) > textLength(previous));
byId.set(id, {