fix(webui): preserve causal message order (NAN-29) (#5503)

This commit is contained in:
chengyongru
2026-08-24 15:08:22 +08:00
committed by GitHub
parent 7f288a49fc
commit 04974b7607
8 changed files with 651 additions and 204 deletions
+5 -5
View File
@@ -21,7 +21,6 @@ import {
isReasoningOnlyPlaceholder,
matchesTurn,
mergeFileEdits,
pruneReasoningOnlyPlaceholders,
replaceMessageAt,
stampLastAssistantCompletion,
stripCoveredFileEditToolHintsFromMessages,
@@ -90,10 +89,12 @@ function attachReasoningChunk(
const activitySegmentId = candidate.activitySegmentId ?? segments?.ensure();
const hasAnswer = candidate.content.length > 0;
if (hasAnswer) break;
// ``reasoning_end`` closes this row even though the assistant placeholder
// stays streaming for the rest of the turn. The next reasoning stream must
// get its own row when an intervening tool trace is delayed or unavailable.
if (
candidate.reasoningStreaming
|| candidate.reasoning !== undefined
|| candidate.isStreaming
|| (candidate.isStreaming && candidate.reasoning === undefined)
) {
const merged: UIMessage = {
...candidate,
@@ -841,7 +842,6 @@ export function useNanobotStream(
const completedAt = Date.now();
setMessages((prev) => {
let finalized = prev.map((m) => (m.isStreaming ? { ...m, isStreaming: false } : m));
finalized = pruneReasoningOnlyPlaceholders(finalized);
const latencyMs =
typeof ev.latency_ms === "number" && ev.latency_ms >= 0
? Math.round(ev.latency_ms)
@@ -1185,7 +1185,7 @@ export function useNanobotStream(
}
const base = finalizeActiveTurn ? finalizeStreamedTurn(prev) : prev;
return [
...(sideChannel || continueActiveTurn ? base : pruneReasoningOnlyPlaceholders(base)),
...base,
{
id: userMessageId,
role: "user",