mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-08-23 18:25:07 +00:00
127 lines
3.2 KiB
Go
127 lines
3.2 KiB
Go
package channelmemory
|
|
|
|
import (
|
|
"encoding/json"
|
|
"regexp"
|
|
"slices"
|
|
"time"
|
|
)
|
|
|
|
var DefaultAllowedTypes = []string{"people", "projects", "decisions", "todos", "preferences", "events"}
|
|
|
|
type Config struct {
|
|
Enabled bool `json:"enabled"`
|
|
ReviewMode bool `json:"review_mode"`
|
|
IntervalMinutes int `json:"interval_minutes"`
|
|
MessageCap int `json:"message_cap"`
|
|
RetentionHours int `json:"retention_hours"`
|
|
AllowedTypes []string `json:"allowed_types"`
|
|
ExcludeUsers []string `json:"exclude_users"`
|
|
ExcludePatterns []string `json:"exclude_patterns"`
|
|
MinMessages int `json:"min_messages"`
|
|
GroupOnly bool `json:"group_only"`
|
|
}
|
|
|
|
func DefaultConfig() Config {
|
|
return Config{
|
|
Enabled: false,
|
|
ReviewMode: true,
|
|
IntervalMinutes: 360,
|
|
MessageCap: 100,
|
|
RetentionHours: 168,
|
|
AllowedTypes: slices.Clone(DefaultAllowedTypes),
|
|
MinMessages: 5,
|
|
GroupOnly: true,
|
|
}
|
|
}
|
|
|
|
func ParseConfig(raw json.RawMessage) Config {
|
|
cfg := DefaultConfig()
|
|
if len(raw) == 0 {
|
|
return cfg
|
|
}
|
|
var root struct {
|
|
PassiveMemory *Config `json:"passive_memory"`
|
|
}
|
|
if err := json.Unmarshal(raw, &root); err != nil || root.PassiveMemory == nil {
|
|
return cfg
|
|
}
|
|
in := root.PassiveMemory
|
|
cfg.Enabled = in.Enabled
|
|
cfg.ReviewMode = in.ReviewMode
|
|
cfg.IntervalMinutes = clampInt(in.IntervalMinutes, 15, 10080, cfg.IntervalMinutes)
|
|
cfg.MessageCap = clampInt(in.MessageCap, 10, 1000, cfg.MessageCap)
|
|
cfg.RetentionHours = clampInt(in.RetentionHours, 1, 720, cfg.RetentionHours)
|
|
cfg.AllowedTypes = normalizeAllowedTypes(in.AllowedTypes)
|
|
cfg.ExcludeUsers = boundedStrings(in.ExcludeUsers, 50, 255)
|
|
cfg.ExcludePatterns = boundedPatterns(in.ExcludePatterns, 20, 255)
|
|
cfg.MinMessages = clampInt(in.MinMessages, 2, 100, cfg.MinMessages)
|
|
cfg.GroupOnly = true
|
|
return cfg
|
|
}
|
|
|
|
func MergeIntoInstanceConfig(raw json.RawMessage, cfg Config) json.RawMessage {
|
|
var root map[string]any
|
|
if len(raw) == 0 || json.Unmarshal(raw, &root) != nil || root == nil {
|
|
root = make(map[string]any)
|
|
}
|
|
root["passive_memory"] = cfg
|
|
out, _ := json.Marshal(root)
|
|
return out
|
|
}
|
|
|
|
func (c Config) Interval() time.Duration {
|
|
return time.Duration(c.IntervalMinutes) * time.Minute
|
|
}
|
|
|
|
func normalizeAllowedTypes(in []string) []string {
|
|
allowed := make([]string, 0, len(DefaultAllowedTypes))
|
|
for _, v := range in {
|
|
if slices.Contains(DefaultAllowedTypes, v) && !slices.Contains(allowed, v) {
|
|
allowed = append(allowed, v)
|
|
}
|
|
}
|
|
if len(allowed) == 0 {
|
|
return slices.Clone(DefaultAllowedTypes)
|
|
}
|
|
return allowed
|
|
}
|
|
|
|
func boundedStrings(in []string, maxCount, maxLen int) []string {
|
|
out := make([]string, 0, min(len(in), maxCount))
|
|
for _, v := range in {
|
|
if v == "" || len(v) > maxLen {
|
|
continue
|
|
}
|
|
out = append(out, v)
|
|
if len(out) >= maxCount {
|
|
break
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func boundedPatterns(in []string, maxCount, maxLen int) []string {
|
|
candidates := boundedStrings(in, maxCount, maxLen)
|
|
out := candidates[:0]
|
|
for _, v := range candidates {
|
|
if _, err := regexp.Compile(v); err == nil {
|
|
out = append(out, v)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func clampInt(v, minV, maxV, fallback int) int {
|
|
if v == 0 {
|
|
return fallback
|
|
}
|
|
if v < minV {
|
|
return minV
|
|
}
|
|
if v > maxV {
|
|
return maxV
|
|
}
|
|
return v
|
|
}
|