fix(gateway): preserve route inheritance for legacy channel session keys (openclaw#33919) thanks @Takhoffman

Verified:
- pnpm build
- pnpm check
- pnpm test src/gateway/server-methods/chat.directive-tags.test.ts
- pnpm test:macmini

Co-authored-by: Takhoffman <781889+Takhoffman@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Tak Hoffman
2026-03-03 22:27:36 -06:00
committed by GitHub
parent f74a04e4ba
commit 8a7d1aa973
3 changed files with 73 additions and 1 deletions

View File

@@ -448,6 +448,75 @@ describe("chat directive tag stripping for non-streaming final payloads", () =>
);
});
it("chat.send inherits routing metadata for legacy channel-peer session keys", async () => {
createTranscriptFixture("openclaw-chat-send-legacy-channel-peer-routing-");
mockState.finalText = "ok";
mockState.sessionEntry = {
deliveryContext: {
channel: "telegram",
to: "telegram:6812765697",
accountId: "default",
},
lastChannel: "telegram",
lastTo: "telegram:6812765697",
lastAccountId: "default",
};
const respond = vi.fn();
const context = createChatContext();
await runNonStreamingChatSend({
context,
respond,
idempotencyKey: "idem-legacy-channel-peer-routing",
sessionKey: "agent:main:telegram:6812765697",
expectBroadcast: false,
});
expect(mockState.lastDispatchCtx).toEqual(
expect.objectContaining({
OriginatingChannel: "telegram",
OriginatingTo: "telegram:6812765697",
AccountId: "default",
}),
);
});
it("chat.send inherits routing metadata for legacy channel-peer thread session keys", async () => {
createTranscriptFixture("openclaw-chat-send-legacy-thread-channel-peer-routing-");
mockState.finalText = "ok";
mockState.sessionEntry = {
deliveryContext: {
channel: "telegram",
to: "telegram:6812765697",
accountId: "default",
threadId: "42",
},
lastChannel: "telegram",
lastTo: "telegram:6812765697",
lastAccountId: "default",
lastThreadId: "42",
};
const respond = vi.fn();
const context = createChatContext();
await runNonStreamingChatSend({
context,
respond,
idempotencyKey: "idem-legacy-thread-channel-peer-routing",
sessionKey: "agent:main:telegram:6812765697:thread:42",
expectBroadcast: false,
});
expect(mockState.lastDispatchCtx).toEqual(
expect.objectContaining({
OriginatingChannel: "telegram",
OriginatingTo: "telegram:6812765697",
AccountId: "default",
MessageThreadId: "42",
}),
);
});
it("chat.send does not inherit external delivery context for shared main sessions", async () => {
createTranscriptFixture("openclaw-chat-send-main-no-cross-route-");
mockState.finalText = "ok";

View File

@@ -875,6 +875,8 @@ export const chatHandlers: GatewayRequestHandlers = {
const isChannelScopedSession = sessionPeerShapeCandidates.some((part) =>
CHANNEL_SCOPED_SESSION_SHAPES.has(part),
);
const hasLegacyChannelPeerShape =
!isChannelScopedSession && typeof sessionScopeParts[1] === "string";
// Only inherit prior external route metadata for channel-scoped sessions.
// Channel-agnostic sessions (main, direct:<peer>, etc.) can otherwise
// leak stale routes across surfaces.
@@ -882,7 +884,7 @@ export const chatHandlers: GatewayRequestHandlers = {
sessionChannelHint &&
sessionChannelHint !== INTERNAL_MESSAGE_CHANNEL &&
!isChannelAgnosticSessionScope &&
isChannelScopedSession,
(isChannelScopedSession || hasLegacyChannelPeerShape),
);
const hasDeliverableRoute =
canInheritDeliverableRoute &&