murashit_codex-panel/tests/features/threads/workflows/thread-title-service.test.ts

68 lines
2.6 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
import { THREAD_TITLE_CONTEXT_UNAVAILABLE_MESSAGE, type ThreadTitleContext } from "../../../../src/domain/threads/title-generation-model";
import {
createThreadTitleService,
type ThreadTitleService,
type ThreadTitleServiceHost,
} from "../../../../src/features/threads/workflows/thread-title-service";
describe("ThreadTitleService", () => {
it("generates a title from visible context without saving it", async () => {
const generateThreadTitle = vi.fn().mockResolvedValue("Generated title");
const withClient = vi.fn().mockRejectedValue(new Error("should not read persisted context"));
const service = titleService({
visibleContext: () => titleContext("visible request", "visible response"),
generateThreadTitle,
transport: {
persistedContext: withClient,
generateTitle: generateThreadTitle,
},
});
await expect(service.generateTitle("thread")).resolves.toBe("Generated title");
expect(withClient).not.toHaveBeenCalled();
expect(generateThreadTitle).toHaveBeenCalledWith(titleContext("visible request", "visible response"));
});
it("throws the existing unavailable-context error when no context can be resolved", async () => {
const service = titleService();
await expect(service.generateTitle("thread")).rejects.toThrow(THREAD_TITLE_CONTEXT_UNAVAILABLE_MESSAGE);
});
it("prefers visible completed-turn context over completed summaries", () => {
const service = titleService({
visibleCompletedTurnContext: () => titleContext("visible turn", "visible answer"),
});
expect(service.completedTurnContext("turn", { userText: "summary turn", assistantText: "summary answer" })).toEqual(
titleContext("visible turn", "visible answer"),
);
});
it("falls back from visible completed-turn context to completed summaries", () => {
const service = titleService({
visibleCompletedTurnContext: () => null,
});
expect(service.completedTurnContext("turn", { userText: "summary turn", assistantText: "summary answer" })).toEqual(
titleContext("summary turn", "summary answer"),
);
});
});
function titleService(options: Partial<ThreadTitleServiceHost> = {}): ThreadTitleService {
return createThreadTitleService({
transport: {
persistedContext: vi.fn().mockResolvedValue(null),
generateTitle: vi.fn().mockResolvedValue(null),
},
...options,
});
}
function titleContext(userRequest: string, assistantResponse: string): ThreadTitleContext {
return { userRequest, assistantResponse };
}