mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 16:34:59 +00:00
fix(session): prefer webchat routes for direct ui turns (#37135)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
import type { SessionEntry } from "../../config/sessions.js";
|
import type { SessionEntry } from "../../config/sessions.js";
|
||||||
import { buildAgentMainSessionKey } from "../../routing/session-key.js";
|
import { buildAgentMainSessionKey } from "../../routing/session-key.js";
|
||||||
import { parseAgentSessionKey } from "../../sessions/session-key-utils.js";
|
import { deriveSessionChatType, parseAgentSessionKey } from "../../sessions/session-key-utils.js";
|
||||||
import {
|
import {
|
||||||
deliveryContextFromSession,
|
deliveryContextFromSession,
|
||||||
deliveryContextKey,
|
deliveryContextKey,
|
||||||
@@ -38,6 +38,10 @@ function isMainSessionKey(sessionKey?: string): boolean {
|
|||||||
return parsed.rest.trim().toLowerCase() === "main";
|
return parsed.rest.trim().toLowerCase() === "main";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDirectSessionKey(sessionKey?: string): boolean {
|
||||||
|
return deriveSessionChatType(sessionKey) === "direct";
|
||||||
|
}
|
||||||
|
|
||||||
function isExternalRoutingChannel(channel?: string): channel is string {
|
function isExternalRoutingChannel(channel?: string): channel is string {
|
||||||
return Boolean(
|
return Boolean(
|
||||||
channel && channel !== INTERNAL_MESSAGE_CHANNEL && isDeliverableMessageChannel(channel),
|
channel && channel !== INTERNAL_MESSAGE_CHANNEL && isDeliverableMessageChannel(channel),
|
||||||
@@ -50,7 +54,12 @@ export function resolveLastChannelRaw(params: {
|
|||||||
sessionKey?: string;
|
sessionKey?: string;
|
||||||
}): string | undefined {
|
}): string | undefined {
|
||||||
const originatingChannel = normalizeMessageChannel(params.originatingChannelRaw);
|
const originatingChannel = normalizeMessageChannel(params.originatingChannelRaw);
|
||||||
if (originatingChannel === INTERNAL_MESSAGE_CHANNEL && isMainSessionKey(params.sessionKey)) {
|
// WebChat should own reply routing for direct-session UI turns, even when the
|
||||||
|
// session previously replied through an external channel like iMessage.
|
||||||
|
if (
|
||||||
|
originatingChannel === INTERNAL_MESSAGE_CHANNEL &&
|
||||||
|
(isMainSessionKey(params.sessionKey) || isDirectSessionKey(params.sessionKey))
|
||||||
|
) {
|
||||||
return params.originatingChannelRaw;
|
return params.originatingChannelRaw;
|
||||||
}
|
}
|
||||||
const persistedChannel = normalizeMessageChannel(params.persistedLastChannel);
|
const persistedChannel = normalizeMessageChannel(params.persistedLastChannel);
|
||||||
@@ -77,7 +86,10 @@ export function resolveLastToRaw(params: {
|
|||||||
sessionKey?: string;
|
sessionKey?: string;
|
||||||
}): string | undefined {
|
}): string | undefined {
|
||||||
const originatingChannel = normalizeMessageChannel(params.originatingChannelRaw);
|
const originatingChannel = normalizeMessageChannel(params.originatingChannelRaw);
|
||||||
if (originatingChannel === INTERNAL_MESSAGE_CHANNEL && isMainSessionKey(params.sessionKey)) {
|
if (
|
||||||
|
originatingChannel === INTERNAL_MESSAGE_CHANNEL &&
|
||||||
|
(isMainSessionKey(params.sessionKey) || isDirectSessionKey(params.sessionKey))
|
||||||
|
) {
|
||||||
return params.originatingToRaw || params.toRaw;
|
return params.originatingToRaw || params.toRaw;
|
||||||
}
|
}
|
||||||
const persistedChannel = normalizeMessageChannel(params.persistedLastChannel);
|
const persistedChannel = normalizeMessageChannel(params.persistedLastChannel);
|
||||||
|
|||||||
@@ -1926,6 +1926,43 @@ describe("initSessionState internal channel routing preservation", () => {
|
|||||||
expect(result.sessionEntry.deliveryContext?.to).toBe("group:12345");
|
expect(result.sessionEntry.deliveryContext?.to).toBe("group:12345");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("lets direct webchat turns override persisted external routes for per-channel-peer sessions", async () => {
|
||||||
|
const storePath = await createStorePath("webchat-direct-route-override-");
|
||||||
|
const sessionKey = "agent:main:imessage:direct:+1555";
|
||||||
|
await writeSessionStoreFast(storePath, {
|
||||||
|
[sessionKey]: {
|
||||||
|
sessionId: "sess-webchat-direct",
|
||||||
|
updatedAt: Date.now(),
|
||||||
|
lastChannel: "imessage",
|
||||||
|
lastTo: "+1555",
|
||||||
|
deliveryContext: {
|
||||||
|
channel: "imessage",
|
||||||
|
to: "+1555",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const cfg = {
|
||||||
|
session: { store: storePath, dmScope: "per-channel-peer" },
|
||||||
|
} as OpenClawConfig;
|
||||||
|
|
||||||
|
const result = await initSessionState({
|
||||||
|
ctx: {
|
||||||
|
Body: "reply from control ui",
|
||||||
|
SessionKey: sessionKey,
|
||||||
|
OriginatingChannel: "webchat",
|
||||||
|
OriginatingTo: "session:dashboard",
|
||||||
|
Surface: "webchat",
|
||||||
|
},
|
||||||
|
cfg,
|
||||||
|
commandAuthorized: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.sessionEntry.lastChannel).toBe("webchat");
|
||||||
|
expect(result.sessionEntry.lastTo).toBe("session:dashboard");
|
||||||
|
expect(result.sessionEntry.deliveryContext?.channel).toBe("webchat");
|
||||||
|
expect(result.sessionEntry.deliveryContext?.to).toBe("session:dashboard");
|
||||||
|
});
|
||||||
|
|
||||||
it("keeps persisted external route when OriginatingChannel is non-deliverable", async () => {
|
it("keeps persisted external route when OriginatingChannel is non-deliverable", async () => {
|
||||||
const storePath = await createStorePath("preserve-nondeliverable-route-");
|
const storePath = await createStorePath("preserve-nondeliverable-route-");
|
||||||
const sessionKey = "agent:main:discord:channel:24680";
|
const sessionKey = "agent:main:discord:channel:24680";
|
||||||
|
|||||||
Reference in New Issue
Block a user