Step 5 + Review

This commit is contained in:
Tyler Yust
2026-01-19 20:16:14 -08:00
committed by Peter Steinberger
parent 2cf444be02
commit 1eab8fa9b0
10 changed files with 219 additions and 15 deletions

View File

@@ -28,7 +28,7 @@ import {
shouldApplyCrossContextMarker,
} from "./outbound-policy.js";
import { executePollAction, executeSendAction } from "./outbound-send-service.js";
import { actionRequiresTarget } from "./message-action-spec.js";
import { actionHasTarget, actionRequiresTarget } from "./message-action-spec.js";
import { resolveChannelTarget } from "./target-resolver.js";
export type MessageActionRunnerGateway = {
@@ -536,10 +536,7 @@ export async function runMessageAction(
applyTargetToParams({ action, args: params });
if (actionRequiresTarget(action)) {
const hasTarget =
(typeof params.to === "string" && params.to.trim()) ||
(typeof params.channelId === "string" && params.channelId.trim());
if (!hasTarget) {
if (!actionHasTarget(action, params)) {
throw new Error(`Action ${action} requires a target.`);
}
}

View File

@@ -11,6 +11,14 @@ export const MESSAGE_ACTION_TARGET_MODE: Record<ChannelMessageActionName, Messag
reactions: "to",
read: "to",
edit: "to",
unsend: "to",
reply: "to",
sendWithEffect: "to",
renameGroup: "to",
addParticipant: "to",
removeParticipant: "to",
leaveGroup: "to",
sendAttachment: "to",
delete: "to",
pin: "to",
unpin: "to",
@@ -45,6 +53,32 @@ export const MESSAGE_ACTION_TARGET_MODE: Record<ChannelMessageActionName, Messag
ban: "none",
};
const ACTION_TARGET_ALIASES: Partial<Record<ChannelMessageActionName, string[]>> = {
unsend: ["messageId"],
renameGroup: ["chatGuid", "chatIdentifier", "chatId"],
addParticipant: ["chatGuid", "chatIdentifier", "chatId"],
removeParticipant: ["chatGuid", "chatIdentifier", "chatId"],
leaveGroup: ["chatGuid", "chatIdentifier", "chatId"],
};
export function actionRequiresTarget(action: ChannelMessageActionName): boolean {
return MESSAGE_ACTION_TARGET_MODE[action] !== "none";
}
export function actionHasTarget(
action: ChannelMessageActionName,
params: Record<string, unknown>,
): boolean {
const to = typeof params.to === "string" ? params.to.trim() : "";
if (to) return true;
const channelId = typeof params.channelId === "string" ? params.channelId.trim() : "";
if (channelId) return true;
const aliases = ACTION_TARGET_ALIASES[action];
if (!aliases) return false;
return aliases.some((alias) => {
const value = params[alias];
if (typeof value === "string") return value.trim().length > 0;
if (typeof value === "number") return Number.isFinite(value);
return false;
});
}

View File

@@ -17,6 +17,9 @@ export type CrossContextDecoration = {
const CONTEXT_GUARDED_ACTIONS = new Set<ChannelMessageActionName>([
"send",
"poll",
"reply",
"sendWithEffect",
"sendAttachment",
"thread-create",
"thread-reply",
"sticker",
@@ -25,6 +28,9 @@ const CONTEXT_GUARDED_ACTIONS = new Set<ChannelMessageActionName>([
const CONTEXT_MARKER_ACTIONS = new Set<ChannelMessageActionName>([
"send",
"poll",
"reply",
"sendWithEffect",
"sendAttachment",
"thread-reply",
"sticker",
]);