import path from "node:path"; import { beforeEach, describe, expect, it, vi } from "vitest"; import type { TemplateContext } from "../templating.js"; import type { FollowupRun, QueueSettings } from "./queue.js"; import { createMockFollowupRun, createMockTypingController } from "./test-helpers.js"; const runEmbeddedPiAgentMock = vi.fn(); const runWithModelFallbackMock = vi.fn(); vi.mock("../../agents/model-fallback.js", () => ({ runWithModelFallback: (params: { provider: string; model: string; run: (provider: string, model: string) => Promise; }) => runWithModelFallbackMock(params), })); vi.mock("../../agents/pi-embedded.js", async () => { const actual = await vi.importActual( "../../agents/pi-embedded.js", ); return { ...actual, queueEmbeddedPiMessage: vi.fn().mockReturnValue(false), runEmbeddedPiAgent: (params: unknown) => runEmbeddedPiAgentMock(params), }; }); vi.mock("./queue.js", async () => { const actual = await vi.importActual("./queue.js"); return { ...actual, enqueueFollowupRun: vi.fn(), scheduleFollowupDrain: vi.fn(), }; }); import { runReplyAgent } from "./agent-runner.js"; describe("runReplyAgent media path normalization", () => { beforeEach(() => { runEmbeddedPiAgentMock.mockReset(); runWithModelFallbackMock.mockReset(); runWithModelFallbackMock.mockImplementation( async ({ provider, model, run, }: { provider: string; model: string; run: (...args: unknown[]) => Promise; }) => ({ result: await run(provider, model), provider, model, }), ); }); it("normalizes final MEDIA replies against the run workspace", async () => { runEmbeddedPiAgentMock.mockResolvedValue({ payloads: [{ text: "MEDIA:./out/generated.png" }], meta: { agentMeta: { sessionId: "session", provider: "anthropic", model: "claude", }, }, }); const result = await runReplyAgent({ commandBody: "generate", followupRun: createMockFollowupRun({ prompt: "generate", run: { agentId: "main", agentDir: "/tmp/agent", messageProvider: "telegram", workspaceDir: "/tmp/workspace", }, }) as unknown as FollowupRun, queueKey: "main", resolvedQueue: { mode: "interrupt" } as QueueSettings, shouldSteer: false, shouldFollowup: false, isActive: false, isStreaming: false, typing: createMockTypingController(), sessionCtx: { Provider: "telegram", Surface: "telegram", To: "chat-1", OriginatingTo: "chat-1", AccountId: "default", MessageSid: "msg-1", } as unknown as TemplateContext, defaultModel: "anthropic/claude", resolvedVerboseLevel: "off", isNewSession: false, blockStreamingEnabled: false, resolvedBlockStreamingBreak: "message_end", shouldInjectGroupIntro: false, typingMode: "instant", }); expect(result).toMatchObject({ mediaUrl: path.join("/tmp/workspace", "out", "generated.png"), mediaUrls: [path.join("/tmp/workspace", "out", "generated.png")], }); }); });