refactor: split slack/discord/session maintenance helpers

This commit is contained in:
Peter Steinberger
2026-03-02 23:07:12 +00:00
parent 3043e68dfa
commit 7eda632324
16 changed files with 983 additions and 749 deletions

View File

@@ -56,6 +56,7 @@ import {
resolveDiscordMessageChannelId,
resolveDiscordMessageText,
} from "./message-utils.js";
import { resolveDiscordPreflightAudioMentionContext } from "./preflight-audio.js";
import { resolveDiscordSenderIdentity, resolveDiscordWebhookId } from "./sender-identity.js";
import { resolveDiscordSystemEvent } from "./system-events.js";
import { isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.js";
@@ -498,50 +499,16 @@ export async function preflightDiscordMessage(
isBoundThreadSession,
});
// Preflight audio transcription for mention detection in guilds
// This allows voice notes to be checked for mentions before being dropped
let preflightTranscript: string | undefined;
const hasAudioAttachment = message.attachments?.some((att: { content_type?: string }) =>
att.content_type?.startsWith("audio/"),
);
const hasTypedText = Boolean(message.content?.trim());
const needsPreflightTranscription =
!isDirectMessage &&
shouldRequireMention &&
hasAudioAttachment &&
// `baseText` includes media placeholders; gate on typed text only.
!hasTypedText &&
mentionRegexes.length > 0;
if (needsPreflightTranscription) {
try {
const { transcribeFirstAudio } = await import("../../media-understanding/audio-preflight.js");
const audioPaths =
message.attachments
?.filter((att: { content_type?: string; url: string }) =>
att.content_type?.startsWith("audio/"),
)
.map((att: { url: string }) => att.url) ?? [];
if (audioPaths.length > 0) {
const tempCtx = {
MediaUrls: audioPaths,
MediaTypes: message.attachments
?.filter((att: { content_type?: string; url: string }) =>
att.content_type?.startsWith("audio/"),
)
.map((att: { content_type?: string }) => att.content_type)
.filter(Boolean) as string[],
};
preflightTranscript = await transcribeFirstAudio({
ctx: tempCtx,
cfg: params.cfg,
agentDir: undefined,
});
}
} catch (err) {
logVerbose(`discord: audio preflight transcription failed: ${String(err)}`);
}
}
// Preflight audio transcription for mention detection in guilds.
// This allows voice notes to be checked for mentions before being dropped.
const { hasTypedText, transcript: preflightTranscript } =
await resolveDiscordPreflightAudioMentionContext({
message,
isDirectMessage,
shouldRequireMention,
mentionRegexes,
cfg: params.cfg,
});
const mentionText = hasTypedText ? baseText : "";
const wasMentioned =

View File

@@ -0,0 +1,72 @@
import type { OpenClawConfig } from "../../config/config.js";
import { logVerbose } from "../../globals.js";
type DiscordAudioAttachment = {
content_type?: string;
url?: string;
};
function collectAudioAttachments(
attachments: DiscordAudioAttachment[] | undefined,
): DiscordAudioAttachment[] {
if (!Array.isArray(attachments)) {
return [];
}
return attachments.filter((att) => att.content_type?.startsWith("audio/"));
}
export async function resolveDiscordPreflightAudioMentionContext(params: {
message: {
attachments?: DiscordAudioAttachment[];
content?: string;
};
isDirectMessage: boolean;
shouldRequireMention: boolean;
mentionRegexes: RegExp[];
cfg: OpenClawConfig;
}): Promise<{
hasAudioAttachment: boolean;
hasTypedText: boolean;
transcript?: string;
}> {
const audioAttachments = collectAudioAttachments(params.message.attachments);
const hasAudioAttachment = audioAttachments.length > 0;
const hasTypedText = Boolean(params.message.content?.trim());
const needsPreflightTranscription =
!params.isDirectMessage &&
params.shouldRequireMention &&
hasAudioAttachment &&
// `baseText` includes media placeholders; gate on typed text only.
!hasTypedText &&
params.mentionRegexes.length > 0;
let transcript: string | undefined;
if (needsPreflightTranscription) {
try {
const { transcribeFirstAudio } = await import("../../media-understanding/audio-preflight.js");
const audioUrls = audioAttachments
.map((att) => att.url)
.filter((url): url is string => typeof url === "string" && url.length > 0);
if (audioUrls.length > 0) {
transcript = await transcribeFirstAudio({
ctx: {
MediaUrls: audioUrls,
MediaTypes: audioAttachments
.map((att) => att.content_type)
.filter((contentType): contentType is string => Boolean(contentType)),
},
cfg: params.cfg,
agentDir: undefined,
});
}
} catch (err) {
logVerbose(`discord: audio preflight transcription failed: ${String(err)}`);
}
}
return {
hasAudioAttachment,
hasTypedText,
transcript,
};
}