@@ -7,6 +7,7 @@
|
||||
- Memory: allow custom OpenAI-compatible embedding endpoints for memory search (remote baseUrl/apiKey/headers). (#819 — thanks @mukhtharcm)
|
||||
|
||||
### Fixes
|
||||
- Discord: avoid duplicate message/reaction listeners on monitor reloads. (#744 — thanks @thewilloftheshadow)
|
||||
- System events: include local timestamps when events are injected into prompts. (#245 — thanks @thewilloftheshadow)
|
||||
- Cron: accept `jobId` aliases for cron update/run/remove params in gateway validation. (#252 — thanks @thewilloftheshadow)
|
||||
- Models/Google: normalize Gemini 3 model ids to preview variants before runtime selection. (#795 — thanks @thewilloftheshadow)
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
isDiscordGroupAllowedByPolicy,
|
||||
normalizeDiscordAllowList,
|
||||
normalizeDiscordSlug,
|
||||
registerDiscordListener,
|
||||
resolveDiscordChannelConfig,
|
||||
resolveDiscordGuildEntry,
|
||||
resolveDiscordReplyTarget,
|
||||
@@ -34,6 +35,18 @@ const makeEntries = (
|
||||
return out;
|
||||
};
|
||||
|
||||
describe("registerDiscordListener", () => {
|
||||
class FakeListener {}
|
||||
|
||||
it("dedupes listeners by constructor", () => {
|
||||
const listeners: object[] = [];
|
||||
|
||||
expect(registerDiscordListener(listeners, new FakeListener())).toBe(true);
|
||||
expect(registerDiscordListener(listeners, new FakeListener())).toBe(false);
|
||||
expect(listeners).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("discord allowlist helpers", () => {
|
||||
it("normalizes slugs", () => {
|
||||
expect(normalizeDiscordSlug("Friends of Clawd")).toBe("friends-of-clawd");
|
||||
|
||||
@@ -175,6 +175,17 @@ function logSlowDiscordListener(params: {
|
||||
}
|
||||
}
|
||||
|
||||
export function registerDiscordListener(
|
||||
listeners: Array<object>,
|
||||
listener: object,
|
||||
) {
|
||||
if (listeners.some((existing) => existing.constructor === listener.constructor)) {
|
||||
return false;
|
||||
}
|
||||
listeners.push(listener);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function resolveDiscordThreadStarter(params: {
|
||||
channel: DiscordThreadChannel;
|
||||
client: Client;
|
||||
@@ -602,8 +613,12 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
||||
guildEntries,
|
||||
});
|
||||
|
||||
client.listeners.push(new DiscordMessageListener(messageHandler, logger));
|
||||
client.listeners.push(
|
||||
registerDiscordListener(
|
||||
client.listeners,
|
||||
new DiscordMessageListener(messageHandler, logger),
|
||||
);
|
||||
registerDiscordListener(
|
||||
client.listeners,
|
||||
new DiscordReactionListener({
|
||||
cfg,
|
||||
accountId: account.accountId,
|
||||
@@ -613,7 +628,8 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
||||
logger,
|
||||
}),
|
||||
);
|
||||
client.listeners.push(
|
||||
registerDiscordListener(
|
||||
client.listeners,
|
||||
new DiscordReactionRemoveListener({
|
||||
cfg,
|
||||
accountId: account.accountId,
|
||||
|
||||
Reference in New Issue
Block a user