Skip to content

Commit 1011640

Browse files
steipetekitze
andcommitted
refactor: drop autoReply, add topic requireMention
Co-authored-by: kitze <kristijan.mkd@gmail.com>
1 parent 25edac9 commit 1011640

13 files changed

Lines changed: 80 additions & 76 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- Model config schema changes (auth profiles + model lists); doctor auto-migrates and the gateway rewrites legacy configs on startup.
1616
- Commands: gate all slash commands to authorized senders; add `/compact` to manually compact session context.
1717
- Groups: `whatsapp.groups`, `telegram.groups`, and `imessage.groups` now act as allowlists when set. Add `"*"` to keep allow-all behavior.
18+
- Auto-reply: removed `autoReply` from Discord/Slack/Telegram channel configs; use `requireMention` instead (Telegram topics now support `requireMention` overrides).
1819

1920
### Fixes
2021
- Pairing: generate DM pairing codes with CSPRNG, expire pending codes after 1 hour, and avoid re-sending codes for already pending requests.

docs/gateway/configuration.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -468,12 +468,16 @@ Set `telegram.enabled: false` to disable automatic startup.
468468
dmPolicy: "pairing", // pairing | allowlist | open | disabled
469469
allowFrom: ["tg:123456789"], // optional; "open" requires ["*"]
470470
groups: {
471-
"*": { requireMention: true, autoReply: false },
471+
"*": { requireMention: true },
472472
"-1001234567890": {
473473
allowFrom: ["@admin"],
474474
systemPrompt: "Keep answers brief.",
475475
topics: {
476-
"99": { skills: ["search"], systemPrompt: "Stay on topic." }
476+
"99": {
477+
requireMention: false,
478+
skills: ["search"],
479+
systemPrompt: "Stay on topic."
480+
}
477481
}
478482
}
479483
},
@@ -580,7 +584,7 @@ Slack runs in Socket Mode and requires both a bot token and app token:
580584
C123: { allow: true, requireMention: true },
581585
"#general": {
582586
allow: true,
583-
autoReply: false,
587+
requireMention: true,
584588
users: ["U123"],
585589
skills: ["docs"],
586590
systemPrompt: "Short answers only."

docs/providers/discord.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,7 @@ Notes:
202202
requireMention: true,
203203
users: ["987654321098765432"],
204204
skills: ["search", "docs"],
205-
systemPrompt: "Keep answers short.",
206-
autoReply: false
205+
systemPrompt: "Keep answers short."
207206
}
208207
}
209208
}
@@ -227,7 +226,6 @@ Ack reactions are controlled globally via `messages.ackReaction` +
227226
- `guilds.<id>.users`: optional per-guild user allowlist (ids or names).
228227
- `guilds.<id>.channels.<channel>.allow`: allow/deny the channel when `groupPolicy="allowlist"`.
229228
- `guilds.<id>.channels.<channel>.requireMention`: mention gating for the channel.
230-
- `guilds.<id>.channels.<channel>.autoReply`: if `true`, reply to all messages (overrides `requireMention`).
231229
- `guilds.<id>.channels.<channel>.users`: optional per-channel user allowlist.
232230
- `guilds.<id>.channels.<channel>.skills`: skill filter (omit = all skills, empty = none).
233231
- `guilds.<id>.channels.<channel>.systemPrompt`: extra system prompt for the channel (combined with channel topic).

