Tests: move cron message-tool skip to seam

This commit is contained in:
Peter Steinberger
2026-04-07 09:41:51 +08:00
parent 3da203556c
commit 2499accca0
3 changed files with 72 additions and 36 deletions

View File

@@ -24,17 +24,6 @@ vi.mock("../agents/auth-profiles/session-override.js", () => ({
}));
const TELEGRAM_TARGET = { mode: "announce", channel: "telegram", to: "123" } as const;
async function runExplicitTelegramAnnounceTurn(params: {
home: string;
storePath: string;
deps: CliDeps;
deliveryContract?: "cron-owned" | "shared";
}): Promise<Awaited<ReturnType<typeof runCronIsolatedAgentTurn>>> {
return runTelegramAnnounceTurn({
...params,
delivery: TELEGRAM_TARGET,
});
}
async function withTelegramAnnounceFixture(
run: (params: { home: string; storePath: string; deps: CliDeps }) => Promise<void>,
@@ -53,11 +42,6 @@ async function withTelegramAnnounceFixture(
});
}
function expectDeliveredOk(result: Awaited<ReturnType<typeof runCronIsolatedAgentTurn>>): void {
expect(result.status).toBe("ok");
expect(result.delivered).toBe(true);
}
async function expectBestEffortTelegramNotDelivered(
payload: Record<string, unknown>,
): Promise<void> {
@@ -248,26 +232,6 @@ describe("runCronIsolatedAgentTurn", () => {
setupIsolatedAgentTurnMocks({ fast: true });
});
it("skips announce when messaging tool already sent to target", async () => {
await withTelegramAnnounceFixture(async ({ home, storePath, deps }) => {
mockAgentPayloads([{ text: "sent" }], {
didSendViaMessagingTool: true,
messagingToolSentTargets: [{ tool: "message", provider: "telegram", to: "123" }],
});
const res = await runExplicitTelegramAnnounceTurn({
home,
storePath,
deps,
deliveryContract: "shared",
});
expectDeliveredOk(res);
expect(runSubagentAnnounceFlow).not.toHaveBeenCalled();
expect(deps.sendMessageTelegram).not.toHaveBeenCalled();
});
});
it("reports not-delivered when best-effort structured outbound sends all fail", async () => {
await expectBestEffortTelegramNotDelivered({
text: "caption",

View File

@@ -1,6 +1,7 @@
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
clearFastTestEnv,
dispatchCronDeliveryMock,
loadRunCronIsolatedAgentTurn,
mockRunCronFallbackPassthrough,
resetRunCronIsolatedAgentTurnHarness,
@@ -92,4 +93,43 @@ describe("runCronIsolatedAgentTurn message tool policy", () => {
expect(runEmbeddedPiAgentMock).toHaveBeenCalledTimes(1);
expect(runEmbeddedPiAgentMock.mock.calls[0]?.[0]?.disableMessageTool).toBe(false);
});
it("skips cron delivery when a shared caller already sent to the same target", async () => {
mockRunCronFallbackPassthrough();
const params = makeParams();
const job = {
id: "message-tool-policy",
name: "Message Tool Policy",
schedule: { kind: "every", everyMs: 60_000 },
sessionTarget: "isolated",
payload: { kind: "agentTurn", message: "send a message" },
delivery: { mode: "announce", channel: "telegram", to: "123" },
} as const;
resolveCronDeliveryPlanMock.mockReturnValue({
requested: true,
mode: "announce",
channel: "telegram",
to: "123",
});
runEmbeddedPiAgentMock.mockResolvedValue({
payloads: [{ text: "sent" }],
didSendViaMessagingTool: true,
messagingToolSentTargets: [{ tool: "message", provider: "telegram", to: "123" }],
meta: { agentMeta: { usage: { input: 10, output: 20 } } },
});
await runCronIsolatedAgentTurn({
...params,
deliveryContract: "shared",
job: job as never,
});
expect(dispatchCronDeliveryMock).toHaveBeenCalledTimes(1);
expect(dispatchCronDeliveryMock.mock.calls[0]?.[0]).toEqual(
expect.objectContaining({
deliveryRequested: true,
skipMessagingToolDelivery: true,
}),
);
});
});

View File

@@ -63,6 +63,7 @@ export const pickLastNonEmptyTextFromPayloadsMock = createMock();
export const resolveCronPayloadOutcomeMock = createMock();
export const resolveCronDeliveryPlanMock = createMock();
export const resolveDeliveryTargetMock = createMock();
export const dispatchCronDeliveryMock = createMock();
export const resolveSessionAuthProfileOverrideMock = createMock();
export const resolveFastModeStateMock = createMock();
@@ -165,6 +166,15 @@ vi.mock("./delivery-target.js", () => ({
resolveDeliveryTarget: resolveDeliveryTargetMock,
}));
vi.mock("./delivery-dispatch.js", async () => {
const actual =
await vi.importActual<typeof import("./delivery-dispatch.js")>("./delivery-dispatch.js");
return {
...actual,
dispatchCronDelivery: dispatchCronDeliveryMock,
};
});
vi.mock("./helpers.js", () => ({
isHeartbeatOnlyResponse: vi.fn().mockReturnValue(false),
pickLastDeliverablePayload: vi.fn().mockReturnValue(undefined),
@@ -328,6 +338,28 @@ function resetRunOutcomeMocks(): void {
accountId: undefined,
error: undefined,
});
dispatchCronDeliveryMock.mockReset();
dispatchCronDeliveryMock.mockImplementation(
({
deliveryPayloads,
summary,
outputText,
synthesizedText,
deliveryRequested,
skipHeartbeatDelivery,
skipMessagingToolDelivery,
}) => ({
result: undefined,
delivered: Boolean(deliveryRequested && !skipHeartbeatDelivery && !skipMessagingToolDelivery),
deliveryAttempted: Boolean(
deliveryRequested && !skipHeartbeatDelivery && !skipMessagingToolDelivery,
),
summary,
outputText,
synthesizedText,
deliveryPayloads,
}),
);
resolveSessionAuthProfileOverrideMock.mockReset();
resolveSessionAuthProfileOverrideMock.mockResolvedValue(undefined);
}