openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
3,464 lines • 169 kB
JavaScript
import { o as asDateTimestampMs } from "./number-coercion-CLj0HTDM.js";
import { i as resolveGlobalSingleton } from "./global-singleton-Dc_stLtU.js";
import { c as normalizeOptionalLowercaseString, l as normalizeOptionalString, o as normalizeLowercaseStringOrEmpty } from "./string-coerce-CIXf7egm.js";
import { n as isAbortError } from "./abort-signal-D2k14JsD.js";
import { c as resolveAgentConfig, m as resolveAgentWorkspaceDir } from "./agent-scope-config-DcbEhP0R.js";
import { O as parseAgentSessionKey, P as resolveSessionDispatchKind, S as isAcpSessionKey, f as resolveAgentIdFromSessionKey } from "./session-key-BnWWjqNc.js";
import { t as formatErrorMessage } from "./errors-Db3Ymjlb.js";
import { f as isDiagnosticsEnabled } from "./diagnostic-events-Cwe92uV3.js";
import { t as createSubsystemLogger } from "./subsystem-Dy2tqXOS.js";
import { o as measureDiagnosticsTimelineSpan } from "./diagnostics-timeline-CRX1LXmg.js";
import { n as resolveGlobalDedupeCache } from "./dedupe-gst1CUro.js";
import { u as resolveToolProfilePolicy } from "./tool-policy-shared-DIyS0iQC.js";
import { a as isToolAllowedByPolicies } from "./tool-policy-match-TnFxBs5z.js";
import { l as mergeAlsoAllowPolicy } from "./tool-policy-Wi0C45cX.js";
import { o as resolveSessionStorePathCore } from "./paths-CXdaYWF_.js";
import { t as applyMergePatch } from "./merge-patch-DCMj2JVh.js";
import { _ as resolveSessionAgentId } from "./agent-scope-DbtJyKUL.js";
import { u as normalizeVerboseLevel } from "./thinking.shared-bHYuuc1L.js";
import { r as logVerbose } from "./globals-CTaGxEqj.js";
import { a as getPluginRuntimeGatewayRequestScope, f as withPluginRuntimeRegistryScope } from "./gateway-request-scope-BCMYlsDI.js";
import "./message-channel-constants-2zSoJXQC.js";
import { n as normalizeMessageChannel } from "./message-channel-core-AaEWic-A.js";
import "./message-channel-BQrhwUEA.js";
import { r as resolveCommandAuthorization } from "./command-auth-DRYzLgCh.js";
import { H as buildConversationRef } from "./openclaw-agent-db-maintenance-wTIy-jt-.js";
import { t as normalizeChatType } from "./chat-type-CG0X_HJM.js";
import { i as shouldCleanTtsDirectiveText, o as normalizeTtsAutoMode } from "./tts-config-lx8wBLdc.js";
import { b as fireAndForgetHook, l as createPluginSubagentRequesterContext, n as getGlobalPluginRegistry, t as getGlobalHookRunner } from "./hook-runner-global-0kfmMG4T.js";
import { _ as readAskUserQuestionId, a as getReplyPayloadMetadata, c as isFastModeAutoProgressPayload, d as isReplyPayloadStatusNotice, i as copyReplyPayloadMetadata, s as isCommandReplyForDelivery, y as setReplyPayloadMetadata } from "./reply-payload-DahKk-7n.js";
import { n as channelRouteDedupeKey } from "./channel-route--2in3Ckg.js";
import { d as sessionDeliveryChannel } from "./delivery-context.shared-CXmRgetN.js";
import { u as readChannelContextGatewayContextResolver } from "./admission-evidence-BW_2Woj4.js";
import { o as prepareChannelParticipantObservation } from "./ingress-drain-DcmwOHP5.js";
import { _ as stripLegacyMediaContextFields } from "./media-facts-8Sl_nPCc.js";
import { f as preparePersistedUserTurnMessageForTranscriptWrite, i as buildPersistedUserTurnMessage, u as buildChannelUserTurnSender } from "./user-turn-transcript.message-LcwHBB2I.js";
import { Ct as appendTranscriptEventSync } from "./session-accessor-YsytfDtG.js";
import { P as redactTranscriptMessage } from "./session-accessor.sqlite-transcript-store-B0zw3fAU.js";
import { d as patchSessionEntryCore, u as loadSessionEntryReadOnly } from "./session-accessor.sqlite-entry-CWk3jL7s.js";
import { a as normalizeChannelId, t as getChannelPlugin } from "./registry-Cz6cv4VC.js";
import { r as resolveGroupSessionKey } from "./group-DlTf9maP.js";
import { K as conversationIdentityFromMsgContext } from "./session-accessor.sqlite-entry-store-BxYl0nro.js";
import { h as runExclusiveSessionLifecycleMutation } from "./session-lifecycle-admission-CS8v45tk.js";
import "./thinking-DterdXhr.js";
import { t as isParentOwnedBackgroundAcpSession } from "./session-interaction-mode-DcV9yxfP.js";
import { n as classifySessionStateActor } from "./session-state-events-DNCKmH78.js";
import { n as GENERIC_EXTERNAL_RUN_FAILURE_TEXT } from "./user-copy-CxiPNpae.js";
import { a as isNativeCommandTurn, c as resolveCommandTurnContext, l as resolveCommandTurnTargetSessionKey } from "./command-turn-context-CmPEYNmV.js";
import { t as getSessionBindingService } from "./session-binding-service-DTXs8JDw.js";
import { n as isPluginOwnedSessionBindingRecord } from "./conversation-binding-metadata-CFOhDjMh.js";
import { i as buildPluginBindingErrorText, l as hasShownPluginBindingFallbackNotice, m as toPluginConversationBinding, o as buildPluginBindingUnavailableText, r as buildPluginBindingDeclinedText, u as markPluginBindingFallbackNoticeShown } from "./conversation-binding-DNzZGFgH.js";
import { i as resolveTextCommand, r as normalizeCommandBody } from "./commands-registry-normalize-Bugd8r0v.js";
import { a as isUnauthorizedTextSlashCommand, n as isExplicitSourceReplyCommand, s as resolveSourceReplyVisibilityPolicy, t as isDirectedSourceReplyTurn } from "./source-reply-delivery-mode-Ct9PBal_.js";
import { n as readAcpSessionEntry } from "./session-meta-dzG4VkYo.js";
import { U as waitForReplyBarrierSettlement, h as replyRunRegistry, o as forceClearReplyRunBySessionId } from "./reply-run-registry.registry-BMo0d96L.js";
import "./reply-run-registry-BlmBKV23.js";
import { f as markDiagnosticSessionProgress, n as logMessageDispatchStarted, t as logMessageDispatchCompleted } from "./diagnostic-ryAZMr5N.js";
import { i as resolveActiveEmbeddedRunSessionId } from "./active-run-projections-C4mdt8WG.js";
import { l as isRestartRecoveryTombstone, u as isSessionWorkStartInvalidatedError } from "./lifecycle-BaroCBMc.js";
import { r as normalizeExplicitSessionKey } from "./session-key-CwhWkrL5.js";
import { t as appendAssistantMessageToSessionTranscript } from "./transcript-Dv8-hmIo.js";
import { r as isFinalizedInboundContext, t as finalizeInboundContext } from "./inbound-context-BJXKd4x8.js";
import { f as markConversationDeliveryReplied, l as findConversationTurnDeliveryByReplyTarget, p as markConversationDeliverySent } from "./delivery-completion-BrAAYzVK.js";
import { i as extractShortModelName } from "./normalize-reply-C1iRjnEc.js";
import { l as ReplyDispatchDeliveryError, n as bindReplyDispatcherConversationContext, o as prepareReplyPayloadForDispatcher, r as captureReplyDispatchDeliveryOutcome, s as waitForReplyDispatcherIdle, t as attachReplyDispatchUndeliveredFallback } from "./reply-dispatcher-BjdCLv_G.js";
import { n as resolveAgentIdentity } from "./identity-L3YWE18q.js";
import { a as toInternalMessageReceivedContext, c as toPluginInboundClaimPair, l as toPluginMessageContext, n as deriveInboundMessageHookContext, u as toPluginMessageReceivedEvent } from "./message-hook-mappers-oV7hnRsq.js";
import { a as hasOutboundReplyContent } from "./reply-payload-Bfsi665c.js";
import { a as resolveSendableOutboundReplyParts } from "./reply-payload-parts-BsFA4sDv.js";
import { s as resolveSubagentCapabilityStore, t as isSubagentEnvelopeSession } from "./subagent-capabilities-Cd0-4jrx.js";
import { a as resolveSubagentToolPolicyForSession, i as resolveInheritedToolPolicyForSession, n as resolveEffectiveToolPolicy, r as resolveGroupToolPolicy } from "./agent-tools.policy-NF_9Y4S4.js";
import { a as resolveReplyDeliveryAccountId, o as resolveReplyToMode, t as createReplyDeliveryContext } from "./reply-threading-b8mBrrsZ.js";
import { a as isCaptionedFinalTextPayload, c as DispatchReplyOperationAbortedError, d as runWithDispatchAbortSignal, f as registerReplyDispatcherSettledTask, i as cleanDeferredFinalText, l as createAbortAwareDispatcher, o as mergeDeferredFinalText, r as buildCaptionedFinalTextFallback, s as shouldDeferFinalTtsText, t as finalizeDispatchAndAudit, u as isDispatchReplyOperationAbortedError } from "./dispatch-from-config.finalize-DcagE2ge.js";
import { n as hasTrustedMessageAuditListeners, t as emitTrustedMessageAuditEvent } from "./message-audit-events-DGtoPYvb.js";
import { t as createTtsDirectiveTextStreamCleaner } from "./directives-EQrayC82.js";
import { a as admitReplyTurn, i as isReplyProfilerEnabled, o as resolveReplyTurnKind, r as createReplyTimingTracker, s as runWithReplyOperationLifecycleAdmission, u as resolveSilentReplyPolicyFromPolicies } from "./session-entry-handle-DbGQ7dok.js";
import { i as resolveTurnCommentaryProgressOwner, n as reserveReplyAdmissionTicket, o as isDuplicateRestartRecoverySource, p as buildTerminalAgentRunFailureReplyPayload, r as shouldBridgeCliPreambleEvents, t as REPLY_ADMISSION_TICKET, v as renderPostCompactionModelFailurePayload } from "./reply-admission-ticket-BvAkCgpI.js";
import { c as hasExecApprovalUnavailablePayload, d as shouldDeliverDespiteSourceReplySuppression, i as createFinalizationAwareTtsPayloadApplier, l as prepareReplyPayloadForSideEffects, o as hasAskUserPayload, p as createBlockReplyContentKey, s as hasExecApprovalPayload, u as requiresDurableToolResultDelivery } from "./dispatch-from-config.payloads-D95ct5gu.js";
import { n as suppressPendingFinalDelivery } from "./dispatch-from-config.pending-final-DOlooYOM.js";
import { n as runAgentHarnessBeforeMessageWriteHook } from "./hook-helpers-3JS9XC0_.js";
import { v as isDispatchFinalReplySessionWriterAuthorized } from "./delivery-queue-recovery-CeXGRhn8.js";
import { E as isAskUserPromptPending } from "./openclaw-tools-CNOZOjlX.js";
import { f as normalizeAgentPlanSteps, s as formatPlanChecklistLines } from "./streaming-B_uLiLJZ.js";
import { o as takeCommandSessionMetadataChanges } from "./commands-goal-B_2zXG79.js";
import { d as resolveAuthorizedSessionResetCommand, f as canReplaceRestartTombstoneFromParent, l as withFullRuntimeReplyConfig, m as bindPreparedReplyDispatchRuntime, t as resolveRunTypingPolicy, u as stageRemoteInboundMediaIfNeeded } from "./typing-policy-tkvEtNc0.js";
import { i as resolveReplyOperationRunState, t as REPLY_OPERATION_RUN_STATE } from "./reply-operation-run-state-B5ZoFcCR.js";
import { t as createDiagnosticMessageLifecycle } from "./message-lifecycle-Dyi3ORkw.js";
import { i as resolveConversationBindingContextFromMessage } from "./conversation-binding-input-BzjT8SWv.js";
import { n as createInternalHookEvent, u as triggerInternalHook } from "./internal-hooks-Dgwjgwuj.js";
import { a as resolveVisibleRepliesPolicy, i as resolveTurnModelOverride, n as resolveStableMessageToolAvailability, o as loadSessionStoreEntry, r as createShouldEmitVerboseProgress } from "./session-stable-reply-mode-DAiyuiQr.js";
import { n as resolveRoutedDeliveryThreadId, t as isSlackDirectRoutedThreadTurn } from "./routed-delivery-thread-D8RIfcVU.js";
import "./user-turn-transcript-DDGwFDzp.js";
import { n as resolveSessionModelRef } from "./session-model-ref-CPZiclLt.js";
import { t as isRecoverableTerminalSessionStatus } from "./terminal-status-Z4Z1U4Xa.js";
import { n as prepareSessionWorkerPlacementMutationCheck, o as resolveWorkerPlacementArchiveRestoreError } from "./session-placement-lifecycle-7DQHpaT9.js";
import { n as shouldHandleTextCommands } from "./commands-text-routing-sBs1BOcS.js";
import { a as isActiveRunSafeCommandTurn, r as findCommandByNativeName } from "./commands-registry-zRoXYk7P.js";
import { a as loadReplyMediaPathsRuntime, i as loadPreparedModelRuntime, n as loadFastApproveRuntime, o as loadRouteReplyRuntime, r as loadGetReplyFromConfigRuntime, s as loadRuntimePlugins, t as loadAbortRuntime } from "./dispatch-from-config.runtime.js";
import { n as resolveEffectiveReplyRoute } from "./effective-reply-route-BeVh8uZJ.js";
import { t as hasInboundAudio } from "./inbound-media-Bq3xonSo.js";
import { n as resolveSendPolicy } from "./send-policy-CO-YZiTT.js";
import { n as claimPendingConversationTurnReply } from "./conversation-turns-CDPTWpv9.js";
import { t as resolveOriginMessageProvider } from "./origin-routing-CgwQQ0I7.js";
import { i as setChannelSourceTurnId, n as readChannelSourceTurnId, o as shouldMintChannelSourceTurnId, t as buildChannelSourceTurnId } from "./source-turn-id-6iBUXSKV.js";
import { t as getGatewayNativeApprovalRuntime } from "./approval-gateway-runtime-context-BSAo6TQe.js";
import { r as hasActiveApprovalNativeRouteRuntime } from "./approval-native-route-coordinator-dwijzZNW.js";
import { i as PLUGIN_COMMAND_DISPATCH, r as matchPluginCommandInvocation, t as createPluginCommandRuntime } from "./plugin-command-runtime-do7b4BK-.js";
import { n as resolveCommandChannel } from "./commands-context-CzCiQCus.js";
import { n as resolveCommandContextText } from "./context-text-D3m6Fy9M.js";
import { AsyncLocalStorage } from "node:async_hooks";
import crypto from "node:crypto";
//#region src/auto-reply/reply/dispatch-from-config.audit.ts
function resolveCompletedInboundAuditReason(reason) {
switch (reason) {
case "fast_abort": return "fast_abort";
case "plugin-bound-handled": return "plugin_bound_handled";
case "plugin-bound-fallback-missing-plugin":
case "plugin-bound-fallback-no-handler": return "plugin_bound_unavailable";
case "plugin-bound-declined": return "plugin_bound_declined";
case "before_dispatch_handled": return "before_dispatch_handled";
case "acp_dispatch": return "acp_dispatch_completed";
case "acp_empty_prompt": return "acp_dispatch_empty";
case "active_run_injected": return "active_run_injected";
default: return;
}
}
function resolveSkippedInboundAuditReason(reason) {
switch (reason) {
case "duplicate": return "duplicate";
case "reply-operation-active": return "reply_operation_active";
case "reply_operation_aborted": return "reply_operation_aborted";
default: return;
}
}
function resolveInboundMessageAuditTerminal(outcome, reason) {
if (reason === "plugin-bound-error") return {
status: "failed",
outcome: "failed",
errorCode: "message_processing_failed",
reasonCode: "plugin_bound_error"
};
if (reason?.startsWith("acp_error:")) return {
status: "failed",
outcome: "failed",
errorCode: "message_processing_failed",
reasonCode: "acp_dispatch_failed"
};
if (reason === "reply_operation_aborted") return {
status: "blocked",
outcome: "skipped",
reasonCode: "reply_operation_aborted"
};
if (reason === "acp_aborted") return {
status: "blocked",
outcome: "skipped",
reasonCode: "acp_dispatch_aborted"
};
if (outcome === "completed") {
const reasonCode = resolveCompletedInboundAuditReason(reason);
return {
status: "succeeded",
outcome: "completed",
...reasonCode ? { reasonCode } : {}
};
}
if (outcome === "skipped") {
const reasonCode = resolveSkippedInboundAuditReason(reason);
return {
status: "blocked",
outcome: "skipped",
...reasonCode ? { reasonCode } : {}
};
}
return {
status: "failed",
outcome: "failed",
errorCode: "message_processing_failed"
};
}
function emitInboundMessageAuditTerminal(params) {
const { ctx, cfg } = params;
const occurredAt = Date.now();
const sessionKey = normalizeOptionalString(ctx.SessionKey) ?? normalizeOptionalString(ctx.CommandTargetSessionKey);
const actorId = normalizeOptionalString(ctx.SenderId);
const accountId = normalizeOptionalString(ctx.AccountId);
const conversationId = normalizeOptionalString(ctx.NativeChannelId) ?? normalizeOptionalString(ctx.OriginatingTo) ?? normalizeOptionalString(ctx.To) ?? normalizeOptionalString(ctx.From);
const messageId = normalizeOptionalString(ctx.MessageSidFull) ?? normalizeOptionalString(ctx.MessageSid) ?? normalizeOptionalString(ctx.MessageSidFirst) ?? normalizeOptionalString(ctx.MessageSidLast);
const terminalFields = resolveInboundMessageAuditTerminal(params.terminal.outcome, params.terminal.options?.reason);
let agentId = normalizeOptionalString(ctx.AgentId);
try {
agentId = resolveSessionAgentId({
sessionKey,
config: cfg,
agentId: ctx.AgentId
});
} catch {}
try {
emitTrustedMessageAuditEvent({
occurredAt,
kind: "message",
action: "message.inbound.processed",
...terminalFields,
actorType: actorId ? "channel_sender" : "system",
actorId: actorId ?? "gateway",
...agentId ? { agentId } : {},
...normalizeOptionalString(params.observedRunId) ? { runId: normalizeOptionalString(params.observedRunId) } : {},
direction: "inbound",
channel: normalizeLowercaseStringOrEmpty(ctx.OriginatingChannel) || normalizeLowercaseStringOrEmpty(ctx.Surface) || normalizeLowercaseStringOrEmpty(ctx.Provider) || "unknown",
conversationKind: normalizeChatType(ctx.ChatType) ?? "unknown",
durationMs: Math.max(0, occurredAt - params.startedAt),
resultCount: params.counts.tool + params.counts.block + params.counts.final,
...accountId ? { accountId } : {},
...conversationId ? { conversationId } : {},
...messageId ? { messageId } : {}
});
} catch {}
}
/**
* Captures one terminal event for the reply-processing boundary. Channel admission and
* pre-dispatch drops remain outside this boundary and need their own ingress projection.
*/
function createInboundMessageAuditTerminal(params) {
if (!hasTrustedMessageAuditListeners()) return;
const startedAt = Date.now();
let notedTerminal;
let observedRunId = normalizeOptionalString(params.replyOptions?.runId);
let finished = false;
const emitTerminal = (terminal, counts) => {
if (finished) return;
finished = true;
emitInboundMessageAuditTerminal({
cfg: params.cfg,
counts,
ctx: params.ctx,
observedRunId,
startedAt,
terminal
});
};
return {
note(outcome, options) {
notedTerminal = {
outcome,
...options ? { options } : {}
};
},
observeRunId(runId) {
observedRunId = normalizeOptionalString(runId) ?? observedRunId;
},
finishSuccess(result) {
emitTerminal(notedTerminal ?? { outcome: "completed" }, result.counts);
},
finishError() {
let counts = {
tool: 0,
block: 0,
final: 0
};
try {
counts = params.dispatcher.getQueuedCounts();
} catch {}
emitTerminal({ outcome: "error" }, counts);
}
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.phase-state.ts
function extendPreparedDispatchState(state, values) {
return Object.assign(state, values);
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.events.ts
function admittedSessionSettingsRestrictRuntime(settings) {
return settings?.permissionMode !== void 0 && settings.permissionMode !== "full" || settings?.toolOverrides !== void 0 && Object.keys(settings.toolOverrides).length > 0;
}
function createReplyDispatchEvent(params) {
const { shouldSendToolSummaries, ...event } = params;
return Object.defineProperty(event, "shouldSendToolSummaries", {
enumerable: true,
get: shouldSendToolSummaries
});
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.restricted-runtime.ts
const RESTRICTED_RUNTIME_TAKEOVER_ERROR = "This session's bound runtime cannot enforce its permission or tool policy; use an embedded runtime for this restricted conversation.";
function runtimeTakeoverHooksAllowed(settings) {
return !admittedSessionSettingsRestrictRuntime(settings);
}
async function maybeRefuseRestrictedRuntimeTakeover(params) {
const { state } = params;
if (state.dispatchKind !== "acp" || runtimeTakeoverHooksAllowed(state.params.replyOptions?.admittedSessionSettings)) return;
const refusal = state.suppressDelivery ? {
queuedFinal: false,
routedFinalCount: 0
} : await params.sendFinalPayload({
text: RESTRICTED_RUNTIME_TAKEOVER_ERROR,
isError: true
}, {
abortSignal: state.getPreDispatchAbortSignal(),
deliveryId: "restricted-runtime-takeover"
});
const counts = state.dispatcher.getQueuedCounts();
counts.final += refusal.routedFinalCount;
state.recordProcessed("error", {
reason: "restricted_runtime_takeover",
error: RESTRICTED_RUNTIME_TAKEOVER_ERROR
});
state.markIdle("message_completed");
state.commitInboundDedupeIfClaimed();
state.completeDispatchReplyOperation();
return {
queuedFinal: refusal.queuedFinal,
counts
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.reply-dispatch-hook.ts
async function runReplyDispatchTakeover(state, shouldSendToolSummaries) {
const { hookRunner, params } = state;
if (!runtimeTakeoverHooksAllowed(params.replyOptions?.admittedSessionSettings) || !hookRunner?.hasHooks("reply_dispatch", { dispatchKind: state.dispatchKind })) return;
const result = await state.traceReplyPhase("reply.reply_dispatch_hooks", () => state.runWithDispatchLifecycleAdmission(async () => await runWithDispatchAbortSignal(state.getPreDispatchAbortSignal(), () => hookRunner.runReplyDispatch(createReplyDispatchEvent({
ctx: state.ctx,
runId: params.replyOptions?.runId,
sessionKey: state.acpDispatchSessionKey,
toolsAllow: params.replyOptions?.toolsAllow,
images: params.replyOptions?.images,
inboundAudio: state.inboundAudio,
sessionTtsAuto: state.sessionTtsAuto,
ttsChannel: state.deliveryChannel,
suppressUserDelivery: state.suppressHookUserDelivery,
suppressReplyLifecycle: state.suppressHookReplyLifecycle,
sourceReplyDeliveryMode: state.sourceReplyDeliveryMode,
shouldRouteToOriginating: state.shouldRouteToOriginating,
originatingChannel: state.routeReplyChannel,
originatingTo: state.routeReplyTo,
originatingAccountId: state.replyContextAccountId,
originatingThreadId: state.routeReplyThreadId,
originatingChatType: state.replyRoute.chatType,
shouldSendToolSummaries,
shouldSendFullToolDetails: state.shouldEmitFullVerboseProgress(),
sendPolicy: state.sendPolicy
}), {
cfg: state.cfg,
dispatchKind: state.dispatchKind,
dispatcher: state.dispatchHookDispatcher,
abortSignal: state.getPreDispatchAbortSignal() ?? params.replyOptions?.abortSignal,
onReplyStart: params.replyOptions?.onReplyStart,
onAgentRunStart: params.replyOptions?.onAgentRunStart,
userTurnTranscriptRecorder: params.replyOptions?.userTurnTranscriptRecorder,
prepareAssistantTranscriptMessage: params.replyOptions?.prepareAssistantTranscriptMessage,
recordProcessed: state.recordProcessed,
markIdle: state.markIdle
}), state.trackDispatchLifecycleWork)));
if (!result?.handled) return;
state.commitInboundDedupeIfClaimed();
state.completeDispatchReplyOperation();
return {
status: "complete",
result: state.attachSourceReplyDeliveryMode({
queuedFinal: result.queuedFinal,
counts: result.counts
})
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.session-metadata.ts
function createSessionMetadataChangeNotifier(onSessionMetadataChanges) {
const notifiedKeys = /* @__PURE__ */ new Set();
const routeState = {};
const notifySessionMetadataChanges = (changes) => {
if (!changes?.length) return;
const freshChanges = changes.filter((change) => {
const key = JSON.stringify([
change.sessionKey,
change.agentId ?? null,
change.reason
]);
if (notifiedKeys.has(key)) return false;
notifiedKeys.add(key);
return true;
});
if (freshChanges.length === 0) return;
routeState.sessionMetadataChangesForResult = [...routeState.sessionMetadataChangesForResult ?? [], ...freshChanges];
onSessionMetadataChanges?.(freshChanges);
};
return {
notifySessionMetadataChanges,
routeState
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.transcript.ts
async function mirrorDeliveredReplyToTranscript(params) {
const mirror = params.metadata;
if (!mirror || mirror.transcriptOwner) return;
try {
const result = await appendAssistantMessageToSessionTranscript({
sessionKey: mirror.sessionKey,
agentId: mirror.agentId,
...mirror.expectedSessionId ? { expectedSessionId: mirror.expectedSessionId } : {},
...mirror.expectedLifecycleRevision !== void 0 ? { expectedLifecycleRevision: mirror.expectedLifecycleRevision } : {},
...mirror.expectedWriterRunId !== void 0 ? { expectedWriterRunId: mirror.expectedWriterRunId } : {},
text: mirror.text,
mediaUrls: mirror.preferText && mirror.text ? void 0 : mirror.mediaUrls,
idempotencyKey: mirror.idempotencyKey,
...mirror.deliveryMirror ? { deliveryMirror: mirror.deliveryMirror } : {},
...mirror.storePath ? { storePath: mirror.storePath } : {},
updateMode: "inline",
config: params.cfg,
beforeMessageWrite: runAgentHarnessBeforeMessageWriteHook
});
if (!result.ok) logVerbose(`dispatch-from-config: transcript mirror skipped: ${result.reason}`);
} catch (error) {
logVerbose(`dispatch-from-config: transcript mirror failed after delivery: ${formatErrorMessage(error)}`);
}
}
function transcriptMirrorForDeliveredPayload(metadata, payload) {
const sendable = resolveSendableOutboundReplyParts(payload);
if (!sendable.text && sendable.mediaUrls.length === 0) return;
return {
...metadata,
text: sendable.text,
mediaUrls: sendable.mediaUrls.length > 0 ? sendable.mediaUrls : void 0
};
}
function captureDeliveredTranscriptMirror(params) {
if (!params.metadata || !params.dispatcher.appendBeforeDeliver) return () => params.metadata?.transcriptOwner ? void 0 : params.metadata;
const metadata = params.metadata;
let deliveredMetadata;
let observedFinal = false;
const { idempotencyKey, sessionKey } = metadata;
params.dispatcher.appendBeforeDeliver((payload, info) => {
if (info.kind !== "final") return payload;
if (getReplyPayloadMetadata(payload)?.finalDeliveryCapture !== params.captureToken) return payload;
observedFinal = true;
const payloadMirror = getReplyPayloadMetadata(payload)?.sourceReplyTranscriptMirror;
if (payloadMirror && payloadMirror.idempotencyKey === idempotencyKey && payloadMirror.sessionKey === sessionKey) deliveredMetadata = transcriptMirrorForDeliveredPayload({
...payloadMirror,
...metadata.expectedSessionId ? { expectedSessionId: metadata.expectedSessionId } : {},
...metadata.expectedLifecycleRevision !== void 0 ? { expectedLifecycleRevision: metadata.expectedLifecycleRevision } : {},
...metadata.expectedWriterRunId !== void 0 ? { expectedWriterRunId: metadata.expectedWriterRunId } : {},
storePath: metadata.storePath
}, payload);
else if (!payloadMirror && !metadata.transcriptOwner && (!idempotencyKey || metadata.deliveryMirror)) deliveredMetadata = transcriptMirrorForDeliveredPayload(metadata, payload);
return payload;
});
return () => observedFinal ? deliveredMetadata : metadata.transcriptOwner ? void 0 : metadata;
}
async function mirrorTranscriptAfterDispatcherSettled(params) {
if (await params.outcome !== "delivered") return;
const metadata = params.metadata();
if (!metadata) return;
await mirrorDeliveredReplyToTranscript({
metadata,
cfg: params.cfg
});
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.choose-route.ts
async function chooseDispatchRoute(state) {
const { acpDispatchSessionKey, attachSourceReplyDeliveryMode, cfg, commitInboundDedupeIfClaimed, completeDispatchReplyOperation, ctx, deliveryChannel, dispatcher, getPreDispatchAbortSignal, hookRunner, isRoutedReplyDelivered, markIdle, markInboundDedupeReplayUnsafe, params, recordProcessed, replyContextAccountId, replyRoute, resolvePreparedTranscriptBinding, routeReplyChannel, routeReplyThreadId, routeReplyTo, runWithDispatchLifecycleAdmission, sendPayloadAsync, sessionAgentId, sessionKey, sessionStoreEntry, sessionTtsAuto, shouldEmitVerboseProgress, shouldRouteToOriginating, traceReplyPhase, trackDispatchLifecycleWork, turnLedger } = state;
const shouldSuppressProgressDelivery = () => state.sendPolicyDenied || state.suppressDelivery && !shouldDeliverVerboseProgressDespiteSourceSuppression();
const shouldSuppressDefaultToolProgressMessages = () => params.replyOptions?.suppressToolProgressMessages === true || !shouldEmitVerboseProgress();
const shouldSendVerboseProgressMessages = () => !shouldSuppressDefaultToolProgressMessages();
const shouldSendToolSummaries = () => shouldSendVerboseProgressMessages();
const { notifySessionMetadataChanges, routeState } = createSessionMetadataChangeNotifier(params.onSessionMetadataChanges);
const shouldDeliverVerboseProgressDespiteSourceSuppression = () => state.suppressAutomaticSourceDelivery && state.sourceReplyDeliveryMode === "message_tool_only" && ctx.InboundEventKind !== "room_event" && !state.sendPolicyDenied && shouldEmitVerboseProgress() && shouldSendVerboseProgressMessages();
const shouldDeliverForcedToolProgressDespiteSourceSuppression = () => state.suppressAutomaticSourceDelivery && state.sourceReplyDeliveryMode === "message_tool_only" && ctx.InboundEventKind !== "room_event" && !state.sendPolicyDenied && params.replyOptions?.forceToolResultProgress === true;
const shouldDeliverFastModeAutoProgressDespiteSourceSuppression = () => state.suppressAutomaticSourceDelivery && state.sourceReplyDeliveryMode === "message_tool_only" && ctx.InboundEventKind !== "room_event" && !state.sendPolicyDenied;
let finalReplyDeliveryStarted = false;
const isSessionWriterDeliveryAuthorized = (payload) => isDispatchFinalReplySessionWriterAuthorized(payload, sessionStoreEntry.storePath, sessionKey);
const shouldSuppressLateTextOnlyToolProgress = (payload) => {
if (!finalReplyDeliveryStarted) return false;
return !requiresDurableToolResultDelivery(payload);
};
let pendingCommentaryProgress = null;
const deliverCommentaryProgressMessage = async (text) => {
if (!shouldSendToolSummaries() || shouldSuppressProgressDelivery()) return;
const payload = { text: `💬 ${text}` };
if (shouldSuppressLateTextOnlyToolProgress(payload)) return;
if (shouldRouteToOriginating) await sendPayloadAsync(payload, void 0, false);
else {
markInboundDedupeReplayUnsafe();
turnLedger.sendQueued("tool", payload);
}
};
const flushPendingCommentaryProgress = async () => {
const pending = pendingCommentaryProgress;
pendingCommentaryProgress = null;
const text = pending?.text.trim();
if (!text) return;
await deliverCommentaryProgressMessage(text);
};
const noteCommentaryProgress = async (payload) => {
const itemId = payload.itemId?.trim() || void 0;
const text = payload.progressText ?? "";
const repeatsBufferedText = pendingCommentaryProgress !== null && pendingCommentaryProgress.text.trim() === text.trim();
const updatesBufferedItem = pendingCommentaryProgress !== null && (pendingCommentaryProgress.itemId !== void 0 && pendingCommentaryProgress.itemId === itemId || repeatsBufferedText);
if (!text.trim()) {
if (updatesBufferedItem) pendingCommentaryProgress = null;
return;
}
if (pendingCommentaryProgress && !updatesBufferedItem) await flushPendingCommentaryProgress();
pendingCommentaryProgress = {
itemId,
text
};
};
const shouldSuppressMessageToolOnlyTextErrorProgress = (payload) => {
if (state.sourceReplyDeliveryMode !== "message_tool_only" || state.shouldEmitFullVerboseProgress() || payload.isError !== true) return false;
return !resolveSendableOutboundReplyParts(payload).hasMedia && !hasExecApprovalPayload(payload);
};
const captionedFinalTtsContext = {
cfg,
ttsAuto: sessionTtsAuto,
agentId: sessionAgentId,
channelId: deliveryChannel,
accountId: replyRoute.accountId,
inboundAudio: state.inboundAudio
};
const deferFinalTtsText = shouldDeferFinalTtsText(captionedFinalTtsContext);
const cleanDeferredFinalDirectives = shouldCleanTtsDirectiveText(captionedFinalTtsContext);
const deliveredBlockContentKeys = /* @__PURE__ */ new Set();
const blockDeliveryOutcomes = /* @__PURE__ */ new Map();
const sendTrackedBlockReply = (payload) => {
const contentKey = createBlockReplyContentKey(payload);
const delivery = turnLedger.sendQueued("block", payload);
if (!delivery.queued) return false;
const outcome = delivery.outcome ?? Promise.resolve("delivered");
const outcomes = blockDeliveryOutcomes.get(contentKey);
if (outcomes) outcomes.push(outcome);
else blockDeliveryOutcomes.set(contentKey, [outcome]);
return true;
};
const recordRoutedBlockReplyDelivery = (payload, result) => {
if (result && isRoutedReplyDelivered(result)) deliveredBlockContentKeys.add(createBlockReplyContentKey(payload));
};
const wasReplyDeliveredAsBlock = async (payload, abortSignal) => {
const contentKey = createBlockReplyContentKey(payload);
if (deliveredBlockContentKeys.has(contentKey)) return true;
const outcomes = blockDeliveryOutcomes.get(contentKey);
if (!outcomes) return false;
blockDeliveryOutcomes.delete(contentKey);
const settlement = Promise.all(outcomes).then((settledOutcomes) => ({
kind: "settled",
outcomes: settledOutcomes
}));
if (abortSignal?.aborted) return false;
let removeAbortListener;
const result = abortSignal ? await Promise.race([settlement, new Promise((resolve) => {
const onAbort = () => resolve({ kind: "aborted" });
abortSignal.addEventListener("abort", onAbort, { once: true });
removeAbortListener = () => abortSignal.removeEventListener("abort", onAbort);
})]).finally(() => removeAbortListener?.()) : await settlement;
if (result.kind === "aborted") return false;
const delivered = result.outcomes.some((outcome) => outcome === "delivered");
if (delivered) deliveredBlockContentKeys.add(contentKey);
return delivered;
};
const sendFinalPayload = async (inputPayload, options = {}) => {
const abortSignal = options.abortSignal === false ? void 0 : options.abortSignal ?? state.getDispatchAbortSignal();
const throwIfFinalDeliveryAborted = () => {
if (abortSignal?.aborted) throw new DispatchReplyOperationAbortedError();
};
throwIfFinalDeliveryAborted();
await flushPendingCommentaryProgress();
throwIfFinalDeliveryAborted();
const preparation = prepareReplyPayloadForDispatcher(dispatcher, "final", inputPayload);
if (preparation.kind === "suppress") {
await suppressPendingFinalDelivery(inputPayload);
return {
queuedFinal: false,
routedFinalCount: 0,
suppressionReason: preparation.reason
};
}
const payload = renderPostCompactionModelFailurePayload(preparation.payload);
const payloadMetadata = getReplyPayloadMetadata(payload);
const expectedWriterRunId = normalizeOptionalString(params.replyOptions?.runId);
const expectedLifecycleRevision = sessionStoreEntry.entry?.lifecycleRevision;
const sourceReplySessionBinding = resolvePreparedTranscriptBinding(payloadMetadata?.sourceReplyTranscriptMirror?.sessionKey);
const sourceReplyTranscriptMirror = payloadMetadata?.sourceReplyTranscriptMirror ? {
...payloadMetadata.sourceReplyTranscriptMirror,
...sourceReplySessionBinding ? { expectedSessionId: sourceReplySessionBinding.sessionId } : {},
...expectedLifecycleRevision !== void 0 ? { expectedLifecycleRevision } : {},
...expectedWriterRunId ? { expectedWriterRunId } : {},
storePath: sourceReplySessionBinding?.storePath ?? sessionStoreEntry.storePath
} : void 0;
const hasTranscriptOwner = payloadMetadata?.assistantMessageIndex !== void 0 || payloadMetadata?.assistantTranscriptOwned === true;
const hasVisibleFinalContent = hasOutboundReplyContent(payload, { trimText: true });
if (hasVisibleFinalContent) {
markInboundDedupeReplayUnsafe();
finalReplyDeliveryStarted = true;
}
const shouldAttachDeferredText = deferFinalTtsText && isCaptionedFinalTextPayload(payload);
const deferredRawText = shouldAttachDeferredText ? mergeDeferredFinalText(options.deferredTtsText ?? "", payload.text) : void 0;
const ttsInputPayload = shouldAttachDeferredText ? copyReplyPayloadMetadata(payload, {
...payload,
text: deferredRawText
}) : payload;
const deferredVisibleText = shouldAttachDeferredText ? cleanDeferredFinalDirectives ? cleanDeferredFinalText(deferredRawText) : deferredRawText : void 0;
let appliedTtsPayload = payload;
if (!options.skipTts && payload.isReasoning !== true && payload.isCommentary !== true) try {
appliedTtsPayload = await state.maybeApplyTtsWithFinalizationLease({
payload: ttsInputPayload,
cfg,
channel: deliveryChannel,
kind: "final",
ttsAuto: sessionTtsAuto,
agentId: sessionAgentId,
accountId: replyRoute.accountId
});
} catch (error) {
if (!shouldAttachDeferredText) throw error;
logVerbose(`dispatch-from-config: final TTS failed: ${formatErrorMessage(error)}`);
}
const ttsPayload = shouldAttachDeferredText ? copyReplyPayloadMetadata(appliedTtsPayload, {
...appliedTtsPayload,
text: deferredVisibleText || void 0
}) : appliedTtsPayload;
throwIfFinalDeliveryAborted();
let normalizedPayload;
try {
normalizedPayload = await state.normalizeReplyMediaPayload(ttsPayload);
} catch (error) {
if (!shouldAttachDeferredText || !deferredVisibleText) throw error;
logVerbose(`dispatch-from-config: media normalization failed: ${formatErrorMessage(error)}`);
normalizedPayload = buildCaptionedFinalTextFallback(ttsPayload);
}
throwIfFinalDeliveryAborted();
const deliveredAsBlock = await wasReplyDeliveredAsBlock(payload, abortSignal);
throwIfFinalDeliveryAborted();
if (deliveredAsBlock) {
if (createBlockReplyContentKey(normalizedPayload) === createBlockReplyContentKey(payload)) return {
dedupedAgainstBlock: true,
queuedFinal: false,
routedFinalCount: 0
};
normalizedPayload = copyReplyPayloadMetadata(normalizedPayload, {
...normalizedPayload,
text: void 0
});
if (!hasOutboundReplyContent(normalizedPayload, { trimText: true })) return {
dedupedAgainstBlock: true,
queuedFinal: false,
routedFinalCount: 0
};
}
if (!isSessionWriterDeliveryAuthorized(normalizedPayload)) return {
queuedFinal: false,
routedFinalCount: 0,
sessionWriterDeliveryRevoked: true
};
const result = await state.routeReplyToOriginating(normalizedPayload, {
abortSignal,
kind: "final",
...hasTranscriptOwner ? { mirror: false } : {}
});
if (result) {
if (!result.ok) logVerbose(`dispatch-from-config: route-reply (final) failed: ${result.error ?? "unknown error"}`);
if (isRoutedReplyDelivered(result)) await mirrorDeliveredReplyToTranscript({
metadata: sourceReplyTranscriptMirror,
cfg
});
const fallbackText = deferFinalTtsText && normalizedPayload.mediaUrl ? normalizeOptionalString(normalizedPayload.text) : void 0;
if (fallbackText && !isRoutedReplyDelivered(result)) {
if (!isSessionWriterDeliveryAuthorized(normalizedPayload)) return {
queuedFinal: false,
routedFinalCount: 0,
sessionWriterDeliveryRevoked: true
};
const fallbackResult = await state.routeReplyToOriginating(copyReplyPayloadMetadata(normalizedPayload, { text: fallbackText }), {
abortSignal,
kind: "final",
...hasTranscriptOwner ? { mirror: false } : {}
});
if (fallbackResult && isRoutedReplyDelivered(fallbackResult)) {
await mirrorDeliveredReplyToTranscript({
metadata: sourceReplyTranscriptMirror,
cfg
});
return {
queuedFinal: true,
routedFinalCount: 1
};
}
}
return {
queuedFinal: result.ok,
routedFinalCount: isRoutedReplyDelivered(result) ? 1 : 0
};
}
throwIfFinalDeliveryAborted();
const transcriptMirrorSessionKey = acpDispatchSessionKey ?? sessionStoreEntry.sessionKey ?? sessionKey;
const transcriptMirrorSourceId = normalizeOptionalString(state.messageIdForHook) ?? normalizeOptionalString(params.replyOptions?.runId);
const transcriptMirrorSessionBinding = resolvePreparedTranscriptBinding(transcriptMirrorSessionKey);
const transcriptMirror = sourceReplyTranscriptMirror ?? (state.normalizedCurrentSurface === "slack" && hasVisibleFinalContent && transcriptMirrorSessionKey ? transcriptMirrorForDeliveredPayload({
sessionKey: transcriptMirrorSessionKey,
agentId: sessionAgentId,
...transcriptMirrorSessionBinding ? { expectedSessionId: transcriptMirrorSessionBinding.sessionId } : {},
...expectedLifecycleRevision !== void 0 ? { expectedLifecycleRevision } : {},
...expectedWriterRunId ? { expectedWriterRunId } : {},
storePath: transcriptMirrorSessionBinding?.storePath ?? sessionStoreEntry.storePath,
preferText: true,
...hasTranscriptOwner ? { transcriptOwner: true } : {},
idempotencyKey: transcriptMirrorSourceId ? `channel-final:${transcriptMirrorSourceId}:${options.deliveryId ?? "single"}` : void 0,
deliveryMirror: {
kind: "channel-final",
...transcriptMirrorSourceId ? { sourceMessageId: transcriptMirrorSourceId } : {}
}
}, normalizedPayload) : void 0);
if (!isSessionWriterDeliveryAuthorized(normalizedPayload)) return {
queuedFinal: false,
routedFinalCount: 0,
sessionWriterDeliveryRevoked: true
};
markInboundDedupeReplayUnsafe();
const finalDeliveryCapture = transcriptMirror ? {} : void 0;
const deliveredTranscriptMirror = transcriptMirror ? captureDeliveredTranscriptMirror({
dispatcher,
metadata: transcriptMirror,
captureToken: finalDeliveryCapture
}) : void 0;
if (finalDeliveryCapture) setReplyPayloadMetadata(normalizedPayload, { finalDeliveryCapture });
if (deferFinalTtsText && normalizedPayload.mediaUrl && normalizedPayload.text?.trim()) attachReplyDispatchUndeliveredFallback(normalizedPayload, buildCaptionedFinalTextFallback(normalizedPayload));
const { queued: queuedFinal, outcome: dispatcherOutcome } = turnLedger.sendQueued("final", normalizedPayload);
if (queuedFinal && deliveredTranscriptMirror && dispatcherOutcome) registerReplyDispatcherSettledTask(dispatcher, () => mirrorTranscriptAfterDispatcherSettled({
outcome: dispatcherOutcome,
metadata: deliveredTranscriptMirror,
cfg
}));
return {
queuedFinal,
routedFinalCount: 0,
...queuedFinal && dispatcherOutcome ? { dispatcherOutcome } : {}
};
};
if (runtimeTakeoverHooksAllowed(params.replyOptions?.admittedSessionSettings) && hookRunner?.hasHooks("before_dispatch")) {
const beforeDispatchSessionKey = sessionStoreEntry.sessionKey ?? sessionKey;
const pluginSubagentRequester = createPluginSubagentRequesterContext({
sessionKey: beforeDispatchSessionKey,
origin: {
channel: routeReplyChannel,
to: routeReplyTo,
accountId: replyContextAccountId,
threadId: routeReplyThreadId
}
});
const beforeDispatchResult = await traceReplyPhase("reply.before_dispatch_hooks", () => runWithDispatchLifecycleAdmission(async () => await runWithDispatchAbortSignal(getPreDispatchAbortSignal(), () => hookRunner.runBeforeDispatch({
messageId: state.hookState.hookContext.messageId,
content: state.hookState.hookContext.content,
body: state.hookState.hookContext.bodyForAgent ?? state.hookState.hookContext.body,
channel: state.hookState.hookContext.channelId,
sessionKey: beforeDispatchSessionKey,
senderId: state.hookState.hookContext.senderId,
replyToId: state.hookState.hookContext.replyToId,
replyToIdFull: state.hookState.hookContext.replyToIdFull,
replyToBody: state.hookState.hookContext.replyToBody,
replyToSender: state.hookState.hookContext.replyToSender,
replyToIsQuote: state.hookState.hookContext.replyToIsQuote,
isGroup: state.hookState.hookContext.isGroup,
timestamp: state.hookState.hookContext.timestamp
}, {
messageId: state.hookState.hookContext.messageId,
channelId: state.hookState.hookContext.channelId,
accountId: state.hookState.hookContext.accountId,
conversationId: state.hookState.inboundClaimContext.conversationId,
sessionKey: beforeDispatchSessionKey,
senderId: state.hookState.hookContext.senderId,
replyToId: state.hookState.hookContext.replyToId,
replyToIdFull: state.hookState.hookContext.replyToIdFull,
replyToBody: state.hookState.hookContext.replyToBody,
replyToSender: state.hookState.hookContext.replyToSender,
replyToIsQuote: state.hookState.hookContext.replyToIsQuote
}, pluginSubagentRequester), trackDispatchLifecycleWork)));
if (beforeDispatchResult?.handled) {
const text = beforeDispatchResult.text;
let queuedFinal = false;
let routedFinalCount = 0;
if (text && !state.suppressDelivery) {
const handledReply = await sendFinalPayload({ text }, {
abortSignal: getPreDispatchAbortSignal(),
deliveryId: "before-dispatch"
});
queuedFinal = handledReply.queuedFinal;
routedFinalCount += handledReply.routedFinalCount;
}
const counts = dispatcher.getQueuedCounts();
counts.final += routedFinalCount;
recordProcessed("completed", { reason: "before_dispatch_handled" });
markIdle("message_completed");
commitInboundDedupeIfClaimed();
completeDispatchReplyOperation();
return {
status: "complete",
result: attachSourceReplyDeliveryMode({
queuedFinal,
counts
})
};
}
}
const restrictedRuntimeRefusal = await maybeRefuseRestrictedRuntimeTakeover({
state,
sendFinalPayload
});
if (restrictedRuntimeRefusal) return {
status: "complete",
result: attachSourceReplyDeliveryMode(restrictedRuntimeRefusal)
};
const replyDispatchTakeover = await runReplyDispatchTakeover(state, shouldSendToolSummaries);
if (replyDispatchTakeover) return replyDispatchTakeover;
const dispatchAcquisition = await state.ensureDispatchReplyOperation(state.activeRunSafeCommandTurn ? "command_resolution" : "dispatch");
if (dispatchAcquisition.status === "aborted") return {
status: "complete",
result: state.finishReplyOperationAbortedDispatch()
};
if (dispatchAcquisition.status === "busy") return {
status: "complete",
result: state.finishReplyOperationBusyDispatch({ dedupeDisposition: "release" })
};
return {
status: "ready",
state: extendPreparedDispatchState(state, {
shouldSuppressDefaultToolProgressMessages,
shouldSendVerboseProgressMessages,
shouldSendToolSummaries,
notifySessionMetadataChanges,
shouldDeliverVerboseProgressDespiteSourceSuppression,
shouldDeliverForcedToolProgressDespiteSourceSuppression,
shouldDeliverFastModeAutoProgressDespiteSourceSuppression,
shouldSuppressLateTextOnlyToolProgress,
flushPendingCommentaryProgress,
noteCommentaryProgress,
shouldSuppressMessageToolOnlyTextErrorProgress,
sendTrackedBlockReply,
recordRoutedBlockReplyDelivery,
wasReplyDeliveredAsBlock,
sendFinalPayload,
isSessionWriterDeliveryAuthorized,
deferFinalTtsText,
routeState
})
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.acp-tail.ts
async function handleAcpDispatchTailAfterReset(state) {
if (state.ctx.AcpDispatchTailAfterReset !== true) return;
state.ctx.AcpDispatchTailAfterReset = false;
const hookRunner = state.hookRunner;
if (admittedSessionSettingsRestrictRuntime(state.params.replyOptions?.admittedSessionSettings)) return;
if (!hookRunner?.hasHooks("reply_dispatch", { dispatchKind: state.dispatchKind })) return;
const tailDispatchResult = await state.runWithDispatchLifecycleAdmission(async () => await runWithDispatchAbortSignal(state.getDispatchAbortSignal(), () => hookRunner.runReplyDispatch(createReplyDispatchEvent({
ctx: state.ctx,
runId: state.params.replyOptions?.runId,
sessionKey: state.acpDispatchSessionKey,
toolsAllow: state.params.replyOptions?.toolsAllow,
images: state.params.replyOptions?.images,
inboundAudio: state.inboundAudio,
sessionTtsAuto: state.sessionTtsAuto,
ttsChannel: state.deliveryChannel,
suppressUserDelivery: state.suppressHookUserDelivery,
suppressReplyLifecycle: state.suppressHookReplyLifecycle,
sourceReplyDeliveryMode: state.sourceReplyDeliveryMode,
shouldRouteToOriginating: state.shouldRouteToOriginating,
originatingChannel: state.routeReplyChannel,
originatingTo: state.routeReplyTo,
originatingAccountId: state.replyContextAccountId,
originatingThreadId: state.routeReplyThreadId,
originatingChatType: state.replyRoute.chatType,
shouldSendToolSummaries: state.shouldSendToolSummaries,
shouldSendFullToolDetails: state.shouldEmitFullVerboseProgress(),
sendPolicy: state.sendPolicy,
isTailDispatch: true
}), {
cfg: state.cfg,
dispatchKind: state.dispatchKind,
dispatcher: state.dispatchHookDispatcher,
abortSignal: state.getPreDispatchAbortSignal() ?? state.params.replyOptions?.abortSignal,
onReplyStart: state.params.replyOptions?.onReplyStart,
onAgentRunStart: state.params.replyOptions?.onAgentRunStart,
userTurnTranscriptRecorder: state.params.replyOptions?.userTurnTranscriptRecorder,
prepareAssistantTranscriptMessage: state.params.replyOptions?.prepareAssistantTranscriptMessage,
recordProcessed: state.recordProcessed,
markIdle: state.markIdle
}), state.trackDispatchLifecycleWork));
if (!tailDispatchResult?.handled) return;
state.recordAgentDispatchCompleted("completed");
state.completeDispatchReplyOperation();
return {
status: "complete",
result: state.attachSourceReplyDeliveryMode({
queuedFinal: tailDispatchResult.queuedFinal,
counts: tailDispatchResult.counts,
...state.routeState.sessionMetadataChangesForResult ? { sessionMetadataChanges: state.routeState.sessionMetadataChangesForResult } : {}
})
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.deferred-final.ts
/** Sends the deferred block text when execution exits before normal finalization. */
async function flushDispatchDeferredFinalText(params) {
try {
if (!params.deferFinalTtsText || params.isHeartbeat) return false;
const deferredVisibleText = params.state.cleanBlockTtsDirectiveText ? cleanDeferredFinalText(params.state.progressState.accumulatedBlockTtsText) : params.state.progressState.accumulatedBlockText;
if (!deferredVisibleText.trim()) return false;
const fallback = await params.state.sendFinalPayload({ text: deferredVisibleText }, {
abortSignal: params.state.isDispatchOperationAborted() ? false : void 0,
skipTts: true
});
if (!fallback.queuedFinal && fallback.routedFinalCount === 0) return false;
params.state.progressState.accumulatedBlockText = "";
params.state.progressState.accumulatedBlockTtsText = "";
return true;
} catch (error) {
logVerbose(`dispatch-from-config: deferred final text fallback failed: ${formatErrorMessage(error)}`);
return false;
}
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.turn-ledger.ts
const SETTLE_QUEUED_TIMEOUT_MS = 3e4;
async function requireQueuedReplyDelivery(params) {
if (!params.delivery.queued) throw new Error("queued reply delivery failed");
const outcome = params.delivery.outcome;
if (!outcome) {
const receipt = await waitForReplyDispatcherIdle(params.dispatcher, params.abortSignal);
if (params.dispatcher.supportsSettledReceipt === true && receipt?.anyVisibleDelivered !== true) throw new Error("queued reply delivery failed");
return;
}
const settledOutcome = await runWithDispatchAbortSignal(params.abortSignal, () => outcome);
if (settledOutcome !== "delivered") throw new ReplyDispatchDeliveryError(settledOutcome);
}
function createReplyTurnLedger(dispatcher) {
let visibleDeliveries = 0;
const enqueue = (kind, payload) => {
if (kind === "tool") return dispatcher.sendToolResult(payload);
if (kind === "block") return dispatcher.sendBlockReply(payload);
return dispatcher.sendFinalReply(payload);
};
return {
sendQueued(kind, payload) {
const capture = dispatcher.supportsSettledReceipt === true ? captureReplyDispatchDeliveryOutcome(payload) : void 0;
if (!enqueue(kind, payload)) return { queued: false };
if (!capture) {
visibleDeliveries += 1;
return { queued: true };
}
if (!capture.isTracked()) return { queued: true };
return {
queued: true,
outcome: capture.promise
};
},
recordRoutedDelivery(payload, delivered) {
if (delivered && hasOutboundReplyContent(payload, { trimText: true })) visibleDeliveries += 1;
},
async settleQueued(abortSignal) {
if (abortSignal?.aborted) return "aborted";
let timedOut = false;
let timer;
const deadline = new Promise((resolve) => {
timer = setTimeout(() => {
timedOut = true;
resolve();
}, SETTLE_QUEUED_TIMEOUT_MS);
timer.unref?.();
});
let removeAbortListener;
const aborted = abortSignal ? new Promise((resolve) => {
const onAbort = () => resolve();
abortSignal.addEventListener("abort", onAbort, { once: true });
removeAbortListener = () => abortSignal.removeEventListener("abort", onAbort);
}) : void 0;
try {
const receipt = await Promise.race([
dispatcher.waitForIdle(),
deadline,
...aborted ? [aborted] : []
]);
if (abortSignal?.aborted) return "aborted";
if (timedOut) return "timed-out";
if (dispatcher.supportsSettledReceipt === true && receipt?.anyVisibleDelivered === true) visibleDeliveries += 1;
return "settled";
} finally {
if (timer) clearTimeout(timer);
removeAbortListener?.();
}
},
hasVisibleDelivery: () => visibleDeliveries > 0
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.execute.ts
async function executeDispatch(state) {
const { cfg, cleanBlockTtsDirectiveText, commentaryPayloadsEnabled, ctx, deliveryChannel, deferFinalTtsText, dispatcher, failDispatchReplyOperation, flushPendingCommentaryProgress, getAgentRunTerminalOutcome, getDispatchAbortOperation, getDispatchAbortSignal, isDispatchOperationAborted, markInboundDedupeReplayUnsafe, markProgress, maybeApplyTtsWithFinalizationLease, normalizeReplyMediaPayload, notifySessionMetadataChanges, onToolResultFromReplyOptions, params, reasoningPayloadsEnabled, replyConfig, replyRoute, resolveToolDeliveryPayload, runWithDispatchLifecycleAdmission, sendPayloadAsync, sessionAgentId, sessionTtsAuto, shouldForwardProgressCallback, shouldRouteToOriginating, shouldSuppressDefaultToolProgressMessages, trackDispatchLifecycleWork, typing, wasReplyDeliveredAsBlock, waitForPendingDirectBlockReplyDelivery, wrapProgressCallback } = state;
const replyResolver = bindPreparedReplyDispatchRuntime(params.configOverride ? void 0 : state.preparedReplyDispatchRuntime, state.replyResolver);
let deliberateSilentTerminalReply = false;
let pendingContinuation = false;
let pendingContinuationSettlement;
const releasePendingContinuation = async () => {
const settlement = pendingContinuationSettlement;
pendingContinuationSettlement = void 0;
await settlement?.settle(false);
};
let didDeliverVisiblePartialReply = false;
const flushDeferredFinalText = async () => {
const delivered = await flushDispatchDeferredFinalText({
deferFinalTtsText,
isHeartbeat: params.replyOptions?.isHeartbeat === true,
state
});
didDeliverVisiblePartialReply ||= delivered;
return delivered;
};
const replyResult = await runWithDispatchLifecycleAdmission(async () => await runWithDispatchAbortSignal(getDispatchAbortSignal(), () => state.traceReplyPhase("reply.run_reply_resolver", () => replyResolver(ctx, {
...state.getReplyOptions(),
[REPLY_OPERATION_RUN_STATE]: state.replyOperationRunState,
sourceReplyDeliveryMode: state.sourceReplyDeliveryMode,
sessionPromptSourceReplyDeliveryMode: state.sessionStableSourceReplyDeliveryMode,
...state.sourceReplyDeliveryRuntimeOptions,
onDeliberateSilentTerminalReply: () => {
deliberateSilentTerminalReply = true;
},
onPendingContinuation: (settlement) => {
pendingContinuation = true;
pendingContinuationSettlement ??= settlement;
},
onSessionMetadataChanges: notifySessionMetadataChanges,
onSessionPrepared: state.notePreparedSession,
onRunVerbosityResolved: (settings) => {
state.noteRunVerbosity(settings);
params.replyOptions?.onRunVerbosityResolved?.(settings);
},
onObservedReplyDelivery: state.markObservedReplyDelivery,
typingPolicy: typing.typingPolicy,
suppressTyping: typing.suppressTyping,
onPartialReply: deferFinalTtsText ? void 0 : wrapProgressCallback(params.replyOptions?.onPartialReply, { onVisible: (payload) => {
if (hasOutboundReplyContent(payload, { trimText: true })) didDeliverVisiblePartialReply = true;
} }),
onReasoningStream: wrapProgressCallback(params.replyOptions?.onReasoningStream),
streamReasoningInNonStreamModes: params.replyOptions?.streamReasoningInNonStreamModes,
onReasoningEnd: wrapProgressCallback(params.replyOptions?.onReasoningEnd),
onAssistantMessageStart: wrapProgressCallback(params.replyOptions?.onAssistantMessageStart),
onQueuedFollowupSettled: params.replyOptions?.onQueuedFollowupSettled ? async () => {
try {
await waitForPendingDirectBlockReplyDelivery();
} catch (error) {
try {
await params.replyOptions?.onQueuedFollowupSettled?.();
} catch (cleanupError) {
logVerbose(`dispatch-from-config: queued cleanup failed; preserving delivery error: ${formatErrorMessage(cleanupError)}`);
}
throw error;
}
await params.replyOptions?.onQueuedFollowupSettled?.();
} : void 0,
onBlockReplyQueued: wrapProgressCallback(params.replyOptions?.onBlockReplyQueued),
onToolStart: wrapProgressCallback(params.replyOptions?.onToolStart, {
allowWhenToolSummariesHidden: params.replyOptions?.allowToolLifecycleWhenProgressHidden === true,
forwardWhenSourceDeliverySuppressed: true,
requiresToolSummaryVisibility: true,
waitForDirectBlockReplyDelivery: true,
onForward: async () => {
await flushPendingCommentaryProgress();
}
}),
onItemEvent: state.onItemEvent,
commentaryProgressEnabled: state.deliverStandaloneCommentaryProgress || state.canForwardSuppressedSourceItemEvents || params.replyOptions?.commentaryProgressEnabled,
reasoningPayloadsEnabled,
commentaryPayloadsEnabled,
onCommandOutput: wrapProgressCallback(params.replyOptions?.onCommandOutput, {
forwardWhenSourceDeliverySuppressed: true,
requiresToolSummaryVisibility: true,
waitForDirectBlockReplyDelivery: true
}),
onCompactionStart: wrapProgressCallback(params.replyOptions?.onCompactionStart, {
allowWhenToolSummariesHidden: params.replyOptions?.allowToolLifecycleWhenProgressHidden === true,
forwardWhenSourceDeliverySuppressed: true,
requiresToolSummaryVisibility: true,
waitForDirectBlockReplyDelivery: true
}),
onCompactionEnd: wrapProgressCallback(params.replyOptions?.onCompactionEnd, {
allowWhenToolSummariesHidden: params.replyOptions?.allowToolLifecycleWhenProgressHidden === true,
forwardWhenSourceDeliverySuppressed: true,
requiresToolSummaryVisibility: true,
waitForDirectBlockReplyDelivery: true
}),
onToolResult: (payload) => {
state.getDispatchReplyOperation()?.recordActivity();
markProgress();
const run = async () => {
if (isDispatchOperationAborted()) return;
await waitForPendingDirectBlockReplyDelivery(getDispatchAbortOperation()?.abortSignal);
if (isDispatchOperationAborted()) return;
markInboundDedupeReplayUnsafe();
await flushPendingCommentaryProgress();
const isFastModeAutoProgress = isFastModeAutoProgressPayload(payload);
const isFastModeAutoProgressDelivery = isFastModeAutoProgress && state.shouldDeliverFastModeAutoProgressDespiteSourceSuppression();
const isForcedToolProgress = state.shouldDeliverForcedToolProgressDespiteSourceSuppression();
const forceToolResultProgress = params.replyOptions?.forceToolResultProgress === true;
const durableToolResult = requiresDurableToolResultDelivery(payload);
const requiresDurableToolResult = forceToolResultProgress && durableToolResult;
if (params.replyOptions?.suppressToolProgressMessages && !durableToolResult) return;
const toolResultProgressCallback = (isFastModeAutoProgress ? shouldForwardProgressCallback({ forwardWhenSourceDeliverySuppressed: true }) : forceToolResultProgress ? !requiresDurableToolResult && !state.shouldEmitVerboseProgress() && shouldForwardProgressCallback({ forwardWhenSourceDeliverySuppressed: true }) : state.shouldSendToolSummaries() && shouldForwardProgressCallback()) ? onToolResultFromReplyOptions : void 0;
if (toolResultProgressCallback) await toolResultProgressCallback(payload);
if (isDispatchOperationAborted()) return;
if (toolResultProgressCallback && (isFastModeAutoProgress || forceToolResultProgress)) return;
if (state.sendPolicyDenied) return;
if (state.shouldSuppressProgressDelivery() && !isFastModeAutoProgressDelivery && !isForcedToolProgress && !hasAskUserPayload(payload)) return;
const visibleToolPayload = prepareReplyPayloadForSideEffects(dispatcher, "tool", isForcedToolProgress ? payload : resolveToolDeliveryPayload(payload), state.progressState);
if (!visibleToolPayload) return;
const ttsPayload = await maybeApplyTtsWithFinalizationLease({
payload: visibleToolPayload,
cfg,
channel: deliveryChannel,
kind: "tool",
ttsAuto: sessionTtsAuto,
agentId: sessionAgentId,
accountId: replyRoute.accountId
});
const normalizedPayload = await normalizeReplyMediaPayload(ttsPayload);
const deliveryPayload = isForcedToolProgress ? normalizedPayload : resolveToolDeliveryPayload(normalizedPayload);
if (!deliveryPayload) return;
if (isDispatchOperationAborted()) return;
if (state.shouldSuppressLateTextOnlyToolProgress(deliveryPayload) && !isFastModeAutoProgressPayload(deliveryPayload) && !isForcedToolProgress) return;
if (state.shouldSuppressMessageToolOnlyTextErrorProgress(deliveryPayload)) return;
if (shouldSuppressDefaultToolProgressMessages() && !isFastModeAutoProgressPayload(deliveryPayload) && !isForcedToolProgress) {
if (!requiresDurableToolResultDelivery(deliveryPayload)) return;
}
const askUserQuestionId = readAskUserQuestionId(deliveryPayload);
if (askUserQuestionId !== void 0 && !await isAskUserPromptPending(askUserQuestionId)) return;
if (isDispatchOperationAborted()) return;
if (shouldRouteToOriginating) await sendPayloadAsync(deliveryPayload, void 0, false);
else {
const delivery = state.turnLedger.sendQueued("tool", deliveryPayload);
if (hasAskUserPayload(deliveryPayload)) await requireQueuedReplyDelivery({
delivery,
dispatcher,
abortSignal: getDispatchAbortOperation()?.abortSignal
});
}
};
return run();
},
onPlanUpdate: async (payload) => {
if (isDispatchOperationAborted()) return;
const steps = normalizeAgentPlanSteps(payload.steps);
const normalized = {
phase: payload.phase,
title: payload.title,
explanation: payload.explanation,
steps,
source: payload.source
};
markProgress();
await waitForPendingDirectBlockReplyDelivery(getDispatchAbortOperation()?.abortSignal);
if (isDispatchOperationAborted()) return;
markInboundDedupeReplayUnsafe();
if (shouldForwardProgressCallback({
forwardWhenSourceDeliverySuppressed: true,
requiresToolSummaryVisibility: true
})) await state.onPlanUpdateFromReplyOptions?.(normalized);
if (isDispatchOperationAborted()) return;
if (payload.phase !== "update" || shouldSuppressDefaultToolProgressMessages()) return;
await state.sendPlanUpdate({
explanation: normalized.explanation,
steps
});
},
onApprovalEvent: async (payload) => {
if (isDispatchOperationAborted()) return;
markProgress();
await waitForPendingDirectBlockReplyDelivery(getDispatchAbortOperation()?.abortSignal);
if (isDispatchOperationAborted()) return;
markInboundDedupeReplayUnsafe();
if (shouldForwardProgressCallback({
forwardWhenSourceDeliverySuppressed: true,
requiresToolSummaryVisibility: true
})) await state.onApprovalEventFromReplyOptions?.(payload);
},
onPatchSummary: async (payload) => {
if (isDispatchOperationAborted()) return;
markProgress();
await waitForPendingDirectBlockReplyDelivery(getDispatchAbortOperation()?.abortSignal);
if (isDispatchOperationAborted()) return;
markInboundDedupeReplayUnsafe();
if (shouldForwardProgressCallback({
forwardWhenSourceDeliverySuppressed: true,
requiresToolSummaryVisibility: true
})) await state.onPatchSummaryFromReplyOptions?.(payload);
},
onBlockReply: (inputPayload, context) => {
markProgress();
const run = async () => {
if (isDispatchOperationAborted()) return;
await flushPendingCommentaryProgress();
const independentDurableBlock = context?.deliveryIntentId !== void 0;
if (independentDurableBlock && state.suppressAcpChildUserDelivery) return;
if (state.suppressDelivery && !shouldDeliverDespiteSourceReplySuppression(inputPayload, state)) return;
if (inputPayload.isReasoning === true && !reasoningPayloadsEnabled) return;
if (inputPayload.isCommentary === true && !commentaryPayloadsEnabled) return;
const payload = prepareReplyPayloadForSideEffects(dispatcher, "block", inputPayload, state.progressState, markInboundDedupeReplayUnsafe);
if (!payload) return;
const contributesToFinalReply = !isReplyPayloadStatusNotice(payload) && !independentDurableBlock && payload.isReasoning !== true && payload.isCommentary !== true;
if (payload.text && contributesToFinalReply) {
const joinsBufferedTtsDirective = cleanBlockTtsDirectiveText?.hasBufferedDirectiveText() === true;
if (state.progressState.accumulatedBlockText.length > 0) state.progressState.accumulatedBlockText += "\n";
state.progressState.accumulatedBlockText += payload.text;
if (state.progressState.accumulatedBlockTtsText.length > 0 && !joinsBufferedTtsDirective) state.progressState.accumulatedBlockTtsText += "\n";
state.progressState.accumulatedBlockTtsText += payload.text;
state.progressState.blockCount++;
}
let visiblePayload = payload.text && cleanBlockTtsDirectiveText && contributesToFinalReply ? (() => {
const text = cleanBlockTtsDirectiveText.push(payload.text);
return copyReplyPayloadMetadata(payload, {
...payload,
text: text.trim() ? text : void 0
});
})() : payload;
if (deferFinalTtsText && contributesToFinalReply) {
if (!Boolean(visiblePayload.mediaUrl || visiblePayload.mediaUrls?.length || visiblePayload.presentation || visiblePayload.interactive || visiblePayload.channelData)) return;
visiblePayload = copyReplyPayloadMetadata(visiblePayload, {
...visiblePayload,
text: void 0
});
}
if (!hasOutboundReplyContent(visiblePayload, { trimText: true })) return;
const payloadMetadata = getReplyPayloadMetadata(payload);
const queuedContext = payloadMetadata?.assistantMessageIndex !== void 0 ? {
...context,
assistantMessageIndex: payloadMetadata.assistantMessageIndex
} : context;
if (isDispatchOperationAborted()) return;
const ttsPayload = payload.isReasoning === true || payload.isCommentary === true ? visiblePayload : await maybeApplyTtsWithFinalizationLease({
payload: visiblePayload,
cfg,
channel: deliveryChannel,
kind: "block",
ttsAuto: sessionTtsAuto,
agentId: sessionAgentId,
accountId: replyRoute.accountId
});
const normalizedPayload = await normalizeReplyMediaPayload(ttsPayload);
if (isDispatchOperationAborted()) return;
if (shouldRouteToOriginating || independentDurableBlock && state.canRouteDurableBlockReply) {
const result = await sendPayloadAsync(normalizedPayload, context?.abortSignal, false, "block", context?.deliveryIntentId);
state.recordRoutedBlockReplyDelivery(normalizedPayload, result);
if (result?.delivered === true && !state.suppressAutomaticSourceDelivery) await params.replyOptions?.onBlockReplyQueued?.(visiblePayload, queuedContext);
} else {
markInboundDedupeReplayUnsafe();
const admitted = state.sendTrackedBlockReply(normalizedPayload);
if (admitted) {
const pending = dispatcher.waitForIdle().then(() => void 0);
pending.catch(() => void 0);
state.progressState.pendingDirectBlockReplyDelivery = pending;
}
if (admitted && !state.suppressAutomaticSourceDelivery && params.replyOptions?.onBlockReplyQueued) trackDispatchLifecycleWork(wasReplyDeliveredAsBlock(normalizedPayload, context?.abortSignal).then(async (delivered) => {
if (delivered) await params.replyOptions?.onBlockReplyQueued?.(visiblePayload, queuedContext);
}), "delivery");
}
};
return run();
}
}, state.preparedReplyDispatchRuntime && !params.configOverride ? void 0 : replyConfig)), trackDispatchLifecycleWork)).catch(async (error) => {
await releasePendingContinuation();
await flushDeferredFinalText();
const failedAgentRun = getAgentRunTerminalOutcome() === "failed";
const adopted = state.turnAdoptionState?.adopted === true;
if (params.replyOptions?.isHeartbeat === true || !failedAgentRun && !didDeliverVisiblePartialReply && !adopted || isDispatchOperationAborted()) throw error;
failDispatchReplyOperation(error, "failed");
if (!didDeliverVisiblePartialReply) return adopted && state.noVisibleReplyFallbackDirected && !state.suppressDelivery && !state.getObservedReplyDelivery() ? {
text: GENERIC_EXTERNAL_RUN_FAILURE_TEXT,
isError: true
} : void 0;
return buildTerminalAgentRunFailureReplyPayload({
visibleReplyDelivered: true,
sessionCtx: ctx,
cfg: replyConfig
});
});
try {
if (isDispatchOperationAborted()) await flushDeferredFinalText();
notifySessionMetadataChanges(takeCommandSessionMetadataChanges(ctx));
const finalDispatchAcquisition = isCommandReplyForDelivery(replyResult) ? { status: "ready" } : await state.ensureDispatchReplyOperation("dispatch");
if (finalDispatchAcquisition.status === "aborted") return {
status: "complete",
result: state.finishReplyOperationAbortedDispatch()
};
if (finalDispatchAcquisition.status === "busy") return {
status: "complete",
result: state.finishReplyOperationBusyDispatch({
recordAgentDispatchCompleted: true,
...state.routeState.sessionMetadataChangesForResult ? { sessionMetadataChanges: state.routeState.sessionMetadataChangesForResult } : {}
})
};
const acpTailResult = await handleAcpDispatchTailAfterReset(state);
if (acpTailResult) return acpTailResult;
const nextState = extendPreparedDispatchState(state, {
deliberateSilentTerminalReply,
pendingContinuation,
pendingContinuationSettlement,
replyResult
});
pendingContinuationSettlement = void 0;
return {
status: "ready",
state: nextState
};
} finally {
await releasePendingContinuation();
}
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.context.ts
function routeThreadIdsDiffer(left, right) {
if (left === void 0 || right === void 0) return false;
return String(left) !== String(right);
}
function shouldLetSlackRoutedThreadBypassBusyReplyOperation(params) {
return isSlackDirectRoutedThreadTurn(params.ctx) && routeThreadIdsDiffer(params.activeOperation?.routeThreadId, params.routeThreadId);
}
function resolveRoutedPolicyConversationType(ctx) {
const commandTargetSessionKey = resolveCommandTurnTargetSessionKey(ctx);
if (commandTargetSessionKey && commandTargetSessionKey !== ctx.SessionKey) return;
const chatType = normalizeChatType(ctx.ChatType);
if (chatType === "direct") return "direct";
if (chatType === "group" || chatType === "channel") return "group";
}
function resolveSessionStoreLookup(ctx, cfg) {
const targetSessionKey = resolveCommandTurnTargetSessionKey(ctx);
const sessionKey = normalizeOptionalString(targetSessionKey ?? ctx.SessionKey);
if (!sessionKey) return {};
const agentId = resolveSessionAgentId({
sessionKey,
config: cfg,
fallbackAgentId: ctx.AgentId
});
const target = {
agentId,
sessionKey,
storePath: resolveSessionStorePathCore(cfg.session?.store, { agentId })
};
try {
const entry = loadSessionStoreEntry({
...target,
readConsistency: "latest",
clone: false
});
return {
...target,
entry,
store: entry ? { [sessionKey]: entry } : void 0
};
} catch {
return target;
}
}
function resolveBoundAcpDispatchSessionKey(params) {
const bindingContext = resolveConversationBindingContextFromMessage({
cfg: params.cfg,
ctx: params.ctx
});
if (!bindingContext) return;
const binding = getSessionBindingService().resolveByConversation({
channel: bindingContext.channel,
accountId: bindingContext.accountId,
conversationId: bindingContext.conversationId,
...bindingContext.parentConversationId ? { parentConversationId: bindingContext.parentConversationId } : {}
});
const targetSessionKey = normalizeOptionalString(binding?.targetSessionKey);
if (!binding || !targetSessionKey || !isAcpSessionKey(targetSessionKey)) return;
if (isPluginOwnedSessionBindingRecord(binding)) return;
getSessionBindingService().touch(binding.bindingId, void 0, binding.conversation);
return targetSessionKey;
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.lifecycle.ts
/** Pre-dispatch session state changed before any user-visible work began. */
var DispatchSessionRefreshRequiredError = class extends Error {
constructor(cause) {
super(cause.message, { cause });
this.name = "DispatchSessionRefreshRequiredError";
}
};
async function restoreArchivedDispatchSession(params) {
const { ctx, entry, hasPluginOwnedBinding, sessionKey, storePath } = params;
if (!entry || !sessionKey || !storePath || entry.archivedAt === void 0 || isRestartRecoveryTombstone(entry) || hasPluginOwnedBinding || ctx.InboundAccessAuthorized !== true || ctx.InboundEventKind === "room_event" || isNativeCommandTurn(ctx.CommandTurn) || classifySessionStateActor({ inputProvenance: ctx.InputProvenance }).actorType !== "human") return entry;
let placementContext = params.placementContext;
if (!placementContext) try {
placementContext = (await import("./session-worker-placement-context-xPPTfC3K.js")).resolveSessionWorkerPlacementContext();
} catch {
return entry;
}
const snapshotSessionId = entry.sessionId;
const snapshotArchivedAt = entry.archivedAt;
let assertCommitAllowed;
return await runExclusiveSessionLifecycleMutation({
scope: storePath,
identities: [sessionKey, snapshotSessionId],
run: async () => await patchSessionEntryCore({
sessionKey,
storePath
}, async (currentEntry) => {
if (currentEntry.sessionId !== snapshotSessionId || currentEntry.archivedAt !== snapshotArchivedAt || isRestartRecoveryTombstone(currentEntry)) return null;
try {
const placement = currentEntry.sessionId ? placementContext.workerSessionPlacementService?.getMany([currentEntry.sessionId]).get(currentEntry.sessionId) : void 0;
if (resolveWorkerPlacementArchiveRestoreError({
context: placementContext,
key: sessionKey,
placement
})) return null;
} catch {
return null;
}
if (currentEntry.worktree) {
const { synchronizeSessionWorktreeArchive } = await import("./session-worktree-lifecycle-CIlCHB-7.js");
assertCommitAllowed = prepareSessionWorkerPlacementMutationCheck({
context: placementContext,
sessionId: currentEntry.sessionId
});
await synchronizeSessionWorktreeArchive({
archived: false,
entry: currentEntry,
scope: {
sessionKey,
storePath
},
commitGuard: assertCommitAllowed
});
}
return {
archivedAt: void 0,
archivedBy: void 0,
archiveReason: void 0
};
}, { assertCommitAllowed: () => assertCommitAllowed?.() }) ?? void 0
});
}
function resolveDispatchResetAdmission(params) {
const { ctx, entry } = params;
const parentSessionKey = normalizeOptionalString(ctx.ParentSessionKey);
const commandTarget = resolveCommandTurnTargetSessionKey(ctx);
const nativeCommandTarget = isNativeCommandTurn(ctx.CommandTurn) ? commandTarget : void 0;
const actorType = classifySessionStateActor({ inputProvenance: ctx.InputProvenance }).actorType;
const mayReplaceRestartTombstoneFromParent = canReplaceRestartTombstoneFromParent({
actorType,
entry,
hasParentForkSource: true,
hasPluginOwnedBinding: params.hasPluginOwnedBinding,
inboundAccessAuthorized: ctx.InboundAccessAuthorized,
inboundEventKind: ctx.InboundEventKind,
nativeCommandTarget: commandTarget,
sessionKey: params.sessionKey
});
let hasParentForkSource = false;
if (mayReplaceRestartTombstoneFromParent && parentSessionKey && parentSessionKey !== params.sessionKey && params.storePath) try {
hasParentForkSource = Boolean(loadSessionStoreEntry({
agentId: params.agentId,
storePath: params.storePath,
sessionKey: parentSessionKey,
readConsistency: "latest",
clone: false
})?.sessionId);
} catch {
hasParentForkSource = false;
}
const allowRestartTombstoneParentFork = mayReplaceRestartTombstoneFromParent && hasParentForkSource;
if (params.hasPluginOwnedBinding || entry?.pluginOwnerId !== void 0 || ctx.InboundAccessAuthorized !== true || ctx.InboundEventKind === "room_event" || nativeCommandTarget !== void 0 && nativeCommandTarget !== params.sessionKey || actorType !== "human") return {
allowRestartTombstoneParentFork,
allowRestartTombstoneReset: false,
resetTriggered: false
};
const normalizedChatType = normalizeChatType(ctx.ChatType);
const isGroup = normalizedChatType != null && normalizedChatType !== "direct" ? true : Boolean(resolveGroupSessionKey(ctx));
const { resetCommand } = resolveAuthorizedSessionResetCommand({
agentId: params.agentId,
cfg: params.cfg,
commandAuthorized: ctx.CommandAuthorized,
ctx,
isGroup
});
const resetTriggered = resetCommand.matchedResetTriggerLower !== void 0;
return {
resetTriggered,
allowRestartTombstoneParentFork,
allowRestartTombstoneReset: resetTriggered && isRestartRecoveryTombstone(entry)
};
}
function createDispatchReplyOperationCoordinator(params) {
let dispatchReplyOperation;
let dispatchAbortOperation;
let preDispatchAbortOperation;
let preDispatchLifecycleAdmission;
let preDispatchLifecycleAbortController;
let dispatchLifecycleAbortController;
let preDispatchLifecycleInterrupted = false;
let dispatchResetTriggered = false;
let allowRestartTombstoneParentFork = false;
let allowRestartTombstoneReset = false;
const dispatchLifecycleWork = {
owner: /* @__PURE__ */ new Set(),
delivery: /* @__PURE__ */ new Set()
};
const trackDispatchLifecycleWork = (work, phase = "owner") => {
if (!dispatchReplyOperation && !preDispatchLifecycleAdmission) return;
const pending = dispatchLifecycleWork[phase];
const settled = work.then(() => {}, () => {});
pending.add(settled);
settled.then(() => {
pending.delete(settled);
});
};
const waitForDispatchDelivery = async () => {
await Promise.allSettled(Array.from(dispatchLifecycleWork.delivery));
await waitForReplyDispatcherIdle(params.dispatcher);
};
const releasePreDispatchLifecycleAdmission = async (afterWorkBarrier) => {
const admission = preDispatchLifecycleAdmission;
const preDispatchAbortController = preDispatchLifecycleAbortController;
const dispatchAbortController = dispatchLifecycleAbortController;
preDispatchLifecycleAdmission = void 0;
if (!admission) return;
const pendingWork = [...dispatchLifecycleWork.owner, ...dispatchLifecycleWork.delivery];
const clearAbortControllers = () => {
if (preDispatchLifecycleAbortController === preDispatchAbortController) preDispatchLifecycleAbortController = void 0;
if (dispatchLifecycleAbortController === dispatchAbortController) dispatchLifecycleAbortController = void 0;
};
if (!afterWorkBarrier && pendingWork.length === 0) {
clearAbortControllers();
admission.release();
return;
}
try {
await Promise.allSettled(pendingWork);
if (afterWorkBarrier) await waitForReplyBarrierSettlement(afterWorkBarrier(), params.dispatcher.resolveFollowupAdmissionBarrierTimeoutPolicy?.());
} finally {
clearAbortControllers();
admission.release();
}
};
const runWithDispatchLifecycleAdmission = async (run) => {
if (dispatchReplyOperation) return await runWithReplyOperationLifecycleAdmission(dispatchReplyOperation, run);
return preDispatchLifecycleAdmission ? await preDispatchLifecycleAdmission.run(run) : await run();
};
const ensureDispatchReplyOperation = async (phase, hasPluginOwnedBinding = false) => {
if (phase === "pre_dispatch") {
params.operationSessionStoreEntry.entry = await restoreArchivedDispatchSession({
ctx: params.ctx,
entry: params.operationSessionStoreEntry.entry,
hasPluginOwnedBinding,
placementContext: params.sessionWorkerPlacementContext,
sessionKey: params.dispatchOperationSessionKey,
storePath: params.operationSessionStoreEntry.storePath
});
({resetTriggered: dispatchResetTriggered, allowRestartTombstoneParentFork, allowRestartTombstoneReset} = resolveDispatchResetAdmission({
agentId: params.agentId,
cfg: params.cfg,
ctx: params.ctx,
entry: params.operationSessionStoreEntry.entry,
hasPluginOwnedBinding,
sessionKey: params.dispatchOperationSessionKey,
storePath: params.operationSessionStoreEntry.storePath
}));
}
if (phase !== "pre_dispatch") {
await releasePreDispatchLifecycleAdmission(() => waitForReplyDispatcherIdle(params.dispatcher));
if (preDispatchLifecycleInterrupted) return { status: dispatchReplyOperation ? "aborted" : "busy" };
}
if (dispatchReplyOperation) return { status: "ready" };
if (dispatchAbortOperation && !dispatchAbortOperation.result) return dispatchReplyOperation ? { status: "ready" } : { status: "busy" };
if (phase !== "pre_dispatch" && preDispatchAbortOperation?.result && preDispatchAbortOperation.result.kind !== "completed" && !dispatchReplyOperation && params.allowActiveQueueResolution !== true) {
dispatchAbortOperation = preDispatchAbortOperation;
return { status: "busy" };
}
const dispatchOperationSessionKey = params.dispatchOperationSessionKey;
if (!dispatchOperationSessionKey) return { status: "ready" };
const operationSessionId = dispatchAbortOperation?.sessionId ?? params.operationSessionStoreEntry.entry?.sessionId ?? crypto.randomUUID();
const replyTurnKind = resolveReplyTurnKind(params.replyOptions);
const activeReplyOperation = replyRunRegistry.get(dispatchOperationSessionKey);
const activeEmbeddedSessionId = resolveActiveEmbeddedRunSessionId(dispatchOperationSessionKey);
if (replyTurnKind === "visible" && (params.replyOptions?.turnAdoptionLifecycle !== void 0 || params.allowActiveQueueResolution === true) && activeReplyOperation === void 0 && activeEmbeddedSessionId === operationSessionId) return { status: "ready" };
const allowActiveResolution = replyTurnKind === "visible" && (phase === "pre_dispatch" || phase === "command_resolution");
if (phase !== "pre_dispatch" && replyTurnKind === "visible" && (params.replyOptions?.turnAdoptionLifecycle !== void 0 || params.allowActiveQueueResolution === true) && activeReplyOperation !== void 0 && activeReplyOperation.turnKind !== "heartbeat") return { status: "ready" };
const allowSlackRoutedThreadBypass = phase !== "pre_dispatch" && shouldLetSlackRoutedThreadBypassBusyReplyOperation({
activeOperation: replyRunRegistry.get(dispatchOperationSessionKey),
ctx: params.ctx,
routeThreadId: params.routeThreadId
});
const lifecycleOnlyAbortController = allowActiveResolution || allowSlackRoutedThreadBypass ? new AbortController() : void 0;
const onLifecycleInterrupt = () => {
preDispatchLifecycleInterrupted = true;
lifecycleOnlyAbortController?.abort();
};
const admitCurrentReplyTurn = async () => {
try {
return await admitReplyTurn({
sessionKey: dispatchOperationSessionKey,
resolveGatewayContext: readChannelContextGatewayContextResolver(params.ctx) ?? getPluginRuntimeGatewayRequestScope()?.resolveGatewayContext,
sessionId: operationSessionId,
expectedSessionId: params.resolveOperationExpectedSessionId(),
expectedActiveOperation: params.initialDispatchReplyOperation,
storePath: params.operationSessionStoreEntry.storePath,
kind: replyTurnKind,
resetTriggered: dispatchResetTriggered,
allowRestartTombstoneParentFork,
allowRestartTombstoneReset,
routeThreadId: params.routeThreadId,
originatingLeafEntryId: params.replyOptions?.turnAdoptionLifecycle?.originatingLeafEntryId,
upstreamAbortSignal: params.replyOptions?.abortSignal,
waitForActive: !allowActiveResolution && !allowSlackRoutedThreadBypass,
retainLifecycleAdmissionOnActive: allowActiveResolution || allowSlackRoutedThreadBypass,
onLifecycleInterrupt
});
} catch (error) {
if (phase === "pre_dispatch" && replyTurnKind === "visible" && isSessionWorkStartInvalidatedError(error)) throw new DispatchSessionRefreshRequiredError(error);
throw error;
}
};
let admission = await admitCurrentReplyTurn();
if (admission.status === "skipped" && admission.reason === "active-run" && replyTurnKind === "visible" && isRecoverableTerminalSessionStatus(params.operationSessionStoreEntry.entry?.status) && admission.activeOperation?.sessionId === params.operationSessionStoreEntry.entry?.sessionId && !admission.activeOperation?.terminalRecovery) {
if (forceClearReplyRunBySessionId(admission.activeOperation?.sessionId ?? operationSessionId, /* @__PURE__ */ new Error("clearing stale terminal reply operation"))) {
admission.lifecycleAdmission?.release();
logVerbose(`dispatch-from-config: cleared stale active reply operation for terminal session ${dispatchOperationSessionKey}`);
admission = await admitCurrentReplyTurn();
}
}
if (admission.status === "skipped") {
if (allowActiveResolution && admission.reason === "active-run") {
preDispatchAbortOperation = admission.activeOperation;
preDispatchLifecycleAdmission = admission.lifecycleAdmission;
if (phase === "pre_dispatch") preDispatchLifecycleAbortController = lifecycleOnlyAbortController;
else dispatchLifecycleAbortController = lifecycleOnlyAbortController;
return { status: "ready" };
}
if (admission.reason === "active-run" && shouldLetSlackRoutedThreadBypassBusyReplyOperation({
activeOperation: admission.activeOperation,
ctx: params.ctx,
routeThreadId: params.routeThreadId
})) {
preDispatchLifecycleAdmission = admission.lifecycleAdmission;
dispatchLifecycleAbortController = lifecycleOnlyAbortController;
logVerbose(`dispatch-from-config: allowing Slack routed thread ${params.routeThreadId} while ${dispatchOperationSessionKey} has an active reply operation in another Slack thread`);
return { status: "ready" };
}
admission.lifecycleAdmission?.release();
dispatchAbortOperation = admission.activeOperation;
logVerbose(`dispatch-from-config: skipped reply operation admission for ${dispatchOperationSessionKey}; reason=${admission.reason}`);
return { status: "busy" };
}
if (replyTurnKind === "visible" && isRecoverableTerminalSessionStatus(params.operationSessionStoreEntry.entry?.status) && operationSessionId === params.operationSessionStoreEntry.entry?.sessionId) admission.operation.markTerminalRecovery();
dispatchReplyOperation = admission.operation;
dispatchReplyOperation.retainFailureUntilComplete();
dispatchAbortOperation = admission.operation;
return { status: "ready" };
};
const getPreDispatchAbortOperation = () => dispatchAbortOperation ?? preDispatchAbortOperation;
let cachedPreDispatchAbortSignal;
let cachedDispatchAbortSignal;
const getPreDispatchAbortSignal = () => {
const operationSignal = getPreDispatchAbortOperation()?.abortSignal;
const lifecycleSignal = preDispatchLifecycleAbortController?.signal;
const upstreamSignal = params.replyOptions?.abortSignal;
if (cachedPreDispatchAbortSignal && cachedPreDispatchAbortSignal.operationSignal === operationSignal && cachedPreDispatchAbortSignal.lifecycleSignal === lifecycleSignal && cachedPreDispatchAbortSignal.upstreamSignal === upstreamSignal) return cachedPreDispatchAbortSignal.signal;
const abortSignals = [
operationSignal,
lifecycleSignal,
upstreamSignal
].filter((signal) => Boolean(signal));
const signal = abortSignals.length > 1 ? AbortSignal.any(abortSignals) : abortSignals[0];
cachedPreDispatchAbortSignal = {
operationSignal,
lifecycleSignal,
upstreamSignal,
signal
};
return signal;
};
const getDispatchAbortSignal = () => {
const operationSignal = dispatchReplyOperation?.abortSignal ?? dispatchLifecycleAbortController?.signal;
const upstreamSignal = operationSignal ? void 0 : params.replyOptions?.abortSignal;
if (cachedDispatchAbortSignal && cachedDispatchAbortSignal.operationSignal === operationSignal && cachedDispatchAbortSignal.upstreamSignal === upstreamSignal) return cachedDispatchAbortSignal.signal;
const signal = operationSignal ?? upstreamSignal;
cachedDispatchAbortSignal = {
operationSignal,
upstreamSignal,
signal
};
return signal;
};
const getQueuedFollowupAbortSignal = () => params.replyOptions?.turnAdoptionLifecycle?.abortSignal ?? dispatchReplyOperation?.abortSignal ?? params.replyOptions?.abortSignal;
let observedReplyDelivery = false;
let agentRunTerminalOutcome;
const markObservedReplyDelivery = async () => {
if (observedReplyDelivery) return;
observedReplyDelivery = true;
await params.replyOptions?.onObservedReplyDelivery?.();
};
const getReplyOptions = () => {
const abortSignal = getDispatchAbortSignal();
const onAgentRunStart = (...args) => {
agentRunTerminalOutcome = "completed";
params.messageAuditTerminal?.observeRunId(args[0]);
return params.replyOptions?.onAgentRunStart?.(...args);
};
const onAgentRunTerminalOutcome = (outcome) => {
if (outcome === "failed" || agentRunTerminalOutcome === void 0) agentRunTerminalOutcome = outcome;
params.replyOptions?.onAgentRunTerminalOutcome?.(outcome);
};
return {
...params.replyOptions,
...abortSignal ? {
abortSignal,
queuedFollowupAbortSignal: getQueuedFollowupAbortSignal()
} : {},
onAgentRunStart,
onAgentRunTerminalOutcome,
...dispatchReplyOperation ? { replyOperation: dispatchReplyOperation } : {}
};
};
const completeDispatchReplyOperation = () => {
releasePreDispatchLifecycleAdmission(() => waitForReplyDispatcherIdle(params.dispatcher));
const operation = dispatchReplyOperation;
if (!operation) return;
const timeoutPolicy = params.dispatcher.resolveFollowupAdmissionBarrierTimeoutPolicy?.();
const complete = () => operation.completeWithAfterClearBarrier(waitForDispatchDelivery(), timeoutPolicy);
if (dispatchLifecycleWork.owner.size > 0) Promise.allSettled(Array.from(dispatchLifecycleWork.owner)).then(complete);
else complete();
};
const failDispatchReplyOperation = (error, terminalOutcome) => {
if (terminalOutcome === "failed") agentRunTerminalOutcome = "failed";
dispatchReplyOperation?.freezeAbort();
if (dispatchReplyOperation && !dispatchReplyOperation.result) dispatchReplyOperation.fail("run_failed", error);
completeDispatchReplyOperation();
};
const isDispatchOperationAborted = () => getDispatchAbortSignal()?.aborted === true;
const isPreDispatchOperationAborted = () => getPreDispatchAbortSignal()?.aborted === true;
const throwIfDispatchOperationAborted = () => {
if (isDispatchOperationAborted()) throw new DispatchReplyOperationAbortedError();
};
const turnLedger = createReplyTurnLedger(params.dispatcher);
return {
completeDispatchReplyOperation,
dispatchHookDispatcher: createAbortAwareDispatcher({
dispatcher: {
...params.dispatcher,
sendToolResult: (payload) => turnLedger.sendQueued("tool", payload).queued,
sendBlockReply: (payload) => turnLedger.sendQueued("block", payload).queued,
sendFinalReply: (payload) => turnLedger.sendQueued("final", payload).queued
},
isAborted: isPreDispatchOperationAborted
}),
turnLedger,
ensureDispatchReplyOperation,
failDispatchReplyOperation,
getAgentRunTerminalOutcome: () => agentRunTerminalOutcome,
getDispatchAbortOperation: () => dispatchAbortOperation,
getDispatchAbortSignal,
getDispatchReplyOperation: () => dispatchReplyOperation,
getReplyOptions,
getObservedReplyDelivery: () => observedReplyDelivery,
getPreDispatchAbortSignal,
isDispatchOperationAborted,
isPreDispatchOperationAborted,
markObservedReplyDelivery,
releasePreDispatchLifecycleAdmission,
runWithDispatchLifecycleAdmission,
throwIfDispatchOperationAborted,
trackDispatchLifecycleWork
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.timing.ts
const replyHotPathTimingLog = createSubsystemLogger("auto-reply/reply-timing");
function createReplyHotPathTimingTracker(options = {}) {
const timing = createReplyTimingTracker({
log: replyHotPathTimingLog,
enabled: options.profilerEnabled === true,
formatMessage: (params, summary, stages) => `reply hot path timings channel=${params.channel} messageId=${params.messageId ?? "unknown"} sessionKey=${params.sessionKey ?? "unknown"} outcome=${params.outcome} totalMs=${summary.totalMs} stages=${stages}${params.reason ? ` reason=${params.reason}` : ""}`,
detailKeys: () => [
"channel",
"messageId",
"sessionKey",
"outcome",
"reason"
]
});
return {
measure: timing.measure,
logIfSlow(params) {
if (!options.profilerEnabled) return;
timing.logIfSlow(params);
},
logPreparationIfSlow(params) {
const { channel, messageId, sessionKey } = params;
timing.logIfSlow({
channel,
messageId,
sessionKey,
outcome: "milestone",
reason: "before_reply_resolver"
}, { repeat: true });
}
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-processed-outcome.ts
const dispatchProcessedOutcomeSink = resolveGlobalSingleton(Symbol.for("openclaw.dispatchProcessedOutcomeSink"), () => new AsyncLocalStorage());
/**
* Runs a channel turn's dispatch under a sink so its terminal outcome can attribute
* zero-count warnings without widening the plugin-visible dispatch result contract.
*/
async function withDispatchProcessedOutcomeSink(run) {
const sink = {};
return {
result: await dispatchProcessedOutcomeSink.run(sink, run),
processedOutcome: sink.current
};
}
/** Records the dispatch's terminal outcome for the surrounding channel turn, if any. */
function noteDispatchProcessedOutcome(note) {
const sink = dispatchProcessedOutcomeSink.getStore();
if (sink) sink.current = note;
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.gather.ts
async function gatherDispatchRequest(params, messageAuditTerminal, allowActiveQueueResolution = false) {
const ctx = isFinalizedInboundContext(params.ctx) ? params.ctx : finalizeInboundContext(params.ctx);
const turnAdoptionLifecycle = params.replyOptions?.turnAdoptionLifecycle;
prepareChannelParticipantObservation(ctx);
const turnAdoptionState = { adopted: false };
const normalizedParams = {
...params,
ctx,
replyOptions: {
...params.replyOptions,
...turnAdoptionLifecycle ? { turnAdoptionLifecycle: {
...turnAdoptionLifecycle,
onAdopted: async () => {
await turnAdoptionLifecycle.onAdopted();
turnAdoptionState.adopted = true;
}
} } : {}
}
};
const replyOperationRunState = resolveReplyOperationRunState(normalizedParams.replyOptions) ?? {};
let replayUnsafeActivity = false;
const state = {
params: normalizedParams,
messageAuditTerminal,
get inboundDedupeReplayUnsafe() {
const admission = replyOperationRunState.admission;
return replayUnsafeActivity || admission?.status === "accepted" && admission.mode === "steer" || admission?.status === "skipped" && admission.reason === "question-response-indeterminate";
},
turnAdoptionState: turnAdoptionLifecycle ? turnAdoptionState : void 0
};
const { cfg, dispatcher } = normalizedParams;
bindReplyDispatcherConversationContext(dispatcher, ctx.agentText);
const diagnosticsEnabled = isDiagnosticsEnabled(cfg);
const channel = normalizeLowercaseStringOrEmpty(ctx.Surface ?? ctx.Provider ?? "unknown");
const chatId = ctx.To ?? ctx.From;
const messageId = ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
const sessionKey = normalizeOptionalString(ctx.SessionKey) ?? normalizeOptionalString(ctx.CommandTargetSessionKey);
const startTime = diagnosticsEnabled ? Date.now() : 0;
const canTrackSession = diagnosticsEnabled && Boolean(sessionKey);
const initialSessionStoreEntry = resolveSessionStoreLookup(ctx, cfg);
const lifecycleSessionId = initialSessionStoreEntry.sessionKey === sessionKey ? initialSessionStoreEntry.entry?.sessionId : void 0;
const messageLifecycle = createDiagnosticMessageLifecycle({
enabled: diagnosticsEnabled,
channel,
chatId,
messageId,
sessionKey,
sessionId: lifecycleSessionId,
source: "dispatch",
processingReason: "message_start",
startedAtMs: startTime,
trackSessionState: canTrackSession
});
const traceAttributes = {
surface: channel,
hasSessionKey: Boolean(sessionKey),
hasRunId: typeof params.replyOptions?.runId === "string"
};
const replyHotPathTiming = createReplyHotPathTimingTracker({ profilerEnabled: isReplyProfilerEnabled({ config: cfg }) });
const traceReplyPhase = (name, run) => replyHotPathTiming.measure(name, () => measureDiagnosticsTimelineSpan(name, run, {
phase: "agent-turn",
config: cfg,
attributes: traceAttributes
}));
let agentDispatchStartedAt = 0;
const recordProcessed = (outcome, opts) => {
noteDispatchProcessedOutcome({
outcome,
...opts?.reason !== void 0 ? { reason: opts.reason } : {}
});
messageAuditTerminal?.note(outcome, opts);
if (diagnosticsEnabled) replyHotPathTiming.logIfSlow({
channel,
messageId,
sessionKey,
outcome,
reason: opts?.reason
});
messageLifecycle.markProcessed(outcome, opts);
};
const finishReplyOperationAborted = () => {
recordProcessed("skipped", { reason: "reply_operation_aborted" });
return {
status: "complete",
result: {
queuedFinal: false,
counts: dispatcher.getQueuedCounts()
}
};
};
if (params.replyOptions?.abortSignal?.aborted) return finishReplyOperationAborted();
const recordAgentDispatchStarted = () => {
if (!diagnosticsEnabled || agentDispatchStartedAt > 0) return;
agentDispatchStartedAt = Date.now();
replyHotPathTiming.logPreparationIfSlow({
channel,
messageId,
sessionKey
});
logMessageDispatchStarted({
channel,
sessionKey: acpDispatchSessionKey,
source: "replyResolver"
});
};
const recordAgentDispatchCompleted = (outcome, opts) => {
if (!diagnosticsEnabled || agentDispatchStartedAt <= 0) return;
logMessageDispatchCompleted({
channel,
sessionKey: acpDispatchSessionKey,
source: "replyResolver",
durationMs: Date.now() - agentDispatchStartedAt,
outcome,
reason: opts?.reason,
error: opts?.error
});
};
const markProcessing = () => {
messageLifecycle.markProcessing();
};
const markIdle = (reason) => {
messageLifecycle.markIdle(reason);
};
const markInboundDedupeReplayUnsafe = () => {
replayUnsafeActivity = true;
};
const boundAcpDispatchSessionKey = resolveBoundAcpDispatchSessionKey({
ctx,
cfg
});
const acpDispatchSessionKey = boundAcpDispatchSessionKey ?? initialSessionStoreEntry.sessionKey ?? sessionKey;
const sourceSessionKey = normalizeOptionalString(ctx.SessionKey);
const dispatchOperationSessionKey = sourceSessionKey ?? initialSessionStoreEntry.sessionKey ?? sessionKey ?? acpDispatchSessionKey;
const operationSessionStoreEntry = sourceSessionKey && initialSessionStoreEntry.sessionKey && sourceSessionKey !== initialSessionStoreEntry.sessionKey ? resolveSessionStoreLookup({
...ctx,
CommandTargetSessionKey: void 0
}, cfg) : initialSessionStoreEntry;
const initialDispatchReplyOperation = dispatchOperationSessionKey ? replyRunRegistry.get(dispatchOperationSessionKey) : void 0;
if (params.replyOptions?.isHeartbeat === true && dispatchOperationSessionKey && initialDispatchReplyOperation) {
noteDispatchProcessedOutcome({
outcome: "skipped",
reason: "reply-operation-active"
});
messageAuditTerminal?.note("skipped", { reason: "reply-operation-active" });
return {
status: "complete",
result: {
queuedFinal: false,
counts: dispatcher.getQueuedCounts()
}
};
}
const markProgress = () => {
if (!canTrackSession || !sessionKey) return;
markDiagnosticSessionProgress({ sessionKey });
if (acpDispatchSessionKey && acpDispatchSessionKey !== sessionKey) markDiagnosticSessionProgress({ sessionKey: acpDispatchSessionKey });
};
const sessionStoreEntry = boundAcpDispatchSessionKey ? resolveSessionStoreLookup({
...ctx,
SessionKey: boundAcpDispatchSessionKey
}, cfg) : initialSessionStoreEntry;
const dispatchKind = resolveSessionDispatchKind(acpDispatchSessionKey, sessionStoreEntry.entry);
let preparedSessionBinding = sessionStoreEntry.sessionKey && sessionStoreEntry.entry?.sessionId ? {
sessionKey: sessionStoreEntry.sessionKey,
sessionId: sessionStoreEntry.entry.sessionId,
storePath: sessionStoreEntry.storePath
} : void 0;
let preparedOperationSessionBinding = operationSessionStoreEntry.sessionKey && operationSessionStoreEntry.entry?.sessionId ? {
sessionKey: operationSessionStoreEntry.sessionKey,
sessionId: operationSessionStoreEntry.entry.sessionId,
storePath: operationSessionStoreEntry.storePath
} : void 0;
const sessionKeysMatch = (left, right) => Boolean(left && right && normalizeExplicitSessionKey(left, ctx) === normalizeExplicitSessionKey(right, ctx));
const notePreparedSession = (binding) => {
if (sessionKeysMatch(binding.sessionKey, sessionStoreEntry.sessionKey)) preparedSessionBinding = binding;
if (sessionKeysMatch(binding.sessionKey, operationSessionStoreEntry.sessionKey)) preparedOperationSessionBinding = binding;
params.replyOptions?.onSessionPrepared?.(binding);
};
const resolveOperationExpectedSessionId = () => preparedOperationSessionBinding?.sessionId ?? operationSessionStoreEntry.entry?.sessionId;
const resolvePreparedTranscriptBinding = (mirrorSessionKey) => {
if (!preparedSessionBinding || !sessionKeysMatch(mirrorSessionKey, preparedSessionBinding.sessionKey)) return;
return preparedSessionBinding;
};
const sessionAgentId = resolveSessionAgentId({
sessionKey: acpDispatchSessionKey,
config: cfg,
fallbackAgentId: ctx.AgentId
});
const sessionAgentCfg = resolveAgentConfig(cfg, sessionAgentId);
const verboseProgress = createShouldEmitVerboseProgress({
agentId: sessionAgentId,
sessionKey: acpDispatchSessionKey,
storePath: sessionStoreEntry.storePath,
initialExplicitLevel: sessionStoreEntry.entry?.verboseLevel,
fallbackLevel: normalizeVerboseLevel(sessionStoreEntry.entry?.verboseLevel ?? sessionAgentCfg?.verboseDefault ?? cfg.agents?.defaults?.verboseDefault ?? "") ?? "off"
});
const shouldEmitVerboseProgress = verboseProgress.shouldEmit;
const shouldEmitFullVerboseProgress = verboseProgress.shouldEmitFull;
const replyRoute = resolveEffectiveReplyRoute({
ctx,
entry: sessionStoreEntry.entry
});
const routeThreadId = resolveRoutedDeliveryThreadId({
ctx,
sessionKey: acpDispatchSessionKey
});
const routeReplyThreadId = replyRoute.threadId ?? routeThreadId;
const inboundAudio = hasInboundAudio(ctx);
const sessionTtsAuto = normalizeTtsAutoMode(sessionStoreEntry.entry?.ttsAuto);
const preparedReplyDispatchAgentId = boundAcpDispatchSessionKey ? resolveSessionAgentId({
sessionKey,
config: cfg,
fallbackAgentId: ctx.AgentId
}) : sessionAgentId;
let preparedReplyDispatchRuntime;
try {
preparedReplyDispatchRuntime = params.usePublishedModelRuntime ? await traceReplyPhase("reply.load_prepared_dispatch_runtime", async () => {
const { loadPublishedGatewayReplyDispatchRuntime } = await loadPreparedModelRuntime();
return await loadPublishedGatewayReplyDispatchRuntime({
agentId: preparedReplyDispatchAgentId,
abortSignal: params.replyOptions?.abortSignal
});
}) : void 0;
} catch (error) {
if (params.replyOptions?.abortSignal?.aborted && isAbortError(error)) return finishReplyOperationAborted();
throw error;
}
const workspaceDir = preparedReplyDispatchRuntime?.workspaceDir ?? resolveAgentWorkspaceDir(cfg, sessionAgentId);
const { completeDispatchReplyOperation, dispatchHookDispatcher, ensureDispatchReplyOperation, failDispatchReplyOperation, getAgentRunTerminalOutcome, getDispatchAbortOperation, getDispatchAbortSignal, getDispatchReplyOperation, getObservedReplyDelivery, getPreDispatchAbortSignal, getReplyOptions, isDispatchOperationAborted, isPreDispatchOperationAborted, markObservedReplyDelivery, releasePreDispatchLifecycleAdmission, runWithDispatchLifecycleAdmission, throwIfDispatchOperationAborted, trackDispatchLifecycleWork, turnLedger } = createDispatchReplyOperationCoordinator({
allowActiveQueueResolution,
agentId: sessionAgentId,
cfg,
ctx,
dispatcher,
dispatchOperationSessionKey,
initialDispatchReplyOperation,
messageAuditTerminal,
operationSessionStoreEntry,
replyOptions: normalizedParams.replyOptions,
resolveOperationExpectedSessionId,
routeThreadId,
sessionWorkerPlacementContext: normalizedParams.sessionWorkerPlacementContext
});
const maybeApplyTtsWithFinalizationLease = createFinalizationAwareTtsPayloadApplier({
getReplyOperation: getDispatchReplyOperation,
hasInboundAudio: () => inboundAudio || getDispatchReplyOperation()?.acceptedSteeredInboundAudio === true
});
const pluginRegistry = preparedReplyDispatchRuntime?.inboundPluginRegistry ?? await traceReplyPhase("reply.load_runtime_plugin_registry_handle", async () => {
const { loadAgentRuntimePluginRegistryHandle } = await traceReplyPhase("reply.load_runtime_plugins", loadRuntimePlugins);
return loadAgentRuntimePluginRegistryHandle({
config: cfg,
workspaceDir,
allowGatewaySubagentBinding: true
});
});
const hookRunner = getGlobalHookRunner();
const timestamp = typeof ctx.Timestamp === "number" && Number.isFinite(ctx.Timestamp) ? ctx.Timestamp : void 0;
const messageIdForHook = ctx.MessageSidFull ?? ctx.MessageSid ?? ctx.MessageSidFirst ?? ctx.MessageSidLast;
const hookCtx = { ...ctx };
const buildHookState = (sourceCtx) => {
const nextHookContext = deriveInboundMessageHookContext(sourceCtx, { messageId: messageIdForHook });
const inboundClaim = toPluginInboundClaimPair(nextHookContext, {
commandAuthorized: typeof ctx.CommandAuthorized === "boolean" ? ctx.CommandAuthorized : void 0,
wasMentioned: typeof ctx.WasMentioned === "boolean" ? ctx.WasMentioned : void 0
});
return {
hookContext: nextHookContext,
inboundClaimContext: inboundClaim.context,
inboundClaimEvent: inboundClaim.event
};
};
const hookState = buildHookState(hookCtx);
const { isGroup, groupId } = hookState.hookContext;
let hookMediaPrepared = false;
let hookMediaMetadataStaged = false;
const prepareHookMediaMetadata = async () => {
if (hookMediaPrepared) return;
hookMediaPrepared = true;
if (await traceReplyPhase("reply.stage_remote_media_for_dispatch", () => stageRemoteInboundMediaIfNeeded({
ctx: hookCtx,
cfg,
agentId: sessionAgentId,
sessionKey: acpDispatchSessionKey,
workspaceDir,
remoteMediaMode: "cache",
abortSignal: getPreDispatchAbortSignal()
}))) {
hookMediaMetadataStaged = true;
Object.assign(hookState, buildHookState(hookCtx));
}
};
const buildMessageReceivedHookContext = () => {
const mediaRemoteHost = normalizeOptionalString(ctx.MediaRemoteHost);
const { hookContext } = hookState;
const hasUnstagedRemoteMediaMetadata = Boolean(hookContext.media?.length);
if (hookMediaMetadataStaged || !mediaRemoteHost || !hasUnstagedRemoteMediaMetadata) return hookContext;
const messageReceivedCtx = { ...hookCtx };
stripLegacyMediaContextFields(messageReceivedCtx);
delete messageReceivedCtx.media;
return {
...buildHookState(messageReceivedCtx).hookContext,
mediaRemoteHost,
mediaStagingPending: true,
originalMedia: hookContext.media?.map((entry) => ({ ...entry })),
originalMediaPath: hookContext.mediaPath,
originalMediaUrl: hookContext.mediaUrl,
originalMediaType: hookContext.mediaType,
originalMediaPaths: hookContext.mediaPaths,
originalMediaUrls: hookContext.mediaUrls,
originalMediaTypes: hookContext.mediaTypes
};
};
return {
status: "ready",
state: extendPreparedDispatchState(state, {
ctx,
cfg,
dispatcher,
sessionKey,
traceReplyPhase,
recordProcessed,
recordAgentDispatchStarted,
recordAgentDispatchCompleted,
markProcessing,
markIdle,
markInboundDedupeReplayUnsafe,
acpDispatchSessionKey,
dispatchKind,
markProgress,
sessionStoreEntry,
notePreparedSession,
resolvePreparedTranscriptBinding,
sessionAgentId,
noteRunVerbosity: verboseProgress.noteRunVerbosity,
shouldEmitVerboseProgress,
shouldEmitFullVerboseProgress,
replyRoute,
routeReplyThreadId,
inboundAudio,
sessionTtsAuto,
workspaceDir,
preparedReplyDispatchRuntime,
pluginRegistry,
replyOperationRunState,
completeDispatchReplyOperation,
dispatchHookDispatcher,
ensureDispatchReplyOperation,
failDispatchReplyOperation,
getAgentRunTerminalOutcome,
getDispatchAbortOperation,
getDispatchAbortSignal,
getDispatchReplyOperation,
getObservedReplyDelivery,
getPreDispatchAbortSignal,
getReplyOptions,
isDispatchOperationAborted,
isPreDispatchOperationAborted,
markObservedReplyDelivery,
releasePreDispatchLifecycleAdmission,
runWithDispatchLifecycleAdmission,
throwIfDispatchOperationAborted,
trackDispatchLifecycleWork,
turnLedger,
maybeApplyTtsWithFinalizationLease,
hookRunner,
timestamp,
messageIdForHook,
isGroup,
groupId,
hookState,
prepareHookMediaMetadata,
buildMessageReceivedHookContext
})
};
}
//#endregion
//#region src/auto-reply/reply/conversation-turn-capture.ts
const EPOCH_MILLISECONDS_THRESHOLD = 0xe8d4a51000;
const CONVERSATION_TURN_REPLY_CUSTOM_TYPE = "openclaw.conversation-turn-reply";
function readPersistedReplyText(message) {
const content = message?.content;
if (typeof content === "string") return normalizeOptionalString(content);
if (!Array.isArray(content)) return;
return normalizeOptionalString(content.flatMap((part) => {
if (!part || typeof part !== "object") return [];
const record = part;
return record.type === "text" && typeof record.text === "string" ? [record.text] : [];
}).join("\n"));
}
function normalizeTimestamp(value) {
const timestamp = typeof value === "number" && Number.isFinite(value) ? value : void 0;
if (timestamp === void 0 || timestamp <= 0) return;
return asDateTimestampMs(timestamp < EPOCH_MILLISECONDS_THRESHOLD ? Math.trunc(timestamp * 1e3) : timestamp);
}
async function capturePendingConversationTurnReplyUnsafe(params) {
if (params.ctx.InboundAccessAuthorized !== true) return false;
const sessionKey = normalizeOptionalString(params.ctx.SessionKey);
const messageId = normalizeOptionalString(params.ctx.MessageSidFull) ?? normalizeOptionalString(params.ctx.MessageSid) ?? normalizeOptionalString(params.ctx.MessageSidFirst) ?? normalizeOptionalString(params.ctx.MessageSidLast);
const replyText = normalizeOptionalString(params.ctx.agentText);
if (!sessionKey || !messageId || !replyText) return false;
const conversation = conversationIdentityFromMsgContext({ ctx: params.ctx });
if (!conversation) return false;
const replyToId = normalizeOptionalString(params.ctx.ReplyToIdFull) ?? normalizeOptionalString(params.ctx.ReplyToId);
const threadId = params.ctx.MessageThreadId == null ? void 0 : normalizeOptionalString(String(params.ctx.MessageThreadId));
const agentId = normalizeOptionalString(params.ctx.AgentId) ?? resolveAgentIdFromSessionKey(sessionKey);
const storePath = resolveSessionStorePathCore(params.cfg.session?.store, { agentId });
const sessionEntry = loadSessionEntryReadOnly({
agentId,
sessionKey,
storePath,
readConsistency: "latest"
});
if (!sessionEntry) return false;
const timestamp = normalizeTimestamp(params.ctx.Timestamp);
const parentConversationRef = threadId ? conversation.parentConversationRef ?? buildConversationRef({
channel: conversation.channel,
accountId: conversation.accountId,
kind: conversation.kind,
peerId: conversation.peerId
}) : void 0;
const input = {
text: replyText,
timestamp,
idempotencyKey: `conversation-inbound:${conversation.conversationRef}:${messageId}`,
...params.ctx.InputProvenance ? { provenance: params.ctx.InputProvenance } : {},
transport: {
channel: conversation.channel,
conversationRef: conversation.conversationRef,
messageId,
...replyToId ? { replyToId } : {},
...threadId ? { threadId } : {}
},
sender: conversation.kind === "group" || conversation.kind === "channel" ? buildChannelUserTurnSender(params.ctx) : void 0
};
const claim = await claimPendingConversationTurnReply({
agentId,
conversationRef: conversation.conversationRef,
...parentConversationRef ? { parentConversationRef } : {},
sessionId: sessionEntry.sessionId,
messageId,
replyToId,
threadId,
text: replyText,
timestamp
});
if (!claim) {
if (replyToId) {
const operation = findConversationTurnDeliveryByReplyTarget({
agentId,
storePath
}, {
conversationRef: conversation.conversationRef,
replyToId
}) ?? (parentConversationRef && parentConversationRef !== conversation.conversationRef ? findConversationTurnDeliveryByReplyTarget({
agentId,
storePath
}, {
conversationRef: parentConversationRef,
replyToId
}) : void 0);
if (operation?.status === "replied" && operation.reply?.messageId === messageId) return true;
if (operation && operation.status !== "replied") markConversationDeliverySent({
agentId,
storePath
}, operation.operationId, replyToId);
}
return false;
}
try {
if (sessionEntry.sessionId !== claim.sessionId) throw new Error(`session changed before captured reply persistence: ${sessionKey}`);
const prepared = preparePersistedUserTurnMessageForTranscriptWrite(buildPersistedUserTurnMessage(input), {
agentId,
sessionKey,
beforeMessageWrite: runAgentHarnessBeforeMessageWriteHook
});
if (!prepared) throw new Error("captured conversation turn reply was blocked before persistence");
const persistedMessage = redactTranscriptMessage(prepared, params.cfg);
const persistedReplyText = readPersistedReplyText(persistedMessage);
if (!persistedReplyText) throw new Error("captured conversation turn reply has no persistable text");
const artifactId = `conversation-turn-reply-${claim.turnId}`;
markConversationDeliveryReplied({
agentId,
storePath
}, {
operationId: claim.turnId,
reply: {
messageId,
...replyToId ? { replyToId } : {},
...threadId ? { threadId } : {},
text: persistedReplyText,
timestamp: timestamp ?? Date.now()
}
});
let persisted = false;
try {
const appendResult = appendTranscriptEventSync({
agentId,
sessionId: sessionEntry.sessionId,
sessionKey,
storePath
}, {
type: "custom",
id: artifactId,
customType: CONVERSATION_TURN_REPLY_CUSTOM_TYPE,
appendMode: "side",
timestamp: timestamp ?? Date.now(),
data: {
turnId: claim.turnId,
conversationRef: conversation.conversationRef,
messageId,
...replyToId ? { replyToId } : {},
...threadId ? { threadId } : {},
message: persistedMessage
}
});
persisted = appendResult.ok && appendResult.value;
if (!appendResult.ok) logVerbose(`captured conversation turn reply audit persistence failed: ${appendResult.error.code}`);
} catch (error) {
logVerbose(`captured conversation turn reply audit persistence failed: ${String(error)}`);
}
if (!persisted) logVerbose("captured conversation turn reply audit artifact was not persisted");
claim.complete(persisted ? { transcriptArtifactId: artifactId } : void 0);
return true;
} catch (error) {
claim.release();
logVerbose(`conversation turn reply capture failed: ${String(error)}`);
return false;
}
}
/** Consumes a correlated channel reply before it can start a second local agent turn. */
async function capturePendingConversationTurnReply(params) {
try {
return await capturePendingConversationTurnReplyUnsafe(params);
} catch (error) {
logVerbose(`conversation turn reply capture unavailable: ${String(error)}`);
return false;
}
}
//#endregion
//#region src/auto-reply/reply/inbound-dedupe.ts
const DEFAULT_INBOUND_DEDUPE_TTL_MS = 12e5;
const DEFAULT_INBOUND_DEDUPE_MAX = 5e3;
/**
* Keep inbound dedupe shared across bundled chunks so the same provider
* message cannot bypass dedupe by entering through a different chunk copy.
*/
const INBOUND_DEDUPE_CACHE_KEY = Symbol.for("openclaw.inboundDedupeCache");
const INBOUND_DEDUPE_INFLIGHT_KEY = Symbol.for("openclaw.inboundDedupeInflight");
const inboundDedupeCache = resolveGlobalDedupeCache(INBOUND_DEDUPE_CACHE_KEY, {
ttlMs: DEFAULT_INBOUND_DEDUPE_TTL_MS,
maxSize: DEFAULT_INBOUND_DEDUPE_MAX
});
const inboundDedupeInFlight = resolveGlobalSingleton(INBOUND_DEDUPE_INFLIGHT_KEY, () => /* @__PURE__ */ new Set());
const resolveInboundPeerId = (ctx) => ctx.OriginatingTo ?? ctx.To ?? ctx.From ?? ctx.SessionKey;
function resolveInboundDedupeSessionScope(ctx) {
const commandTarget = resolveCommandTurnTargetSessionKey(ctx);
if (commandTarget) return commandTarget;
const sessionKey = normalizeOptionalString(ctx.SessionKey) || "";
if (!sessionKey) return "";
const parsed = parseAgentSessionKey(sessionKey);
if (!parsed) return sessionKey;
return `agent:${parsed.agentId}`;
}
function buildInboundDedupeKey(ctx) {
const provider = normalizeOptionalLowercaseString(ctx.OriginatingChannel ?? ctx.Provider ?? ctx.Surface) || "";
const messageId = normalizeOptionalString(ctx.MessageSid);
if (!provider || !messageId) return null;
const peerId = resolveInboundPeerId(ctx);
if (!peerId) return null;
const sessionScope = resolveInboundDedupeSessionScope(ctx);
const accountId = normalizeOptionalString(ctx.AccountId) ?? "";
const routeKey = channelRouteDedupeKey({
channel: provider,
to: peerId,
accountId,
threadId: ctx.MessageThreadId
});
return JSON.stringify([
sessionScope,
routeKey,
messageId
]);
}
function claimInboundDedupe(ctx, opts) {
const key = buildInboundDedupeKey(ctx);
if (!key) return { status: "invalid" };
if ((opts?.cache ?? inboundDedupeCache).peek(key, opts?.now)) return {
status: "duplicate",
key
};
const inFlight = opts?.inFlight ?? inboundDedupeInFlight;
if (inFlight.has(key)) return {
status: "inflight",
key
};
inFlight.add(key);
return {
status: "claimed",
key
};
}
function commitInboundDedupe(key, opts) {
(opts?.cache ?? inboundDedupeCache).check(key, opts?.now);
(opts?.inFlight ?? inboundDedupeInFlight).delete(key);
}
function releaseInboundDedupe(key, opts) {
(opts?.inFlight ?? inboundDedupeInFlight).delete(key);
}
function resetInboundDedupe() {
inboundDedupeCache.clear();
inboundDedupeInFlight.clear();
}
//#endregion
//#region src/auto-reply/reply/message-received-hooks.ts
/** Emit observation hooks once for an accepted inbound turn, independent of reply dispatch. */
function emitMessageReceivedHooks(params) {
if (params.ctx.SuppressMessageReceivedHooks === true) return;
const buildContext = params.buildContext ?? (() => deriveInboundMessageHookContext(params.ctx, { messageId: params.ctx.MessageSidFull ?? params.ctx.MessageSid ?? params.ctx.MessageSidFirst ?? params.ctx.MessageSidLast }));
if (params.hookRunner?.hasHooks("message_received") === true) {
const context = buildContext();
fireAndForgetHook(params.hookRunner.runMessageReceived(toPluginMessageReceivedEvent(context), toPluginMessageContext(context)), "message_received plugin hook failed");
}
if (params.sessionKey) {
const context = buildContext();
fireAndForgetHook(triggerInternalHook(createInternalHookEvent("message", "received", params.sessionKey, {
...toInternalMessageReceivedContext(context),
timestamp: params.timestamp
})), "message_received internal hook failed");
}
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.prepare-context.ts
async function prepareDispatchOperationContext(state) {
const { acpDispatchSessionKey, buildMessageReceivedHookContext, cfg, ctx, dispatcher, hookRunner, isInternalWebchatTurn, markIdle, params, recordAgentDispatchCompleted, recordProcessed, replyRoute, sessionAgentId, sessionKey, sessionStoreEntry } = state;
const sendBindingNotice = async (payload, mode, transcriptOwner) => {
if (sourceReplyPolicy.suppressAutomaticSourceDelivery) return false;
return await state.deliverBindingPayload(payload, mode, transcriptOwner);
};
const pluginBindingConversation = resolveConversationBindingContextFromMessage({
cfg,
ctx
});
const pluginOwnedBindingRecord = pluginBindingConversation ? getSessionBindingService().resolveByConversation({
channel: pluginBindingConversation.channel,
accountId: pluginBindingConversation.accountId,
conversationId: pluginBindingConversation.conversationId,
parentConversationId: pluginBindingConversation.parentConversationId
}) : null;
const pluginOwnedBinding = toPluginConversationBinding(pluginOwnedBindingRecord);
const pluginBindingSessionKey = normalizeOptionalString(pluginOwnedBindingRecord?.targetSessionKey);
const persistPluginBindingUserTurn = async () => {
const recorder = params.replyOptions?.userTurnTranscriptRecorder;
if (!recorder || !pluginBindingSessionKey) return;
const targetAgentId = resolveSessionAgentId({
sessionKey: pluginBindingSessionKey,
config: cfg,
fallbackAgentId: ctx.AgentId
});
const blockedOwner = (expectedSessionId) => ({
agentId: targetAgentId,
sessionKey: pluginBindingSessionKey,
...expectedSessionId ? { expectedSessionId } : {},
transcriptWriteBlocked: true
});
if (recorder.hasPersisted()) return blockedOwner();
let attemptedSessionId;
let lastOwner;
for (let attempt = 0; attempt < 2; attempt += 1) {
const targetSessionStoreEntry = resolveSessionStoreLookup({
...ctx,
CommandTargetSessionKey: void 0,
SessionKey: pluginBindingSessionKey
}, cfg);
const targetSessionEntry = targetSessionStoreEntry.entry;
if (!targetSessionEntry || targetSessionEntry.sessionId === attemptedSessionId) break;
attemptedSessionId = targetSessionEntry.sessionId;
lastOwner = {
agentId: targetAgentId,
expectedSessionId: targetSessionEntry.sessionId,
sessionKey: pluginBindingSessionKey
};
if (await recorder.persistApproved({
target: {
sessionId: targetSessionEntry.sessionId,
sessionKey: pluginBindingSessionKey,
sessionEntry: targetSessionEntry,
...targetSessionStoreEntry.store ? { sessionStore: targetSessionStoreEntry.store } : {},
storePath: targetSessionStoreEntry.storePath,
agentId: targetAgentId,
cwd: resolveAgentWorkspaceDir(cfg, targetAgentId),
config: cfg
},
expectedSessionId: targetSessionEntry.sessionId,
retryIfUnpersisted: true
})) return lastOwner;
}
if (!lastOwner) {
recorder.markBlocked();
return blockedOwner();
}
recorder.markBlocked();
logVerbose(`plugin-bound user-turn persistence skipped after the target session changed`);
return blockedOwner(lastOwner.expectedSessionId);
};
const sendPolicy = resolveSendPolicy({
cfg,
entry: sessionStoreEntry.entry,
sessionKey: sessionStoreEntry.sessionKey ?? sessionKey,
channel: (state.shouldRouteToOriginating ? state.routeReplyChannel : void 0) ?? sessionDeliveryChannel(sessionStoreEntry.entry) ?? replyRoute.channel ?? ctx.Surface ?? ctx.Provider ?? void 0,
chatType: sessionStoreEntry.entry?.chatType
});
const { globalPolicy, globalProviderPolicy, agentPolicy, agentProviderPolicy, profile, providerProfile, profileAlsoAllow, providerProfileAlsoAllow } = resolveEffectiveToolPolicy({
config: cfg,
sessionKey: acpDispatchSessionKey,
agentId: sessionAgentId
});
const chatType = normalizeChatType(ctx.ChatType);
const silentReplyConversationType = resolveRoutedPolicyConversationType(ctx);
const silentReplySurface = normalizeLowercaseStringOrEmpty(ctx.Surface ?? ctx.Provider);
const emptyFinalAllowedAsSilent = ctx.WasMentioned !== true && silentReplyConversationType !== void 0 && resolveSilentReplyPolicyFromPolicies({
conversationType: silentReplyConversationType,
defaultPolicy: cfg.agents?.defaults?.silentReply,
surfacePolicy: silentReplySurface ? cfg.surfaces?.[silentReplySurface]?.silentReply : void 0
}) === "allow";
const { configuredVisibleReplies, harnessDefaultVisibleReplies } = resolveVisibleRepliesPolicy({
cfg,
chatType,
ctx,
entry: sessionStoreEntry.entry,
sessionAgentId,
sessionKey: acpDispatchSessionKey,
sessionStore: sessionStoreEntry.store,
turnModelOverride: resolveTurnModelOverride(params.replyOptions)
});
const effectiveVisibleReplies = configuredVisibleReplies ?? harnessDefaultVisibleReplies;
const runtimeProfileAlsoAllow = params.replyOptions?.sourceReplyDeliveryMode === "message_tool_only" || ctx.InboundEventKind === "room_event" && !isInternalWebchatTurn || params.replyOptions?.sourceReplyDeliveryMode === void 0 && !isExplicitSourceReplyCommand(ctx, cfg) && (configuredVisibleReplies === "message_tool" || !isInternalWebchatTurn && effectiveVisibleReplies === "message_tool") ? ["message"] : [];
const profilePolicy = mergeAlsoAllowPolicy(resolveToolProfilePolicy(profile), [...profileAlsoAllow ?? [], ...runtimeProfileAlsoAllow]);
const providerProfilePolicy = mergeAlsoAllowPolicy(resolveToolProfilePolicy(providerProfile), [...providerProfileAlsoAllow ?? [], ...runtimeProfileAlsoAllow]);
const groupResolution = resolveGroupSessionKey(ctx);
const messageProvider = resolveOriginMessageProvider({
originatingChannel: ctx.OriginatingChannel,
provider: ctx.Provider ?? ctx.Surface
});
const groupPolicy = resolveGroupToolPolicy({
config: cfg,
sessionKey: acpDispatchSessionKey,
messageProvider,
groupId: groupResolution?.id,
groupChannel: normalizeOptionalString(ctx.GroupChannel) ?? normalizeOptionalString(ctx.GroupSubject),
groupSpace: normalizeOptionalString(ctx.GroupSpace),
accountId: ctx.AccountId,
senderId: normalizeOptionalString(ctx.SenderId),
senderName: normalizeOptionalString(ctx.SenderName),
senderUsername: normalizeOptionalString(ctx.SenderUsername),
senderE164: normalizeOptionalString(ctx.SenderE164)
});
const subagentStore = resolveSubagentCapabilityStore(acpDispatchSessionKey, { cfg });
const subagentPolicy = acpDispatchSessionKey && isSubagentEnvelopeSession(acpDispatchSessionKey, {
cfg,
store: subagentStore
}) ? resolveSubagentToolPolicyForSession(cfg, acpDispatchSessionKey, { store: subagentStore }) : void 0;
const inheritedToolPolicy = resolveInheritedToolPolicyForSession(cfg, acpDispatchSessionKey, { store: subagentStore });
const messageToolAvailable = isToolAllowedByPolicies("message", [
profilePolicy,
providerProfilePolicy,
globalProviderPolicy,
agentProviderPolicy,
globalPolicy,
agentPolicy,
groupPolicy,
subagentPolicy,
inheritedToolPolicy
]);
const sessionStableMessageToolAvailable = effectiveVisibleReplies === "message_tool" ? resolveStableMessageToolAvailability({
cfg,
ctx,
sessionEntry: sessionStoreEntry.entry,
sessionAgentId,
sessionKey: acpDispatchSessionKey
}) : void 0;
const sourceReplyPolicyParams = {
cfg,
ctx,
strictMessageToolOnly: ctx.InboundEventKind === "room_event" && !isInternalWebchatTurn,
sendPolicy,
suppressAcpChildUserDelivery: state.suppressAcpChildUserDelivery,
explicitSuppressTyping: params.replyOptions?.suppressTyping === true,
shouldSuppressTyping: state.shouldSuppressTyping,
messageToolAvailable,
sessionStableMessageToolAvailable,
isHeartbeat: params.replyOptions?.isHeartbeat
};
let sourceReplyPolicy = resolveSourceReplyVisibilityPolicy({
...sourceReplyPolicyParams,
requested: params.replyOptions?.sourceReplyDeliveryMode,
defaultVisibleReplies: harnessDefaultVisibleReplies
});
const alternateHarnessDefault = harnessDefaultVisibleReplies === "message_tool" ? "automatic" : "message_tool";
const sourceReplyDeliveryRuntimeOptions = {
sourceReplyDeliveryModeOrigin: resolveSourceReplyVisibilityPolicy({
...sourceReplyPolicyParams,
requested: params.replyOptions?.sourceReplyDeliveryMode,
defaultVisibleReplies: alternateHarnessDefault
}).sourceReplyDeliveryMode === sourceReplyPolicy.sourceReplyDeliveryMode ? "stable_policy" : "runtime_default",
onSourceReplyDeliveryModeResolved: (mode) => {
const stableMode = sourceReplyPolicy.sessionStableSourceReplyDeliveryMode;
sourceReplyPolicy = resolveSourceReplyVisibilityPolicy({
...sourceReplyPolicyParams,
requested: mode
});
sourceReplyPolicy.sessionStableSourceReplyDeliveryMode = stableMode;
Object.assign(state, sourceReplyPolicy, { sourceReplyPolicy });
}
};
Object.assign(sourceReplyPolicy, sourceReplyDeliveryRuntimeOptions);
const { sourceReplyDeliveryMode, sessionStableSourceReplyDeliveryMode, suppressAutomaticSourceDelivery, suppressDelivery, sendPolicyDenied, deliverySuppressionReason, suppressHookUserDelivery, suppressHookReplyLifecycle } = sourceReplyPolicy;
const reasoningPayloadsEnabled = params.replyOptions?.reasoningPayloadsEnabled === true;
const commentaryPayloadsEnabled = params.replyOptions?.commentaryPayloadsEnabled === true;
const attachSourceReplyDeliveryMode = (result) => sourceReplyPolicy.sourceReplyDeliveryMode === "message_tool_only" || sourceReplyPolicy.sendPolicyDenied ? {
...result,
...sourceReplyPolicy.sourceReplyDeliveryMode === "message_tool_only" ? { sourceReplyDeliveryMode: sourceReplyPolicy.sourceReplyDeliveryMode } : {},
...sourceReplyPolicy.sendPolicyDenied ? { sendPolicyDenied: true } : {}
} : result;
const explicitCommandTurnCtx = isExplicitSourceReplyCommand(ctx, cfg);
const activeRunSafeCommandTurn = explicitCommandTurnCtx && isActiveRunSafeCommandTurn({
commandTurn: resolveCommandTurnContext(ctx),
cfg,
provider: ctx.Provider ?? ctx.Surface
});
const unauthorizedTextSlashSourceReplyCtx = (chatType === "group" || chatType === "channel") && isUnauthorizedTextSlashCommand(ctx);
const noVisibleReplyFallbackDirected = isDirectedSourceReplyTurn(ctx, cfg, chatType === "direct");
const shouldDeliverPluginBindingReply = !suppressAutomaticSourceDelivery || explicitCommandTurnCtx || ctx.InboundEventKind !== "room_event" && !unauthorizedTextSlashSourceReplyCtx;
const durableSourceTurnId = readChannelSourceTurnId(ctx) ?? (shouldMintChannelSourceTurnId(ctx.Provider ?? ctx.Surface) ? buildChannelSourceTurnId({
provider: resolveOriginMessageProvider({
originatingChannel: replyRoute.channel,
provider: ctx.Provider ?? ctx.Surface
}),
accountId: replyRoute.accountId,
conversationId: replyRoute.to,
messageId: normalizeOptionalString(ctx.MessageSidFull) ?? normalizeOptionalString(ctx.MessageSid)
}) : void 0);
setChannelSourceTurnId(ctx, durableSourceTurnId);
if (isDuplicateRestartRecoverySource(sessionStoreEntry.entry, durableSourceTurnId)) {
recordProcessed("skipped", { reason: "duplicate" });
return {
status: "complete",
result: attachSourceReplyDeliveryMode({
queuedFinal: false,
counts: dispatcher.getQueuedCounts()
})
};
}
const inboundDedupeClaim = claimInboundDedupe(ctx);
if (inboundDedupeClaim.status === "duplicate" || inboundDedupeClaim.status === "inflight") {
recordProcessed("skipped", { reason: "duplicate" });
return {
status: "complete",
result: attachSourceReplyDeliveryMode({
queuedFinal: false,
counts: dispatcher.getQueuedCounts()
})
};
}
const commitInboundDedupeIfClaimed = () => {
if (inboundDedupeClaim.status === "claimed") commitInboundDedupe(inboundDedupeClaim.key);
};
const releaseInboundDedupeIfClaimed = () => {
if (inboundDedupeClaim.status === "claimed") releaseInboundDedupe(inboundDedupeClaim.key);
};
const finishReplyOperationBusyDispatch = (opts) => {
state.releasePreDispatchLifecycleAdmission(() => waitForReplyDispatcherIdle(dispatcher));
if (opts?.recordAgentDispatchCompleted) recordAgentDispatchCompleted("completed", { reason: "reply-operation-active" });
recordProcessed("skipped", { reason: "reply-operation-active" });
markIdle("message_completed");
if (opts?.dedupeDisposition === "release") releaseInboundDedupeIfClaimed();
else commitInboundDedupeIfClaimed();
return attachSourceReplyDeliveryMode({
queuedFinal: false,
counts: dispatcher.getQueuedCounts(),
...opts?.sessionMetadataChanges ? { sessionMetadataChanges: opts.sessionMetadataChanges } : {}
});
};
const finishReplyOperationAbortedDispatch = () => {
const operation = state.getDispatchReplyOperation();
const queuedFinal = operation?.result?.kind === "failed" && operation.result.code === "run_stalled" && (operation.staleExpiryReason === "no_activity" || operation.staleExpiryReason === "stuck_recovery") ? dispatcher.sendFinalReply({
text: "⚠️ This turn was interrupted because it stopped making progress. Please try again.",
isError: true
}) : false;
if (state.turnAdoptionState && !state.turnAdoptionState.adopted && !state.inboundDedupeReplayUnsafe) releaseInboundDedupeIfClaimed();
else commitInboundDedupeIfClaimed();
recordProcessed("skipped", { reason: "reply_operation_aborted" });
markIdle("message_completed");
state.completeDispatchReplyOperation();
return attachSourceReplyDeliveryMode({
queuedFinal,
counts: dispatcher.getQueuedCounts(),
...state.turnLedger.hasVisibleDelivery() ? { observedReplyDelivery: true } : {}
});
};
const bindingState = {};
const emitMessageReceivedHooks$1 = () => {
emitMessageReceivedHooks({
ctx,
hookRunner,
sessionKey,
timestamp: state.timestamp,
buildContext: buildMessageReceivedHookContext
});
};
state.markProcessing();
if (await capturePendingConversationTurnReply({
cfg,
ctx
})) {
emitMessageReceivedHooks$1();
commitInboundDedupeIfClaimed();
recordProcessed("completed", { reason: "conversation-turn-reply" });
markIdle("message_completed");
return {
status: "complete",
result: attachSourceReplyDeliveryMode({
queuedFinal: false,
counts: dispatcher.getQueuedCounts(),
observedReplyDelivery: true
})
};
}
return {
status: "ready",
state: extendPreparedDispatchState(state, {
sendBindingNotice,
pluginOwnedBinding,
persistPluginBindingUserTurn,
sendPolicy,
chatType,
emptyFinalAllowedAsSilent,
noVisibleReplyFallbackDirected,
sourceReplyPolicy,
sourceReplyDeliveryRuntimeOptions,
sourceReplyDeliveryMode,
sessionStableSourceReplyDeliveryMode,
suppressAutomaticSourceDelivery,
suppressDelivery,
sendPolicyDenied,
deliverySuppressionReason,
suppressHookUserDelivery,
suppressHookReplyLifecycle,
reasoningPayloadsEnabled,
commentaryPayloadsEnabled,
attachSourceReplyDeliveryMode,
explicitCommandTurnCtx,
activeRunSafeCommandTurn,
shouldDeliverPluginBindingReply,
inboundDedupeClaim,
commitInboundDedupeIfClaimed,
finishReplyOperationBusyDispatch,
finishReplyOperationAbortedDispatch,
emitMessageReceivedHooks: emitMessageReceivedHooks$1,
bindingState
})
};
}
//#endregion
//#region src/auto-reply/reply/routing-policy.ts
/** Resolves whether replies should route to the originating channel or current surface. */
/** Computes source-routing and typing suppression for a reply turn. */
function resolveReplyRoutingDecision(params) {
const originatingChannel = normalizeMessageChannel(params.originatingChannel);
const providerChannel = normalizeMessageChannel(params.provider);
const surfaceChannel = normalizeMessageChannel(params.surface);
const currentSurface = providerChannel ?? surfaceChannel;
const isInternalWebchatTurn = currentSurface === "webchat" && (surfaceChannel === "webchat" || !surfaceChannel) && params.explicitDeliverRoute !== true;
const shouldRouteToOriginating = Boolean(!params.suppressDirectUserDelivery && !isInternalWebchatTurn && params.isRoutableChannel(originatingChannel) && params.originatingTo && originatingChannel !== currentSurface);
return {
originatingChannel,
currentSurface,
isInternalWebchatTurn,
shouldRouteToOriginating,
shouldSuppressTyping: params.suppressDirectUserDelivery === true || shouldRouteToOriginating || originatingChannel === "webchat"
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.prepare-delivery.ts
async function prepareDispatchDelivery(state) {
const { cfg, ctx, groupId, markInboundDedupeReplayUnsafe, replyRoute, sessionStoreEntry, turnLedger } = state;
const currentAcpSession = sessionStoreEntry.sessionKey ? readAcpSessionEntry({
cfg,
agentId: sessionStoreEntry.agentId,
sessionKey: sessionStoreEntry.sessionKey
}) : void 0;
const sessionEntryWithAcp = currentAcpSession?.entry ? {
...currentAcpSession.entry,
acp: currentAcpSession.acp
} : void 0;
const suppressAcpChildUserDelivery = isParentOwnedBackgroundAcpSession(sessionEntryWithAcp);
const normalizedRouteReplyChannel = normalizeMessageChannel(replyRoute.channel);
const normalizedProviderChannel = normalizeMessageChannel(ctx.Provider);
const normalizedSurfaceChannel = normalizeMessageChannel(ctx.Surface);
const normalizedCurrentSurface = normalizedProviderChannel ?? normalizedSurfaceChannel;
const effectiveExplicitDeliverRoute = ctx.ExplicitDeliverRoute === true || replyRoute.inheritedExternalRoute === true;
const isInternalWebchatTurn = normalizedCurrentSurface === "webchat" && (normalizedSurfaceChannel === "webchat" || !normalizedSurfaceChannel) && !effectiveExplicitDeliverRoute;
const routeReplyRuntime = Boolean(!suppressAcpChildUserDelivery && !isInternalWebchatTurn && normalizedRouteReplyChannel && replyRoute.to && normalizedRouteReplyChannel !== normalizedCurrentSurface) ? await loadRouteReplyRuntime() : void 0;
const { originatingChannel: routeReplyChannel, currentSurface, shouldRouteToOriginating, shouldSuppressTyping } = resolveReplyRoutingDecision({
provider: ctx.Provider,
surface: ctx.Surface,
explicitDeliverRoute: effectiveExplicitDeliverRoute,
originatingChannel: replyRoute.channel,
originatingTo: replyRoute.to,
suppressDirectUserDelivery: suppressAcpChildUserDelivery,
isRoutableChannel: routeReplyRuntime?.isRoutableChannel ?? (() => false)
});
const routeReplyTo = replyRoute.to;
const canRouteDurableBlockReply = Boolean(!suppressAcpChildUserDelivery && !isInternalWebchatTurn && routeReplyChannel && routeReplyTo && routeReplyChannel === normalizedCurrentSurface);
const deliveryChannel = shouldRouteToOriginating ? routeReplyChannel : currentSurface;
const replyContextAccountId = routeReplyChannel ? resolveReplyDeliveryAccountId(cfg, routeReplyChannel, replyRoute.accountId) : void 0;
let normalizeReplyMediaPaths;
const getNormalizeReplyMediaPaths = async () => {
if (normalizeReplyMediaPaths) return normalizeReplyMediaPaths;
const { createReplyMediaPathNormalizer } = await loadReplyMediaPathsRuntime();
normalizeReplyMediaPaths = createReplyMediaPathNormalizer({
cfg,
agentId: state.sessionAgentId,
sessionKey: state.acpDispatchSessionKey,
workspaceDir: state.workspaceDir,
messageProvider: deliveryChannel,
accountId: replyContextAccountId,
groupId,
groupChannel: ctx.GroupChannel,
groupSpace: ctx.GroupSpace,
requesterSenderId: ctx.SenderId,
requesterSenderName: ctx.SenderName,
requesterSenderUsername: ctx.SenderUsername,
requesterSenderE164: ctx.SenderE164
});
return normalizeReplyMediaPaths;
};
const normalizeReplyMediaPayload = async (payload) => {
if (!resolveSendableOutboundReplyParts(payload).hasMedia) return payload;
return await (await getNormalizeReplyMediaPaths())(payload);
};
const routeReplyToOriginating = async (payload, options) => {
const durableRouteAuthorized = options?.deliveryIntentId !== void 0 && canRouteDurableBlockReply;
const runtime = routeReplyRuntime ?? (durableRouteAuthorized ? await loadRouteReplyRuntime() : void 0);
if (!shouldRouteToOriginating && !durableRouteAuthorized || !routeReplyChannel || !routeReplyTo || !runtime) {
if (options?.deliveryIntentId) throw new Error("durable block reply route unavailable");
return null;
}
markInboundDedupeReplayUnsafe();
const agentRuntimeSessionKey = options?.sessionKey ?? (ctx.CommandSource === "native" ? resolveCommandTurnTargetSessionKey(ctx) ?? ctx.SessionKey : ctx.SessionKey);
const result = await runtime.routeReply({
payload,
channel: routeReplyChannel,
to: routeReplyTo,
agentId: state.sessionAgentId,
sessionKey: agentRuntimeSessionKey,
policySessionKey: options?.sessionKey ?? resolveCommandTurnTargetSessionKey(ctx) ?? ctx.SessionKey,
policyConversationType: resolveRoutedPolicyConversationType(ctx),
accountId: replyContextAccountId,
requesterSenderId: ctx.SenderId,
requesterSenderName: ctx.SenderName,
requesterSenderUsername: ctx.SenderUsername,
requesterSenderE164: ctx.SenderE164,
threadId: state.routeReplyThreadId,
replyDelivery: createReplyDeliveryContext(resolveReplyToMode(cfg, routeReplyChannel, replyContextAccountId, replyRoute.chatType), replyRoute.chatType),
cfg,
abortSignal: options?.abortSignal,
mirror: options?.mirror,
isGroup: state.isGroup,
groupId,
replyKind: options?.kind ?? "final",
runId: state.params.replyOptions?.runId,
responsePrefixContext: options?.responsePrefixContext,
deliveryIntentId: options?.deliveryIntentId
});
turnLedger.recordRoutedDelivery(payload, isRoutedReplyDelivered(result));
return result;
};
const isRoutedReplyDelivered = (result) => result.delivered;
/**
* Helper to send a payload via route-reply (async).
* Only used when actually routing to a different provider.
* Note: Only called when shouldRouteToOriginating is true, so
* routeReplyChannel and routeReplyTo are guaranteed to be defined.
*/
const sendPayloadAsync = async (payload, abortSignal, mirror, kind = "tool", deliveryIntentId) => {
if (!routeReplyRuntime && !deliveryIntentId) return null;
const effectiveAbortSignal = abortSignal ?? state.getDispatchAbortSignal();
if (effectiveAbortSignal?.aborted) return null;
const result = await routeReplyToOriginating(payload, {
abortSignal: effectiveAbortSignal,
mirror,
kind,
deliveryIntentId
});
if (result && !result.ok) {
logVerbose(`dispatch-from-config: route-reply failed: ${result.error ?? "unknown error"}`);
if (deliveryIntentId) throw new Error(result.error ?? "durable block reply delivery failed");
}
if (hasAskUserPayload(payload) && !effectiveAbortSignal?.aborted && !result?.delivered) throw new Error("ask_user prompt delivery failed");
return result;
};
const deliverBindingPayload = async (payload, mode, transcriptOwner) => {
const bindingPayload = setReplyPayloadMetadata(copyReplyPayloadMetadata(payload, { ...payload }), { sourceReplyTranscriptMirror: transcriptOwner ? {
sessionKey: transcriptOwner.sessionKey,
agentId: transcriptOwner.agentId,
...transcriptOwner.expectedSessionId ? { expectedSessionId: transcriptOwner.expectedSessionId } : {},
...transcriptOwner.transcriptWriteBlocked ? { transcriptWriteBlocked: true } : {}
} : void 0 });
const result = await routeReplyToOriginating(bindingPayload, {
kind: mode === "terminal" ? "final" : "tool",
sessionKey: transcriptOwner?.sessionKey
});
if (result) {
if (!result.ok) logVerbose(`dispatch-from-config: route-reply (plugin binding notice) failed: ${result.error ?? "unknown error"}`);
return result.delivered || result.suppressed === true;
}
markInboundDedupeReplayUnsafe();
return mode === "additive" ? turnLedger.sendQueued("tool", bindingPayload).queued : turnLedger.sendQueued("final", bindingPayload).queued;
};
return {
status: "ready",
state: extendPreparedDispatchState(state, {
suppressAcpChildUserDelivery,
normalizedCurrentSurface,
isInternalWebchatTurn,
routeReplyChannel,
canRouteDurableBlockReply,
shouldRouteToOriginating,
shouldSuppressTyping,
routeReplyTo,
deliveryChannel,
replyContextAccountId,
normalizeReplyMediaPayload,
routeReplyToOriginating,
isRoutedReplyDelivered,
sendPayloadAsync,
deliverBindingPayload
})
};
}
//#endregion
//#region src/channels/plugins/exec-approval-local.ts
function shouldSuppressLocalExecApprovalPrompt(params) {
const channel = params.channel ? normalizeChannelId(params.channel) : null;
if (!channel) return false;
return getChannelPlugin(channel)?.outbound?.shouldSuppressLocalPayloadPrompt?.({
cfg: params.cfg,
accountId: params.accountId,
payload: params.payload,
hint: {
kind: "approval-pending",
approvalKind: "exec",
nativeRouteActive: getGatewayNativeApprovalRuntime()?.routeCoordinator.hasActiveRuntime({
channel,
accountId: params.accountId,
approvalKind: "exec"
}) ?? hasActiveApprovalNativeRouteRuntime({
channel,
accountId: params.accountId,
approvalKind: "exec"
})
}
}) ?? false;
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.prepare-execution.ts
async function prepareDispatchExecution(state) {
const { cfg, ctx, isDispatchOperationAborted, markInboundDedupeReplayUnsafe, markProgress, noteCommentaryProgress, params, sendPayloadAsync, sessionKey, shouldEmitVerboseProgress, shouldRouteToOriginating, shouldSendToolSummaries, shouldSendVerboseProgressMessages, turnLedger } = state;
if (state.suppressDelivery) logVerbose(`Delivery suppressed by ${state.deliverySuppressionReason} for session ${state.sessionStoreEntry.sessionKey ?? sessionKey ?? "unknown"} — agent will still process the message`);
let didSendPlanStatusNotice = false;
const formatPlanUpdateText = (payload) => {
const explanation = payload.explanation?.replace(/\s+/g, " ").trim();
const steps = (payload.steps ?? []).map((entry) => ({
step: entry.step.replace(/\s+/g, " ").trim(),
status: entry.status
})).filter((entry) => entry.step);
if (steps.length > 0) return formatPlanChecklistLines(steps, {
maxLines: steps.length,
maxLineChars: 120
}).join("\n");
return explanation || "Planning next steps.";
};
const sendPlanUpdate = async (payload) => {
if (shouldSuppressProgressDelivery() || !shouldSendVerboseProgressMessages() || didSendPlanStatusNotice) return;
didSendPlanStatusNotice = true;
const replyPayload = {
text: formatPlanUpdateText(payload),
isStatusNotice: true
};
if (shouldRouteToOriginating) {
await sendPayloadAsync(replyPayload, void 0, false);
return;
}
markInboundDedupeReplayUnsafe();
turnLedger.sendQueued("tool", replyPayload);
};
const progressState = {
accumulatedBlockText: "",
accumulatedBlockTtsText: "",
acceptedReplyPayload: false,
blockCount: 0,
channelTransformSuppressed: false,
pendingDirectBlockReplyDelivery: Promise.resolve(),
progressCallbackStartTail: Promise.resolve()
};
const cleanBlockTtsDirectiveText = shouldCleanTtsDirectiveText({
cfg,
ttsAuto: state.sessionTtsAuto,
agentId: state.sessionAgentId,
channelId: state.deliveryChannel,
accountId: state.replyRoute.accountId
}) ? createTtsDirectiveTextStreamCleaner() : void 0;
const resolveToolDeliveryPayload = (payload) => {
if (shouldSuppressLocalExecApprovalPrompt({
channel: normalizeMessageChannel(ctx.Surface ?? ctx.Provider),
cfg,
accountId: ctx.AccountId,
payload
})) return null;
if (shouldSendToolSummaries()) return payload;
if (hasExecApprovalPayload(payload) || hasExecApprovalUnavailablePayload(payload)) return payload;
if (hasAskUserPayload(payload)) return payload;
if (isFastModeAutoProgressPayload(payload)) return payload;
if (!resolveSendableOutboundReplyParts(payload).hasMedia) return null;
return {
...payload,
text: void 0
};
};
const typing = resolveRunTypingPolicy({
requestedPolicy: params.replyOptions?.typingPolicy,
suppressTyping: state.sourceReplyPolicy.suppressTyping,
originatingChannel: state.routeReplyChannel,
systemEvent: shouldRouteToOriginating
});
const shouldSuppressProgressDelivery = () => state.sendPolicyDenied || state.suppressDelivery && !state.shouldDeliverVerboseProgressDespiteSourceSuppression();
const onToolResultFromReplyOptions = params.replyOptions?.onToolResult;
const onPlanUpdateFromReplyOptions = params.replyOptions?.onPlanUpdate;
const onApprovalEventFromReplyOptions = params.replyOptions?.onApprovalEvent;
const onPatchSummaryFromReplyOptions = params.replyOptions?.onPatchSummary;
const allowSuppressedSourceProgressCallbacks = params.replyOptions?.allowProgressCallbacksWhenSourceDeliverySuppressed === true;
const shouldAllowQuietChannelOwnedProgressCallbacks = (options) => options?.requiresToolSummaryVisibility === true && (params.replyOptions?.suppressDefaultToolProgressMessages === true || options.allowWhenToolSummariesHidden === true);
const waitForPendingDirectBlockReplyDelivery = (abortSignal) => waitForReplyDispatcherIdle({ waitForIdle: () => progressState.pendingDirectBlockReplyDelivery }, abortSignal);
const shouldForwardProgressCallback = (options) => {
if (options?.requiresToolSummaryVisibility === true && !shouldSendToolSummaries() && !shouldAllowQuietChannelOwnedProgressCallbacks(options)) return false;
return !state.suppressAutomaticSourceDelivery || allowSuppressedSourceProgressCallbacks && !state.sendPolicyDenied && options?.forwardWhenSourceDeliverySuppressed === true;
};
const preserveProgressCallbackStartOrder = params.replyOptions?.preserveProgressCallbackStartOrder === true;
const reserveProgressCallbackStart = () => {
const previousStart = progressState.progressCallbackStartTail;
let releaseStart;
progressState.progressCallbackStartTail = new Promise((resolve) => {
releaseStart = resolve;
});
return {
previousStart,
releaseStart: () => releaseStart?.()
};
};
const wrapProgressCallback = (callback, options) => {
if (!callback) return;
const runProgressCallback = async (args, noteCallbackStarted) => {
try {
if (isDispatchOperationAborted()) return;
state.getDispatchReplyOperation()?.recordActivity();
markProgress();
if (options?.waitForDirectBlockReplyDelivery) {
await waitForPendingDirectBlockReplyDelivery(state.getDispatchAbortOperation()?.abortSignal);
if (isDispatchOperationAborted()) return;
}
if (shouldForwardProgressCallback(options)) {
if (preserveProgressCallbackStartOrder && options?.onForward) await options.onForward(...args);
else if (!preserveProgressCallbackStartOrder) await options?.onForward?.(...args);
const callbackResult = callback(...args);
noteCallbackStarted();
const result = await callbackResult;
if (result === false) return result;
await options?.onVisible?.(...args);
}
return;
} finally {
noteCallbackStarted();
}
};
return (...args) => {
if (!preserveProgressCallbackStartOrder) return runProgressCallback(args, () => void 0);
const start = reserveProgressCallbackStart();
return (async () => {
await start.previousStart;
return await runProgressCallback(args, start.releaseStart);
})();
};
};
const standaloneCommentaryProgressVisible = shouldEmitVerboseProgress();
const resolveVerboseProgressVisibility = () => standaloneCommentaryProgressVisible && shouldSendVerboseProgressMessages() && !shouldSuppressProgressDelivery();
const { commentaryPayloadsEnabled, draftOwnsCommentaryProgress } = resolveTurnCommentaryProgressOwner({
commentaryPayloadsEnabled: state.commentaryPayloadsEnabled,
options: params.replyOptions,
resolveVerboseProgressVisibility
});
const deliverStandaloneCommentaryProgress = standaloneCommentaryProgressVisible && !draftOwnsCommentaryProgress;
const itemEventForwardingOptions = {
forwardWhenSourceDeliverySuppressed: true,
requiresToolSummaryVisibility: true
};
const canForwardItemEvents = Boolean(params.replyOptions?.onItemEvent);
const canForwardSuppressedSourceItemEvents = allowSuppressedSourceProgressCallbacks && !state.sendPolicyDenied && Boolean(params.replyOptions?.onItemEvent);
const shouldDeliverDurableCommentaryProgress = (payload) => deliverStandaloneCommentaryProgress && payload.kind === "preamble" && payload.suppressDurableProgress !== true;
const forwardItemEvent = canForwardItemEvents ? wrapProgressCallback(params.replyOptions?.onItemEvent, {
...itemEventForwardingOptions,
waitForDirectBlockReplyDelivery: true,
onForward: (payload) => preserveProgressCallbackStartOrder && shouldDeliverDurableCommentaryProgress(payload) ? noteCommentaryProgress(payload) : void 0
}) : void 0;
const canCaptureCliPreambleEvents = Boolean(params.replyOptions?.onItemEvent) && shouldBridgeCliPreambleEvents(params.replyOptions);
const onItemEvent = deliverStandaloneCommentaryProgress || canForwardItemEvents || canCaptureCliPreambleEvents ? async (payload) => {
if (isDispatchOperationAborted()) return;
if (!forwardItemEvent && deliverStandaloneCommentaryProgress) markProgress();
if ((!forwardItemEvent || !preserveProgressCallbackStartOrder) && shouldDeliverDurableCommentaryProgress(payload)) await noteCommentaryProgress(payload);
return await forwardItemEvent?.(payload);
} : void 0;
const replyResolver = params.replyResolver ?? (await state.traceReplyPhase("reply.load_reply_resolver", () => loadGetReplyFromConfigRuntime())).getReplyFromConfig;
const runtimeReplyConfig = state.preparedReplyDispatchRuntime?.config ?? cfg;
const replyConfig = withFullRuntimeReplyConfig(params.configOverride ? applyMergePatch(runtimeReplyConfig, params.configOverride) : runtimeReplyConfig);
state.recordAgentDispatchStarted();
return {
status: "ready",
state: extendPreparedDispatchState(state, {
sendPlanUpdate,
cleanBlockTtsDirectiveText,
resolveToolDeliveryPayload,
typing,
shouldSuppressProgressDelivery,
onToolResultFromReplyOptions,
onPlanUpdateFromReplyOptions,
onApprovalEventFromReplyOptions,
onPatchSummaryFromReplyOptions,
waitForPendingDirectBlockReplyDelivery,
shouldForwardProgressCallback,
preserveProgressCallbackStartOrder,
wrapProgressCallback,
deliverStandaloneCommentaryProgress,
canForwardSuppressedSourceItemEvents,
onItemEvent,
commentaryPayloadsEnabled,
replyResolver,
replyConfig,
progressState
})
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.plugin-binding.ts
function shouldBypassPluginOwnedBindingForCommand(ctx, cfg, replyOptions) {
if (ctx.CommandAuthorized !== void 0 && typeof ctx.CommandAuthorized !== "boolean") return false;
const commandTurn = resolveCommandTurnContext(ctx);
if ((commandTurn.kind === "native" || commandTurn.kind === "text-slash") && !commandTurn.authorized) return false;
if (isNativeCommandTurn(commandTurn) && commandTurn.authorized) return true;
if (!(commandTurn.kind === "text-slash" && commandTurn.authorized || commandTurn.kind === "normal" && typeof ctx.CommandAuthorized === "boolean" && ctx.CommandAuthorized) || !shouldHandleTextCommands({
cfg,
surface: ctx.Surface ?? ctx.Provider ?? "",
commandSource: ctx.CommandSource
})) return false;
const commandBody = normalizeCommandBody(commandTurn.body ?? resolveCommandContextText(ctx), { botUsername: ctx.BotUsername });
if (!commandBody.startsWith("/")) return false;
if (replyOptions?.[PLUGIN_COMMAND_DISPATCH]) return true;
const channel = resolveCommandChannel(ctx);
const match = matchPluginCommandInvocation(createPluginCommandRuntime(), commandBody, { channel });
if (match) {
if (replyOptions) replyOptions[PLUGIN_COMMAND_DISPATCH] = match.dispatch;
return true;
}
if (!isExplicitSourceReplyCommand(ctx, cfg)) return false;
if (resolveTextCommand(commandBody)) return true;
const provider = normalizeOptionalString(ctx.Provider ?? ctx.Surface);
if (commandTurn.commandName && findCommandByNativeName(commandTurn.commandName, provider, { includeBundledChannelFallback: true })) return true;
return false;
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.prepare-operation.ts
async function prepareDispatchOperation(state) {
const { attachSourceReplyDeliveryMode, cfg, chatType, commitInboundDedupeIfClaimed, completeDispatchReplyOperation, ctx, deliverySuppressionReason, dispatcher, emitMessageReceivedHooks, finishReplyOperationAbortedDispatch, hookRunner, isPreDispatchOperationAborted, markIdle, params, persistPluginBindingUserTurn, pluginOwnedBinding, recordProcessed, sendBindingNotice, sessionAgentId, sessionKey, sessionStoreEntry, suppressDelivery, turnLedger } = state;
const abortRuntime = params.fastAbortResolver ? null : await loadAbortRuntime();
const fastAbortResolver = params.fastAbortResolver ?? abortRuntime?.tryFastAbortFromMessage;
const formatAbortReplyTextResolver = params.formatAbortReplyTextResolver ?? abortRuntime?.formatAbortReplyText;
if (!fastAbortResolver || !formatAbortReplyTextResolver) throw new Error("abort runtime unavailable");
const finishFastCommand = async (fast) => {
if (pluginOwnedBinding) getSessionBindingService().touch(pluginOwnedBinding.bindingId, void 0, pluginOwnedBinding);
emitMessageReceivedHooks();
let queuedFinal = false;
let routedFinalCount = 0;
if (!suppressDelivery && fast.payload) {
const selectedModel = resolveSessionModelRef(cfg, sessionStoreEntry.entry, sessionAgentId);
const modelSelection = {
...selectedModel,
thinkLevel: sessionStoreEntry.entry?.thinkingLevel
};
const responsePrefixContext = {
identityName: normalizeOptionalString(resolveAgentIdentity(cfg, sessionAgentId)?.name),
provider: selectedModel.provider,
model: extractShortModelName(selectedModel.model),
modelFull: `${selectedModel.provider}/${selectedModel.model}`,
thinkingLevel: modelSelection.thinkLevel ?? "off"
};
const result = await state.routeReplyToOriginating(fast.payload, { responsePrefixContext });
if (result) {
queuedFinal = result.ok;
if (state.isRoutedReplyDelivered(result)) routedFinalCount += 1;
if (!result.ok) logVerbose(`dispatch-from-config: route-reply (${fast.logKind}) failed: ${result.error ?? "unknown error"}`);
} else {
state.markInboundDedupeReplayUnsafe();
params.replyOptions?.onModelSelected?.(modelSelection);
queuedFinal = dispatcher.sendFinalReply(fast.payload);
}
} else if (suppressDelivery) logVerbose(`dispatch-from-config: ${fast.logKind} reply suppressed by ${deliverySuppressionReason} (session=${sessionKey ?? "unknown"})`);
const counts = dispatcher.getQueuedCounts();
counts.final += routedFinalCount;
recordProcessed("completed", { reason: fast.reason });
markIdle("message_completed");
commitInboundDedupeIfClaimed();
completeDispatchReplyOperation();
return {
status: "complete",
result: attachSourceReplyDeliveryMode({
queuedFinal,
counts
})
};
};
const fastAbort = await fastAbortResolver({
ctx,
cfg,
isCommandTargetCurrent: params.replyOptions?.isCommandTargetCurrent
});
if (fastAbort.handled) return await finishFastCommand({
payload: { text: formatAbortReplyTextResolver(fastAbort.stoppedSubagents, fastAbort.rejectionReason, fastAbort.failedSubagents) },
reason: "fast_abort",
logKind: "fast_abort"
});
if (/^\s*\/approve(?:@[^\s]+)?(?:\s|$)/i.test(ctx.commandText)) {
const fastApprove = await (await loadFastApproveRuntime()).tryFastApproveFromMessage({
ctx,
cfg,
agentId: sessionAgentId,
sessionKey
});
if (fastApprove.handled) return await finishFastCommand({
...fastApprove.reply ? { payload: fastApprove.reply } : {},
reason: "before_dispatch_handled",
logKind: "fast_approve"
});
}
const admissionTicket = params.replyOptions?.[REPLY_ADMISSION_TICKET];
if (admissionTicket && !await admissionTicket.wait(params.replyOptions?.abortSignal)) return {
status: "complete",
result: finishReplyOperationAbortedDispatch()
};
const preDispatchAcquisition = await state.ensureDispatchReplyOperation("pre_dispatch", Boolean(pluginOwnedBinding));
if (preDispatchAcquisition.status === "aborted") return {
status: "complete",
result: finishReplyOperationAbortedDispatch()
};
if (preDispatchAcquisition.status === "busy") return {
status: "complete",
result: state.finishReplyOperationBusyDispatch({ dedupeDisposition: "release" })
};
const finishPluginBindingDispatch = async (outcome) => {
if (await turnLedger.settleQueued(state.getPreDispatchAbortSignal()) === "aborted" || isPreDispatchOperationAborted()) return {
status: "complete",
result: finishReplyOperationAbortedDispatch()
};
markIdle(outcome === "handled" ? "plugin_binding_dispatch" : `plugin_binding_${outcome}`);
recordProcessed("completed", { reason: `plugin-bound-${outcome}` });
commitInboundDedupeIfClaimed();
completeDispatchReplyOperation();
return {
status: "complete",
result: attachSourceReplyDeliveryMode({
queuedFinal: false,
counts: dispatcher.getQueuedCounts(),
...turnLedger.hasVisibleDelivery() ? { observedReplyDelivery: true } : {}
})
};
};
if (pluginOwnedBinding) {
if (isPreDispatchOperationAborted()) return {
status: "complete",
result: finishReplyOperationAbortedDispatch()
};
getSessionBindingService().touch(pluginOwnedBinding.bindingId, void 0, pluginOwnedBinding);
params.replyOptions ??= {};
if (shouldBypassPluginOwnedBindingForCommand(ctx, cfg, params.replyOptions)) logVerbose(`plugin-bound inbound command escaped plugin binding (plugin=${pluginOwnedBinding.pluginId} session=${sessionKey ?? "unknown"}); falling through to command processing`);
else if (state.sendPolicyDenied || suppressDelivery && !state.suppressAutomaticSourceDelivery) logVerbose(`plugin-bound inbound skipped under ${deliverySuppressionReason} (plugin=${pluginOwnedBinding.pluginId} session=${sessionKey ?? "unknown"}); falling through to suppressed agent processing`);
else {
logVerbose(`plugin-bound inbound routed to ${pluginOwnedBinding.pluginId} conversation=${pluginOwnedBinding.conversationId}`);
const bindingAuthorization = resolveCommandAuthorization({
ctx,
cfg,
commandAuthorized: ctx.CommandAuthorized
});
const targetedClaimOutcome = hookRunner?.runInboundClaimForPluginOutcome ? await (async () => {
await runWithDispatchAbortSignal(state.getPreDispatchAbortSignal(), state.prepareHookMediaMetadata, state.trackDispatchLifecycleWork);
if (isPreDispatchOperationAborted()) throw new DispatchReplyOperationAbortedError();
const authorizedInboundClaimEvent = {
...state.hookState.inboundClaimEvent,
senderIsOwner: bindingAuthorization.senderIsOwner
};
return await state.runWithDispatchLifecycleAdmission(async () => await hookRunner.runInboundClaimForPluginOutcome(pluginOwnedBinding.pluginId, authorizedInboundClaimEvent, {
...state.hookState.inboundClaimContext,
pluginBinding: pluginOwnedBinding
}));
})() : (() => {
return getGlobalPluginRegistry()?.plugins.some((plugin) => plugin.id === pluginOwnedBinding.pluginId && plugin.status === "loaded") ?? false ? { status: "no_handler" } : { status: "missing_plugin" };
})();
if (isPreDispatchOperationAborted()) return {
status: "complete",
result: finishReplyOperationAbortedDispatch()
};
switch (targetedClaimOutcome.status) {
case "handled": {
const transcriptOwner = await persistPluginBindingUserTurn();
if (targetedClaimOutcome.result.reply && state.shouldDeliverPluginBindingReply) await state.deliverBindingPayload(targetedClaimOutcome.result.reply, "terminal", transcriptOwner);
return await finishPluginBindingDispatch("handled");
}
case "missing_plugin":
case "no_handler":
state.bindingState.pluginFallbackReason = targetedClaimOutcome.status === "missing_plugin" ? "plugin-bound-fallback-missing-plugin" : "plugin-bound-fallback-no-handler";
if ((chatType === "group" || chatType === "channel") && ctx.WasMentioned === false && !state.explicitCommandTurnCtx && ctx.GroupRequireMention !== false) {
markIdle("plugin_binding_fallback_unmentioned");
recordProcessed("completed", { reason: state.bindingState.pluginFallbackReason });
commitInboundDedupeIfClaimed();
completeDispatchReplyOperation();
return {
status: "complete",
result: attachSourceReplyDeliveryMode({
queuedFinal: false,
counts: dispatcher.getQueuedCounts()
})
};
}
if (!hasShownPluginBindingFallbackNotice(pluginOwnedBinding.bindingId, pluginOwnedBinding)) {
if (await sendBindingNotice({ text: buildPluginBindingUnavailableText(pluginOwnedBinding) }, "additive")) markPluginBindingFallbackNoticeShown(pluginOwnedBinding.bindingId, pluginOwnedBinding);
}
break;
case "declined": {
const transcriptOwner = await persistPluginBindingUserTurn();
await sendBindingNotice({ text: buildPluginBindingDeclinedText(pluginOwnedBinding) }, "terminal", transcriptOwner);
return await finishPluginBindingDispatch("declined");
}
case "error": {
const transcriptOwner = await persistPluginBindingUserTurn();
logVerbose(`plugin-bound inbound claim failed for ${pluginOwnedBinding.pluginId}: ${targetedClaimOutcome.error}`);
await sendBindingNotice({ text: buildPluginBindingErrorText(pluginOwnedBinding) }, "terminal", transcriptOwner);
return await finishPluginBindingDispatch("error");
}
}
}
}
emitMessageReceivedHooks();
return {
status: "ready",
state
};
}
//#endregion
//#region src/auto-reply/reply/dispatch-from-config.ts
/** Main reply dispatch pipeline from finalized config/context to delivery payloads. */
/** Dispatches a reply from config, context, command handling, agent run, and delivery policy. */
async function dispatchReplyFromConfig(params) {
return await dispatchReplyFromConfigWithQueuePolicy(params, false);
}
/** Low-level plugin dispatch must reach queue policy before waiting on the active reply owner. */
async function dispatchLowLevelChannelReplyFromConfig(params) {
return await dispatchReplyFromConfigWithQueuePolicy(params, true);
}
async function dispatchReplyFromConfigWithQueuePolicy(params, allowActiveQueueResolution) {
const ticket = reserveReplyAdmissionTicket([params.ctx.SessionKey, params.ctx.CommandTargetSessionKey]);
const ticketedParams = ticket ? {
...params,
replyOptions: {
...params.replyOptions,
[REPLY_ADMISSION_TICKET]: ticket
}
} : params;
const messageAuditTerminal = createInboundMessageAuditTerminal(params);
let refreshedSessionSnapshot = false;
try {
while (true) try {
const result = await dispatchReplyFromConfigInner(ticketedParams, messageAuditTerminal, allowActiveQueueResolution);
messageAuditTerminal?.finishSuccess(result);
return result;
} catch (error) {
if (error instanceof DispatchSessionRefreshRequiredError && !refreshedSessionSnapshot && params.replyOptions?.abortSignal?.aborted !== true) {
refreshedSessionSnapshot = true;
continue;
}
messageAuditTerminal?.finishError();
throw error;
}
} finally {
ticket?.release();
}
}
async function dispatchReplyFromConfigInner(params, messageAuditTerminal, allowActiveQueueResolution) {
const gathered = await gatherDispatchRequest(params, messageAuditTerminal, allowActiveQueueResolution);
if (gathered.status === "complete") return gathered.result;
return await withPluginRuntimeRegistryScope(gathered.state.pluginRegistry, async () => {
const context = await prepareDispatchOperationContext((await prepareDispatchDelivery(gathered.state)).state);
if (context.status === "complete") return context.result;
const errorState = context.state;
try {
const operation = await prepareDispatchOperation(context.state);
if (operation.status === "complete") return operation.result;
const route = await chooseDispatchRoute(operation.state);
if (route.status === "complete") return route.result;
const executed = await executeDispatch((await prepareDispatchExecution(route.state)).state);
if (executed.status === "complete") return executed.result;
return (await finalizeDispatchAndAudit(executed.state)).result;
} catch (err) {
const { failDispatchReplyOperation, finishReplyOperationAbortedDispatch, inboundDedupeClaim, markIdle, recordAgentDispatchCompleted, recordProcessed } = errorState;
if (isDispatchReplyOperationAbortedError(err)) return finishReplyOperationAbortedDispatch();
if (inboundDedupeClaim.status === "claimed") {
if (errorState.turnAdoptionState?.adopted || errorState.inboundDedupeReplayUnsafe) commitInboundDedupe(inboundDedupeClaim.key);
else releaseInboundDedupe(inboundDedupeClaim.key);
}
if (err instanceof DispatchSessionRefreshRequiredError) markIdle("session_refresh");
else {
recordAgentDispatchCompleted("error", { error: String(err) });
recordProcessed("error", { error: String(err) });
markIdle("message_error");
}
failDispatchReplyOperation(err);
throw err;
}
});
}
//#endregion
export { withDispatchProcessedOutcomeSink as a, resetInboundDedupe as i, dispatchReplyFromConfig as n, emitInboundMessageAuditTerminal as o, emitMessageReceivedHooks as r, dispatchLowLevelChannelReplyFromConfig as t };