Files
openclaw/src/slack/monitor/message-handler/prepare-content.ts
2026-03-02 22:30:21 +00:00

107 lines
3.1 KiB
TypeScript

import { logVerbose } from "../../../globals.js";
import type { SlackFile, SlackMessageEvent } from "../../types.js";
import {
MAX_SLACK_MEDIA_FILES,
resolveSlackAttachmentContent,
resolveSlackMedia,
type SlackMediaResult,
type SlackThreadStarter,
} from "../media.js";
export type SlackResolvedMessageContent = {
rawBody: string;
effectiveDirectMedia: SlackMediaResult[] | null;
};
function filterInheritedParentFiles(params: {
files: SlackFile[] | undefined;
isThreadReply: boolean;
threadStarter: SlackThreadStarter | null;
}): SlackFile[] | undefined {
const { files, isThreadReply, threadStarter } = params;
if (!isThreadReply || !files?.length) {
return files;
}
if (!threadStarter?.files?.length) {
return files;
}
const starterFileIds = new Set(threadStarter.files.map((file) => file.id));
const filtered = files.filter((file) => !file.id || !starterFileIds.has(file.id));
if (filtered.length < files.length) {
logVerbose(
`slack: filtered ${files.length - filtered.length} inherited parent file(s) from thread reply`,
);
}
return filtered.length > 0 ? filtered : undefined;
}
export async function resolveSlackMessageContent(params: {
message: SlackMessageEvent;
isThreadReply: boolean;
threadStarter: SlackThreadStarter | null;
isBotMessage: boolean;
botToken: string;
mediaMaxBytes: number;
}): Promise<SlackResolvedMessageContent | null> {
const ownFiles = filterInheritedParentFiles({
files: params.message.files,
isThreadReply: params.isThreadReply,
threadStarter: params.threadStarter,
});
const media = await resolveSlackMedia({
files: ownFiles,
token: params.botToken,
maxBytes: params.mediaMaxBytes,
});
const attachmentContent = await resolveSlackAttachmentContent({
attachments: params.message.attachments,
token: params.botToken,
maxBytes: params.mediaMaxBytes,
});
const mergedMedia = [...(media ?? []), ...(attachmentContent?.media ?? [])];
const effectiveDirectMedia = mergedMedia.length > 0 ? mergedMedia : null;
const mediaPlaceholder = effectiveDirectMedia
? effectiveDirectMedia.map((item) => item.placeholder).join(" ")
: undefined;
const fallbackFiles = ownFiles ?? [];
const fileOnlyFallback =
!mediaPlaceholder && fallbackFiles.length > 0
? fallbackFiles
.slice(0, MAX_SLACK_MEDIA_FILES)
.map((file) => file.name?.trim() || "file")
.join(", ")
: undefined;
const fileOnlyPlaceholder = fileOnlyFallback ? `[Slack file: ${fileOnlyFallback}]` : undefined;
const botAttachmentText =
params.isBotMessage && !attachmentContent?.text
? (params.message.attachments ?? [])
.map((attachment) => attachment.text?.trim() || attachment.fallback?.trim())
.filter(Boolean)
.join("\n")
: undefined;
const rawBody =
[
(params.message.text ?? "").trim(),
attachmentContent?.text,
botAttachmentText,
mediaPlaceholder,
fileOnlyPlaceholder,
]
.filter(Boolean)
.join("\n") || "";
if (!rawBody) {
return null;
}
return {
rawBody,
effectiveDirectMedia,
};
}