fix(agents): prefer target agent's bound Matrix account for subagent spawns (#67508)

Merged via squash.

Prepared head SHA: 9300111038
Co-authored-by: lukeboyett <46942646+lukeboyett@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
lukeboyett
2026-04-18 14:02:53 -04:00
committed by GitHub
parent 3f3bc97cd3
commit c39314c14a
38 changed files with 1781 additions and 74 deletions

View File

@@ -464,6 +464,7 @@ async function dispatchDiscordComponentEvent(params: {
SenderTag: senderTag,
GroupSubject: groupSubject,
GroupChannel: groupChannel,
MemberRoleIds: interactionCtx.memberRoleIds,
GroupSystemPrompt: interactionCtx.isDirectMessage ? undefined : groupSystemPrompt,
GroupSpace: guildInfo?.id ?? guildInfo?.slug ?? interactionCtx.rawGuildId ?? undefined,
OwnerAllowFrom: ownerAllowFrom,

View File

@@ -1083,6 +1083,7 @@ export async function preflightDiscordMessage(
messageChannelId,
author,
sender,
memberRoleIds,
channelInfo,
channelName,
isGuildMessage,

View File

@@ -44,6 +44,7 @@ export type DiscordMessagePreflightContext = DiscordMessagePreflightSharedFields
messageChannelId: string;
author: User;
sender: DiscordSenderIdentity;
memberRoleIds: string[];
channelInfo: DiscordChannelInfo | null;
channelName?: string;

View File

@@ -144,6 +144,7 @@ export async function processDiscordMessage(
displayChannelSlug,
guildInfo,
guildSlug,
memberRoleIds,
channelConfig,
baseSessionKey,
boundSessionKey,
@@ -481,6 +482,7 @@ export async function processDiscordMessage(
SenderTag: senderTag,
GroupSubject: groupSubject,
GroupChannel: groupChannel,
MemberRoleIds: memberRoleIds,
UntrustedContext: untrustedContext,
GroupSystemPrompt: isGuildMessage ? groupSystemPrompt : undefined,
GroupSpace: isGuildMessage ? (guildInfo?.id ?? guildSlug) || undefined : undefined,

View File

@@ -50,6 +50,7 @@ describe("buildDiscordNativeCommandContext", () => {
interactionId: "interaction-1",
channelId: "chan-1",
threadParentId: "parent-1",
memberRoleIds: ["admin"],
guildName: "Ops",
channelTopic: "Production alerts only",
channelConfig: {
@@ -82,6 +83,8 @@ describe("buildDiscordNativeCommandContext", () => {
expect(ctx.ChatType).toBe("channel");
expect(ctx.ConversationLabel).toBe("chan-1");
expect(ctx.GroupSubject).toBe("Ops");
expect(ctx.GroupSpace).toBe("guild-1");
expect(ctx.MemberRoleIds).toEqual(["admin"]);
expect(ctx.GroupSystemPrompt).toBe("Use the runbook.");
expect(ctx.OwnerAllowFrom).toEqual(["user-1"]);
expect(ctx.MessageThreadId).toBe("chan-1");

View File

@@ -13,6 +13,8 @@ export type BuildDiscordNativeCommandContextParams = {
interactionId: string;
channelId: string;
threadParentId?: string;
memberRoleIds?: string[];
guildId?: string;
guildName?: string;
channelTopic?: string;
channelConfig?: DiscordChannelConfigResolved | null;
@@ -67,6 +69,10 @@ export function buildDiscordNativeCommandContext(params: BuildDiscordNativeComma
ChatType: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
ConversationLabel: conversationLabel,
GroupSubject: params.isGuild ? params.guildName : undefined,
GroupSpace: params.isGuild
? (params.guildInfo?.id ?? params.guildInfo?.slug ?? params.guildId)
: undefined,
MemberRoleIds: params.memberRoleIds,
GroupSystemPrompt: groupSystemPrompt,
UntrustedContext: untrustedContext,
OwnerAllowFrom: ownerAllowFrom,

View File

@@ -1183,6 +1183,8 @@ async function dispatchDiscordCommandInteraction(params: {
interactionId,
channelId,
threadParentId,
memberRoleIds,
guildId: interaction.guild?.id,
guildName: interaction.guild?.name,
channelTopic: channel && "topic" in channel ? (channel.topic ?? undefined) : undefined,
channelConfig,

View File

@@ -651,6 +651,7 @@ describe("msteams monitor handler authz", () => {
expect(dispatched?.ctxPayload).toMatchObject({
BodyForAgent:
"[Thread history]\nAlice: Allowed context\n[/Thread history]\n\nCurrent message",
GroupSpace: "team123",
});
expect(
String((dispatched?.ctxPayload as { BodyForAgent?: string }).BodyForAgent),

View File

@@ -773,6 +773,7 @@ export function createMSTeamsMessageHandler(deps: MSTeamsMessageHandlerDeps) {
ChatType: isDirectMessage ? "direct" : isChannel ? "channel" : "group",
ConversationLabel: envelopeFrom,
GroupSubject: !isDirectMessage ? conversationType : undefined,
GroupSpace: teamId,
SenderName: senderName,
SenderId: senderId,
Provider: "msteams" as const,

View File

@@ -196,6 +196,7 @@ describe("slack prepareSlackMessage inbound contract", () => {
expect(prepared).toBeTruthy();
expectInboundContextContract(prepared!.ctxPayload as any);
expect(prepared!.ctxPayload.GroupSpace).toBe("T1");
});
it("does not enable Slack status reactions when the message timestamp is missing", async () => {

View File

@@ -736,6 +736,7 @@ export async function prepareSlackMessage(params: {
ChatType: isDirectMessage ? "direct" : "channel",
ConversationLabel: envelopeFrom,
GroupSubject: isRoomish ? roomLabel : undefined,
GroupSpace: ctx.teamId || undefined,
GroupSystemPrompt: groupSystemPrompt,
UntrustedContext: untrustedChannelMetadata ? [untrustedChannelMetadata] : undefined,
SenderName: senderName,

View File

@@ -983,9 +983,10 @@ describe("slack slash command session metadata", () => {
expect(recordSessionMetaFromInboundMock).toHaveBeenCalledTimes(1);
const call = recordSessionMetaFromInboundMock.mock.calls[0]?.[0] as {
sessionKey?: string;
ctx?: { OriginatingChannel?: string };
ctx?: { GroupSpace?: string; OriginatingChannel?: string };
};
expect(call.ctx?.OriginatingChannel).toBe("slack");
expect(call.ctx?.GroupSpace).toBe("T1");
expect(call.sessionKey).toBeDefined();
});

View File

@@ -577,6 +577,7 @@ export async function registerSlackMonitorSlashCommands(params: {
: `slack:group:${command.channel_id}`,
}) ?? (isDirectMessage ? senderName : roomLabel),
GroupSubject: isRoomish ? roomLabel : undefined,
GroupSpace: ctx.teamId || undefined,
GroupSystemPrompt: groupSystemPrompt,
UntrustedContext: untrustedChannelMetadata ? [untrustedChannelMetadata] : undefined,
SenderName: senderName,