fix(cron): require explicit poll delivery targets

This commit is contained in:
Vincent Koc
2026-06-16 03:09:31 +08:00
parent eb67ac5cbe
commit b3128ba93d
2 changed files with 34 additions and 12 deletions
+29
View File
@@ -1258,6 +1258,35 @@ describe("message tool explicit target guard", () => {
expect(mocks.runMessageAction).not.toHaveBeenCalled();
});
it.each([
{
action: "poll",
params: {
action: "poll",
pollQuestion: "Lunch?",
pollOption: ["Pizza", "Sushi"],
},
},
{
action: "sticker",
params: {
action: "sticker",
stickerId: "sticker-1",
},
},
] as const)("requires an explicit target for $action when configured", async ({ params }) => {
const tool = createMessageTool({
runMessageAction: mocks.runMessageAction as never,
requireExplicitTarget: true,
currentChannelProvider: "slack",
currentChannelId: "channel:C123",
});
await expect(tool.execute("1", params)).rejects.toThrow(/Explicit message target required/i);
expect(mocks.runMessageAction).not.toHaveBeenCalled();
});
it("allows upload-file when an explicit target is provided", async () => {
mocks.runMessageAction.mockResolvedValueOnce({
kind: "action",
+5 -12
View File
@@ -50,7 +50,10 @@ import {
runMessageAction,
type MessageActionRunResult,
} from "../../infra/outbound/message-action-runner.js";
import { resolveAllowedMessageActions } from "../../infra/outbound/outbound-policy.js";
import {
resolveAllowedMessageActions,
shouldApplyCrossContextMarker,
} from "../../infra/outbound/outbound-policy.js";
import { hasReplyPayloadContent } from "../../interactive/payload.js";
import { stringifyRouteThreadId } from "../../plugin-sdk/channel-route.js";
import { POLL_CREATION_PARAM_DEFS, SHARED_POLL_CREATION_PARAM_NAMES } from "../../poll-params.js";
@@ -83,18 +86,8 @@ import {
const AllMessageActions = CHANNEL_MESSAGE_ACTION_NAMES;
const MESSAGE_TOOL_THREAD_READ_HINT =
' Use action="read" with threadId to fetch prior messages in a thread when you need conversation context you do not have yet.';
const EXPLICIT_TARGET_ACTIONS = new Set<ChannelMessageActionName>([
"send",
"sendWithEffect",
"sendAttachment",
"upload-file",
"reply",
"thread-reply",
"broadcast",
]);
function actionNeedsExplicitTarget(action: ChannelMessageActionName): boolean {
return EXPLICIT_TARGET_ACTIONS.has(action);
return action === "broadcast" || shouldApplyCrossContextMarker(action);
}
function normalizeMessageToolIdempotencyKeyPart(value: unknown): string | undefined {