实时交替渲染的切分点吸附到句子边界,避免把文本切碎
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Failing after 2m11s
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Failing after 2m12s
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Failing after 2m38s
Project CI / Backend tests (pull_request) Failing after 10s
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Failing after 2m32s
Project CI / AI game creator shell Rust smoke (pull_request) Successful in 2m39s
Project CI / Repository checks (pull_request) Failing after 11s
Project CI / AI game creator shell web tests (pull_request) Failing after 53s
Project CI / AI game creator shell Rust crates (pull_request) Successful in 2m1s
Project CI / Native shell tests (pull_request) Failing after 2m50s
Project CI / Frontend tests (pull_request) Failing after 3m35s

- renderLiveStream:工具切分点向后吸附到最近的句末标点或换行(最多前探 200 字符)
- 同一条句子里的多个工具因此落到同一切点,自动合并成一个块(不再出现 轻|量|的 这种碎片)
- 找不到边界或已到文本末尾时保留原位置,不丢内容
This commit is contained in:
2026-09-16 00:23:13 +08:00
parent 67126a981e
commit b4e6f7e07e
@@ -381,10 +381,38 @@ export function ProjectSupervisorView({
*/
const renderLiveStream = (liveText: string, calls: typeof liveToolCalls) => {
const offsets = directToolTextOffsets[liveToolCallTurnId] ?? {};
/**
* 把切分点吸附到句子边界:工具事件与文本增量是交替到达的,直接按"当时的长度"切
* 会把句子切碎(历史上出现过"我来做一次轻|量|的"这种)。这里向后找最近的
* 句末标点或换行,同一句里的多个工具因此落到同一个切点、自动合并成一块。
*/
const snapToBoundary = (source: string, index: number) => {
const start = Math.max(0, Math.min(index, source.length));
const limit = Math.min(source.length, start + 200);
for (let cursor = start; cursor < limit; cursor += 1) {
const char = source[cursor];
if (char === '\n') {
return cursor + 1;
}
if ('。!?;!?;'.includes(char)) {
return cursor + 1;
}
if (
char === '.' &&
(source[cursor + 1] === ' ' || source[cursor + 1] === undefined)
) {
return cursor + 1;
}
}
return start;
};
const groups = new Map<number, typeof calls>();
for (const call of calls) {
const offset = offsets[call.id];
const key = Number.isFinite(offset) ? Number(offset) : liveText.length;
const key = snapToBoundary(
liveText,
Number.isFinite(offset) ? Number(offset) : liveText.length,
);
const bucket = groups.get(key) ?? [];
bucket.push(call);
groups.set(key, bucket);