UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

1,421 lines 53.7 kB
import { i as formatErrorMessage } from "./errors-BXgSefBE.js";
import { i as emitInternalDiagnosticEvent } from "./diagnostic-events-Chmz2PSy.js";
import { t as createSubsystemLogger } from "./subsystem-BzXSmsuh.js";
import { r as copyReplyPayloadMetadata } from "./reply-payload-CZJ2cgZc.js";
import { t as getGlobalHookRunner, u as fireAndForgetHook } from "./hook-runner-global-BnyQREr6.js";
import { m as triggerInternalHook, n as createInternalHookEvent } from "./internal-hooks-Bq6_9FFu.js";
import { o as resolveMirroredTranscriptText } from "./transcript-Cw-EfeYD.js";
import { a as toInternalMessageSentContext, d as toPluginMessageSentEvent, l as toPluginMessageContext, t as buildCanonicalSentMessageHookContext } from "./message-hook-mappers-BqsqHKq-.js";
import { C as createReplyToDeliveryPolicy } from "./reply-payload-D-VMfpYI.js";
import { a as hasReplyPayloadContent, f as renderMessagePresentationFallbackText, l as normalizeMessagePresentation } from "./payload-CZlThETZ.js";
import { t as diagnosticErrorCategory } from "./diagnostic-error-metadata-CkeS05A3.js";
import { c as resolveTextChunkLimit, i as chunkMarkdownTextWithMode, n as chunkByParagraph, s as resolveChunkMode } from "./chunk-Cpb8JO1x.js";
import { n as adaptMessagePresentationForChannel } from "./interactive-DED9EUdL.js";
import { t as loadChannelOutboundAdapter } from "./load-BBQWnOQX.js";
import { t as resolveAgentScopedOutboundMediaAccess } from "./read-capability-D9fJOFWQ.js";
import { n as resolveOutboundChannelMessageAdapter } from "./channel-resolution-azq0u3DK.js";
import { S as runOutboundDeliveryCommitHooks, c as enqueueDelivery, f as markDeliveryPlatformOutcomeUnknown, l as failDelivery, o as withActiveDeliveryClaim, p as markDeliveryPlatformSendAttemptStarted, s as ackDelivery, x as attachOutboundDeliveryCommitHook } from "./delivery-queue-Ds6M9589.js";
import { l as summarizeOutboundPayloadForTransport, t as createOutboundPayloadPlan } from "./payloads-B4DTFTLz.js";
import { n as stripInternalRuntimeScaffolding } from "./sanitize-text-BOGhD8MR.js";
//#region src/infra/outbound/deliver-types.ts
/** Error carrying partial delivery results when an outbound send fails mid-batch. */
var OutboundDeliveryError = class extends Error {
	constructor(message, options) {
		super(message, { cause: options.cause });
		this.name = "OutboundDeliveryError";
		this.results = [...options.results ?? []];
		this.payloadOutcomes = [...options.payloadOutcomes ?? []];
		this.sentBeforeError = this.results.length > 0;
		this.stage = options.stage ?? "unknown";
	}
};
/** Narrows unknown failures to outbound delivery errors with partial-send metadata. */
function isOutboundDeliveryError(error) {
	return error instanceof OutboundDeliveryError;
}
//#endregion
//#region src/auto-reply/reply/reply-payload-sending-hook.ts
/** Runs plugin hooks that may rewrite or cancel an outbound reply payload. */
async function runReplyPayloadSendingHook(params) {
	const hookRunner = getGlobalHookRunner();
	if (!hookRunner?.hasHooks("reply_payload_sending")) return params.payload;
	const result = await hookRunner.runReplyPayloadSending({
		payload: params.payload,
		kind: params.kind,
		channel: params.channel,
		sessionKey: params.sessionKey,
		runId: params.runId
	}, params.context);
	if (result?.cancel) return null;
	const payload = result?.payload ?? params.payload;
	return copyReplyPayloadMetadata(params.payload, payload);
}
//#endregion
//#region src/channels/message/rendered-batch.ts
function countMedia(payload) {
	return (payload.mediaUrls?.filter(Boolean).length ?? 0) + (payload.mediaUrl ? 1 : 0);
}
function collectMediaUrls(payload) {
	return [payload.mediaUrl, ...payload.mediaUrls ?? []].map((url) => url?.trim()).filter((url) => Boolean(url));
}
function createRenderedMessageBatchPlanItem(payload, index) {
	const text = payload.text?.trim();
	const mediaUrls = collectMediaUrls(payload);
	const presentationBlockCount = payload.presentation?.blocks?.length ?? 0;
	const kinds = [];
	if (text) kinds.push("text");
	if (mediaUrls.length > 0) kinds.push(payload.audioAsVoice ? "voice" : "media");
	if (presentationBlockCount > 0) kinds.push("presentation");
	if (payload.interactive) kinds.push("interactive");
	if (payload.channelData) kinds.push("channelData");
	return {
		index,
		kinds: kinds.length > 0 ? kinds : ["empty"],
		...text ? { text } : {},
		mediaUrls,
		...payload.audioAsVoice && mediaUrls.length > 0 ? { audioAsVoice: true } : {},
		...presentationBlockCount > 0 ? { presentationBlockCount } : {},
		...payload.interactive ? { hasInteractive: true } : {},
		...payload.channelData ? { hasChannelData: true } : {}
	};
}
/** Summarizes rendered reply payloads so delivery can choose adapter paths and recovery metadata. */
function createRenderedMessageBatchPlan(payloads) {
	const items = payloads.map(createRenderedMessageBatchPlanItem);
	return payloads.reduce((plan, payload) => {
		const text = payload.text?.trim();
		const mediaCount = countMedia(payload);
		return {
			payloadCount: plan.payloadCount + 1,
			textCount: plan.textCount + (text ? 1 : 0),
			mediaCount: plan.mediaCount + mediaCount,
			voiceCount: plan.voiceCount + (payload.audioAsVoice && mediaCount > 0 ? 1 : 0),
			presentationCount: plan.presentationCount + (payload.presentation?.blocks?.length ? 1 : 0),
			interactiveCount: plan.interactiveCount + (payload.interactive ? 1 : 0),
			channelDataCount: plan.channelDataCount + (payload.channelData ? 1 : 0),
			items: plan.items
		};
	}, {
		payloadCount: 0,
		textCount: 0,
		mediaCount: 0,
		voiceCount: 0,
		presentationCount: 0,
		interactiveCount: 0,
		channelDataCount: 0,
		items
	});
}
/** Pairs reply payloads with their render plan for durable send and live-preview flows. */
function createRenderedMessageBatch(payloads) {
	return {
		payloads,
		plan: createRenderedMessageBatchPlan(payloads)
	};
}
//#endregion
//#region src/infra/outbound/abort.ts
/**
* Throws an AbortError if the given signal has been aborted.
* Use at async checkpoints to support cancellation.
*/
function throwIfAborted(abortSignal) {
	if (abortSignal?.aborted) {
		const err = /* @__PURE__ */ new Error("Operation aborted");
		err.name = "AbortError";
		throw err;
	}
}
//#endregion
//#region src/infra/outbound/message-plan.ts
function withPlannedReplyTo(overrides, consumeReplyTo) {
	return consumeReplyTo ? consumeReplyTo({ ...overrides }) : { ...overrides };
}
function withChunkedTextFormatting(overrides, formatting) {
	return formatting ? {
		...overrides,
		formatting: {
			...overrides.formatting,
			...formatting
		}
	} : overrides;
}
function chunkTextForPlan(params) {
	return params.formatting ? params.chunker(params.text, params.limit, { formatting: params.formatting }) : params.chunker(params.text, params.limit);
}
/**
* Plans text sends, preserving reply-to policy across chunked delivery units.
*/
function planOutboundTextMessageUnits(params) {
	const planTextUnit = (text) => ({
		kind: "text",
		text,
		overrides: withPlannedReplyTo(params.overrides, params.consumeReplyTo)
	});
	const planChunkedTextUnit = (text) => {
		const unit = planTextUnit(text);
		return {
			...unit,
			overrides: withChunkedTextFormatting(unit.overrides, params.chunkedTextFormatting)
		};
	};
	if (!params.chunker || params.textLimit === void 0) return [planTextUnit(params.text)];
	if (params.chunkMode === "newline") {
		const blockChunks = (params.chunkerMode ?? "text") === "markdown" ? chunkMarkdownTextWithMode(params.text, params.textLimit, "newline") : chunkByParagraph(params.text, params.textLimit);
		if (!blockChunks.length && params.text) blockChunks.push(params.text);
		const units = [];
		for (const blockChunk of blockChunks) {
			const chunks = chunkTextForPlan({
				text: blockChunk,
				limit: params.textLimit,
				chunker: params.chunker,
				formatting: params.formatting
			});
			if (!chunks.length && blockChunk) chunks.push(blockChunk);
			for (const chunk of chunks) units.push(planChunkedTextUnit(chunk));
		}
		return units;
	}
	return chunkTextForPlan({
		text: params.text,
		limit: params.textLimit,
		chunker: params.chunker,
		formatting: params.formatting
	}).map(planChunkedTextUnit);
}
/**
* Plans media sends with a caption only on the leading media unit.
*/
function planOutboundMediaMessageUnits(params) {
	return params.mediaUrls.map((mediaUrl, index) => ({
		kind: "media",
		mediaUrl,
		...index === 0 ? { caption: params.caption } : {},
		overrides: withPlannedReplyTo(params.overrides, params.consumeReplyTo)
	}));
}
//#endregion
//#region src/infra/outbound/deliver.ts
const log = createSubsystemLogger("outbound/deliver");
let transcriptRuntimePromise;
async function loadTranscriptRuntime() {
	transcriptRuntimePromise ??= import("./transcript.runtime.js");
	return await transcriptRuntimePromise;
}
let channelBootstrapRuntimePromise;
async function loadChannelBootstrapRuntime() {
	channelBootstrapRuntimePromise ??= import("./channel-bootstrap.runtime.js");
	return await channelBootstrapRuntimePromise;
}
async function resolveChannelOutboundDirectiveOptions(params) {
	return { extractMarkdownImages: (await loadBootstrappedOutboundAdapter(params))?.extractMarkdownImages === true ? true : void 0 };
}
async function createChannelHandler(params) {
	const outbound = await loadBootstrappedOutboundAdapter(params);
	const message = resolveOutboundChannelMessageAdapter(params);
	const handler = createPluginHandler({
		...params,
		outbound,
		message
	});
	if (!handler) throw new Error(`Outbound not configured for channel: ${params.channel}`);
	return handler;
}
async function loadBootstrappedOutboundAdapter(params) {
	let outbound = await loadChannelOutboundAdapter(params.channel);
	if (!outbound) {
		const { bootstrapOutboundChannelPlugin } = await loadChannelBootstrapRuntime();
		bootstrapOutboundChannelPlugin({
			channel: params.channel,
			cfg: params.cfg
		});
		outbound = await loadChannelOutboundAdapter(params.channel);
	}
	return outbound;
}
async function runChannelMessageSendWithLifecycle(params) {
	if (!params.lifecycle) return { result: await params.send() };
	let attemptToken;
	try {
		attemptToken = await params.lifecycle.beforeSendAttempt?.(params.ctx);
		const result = await params.send();
		const successCtx = {
			...params.ctx,
			result,
			...attemptToken !== void 0 ? { attemptToken } : {}
		};
		try {
			await params.lifecycle.afterSendSuccess?.(successCtx);
		} catch (successHookError) {
			log.warn(`channel message send success hook failed after platform send; preserving send result: ${formatErrorMessage(successHookError)}`);
		}
		return {
			result,
			...params.lifecycle.afterCommit ? { afterCommit: async () => {
				await params.lifecycle?.afterCommit?.(successCtx);
			} } : {}
		};
	} catch (error) {
		try {
			await params.lifecycle.afterSendFailure?.({
				...params.ctx,
				error,
				...attemptToken !== void 0 ? { attemptToken } : {}
			});
		} catch (cleanupError) {
			log.warn(`channel message send failure cleanup failed; preserving original send error: ${formatErrorMessage(cleanupError)}`);
		}
		throw error;
	}
}
async function resolveOutboundDurableFinalDeliverySupport(params) {
	const outbound = await loadBootstrappedOutboundAdapter(params);
	const message = resolveOutboundChannelMessageAdapter(params);
	if (!message?.send?.text && !outbound?.sendText) return {
		ok: false,
		reason: "missing_outbound_handler"
	};
	const messageDurableFinal = message?.durableFinal;
	const durableFinal = messageDurableFinal?.capabilities ?? outbound?.deliveryCapabilities?.durableFinal;
	for (const [capability, required] of Object.entries(params.requirements ?? {})) {
		if (required === true && durableFinal?.[capability] !== true) return {
			ok: false,
			reason: "capability_mismatch",
			capability
		};
		if (required === true && capability === "reconcileUnknownSend" && typeof messageDurableFinal?.reconcileUnknownSend !== "function") return {
			ok: false,
			reason: "capability_mismatch",
			capability
		};
	}
	return { ok: true };
}
function createPluginHandler(params) {
	const outbound = params.outbound;
	const messageText = params.message?.send?.text;
	const messageMedia = params.message?.send?.media;
	const messagePayload = params.message?.send?.payload;
	const messageLifecycle = params.message?.send?.lifecycle;
	if (!messageText && !outbound?.sendText) return null;
	const baseCtx = createChannelOutboundContextBase(params);
	const sendText = outbound?.sendText;
	const sendMedia = outbound?.sendMedia;
	const chunker = outbound?.chunker ?? null;
	const chunkerMode = outbound?.chunkerMode;
	const resolveCtx = (overrides) => ({
		...baseCtx,
		replyToId: overrides && "replyToId" in overrides ? overrides.replyToId : baseCtx.replyToId,
		replyToIdSource: overrides && "replyToIdSource" in overrides ? overrides.replyToIdSource : baseCtx.replyToIdSource,
		threadId: overrides && "threadId" in overrides ? overrides.threadId : baseCtx.threadId,
		audioAsVoice: overrides?.audioAsVoice,
		formatting: overrides && "formatting" in overrides ? {
			...baseCtx.formatting,
			...overrides.formatting
		} : baseCtx.formatting
	});
	const buildTargetRef = (overrides) => ({
		channel: params.channel,
		to: params.to,
		accountId: params.accountId ?? void 0,
		threadId: overrides?.threadId ?? baseCtx.threadId
	});
	return {
		chunker,
		chunkerMode,
		chunkedTextFormatting: outbound?.chunkedTextFormatting,
		textChunkLimit: outbound?.textChunkLimit,
		supportsMedia: Boolean(messageMedia ?? sendMedia),
		sanitizeText: outbound?.sanitizeText ? (payload) => outbound.sanitizeText({
			text: payload.text ?? "",
			payload
		}) : void 0,
		normalizePayload: outbound?.normalizePayload ? (payload) => outbound.normalizePayload({
			payload,
			cfg: params.cfg,
			accountId: params.accountId
		}) : void 0,
		sendTextOnlyErrorPayloads: outbound?.sendTextOnlyErrorPayloads === true,
		presentationCapabilities: outbound?.presentationCapabilities,
		renderPresentation: outbound?.renderPresentation ? async (payload) => {
			const presentation = normalizeMessagePresentation(payload.presentation);
			if (!presentation) return payload;
			const ctx = {
				...resolveCtx({
					replyToId: payload.replyToId ?? baseCtx.replyToId,
					threadId: baseCtx.threadId,
					audioAsVoice: payload.audioAsVoice
				}),
				text: payload.text ?? "",
				mediaUrl: payload.mediaUrl,
				payload
			};
			return await outbound.renderPresentation({
				payload,
				presentation,
				ctx
			});
		} : void 0,
		pinDeliveredMessage: outbound?.pinDeliveredMessage ? async ({ target, messageId, pin, gatewayClientScopes }) => outbound.pinDeliveredMessage({
			cfg: params.cfg,
			target,
			messageId,
			pin,
			gatewayClientScopes
		}) : void 0,
		afterDeliverPayload: outbound?.afterDeliverPayload ? async ({ target, payload, results }) => outbound.afterDeliverPayload({
			cfg: params.cfg,
			target,
			payload,
			results
		}) : void 0,
		shouldSkipPlainTextSanitization: outbound?.shouldSkipPlainTextSanitization ? (payload) => outbound.shouldSkipPlainTextSanitization({ payload }) : void 0,
		resolveEffectiveTextChunkLimit: outbound?.resolveEffectiveTextChunkLimit ? (fallbackLimit) => outbound.resolveEffectiveTextChunkLimit({
			cfg: params.cfg,
			accountId: params.accountId ?? void 0,
			fallbackLimit
		}) : void 0,
		sendPayload: messagePayload || outbound?.sendPayload ? async (payload, overrides) => {
			const payloadCtx = {
				...resolveCtx(overrides),
				kind: "payload",
				text: payload.text ?? "",
				mediaUrl: payload.mediaUrl,
				payload
			};
			if (messagePayload) {
				const sent = await runChannelMessageSendWithLifecycle({
					lifecycle: messageLifecycle,
					ctx: payloadCtx,
					send: async () => {
						await params.onPlatformSendStart?.();
						return await messagePayload(payloadCtx);
					}
				});
				return attachOutboundDeliveryCommitHook(normalizeChannelMessageSendResult(params.channel, sent.result), sent.afterCommit);
			}
			await params.onPlatformSendStart?.();
			return outbound.sendPayload(payloadCtx);
		} : void 0,
		sendFormattedText: outbound?.sendFormattedText ? async (text, overrides) => {
			await params.onPlatformSendStart?.();
			return await outbound.sendFormattedText({
				...resolveCtx(overrides),
				text
			});
		} : void 0,
		sendFormattedMedia: outbound?.sendFormattedMedia ? async (caption, mediaUrl, overrides) => {
			await params.onPlatformSendStart?.();
			return await outbound.sendFormattedMedia({
				...resolveCtx(overrides),
				text: caption,
				mediaUrl
			});
		} : void 0,
		sendText: async (text, overrides) => {
			const textCtx = {
				...resolveCtx(overrides),
				kind: "text",
				text
			};
			if (messageText) {
				const sent = await runChannelMessageSendWithLifecycle({
					lifecycle: messageLifecycle,
					ctx: textCtx,
					send: async () => {
						await params.onPlatformSendStart?.();
						return await messageText(textCtx);
					}
				});
				return attachOutboundDeliveryCommitHook(normalizeChannelMessageSendResult(params.channel, sent.result), sent.afterCommit);
			}
			await params.onPlatformSendStart?.();
			return sendText(textCtx);
		},
		buildTargetRef,
		sendMedia: async (caption, mediaUrl, overrides) => {
			const mediaCtx = {
				...resolveCtx(overrides),
				kind: "media",
				text: caption,
				mediaUrl
			};
			if (messageMedia) {
				const sent = await runChannelMessageSendWithLifecycle({
					lifecycle: messageLifecycle,
					ctx: mediaCtx,
					send: async () => {
						await params.onPlatformSendStart?.();
						return await messageMedia(mediaCtx);
					}
				});
				return attachOutboundDeliveryCommitHook(normalizeChannelMessageSendResult(params.channel, sent.result), sent.afterCommit);
			}
			if (sendMedia) {
				await params.onPlatformSendStart?.();
				return sendMedia(mediaCtx);
			}
			await params.onPlatformSendStart?.();
			return sendText(mediaCtx);
		}
	};
}
function normalizeChannelMessageSendResult(channel, result) {
	const source = result;
	return {
		...source,
		channel,
		messageId: source.messageId ?? source.receipt.primaryPlatformMessageId ?? source.receipt.platformMessageIds[0] ?? "",
		receipt: source.receipt
	};
}
function createChannelOutboundContextBase(params) {
	return {
		cfg: params.cfg,
		to: params.to,
		accountId: params.accountId,
		replyToId: params.replyToId,
		replyToMode: params.replyToMode,
		formatting: params.formatting,
		threadId: params.threadId,
		identity: params.identity,
		gifPlayback: params.gifPlayback,
		forceDocument: params.forceDocument,
		deps: params.deps,
		silent: params.silent,
		mediaAccess: params.mediaAccess,
		mediaLocalRoots: params.mediaAccess?.localRoots,
		mediaReadFile: params.mediaAccess?.readFile,
		gatewayClientScopes: params.gatewayClientScopes
	};
}
const isAbortError = (err) => err instanceof Error && err.name === "AbortError";
const isDeliveryAbortError = (err) => isAbortError(err) || err instanceof OutboundDeliveryError && isAbortError(err.cause);
async function markQueuedPlatformSendAttemptStarted(params) {
	try {
		await markDeliveryPlatformSendAttemptStarted(params.queueId);
		return true;
	} catch (err) {
		if (params.queuePolicy === "required") throw err;
		log.warn(`failed to mark queued delivery ${params.queueId} as platform-send-attempt-started; continuing best-effort delivery: ${formatErrorMessage(err)}`);
		return false;
	}
}
async function markQueuedPlatformOutcomeUnknown(params) {
	try {
		await markDeliveryPlatformOutcomeUnknown(params.queueId);
	} catch (err) {
		if (params.queuePolicy === "required") throw err;
		log.warn(`failed to mark queued delivery ${params.queueId} as platform-outcome-unknown; continuing best-effort delivery: ${formatErrorMessage(err)}`);
	}
}
/**
* Best-effort session identifier for delivery telemetry only. Falls back to
* `policyKey` as a last resort so diagnostic emission still has a stable
* string when neither mirror nor canonical key are available. **Do not use
* this value for hook-context correlation** — use `sessionKeyForInternalHooks`
* (mirror.sessionKey ?? session.key, no policyKey fallback) instead, so we
* never accidentally hand the policy key to plugins that expect the canonical
* session key.
*/
function sessionKeyForDeliveryDiagnostics(params) {
	return params.mirror?.sessionKey ?? params.session?.key ?? params.session?.policyKey;
}
function deliveryKindForPayload(payload, payloadSummary) {
	if (payloadSummary.mediaUrls.length > 0 || payload.mediaUrl || payload.mediaUrls?.length) return "media";
	if (payload.presentation || payload.interactive || payload.channelData || payload.audioAsVoice) return "other";
	return "text";
}
function emitMessageDeliveryStarted(params) {
	emitInternalDiagnosticEvent({
		type: "message.delivery.started",
		channel: params.channel,
		deliveryKind: params.deliveryKind,
		...params.sessionKey ? { sessionKey: params.sessionKey } : {}
	});
}
function emitMessageDeliveryCompleted(params) {
	emitInternalDiagnosticEvent({
		type: "message.delivery.completed",
		channel: params.channel,
		deliveryKind: params.deliveryKind,
		durationMs: params.durationMs,
		resultCount: params.resultCount,
		...params.sessionKey ? { sessionKey: params.sessionKey } : {}
	});
}
function emitMessageDeliveryError(params) {
	emitInternalDiagnosticEvent({
		type: "message.delivery.error",
		channel: params.channel,
		deliveryKind: params.deliveryKind,
		durationMs: params.durationMs,
		errorCategory: diagnosticErrorCategory(params.error),
		...params.sessionKey ? { sessionKey: params.sessionKey } : {}
	});
}
function normalizeEmptyPayloadForDelivery(payload) {
	const text = typeof payload.text === "string" ? payload.text : "";
	if (!text.trim()) {
		if (!hasReplyPayloadContent({
			...payload,
			text
		})) return null;
		if (text) return {
			...payload,
			text: ""
		};
	}
	return payload;
}
function normalizePayloadsForChannelDelivery(plan, handler) {
	const normalizedPayloads = [];
	for (const entry of plan) {
		let sanitizedPayload = stripInternalRuntimeScaffoldingFromPayload(entry.payload);
		if (handler.sanitizeText && sanitizedPayload.text) {
			if (!handler.shouldSkipPlainTextSanitization?.(sanitizedPayload)) sanitizedPayload = {
				...sanitizedPayload,
				text: handler.sanitizeText(sanitizedPayload)
			};
		}
		const normalizedPayload = handler.normalizePayload ? handler.normalizePayload(sanitizedPayload) : sanitizedPayload;
		const normalized = normalizedPayload ? normalizeEmptyPayloadForDelivery(stripInternalRuntimeScaffoldingFromPayload(normalizedPayload)) : null;
		if (normalized) normalizedPayloads.push({
			index: entry.sourceIndex,
			payload: normalized
		});
	}
	return normalizedPayloads;
}
function stripInternalRuntimeScaffoldingFromValue(value) {
	if (typeof value === "string") return stripInternalRuntimeScaffolding(value);
	if (Array.isArray(value)) {
		let changed = false;
		const next = value.map((entry) => {
			const stripped = stripInternalRuntimeScaffoldingFromValue(entry);
			changed ||= stripped !== entry;
			return stripped;
		});
		return changed ? next : value;
	}
	if (!value || typeof value !== "object") return value;
	const proto = Object.getPrototypeOf(value);
	if (proto !== Object.prototype && proto !== null) return value;
	let changed = false;
	const next = {};
	for (const [key, entry] of Object.entries(value)) {
		const stripped = stripInternalRuntimeScaffoldingFromValue(entry);
		changed ||= stripped !== entry;
		next[key] = stripped;
	}
	return changed ? next : value;
}
function stripInternalRuntimeScaffoldingFromPayload(payload) {
	const stripped = stripInternalRuntimeScaffoldingFromValue(payload);
	return stripped && typeof stripped === "object" && !Array.isArray(stripped) ? stripped : payload;
}
function buildPayloadSummary(payload) {
	return summarizeOutboundPayloadForTransport(payload);
}
function hasDeliveryResultIdentity(result) {
	return Boolean(result.messageId || result.chatId || result.channelId || result.roomId || result.conversationId || result.toJid || result.pollId);
}
function normalizeDeliveryPin(payload) {
	const pin = payload.delivery?.pin;
	if (pin === true) return { enabled: true };
	if (!pin || typeof pin !== "object" || Array.isArray(pin)) return;
	if (!pin.enabled) return;
	const normalized = { enabled: true };
	if (pin.notify === true) normalized.notify = true;
	if (pin.required === true) normalized.required = true;
	return normalized;
}
async function maybePinDeliveredMessage(params) {
	const pin = normalizeDeliveryPin(params.payload);
	if (!pin) return;
	if (!params.messageId) {
		if (pin.required) throw new Error("Delivery pin requested, but no delivered message id was returned.");
		log.warn("Delivery pin requested, but no delivered message id was returned.", {
			channel: params.target.channel,
			to: params.target.to
		});
		return;
	}
	if (!params.handler.pinDeliveredMessage) {
		if (pin.required) throw new Error(`Delivery pin is not supported by channel: ${params.target.channel}`);
		log.warn("Delivery pin requested, but channel does not support pinning delivered messages.", {
			channel: params.target.channel,
			to: params.target.to
		});
		return;
	}
	try {
		await params.handler.pinDeliveredMessage({
			target: params.target,
			messageId: params.messageId,
			pin,
			gatewayClientScopes: params.gatewayClientScopes
		});
	} catch (err) {
		if (pin.required) throw err;
		log.warn("Delivery pin requested, but channel failed to pin delivered message.", {
			channel: params.target.channel,
			to: params.target.to,
			messageId: params.messageId,
			error: formatErrorMessage(err)
		});
	}
}
async function maybeNotifyAfterDeliveredPayload(params) {
	if (!params.handler.afterDeliverPayload || params.results.length === 0) return;
	try {
		await params.handler.afterDeliverPayload({
			target: params.target,
			payload: params.payload,
			results: params.results
		});
	} catch (err) {
		log.warn("Plugin outbound adapter after-delivery hook failed.", {
			channel: params.target.channel,
			to: params.target.to,
			error: formatErrorMessage(err)
		});
	}
}
async function renderPresentationForDelivery(handler, payload) {
	const presentation = normalizeMessagePresentation(payload.presentation);
	if (!presentation) return payload;
	const adaptedPresentation = adaptMessagePresentationForChannel({
		presentation,
		capabilities: handler.presentationCapabilities
	});
	const adaptedPayload = {
		...payload,
		presentation: adaptedPresentation
	};
	const rendered = handler.renderPresentation ? await handler.renderPresentation(adaptedPayload) : null;
	if (rendered) {
		const { presentation: _presentation, ...withoutPresentation } = rendered;
		return withoutPresentation;
	}
	const { presentation: _presentation, ...withoutPresentation } = payload;
	return {
		...withoutPresentation,
		text: renderMessagePresentationFallbackText({
			text: payload.text,
			presentation: adaptedPresentation
		})
	};
}
function createMessageSentEmitter(params) {
	const hasMessageSentHooks = params.hookRunner?.hasHooks("message_sent") ?? false;
	const canEmitInternalHook = Boolean(params.sessionKeyForInternalHooks);
	const emitMessageSent = (event) => {
		if (!hasMessageSentHooks && !canEmitInternalHook) return;
		const canonical = buildCanonicalSentMessageHookContext({
			to: params.to,
			content: event.content,
			success: event.success,
			error: event.error,
			channelId: params.channel,
			accountId: params.accountId ?? void 0,
			conversationId: params.to,
			sessionKey: params.sessionKeyForInternalHooks,
			messageId: event.messageId,
			isGroup: params.mirrorIsGroup,
			groupId: params.mirrorGroupId
		});
		if (hasMessageSentHooks) fireAndForgetHook(params.hookRunner.runMessageSent(toPluginMessageSentEvent(canonical), toPluginMessageContext(canonical)), "deliverOutboundPayloads: message_sent plugin hook failed", (message) => {
			log.warn(message);
		});
		if (!canEmitInternalHook) return;
		fireAndForgetHook(triggerInternalHook(createInternalHookEvent("message", "sent", params.sessionKeyForInternalHooks, toInternalMessageSentContext(canonical))), "deliverOutboundPayloads: message:sent internal hook failed", (message) => {
			log.warn(message);
		});
	};
	return {
		emitMessageSent,
		hasMessageSentHooks
	};
}
async function applyMessageSendingHook(params) {
	if (!params.enabled) return {
		cancelled: false,
		contentRewritten: false,
		payload: params.payload,
		payloadSummary: params.payloadSummary
	};
	try {
		const sendingResult = await params.hookRunner.runMessageSending({
			to: params.to,
			content: params.payloadSummary.hookContent ?? params.payloadSummary.text,
			replyToId: params.replyToId ?? void 0,
			threadId: params.threadId ?? void 0,
			metadata: {
				channel: params.channel,
				accountId: params.accountId,
				mediaUrls: params.payloadSummary.mediaUrls
			}
		}, {
			channelId: params.channel,
			accountId: params.accountId ?? void 0,
			conversationId: params.to,
			...params.sessionKey ? { sessionKey: params.sessionKey } : {}
		});
		if (sendingResult?.cancel) return {
			cancelled: true,
			...sendingResult.cancelReason ? { cancelReason: sendingResult.cancelReason } : {},
			...sendingResult.metadata ? { hookMetadata: sendingResult.metadata } : {},
			contentRewritten: false,
			payload: params.payload,
			payloadSummary: params.payloadSummary
		};
		if (sendingResult?.content == null) return {
			cancelled: false,
			contentRewritten: false,
			payload: params.payload,
			payloadSummary: params.payloadSummary
		};
		if (params.payloadSummary.hookContent && !params.payloadSummary.text) {
			const spokenText = sendingResult.content;
			return {
				cancelled: false,
				contentRewritten: true,
				payload: {
					...params.payload,
					spokenText
				},
				payloadSummary: {
					...params.payloadSummary,
					hookContent: spokenText
				}
			};
		}
		return {
			cancelled: false,
			contentRewritten: true,
			payload: {
				...params.payload,
				text: sendingResult.content
			},
			payloadSummary: {
				...params.payloadSummary,
				text: sendingResult.content
			}
		};
	} catch {
		return {
			cancelled: false,
			contentRewritten: false,
			payload: params.payload,
			payloadSummary: params.payloadSummary
		};
	}
}
async function applyReplyPayloadSendingHook(params) {
	if (!params.hook) return {
		cancelled: false,
		payload: params.payload,
		changed: false
	};
	const nextPayload = await runReplyPayloadSendingHook({
		payload: params.payload,
		kind: params.hook.kind,
		...params.hook.channel ? { channel: params.hook.channel } : {},
		...params.hook.sessionKey ? { sessionKey: params.hook.sessionKey } : {},
		...params.hook.runId ? { runId: params.hook.runId } : {},
		context: params.hook.context
	});
	if (!nextPayload) return {
		cancelled: true,
		payload: params.payload,
		changed: false
	};
	return {
		cancelled: false,
		payload: nextPayload,
		changed: nextPayload !== params.payload
	};
}
function toOutboundDeliveryError(params) {
	if (params.error instanceof OutboundDeliveryError) return params.error;
	return new OutboundDeliveryError(formatErrorMessage(params.error), {
		cause: params.error,
		results: params.results,
		payloadOutcomes: params.payloadOutcomes,
		stage: params.stage
	});
}
function suppressedPayloadOutcome(params) {
	return {
		index: params.index,
		status: "suppressed",
		reason: params.reason,
		...params.hookEffect ? { hookEffect: params.hookEffect } : {}
	};
}
/**
* @deprecated Direct outbound delivery is compatibility/runtime substrate.
* New message lifecycle code should use `sendDurableMessageBatch` from
* `src/channels/message/send.ts` or `deliverInboundReplyWithMessageSendContext`
* from `src/channels/turn/durable-delivery.ts`. Keep direct use only for
* outbound substrate, recovery, and compatibility paths.
*/
async function deliverOutboundPayloads(params) {
	return await deliverOutboundPayloadsInternal(params);
}
async function deliverOutboundPayloadsInternal(params) {
	const { channel, to, payloads } = params;
	const queuePolicy = params.queuePolicy ?? "best_effort";
	const queuePayloads = payloads.map(stripInternalRuntimeScaffoldingFromPayload);
	const queuePayloadsChanged = queuePayloads.some((payload, index) => payload !== payloads[index]);
	const renderedBatchPlan = params.renderedBatchPlan ?? createRenderedMessageBatchPlan(params.payloads);
	const queueRenderedBatchPlan = queuePayloadsChanged ? createRenderedMessageBatchPlan(queuePayloads) : renderedBatchPlan;
	const queueId = params.skipQueue ? null : await enqueueDelivery({
		channel,
		to,
		accountId: params.accountId,
		payloads: queuePayloads,
		renderedBatchPlan: queueRenderedBatchPlan,
		threadId: params.threadId,
		replyToId: params.replyToId,
		replyToMode: params.replyToMode,
		formatting: params.formatting,
		identity: params.identity,
		bestEffort: params.bestEffort,
		gifPlayback: params.gifPlayback,
		forceDocument: params.forceDocument,
		replyPayloadSendingHook: params.replyPayloadSendingHook,
		silent: params.silent,
		mirror: params.mirror,
		session: params.session,
		gatewayClientScopes: params.gatewayClientScopes
	}).catch((err) => {
		if (queuePolicy === "required") throw err;
		return null;
	});
	if (queueId) params.onDeliveryIntent?.({
		id: queueId,
		channel,
		to,
		...params.accountId ? { accountId: params.accountId } : {},
		queuePolicy
	});
	if (!queueId) return await deliverOutboundPayloadsWithQueueCleanup(params, null);
	const claimResult = await withActiveDeliveryClaim(queueId, () => deliverOutboundPayloadsWithQueueCleanup(params, queueId));
	if (claimResult.status === "claimed-by-other-owner") return [];
	return claimResult.value;
}
async function deliverOutboundPayloadsWithQueueCleanup(params, queueId) {
	let hadPartialFailure = false;
	const wrappedParams = {
		...params,
		onError: (err, payload) => {
			hadPartialFailure = true;
			params.onError?.(err, payload);
		}
	};
	const queuePolicy = params.queuePolicy ?? "best_effort";
	let platformResultsReturned = false;
	try {
		let platformSendStarted = false;
		const results = await deliverOutboundPayloadsCore({
			...wrappedParams,
			...queueId ? { onPlatformSendStart: async () => {
				if (platformSendStarted) return;
				platformSendStarted = await markQueuedPlatformSendAttemptStarted({
					queueId,
					queuePolicy
				});
			} } : {}
		});
		platformResultsReturned = true;
		if (!queueId) {
			if (!params.deferCommitHooks) await runOutboundDeliveryCommitHooks(results);
			return results;
		}
		if (queueId) if (hadPartialFailure) await failDelivery(queueId, "partial delivery failure (bestEffort)").catch((err) => {
			log.warn(`failed to mark queued delivery ${queueId} as failed after partial failure; continuing best-effort delivery: ${formatErrorMessage(err)}`);
		});
		else {
			if (platformSendStarted) await markQueuedPlatformOutcomeUnknown({
				queueId,
				queuePolicy
			});
			if (await ackDelivery(queueId).then(() => true).catch((err) => {
				if (queuePolicy === "required") throw err;
				log.warn(`failed to ack queued delivery ${queueId}; continuing best-effort delivery: ${formatErrorMessage(err)}`);
				return false;
			})) await runOutboundDeliveryCommitHooks(results);
		}
		return results;
	} catch (err) {
		if (queueId) {
			if (isDeliveryAbortError(err)) await ackDelivery(queueId).catch(() => {});
			else if (!platformResultsReturned) await failDelivery(queueId, formatErrorMessage(err)).catch((failErr) => {
				log.warn(`failed to mark queued delivery ${queueId} as failed: ${formatErrorMessage(failErr)}`);
			});
		}
		throw err;
	}
}
/** Core delivery logic (extracted for queue wrapper). */
async function deliverOutboundPayloadsCore(params) {
	const { cfg, channel, to, payloads } = params;
	const directiveOptions = await resolveChannelOutboundDirectiveOptions({
		cfg,
		channel
	});
	const outboundPayloadPlan = createOutboundPayloadPlan(payloads, {
		cfg,
		sessionKey: params.session?.policyKey ?? params.session?.key,
		surface: channel,
		conversationType: params.session?.conversationType,
		extractMarkdownImages: directiveOptions.extractMarkdownImages
	});
	const accountId = params.accountId;
	const deps = params.deps;
	const abortSignal = params.abortSignal;
	const resolveMediaAccess = (mediaSources) => mediaSources.length > 0 ? resolveAgentScopedOutboundMediaAccess({
		cfg,
		agentId: params.session?.agentId ?? params.mirror?.agentId,
		mediaSources,
		mediaAccess: params.mediaAccess,
		sessionKey: params.session?.key,
		messageProvider: params.session?.key ? void 0 : channel,
		accountId: params.session?.requesterAccountId ?? accountId,
		requesterSenderId: params.session?.requesterSenderId,
		requesterSenderName: params.session?.requesterSenderName,
		requesterSenderUsername: params.session?.requesterSenderUsername,
		requesterSenderE164: params.session?.requesterSenderE164
	}) : params.mediaAccess ?? {};
	const createHandler = (mediaSources) => createChannelHandler({
		cfg,
		channel,
		to,
		deps,
		accountId,
		replyToId: params.replyToId,
		replyToMode: params.replyToMode,
		formatting: params.formatting,
		threadId: params.threadId,
		identity: params.identity,
		gifPlayback: params.gifPlayback,
		forceDocument: params.forceDocument,
		silent: params.silent,
		mediaAccess: resolveMediaAccess(mediaSources),
		gatewayClientScopes: params.gatewayClientScopes,
		...params.onPlatformSendStart ? { onPlatformSendStart: params.onPlatformSendStart } : {}
	});
	const baseHandler = await createHandler([]);
	const handlerByMediaSources = /* @__PURE__ */ new Map();
	const getDeliveryHandler = (mediaSources) => {
		if (mediaSources.length === 0) return Promise.resolve(baseHandler);
		const key = JSON.stringify(mediaSources);
		const cached = handlerByMediaSources.get(key);
		if (cached) return cached;
		const created = createHandler(mediaSources);
		handlerByMediaSources.set(key, created);
		return created;
	};
	const results = [];
	const handler = baseHandler;
	const configuredTextLimit = handler.chunker ? resolveTextChunkLimit(cfg, channel, accountId, { fallbackLimit: handler.textChunkLimit }) : void 0;
	const textLimit = params.formatting?.textLimit ?? (handler.resolveEffectiveTextChunkLimit ? handler.resolveEffectiveTextChunkLimit(configuredTextLimit) : configuredTextLimit);
	const chunkMode = handler.chunker ? params.formatting?.chunkMode ?? resolveChunkMode(cfg, channel, accountId) : "length";
	const { resolveCurrentReplyTo, applyReplyToConsumption } = createReplyToDeliveryPolicy({
		replyToId: params.replyToId,
		replyToMode: params.replyToMode
	});
	const sendTextChunks = async (sendHandler, text, overrides = {}) => {
		const units = planOutboundTextMessageUnits({
			text,
			overrides,
			chunker: sendHandler.chunker,
			chunkerMode: sendHandler.chunkerMode,
			chunkedTextFormatting: sendHandler.chunkedTextFormatting,
			textLimit,
			chunkMode,
			formatting: params.formatting,
			consumeReplyTo: (value) => applyReplyToConsumption(value, { consumeImplicitReply: value.replyToIdSource === "implicit" })
		});
		for (const unit of units) {
			if (unit.kind !== "text") continue;
			throwIfAborted(abortSignal);
			results.push(await sendHandler.sendText(unit.text, unit.overrides));
		}
	};
	const normalizedPayloads = normalizePayloadsForChannelDelivery(outboundPayloadPlan, handler);
	const payloadOutcomes = [];
	const recordPayloadOutcome = (outcome) => {
		payloadOutcomes.push(outcome);
		params.onPayloadDeliveryOutcome?.(outcome);
	};
	if (normalizedPayloads.length === 0 && payloads.length > 0) payloads.forEach((_payload, index) => {
		recordPayloadOutcome(suppressedPayloadOutcome({
			index,
			reason: "no_visible_payload"
		}));
	});
	const deliveredMirrorPayloads = [];
	const recordDeliveredMirrorPayload = (payloadSummary, deliveredResults) => {
		if (!params.mirror || !params.replyPayloadSendingHook || deliveredResults.length === 0) return;
		deliveredMirrorPayloads.push(payloadSummary);
	};
	const hookRunner = getGlobalHookRunner();
	const sessionKeyForInternalHooks = params.mirror?.sessionKey ?? params.session?.key;
	const mirrorIsGroup = params.mirror?.isGroup;
	const mirrorGroupId = params.mirror?.groupId;
	const { emitMessageSent, hasMessageSentHooks } = createMessageSentEmitter({
		hookRunner,
		channel,
		to,
		accountId,
		sessionKeyForInternalHooks,
		mirrorIsGroup,
		mirrorGroupId
	});
	const hasMessageSendingHooks = hookRunner?.hasHooks("message_sending") ?? false;
	const diagnosticSessionKey = sessionKeyForDeliveryDiagnostics(params);
	if (hasMessageSentHooks && params.session?.agentId && !sessionKeyForInternalHooks) log.warn("deliverOutboundPayloads: session.agentId present without session key; internal message:sent hook will be skipped", {
		channel,
		to,
		agentId: params.session.agentId
	});
	for (const { index: payloadIndex, payload } of normalizedPayloads) {
		let payloadSummary = buildPayloadSummary(payload);
		let deliveryKind = "other";
		let deliveryStartedAt = 0;
		let deliveryStarted = false;
		let deliveryFinished = false;
		const startDeliveryDiagnostics = (kind) => {
			deliveryKind = kind;
			deliveryStartedAt = Date.now();
			deliveryStarted = true;
			deliveryFinished = false;
			emitMessageDeliveryStarted({
				channel,
				deliveryKind,
				sessionKey: diagnosticSessionKey
			});
		};
		const completeDeliveryDiagnostics = (resultCount) => {
			if (!deliveryStarted) return;
			deliveryFinished = true;
			emitMessageDeliveryCompleted({
				channel,
				deliveryKind,
				durationMs: Date.now() - deliveryStartedAt,
				resultCount,
				sessionKey: diagnosticSessionKey
			});
		};
		const errorDeliveryDiagnostics = (err) => {
			if (!deliveryStarted || deliveryFinished) return;
			deliveryFinished = true;
			emitMessageDeliveryError({
				channel,
				deliveryKind,
				durationMs: Date.now() - deliveryStartedAt,
				error: err,
				sessionKey: diagnosticSessionKey
			});
		};
		try {
			throwIfAborted(abortSignal);
			const replyHookResult = await applyReplyPayloadSendingHook({
				hook: params.replyPayloadSendingHook,
				payload
			});
			if (replyHookResult.cancelled) {
				recordPayloadOutcome(suppressedPayloadOutcome({
					index: payloadIndex,
					reason: "cancelled_by_reply_payload_sending_hook"
				}));
				continue;
			}
			let deliveryPayload = replyHookResult.payload;
			payloadSummary = buildPayloadSummary(deliveryPayload);
			const hookResult = await applyMessageSendingHook({
				hookRunner,
				enabled: hasMessageSendingHooks,
				payload: deliveryPayload,
				payloadSummary,
				to,
				channel,
				accountId,
				replyToId: resolveCurrentReplyTo(deliveryPayload).replyToId,
				threadId: params.threadId,
				sessionKey: sessionKeyForInternalHooks
			});
			if (hookResult.cancelled) {
				const hookEffect = hookResult.cancelReason || hookResult.hookMetadata ? {
					...hookResult.cancelReason ? { cancelReason: hookResult.cancelReason } : {},
					...hookResult.hookMetadata ? { metadata: hookResult.hookMetadata } : {}
				} : void 0;
				recordPayloadOutcome(suppressedPayloadOutcome({
					index: payloadIndex,
					reason: "cancelled_by_message_sending_hook",
					...hookEffect ? { hookEffect } : {}
				}));
				continue;
			}
			deliveryPayload = hookResult.payload;
			const renderedPayload = stripInternalRuntimeScaffoldingFromPayload(await renderPresentationForDelivery(await getDeliveryHandler(buildPayloadSummary(deliveryPayload).mediaUrls), deliveryPayload));
			const renderedHandler = await getDeliveryHandler(buildPayloadSummary(renderedPayload).mediaUrls);
			const normalizedEffectivePayload = renderedHandler.normalizePayload ? renderedHandler.normalizePayload(renderedPayload) : renderedPayload;
			const effectivePayload = normalizedEffectivePayload ? normalizeEmptyPayloadForDelivery(stripInternalRuntimeScaffoldingFromPayload(normalizedEffectivePayload)) : null;
			if (!effectivePayload) {
				recordPayloadOutcome(suppressedPayloadOutcome({
					index: payloadIndex,
					reason: hookResult.contentRewritten ? "empty_after_message_sending_hook" : replyHookResult.changed ? "empty_after_reply_payload_sending_hook" : "no_visible_payload"
				}));
				continue;
			}
			payloadSummary = buildPayloadSummary(effectivePayload);
			const deliveryHandler = await getDeliveryHandler(payloadSummary.mediaUrls);
			startDeliveryDiagnostics(deliveryKindForPayload(effectivePayload, payloadSummary));
			params.onPayload?.(payloadSummary);
			const replyToResolution = resolveCurrentReplyTo(effectivePayload);
			const sendOverrides = {
				replyToId: replyToResolution.replyToId,
				replyToIdSource: replyToResolution.source,
				...params.threadId !== void 0 ? { threadId: params.threadId } : {},
				...effectivePayload.audioAsVoice === true ? { audioAsVoice: true } : {},
				...params.forceDocument !== void 0 ? { forceDocument: params.forceDocument } : {}
			};
			const applySendReplyToConsumption = (overrides) => applyReplyToConsumption(overrides, { consumeImplicitReply: replyToResolution.source === "implicit" });
			const deliveryTarget = deliveryHandler.buildTargetRef({ threadId: sendOverrides.threadId });
			if (deliveryHandler.sendPayload && (effectivePayload.isError === true && deliveryHandler.sendTextOnlyErrorPayloads === true || hasReplyPayloadContent({
				presentation: effectivePayload.presentation,
				interactive: effectivePayload.interactive,
				channelData: effectivePayload.channelData
			}) || effectivePayload.audioAsVoice === true)) {
				const delivery = await deliveryHandler.sendPayload(effectivePayload, applySendReplyToConsumption(sendOverrides));
				if (!hasDeliveryResultIdentity(delivery)) {
					completeDeliveryDiagnostics(0);
					recordPayloadOutcome(suppressedPayloadOutcome({
						index: payloadIndex,
						reason: "adapter_returned_no_identity"
					}));
					continue;
				}
				results.push(delivery);
				recordPayloadOutcome({
					index: payloadIndex,
					status: "sent",
					results: [delivery]
				});
				recordDeliveredMirrorPayload(payloadSummary, [delivery]);
				await maybePinDeliveredMessage({
					handler: deliveryHandler,
					payload: effectivePayload,
					target: deliveryTarget,
					messageId: delivery.messageId,
					gatewayClientScopes: params.gatewayClientScopes
				});
				await maybeNotifyAfterDeliveredPayload({
					handler: deliveryHandler,
					payload: effectivePayload,
					target: deliveryTarget,
					results: [delivery]
				});
				completeDeliveryDiagnostics(1);
				emitMessageSent({
					success: true,
					content: payloadSummary.hookContent ?? payloadSummary.text,
					messageId: delivery.messageId
				});
				continue;
			}
			if (payloadSummary.mediaUrls.length === 0) {
				const beforeCount = results.length;
				if (deliveryHandler.sendFormattedText) results.push(...await deliveryHandler.sendFormattedText(payloadSummary.text, applySendReplyToConsumption(sendOverrides)));
				else await sendTextChunks(deliveryHandler, payloadSummary.text, sendOverrides);
				const deliveredResults = results.slice(beforeCount);
				if (deliveredResults.length > 0) {
					recordPayloadOutcome({
						index: payloadIndex,
						status: "sent",
						results: deliveredResults
					});
					recordDeliveredMirrorPayload(payloadSummary, deliveredResults);
				} else recordPayloadOutcome(suppressedPayloadOutcome({
					index: payloadIndex,
					reason: "adapter_returned_no_identity"
				}));
				const messageId = results.at(-1)?.messageId;
				const pinMessageId = deliveredResults.find((entry) => entry.messageId)?.messageId;
				await maybePinDeliveredMessage({
					handler: deliveryHandler,
					payload: effectivePayload,
					target: deliveryTarget,
					messageId: pinMessageId,
					gatewayClientScopes: params.gatewayClientScopes
				});
				await maybeNotifyAfterDeliveredPayload({
					handler: deliveryHandler,
					payload: effectivePayload,
					target: deliveryTarget,
					results: deliveredResults
				});
				completeDeliveryDiagnostics(deliveredResults.length);
				emitMessageSent({
					success: results.length > beforeCount,
					content: payloadSummary.hookContent ?? payloadSummary.text,
					messageId
				});
				continue;
			}
			if (!deliveryHandler.supportsMedia) {
				log.warn("Plugin outbound adapter does not implement sendMedia; media URLs will be dropped and text fallback will be used", {
					channel,
					to,
					mediaCount: payloadSummary.mediaUrls.length
				});
				const fallbackText = payloadSummary.text.trim();
				if (!fallbackText) throw new Error("Plugin outbound adapter does not implement sendMedia and no text fallback is available for media payload");
				const beforeCount = results.length;
				await sendTextChunks(deliveryHandler, fallbackText, sendOverrides);
				const deliveredResults = results.slice(beforeCount);
				if (deliveredResults.length > 0) {
					recordPayloadOutcome({
						index: payloadIndex,
						status: "sent",
						results: deliveredResults
					});
					recordDeliveredMirrorPayload(payloadSummary, deliveredResults);
				} else recordPayloadOutcome(suppressedPayloadOutcome({
					index: payloadIndex,
					reason: "adapter_returned_no_identity"
				}));
				const messageId = results.at(-1)?.messageId;
				const pinMessageId = deliveredResults.find((entry) => entry.messageId)?.messageId;
				await maybePinDeliveredMessage({
					handler: deliveryHandler,
					payload: effectivePayload,
					target: deliveryTarget,
					messageId: pinMessageId,
					gatewayClientScopes: params.gatewayClientScopes
				});
				await maybeNotifyAfterDeliveredPayload({
					handler: deliveryHandler,
					payload: effectivePayload,
					target: deliveryTarget,
					results: deliveredResults
				});
				completeDeliveryDiagnostics(deliveredResults.length);
				emitMessageSent({
					success: results.length > beforeCount,
					content: payloadSummary.hookContent ?? payloadSummary.text,
					messageId
				});
				continue;
			}
			let firstMessageId;
			let lastMessageId;
			const beforeCount = results.length;
			const mediaUnits = planOutboundMediaMessageUnits({
				mediaUrls: payloadSummary.mediaUrls,
				caption: payloadSummary.text,
				overrides: sendOverrides,
				consumeReplyTo: applySendReplyToConsumption
			});
			for (const unit of mediaUnits) {
				if (unit.kind !== "media") continue;
				throwIfAborted(abortSignal);
				const delivery = deliveryHandler.sendFormattedMedia ? await deliveryHandler.sendFormattedMedia(unit.caption ?? "", unit.mediaUrl, unit.overrides) : await deliveryHandler.sendMedia(unit.caption ?? "", unit.mediaUrl, unit.overrides);
				results.push(delivery);
				firstMessageId ??= delivery.messageId;
				lastMessageId = delivery.messageId;
			}
			await maybePinDeliveredMessage({
				handler: deliveryHandler,
				payload: effectivePayload,
				target: deliveryTarget,
				messageId: firstMessageId,
				gatewayClientScopes: params.gatewayClientScopes
			});
			await maybeNotifyAfterDeliveredPayload({
				handler: deliveryHandler,
				payload: effectivePayload,
				target: deliveryTarget,
				results: results.slice(beforeCount)
			});
			const deliveredResults = results.slice(beforeCount);
			if (deliveredResults.length > 0) {
				recordPayloadOutcome({
					index: payloadIndex,
					status: "sent",
					results: deliveredResults
				});
				recordDeliveredMirrorPayload(payloadSummary, deliveredResults);
			} else recordPayloadOutcome(suppressedPayloadOutcome({
				index: payloadIndex,
				reason: "adapter_returned_no_identity"
			}));
			completeDeliveryDiagnostics(results.length - beforeCount);
			emitMessageSent({
				success: true,
				content: payloadSummary.hookContent ?? payloadSummary.text,
				messageId: lastMessageId
			});
		} catch (err) {
			recordPayloadOutcome({
				index: payloadIndex,
				status: "failed",
				error: err,
				sentBeforeError: results.length > 0,
				stage: "platform_send"
			});
			errorDeliveryDiagnostics(err);
			emitMessageSent({
				success: false,
				content: payloadSummary.hookContent ?? payloadSummary.text,
				error: formatErrorMessage(err)
			});
			if (!params.bestEffort) throw toOutboundDeliveryError({
				error: err,
				results,
				payloadOutcomes,
				stage: "platform_send"
			});
			params.onError?.(err, payloadSummary);
		}
	}
	if (params.mirror && results.length > 0) {
		const deliveredMirror = deliveredMirrorPayloads.length > 0 ? {
			text: deliveredMirrorPayloads.map((payload) => payload.hookContent ?? payload.text).filter((text) => text.trim()).join("\n"),
			mediaUrls: deliveredMirrorPayloads.flatMap((payload) => payload.mediaUrls)
		} : params.mirror;
		const mirrorText = resolveMirroredTranscriptText({
			text: deliveredMirror.text,
			mediaUrls: deliveredMirror.mediaUrls
		});
		if (mirrorText) try {
			const { appendAssistantMessageToSessionTranscript } = await loadTranscriptRuntime();
			const mirrorResult = await appendAssistantMessageToSessionTranscript({
				agentId: params.mirror.agentId,
				sessionKey: params.mirror.sessionKey,
				text: mirrorText,
				idempotencyKey: params.mirror.idempotencyKey,
				config: params.cfg
			});
			if (!mirrorResult.ok) log.warn(`failed to mirror outbound delivery into session transcript; channel send already succeeded: ${mirrorResult.reason}`, {
				channel,
				to,
				sessionKey: params.mirror.sessionKey
			});
		} catch (err) {
			log.warn(`failed to mirror outbound delivery into session transcript; channel send already succeeded: ${formatErrorMessage(err)}`, {
				channel,
				to,
				sessionKey: params.mirror.sessionKey
			});
		}
	}
	return results;
}
//#endregion
export { createRenderedMessageBatch as a, throwIfAborted as i, deliverOutboundPayloadsInternal as n, runReplyPayloadSendingHook as o, resolveOutboundDurableFinalDeliverySupport as r, isOutboundDeliveryError as s, deliverOutboundPayloads as t };