zot/packages/agent/modelsync_test.go
patriceckhart fa7d8d8be5 refactor: split source into packages/{provider,core,tui,agent}
Single Go module, four top-level packages under packages/. Import
paths become github.com/patriceckhart/zot/packages/<name>; downstream
consumers can depend on individual packages without pulling the rest.

Layout:
  packages/provider/     LLM clients + catalog
  packages/provider/auth/ credential store + OAuth + login server
  packages/core/         agent loop, sessions, cost
  packages/tui/          terminal toolkit + chat view
  packages/agent/        CLI wiring, system prompt
    extensions/ extproto/ modes/ tools/ skills/ swarm/
    sdk/  (was pkg/zotcore, package renamed zotcore -> sdk)
    ext/  (was pkg/zotext, package renamed zotext -> ext)

internal/ and pkg/ removed. The internal/assets logo moved into
packages/provider/auth/assets.

Public Go SDK identifiers renamed:
  pkg/zotcore (package zotcore) -> packages/agent/sdk (package sdk)
  pkg/zotext  (package zotext)  -> packages/agent/ext (package ext)

This breaks Go-based extensions and embedders; the JSON wire protocol
for extensions and RPC is unchanged, so non-Go extensions, already-
built extension binaries, and zot rpc consumers are unaffected.

Docs, examples, and the built-in write-zot-extension skill updated
for the new paths and identifiers. Shadow-bug fixes in code samples
(ext := ext.New -> e := ext.New).
2026-05-27 09:07:15 +02:00

121 lines
3.3 KiB
Go

package agent
import (
"encoding/json"
"os"
"path/filepath"
"testing"
)
// TestValidateAndRepairConfig_MismatchedPair simulates the bug from a
// stale /model switch: provider=anthropic but model=kimi-for-coding
// (which belongs to provider=kimi). The validator should rewrite the
// model to anthropic's default and persist.
func TestValidateAndRepairConfig_MismatchedPair(t *testing.T) {
home := t.TempDir()
t.Setenv("ZOT_HOME", home)
must := func(c Config) {
t.Helper()
b, _ := json.Marshal(c)
if err := os.WriteFile(filepath.Join(home, "config.json"), b, 0o644); err != nil {
t.Fatal(err)
}
}
must(Config{Provider: "anthropic", Model: "kimi-for-coding"})
ValidateAndRepairConfig()
out, err := LoadConfig()
if err != nil {
t.Fatal(err)
}
if out.Provider != "anthropic" {
t.Errorf("provider not preserved: %q", out.Provider)
}
if out.Model == "kimi-for-coding" {
t.Errorf("model not repaired; still %q", out.Model)
}
if out.Model == "" {
t.Errorf("model not set; expected anthropic default")
}
}
// TestValidateAndRepairConfig_UnknownProvider resets to anthropic and
// clears the model when the saved provider id isn't recognised
// (e.g. user removed it from a previous build).
func TestValidateAndRepairConfig_UnknownProvider(t *testing.T) {
home := t.TempDir()
t.Setenv("ZOT_HOME", home)
b, _ := json.Marshal(Config{Provider: "made-up-provider", Model: "some-model"})
_ = os.WriteFile(filepath.Join(home, "config.json"), b, 0o644)
ValidateAndRepairConfig()
out, _ := LoadConfig()
if out.Provider != "anthropic" {
t.Errorf("provider not reset: %q", out.Provider)
}
if out.Model != "" {
t.Errorf("model not cleared: %q", out.Model)
}
}
// TestValidateAndRepairConfig_UnknownModel keeps the provider but
// snaps the model to that provider's default when the saved id is no
// longer in the catalog.
func TestValidateAndRepairConfig_UnknownModel(t *testing.T) {
home := t.TempDir()
t.Setenv("ZOT_HOME", home)
b, _ := json.Marshal(Config{Provider: "anthropic", Model: "claude-deleted-model"})
_ = os.WriteFile(filepath.Join(home, "config.json"), b, 0o644)
ValidateAndRepairConfig()
out, _ := LoadConfig()
if out.Provider != "anthropic" {
t.Errorf("provider changed: %q", out.Provider)
}
if out.Model == "" || out.Model == "claude-deleted-model" {
t.Errorf("model not repaired: %q", out.Model)
}
}
func TestValidateAndRepairConfig_DuplicateModelIDValidForConfiguredProvider(t *testing.T) {
home := t.TempDir()
t.Setenv("ZOT_HOME", home)
b, _ := json.Marshal(Config{Provider: "openai-codex", Model: "gpt-5.5"})
_ = os.WriteFile(filepath.Join(home, "config.json"), b, 0o644)
ValidateAndRepairConfig()
out, _ := LoadConfig()
if out.Provider != "openai-codex" {
t.Errorf("provider mutated: %q", out.Provider)
}
if out.Model != "gpt-5.5" {
t.Errorf("model mutated: %q", out.Model)
}
}
// TestValidateAndRepairConfig_HappyPath leaves a valid config alone.
func TestValidateAndRepairConfig_HappyPath(t *testing.T) {
home := t.TempDir()
t.Setenv("ZOT_HOME", home)
b, _ := json.Marshal(Config{Provider: "anthropic", Model: "claude-sonnet-4-5"})
_ = os.WriteFile(filepath.Join(home, "config.json"), b, 0o644)
ValidateAndRepairConfig()
out, _ := LoadConfig()
if out.Provider != "anthropic" {
t.Errorf("provider mutated: %q", out.Provider)
}
if out.Model != "claude-sonnet-4-5" {
t.Errorf("model mutated: %q", out.Model)
}
}