Skip to content

Commit b3128ba

Browse files
committed
fix(cron): require explicit poll delivery targets
1 parent eb67ac5 commit b3128ba

2 files changed

Lines changed: 34 additions & 12 deletions

File tree

src/agents/tools/message-tool.test.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,35 @@ describe("message tool explicit target guard", () => {
12581258
expect(mocks.runMessageAction).not.toHaveBeenCalled();
12591259
});
12601260

1261+
it.each([
1262+
{
1263+
action: "poll",
1264+
params: {
1265+
action: "poll",
1266+
pollQuestion: "Lunch?",
1267+
pollOption: ["Pizza", "Sushi"],
1268+
},
1269+
},
1270+
{
1271+
action: "sticker",
1272+
params: {
1273+
action: "sticker",
1274+
stickerId: "sticker-1",
1275+
},
1276+
},
1277+
] as const)("requires an explicit target for $action when configured", async ({ params }) => {
1278+
const tool = createMessageTool({
1279+
runMessageAction: mocks.runMessageAction as never,
1280+
requireExplicitTarget: true,
1281+
currentChannelProvider: "slack",
1282+
currentChannelId: "channel:C123",
1283+
});
1284+
1285+
await expect(tool.execute("1", params)).rejects.toThrow(/Explicit message target required/i);
1286+
1287+
expect(mocks.runMessageAction).not.toHaveBeenCalled();
1288+
});
1289+
12611290
it("allows upload-file when an explicit target is provided", async () => {
12621291
mocks.runMessageAction.mockResolvedValueOnce({
12631292
kind: "action",

src/agents/tools/message-tool.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ import {
5050
runMessageAction,
5151
type MessageActionRunResult,
5252
} from "../../infra/outbound/message-action-runner.js";
53-
import { resolveAllowedMessageActions } from "../../infra/outbound/outbound-policy.js";
53+
import {
54+
resolveAllowedMessageActions,
55+
shouldApplyCrossContextMarker,
56+
} from "../../infra/outbound/outbound-policy.js";
5457
import { hasReplyPayloadContent } from "../../interactive/payload.js";
5558
import { stringifyRouteThreadId } from "../../plugin-sdk/channel-route.js";
5659
import { POLL_CREATION_PARAM_DEFS, SHARED_POLL_CREATION_PARAM_NAMES } from "../../poll-params.js";
@@ -83,18 +86,8 @@ import {
8386
const AllMessageActions = CHANNEL_MESSAGE_ACTION_NAMES;
8487
const MESSAGE_TOOL_THREAD_READ_HINT =
8588
' Use action="read" with threadId to fetch prior messages in a thread when you need conversation context you do not have yet.';
86-
const EXPLICIT_TARGET_ACTIONS = new Set<ChannelMessageActionName>([
87-
"send",
88-
"sendWithEffect",
89-
"sendAttachment",
90-
"upload-file",
91-
"reply",
92-
"thread-reply",
93-
"broadcast",
94-
]);
95-
9689
function actionNeedsExplicitTarget(action: ChannelMessageActionName): boolean {
97-
return EXPLICIT_TARGET_ACTIONS.has(action);
90+
return action === "broadcast" || shouldApplyCrossContextMarker(action);
9891
}
9992

10093
function normalizeMessageToolIdempotencyKeyPart(value: unknown): string | undefined {

0 commit comments

Comments
 (0)