mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-19 16:12:30 +00:00
fix(webui): keep reasoning scoped to the current user turn
The post-hoc reasoning fix allowed late reasoning frames to attach back to the nearest assistant message, but the scan crossed a newer user message. That made the next turn's Thinking bubble render above the previous assistant reply. Treat the latest user message as a hard boundary: reasoning after it must start a new assistant placeholder and can no longer attach to earlier assistant turns. Add a regression covering previous assistant -> new user -> reasoning_delta. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
9829cf66d2
commit
0033a8a185
@ -30,6 +30,9 @@ interface StreamBuffer {
|
||||
function attachReasoningChunk(prev: UIMessage[], chunk: string): UIMessage[] {
|
||||
for (let i = prev.length - 1; i >= 0; i -= 1) {
|
||||
const candidate = prev[i];
|
||||
// A user turn is a hard boundary: reasoning after it belongs to the new
|
||||
// assistant turn, never to an earlier assistant reply.
|
||||
if (candidate.role === "user") break;
|
||||
if (candidate.role !== "assistant" || candidate.kind === "trace") continue;
|
||||
const hasAnswer = candidate.content.length > 0;
|
||||
if (
|
||||
|
||||
@ -238,6 +238,44 @@ describe("useNanobotStream", () => {
|
||||
expect(result.current.messages[0].reasoningStreaming).toBe(false);
|
||||
});
|
||||
|
||||
it("does not attach a new turn's reasoning across the latest user boundary", () => {
|
||||
const fake = fakeClient();
|
||||
const initialMessages = [
|
||||
{
|
||||
id: "a-prev",
|
||||
role: "assistant" as const,
|
||||
content: "Previous answer.",
|
||||
reasoning: "Previous thought.",
|
||||
createdAt: Date.now(),
|
||||
},
|
||||
{
|
||||
id: "u-next",
|
||||
role: "user" as const,
|
||||
content: "Next question",
|
||||
createdAt: Date.now(),
|
||||
},
|
||||
];
|
||||
const { result } = renderHook(
|
||||
() => useNanobotStream("chat-r6", initialMessages),
|
||||
{ wrapper: wrap(fake.client) },
|
||||
);
|
||||
|
||||
act(() => {
|
||||
fake.emit("chat-r6", {
|
||||
event: "reasoning_delta",
|
||||
chat_id: "chat-r6",
|
||||
text: "New turn thinking.",
|
||||
});
|
||||
});
|
||||
|
||||
expect(result.current.messages).toHaveLength(3);
|
||||
expect(result.current.messages[0].reasoning).toBe("Previous thought.");
|
||||
expect(result.current.messages[2].role).toBe("assistant");
|
||||
expect(result.current.messages[2].content).toBe("");
|
||||
expect(result.current.messages[2].reasoning).toBe("New turn thinking.");
|
||||
expect(result.current.messages[2].reasoningStreaming).toBe(true);
|
||||
});
|
||||
|
||||
it("attaches assistant media_urls to complete messages", () => {
|
||||
const fake = fakeClient();
|
||||
const { result } = renderHook(() => useNanobotStream("chat-m", EMPTY_MESSAGES), {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user