Files
oh-my-pi/packages/agent/test/handoff.test.ts
T
can1357 1b9d9d0851 refactor(catalog)!: split model catalog from pi-ai
Move bundled models, model cache/manager, thinking metadata, effort helpers,
provider descriptors/discovery, wire constants, and model identity utilities
into the new @oh-my-pi/pi-catalog package.

Update pi-ai to keep provider runtime/auth concerns, move catalog provider
metadata into CATALOG_PROVIDERS, and migrate coding-agent, agent, stats, docs,
and tests to import catalog values from pi-catalog.

Split coding-agent model registry helpers into discovery, roles, and models
config modules while preserving registry orchestration.

BREAKING CHANGE: @oh-my-pi/pi-ai no longer exports catalog subpaths such as
/models, /model-cache, /model-manager, /model-thinking, /effort,
/provider-models*, discovery helpers, and provider wire constants; use the
matching @oh-my-pi/pi-catalog subpaths instead.
2026-06-10 04:06:57 +02:00

113 lines
3.8 KiB
TypeScript

import { afterEach, describe, expect, test, vi } from "bun:test";
import type { AgentMessage, AgentTool } from "@oh-my-pi/pi-agent-core";
import { AUTO_HANDOFF_THRESHOLD_FOCUS, generateHandoff, renderHandoffPrompt } from "@oh-my-pi/pi-agent-core/compaction";
import type { AssistantMessage, Model, ToolCall } from "@oh-my-pi/pi-ai";
import * as ai from "@oh-my-pi/pi-ai";
import { Effort } from "@oh-my-pi/pi-ai";
import { getBundledModel } from "@oh-my-pi/pi-catalog/models";
function createAssistantMessage(content: AssistantMessage["content"]): AssistantMessage {
return {
role: "assistant",
content,
timestamp: Date.now(),
provider: "mock",
model: "mock",
api: "mock",
usage: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
totalTokens: 0,
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
},
stopReason: "stop",
};
}
function getTestModel(): Model {
const model = getBundledModel("anthropic", "claude-sonnet-4-5");
if (!model) {
throw new Error("Expected built-in anthropic model to exist");
}
return model;
}
afterEach(() => {
vi.restoreAllMocks();
});
describe("handoff helpers", () => {
test("renders custom focus into the handoff prompt", () => {
const rendered = renderHandoffPrompt("preserve failing test name");
expect(rendered).toContain("preserve failing test name");
});
test("exports the threshold focus text used by auto-handoff", () => {
expect(AUTO_HANDOFF_THRESHOLD_FOCUS).toBe(
"Threshold-triggered maintenance: preserve critical implementation state and immediate next actions.",
);
});
test("generates handoff with the live cache prefix and tool use disabled", async () => {
const strayToolCall: ToolCall = { type: "toolCall", id: "call_1", name: "read", arguments: {} };
const completeSimpleSpy = vi
.spyOn(ai, "completeSimple")
.mockResolvedValue(
createAssistantMessage([
{ type: "text", text: "## Goal\nContinue" },
strayToolCall,
{ type: "text", text: "## Next Steps\n1. Run the focused test" },
]),
);
const model = getTestModel();
const systemPrompt = ["Live system prompt"];
const tools: AgentTool[] = [];
const messages: AgentMessage[] = [
{ role: "user", content: "start work", timestamp: 1 },
createAssistantMessage([{ type: "text", text: "started" }]),
];
const document = await generateHandoff(messages, model, "test-key", {
systemPrompt,
tools,
customInstructions: "preserve failing test name",
initiatorOverride: "agent",
metadata: { session: "handoff-test" },
});
expect(document).toBe("## Goal\nContinue\n## Next Steps\n1. Run the focused test");
expect(completeSimpleSpy).toHaveBeenCalledTimes(1);
const call = completeSimpleSpy.mock.calls[0];
if (!call) throw new Error("Expected completeSimple call");
const [calledModel, context, options] = call;
expect(calledModel).toBe(model);
expect(context.systemPrompt).toBe(systemPrompt);
expect(context.tools).toBe(tools);
expect(context.messages[0]).toMatchObject({ role: "user", content: "start work" });
expect(options).toMatchObject({
apiKey: "test-key",
reasoning: Effort.High,
toolChoice: "none",
initiatorOverride: "agent",
metadata: { session: "handoff-test" },
});
const lastMessage = context.messages[context.messages.length - 1];
if (!lastMessage) throw new Error("Expected trailing handoff prompt message");
if (lastMessage.role !== "user") {
throw new Error("Expected trailing handoff prompt to be a user message");
}
expect(lastMessage.attribution).toBe("agent");
if (!Array.isArray(lastMessage.content)) {
throw new Error("Expected handoff prompt content blocks");
}
const promptBlock = lastMessage.content[0];
if (promptBlock?.type !== "text") {
throw new Error("Expected text handoff prompt block");
}
expect(promptBlock.text).toContain("preserve failing test name");
});
});