Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion plugins/ask.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"net/url"
"os"
"strconv"
"strings"
"sync"
"time"
Expand All @@ -34,12 +35,35 @@ func (p *Ask) Help() string {
}

func (p *Ask) Init(c bot.PluginConfig, _ *storage.DB) error {
p.cfg = c
p.cfg = withAskEnvironment(c)
p.last = make(map[string]time.Time)
p.lastWarning = make(map[string]time.Time)
return nil
}

// withAskEnvironment applies the ask-specific environment variables after
// the config file has been decoded. Viper can read bound scalar environment
// values with Get, but nested map values are not reliably reflected when the
// whole plugin map is unmarshaled into PluginConfig. Applying these two
// switches here makes the documented .env overrides authoritative without
// requiring secrets in config.yaml.
func withAskEnvironment(c bot.PluginConfig) bot.PluginConfig {
cfg := make(bot.PluginConfig, len(c)+2)
for key, value := range c {
cfg[key] = value
}

if provider := strings.TrimSpace(os.Getenv("BOT_ASK_PROVIDER")); provider != "" {
cfg["provider"] = provider
}
if raw, ok := os.LookupEnv("BOT_ASK_AI_REWRITE"); ok {
if enabled, err := strconv.ParseBool(strings.TrimSpace(raw)); err == nil {
cfg["ai_rewrite"] = enabled
}
}
return cfg
}

func (p *Ask) Handle(b *bot.Bot, m bot.Message) bool {
cmd, arg, ok := bot.IsCommand(m, b.Config.CommandPrefix)
if !ok || !isAskCommand(cmd) {
Expand Down
32 changes: 32 additions & 0 deletions plugins/ask_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,38 @@ func TestAskProviderNoneDoesNotCallAI(t *testing.T) {
}
}

func TestAskEnvironmentOverridesNestedConfig(t *testing.T) {
t.Setenv("BOT_ASK_PROVIDER", "openrouter")
t.Setenv("BOT_ASK_AI_REWRITE", "true")

p := &Ask{}
if err := p.Init(bot.PluginConfig{
"provider": "none",
"ai_rewrite": false,
"max_length": 360,
}, nil); err != nil {
t.Fatalf("init failed: %v", err)
}
if got := p.cfg.String("provider", "none"); got != "openrouter" {
t.Fatalf("provider = %q, want openrouter", got)
}
if !p.cfg.Bool("ai_rewrite", false) {
t.Fatal("ai_rewrite remained disabled despite BOT_ASK_AI_REWRITE=true")
}
}

func TestAskInvalidEnvironmentBooleanLeavesConfigUnchanged(t *testing.T) {
t.Setenv("BOT_ASK_AI_REWRITE", "not-a-boolean")

p := &Ask{}
if err := p.Init(bot.PluginConfig{"ai_rewrite": true}, nil); err != nil {
t.Fatalf("init failed: %v", err)
}
if !p.cfg.Bool("ai_rewrite", false) {
t.Fatal("invalid environment boolean unexpectedly changed config")
}
}

func TestAskSenderKeyUsesAccountWhenAvailable(t *testing.T) {
key := askSenderKey(bot.Message{Nick: "Echo", Account: "UserAccount"})
if key != "account:useraccount" {
Expand Down