docs/providers/slack.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ Slack uses Socket Mode only (no HTTP webhook server). Provide both tokens:
159159
"C123": { "allow": true, "requireMention": true },
160160
"#general": {
161161
"allow": true,
162-
"autoReply": false,
162+
"requireMention": true,
163163
"users": ["U123"],
164164
"skills": ["search", "docs"],
165165
"systemPrompt": "Keep answers short."
@@ -212,7 +212,6 @@ Ack reactions are controlled globally via `messages.ackReaction` +
212212
Channel options (`slack.channels.<id>` or `slack.channels.<name>`):
213213
- `allow`: allow/deny the channel when `groupPolicy="allowlist"`.
214214
- `requireMention`: mention gating for the channel.
215-
- `autoReply`: if `true`, reply to every message (overrides `requireMention`).
216215
- `users`: optional per-channel user allowlist.
217216
- `skills`: skill filter (omit = all skills, empty = none).
218217
- `systemPrompt`: extra system prompt for the channel (combined with topic/purpose).

docs/providers/telegram.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@ Provider options:
117117
- `telegram.groupAllowFrom`: group sender allowlist (ids/usernames).
118118
- `telegram.groups`: per-group defaults + allowlist (use `"*"` for global defaults).
119119
- `telegram.groups.<id>.requireMention`: mention gating default.
120-
- `telegram.groups.<id>.autoReply`: reply to every message (overrides `requireMention`).
121120
- `telegram.groups.<id>.skills`: skill filter (omit = all skills, empty = none).
122121
- `telegram.groups.<id>.allowFrom`: per-group sender allowlist override.
123122
- `telegram.groups.<id>.systemPrompt`: extra system prompt for the group.
124123
- `telegram.groups.<id>.enabled`: disable the group when `false`.
125124
- `telegram.groups.<id>.topics.<threadId>.*`: per-topic overrides (same fields as group).
125+
- `telegram.groups.<id>.topics.<threadId>.requireMention`: per-topic mention gating override.
126126
- `telegram.replyToMode`: `off | first | all`.
127127
- `telegram.textChunkLimit`: outbound chunk size (chars).
128128
- `telegram.streamMode`: `off | partial | block` (draft streaming).

src/auto-reply/reply/groups.ts

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,7 @@ function parseTelegramGroupId(value?: string | null) {
4444
return { chatId: raw, topicId: undefined };
4545
}
4646

47-
function hasOwn(obj: unknown, key: string): boolean {
48-
return Boolean(obj && typeof obj === "object" && Object.hasOwn(obj, key));
49-
}
50-
51-
function resolveTelegramAutoReply(params: {
47+
function resolveTelegramRequireMention(params: {
5248
cfg: ClawdbotConfig;
5349
chatId?: string;
5450
topicId?: string;
@@ -61,17 +57,17 @@ function resolveTelegramAutoReply(params: {
6157
topicId && groupConfig?.topics ? groupConfig.topics[topicId] : undefined;
6258
const defaultTopicConfig =
6359
topicId && groupDefault?.topics ? groupDefault.topics[topicId] : undefined;
64-
if (hasOwn(topicConfig, "autoReply")) {
65-
return (topicConfig as { autoReply?: boolean }).autoReply;
60+
if (typeof topicConfig?.requireMention === "boolean") {
61+
return topicConfig.requireMention;
6662
}
67-
if (hasOwn(defaultTopicConfig, "autoReply")) {
68-
return (defaultTopicConfig as { autoReply?: boolean }).autoReply;
63+
if (typeof defaultTopicConfig?.requireMention === "boolean") {
64+
return defaultTopicConfig.requireMention;
6965
}
70-
if (hasOwn(groupConfig, "autoReply")) {
71-
return (groupConfig as { autoReply?: boolean }).autoReply;
66+
if (typeof groupConfig?.requireMention === "boolean") {
67+
return groupConfig.requireMention;
7268
}
73-
if (hasOwn(groupDefault, "autoReply")) {
74-
return (groupDefault as { autoReply?: boolean }).autoReply;
69+
if (typeof groupDefault?.requireMention === "boolean") {
70+
return groupDefault.requireMention;
7571
}
7672
return undefined;
7773
}
@@ -107,8 +103,12 @@ export function resolveGroupRequireMention(params: {
107103
const groupSpace = ctx.GroupSpace?.trim();
108104
if (provider === "telegram") {
109105
const { chatId, topicId } = parseTelegramGroupId(groupId);
110-
const autoReply = resolveTelegramAutoReply({ cfg, chatId, topicId });
111-
if (typeof autoReply === "boolean") return !autoReply;
106+
const requireMention = resolveTelegramRequireMention({
107+
cfg,
108+
chatId,
109+
topicId,
110+
});
111+
if (typeof requireMention === "boolean") return requireMention;
112112
return resolveProviderGroupRequireMention({
113113
cfg,
114114
provider,
@@ -138,9 +138,6 @@ export function resolveGroupRequireMention(params: {
138138
(groupRoom
139139
? channelEntries[normalizeDiscordSlug(groupRoom)]
140140
: undefined);
141-
if (entry && typeof entry.autoReply === "boolean") {
142-
return !entry.autoReply;
143-
}
144141
if (entry && typeof entry.requireMention === "boolean") {
145142
return entry.requireMention;
146143
}
@@ -163,7 +160,7 @@ export function resolveGroupRequireMention(params: {
163160
channelName ?? "",
164161
normalizedName,
165162
].filter(Boolean);
166-
let matched: { requireMention?: boolean; autoReply?: boolean } | undefined;
163+
let matched: { requireMention?: boolean } | undefined;
167164
for (const candidate of candidates) {
168165
if (candidate && channels[candidate]) {
169166
matched = channels[candidate];
@@ -172,9 +169,6 @@ export function resolveGroupRequireMention(params: {
172169
}
173170
const fallback = channels["*"];
174171
const resolved = matched ?? fallback;
175-
if (typeof resolved?.autoReply === "boolean") {
176-
return !resolved.autoReply;
177-
}
178172
if (typeof resolved?.requireMention === "boolean") {
179173
return resolved.requireMention;
180174
}

src/config/types.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,11 @@ export type TelegramActionConfig = {
237237
};
238238

239239
export type TelegramTopicConfig = {
240+
requireMention?: boolean;
240241
/** If specified, only load these skills for this topic. Omit = all skills; empty = no skills. */
241242
skills?: string[];
242243
/** If false, disable the bot for this topic. */
243244
enabled?: boolean;
244-
/** If true, reply to every message (no mention required). */
245-
autoReply?: boolean;
246245
/** Optional allowlist for topic senders (ids or usernames). */
247246
allowFrom?: Array<string | number>;
248247
/** Optional system prompt snippet for this topic. */
@@ -257,8 +256,6 @@ export type TelegramGroupConfig = {
257256
topics?: Record<string, TelegramTopicConfig>;
258257
/** If false, disable the bot for this group (and its topics). */
259258
enabled?: boolean;
260-
/** If true, reply to every message (no mention required). */
261-
autoReply?: boolean;
262259
/** Optional allowlist for group senders (ids or usernames). */
263260
allowFrom?: Array<string | number>;
264261
/** Optional system prompt snippet for this group. */
@@ -325,8 +322,6 @@ export type DiscordGuildChannelConfig = {
325322
skills?: string[];
326323
/** If false, disable the bot for this channel. */
327324
enabled?: boolean;
328-
/** If true, reply to every message (no mention required). */
329-
autoReply?: boolean;
330325
/** Optional allowlist for channel senders (ids or names). */
331326
users?: Array<string | number>;
332327
/** Optional system prompt snippet for this channel. */
@@ -412,8 +407,6 @@ export type SlackChannelConfig = {
412407
allow?: boolean;
413408
/** Require mentioning the bot to trigger replies. */
414409
requireMention?: boolean;
415-
/** Reply to all messages without needing a mention. */
416-
autoReply?: boolean;
417410
/** Allowlist of users that can invoke the bot in this channel. */
418411
users?: Array<string | number>;
419412
/** Optional skill filter for this channel. */

src/config/zod-schema.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -787,17 +787,16 @@ export const ClawdbotSchema = z.object({
787787
requireMention: z.boolean().optional(),
788788
skills: z.array(z.string()).optional(),
789789
enabled: z.boolean().optional(),
790-
autoReply: z.boolean().optional(),
791790
allowFrom: z.array(z.union([z.string(), z.number()])).optional(),
792791
systemPrompt: z.string().optional(),
793792
topics: z
794793
.record(
795794
z.string(),
796795
z
797796
.object({
797+
requireMention: z.boolean().optional(),
798798
skills: z.array(z.string()).optional(),
799799
enabled: z.boolean().optional(),
800-
autoReply: z.boolean().optional(),
801800
allowFrom: z
802801
.array(z.union([z.string(), z.number()]))
803802
.optional(),
@@ -913,7 +912,6 @@ export const ClawdbotSchema = z.object({
913912
requireMention: z.boolean().optional(),
914913
skills: z.array(z.string()).optional(),
915914
enabled: z.boolean().optional(),
916-
autoReply: z.boolean().optional(),
917915
users: z
918916
.array(z.union([z.string(), z.number()]))
919917
.optional(),
@@ -990,7 +988,6 @@ export const ClawdbotSchema = z.object({
990988
enabled: z.boolean().optional(),
991989
allow: z.boolean().optional(),
992990
requireMention: z.boolean().optional(),
993-
autoReply: z.boolean().optional(),
994991
users: z.array(z.union([z.string(), z.number()])).optional(),
995992
skills: z.array(z.string()).optional(),
996993
systemPrompt: z.string().optional(),

src/discord/monitor.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ describe("discord guild/channel resolution", () => {
101101
requireMention: true,
102102
skills: ["search"],
103103
enabled: false,
104-
autoReply: true,
105104
users: ["123"],
106105
systemPrompt: "Use short answers.",
107106
},
@@ -126,7 +125,6 @@ describe("discord guild/channel resolution", () => {
126125
expect(help?.requireMention).toBe(true);
127126
expect(help?.skills).toEqual(["search"]);
128127
expect(help?.enabled).toBe(false);
129-
expect(help?.autoReply).toBe(true);
130128
expect(help?.users).toEqual(["123"]);
131129
expect(help?.systemPrompt).toBe("Use short answers.");
132130
});

src/discord/monitor.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,6 @@ export type DiscordGuildEntryResolved = {
101101
requireMention?: boolean;
102102
skills?: string[];
103103
enabled?: boolean;
104-
autoReply?: boolean;
105104
users?: Array<string | number>;
106105
systemPrompt?: string;
107106
}
@@ -113,7 +112,6 @@ export type DiscordChannelConfigResolved = {
113112
requireMention?: boolean;
114113
skills?: string[];
115114
enabled?: boolean;
116-
autoReply?: boolean;
117115
users?: Array<string | number>;
118116
systemPrompt?: string;
119117
};
@@ -601,14 +599,8 @@ export function createDiscordMessageHandler(params: {
601599
guildHistories.set(message.channelId, history);
602600
}
603601

604-
const baseRequireMention =
605-
channelConfig?.requireMention ?? guildInfo?.requireMention ?? true;
606602
const shouldRequireMention =
607-
channelConfig?.autoReply === true
608-
? false
609-
: channelConfig?.autoReply === false
610-
? true
611-
: baseRequireMention;
603+
channelConfig?.requireMention ?? guildInfo?.requireMention ?? true;
612604
const hasAnyMention = Boolean(
613605
!isDirectMessage &&
614606
(message.mentionedEveryone ||
@@ -1810,7 +1802,6 @@ export function resolveDiscordChannelConfig(params: {
18101802
requireMention: byId.requireMention,
18111803
skills: byId.skills,
18121804
enabled: byId.enabled,
1813-
autoReply: byId.autoReply,
18141805
users: byId.users,
18151806
systemPrompt: byId.systemPrompt,
18161807
};
@@ -1821,7 +1812,6 @@ export function resolveDiscordChannelConfig(params: {
18211812
requireMention: entry.requireMention,
18221813
skills: entry.skills,
18231814
enabled: entry.enabled,
1824-
autoReply: entry.autoReply,
18251815
users: entry.users,
18261816
systemPrompt: entry.systemPrompt,
18271817
};
@@ -1833,7 +1823,6 @@ export function resolveDiscordChannelConfig(params: {
18331823
requireMention: entry.requireMention,
18341824
skills: entry.skills,
18351825
enabled: entry.enabled,
1836-
autoReply: entry.autoReply,
18371826
users: entry.users,
18381827
systemPrompt: entry.systemPrompt,
18391828
};

0 commit comments

Comments
 (0)