
























@@ -67,6 +67,7 @@ import type {
6767DispatchFromConfigParams,
6868DispatchFromConfigResult,
6969} from "./dispatch-from-config.types.js";
70+import { resolveEffectiveReplyRoute } from "./effective-reply-route.js";
7071import { claimInboundDedupe, commitInboundDedupe, releaseInboundDedupe } from "./inbound-dedupe.js";
7172import { resolveReplyRoutingDecision } from "./routing-policy.js";
7273import { resolveRunTypingPolicy } from "./typing-policy.js";
@@ -105,33 +106,6 @@ function loadReplyMediaPathsRuntime() {
105106return replyMediaPathsRuntimePromise;
106107}
107108108-function isSystemEventProvider(provider?: string): boolean {
109-return provider === "heartbeat" || provider === "cron-event" || provider === "exec-event";
110-}
111-112-function resolveEffectiveReplyRoute(params: {
113-ctx: Pick<FinalizedMsgContext, "Provider" | "OriginatingChannel" | "OriginatingTo" | "AccountId">;
114-entry?: Pick<SessionEntry, "deliveryContext" | "lastChannel" | "lastTo" | "lastAccountId">;
115-}): { channel?: string; to?: string; accountId?: string } {
116-if (!isSystemEventProvider(params.ctx.Provider)) {
117-return {
118-channel: params.ctx.OriginatingChannel,
119-to: params.ctx.OriginatingTo,
120-accountId: params.ctx.AccountId,
121-};
122-}
123-const persistedDeliveryContext = params.entry?.deliveryContext;
124-return {
125-channel:
126-params.ctx.OriginatingChannel ??
127-persistedDeliveryContext?.channel ??
128-params.entry?.lastChannel,
129-to: params.ctx.OriginatingTo ?? persistedDeliveryContext?.to ?? params.entry?.lastTo,
130-accountId:
131-params.ctx.AccountId ?? persistedDeliveryContext?.accountId ?? params.entry?.lastAccountId,
132-};
133-}
134-135109async function maybeApplyTtsToReplyPayload(
136110params: Parameters<Awaited<ReturnType<typeof loadTtsRuntime>>["maybeApplyTtsToPayload"]>[0],
137111) {
@@ -314,7 +288,7 @@ export async function dispatchReplyFromConfig(
314288"",
315289) ?? "off",
316290});
317-const effectiveReplyRoute = resolveEffectiveReplyRoute({ ctx, entry: sessionStoreEntry.entry });
291+const replyRoute = resolveEffectiveReplyRoute({ ctx, entry: sessionStoreEntry.entry });
318292// Restore route thread context only from the active turn or the thread-scoped session key.
319293// Do not read thread ids from the normalised session store here: `origin.threadId` can be
320294// folded back into lastThreadId/deliveryContext during store normalisation and resurrect a
@@ -347,7 +321,7 @@ export async function dispatchReplyFromConfig(
347321//
348322// Debug: `pnpm test src/auto-reply/reply/dispatch-from-config.test.ts`
349323const suppressAcpChildUserDelivery = isParentOwnedBackgroundAcpSession(sessionStoreEntry.entry);
350-const normalizedOriginatingChannel = normalizeMessageChannel(effectiveReplyRoute.channel);
324+const normalizedRouteReplyChannel = normalizeMessageChannel(replyRoute.channel);
351325const normalizedProviderChannel = normalizeMessageChannel(ctx.Provider);
352326const normalizedSurfaceChannel = normalizeMessageChannel(ctx.Surface);
353327const normalizedCurrentSurface = normalizedProviderChannel ?? normalizedSurfaceChannel;
@@ -358,30 +332,34 @@ export async function dispatchReplyFromConfig(
358332const hasRouteReplyCandidate = Boolean(
359333!suppressAcpChildUserDelivery &&
360334!isInternalWebchatTurn &&
361-normalizedOriginatingChannel &&
362-effectiveReplyRoute.to &&
363-normalizedOriginatingChannel !== normalizedCurrentSurface,
335+normalizedRouteReplyChannel &&
336+replyRoute.to &&
337+normalizedRouteReplyChannel !== normalizedCurrentSurface,
364338);
365339const routeReplyRuntime = hasRouteReplyCandidate ? await loadRouteReplyRuntime() : undefined;
366-const { originatingChannel, currentSurface, shouldRouteToOriginating, shouldSuppressTyping } =
367-resolveReplyRoutingDecision({
368-provider: ctx.Provider,
369-surface: ctx.Surface,
370-explicitDeliverRoute: ctx.ExplicitDeliverRoute,
371-originatingChannel: effectiveReplyRoute.channel,
372-originatingTo: effectiveReplyRoute.to,
373-suppressDirectUserDelivery: suppressAcpChildUserDelivery,
374-isRoutableChannel: routeReplyRuntime?.isRoutableChannel ?? (() => false),
375-});
376-const originatingTo = effectiveReplyRoute.to;
377-const ttsChannel = shouldRouteToOriginating ? originatingChannel : currentSurface;
340+const {
341+originatingChannel: routeReplyChannel,
342+ currentSurface,
343+ shouldRouteToOriginating,
344+ shouldSuppressTyping,
345+} = resolveReplyRoutingDecision({
346+provider: ctx.Provider,
347+surface: ctx.Surface,
348+explicitDeliverRoute: ctx.ExplicitDeliverRoute,
349+originatingChannel: replyRoute.channel,
350+originatingTo: replyRoute.to,
351+suppressDirectUserDelivery: suppressAcpChildUserDelivery,
352+isRoutableChannel: routeReplyRuntime?.isRoutableChannel ?? (() => false),
353+});
354+const routeReplyTo = replyRoute.to;
355+const deliveryChannel = shouldRouteToOriginating ? routeReplyChannel : currentSurface;
378356const { createReplyMediaPathNormalizer } = await loadReplyMediaPathsRuntime();
379357const normalizeReplyMediaPaths = createReplyMediaPathNormalizer({
380358 cfg,
381359sessionKey: acpDispatchSessionKey,
382360workspaceDir: resolveAgentWorkspaceDir(cfg, sessionAgentId),
383-messageProvider: ttsChannel,
384-accountId: effectiveReplyRoute.accountId,
361+messageProvider: deliveryChannel,
362+accountId: replyRoute.accountId,
385363 groupId,
386364groupChannel: ctx.GroupChannel,
387365groupSpace: ctx.GroupSpace,
@@ -401,19 +379,19 @@ export async function dispatchReplyFromConfig(
401379payload: ReplyPayload,
402380options?: { abortSignal?: AbortSignal; mirror?: boolean },
403381) => {
404-if (!shouldRouteToOriginating || !originatingChannel || !originatingTo || !routeReplyRuntime) {
382+if (!shouldRouteToOriginating || !routeReplyChannel || !routeReplyTo || !routeReplyRuntime) {
405383return null;
406384}
407385return await routeReplyRuntime.routeReply({
408386 payload,
409-channel: originatingChannel,
410-to: originatingTo,
387+channel: routeReplyChannel,
388+to: routeReplyTo,
411389sessionKey: ctx.SessionKey,
412390policySessionKey:
413391ctx.CommandSource === "native"
414392 ? (ctx.CommandTargetSessionKey ?? ctx.SessionKey)
415393 : ctx.SessionKey,
416-accountId: effectiveReplyRoute.accountId,
394+accountId: replyRoute.accountId,
417395requesterSenderId: ctx.SenderId,
418396requesterSenderName: ctx.SenderName,
419397requesterSenderUsername: ctx.SenderUsername,
@@ -431,7 +409,7 @@ export async function dispatchReplyFromConfig(
431409 * Helper to send a payload via route-reply (async).
432410 * Only used when actually routing to a different provider.
433411 * Note: Only called when shouldRouteToOriginating is true, so
434- * originatingChannel and originatingTo are guaranteed to be defined.
412+ * routeReplyChannel and routeReplyTo are guaranteed to be defined.
435413 */
436414const sendPayloadAsync = async (
437415payload: ReplyPayload,
@@ -440,7 +418,7 @@ export async function dispatchReplyFromConfig(
440418): Promise<void> => {
441419// Keep the runtime guard explicit because this helper is called from nested
442420// reply callbacks where TypeScript cannot narrow shouldRouteToOriginating.
443-if (!routeReplyRuntime || !originatingChannel || !originatingTo) {
421+if (!routeReplyRuntime || !routeReplyChannel || !routeReplyTo) {
444422return;
445423}
446424if (abortSignal?.aborted) {
@@ -500,9 +478,9 @@ export async function dispatchReplyFromConfig(
500478entry: sessionStoreEntry.entry,
501479sessionKey: sessionStoreEntry.sessionKey ?? sessionKey,
502480channel:
503-(shouldRouteToOriginating ? originatingChannel : undefined) ??
481+(shouldRouteToOriginating ? routeReplyChannel : undefined) ??
504482sessionStoreEntry.entry?.channel ??
505-effectiveReplyRoute.channel ??
483+replyRoute.channel ??
506484ctx.Surface ??
507485ctx.Provider ??
508486undefined,
@@ -670,7 +648,7 @@ export async function dispatchReplyFromConfig(
670648const ttsPayload = await maybeApplyTtsToReplyPayload({
671649 payload,
672650 cfg,
673-channel: ttsChannel,
651+channel: deliveryChannel,
674652kind: "final",
675653 inboundAudio,
676654ttsAuto: sessionTtsAuto,
@@ -740,11 +718,11 @@ export async function dispatchReplyFromConfig(
740718images: params.replyOptions?.images,
741719 inboundAudio,
742720 sessionTtsAuto,
743- ttsChannel,
721+ttsChannel: deliveryChannel,
744722suppressUserDelivery: suppressHookUserDelivery,
745723 shouldRouteToOriginating,
746- originatingChannel,
747- originatingTo,
724+originatingChannel: routeReplyChannel,
725+originatingTo: routeReplyTo,
748726 shouldSendToolSummaries,
749727 sendPolicy,
750728},
@@ -910,7 +888,7 @@ export async function dispatchReplyFromConfig(
910888requestedPolicy: params.replyOptions?.typingPolicy,
911889suppressTyping:
912890suppressDelivery || params.replyOptions?.suppressTyping === true || shouldSuppressTyping,
913- originatingChannel,
891+originatingChannel: routeReplyChannel,
914892systemEvent: shouldRouteToOriginating,
915893});
916894const suppressDefaultToolProgressMessages =
@@ -937,7 +915,7 @@ export async function dispatchReplyFromConfig(
937915const ttsPayload = await maybeApplyTtsToReplyPayload({
938916 payload,
939917 cfg,
940-channel: ttsChannel,
918+channel: deliveryChannel,
941919kind: "tool",
942920 inboundAudio,
943921ttsAuto: sessionTtsAuto,
@@ -1038,7 +1016,7 @@ export async function dispatchReplyFromConfig(
10381016const ttsPayload = await maybeApplyTtsToReplyPayload({
10391017 payload,
10401018 cfg,
1041-channel: ttsChannel,
1019+channel: deliveryChannel,
10421020kind: "block",
10431021 inboundAudio,
10441022ttsAuto: sessionTtsAuto,
@@ -1069,11 +1047,11 @@ export async function dispatchReplyFromConfig(
10691047images: params.replyOptions?.images,
10701048 inboundAudio,
10711049 sessionTtsAuto,
1072- ttsChannel,
1050+ttsChannel: deliveryChannel,
10731051suppressUserDelivery: suppressHookUserDelivery,
10741052 shouldRouteToOriginating,
1075- originatingChannel,
1076- originatingTo,
1053+originatingChannel: routeReplyChannel,
1054+originatingTo: routeReplyTo,
10771055 shouldSendToolSummaries,
10781056 sendPolicy,
10791057isTailDispatch: true,
@@ -1126,7 +1104,7 @@ export async function dispatchReplyFromConfig(
11261104const ttsSyntheticReply = await maybeApplyTtsToReplyPayload({
11271105payload: { text: accumulatedBlockText },
11281106 cfg,
1129-channel: ttsChannel,
1107+channel: deliveryChannel,
11301108kind: "final",
11311109 inboundAudio,
11321110ttsAuto: sessionTtsAuto,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。