@@ -42,6 +42,7 @@ import { stripFormattedReasoningMessage } from "../../shared/text/formatted-reas
|
42 | 42 | import { parseInlineDirectives } from "../../utils/directive-tags.js"; |
43 | 43 | import { |
44 | 44 | INTERNAL_MESSAGE_CHANNEL, |
| 45 | +normalizeMessageChannel, |
45 | 46 | type GatewayClientMode, |
46 | 47 | type GatewayClientName, |
47 | 48 | } from "../../utils/message-channel.js"; |
@@ -630,17 +631,39 @@ function hasCurrentSourceReplyContext(input: RunMessageActionParams): boolean {
|
630 | 631 | ); |
631 | 632 | } |
632 | 633 | |
633 | | -function shouldUseInternalSourceReplySink( |
| 634 | +async function hasConfiguredCurrentSourceChannel(input: RunMessageActionParams): Promise<boolean> { |
| 635 | +const provider = |
| 636 | +normalizeMessageChannel(input.toolContext?.currentChannelProvider) ?? |
| 637 | +normalizeOptionalLowercaseString(input.toolContext?.currentChannelProvider); |
| 638 | +if (!provider || provider === INTERNAL_MESSAGE_CHANNEL) { |
| 639 | +return false; |
| 640 | +} |
| 641 | +if (!resolveOutboundChannelPlugin({ channel: provider, cfg: input.cfg, allowBootstrap: true })) { |
| 642 | +return false; |
| 643 | +} |
| 644 | +const configuredChannels = await listConfiguredMessageChannels(input.cfg); |
| 645 | +return configuredChannels.some((channel) => channel === provider); |
| 646 | +} |
| 647 | + |
| 648 | +async function shouldUseInternalSourceReplySink( |
634 | 649 | input: RunMessageActionParams, |
635 | 650 | params: Record<string, unknown>, |
636 | 651 | ) { |
637 | | -return ( |
| 652 | +const hasImplicitCurrentSourceRoute = |
638 | 653 | input.action === "send" && |
639 | 654 | input.sourceReplyDeliveryMode === "message_tool_only" && |
640 | 655 | hasCurrentSourceReplyContext(input) && |
641 | 656 | Boolean(input.sessionKey?.trim()) && |
642 | | -!hasExplicitRouteParam(params) |
643 | | -); |
| 657 | +!hasExplicitRouteParam(params); |
| 658 | +if (!hasImplicitCurrentSourceRoute) { |
| 659 | +return false; |
| 660 | +} |
| 661 | +if (!normalizeOptionalString(input.toolContext?.currentChannelId)) { |
| 662 | +return true; |
| 663 | +} |
| 664 | +// Configured current-source channels can infer the target and deliver through |
| 665 | +// the normal plugin path; the sink is only the private fallback. |
| 666 | +return !(await hasConfiguredCurrentSourceChannel(input)); |
644 | 667 | } |
645 | 668 | |
646 | 669 | async function runGatewayPluginMessageActionOrNull(params: { |
@@ -1404,7 +1427,7 @@ export async function runMessageAction(
|
1404 | 1427 | if (action === "send" && hasPollCreationParams(params)) { |
1405 | 1428 | throw new Error('Poll fields require action "poll"; use action "poll" instead of "send".'); |
1406 | 1429 | } |
1407 | | -if (shouldUseInternalSourceReplySink(input, params)) { |
| 1430 | +if (await shouldUseInternalSourceReplySink(input, params)) { |
1408 | 1431 | return handleInternalSourceReplySendAction({ ...input, agentId: resolvedAgentId }, params); |
1409 | 1432 | } |
1410 | 1433 | applyImplicitSourceReplySendPolicy(input, params); |
|