fix(cron): track implicit message sends

This commit is contained in:
Ayaan Zaidi
2026-04-21 11:05:41 +05:30
parent 9e160d5c0f
commit 4f0a978fc2
2 changed files with 77 additions and 1 deletions

View File

@@ -405,6 +405,53 @@ describe("runCronIsolatedAgentTurn message tool policy", () => {
);
});
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: "telegram", to: "123" },
} as const;
resolveCronDeliveryPlanMock.mockReturnValue({
requested: true,
mode: "announce",
channel: "telegram",
to: "123",
});
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: "telegram", to: "123", source: "explicit" },
resolved: { ok: true, channel: "telegram", to: "123", source: "explicit" },
messageToolSentTo: [{ channel: "telegram", to: "123" }],
fallbackUsed: false,
delivered: true,
}),
);
});
it("does not mark message tool delivery as matched when cron target resolution failed", async () => {
mockRunCronFallbackPassthrough();
resolveCronDeliveryPlanMock.mockReturnValue({

View File

@@ -206,6 +206,32 @@ function buildCronDeliveryTrace(params: {
};
}
function resolveMessagingToolSentTargets(params: {
resolvedDelivery: ResolvedCronDeliveryTarget;
runResult: CronExecutionResult["runResult"];
}): MessagingToolSend[] {
const explicitTargets = params.runResult.messagingToolSentTargets ?? [];
if (explicitTargets.length > 0 || params.runResult.didSendViaMessagingTool !== true) {
return explicitTargets;
}
if (!params.resolvedDelivery.ok) {
return [];
}
return [
{
tool: "message",
provider: params.resolvedDelivery.channel,
...(params.resolvedDelivery.accountId
? { accountId: params.resolvedDelivery.accountId }
: {}),
...(params.resolvedDelivery.to ? { to: params.resolvedDelivery.to } : {}),
...(params.resolvedDelivery.threadId
? { threadId: String(params.resolvedDelivery.threadId) }
: {}),
},
];
}
function resolveCronToolPolicy(params: { deliveryMode: "announce" | "webhook" | "none" }) {
const enableMessageTool = params.deliveryMode !== "webhook";
return {
@@ -756,7 +782,10 @@ async function finalizeCronRun(params: {
matchesMessagingToolDeliveryTarget,
resolveCronDeliveryBestEffort,
} = await loadCronDeliveryRuntime();
const messagingToolSentTargets = finalRunResult.messagingToolSentTargets ?? [];
const messagingToolSentTargets = resolveMessagingToolSentTargets({
resolvedDelivery: prepared.resolvedDelivery,
runResult: finalRunResult,
});
const didSendViaMessagingTool =
finalRunResult.didSendViaMessagingTool === true && messagingToolSentTargets.length > 0;
const skipMessagingToolDelivery =