env tweaks

This commit is contained in:
Luxferre
2026-09-10 12:20:41 +03:00
parent 502a3f8c03
commit b0a16e99e1
4 changed files with 185 additions and 32 deletions
+120 -8
View File
@@ -262,8 +262,20 @@ func TestDefaultSystemPrompt(t *testing.T) {
}
}
func clearBantamEnv(t *testing.T) {
for _, k := range []string{
"BANTAM_ENDPOINT", "BANTAM_MODEL", "BANTAM_TEMP", "BANTAM_TEMPERATURE",
"BANTAM_API_KEY", "BANTAM_STREAM", "BANTAM_COLOR", "BANTAM_NO_COLOR",
"BANTAM_TIMEOUT", "BANTAM_SHELL_TIMEOUT", "BANTAM_MAX_AL_ITERATIONS",
"BANTAM_CONTEXT_WINDOW", "BANTAM_REASONING_EFFORT", "BANTAM_TOOLS_DIR",
"BANTAM_SKILLS_DIR",
} {
t.Setenv(k, "")
}
}
func TestGetCfgDefaults(t *testing.T) {
t.Setenv("BANTAM_API_KEY", "")
clearBantamEnv(t)
cfg := getCfg(filepath.Join(t.TempDir(), "missing.cfg"))
if cfg.Endpoint != defCfg.Endpoint || cfg.Model != defCfg.Model || cfg.APIKey != defCfg.APIKey {
t.Errorf("defaults mismatch: %+v", cfg)
@@ -280,6 +292,7 @@ func TestGetCfgDefaults(t *testing.T) {
}
func TestGetCfgParsesFile(t *testing.T) {
clearBantamEnv(t)
p := writeCfg(t, strings.Join([]string{
"endpoint=http://localhost:9999/v1",
"model=test-model",
@@ -317,6 +330,7 @@ func TestGetCfgParsesFile(t *testing.T) {
}
func TestGetCfgIgnoresCommentsBlankAndInvalid(t *testing.T) {
clearBantamEnv(t)
p := writeCfg(t, strings.Join([]string{
"# comment",
"",
@@ -345,6 +359,7 @@ func TestGetCfgIgnoresCommentsBlankAndInvalid(t *testing.T) {
}
func TestGetCfgStreamTruthyVariants(t *testing.T) {
clearBantamEnv(t)
for _, tc := range []struct{ v, want string }{
{"true", "true"}, {"1", "true"}, {"yes", "true"},
{"false", "false"}, {"TRUE", "false"}, {"0", "false"},
@@ -359,6 +374,7 @@ func TestGetCfgStreamTruthyVariants(t *testing.T) {
}
func TestGetCfgAPIKeyEnvFallback(t *testing.T) {
clearBantamEnv(t)
t.Setenv("BANTAM_API_KEY", "sk-env")
t.Setenv("HOME", t.TempDir())
@@ -389,16 +405,34 @@ func TestGetCfgAPIKeyEnvFallback(t *testing.T) {
}
func TestGetCfgEnvOverriddenByFile(t *testing.T) {
// New env vars BANTAM_ENDPOINT / BANTAM_MODEL / BANTAM_TEMP act as fallbacks
// that must yield to any value set in the config file (.bantam.cfg).
// File values override environment variables.
clearBantamEnv(t)
t.Setenv("BANTAM_ENDPOINT", "http://env-endpoint/v1")
t.Setenv("BANTAM_MODEL", "env-model")
t.Setenv("BANTAM_TEMP", "0.9")
t.Setenv("BANTAM_API_KEY", "")
t.Setenv("BANTAM_STREAM", "false")
t.Setenv("BANTAM_COLOR", "never")
t.Setenv("BANTAM_TIMEOUT", "45")
t.Setenv("BANTAM_SHELL_TIMEOUT", "15")
t.Setenv("BANTAM_MAX_AL_ITERATIONS", "50")
t.Setenv("BANTAM_CONTEXT_WINDOW", "100000")
t.Setenv("BANTAM_REASONING_EFFORT", "low")
t.Setenv("BANTAM_TOOLS_DIR", "/env/tools")
t.Setenv("BANTAM_SKILLS_DIR", "/env/skills")
p := writeCfg(t, strings.Join([]string{
"endpoint=http://file-endpoint/v1",
"model=file-model",
"temperature=0.1",
"stream=true",
"color=always",
"timeout=300",
"shell_timeout=120",
"max_al_iterations=1000",
"context_window=200000",
"reasoning_effort=high",
"bantam_tools_dir=/file/tools",
"bantam_skills_dir=/file/skills",
}, "\n"))
cfg := getCfg(p)
if cfg.Endpoint != "http://file-endpoint/v1" {
@@ -410,18 +444,72 @@ func TestGetCfgEnvOverriddenByFile(t *testing.T) {
if cfg.Temperature != 0.1 {
t.Errorf("temperature: got %v, want file value", cfg.Temperature)
}
if !cfg.Stream {
t.Errorf("stream: got %v, want true from file", cfg.Stream)
}
if cfg.Color != "always" {
t.Errorf("color: got %q, want always from file", cfg.Color)
}
if cfg.Timeout != 300 {
t.Errorf("timeout: got %d, want 300 from file", cfg.Timeout)
}
if cfg.ShellTimeout != 120 {
t.Errorf("shell_timeout: got %d, want 120 from file", cfg.ShellTimeout)
}
if cfg.MaxALIterations != 1000 {
t.Errorf("max_al_iterations: got %d, want 1000 from file", cfg.MaxALIterations)
}
if cfg.ContextWindow != 200000 {
t.Errorf("context_window: got %d, want 200000 from file", cfg.ContextWindow)
}
if cfg.Raw["reasoning_effort"] != "high" {
t.Errorf("reasoning_effort: got %q, want high from file", cfg.Raw["reasoning_effort"])
}
if toolsDir(&cfg) != "/file/tools" {
t.Errorf("toolsDir: got %q, want /file/tools", toolsDir(&cfg))
}
if skillsDir(&cfg) != "/file/skills" {
t.Errorf("skillsDir: got %q, want /file/skills", skillsDir(&cfg))
}
}
func TestGetCfgEnvFallbackWhenNoFile(t *testing.T) {
// Without a config file the new env vars supply the values.
clearBantamEnv(t)
t.Setenv("BANTAM_ENDPOINT", "http://env-endpoint/v1")
t.Setenv("BANTAM_MODEL", "env-model")
t.Setenv("BANTAM_TEMP", "0.42")
t.Setenv("BANTAM_STREAM", "false")
t.Setenv("BANTAM_COLOR", "never")
t.Setenv("BANTAM_TIMEOUT", "45")
t.Setenv("BANTAM_SHELL_TIMEOUT", "15")
t.Setenv("BANTAM_MAX_AL_ITERATIONS", "50")
t.Setenv("BANTAM_CONTEXT_WINDOW", "100000")
t.Setenv("BANTAM_REASONING_EFFORT", "low")
t.Setenv("BANTAM_TOOLS_DIR", "/env/tools")
t.Setenv("BANTAM_SKILLS_DIR", "/env/skills")
t.Setenv("BANTAM_API_KEY", "")
cfg := getCfg(filepath.Join(t.TempDir(), "missing.cfg"))
if cfg.Endpoint != "http://env-endpoint/v1" || cfg.Model != "env-model" || cfg.Temperature != 0.42 {
t.Errorf("env fallback mismatch: %+v", cfg)
}
if cfg.Stream {
t.Errorf("stream: got %v, want false from env", cfg.Stream)
}
if cfg.Color != "never" {
t.Errorf("color: got %q, want never from env", cfg.Color)
}
if cfg.Timeout != 45 || cfg.ShellTimeout != 15 || cfg.MaxALIterations != 50 || cfg.ContextWindow != 100000 {
t.Errorf("numeric env fallback mismatch: %+v", cfg)
}
if cfg.Raw["reasoning_effort"] != "low" {
t.Errorf("reasoning_effort: got %q, want low from env", cfg.Raw["reasoning_effort"])
}
if toolsDir(&cfg) != "/env/tools" {
t.Errorf("toolsDir: got %q, want /env/tools", toolsDir(&cfg))
}
if skillsDir(&cfg) != "/env/skills" {
t.Errorf("skillsDir: got %q, want /env/skills", skillsDir(&cfg))
}
}
func TestAtoiD(t *testing.T) {
@@ -1446,6 +1534,7 @@ func TestCompactHappyPath(t *testing.T) {
// ---------- setCfg and LLM parameter forwarding ----------
func TestSetCfgUpdatesAndAppends(t *testing.T) {
clearBantamEnv(t)
p := filepath.Join(t.TempDir(), "model.cfg")
if err := os.WriteFile(p, []byte("model=old-model\ntemperature=0.5\n"), 0644); err != nil {
t.Fatalf("WriteFile: %v", err)
@@ -1471,6 +1560,7 @@ func TestSetCfgUpdatesAndAppends(t *testing.T) {
}
func TestLLMForwardsRelevantParameters(t *testing.T) {
clearBantamEnv(t)
var received map[string]any
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewDecoder(r.Body).Decode(&received)
@@ -2575,9 +2665,12 @@ func TestSkills(t *testing.T) {
}
// skillsDir prefers the config key, then the environment variable.
t.Setenv("BANTAM_SKILLS_DIR", skillDir)
if got := skillsDir(&Cfg{}); got != skillDir {
t.Errorf("skillsDir() with env = %q, want %q", got, skillDir)
t.Setenv("BANTAM_SKILLS_DIR", "/env/skills")
if got := skillsDir(&Cfg{Raw: map[string]string{"bantam_skills_dir": skillDir}}); got != skillDir {
t.Errorf("skillsDir() with config overriding env = %q, want %q", got, skillDir)
}
if got := skillsDir(&Cfg{Raw: map[string]string{}}); got != "/env/skills" {
t.Errorf("skillsDir() with env fallback = %q, want %q", got, "/env/skills")
}
t.Setenv("BANTAM_SKILLS_DIR", "")
if got := skillsDir(&Cfg{Raw: map[string]string{"bantam_skills_dir": skillDir}}); got != skillDir {
@@ -2623,6 +2716,7 @@ func TestSkills(t *testing.T) {
// #19: bare /skill lists skills under the configured dir, or reports none.
func TestListSkills(t *testing.T) {
t.Setenv("BANTAM_SKILLS_DIR", "")
base := t.TempDir()
skillDir := filepath.Join(base, "skills")
if err := os.MkdirAll(filepath.Join(skillDir, "alpha"), 0755); err != nil {
@@ -2669,3 +2763,21 @@ func TestListSkills(t *testing.T) {
listSkills(&Cfg{})
os.Stdout.Close()
}
func TestToolsDir(t *testing.T) {
t.Setenv("BANTAM_TOOLS_DIR", "/env/tools")
if got := toolsDir(&Cfg{Raw: map[string]string{"bantam_tools_dir": "/config/tools"}}); got != "/config/tools" {
t.Errorf("toolsDir() with config overriding env = %q, want /config/tools", got)
}
if got := toolsDir(&Cfg{Raw: map[string]string{}}); got != "/env/tools" {
t.Errorf("toolsDir() with env fallback = %q, want /env/tools", got)
}
t.Setenv("BANTAM_TOOLS_DIR", "")
if got := toolsDir(&Cfg{Raw: map[string]string{"bantam_tools_dir": "/config/tools"}}); got != "/config/tools" {
t.Errorf("toolsDir() with config = %q, want /config/tools", got)
}
if got := toolsDir(&Cfg{}); got != "" {
t.Errorf("toolsDir() empty = %q, want empty", got)
}
}