mirror of https://github.com/openclaw/openclaw.git
fix(discord): preserve native command session keys
This commit is contained in:
parent
cf1c2cc208
commit
bc91ae9ca0
|
|
@ -325,6 +325,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Telegram/DM streaming transport parity: use message preview transport for all DM streaming lanes so final delivery can edit the active preview instead of sending duplicate finals. Landed from contributor PR #38906 by @gambletan. Thanks @gambletan.
|
||||
- Telegram/send retry safety: retry non-idempotent send paths only for pre-connect failures and make custom retry predicates strict, preventing ambiguous reconnect retries from sending duplicate messages. Landed from contributor PR #34238 by @hal-crackbot. Thanks @hal-crackbot.
|
||||
- Discord/DM session-key normalization: rewrite legacy `discord:dm:*` and phantom direct-message `discord:channel:<user>` session keys to `discord:direct:*` when the sender matches, so multi-agent Discord DMs stop falling into empty channel-shaped sessions and resume replying correctly.
|
||||
- Discord/native slash session fallback: treat empty configured bound-session keys as missing so `/status` and other native commands fall back to the routed slash session and routed channel session instead of blanking Discord session keys in normal channel bindings.
|
||||
|
||||
## 2026.3.2
|
||||
|
||||
|
|
|
|||
|
|
@ -230,6 +230,61 @@ describe("Discord native plugin command dispatch", () => {
|
|||
expectBoundSessionDispatch(dispatchSpy, boundSessionKey);
|
||||
});
|
||||
|
||||
it("falls back to the routed slash and channel session keys when no bound session exists", async () => {
|
||||
const guildId = "1459246755253325866";
|
||||
const channelId = "1478836151241412759";
|
||||
const cfg = {
|
||||
commands: {
|
||||
useAccessGroups: false,
|
||||
},
|
||||
bindings: [
|
||||
{
|
||||
agentId: "qwen",
|
||||
match: {
|
||||
channel: "discord",
|
||||
accountId: "default",
|
||||
peer: { kind: "channel", id: channelId },
|
||||
guildId,
|
||||
},
|
||||
},
|
||||
],
|
||||
channels: {
|
||||
discord: {
|
||||
guilds: {
|
||||
[guildId]: {
|
||||
channels: {
|
||||
[channelId]: { allow: true, requireMention: false },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
const command = createStatusCommand(cfg);
|
||||
const interaction = createInteraction({
|
||||
channelType: ChannelType.GuildText,
|
||||
channelId,
|
||||
guildId,
|
||||
guildName: "Ops",
|
||||
});
|
||||
|
||||
vi.spyOn(pluginCommandsModule, "matchPluginCommand").mockReturnValue(null);
|
||||
const dispatchSpy = createDispatchSpy();
|
||||
|
||||
await (command as { run: (interaction: unknown) => Promise<void> }).run(interaction as unknown);
|
||||
|
||||
expect(dispatchSpy).toHaveBeenCalledTimes(1);
|
||||
const dispatchCall = dispatchSpy.mock.calls[0]?.[0] as {
|
||||
ctx?: { SessionKey?: string; CommandTargetSessionKey?: string };
|
||||
};
|
||||
expect(dispatchCall.ctx?.SessionKey).toBe("agent:qwen:discord:slash:owner");
|
||||
expect(dispatchCall.ctx?.CommandTargetSessionKey).toBe(
|
||||
"agent:qwen:discord:channel:1478836151241412759",
|
||||
);
|
||||
expect(persistentBindingMocks.resolveConfiguredAcpBindingRecord).toHaveBeenCalledTimes(1);
|
||||
expect(persistentBindingMocks.ensureConfiguredAcpBindingSession).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("routes Discord DM native slash commands through configured ACP bindings", async () => {
|
||||
const channelId = "dm-1";
|
||||
const boundSessionKey = "agent:codex:acp:binding:discord:default:dmfeedface";
|
||||
|
|
|
|||
|
|
@ -1644,7 +1644,7 @@ async function dispatchDiscordCommandInteraction(params: {
|
|||
return;
|
||||
}
|
||||
}
|
||||
const configuredBoundSessionKey = configuredRoute?.boundSessionKey ?? "";
|
||||
const configuredBoundSessionKey = configuredRoute?.boundSessionKey?.trim() || undefined;
|
||||
const boundSessionKey = threadBinding?.targetSessionKey?.trim() || configuredBoundSessionKey;
|
||||
const boundAgentId = boundSessionKey ? resolveAgentIdFromSessionKey(boundSessionKey) : undefined;
|
||||
const effectiveRoute = boundSessionKey
|
||||
|
|
|
|||
Loading…
Reference in New Issue