fix: fail-closed shared-session reply routing (#24571) (thanks @brandonwise)

This commit is contained in:
Peter Steinberger
2026-02-25 01:41:04 +00:00
parent e28803503d
commit 885452f5c1
8 changed files with 180 additions and 14 deletions

View File

@@ -191,6 +191,49 @@ describe("deliverAgentCommandResult", () => {
);
});
it("uses runContext turn source over stale session last route", async () => {
await runDelivery({
opts: {
message: "hello",
deliver: true,
runContext: {
messageChannel: "whatsapp",
currentChannelId: "+15559876543",
accountId: "work",
},
},
sessionEntry: {
lastChannel: "slack",
lastTo: "U_WRONG",
lastAccountId: "wrong",
} as SessionEntry,
});
expect(mocks.resolveOutboundTarget).toHaveBeenCalledWith(
expect.objectContaining({ channel: "whatsapp", to: "+15559876543", accountId: "work" }),
);
});
it("does not reuse session lastTo when runContext source omits currentChannelId", async () => {
await runDelivery({
opts: {
message: "hello",
deliver: true,
runContext: {
messageChannel: "whatsapp",
},
},
sessionEntry: {
lastChannel: "slack",
lastTo: "U_WRONG",
} as SessionEntry,
});
expect(mocks.resolveOutboundTarget).toHaveBeenCalledWith(
expect.objectContaining({ channel: "whatsapp", to: undefined }),
);
});
it("prefixes nested agent outputs with context", async () => {
const runtime = createRuntime();
await runDelivery({

View File

@@ -71,6 +71,10 @@ export async function deliverAgentCommandResult(params: {
const { cfg, deps, runtime, opts, sessionEntry, payloads, result } = params;
const deliver = opts.deliver === true;
const bestEffortDeliver = opts.bestEffortDeliver === true;
const turnSourceChannel = opts.runContext?.messageChannel ?? opts.messageChannel;
const turnSourceTo = opts.runContext?.currentChannelId ?? opts.to;
const turnSourceAccountId = opts.runContext?.accountId ?? opts.accountId;
const turnSourceThreadId = opts.runContext?.currentThreadTs ?? opts.threadId;
const deliveryPlan = resolveAgentDeliveryPlan({
sessionEntry,
requestedChannel: opts.replyChannel ?? opts.channel,
@@ -78,6 +82,10 @@ export async function deliverAgentCommandResult(params: {
explicitThreadId: opts.threadId,
accountId: opts.replyAccountId ?? opts.accountId,
wantsDelivery: deliver,
turnSourceChannel,
turnSourceTo,
turnSourceAccountId,
turnSourceThreadId,
});
let deliveryChannel = deliveryPlan.resolvedChannel;
const explicitChannelHint = (opts.replyChannel ?? opts.channel)?.trim();