Files
oh-my-pi/packages/coding-agent/test/modes/controllers/event-controller-tool-render-mode.test.ts
T
roboomp 64b48b57b1 fix(tui): rebuilt scrollback during assistant streaming
Enable eager native scrollback rebuild mode while assistant text is actively streaming so reflowed Markdown rows do not leave stale duplicated tails in WSL/Windows Terminal scrollback.\n\nFixes #1615
2026-06-01 02:40:45 +00:00

84 lines
3.1 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it, vi } from "bun:test";
import { resetSettingsForTest, Settings } from "@oh-my-pi/pi-coding-agent/config/settings";
import { EventController } from "@oh-my-pi/pi-coding-agent/modes/controllers/event-controller";
import type { InteractiveModeContext } from "@oh-my-pi/pi-coding-agent/modes/types";
import type { AgentSessionEvent } from "@oh-my-pi/pi-coding-agent/session/agent-session";
function createContext() {
const setEagerNativeScrollbackRebuild = vi.fn();
const pendingTools = new Map<string, unknown>();
const chatContainer = { addChild: vi.fn() };
const ctx = {
isInitialized: true,
statusLine: { invalidate: vi.fn() },
updateEditorTopBorder: vi.fn(),
pendingTools,
chatContainer,
hideThinkingBlock: false,
session: { isTtsrAbortPending: false, retryAttempt: 0 },
ui: { setEagerNativeScrollbackRebuild, requestRender: vi.fn() },
} as unknown as InteractiveModeContext;
return { ctx, pendingTools, setEagerNativeScrollbackRebuild };
}
// A tool_execution_update for an id that is not pending is a no-op in its handler,
// so dispatching it exercises only the gated post-dispatch refresh in handleEvent —
// which is what syncs the TUI eager-rebuild flag to foreground-tool activity.
const REFRESH_TRIGGER = {
type: "tool_execution_update",
toolCallId: "not-pending",
partialResult: { content: [], details: {} },
} as unknown as AgentSessionEvent;
describe("EventController tool render mode", () => {
beforeEach(async () => {
resetSettingsForTest();
await Settings.init({ inMemory: true });
});
afterEach(() => {
resetSettingsForTest();
vi.restoreAllMocks();
});
it("enables eager native scrollback rebuild while a foreground tool is pending", async () => {
const { ctx, pendingTools, setEagerNativeScrollbackRebuild } = createContext();
const controller = new EventController(ctx);
pendingTools.set("call-1", {});
await controller.handleEvent(REFRESH_TRIGGER);
expect(setEagerNativeScrollbackRebuild).toHaveBeenLastCalledWith(true);
pendingTools.clear();
await controller.handleEvent(REFRESH_TRIGGER);
expect(setEagerNativeScrollbackRebuild).toHaveBeenLastCalledWith(false);
});
it("enables eager native scrollback rebuild while assistant text is streaming", async () => {
const { ctx, setEagerNativeScrollbackRebuild } = createContext();
const controller = new EventController(ctx);
const message = {
role: "assistant",
content: [{ type: "text", text: "" }],
api: "anthropic-messages",
provider: "anthropic",
model: "test-model",
usage: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 0,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
},
stopReason: "stop",
timestamp: 0,
} as const;
await controller.handleEvent({ type: "message_start", message } as unknown as AgentSessionEvent);
expect(setEagerNativeScrollbackRebuild).toHaveBeenLastCalledWith(true);
await controller.handleEvent({ type: "message_end", message } as unknown as AgentSessionEvent);
expect(setEagerNativeScrollbackRebuild).toHaveBeenLastCalledWith(false);
});
});