Files
openclaw/src/auto-reply/reply/agent-runner.media-paths.test.ts
kiranvk2011 84401223c7 fix: per-model cooldown scope, stepped backoff, and user-facing rate-limit message (#49834)
Merged via squash.

Prepared head SHA: 7c488c070c
Co-authored-by: kiranvk-2011 <91108465+kiranvk-2011@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
2026-03-25 22:03:49 +03:00

145 lines
4.8 KiB
TypeScript

import path from "node:path";
import { afterEach, 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();
const abortEmbeddedPiRunMock = vi.fn();
const compactEmbeddedPiSessionMock = vi.fn();
const isEmbeddedPiRunActiveMock = vi.fn(() => false);
const isEmbeddedPiRunStreamingMock = vi.fn(() => false);
const queueEmbeddedPiMessageMock = vi.fn(() => false);
const resolveEmbeddedSessionLaneMock = vi.fn();
const waitForEmbeddedPiRunEndMock = vi.fn();
const enqueueFollowupRunMock = vi.fn();
const scheduleFollowupDrainMock = vi.fn();
const refreshQueuedFollowupSessionMock = vi.fn();
vi.mock("../../agents/model-fallback.js", () => ({
runWithModelFallback: (params: {
provider: string;
model: string;
run: (provider: string, model: string) => Promise<unknown>;
}) => runWithModelFallbackMock(params),
isFallbackSummaryError: (err: unknown) =>
err instanceof Error &&
err.name === "FallbackSummaryError" &&
Array.isArray((err as { attempts?: unknown[] }).attempts),
}));
vi.mock("../../agents/pi-embedded.js", () => ({
abortEmbeddedPiRun: abortEmbeddedPiRunMock,
compactEmbeddedPiSession: compactEmbeddedPiSessionMock,
isEmbeddedPiRunActive: isEmbeddedPiRunActiveMock,
isEmbeddedPiRunStreaming: isEmbeddedPiRunStreamingMock,
queueEmbeddedPiMessage: queueEmbeddedPiMessageMock,
resolveEmbeddedSessionLane: resolveEmbeddedSessionLaneMock,
runEmbeddedPiAgent: runEmbeddedPiAgentMock,
waitForEmbeddedPiRunEnd: waitForEmbeddedPiRunEndMock,
}));
vi.mock("./queue.js", () => ({
enqueueFollowupRun: enqueueFollowupRunMock,
refreshQueuedFollowupSession: refreshQueuedFollowupSessionMock,
scheduleFollowupDrain: scheduleFollowupDrainMock,
}));
let runReplyAgent: typeof import("./agent-runner.js").runReplyAgent;
describe("runReplyAgent media path normalization", () => {
beforeEach(async () => {
vi.resetModules();
runEmbeddedPiAgentMock.mockReset();
runWithModelFallbackMock.mockReset();
abortEmbeddedPiRunMock.mockReset();
compactEmbeddedPiSessionMock.mockReset();
isEmbeddedPiRunActiveMock.mockReset();
isEmbeddedPiRunActiveMock.mockReturnValue(false);
isEmbeddedPiRunStreamingMock.mockReset();
isEmbeddedPiRunStreamingMock.mockReturnValue(false);
queueEmbeddedPiMessageMock.mockReset();
queueEmbeddedPiMessageMock.mockReturnValue(false);
resolveEmbeddedSessionLaneMock.mockReset();
waitForEmbeddedPiRunEndMock.mockReset();
enqueueFollowupRunMock.mockReset();
scheduleFollowupDrainMock.mockReset();
refreshQueuedFollowupSessionMock.mockReset();
vi.stubEnv("OPENCLAW_TEST_FAST", "1");
runWithModelFallbackMock.mockImplementation(
async ({
provider,
model,
run,
}: {
provider: string;
model: string;
run: (...args: unknown[]) => Promise<unknown>;
}) => ({
result: await run(provider, model),
provider,
model,
}),
);
({ runReplyAgent } = await import("./agent-runner.js"));
});
afterEach(() => {
vi.useRealTimers();
});
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")],
});
});
});