fix(discord): honor disabled group history limit (#1406)

Co-authored-by: Collective Developer <man@collective.dev>
This commit is contained in:
ナムandCollective Developer authored and GitHub committed 2026-07-09 17:25:37 +07:00
1 parent 2b7bfec504
commit e9898be505
9 files changed
+102 -11

No files matched your search

+1 -6
View File
@@ -61,11 +61,6 @@ func New(cfg config.DiscordConfig, msgBus *bus.MessageBus, pairingSvc store.Pair
requireMention = *cfg.RequireMention
}
historyLimit := cfg.HistoryLimit
if historyLimit == 0 {
historyLimit = channels.DefaultGroupHistoryLimit
}
ch := &Channel{
BaseChannel: base,
session: session,
@@ -77,7 +72,7 @@ func New(cfg config.DiscordConfig, msgBus *bus.MessageBus, pairingSvc store.Pair
ch.SetRequireMention(requireMention)
ch.SetPairingService(pairingSvc)
ch.SetGroupHistory(channels.MakeHistory(channels.TypeDiscord, pendingStore, base.TenantID()))
ch.SetHistoryLimit(historyLimit)
ch.SetHistoryLimit(cfg.HistoryLimit)
return ch, nil
}
@@ -0,0 +1,47 @@
package discord
import (
"encoding/json"
"testing"
"github.com/nextlevelbuilder/goclaw/internal/channels"
"github.com/nextlevelbuilder/goclaw/internal/config"
)
func TestNewPreservesExplicitZeroHistoryLimit(t *testing.T) {
ch, err := New(config.DiscordConfig{Token: "token", HistoryLimit: 0}, nil, nil, nil, nil, nil, nil)
if err != nil {
t.Fatalf("New returned error: %v", err)
}
if got := ch.HistoryLimit(); got != 0 {
t.Fatalf("HistoryLimit() = %d, want 0", got)
}
}
func TestFactoryDefaultsMissingHistoryLimitButPreservesExplicitZero(t *testing.T) {
creds := json.RawMessage(`{"token":"token"}`)
defaulted, err := Factory("discord-main", creds, json.RawMessage(`{}`), nil, nil)
if err != nil {
t.Fatalf("Factory default config returned error: %v", err)
}
defaultedDiscord, ok := defaulted.(*Channel)
if !ok {
t.Fatalf("Factory returned %T, want *discord.Channel", defaulted)
}
if got := defaultedDiscord.HistoryLimit(); got != channels.DefaultGroupHistoryLimit {
t.Fatalf("default HistoryLimit() = %d, want %d", got, channels.DefaultGroupHistoryLimit)
}
disabled, err := Factory("discord-disabled", creds, json.RawMessage(`{"history_limit":0}`), nil, nil)
if err != nil {
t.Fatalf("Factory explicit zero returned error: %v", err)
}
disabledDiscord, ok := disabled.(*Channel)
if !ok {
t.Fatalf("Factory returned %T, want *discord.Channel", disabled)
}
if got := disabledDiscord.HistoryLimit(); got != 0 {
t.Fatalf("explicit zero HistoryLimit() = %d, want 0", got)
}
}
+9 -2
View File
@@ -22,7 +22,7 @@ type discordInstanceConfig struct {
GroupPolicy string `json:"group_policy,omitempty"`
AllowFrom []string `json:"allow_from,omitempty"`
RequireMention *bool `json:"require_mention,omitempty"`
HistoryLimit int `json:"history_limit,omitempty"`
HistoryLimit *int `json:"history_limit,omitempty"`
BlockReply *bool `json:"block_reply,omitempty"`
ChatBehavior *config.ChatBehaviorConfig `json:"chat_behavior,omitempty"`
MediaMaxBytes int64 `json:"media_max_bytes,omitempty"`
@@ -81,7 +81,7 @@ func buildChannel(name string, creds json.RawMessage, cfg json.RawMessage,
DMPolicy: ic.DMPolicy,
GroupPolicy: ic.GroupPolicy,
RequireMention: ic.RequireMention,
HistoryLimit: ic.HistoryLimit,
HistoryLimit: resolveHistoryLimit(ic.HistoryLimit),
BlockReply: ic.BlockReply,
ChatBehavior: ic.ChatBehavior,
MediaMaxBytes: ic.MediaMaxBytes,
@@ -105,3 +105,10 @@ func buildChannel(name string, creds json.RawMessage, cfg json.RawMessage,
ch.SetName(name)
return ch, nil
}
func resolveHistoryLimit(limit *int) int {
if limit == nil {
return channels.DefaultGroupHistoryLimit
}
return *limit
}
+1 -1
View File
@@ -152,7 +152,7 @@ type DiscordConfig struct {
DMPolicy string `json:"dm_policy,omitempty"` // "open" (default), "allowlist", "disabled"
GroupPolicy string `json:"group_policy,omitempty"` // "open" (default), "allowlist", "disabled"
RequireMention *bool `json:"require_mention,omitempty"` // require @bot mention in groups (default true)
HistoryLimit int `json:"history_limit,omitempty"` // max pending group messages for context (default 50, 0=disabled)
HistoryLimit int `json:"history_limit,omitempty"` // max pending group messages for context (default 200, 0=disabled)
BlockReply *bool `json:"block_reply,omitempty"` // override gateway block_reply (nil = inherit)
ChatBehavior *ChatBehaviorConfig `json:"chat_behavior,omitempty"` // override gateway chat behavior (nil = inherit)
MediaMaxBytes int64 `json:"media_max_bytes,omitempty"` // max media download size (default 25MB)
+3
View File
@@ -97,6 +97,9 @@ func Default() *Config {
Telegram: TelegramConfig{
ReactionLevel: "full",
},
Discord: DiscordConfig{
HistoryLimit: 200,
},
},
Gateway: GatewayConfig{
Host: "0.0.0.0",
+28
View File
@@ -40,6 +40,9 @@ func TestDefault_SensibleDefaults(t *testing.T) {
if cfg.Skills.SlashCommands.EffectivePrefix() != "/" {
t.Fatalf("slash command prefix = %q, want /", cfg.Skills.SlashCommands.EffectivePrefix())
}
if cfg.Channels.Discord.HistoryLimit != 200 {
t.Fatalf("default discord history limit: got %d, want 200", cfg.Channels.Discord.HistoryLimit)
}
}
@@ -53,6 +56,9 @@ func TestLoad_MissingFile_UsesDefaults(t *testing.T) {
if cfg.Gateway.Port != 18790 {
t.Fatalf("expected default port, got %d", cfg.Gateway.Port)
}
if cfg.Channels.Discord.HistoryLimit != 200 {
t.Fatalf("expected default discord history limit, got %d", cfg.Channels.Discord.HistoryLimit)
}
}
// --- Load with valid JSON5 ---
@@ -87,6 +93,28 @@ func TestLoad_ValidJSON5(t *testing.T) {
}
}
func TestLoad_DiscordHistoryLimitExplicitZeroDisables(t *testing.T) {
dir := t.TempDir()
cfgPath := filepath.Join(dir, "config.json5")
content := `{
"channels": {
"discord": {
"history_limit": 0,
},
},
}`
os.WriteFile(cfgPath, []byte(content), 0644)
cfg, err := Load(cfgPath)
if err != nil {
t.Fatalf("load error: %v", err)
}
if cfg.Channels.Discord.HistoryLimit != 0 {
t.Fatalf("discord history_limit explicit zero: got %d, want 0", cfg.Channels.Discord.HistoryLimit)
}
}
// --- Load with invalid JSON5 → error ---
func TestLoad_InvalidJSON5(t *testing.T) {
@@ -84,7 +84,7 @@ export const configSchema: Record<string, FieldDef[]> = {
{ key: 'dm_policy', label: 'DM Policy', type: 'select', options: dmPolicyOptions, defaultValue: 'pairing' },
{ key: 'group_policy', label: 'Group Policy', type: 'select', options: groupPolicyOptions, defaultValue: 'pairing' },
{ key: 'require_mention', label: 'Require @mention in groups', type: 'boolean', defaultValue: true },
{ key: 'history_limit', label: 'Group History Limit', type: 'number', defaultValue: 50, help: 'Max pending group messages for context (0 = disabled)' },
{ key: 'history_limit', label: 'Group History Limit', type: 'number', defaultValue: 200, help: 'Max pending group messages for context (0 = disabled)' },
{ key: 'allow_from', label: 'Allowed Users', type: 'tags', help: 'Discord user IDs' },
{ key: 'block_reply', label: 'Block Reply', type: 'select', options: blockReplyOptions, defaultValue: 'inherit', help: 'Deliver intermediate text during tool iterations' },
],
@@ -73,6 +73,17 @@ describe("telegram configSchema", () => {
});
});
describe("discord configSchema", () => {
const discordConfig = configSchema["discord"]!;
it("matches the backend pending group history default", () => {
const historyLimit = discordConfig.find((field) => field.key === "history_limit");
expect(historyLimit).toBeDefined();
expect(historyLimit!.defaultValue).toBe(200);
expect(historyLimit!.help).toMatch(/0 = disabled/i);
});
});
describe("pancake configSchema", () => {
const pancakeConfig = configSchema["pancake"]!;
+1 -1
View File
@@ -173,7 +173,7 @@ export const configSchema: Record<string, FieldDef[]> = {
{ key: "dm_policy", label: "DM Policy", type: "select", options: dmPolicyOptions, defaultValue: "pairing" },
{ key: "group_policy", label: "Group Policy", type: "select", options: groupPolicyOptions, defaultValue: "pairing" },
{ key: "require_mention", label: "Require @mention in groups", type: "boolean", defaultValue: true },
{ key: "history_limit", label: "Group History Limit", type: "number", defaultValue: 50, help: "Max pending group messages for context (0 = disabled)" },
{ key: "history_limit", label: "Group History Limit", type: "number", defaultValue: 200, help: "Max pending group messages for context (0 = disabled)" },
{ key: "allow_from", label: "Allowed Users", type: "tags", help: "Discord user IDs" },
...chatBehaviorOverrideFields,
],