fd6659dd5d
closes #6162
137 lines
4.2 KiB
TypeScript
137 lines
4.2 KiB
TypeScript
import { fauxAssistantMessage, fauxToolCall } from "@earendil-works/pi-ai";
|
|
import { Type } from "typebox";
|
|
import { describe, expect, it } from "vitest";
|
|
import type { ExtensionFactory } from "../../../src/index.ts";
|
|
import { createHarness } from "../harness.ts";
|
|
|
|
describe("extension active tools next-turn refresh", () => {
|
|
it("applies pi.setActiveTools before the next provider request in the same run", async () => {
|
|
const extensionFactories: ExtensionFactory[] = [
|
|
(pi) => {
|
|
pi.registerTool({
|
|
name: "switch_tools",
|
|
label: "Switch Tools",
|
|
description: "Switch the active extension tool set",
|
|
promptSnippet: "Switch to the next extension tool",
|
|
parameters: Type.Object({}),
|
|
execute: async () => {
|
|
pi.setActiveTools(["after_switch"]);
|
|
return {
|
|
content: [{ type: "text", text: "switched" }],
|
|
details: {},
|
|
};
|
|
},
|
|
});
|
|
|
|
pi.registerTool({
|
|
name: "after_switch",
|
|
label: "After Switch",
|
|
description: "Tool that should be available after switching",
|
|
promptSnippet: "Run after the active tool set changes",
|
|
parameters: Type.Object({}),
|
|
execute: async () => ({
|
|
content: [{ type: "text", text: "after" }],
|
|
details: {},
|
|
}),
|
|
});
|
|
},
|
|
];
|
|
const harness = await createHarness({
|
|
extensionFactories,
|
|
});
|
|
|
|
try {
|
|
harness.session.setActiveToolsByName(["switch_tools"]);
|
|
|
|
const providerToolNames: string[][] = [];
|
|
harness.setResponses([
|
|
(context) => {
|
|
providerToolNames.push((context.tools ?? []).map((tool) => tool.name).sort());
|
|
return fauxAssistantMessage(fauxToolCall("switch_tools", {}), { stopReason: "toolUse" });
|
|
},
|
|
(context) => {
|
|
providerToolNames.push((context.tools ?? []).map((tool) => tool.name).sort());
|
|
return fauxAssistantMessage("done");
|
|
},
|
|
]);
|
|
|
|
expect(harness.session.getActiveToolNames()).toEqual(["switch_tools"]);
|
|
|
|
await harness.session.prompt("start");
|
|
|
|
expect(harness.session.getActiveToolNames()).toEqual(["after_switch"]);
|
|
expect(providerToolNames).toEqual([["switch_tools"], ["after_switch"]]);
|
|
} finally {
|
|
harness.cleanup();
|
|
}
|
|
});
|
|
|
|
it("preserves before_agent_start system prompt overrides when tools change mid-run", async () => {
|
|
const extensionFactories: ExtensionFactory[] = [
|
|
(pi) => {
|
|
pi.on("before_agent_start", async (event) => ({
|
|
systemPrompt: `${event.systemPrompt}\n\nkeep this run override`,
|
|
}));
|
|
|
|
pi.registerTool({
|
|
name: "switch_tools",
|
|
label: "Switch Tools",
|
|
description: "Switch the active extension tool set",
|
|
promptSnippet: "Switch to the next extension tool",
|
|
parameters: Type.Object({}),
|
|
execute: async () => {
|
|
pi.setActiveTools(["after_switch"]);
|
|
return {
|
|
content: [{ type: "text", text: "switched" }],
|
|
details: {},
|
|
};
|
|
},
|
|
});
|
|
|
|
pi.registerTool({
|
|
name: "after_switch",
|
|
label: "After Switch",
|
|
description: "Tool that should be available after switching",
|
|
promptSnippet: "Run after the active tool set changes",
|
|
parameters: Type.Object({}),
|
|
execute: async () => ({
|
|
content: [{ type: "text", text: "after" }],
|
|
details: {},
|
|
}),
|
|
});
|
|
},
|
|
];
|
|
const harness = await createHarness({
|
|
extensionFactories,
|
|
});
|
|
|
|
try {
|
|
harness.session.setActiveToolsByName(["switch_tools"]);
|
|
|
|
const providerSystemPrompts: string[] = [];
|
|
const providerToolNames: string[][] = [];
|
|
harness.setResponses([
|
|
(context) => {
|
|
providerSystemPrompts.push(context.systemPrompt ?? "");
|
|
providerToolNames.push((context.tools ?? []).map((tool) => tool.name).sort());
|
|
return fauxAssistantMessage(fauxToolCall("switch_tools", {}), { stopReason: "toolUse" });
|
|
},
|
|
(context) => {
|
|
providerSystemPrompts.push(context.systemPrompt ?? "");
|
|
providerToolNames.push((context.tools ?? []).map((tool) => tool.name).sort());
|
|
return fauxAssistantMessage("done");
|
|
},
|
|
]);
|
|
|
|
await harness.session.prompt("start");
|
|
|
|
expect(providerToolNames).toEqual([["switch_tools"], ["after_switch"]]);
|
|
expect(providerSystemPrompts).toHaveLength(2);
|
|
expect(providerSystemPrompts[0]).toContain("keep this run override");
|
|
expect(providerSystemPrompts[1]).toContain("keep this run override");
|
|
} finally {
|
|
harness.cleanup();
|
|
}
|
|
});
|
|
});
|