diff --git a/src/agents/tools/media-generate-background.test-support.ts b/src/agents/tools/media-generate-background.test-support.ts new file mode 100644 index 00000000000..e8664b9014e --- /dev/null +++ b/src/agents/tools/media-generate-background.test-support.ts @@ -0,0 +1,162 @@ +import { expect, vi } from "vitest"; + +type MockWithReset = { + mockReset(): void; +}; + +export const taskExecutorMocks = { + createRunningTaskRun: vi.fn(), + recordTaskRunProgressByRunId: vi.fn(), + completeTaskRunByRunId: vi.fn(), + failTaskRunByRunId: vi.fn(), +}; + +export const announceDeliveryMocks = { + deliverSubagentAnnouncement: vi.fn(), +}; + +export const taskDeliveryRuntimeMocks = { + sendMessage: vi.fn(), +}; + +type TaskExecutorBackgroundMocks = { + createRunningTaskRun: MockWithReset; + recordTaskRunProgressByRunId: MockWithReset; +}; + +type TaskDeliveryBackgroundMocks = { + sendMessage: MockWithReset; +}; + +type AnnouncementBackgroundMocks = { + deliverSubagentAnnouncement: MockWithReset; +}; + +type MediaBackgroundResetMocks = { + taskExecutorMocks: TaskExecutorBackgroundMocks; + taskDeliveryRuntimeMocks: TaskDeliveryBackgroundMocks; + announceDeliveryMocks: AnnouncementBackgroundMocks; +}; + +type QueuedTaskExpectation = { + taskExecutorMocks: TaskExecutorBackgroundMocks; + taskKind: string; + sourceId: string; + progressSummary: string; +}; + +type ProgressExpectation = { + taskExecutorMocks: TaskExecutorBackgroundMocks; + runId: string; + progressSummary: string; +}; + +type DirectSendExpectation = { + sendMessageMock: unknown; + channel: string; + to: string; + threadId: string; + content: string; + mediaUrls: string[]; +}; + +type FallbackAnnouncementExpectation = { + deliverAnnouncementMock: unknown; + requesterSessionKey: string; + channel: string; + to: string; + source: string; + announceType: string; + resultMediaPath: string; + mediaUrls: string[]; +}; + +export function resetMediaBackgroundMocks({ + taskExecutorMocks, + taskDeliveryRuntimeMocks, + announceDeliveryMocks, +}: MediaBackgroundResetMocks): void { + taskExecutorMocks.createRunningTaskRun.mockReset(); + taskExecutorMocks.recordTaskRunProgressByRunId.mockReset(); + taskDeliveryRuntimeMocks.sendMessage.mockReset(); + announceDeliveryMocks.deliverSubagentAnnouncement.mockReset(); +} + +export function expectQueuedTaskRun({ + taskExecutorMocks, + taskKind, + sourceId, + progressSummary, +}: QueuedTaskExpectation): void { + expect(taskExecutorMocks.createRunningTaskRun).toHaveBeenCalledWith( + expect.objectContaining({ + taskKind, + sourceId, + progressSummary, + }), + ); +} + +export function expectRecordedTaskProgress({ + taskExecutorMocks, + runId, + progressSummary, +}: ProgressExpectation): void { + expect(taskExecutorMocks.recordTaskRunProgressByRunId).toHaveBeenCalledWith( + expect.objectContaining({ + runId, + progressSummary, + }), + ); +} + +export function expectDirectMediaSend({ + sendMessageMock, + channel, + to, + threadId, + content, + mediaUrls, +}: DirectSendExpectation): void { + expect(sendMessageMock).toHaveBeenCalledWith( + expect.objectContaining({ + channel, + to, + threadId, + content, + mediaUrls, + }), + ); +} + +export function expectFallbackMediaAnnouncement({ + deliverAnnouncementMock, + requesterSessionKey, + channel, + to, + source, + announceType, + resultMediaPath, + mediaUrls, +}: FallbackAnnouncementExpectation): void { + expect(deliverAnnouncementMock).toHaveBeenCalledWith( + expect.objectContaining({ + requesterSessionKey, + requesterOrigin: expect.objectContaining({ + channel, + to, + }), + expectsCompletionMessage: true, + internalEvents: expect.arrayContaining([ + expect.objectContaining({ + source, + announceType, + status: "ok", + result: expect.stringContaining(resultMediaPath), + mediaUrls, + replyInstruction: expect.stringContaining("Prefer the message tool for delivery"), + }), + ]), + }), + ); +} diff --git a/src/agents/tools/music-generate-background.test.ts b/src/agents/tools/music-generate-background.test.ts index 9f8a72f226f..3d9d9958675 100644 --- a/src/agents/tools/music-generate-background.test.ts +++ b/src/agents/tools/music-generate-background.test.ts @@ -1,35 +1,33 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { MUSIC_GENERATION_TASK_KIND } from "../music-generation-task-status.js"; import { - createMusicGenerationTaskRun, - recordMusicGenerationTaskProgress, - wakeMusicGenerationTaskCompletion, -} from "./music-generate-background.js"; - -const taskExecutorMocks = vi.hoisted(() => ({ - createRunningTaskRun: vi.fn(), - recordTaskRunProgressByRunId: vi.fn(), - completeTaskRunByRunId: vi.fn(), - failTaskRunByRunId: vi.fn(), -})); - -const announceDeliveryMocks = vi.hoisted(() => ({ - deliverSubagentAnnouncement: vi.fn(), -})); -const taskDeliveryRuntimeMocks = vi.hoisted(() => ({ - sendMessage: vi.fn(), -})); + announceDeliveryMocks, + expectDirectMediaSend, + expectFallbackMediaAnnouncement, + expectQueuedTaskRun, + expectRecordedTaskProgress, + resetMediaBackgroundMocks, + taskDeliveryRuntimeMocks, + taskExecutorMocks, +} from "./media-generate-background.test-support.js"; vi.mock("../../tasks/task-executor.js", () => taskExecutorMocks); vi.mock("../../tasks/task-registry-delivery-runtime.js", () => taskDeliveryRuntimeMocks); vi.mock("../subagent-announce-delivery.js", () => announceDeliveryMocks); +const { + createMusicGenerationTaskRun, + recordMusicGenerationTaskProgress, + wakeMusicGenerationTaskCompletion, +} = await import("./music-generate-background.js"); + describe("music generate background helpers", () => { beforeEach(() => { - taskExecutorMocks.createRunningTaskRun.mockReset(); - taskExecutorMocks.recordTaskRunProgressByRunId.mockReset(); - taskDeliveryRuntimeMocks.sendMessage.mockReset(); - announceDeliveryMocks.deliverSubagentAnnouncement.mockReset(); + resetMediaBackgroundMocks({ + taskExecutorMocks, + taskDeliveryRuntimeMocks, + announceDeliveryMocks, + }); }); it("creates a running task with queued progress text", () => { @@ -52,13 +50,12 @@ describe("music generate background helpers", () => { requesterSessionKey: "agent:main:discord:direct:123", taskLabel: "night-drive synthwave", }); - expect(taskExecutorMocks.createRunningTaskRun).toHaveBeenCalledWith( - expect.objectContaining({ - taskKind: MUSIC_GENERATION_TASK_KIND, - sourceId: "music_generate:google", - progressSummary: "Queued music generation", - }), - ); + expectQueuedTaskRun({ + taskExecutorMocks, + taskKind: MUSIC_GENERATION_TASK_KIND, + sourceId: "music_generate:google", + progressSummary: "Queued music generation", + }); }); it("records task progress updates", () => { @@ -72,12 +69,11 @@ describe("music generate background helpers", () => { progressSummary: "Saving generated music", }); - expect(taskExecutorMocks.recordTaskRunProgressByRunId).toHaveBeenCalledWith( - expect.objectContaining({ - runId: "tool:music_generate:abc", - progressSummary: "Saving generated music", - }), - ); + expectRecordedTaskProgress({ + taskExecutorMocks, + runId: "tool:music_generate:abc", + progressSummary: "Saving generated music", + }); }); it("queues a completion event by default when direct send is disabled", async () => { @@ -132,15 +128,14 @@ describe("music generate background helpers", () => { result: "Generated 1 track.\nMEDIA:/tmp/generated-night-drive.mp3", }); - expect(taskDeliveryRuntimeMocks.sendMessage).toHaveBeenCalledWith( - expect.objectContaining({ - channel: "discord", - to: "channel:1", - threadId: "thread-1", - content: "Generated 1 track.", - mediaUrls: ["/tmp/generated-night-drive.mp3"], - }), - ); + expectDirectMediaSend({ + sendMessageMock: taskDeliveryRuntimeMocks.sendMessage, + channel: "discord", + to: "channel:1", + threadId: "thread-1", + content: "Generated 1 track.", + mediaUrls: ["/tmp/generated-night-drive.mp3"], + }); expect(announceDeliveryMocks.deliverSubagentAnnouncement).not.toHaveBeenCalled(); }); @@ -170,25 +165,15 @@ describe("music generate background helpers", () => { mediaUrls: ["/tmp/generated-night-drive.mp3"], }); - expect(announceDeliveryMocks.deliverSubagentAnnouncement).toHaveBeenCalledWith( - expect.objectContaining({ - requesterSessionKey: "agent:main:discord:direct:123", - requesterOrigin: expect.objectContaining({ - channel: "discord", - to: "channel:1", - }), - expectsCompletionMessage: true, - internalEvents: expect.arrayContaining([ - expect.objectContaining({ - source: "music_generation", - announceType: "music generation task", - status: "ok", - result: expect.stringContaining("MEDIA:/tmp/generated-night-drive.mp3"), - mediaUrls: ["/tmp/generated-night-drive.mp3"], - replyInstruction: expect.stringContaining("Prefer the message tool for delivery"), - }), - ]), - }), - ); + expectFallbackMediaAnnouncement({ + deliverAnnouncementMock: announceDeliveryMocks.deliverSubagentAnnouncement, + requesterSessionKey: "agent:main:discord:direct:123", + channel: "discord", + to: "channel:1", + source: "music_generation", + announceType: "music generation task", + resultMediaPath: "MEDIA:/tmp/generated-night-drive.mp3", + mediaUrls: ["/tmp/generated-night-drive.mp3"], + }); }); }); diff --git a/src/agents/tools/video-generate-background.test.ts b/src/agents/tools/video-generate-background.test.ts index ec932d233ae..ae23883673d 100644 --- a/src/agents/tools/video-generate-background.test.ts +++ b/src/agents/tools/video-generate-background.test.ts @@ -1,35 +1,33 @@ import { beforeEach, describe, expect, it, vi } from "vitest"; import { VIDEO_GENERATION_TASK_KIND } from "../video-generation-task-status.js"; import { - createVideoGenerationTaskRun, - recordVideoGenerationTaskProgress, - wakeVideoGenerationTaskCompletion, -} from "./video-generate-background.js"; - -const taskExecutorMocks = vi.hoisted(() => ({ - createRunningTaskRun: vi.fn(), - recordTaskRunProgressByRunId: vi.fn(), - completeTaskRunByRunId: vi.fn(), - failTaskRunByRunId: vi.fn(), -})); - -const announceDeliveryMocks = vi.hoisted(() => ({ - deliverSubagentAnnouncement: vi.fn(), -})); -const taskDeliveryRuntimeMocks = vi.hoisted(() => ({ - sendMessage: vi.fn(), -})); + announceDeliveryMocks, + expectDirectMediaSend, + expectFallbackMediaAnnouncement, + expectQueuedTaskRun, + expectRecordedTaskProgress, + resetMediaBackgroundMocks, + taskDeliveryRuntimeMocks, + taskExecutorMocks, +} from "./media-generate-background.test-support.js"; vi.mock("../../tasks/task-executor.js", () => taskExecutorMocks); vi.mock("../../tasks/task-registry-delivery-runtime.js", () => taskDeliveryRuntimeMocks); vi.mock("../subagent-announce-delivery.js", () => announceDeliveryMocks); +const { + createVideoGenerationTaskRun, + recordVideoGenerationTaskProgress, + wakeVideoGenerationTaskCompletion, +} = await import("./video-generate-background.js"); + describe("video generate background helpers", () => { beforeEach(() => { - taskExecutorMocks.createRunningTaskRun.mockReset(); - taskExecutorMocks.recordTaskRunProgressByRunId.mockReset(); - taskDeliveryRuntimeMocks.sendMessage.mockReset(); - announceDeliveryMocks.deliverSubagentAnnouncement.mockReset(); + resetMediaBackgroundMocks({ + taskExecutorMocks, + taskDeliveryRuntimeMocks, + announceDeliveryMocks, + }); }); it("creates a running task with queued progress text", () => { @@ -52,13 +50,12 @@ describe("video generate background helpers", () => { requesterSessionKey: "agent:main:discord:direct:123", taskLabel: "friendly lobster surfing", }); - expect(taskExecutorMocks.createRunningTaskRun).toHaveBeenCalledWith( - expect.objectContaining({ - taskKind: VIDEO_GENERATION_TASK_KIND, - sourceId: "video_generate:openai", - progressSummary: "Queued video generation", - }), - ); + expectQueuedTaskRun({ + taskExecutorMocks, + taskKind: VIDEO_GENERATION_TASK_KIND, + sourceId: "video_generate:openai", + progressSummary: "Queued video generation", + }); }); it("records task progress updates", () => { @@ -72,12 +69,11 @@ describe("video generate background helpers", () => { progressSummary: "Saving generated video", }); - expect(taskExecutorMocks.recordTaskRunProgressByRunId).toHaveBeenCalledWith( - expect.objectContaining({ - runId: "tool:video_generate:abc", - progressSummary: "Saving generated video", - }), - ); + expectRecordedTaskProgress({ + taskExecutorMocks, + runId: "tool:video_generate:abc", + progressSummary: "Saving generated video", + }); }); it("queues a completion event by default when direct send is disabled", async () => { @@ -132,15 +128,14 @@ describe("video generate background helpers", () => { result: "Generated 1 video.\nMEDIA:/tmp/generated-lobster.mp4", }); - expect(taskDeliveryRuntimeMocks.sendMessage).toHaveBeenCalledWith( - expect.objectContaining({ - channel: "discord", - to: "channel:1", - threadId: "thread-1", - content: "Generated 1 video.", - mediaUrls: ["/tmp/generated-lobster.mp4"], - }), - ); + expectDirectMediaSend({ + sendMessageMock: taskDeliveryRuntimeMocks.sendMessage, + channel: "discord", + to: "channel:1", + threadId: "thread-1", + content: "Generated 1 video.", + mediaUrls: ["/tmp/generated-lobster.mp4"], + }); expect(announceDeliveryMocks.deliverSubagentAnnouncement).not.toHaveBeenCalled(); }); @@ -170,25 +165,15 @@ describe("video generate background helpers", () => { mediaUrls: ["/tmp/generated-lobster.mp4"], }); - expect(announceDeliveryMocks.deliverSubagentAnnouncement).toHaveBeenCalledWith( - expect.objectContaining({ - requesterSessionKey: "agent:main:discord:direct:123", - requesterOrigin: expect.objectContaining({ - channel: "discord", - to: "channel:1", - }), - expectsCompletionMessage: true, - internalEvents: expect.arrayContaining([ - expect.objectContaining({ - source: "video_generation", - announceType: "video generation task", - status: "ok", - result: expect.stringContaining("MEDIA:/tmp/generated-lobster.mp4"), - mediaUrls: ["/tmp/generated-lobster.mp4"], - replyInstruction: expect.stringContaining("Prefer the message tool for delivery"), - }), - ]), - }), - ); + expectFallbackMediaAnnouncement({ + deliverAnnouncementMock: announceDeliveryMocks.deliverSubagentAnnouncement, + requesterSessionKey: "agent:main:discord:direct:123", + channel: "discord", + to: "channel:1", + source: "video_generation", + announceType: "video generation task", + resultMediaPath: "MEDIA:/tmp/generated-lobster.mp4", + mediaUrls: ["/tmp/generated-lobster.mp4"], + }); }); });