fix(coding-agent): emit session_shutdown in print mode closes #2576
This commit is contained in:
124
packages/coding-agent/test/print-mode.test.ts
Normal file
124
packages/coding-agent/test/print-mode.test.ts
Normal file
@@ -0,0 +1,124 @@
|
||||
import type { AssistantMessage, ImageContent } from "@mariozechner/pi-ai";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { runPrintMode } from "../src/modes/print-mode.js";
|
||||
|
||||
type EmitEvent = { type: string };
|
||||
|
||||
type FakeExtensionRunner = {
|
||||
hasHandlers: (eventType: string) => boolean;
|
||||
emit: ReturnType<typeof vi.fn<(event: EmitEvent) => Promise<void>>>;
|
||||
};
|
||||
|
||||
type FakeSession = {
|
||||
sessionManager: { getHeader: () => object | undefined };
|
||||
agent: { waitForIdle: () => Promise<void> };
|
||||
state: { messages: AssistantMessage[] };
|
||||
extensionRunner: FakeExtensionRunner;
|
||||
bindExtensions: ReturnType<typeof vi.fn>;
|
||||
subscribe: ReturnType<typeof vi.fn>;
|
||||
prompt: ReturnType<typeof vi.fn>;
|
||||
newSession: ReturnType<typeof vi.fn>;
|
||||
fork: ReturnType<typeof vi.fn>;
|
||||
navigateTree: ReturnType<typeof vi.fn>;
|
||||
switchSession: ReturnType<typeof vi.fn>;
|
||||
reload: ReturnType<typeof vi.fn>;
|
||||
};
|
||||
|
||||
function createAssistantMessage(options?: {
|
||||
text?: string;
|
||||
stopReason?: AssistantMessage["stopReason"];
|
||||
errorMessage?: string;
|
||||
}): AssistantMessage {
|
||||
return {
|
||||
role: "assistant",
|
||||
content: options?.text ? [{ type: "text", text: options.text }] : [],
|
||||
api: "openai-responses",
|
||||
provider: "openai",
|
||||
model: "gpt-4o-mini",
|
||||
usage: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
totalTokens: 0,
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
||||
},
|
||||
stopReason: options?.stopReason ?? "stop",
|
||||
errorMessage: options?.errorMessage,
|
||||
timestamp: Date.now(),
|
||||
};
|
||||
}
|
||||
|
||||
function createSession(assistantMessage: AssistantMessage): FakeSession {
|
||||
const extensionRunner: FakeExtensionRunner = {
|
||||
hasHandlers: (eventType: string) => eventType === "session_shutdown",
|
||||
emit: vi.fn(async () => {}),
|
||||
};
|
||||
|
||||
const state = { messages: [assistantMessage] };
|
||||
|
||||
return {
|
||||
sessionManager: { getHeader: () => undefined },
|
||||
agent: { waitForIdle: async () => {} },
|
||||
state,
|
||||
extensionRunner,
|
||||
bindExtensions: vi.fn(async () => {}),
|
||||
subscribe: vi.fn(() => () => {}),
|
||||
prompt: vi.fn(async () => {}),
|
||||
newSession: vi.fn(async () => true),
|
||||
fork: vi.fn(async () => ({ cancelled: false })),
|
||||
navigateTree: vi.fn(async () => ({ cancelled: false })),
|
||||
switchSession: vi.fn(async () => true),
|
||||
reload: vi.fn(async () => {}),
|
||||
};
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe("runPrintMode", () => {
|
||||
it("emits session_shutdown in text mode", async () => {
|
||||
const session = createSession(createAssistantMessage({ text: "done" }));
|
||||
const images: ImageContent[] = [{ type: "image", mimeType: "image/png", data: "abc" }];
|
||||
|
||||
const exitCode = await runPrintMode(session as unknown as Parameters<typeof runPrintMode>[0], {
|
||||
mode: "text",
|
||||
initialMessage: "Say done",
|
||||
initialImages: images,
|
||||
});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(session.prompt).toHaveBeenCalledWith("Say done", { images });
|
||||
expect(session.extensionRunner.emit).toHaveBeenCalledTimes(1);
|
||||
expect(session.extensionRunner.emit).toHaveBeenCalledWith({ type: "session_shutdown" });
|
||||
});
|
||||
|
||||
it("emits session_shutdown in json mode", async () => {
|
||||
const session = createSession(createAssistantMessage({ text: "done" }));
|
||||
|
||||
const exitCode = await runPrintMode(session as unknown as Parameters<typeof runPrintMode>[0], {
|
||||
mode: "json",
|
||||
messages: ["hello"],
|
||||
});
|
||||
|
||||
expect(exitCode).toBe(0);
|
||||
expect(session.prompt).toHaveBeenCalledWith("hello");
|
||||
expect(session.extensionRunner.emit).toHaveBeenCalledTimes(1);
|
||||
expect(session.extensionRunner.emit).toHaveBeenCalledWith({ type: "session_shutdown" });
|
||||
});
|
||||
|
||||
it("emits session_shutdown and returns non-zero on assistant error", async () => {
|
||||
const session = createSession(createAssistantMessage({ stopReason: "error", errorMessage: "provider failure" }));
|
||||
const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
||||
|
||||
const exitCode = await runPrintMode(session as unknown as Parameters<typeof runPrintMode>[0], {
|
||||
mode: "text",
|
||||
});
|
||||
|
||||
expect(exitCode).toBe(1);
|
||||
expect(errorSpy).toHaveBeenCalledWith("provider failure");
|
||||
expect(session.extensionRunner.emit).toHaveBeenCalledTimes(1);
|
||||
expect(session.extensionRunner.emit).toHaveBeenCalledWith({ type: "session_shutdown" });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user