Übersicht der Quellen

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer


Bilddatei

outbound-adapter.ts


products/Sources/formale Sprachen/Java/Openclaw/extensions/discord/src/outbound-adapter.ts

import { type ChannelOutboundAdapter, createAttachedChannelResultAdapter, } from "openclaw/plugin-sdk/channel-send-result"; import type { OpenClawConfig } from "openclaw/plugin-sdk/config-runtime"; import { resolveOutboundSendDep, type OutboundIdentity, } from "openclaw/plugin-sdk/outbound-runtime"; import { normalizeOptionalString, normalizeOptionalStringifiedId, } from "openclaw/plugin-sdk/text-runtime"; import { chunkDiscordTextWithMode } from "./chunk.js"; import { withDiscordDeliveryRetry } from "./delivery-retry.js"; import { isLikelyDiscordVideoMedia } from "./media-detection.js"; import type { ThreadBindingRecord } from "./monitor/thread-bindings.js"; import { normalizeDiscordOutboundTarget } from "./normalize.js"; import { normalizeDiscordApprovalPayload } from "./outbound-approval.js"; import { buildDiscordPresentationPayload } from "./outbound-components.js"; import { sendDiscordOutboundPayload } from "./outbound-payload.js"; import { loadDiscordSendRuntime, resolveDiscordFormattingOptions, resolveDiscordOutboundTarget, type DiscordSendFn, type DiscordVoiceSendFn, } from "./outbound-send-context.js"; export const DISCORD_TEXT_CHUNK_LIMIT = 2000; type DiscordThreadBindingsModule = typeof import("./monitor/thread-bindings.js"); let discordThreadBindingsPromise: Promise | undefined; function loadDiscordThreadBindings(): Promise { discordThreadBindingsPromise ??= import("./monitor/thread-bindings.js"); return discordThreadBindingsPromise; } function resolveDiscordWebhookIdentity(params: { identity?: OutboundIdentity; binding: ThreadBindingRecord; }): { username?: string; avatarUrl?: string } { const usernameRaw = normalizeOptionalString(params.identity?.name); const fallbackUsername = normalizeOptionalString(params.binding.label) ?? params.binding.agentId; const username = (usernameRaw || fallbackUsername || "").slice(0, 80) || undefined; const avatarUrl = normalizeOptionalString(params.identity?.avatarUrl); return { username, avatarUrl }; } async function maybeSendDiscordWebhookText(params: { cfg: OpenClawConfig; text: string; threadId?: string | number | null; accountId?: string | null; identity?: OutboundIdentity; replyToId?: string | null; }): Promise<{ messageId: string; channelId: string } | null> { if (params.threadId == null) { return null; } const threadId = normalizeOptionalStringifiedId(params.threadId) ?? ""; if (!threadId) { return null; } const { getThreadBindingManager } = await loadDiscordThreadBindings(); const manager = getThreadBindingManager(params.accountId ?? undefined); if (!manager) { return null; } const binding = manager.getByThreadId(threadId); if (!binding?.webhookId || !binding?.webhookToken) { return null; } const persona = resolveDiscordWebhookIdentity({ identity: params.identity, binding, }); const { sendWebhookMessageDiscord } = await loadDiscordSendRuntime(); const result = await sendWebhookMessageDiscord(params.text, { webhookId: binding.webhookId, webhookToken: binding.webhookToken, accountId: binding.accountId, threadId: binding.threadId, cfg: params.cfg, replyTo: params.replyToId ?? undefined, username: persona.username, avatarUrl: persona.avatarUrl, }); return result; } export const discordOutbound: ChannelOutboundAdapter = { deliveryMode: "direct", chunker: (text, limit, ctx) => chunkDiscordTextWithMode(text, { maxChars: limit, maxLines: ctx?.formatting?.maxLinesPerMessage, }), textChunkLimit: DISCORD_TEXT_CHUNK_LIMIT, pollMaxOptions: 10, normalizePayload: ({ payload }) => normalizeDiscordApprovalPayload(payload), presentationCapabilities: { supported: true, buttons: true, selects: true, context: true, divider: true, }, renderPresentation: async ({ payload, presentation }) => { return await buildDiscordPresentationPayload({ payload, presentation, }); }, resolveTarget: ({ to }) => normalizeDiscordOutboundTarget(to), sendPayload: async (ctx) => await sendDiscordOutboundPayload({ ctx, fallbackAdapter: discordOutbound, }), ...createAttachedChannelResultAdapter({ channel: "discord", sendText: async ({ cfg, to, text, accountId, deps, replyToId, threadId, identity, silent, formatting, }) => { if (!silent) { const webhookResult = await maybeSendDiscordWebhookText({ cfg, text, threadId, accountId, identity, replyToId, }).catch(() => null); if (webhookResult) { return webhookResult; } } const send = resolveOutboundSendDep(deps, "discord") ?? (await loadDiscordSendRuntime()).sendMessageDiscord; return await withDiscordDeliveryRetry({ cfg, accountId, fn: async () => await send(resolveDiscordOutboundTarget({ to, threadId }), text, { verbose: false, replyTo: replyToId ?? undefined, accountId: accountId ?? undefined, silent: silent ?? undefined, cfg, ...resolveDiscordFormattingOptions({ formatting }), }), }); }, sendMedia: async ({ cfg, to, text, mediaUrl, audioAsVoice, mediaAccess, mediaLocalRoots, mediaReadFile, accountId, deps, replyToId, threadId, silent, formatting, }) => { const send = resolveOutboundSendDep(deps, "discord") ?? (await loadDiscordSendRuntime()).sendMessageDiscord; const target = resolveDiscordOutboundTarget({ to, threadId }); const formattingOptions = resolveDiscordFormattingOptions({ formatting }); if (audioAsVoice && mediaUrl) { const sendVoice = resolveOutboundSendDep(deps, "discordVoice") ?? (await loadDiscordSendRuntime()).sendVoiceMessageDiscord; return await withDiscordDeliveryRetry({ cfg, accountId, fn: async () => await sendVoice(target, mediaUrl, { cfg, replyTo: replyToId ?? undefined, accountId: accountId ?? undefined, silent: silent ?? undefined, }), }); } if (text.trim() && mediaUrl && isLikelyDiscordVideoMedia(mediaUrl)) { await withDiscordDeliveryRetry({ cfg, accountId, fn: async () => await send(target, text, { verbose: false, replyTo: replyToId ?? undefined, accountId: accountId ?? undefined, silent: silent ?? undefined, cfg, ...formattingOptions, }), }); return await withDiscordDeliveryRetry({ cfg, accountId, fn: async () => await send(target, "", { verbose: false, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, accountId: accountId ?? undefined, silent: silent ?? undefined, cfg, ...formattingOptions, }), }); } return await withDiscordDeliveryRetry({ cfg, accountId, fn: async () => await send(target, text, { verbose: false, mediaUrl, mediaAccess, mediaLocalRoots, mediaReadFile, replyTo: replyToId ?? undefined, accountId: accountId ?? undefined, silent: silent ?? undefined, cfg, ...formattingOptions, }), }); }, sendPoll: async ({ cfg, to, poll, accountId, threadId, silent }) => await withDiscordDeliveryRetry({ cfg, accountId, fn: async () => await ( await loadDiscordSendRuntime() ).sendPollDiscord(resolveDiscordOutboundTarget({ to, threadId }), poll, { accountId: accountId ?? undefined, silent: silent ?? undefined, cfg, }), }), }), afterDeliverPayload: async ({ target }) => { const threadId = normalizeOptionalStringifiedId(target.threadId); if (!threadId) { return; } const { getThreadBindingManager } = await loadDiscordThreadBindings(); const manager = getThreadBindingManager(target.accountId ?? undefined); if (!manager?.getByThreadId(threadId)) { return; } manager.touchThread({ threadId }); }, };

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1126864
#Domains=2039723