import { describe, expect, it } from "vitest"; import { ToolConfirmationManager, type ToolConfirmationRequest } from "../src/agent/confirmations.js"; function request(manager: ToolConfirmationManager, toolCallId = "call-1", signal?: AbortSignal) { let emitted: ToolConfirmationRequest | undefined; const promise = manager.request( { sessionId: "s1", toolCallId, toolName: "generate_image", args: { prompt: "poster" }, }, (value) => { emitted = value; }, signal, ); return { promise, get emitted() { return emitted; } }; } describe("ToolConfirmationManager", () => { it("waits for approval and resolves the tool call", async () => { const manager = new ToolConfirmationManager(1_000); const pending = request(manager); expect(pending.emitted?.toolCallId).toBe("call-1"); expect(pending.emitted?.expiresAt).toBeGreaterThan(Date.now()); expect(manager.resolve("s1", "call-1", true)).toBe(true); await expect(pending.promise).resolves.toEqual({ approved: true, reason: undefined }); expect(manager.count()).toBe(0); }); it("carries confirm type/payload and resolves edited content", async () => { const manager = new ToolConfirmationManager(1_000); let emitted: ToolConfirmationRequest | undefined; const promise = manager.request( { sessionId: "s1", toolCallId: "call-content", toolName: "confirm_travel_content", confirmType: "travel_content_confirm", payload: { summary: "线路:测试" }, args: {}, }, (value) => { emitted = value; }, ); expect(emitted?.confirmType).toBe("travel_content_confirm"); expect(emitted?.payload).toEqual({ summary: "线路:测试" }); expect(manager.resolve("s1", "call-content", { approved: true, content: "用户修改后的内容" })).toBe(true); await expect(promise).resolves.toEqual({ approved: true, content: "用户修改后的内容" }); }); it("returns a rejection reason", async () => { const manager = new ToolConfirmationManager(1_000); const pending = request(manager); manager.resolve("s1", "call-1", false, "不要生成"); await expect(pending.promise).resolves.toEqual({ approved: false, reason: "不要生成" }); }); it("times out and does not leave stale entries", async () => { const manager = new ToolConfirmationManager(10); const pending = request(manager); await expect(pending.promise).resolves.toMatchObject({ approved: false, reason: "等待用户确认超时" }); expect(manager.count()).toBe(0); }); it("cancels when the run is aborted", async () => { const manager = new ToolConfirmationManager(1_000); const controller = new AbortController(); const pending = request(manager, "call-abort", controller.signal); controller.abort(); await expect(pending.promise).resolves.toEqual({ approved: false, reason: "请求已中止" }); }); it("clears all pending confirmations for a session", async () => { const manager = new ToolConfirmationManager(1_000); const first = request(manager, "call-1"); const second = request(manager, "call-2"); manager.clearSession("s1"); await expect(first.promise).resolves.toMatchObject({ approved: false, reason: "会话已结束" }); await expect(second.promise).resolves.toMatchObject({ approved: false, reason: "会话已结束" }); }); it("rejects duplicate pending confirmations for the same tool call", async () => { const manager = new ToolConfirmationManager(1_000); const first = request(manager); const duplicate = request(manager); await expect(duplicate.promise).resolves.toMatchObject({ approved: false }); manager.resolve("s1", "call-1", true); await expect(first.promise).resolves.toEqual({ approved: true, reason: undefined }); }); });