






















@@ -8,6 +8,8 @@ type HandlerChatLog = {
88startTool: (...args: unknown[]) => void;
99updateToolResult: (...args: unknown[]) => void;
1010addSystem: (...args: unknown[]) => void;
11+addPendingSystem: (...args: unknown[]) => void;
12+dismissPendingSystem: (...args: unknown[]) => void;
1113updateAssistant: (...args: unknown[]) => void;
1214finalizeAssistant: (...args: unknown[]) => void;
1315dropAssistant: (...args: unknown[]) => void;
@@ -21,6 +23,8 @@ type MockChatLog = {
2123startTool: MockFn;
2224updateToolResult: MockFn;
2325addSystem: MockFn;
26+addPendingSystem: MockFn;
27+dismissPendingSystem: MockFn;
2428updateAssistant: MockFn;
2529finalizeAssistant: MockFn;
2630dropAssistant: MockFn;
@@ -36,6 +40,8 @@ function createMockChatLog(): MockChatLog & HandlerChatLog {
3640startTool: vi.fn(),
3741updateToolResult: vi.fn(),
3842addSystem: vi.fn(),
43+addPendingSystem: vi.fn(),
44+dismissPendingSystem: vi.fn(),
3945updateAssistant: vi.fn(),
4046finalizeAssistant: vi.fn(),
4147dropAssistant: vi.fn(),
@@ -1178,7 +1184,7 @@ describe("tui-event-handlers: streaming watchdog", () => {
1178118411791185expect(setActivityStatus).toHaveBeenLastCalledWith("idle");
11801186expect(state.activeChatRunId).toBeNull();
1181-expect(chatLog.addSystem).toHaveBeenCalledWith(expectedTimeoutMessage);
1187+expect(chatLog.addPendingSystem).toHaveBeenCalledWith("run-stuck", expectedTimeoutMessage);
1182118811831189handlers.dispose?.();
11841190});
@@ -1384,7 +1390,7 @@ describe("tui-event-handlers: streaming watchdog", () => {
13841390expect(setActivityStatus).toHaveBeenLastCalledWith("idle");
13851391expect(state.activeChatRunId).toBeNull();
13861392expect(loadHistory).toHaveBeenCalledTimes(1);
1387-expect(chatLog.addSystem).not.toHaveBeenCalledWith(expectedTimeoutMessage);
1393+expect(chatLog.addPendingSystem).not.toHaveBeenCalled();
1388139413891395handlers.dispose?.();
13901396});
@@ -1410,8 +1416,8 @@ describe("tui-event-handlers: streaming watchdog", () => {
14101416vi.advanceTimersByTime(10_000);
1411141714121418const statusCalls = setActivityStatus.mock.calls.map((c) => c[0]);
1413-expect(statusCalls.reduce((count, s) => count + (s === "idle" ? 1 : 0), 0)).toBe(1);
1414-expect(chatLog.addSystem).not.toHaveBeenCalledWith(expectedTimeoutMessage);
1419+expect(statusCalls.filter((s) => s === "idle").length).toBe(1);
1420+expect(chatLog.addPendingSystem).not.toHaveBeenCalled();
14151421expect(state.activeChatRunId).toBeNull();
1416142214171423handlers.dispose?.();
@@ -1432,7 +1438,7 @@ describe("tui-event-handlers: streaming watchdog", () => {
14321438vi.advanceTimersByTime(60_000);
1433143914341440expect(setActivityStatus).not.toHaveBeenCalledWith("idle");
1435-expect(chatLog.addSystem).not.toHaveBeenCalled();
1441+expect(chatLog.addPendingSystem).not.toHaveBeenCalled();
14361442expect(state.activeChatRunId).toBe("run-no-watchdog");
1437144314381444handlers.dispose?.();
@@ -1474,7 +1480,7 @@ describe("tui-event-handlers: streaming watchdog", () => {
1474148014751481expect(setActivityStatus).toHaveBeenLastCalledWith("idle");
14761482expect(state.activeChatRunId).toBeNull();
1477-expect(chatLog.addSystem).toHaveBeenCalledTimes(2);
1483+expect(chatLog.addPendingSystem).toHaveBeenCalledTimes(2);
1478148414791485handlers.dispose?.();
14801486});
@@ -1495,6 +1501,60 @@ describe("tui-event-handlers: streaming watchdog", () => {
14951501vi.advanceTimersByTime(10_000);
1496150214971503expect(setActivityStatus).not.toHaveBeenCalledWith("idle");
1498-expect(chatLog.addSystem).not.toHaveBeenCalled();
1504+expect(chatLog.addPendingSystem).not.toHaveBeenCalled();
1505+});
1506+1507+it("dismisses the watchdog notice when a delta arrives after the watchdog fires", () => {
1508+const { state, chatLog, handlers } = createHarness({
1509+streamingWatchdogMs: 5_000,
1510+});
1511+1512+handlers.handleChatEvent({
1513+runId: "run-late",
1514+sessionKey: state.currentSessionKey,
1515+state: "delta",
1516+message: { content: "starting" },
1517+} satisfies ChatEvent);
1518+1519+vi.advanceTimersByTime(5_001);
1520+expect(chatLog.addPendingSystem).toHaveBeenCalledWith("run-late", expectedTimeoutMessage);
1521+1522+handlers.handleChatEvent({
1523+runId: "run-late",
1524+sessionKey: state.currentSessionKey,
1525+state: "delta",
1526+message: { content: "actually here" },
1527+} satisfies ChatEvent);
1528+1529+expect(chatLog.dismissPendingSystem).toHaveBeenCalledWith("run-late");
1530+1531+handlers.dispose?.();
1532+});
1533+1534+it("dismisses the watchdog notice when the final arrives after the watchdog fires", () => {
1535+const { state, chatLog, handlers } = createHarness({
1536+streamingWatchdogMs: 5_000,
1537+});
1538+1539+handlers.handleChatEvent({
1540+runId: "run-final-late",
1541+sessionKey: state.currentSessionKey,
1542+state: "delta",
1543+message: { content: "starting" },
1544+} satisfies ChatEvent);
1545+1546+vi.advanceTimersByTime(5_001);
1547+expect(chatLog.addPendingSystem).toHaveBeenCalledWith("run-final-late", expectedTimeoutMessage);
1548+1549+handlers.handleChatEvent({
1550+runId: "run-final-late",
1551+sessionKey: state.currentSessionKey,
1552+state: "final",
1553+message: { content: [{ type: "text", text: "done" }], stopReason: "stop" },
1554+} satisfies ChatEvent);
1555+1556+expect(chatLog.dismissPendingSystem).toHaveBeenCalledWith("run-final-late");
1557+1558+handlers.dispose?.();
14991559});
15001560});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。