mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-05 03:40:22 +00:00
Fix Discord /codex_resume picker expiration (#51260)
Merged via squash.
Prepared head SHA: 76eb184dbe
Co-authored-by: huntharo <5617868+huntharo@users.noreply.github.com>
Co-authored-by: huntharo <5617868+huntharo@users.noreply.github.com>
Reviewed-by: @huntharo
This commit is contained in:
@@ -9,6 +9,7 @@ export type { DiscordConfig, DiscordPluralKitConfig } from "../config/types.disc
|
||||
export type { InspectedDiscordAccount } from "../../extensions/discord/api.js";
|
||||
export type { ResolvedDiscordAccount } from "../../extensions/discord/api.js";
|
||||
export type { DiscordSendComponents, DiscordSendEmbeds } from "../../extensions/discord/api.js";
|
||||
export type { DiscordComponentMessageSpec } from "../../extensions/discord/api.js";
|
||||
export type {
|
||||
ThreadBindingManager,
|
||||
ThreadBindingRecord,
|
||||
@@ -64,8 +65,10 @@ export {
|
||||
} from "./status-helpers.js";
|
||||
|
||||
export {
|
||||
buildDiscordComponentMessage,
|
||||
createDiscordActionGate,
|
||||
listDiscordAccountIds,
|
||||
resolveDiscordAccount,
|
||||
resolveDefaultDiscordAccountId,
|
||||
} from "../../extensions/discord/api.js";
|
||||
export { inspectDiscordAccount } from "../../extensions/discord/api.js";
|
||||
@@ -105,6 +108,8 @@ export {
|
||||
createScheduledEventDiscord,
|
||||
createThreadDiscord,
|
||||
deleteChannelDiscord,
|
||||
editDiscordComponentMessage,
|
||||
registerBuiltDiscordComponentMessage,
|
||||
deleteMessageDiscord,
|
||||
editChannelDiscord,
|
||||
editMessageDiscord,
|
||||
|
||||
@@ -9,6 +9,7 @@ const require = createRequire(import.meta.url);
|
||||
const rootSdk = require("./root-alias.cjs") as Record<string, unknown>;
|
||||
const rootAliasPath = fileURLToPath(new URL("./root-alias.cjs", import.meta.url));
|
||||
const rootAliasSource = fs.readFileSync(rootAliasPath, "utf-8");
|
||||
const packageJsonPath = fileURLToPath(new URL("../../package.json", import.meta.url));
|
||||
|
||||
type EmptySchema = {
|
||||
safeParse: (value: unknown) =>
|
||||
@@ -196,6 +197,14 @@ describe("plugin-sdk root alias", () => {
|
||||
expect(rootSdk.__esModule).toBe(true);
|
||||
});
|
||||
|
||||
it("publishes the Discord plugin-sdk subpath", () => {
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")) as {
|
||||
exports?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
expect(packageJson.exports?.["./plugin-sdk/discord"]).toBeDefined();
|
||||
});
|
||||
|
||||
it("preserves reflection semantics for lazily resolved exports", { timeout: 240_000 }, () => {
|
||||
expect("resolveControlCommandGate" in rootSdk).toBe(true);
|
||||
expect("onDiagnosticEvent" in rootSdk).toBe(true);
|
||||
|
||||
@@ -97,7 +97,6 @@ describe("plugin-sdk subpath exports", () => {
|
||||
expect(pluginSdkSubpaths).not.toContain("bluebubbles");
|
||||
expect(pluginSdkSubpaths).not.toContain("compat");
|
||||
expect(pluginSdkSubpaths).not.toContain("device-pair");
|
||||
expect(pluginSdkSubpaths).not.toContain("discord");
|
||||
expect(pluginSdkSubpaths).not.toContain("feishu");
|
||||
expect(pluginSdkSubpaths).not.toContain("google");
|
||||
expect(pluginSdkSubpaths).not.toContain("googlechat");
|
||||
@@ -132,7 +131,6 @@ describe("plugin-sdk subpath exports", () => {
|
||||
expect(pluginSdkSubpaths).not.toContain("secret-input-runtime");
|
||||
expect(pluginSdkSubpaths).not.toContain("secret-input-schema");
|
||||
expect(pluginSdkSubpaths).not.toContain("zai");
|
||||
expect(pluginSdkSubpaths).not.toContain("discord-core");
|
||||
expect(pluginSdkSubpaths).not.toContain("slack-core");
|
||||
expect(pluginSdkSubpaths).not.toContain("provider-model-definitions");
|
||||
});
|
||||
@@ -220,6 +218,14 @@ describe("plugin-sdk subpath exports", () => {
|
||||
expect(typeof runtimeSdk.createLoggerBackedRuntime).toBe("function");
|
||||
});
|
||||
|
||||
it("exports Discord component helpers from the dedicated subpath", async () => {
|
||||
const discordSdk = await import("openclaw/plugin-sdk/discord");
|
||||
expect(typeof discordSdk.buildDiscordComponentMessage).toBe("function");
|
||||
expect(typeof discordSdk.editDiscordComponentMessage).toBe("function");
|
||||
expect(typeof discordSdk.registerBuiltDiscordComponentMessage).toBe("function");
|
||||
expect(typeof discordSdk.resolveDiscordAccount).toBe("function");
|
||||
});
|
||||
|
||||
it("exports channel identity and session helpers from stronger existing homes", () => {
|
||||
expect(typeof routingSdk.normalizeMessageChannel).toBe("function");
|
||||
expect(typeof routingSdk.resolveGatewayMessageChannel).toBe("function");
|
||||
|
||||
@@ -313,6 +313,58 @@ describe("plugin interactive handlers", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("acknowledges matched Discord interactions before awaiting plugin handlers", async () => {
|
||||
const callOrder: string[] = [];
|
||||
const handler = vi.fn(async () => {
|
||||
callOrder.push("handler");
|
||||
expect(callOrder).toEqual(["ack", "handler"]);
|
||||
return { handled: true };
|
||||
});
|
||||
expect(
|
||||
registerPluginInteractiveHandler("codex-plugin", {
|
||||
channel: "discord",
|
||||
namespace: "codex",
|
||||
handler,
|
||||
}),
|
||||
).toEqual({ ok: true });
|
||||
|
||||
await expect(
|
||||
dispatchPluginInteractiveHandler({
|
||||
channel: "discord",
|
||||
data: "codex:approve:thread-1",
|
||||
interactionId: "ix-ack-1",
|
||||
ctx: {
|
||||
accountId: "default",
|
||||
interactionId: "ix-ack-1",
|
||||
conversationId: "channel-1",
|
||||
parentConversationId: "parent-1",
|
||||
guildId: "guild-1",
|
||||
senderId: "user-1",
|
||||
senderUsername: "ada",
|
||||
auth: { isAuthorizedSender: true },
|
||||
interaction: {
|
||||
kind: "button",
|
||||
messageId: "message-1",
|
||||
},
|
||||
},
|
||||
respond: {
|
||||
acknowledge: vi.fn(async () => {}),
|
||||
reply: vi.fn(async () => {}),
|
||||
followUp: vi.fn(async () => {}),
|
||||
editMessage: vi.fn(async () => {}),
|
||||
clearComponents: vi.fn(async () => {}),
|
||||
},
|
||||
onMatched: async () => {
|
||||
callOrder.push("ack");
|
||||
},
|
||||
}),
|
||||
).resolves.toEqual({
|
||||
matched: true,
|
||||
handled: true,
|
||||
duplicate: false,
|
||||
});
|
||||
});
|
||||
|
||||
it("routes Slack interactions by namespace and dedupes interaction ids", async () => {
|
||||
const handler = vi.fn(async () => ({ handled: true }));
|
||||
expect(
|
||||
|
||||
@@ -168,6 +168,7 @@ export async function dispatchPluginInteractiveHandler(params: {
|
||||
clearButtons: () => Promise<void>;
|
||||
deleteMessage: () => Promise<void>;
|
||||
};
|
||||
onMatched?: () => Promise<void> | void;
|
||||
}): Promise<InteractiveDispatchResult>;
|
||||
export async function dispatchPluginInteractiveHandler(params: {
|
||||
channel: "discord";
|
||||
@@ -175,6 +176,7 @@ export async function dispatchPluginInteractiveHandler(params: {
|
||||
interactionId: string;
|
||||
ctx: DiscordInteractiveDispatchContext;
|
||||
respond: PluginInteractiveDiscordHandlerContext["respond"];
|
||||
onMatched?: () => Promise<void> | void;
|
||||
}): Promise<InteractiveDispatchResult>;
|
||||
export async function dispatchPluginInteractiveHandler(params: {
|
||||
channel: "slack";
|
||||
@@ -182,6 +184,7 @@ export async function dispatchPluginInteractiveHandler(params: {
|
||||
interactionId: string;
|
||||
ctx: SlackInteractiveDispatchContext;
|
||||
respond: PluginInteractiveSlackHandlerContext["respond"];
|
||||
onMatched?: () => Promise<void> | void;
|
||||
}): Promise<InteractiveDispatchResult>;
|
||||
export async function dispatchPluginInteractiveHandler(params: {
|
||||
channel: "telegram" | "discord" | "slack";
|
||||
@@ -205,6 +208,7 @@ export async function dispatchPluginInteractiveHandler(params: {
|
||||
}
|
||||
| PluginInteractiveDiscordHandlerContext["respond"]
|
||||
| PluginInteractiveSlackHandlerContext["respond"];
|
||||
onMatched?: () => Promise<void> | void;
|
||||
}): Promise<InteractiveDispatchResult> {
|
||||
const match = resolveNamespaceMatch(params.channel, params.data);
|
||||
if (!match) {
|
||||
@@ -217,6 +221,8 @@ export async function dispatchPluginInteractiveHandler(params: {
|
||||
return { matched: true, handled: true, duplicate: true };
|
||||
}
|
||||
|
||||
await params.onMatched?.();
|
||||
|
||||
let result:
|
||||
| ReturnType<PluginInteractiveTelegramHandlerRegistration["handler"]>
|
||||
| ReturnType<PluginInteractiveDiscordHandlerRegistration["handler"]>
|
||||
|
||||
Reference in New Issue
Block a user