From 16306074634150c4999edebeaf6816816fbe75ef Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Thu, 23 Apr 2026 18:18:24 +0100 Subject: [PATCH] test: dedupe cron and channel fixtures --- src/channels/plugins/read-only.test.ts | 36 +- .../run.message-tool-policy.test.ts | 340 +++++++----------- 2 files changed, 145 insertions(+), 231 deletions(-) diff --git a/src/channels/plugins/read-only.test.ts b/src/channels/plugins/read-only.test.ts index bcc7a7384d7..9a75c7aaa98 100644 --- a/src/channels/plugins/read-only.test.ts +++ b/src/channels/plugins/read-only.test.ts @@ -266,6 +266,22 @@ module.exports = { return { bundledRoot, pluginDir, fullMarker, setupMarker, pluginId, channelId, envVar }; } +function expectExternalChatSetupOnlyPluginLoaded(params: { + plugins: ReturnType; + setupMarker: string; + fullMarker: string; +}) { + const plugin = params.plugins.find((entry) => entry.id === "external-chat"); + expect(plugin?.meta.blurb).toBe("setup entry"); + expect( + plugin?.secrets?.secretTargetRegistryEntries?.some( + (entry) => entry.id === "channels.external-chat.token", + ), + ).toBe(true); + expect(fs.existsSync(params.setupMarker)).toBe(true); + expect(fs.existsSync(params.fullMarker)).toBe(false); +} + afterEach(() => { resetPluginLoaderTestStateForTest(); }); @@ -293,15 +309,7 @@ describe("listReadOnlyChannelPluginsForConfig", () => { }, ); - const plugin = plugins.find((entry) => entry.id === "external-chat"); - expect(plugin?.meta.blurb).toBe("setup entry"); - expect( - plugin?.secrets?.secretTargetRegistryEntries?.some( - (entry) => entry.id === "channels.external-chat.token", - ), - ).toBe(true); - expect(fs.existsSync(setupMarker)).toBe(true); - expect(fs.existsSync(fullMarker)).toBe(false); + expectExternalChatSetupOnlyPluginLoaded({ plugins, setupMarker, fullMarker }); }); it("matches setup-only plugins by manifest-owned channel ids when plugin id differs", () => { @@ -466,15 +474,7 @@ describe("listReadOnlyChannelPluginsForConfig", () => { }, ); - const plugin = plugins.find((entry) => entry.id === "external-chat"); - expect(plugin?.meta.blurb).toBe("setup entry"); - expect( - plugin?.secrets?.secretTargetRegistryEntries?.some( - (entry) => entry.id === "channels.external-chat.token", - ), - ).toBe(true); - expect(fs.existsSync(setupMarker)).toBe(true); - expect(fs.existsSync(fullMarker)).toBe(false); + expectExternalChatSetupOnlyPluginLoaded({ plugins, setupMarker, fullMarker }); }); it("does not promote disabled external channels from manifest env", () => { diff --git a/src/cron/isolated-agent/run.message-tool-policy.test.ts b/src/cron/isolated-agent/run.message-tool-policy.test.ts index 0eeee20586c..85c9304d8ff 100644 --- a/src/cron/isolated-agent/run.message-tool-policy.test.ts +++ b/src/cron/isolated-agent/run.message-tool-policy.test.ts @@ -34,6 +34,23 @@ function makeMessageToolPolicyJob( } as never; } +function makeAnnounceMessageToolJob( + options: { + id?: string; + name?: string; + delivery?: Record; + } = {}, +) { + return { + id: options.id ?? "message-tool-policy", + name: options.name ?? "Message Tool Policy", + schedule: { kind: "every", everyMs: 60_000 }, + sessionTarget: "isolated", + payload: { kind: "agentTurn", message: "send a message" }, + delivery: { mode: "announce", channel: "messagechat", to: "123", ...options.delivery }, + } as never; +} + function makeParams() { return { cfg: {}, @@ -44,6 +61,37 @@ function makeParams() { }; } +function makeAnnounceDeliveryPlan(overrides: Record = {}) { + return { + requested: true, + mode: "announce", + channel: "messagechat", + to: "123", + ...overrides, + }; +} + +function makeResolvedAnnounceTarget(overrides: Record = {}) { + return { + ok: true, + channel: "messagechat", + to: "123", + accountId: undefined, + threadId: undefined, + mode: "explicit", + ...overrides, + }; +} + +function makeMessageToolRunResult(messagingToolSentTargets: Array>) { + return { + payloads: [{ text: "sent" }], + didSendViaMessagingTool: true, + messagingToolSentTargets, + meta: { agentMeta: { usage: { input: 10, output: 20 } } }, + }; +} + describe("runCronIsolatedAgentTurn message tool policy", () => { let previousFastTestEnv: string | undefined; @@ -103,6 +151,37 @@ describe("runCronIsolatedAgentTurn message tool policy", () => { }); } + async function expectCronFallbackSkippedForMessageToolDelivery(options: { + sentTargets: Array>; + job?: Parameters[0]; + }) { + mockRunCronFallbackPassthrough(); + resolveCronDeliveryPlanMock.mockReturnValue(makeAnnounceDeliveryPlan()); + runEmbeddedPiAgentMock.mockResolvedValue(makeMessageToolRunResult(options.sentTargets)); + + const result = await runCronIsolatedAgentTurn({ + ...makeParams(), + job: makeAnnounceMessageToolJob(options.job), + }); + + expect(dispatchCronDeliveryMock).toHaveBeenCalledTimes(1); + expect(dispatchCronDeliveryMock.mock.calls[0]?.[0]).toEqual( + expect.objectContaining({ + deliveryRequested: true, + skipMessagingToolDelivery: true, + }), + ); + expect(result.delivery).toEqual( + expect.objectContaining({ + intended: { channel: "messagechat", to: "123", source: "explicit" }, + resolved: { ok: true, channel: "messagechat", to: "123", source: "explicit" }, + messageToolSentTo: [{ channel: "messagechat", to: "123" }], + fallbackUsed: false, + delivered: true, + }), + ); + } + beforeEach(() => { previousFastTestEnv = clearFastTestEnv(); resetRunCronIsolatedAgentTurnHarness(); @@ -358,24 +437,12 @@ describe("runCronIsolatedAgentTurn message tool policy", () => { it("skips cron delivery when output is heartbeat-only", async () => { mockRunCronFallbackPassthrough(); - resolveCronDeliveryPlanMock.mockReturnValue({ - requested: true, - mode: "announce", - channel: "messagechat", - to: "123", - }); + resolveCronDeliveryPlanMock.mockReturnValue(makeAnnounceDeliveryPlan()); isHeartbeatOnlyResponseMock.mockReturnValue(true); await runCronIsolatedAgentTurn({ ...makeParams(), - 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: "messagechat", to: "123" }, - } as never, + job: makeAnnounceMessageToolJob(), }); expect(dispatchCronDeliveryMock).toHaveBeenCalledTimes(1); @@ -388,124 +455,34 @@ describe("runCronIsolatedAgentTurn message tool policy", () => { }); it("skips cron fallback delivery when the message tool 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: "messagechat", to: "123" }, - } as const; - resolveCronDeliveryPlanMock.mockReturnValue({ - requested: true, - mode: "announce", - channel: "messagechat", - to: "123", + await expectCronFallbackSkippedForMessageToolDelivery({ + sentTargets: [{ tool: "message", provider: "messagechat", to: "123" }], }); - runEmbeddedPiAgentMock.mockResolvedValue({ - payloads: [{ text: "sent" }], - didSendViaMessagingTool: true, - messagingToolSentTargets: [{ tool: "message", provider: "messagechat", to: "123" }], - meta: { agentMeta: { usage: { input: 10, output: 20 } } }, - }); - - const result = await runCronIsolatedAgentTurn({ - ...params, - job: job as never, - }); - - expect(dispatchCronDeliveryMock).toHaveBeenCalledTimes(1); - expect(dispatchCronDeliveryMock.mock.calls[0]?.[0]).toEqual( - expect.objectContaining({ - deliveryRequested: true, - skipMessagingToolDelivery: true, - }), - ); - expect(result.delivery).toEqual( - expect.objectContaining({ - intended: { channel: "messagechat", to: "123", source: "explicit" }, - resolved: { ok: true, channel: "messagechat", to: "123", source: "explicit" }, - messageToolSentTo: [{ channel: "messagechat", to: "123" }], - fallbackUsed: false, - delivered: true, - }), - ); }); it("skips cron fallback delivery when the message tool sends to the bound target", async () => { - mockRunCronFallbackPassthrough(); - const params = makeParams(); - const job = { - id: "message-tool-bound-target", - name: "Message Tool Bound Target", - schedule: { kind: "every", everyMs: 60_000 }, - sessionTarget: "isolated", - payload: { kind: "agentTurn", message: "send a message" }, - delivery: { mode: "announce", channel: "messagechat", to: "123" }, - } as const; - resolveCronDeliveryPlanMock.mockReturnValue({ - requested: true, - mode: "announce", - channel: "messagechat", - to: "123", + await expectCronFallbackSkippedForMessageToolDelivery({ + sentTargets: [], + job: { + id: "message-tool-bound-target", + name: "Message Tool Bound Target", + }, }); - runEmbeddedPiAgentMock.mockResolvedValue({ - payloads: [{ text: "sent" }], - didSendViaMessagingTool: true, - messagingToolSentTargets: [], - meta: { agentMeta: { usage: { input: 10, output: 20 } } }, - }); - - const result = await runCronIsolatedAgentTurn({ - ...params, - job: job as never, - }); - - expect(dispatchCronDeliveryMock).toHaveBeenCalledTimes(1); - expect(dispatchCronDeliveryMock.mock.calls[0]?.[0]).toEqual( - expect.objectContaining({ - deliveryRequested: true, - skipMessagingToolDelivery: true, - }), - ); - expect(result.delivery).toEqual( - expect.objectContaining({ - intended: { channel: "messagechat", to: "123", source: "explicit" }, - resolved: { ok: true, channel: "messagechat", to: "123", source: "explicit" }, - messageToolSentTo: [{ channel: "messagechat", to: "123" }], - fallbackUsed: false, - delivered: true, - }), - ); }); it("rewrites generic message provider to resolved channel in delivery trace", async () => { mockRunCronFallbackPassthrough(); - resolveCronDeliveryPlanMock.mockReturnValue({ - requested: true, - mode: "announce", - channel: "messagechat", - to: "123", - }); - runEmbeddedPiAgentMock.mockResolvedValue({ - payloads: [{ text: "sent" }], - didSendViaMessagingTool: true, - messagingToolSentTargets: [{ tool: "message", provider: "message", to: "123" }], - meta: { agentMeta: { usage: { input: 10, output: 20 } } }, - }); + resolveCronDeliveryPlanMock.mockReturnValue(makeAnnounceDeliveryPlan()); + runEmbeddedPiAgentMock.mockResolvedValue( + makeMessageToolRunResult([{ tool: "message", provider: "message", to: "123" }]), + ); const result = await runCronIsolatedAgentTurn({ ...makeParams(), - job: { + job: makeAnnounceMessageToolJob({ id: "message-tool-generic-target", name: "Message Tool Generic Target", - schedule: { kind: "every", everyMs: 60_000 }, - sessionTarget: "isolated", - payload: { kind: "agentTurn", message: "send a message" }, - delivery: { mode: "announce", channel: "messagechat", to: "123" }, - } as never, + }), }); expect(result.delivery).toEqual( @@ -518,40 +495,21 @@ describe("runCronIsolatedAgentTurn message tool policy", () => { it("preserves accountId when rewriting generic message provider to resolved channel", async () => { mockRunCronFallbackPassthrough(); - resolveCronDeliveryPlanMock.mockReturnValue({ - requested: true, - mode: "announce", - channel: "messagechat", - to: "123", - accountId: "bot-a", - }); - resolveDeliveryTargetMock.mockResolvedValue({ - ok: true, - channel: "messagechat", - to: "123", - accountId: "bot-a", - threadId: undefined, - mode: "explicit", - }); - runEmbeddedPiAgentMock.mockResolvedValue({ - payloads: [{ text: "sent" }], - didSendViaMessagingTool: true, - messagingToolSentTargets: [ + resolveCronDeliveryPlanMock.mockReturnValue(makeAnnounceDeliveryPlan({ accountId: "bot-a" })); + resolveDeliveryTargetMock.mockResolvedValue(makeResolvedAnnounceTarget({ accountId: "bot-a" })); + runEmbeddedPiAgentMock.mockResolvedValue( + makeMessageToolRunResult([ { tool: "message", provider: "message", to: "123", accountId: "bot-a" }, - ], - meta: { agentMeta: { usage: { input: 10, output: 20 } } }, - }); + ]), + ); const result = await runCronIsolatedAgentTurn({ ...makeParams(), - job: { + job: makeAnnounceMessageToolJob({ id: "message-tool-generic-target-account", name: "Message Tool Generic Target (accountId)", - schedule: { kind: "every", everyMs: 60_000 }, - sessionTarget: "isolated", - payload: { kind: "agentTurn", message: "send a message" }, - delivery: { mode: "announce", channel: "messagechat", to: "123", accountId: "bot-a" }, - } as never, + delivery: { accountId: "bot-a" }, + }), }); expect(result.delivery).toEqual( @@ -563,38 +521,19 @@ describe("runCronIsolatedAgentTurn message tool policy", () => { it("rewrites generic message provider when tool send omits accountId (tool fills at exec)", async () => { mockRunCronFallbackPassthrough(); - resolveCronDeliveryPlanMock.mockReturnValue({ - requested: true, - mode: "announce", - channel: "messagechat", - to: "123", - accountId: "bot-a", - }); - resolveDeliveryTargetMock.mockResolvedValue({ - ok: true, - channel: "messagechat", - to: "123", - accountId: "bot-a", - threadId: undefined, - mode: "explicit", - }); - runEmbeddedPiAgentMock.mockResolvedValue({ - payloads: [{ text: "sent" }], - didSendViaMessagingTool: true, - messagingToolSentTargets: [{ tool: "message", provider: "message", to: "123" }], - meta: { agentMeta: { usage: { input: 10, output: 20 } } }, - }); + resolveCronDeliveryPlanMock.mockReturnValue(makeAnnounceDeliveryPlan({ accountId: "bot-a" })); + resolveDeliveryTargetMock.mockResolvedValue(makeResolvedAnnounceTarget({ accountId: "bot-a" })); + runEmbeddedPiAgentMock.mockResolvedValue( + makeMessageToolRunResult([{ tool: "message", provider: "message", to: "123" }]), + ); const result = await runCronIsolatedAgentTurn({ ...makeParams(), - job: { + job: makeAnnounceMessageToolJob({ id: "message-tool-generic-target-account-default", name: "Message Tool Generic Target (accountId default)", - schedule: { kind: "every", everyMs: 60_000 }, - sessionTarget: "isolated", - payload: { kind: "agentTurn", message: "send a message" }, - delivery: { mode: "announce", channel: "messagechat", to: "123", accountId: "bot-a" }, - } as never, + delivery: { accountId: "bot-a" }, + }), }); expect(result.delivery).toEqual( @@ -606,40 +545,21 @@ describe("runCronIsolatedAgentTurn message tool policy", () => { it("does not rewrite generic message provider when tool names a different accountId (spoof guard)", async () => { mockRunCronFallbackPassthrough(); - resolveCronDeliveryPlanMock.mockReturnValue({ - requested: true, - mode: "announce", - channel: "messagechat", - to: "123", - accountId: "bot-a", - }); - resolveDeliveryTargetMock.mockResolvedValue({ - ok: true, - channel: "messagechat", - to: "123", - accountId: "bot-a", - threadId: undefined, - mode: "explicit", - }); - runEmbeddedPiAgentMock.mockResolvedValue({ - payloads: [{ text: "sent" }], - didSendViaMessagingTool: true, - messagingToolSentTargets: [ + resolveCronDeliveryPlanMock.mockReturnValue(makeAnnounceDeliveryPlan({ accountId: "bot-a" })); + resolveDeliveryTargetMock.mockResolvedValue(makeResolvedAnnounceTarget({ accountId: "bot-a" })); + runEmbeddedPiAgentMock.mockResolvedValue( + makeMessageToolRunResult([ { tool: "message", provider: "message", to: "123", accountId: "bot-b" }, - ], - meta: { agentMeta: { usage: { input: 10, output: 20 } } }, - }); + ]), + ); const result = await runCronIsolatedAgentTurn({ ...makeParams(), - job: { + job: makeAnnounceMessageToolJob({ id: "message-tool-generic-target-account-spoof", name: "Message Tool Generic Target (account spoof guard)", - schedule: { kind: "every", everyMs: 60_000 }, - sessionTarget: "isolated", - payload: { kind: "agentTurn", message: "send a message" }, - delivery: { mode: "announce", channel: "messagechat", to: "123", accountId: "bot-a" }, - } as never, + delivery: { accountId: "bot-a" }, + }), }); expect(result.delivery).toEqual( @@ -665,12 +585,9 @@ describe("runCronIsolatedAgentTurn message tool policy", () => { mode: "implicit", error: new Error("sessionKey is required to resolve delivery.channel=last"), }); - runEmbeddedPiAgentMock.mockResolvedValue({ - payloads: [{ text: "sent" }], - didSendViaMessagingTool: true, - messagingToolSentTargets: [{ tool: "message", provider: "messagechat", to: "123" }], - meta: { agentMeta: { usage: { input: 10, output: 20 } } }, - }); + runEmbeddedPiAgentMock.mockResolvedValue( + makeMessageToolRunResult([{ tool: "message", provider: "messagechat", to: "123" }]), + ); const result = await runCronIsolatedAgentTurn(makeParams()); @@ -704,12 +621,9 @@ describe("runCronIsolatedAgentTurn message tool policy", () => { mode: "none", channel: "last", }); - runEmbeddedPiAgentMock.mockResolvedValue({ - payloads: [{ text: "sent" }], - didSendViaMessagingTool: true, - messagingToolSentTargets: [{ tool: "message", provider: "messagechat", to: "123" }], - meta: { agentMeta: { usage: { input: 10, output: 20 } } }, - }); + runEmbeddedPiAgentMock.mockResolvedValue( + makeMessageToolRunResult([{ tool: "message", provider: "messagechat", to: "123" }]), + ); const result = await runCronIsolatedAgentTurn(makeParams());