mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-09-04 10:11:46 +03:00
fix(webui): clear stale stream state after reconnect
This commit is contained in:
@@ -70,6 +70,7 @@ function normalizeProjection(messages: UIMessage[]): Array<Record<string, unknow
|
||||
function fakeClient() {
|
||||
const handlers = new Map<string, Set<(ev: InboundEvent) => void>>();
|
||||
const statusHandlers = new Set<(status: ConnectionStatus) => void>();
|
||||
const runStatusHandlers = new Set<(chatId: string, startedAt: number | null) => void>();
|
||||
const errorHandlers = new Set<(error: StreamError) => void>();
|
||||
const runStartedAtByChatId = new Map<string, number>();
|
||||
const unsettledRunByChatId = new Map<string, boolean>();
|
||||
@@ -111,6 +112,11 @@ function fakeClient() {
|
||||
handler(status);
|
||||
return () => statusHandlers.delete(handler);
|
||||
},
|
||||
onRunStatus(handler: (chatId: string, startedAt: number | null) => void) {
|
||||
runStatusHandlers.add(handler);
|
||||
for (const [chatId, startedAt] of runStartedAtByChatId) handler(chatId, startedAt);
|
||||
return () => runStatusHandlers.delete(handler);
|
||||
},
|
||||
onError(handler: (error: StreamError) => void) {
|
||||
errorHandlers.add(handler);
|
||||
return () => errorHandlers.delete(handler);
|
||||
@@ -154,6 +160,11 @@ function fakeClient() {
|
||||
status = nextStatus;
|
||||
statusHandlers.forEach((handler) => handler(status));
|
||||
},
|
||||
emitRunStatus(chatId: string, startedAt: number | null) {
|
||||
if (startedAt === null) runStartedAtByChatId.delete(chatId);
|
||||
else runStartedAtByChatId.set(chatId, startedAt);
|
||||
runStatusHandlers.forEach((handler) => handler(chatId, startedAt));
|
||||
},
|
||||
emitError(error: StreamError) {
|
||||
errorHandlers.forEach((handler) => handler(error));
|
||||
},
|
||||
@@ -327,6 +338,39 @@ describe("useNanobotStream", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("clears stale stream state when the transport resets a run", async () => {
|
||||
const fake = fakeClient();
|
||||
const { result } = renderHook(
|
||||
() => useNanobotStream("chat-reconnect-reset", EMPTY_MESSAGES),
|
||||
{ wrapper: wrap(fake.client) },
|
||||
);
|
||||
|
||||
act(() => {
|
||||
fake.emit("chat-reconnect-reset", {
|
||||
event: "goal_status",
|
||||
chat_id: "chat-reconnect-reset",
|
||||
status: "running",
|
||||
started_at: 1_700,
|
||||
});
|
||||
fake.emit("chat-reconnect-reset", {
|
||||
event: "delta",
|
||||
chat_id: "chat-reconnect-reset",
|
||||
text: "partial",
|
||||
});
|
||||
});
|
||||
await flushStreamFrame();
|
||||
expect(result.current.isStreaming).toBe(true);
|
||||
|
||||
act(() => fake.emitRunStatus("chat-reconnect-reset", null));
|
||||
|
||||
expect(result.current.runStartedAt).toBeNull();
|
||||
expect(result.current.isStreaming).toBe(false);
|
||||
expect(result.current.messages[0]).toMatchObject({
|
||||
content: "partial",
|
||||
isStreaming: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("flushes pending delta text before turn_end finalizes the turn", () => {
|
||||
const fake = fakeClient();
|
||||
const { result } = renderHook(() => useNanobotStream("chat-flush", EMPTY_MESSAGES), {
|
||||
|
||||
Reference in New Issue
Block a user