llm(三协议 Provider)/ session(JSONL 持久化)/ tools(Registry、围栏、 builtin、computer)/ cdp(browser)/ skills / mcp / agent(循环、两级压缩、 编排、审批门控)+ 底座 jsonl/textx/execx/diag/scratch/spill/imagecache。 产品装配代码(config 桥接、schedule 工具、memory/plan/retro/prompt) 留在 AutoGo,宿主接入方式见 MIGRATION.md。
140 lines
4.5 KiB
Go
140 lines
4.5 KiB
Go
package llm
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
func TestFilterAllowed(t *testing.T) {
|
|
models := []string{"glm-4.7", "glm-4.7-air", "glm-4.6", "deepseek-v4-flash", "gpt-5-mini"}
|
|
|
|
// 空白名单不筛选
|
|
if got := FilterAllowed(models, nil); !reflect.DeepEqual(got, models) {
|
|
t.Errorf("FilterAllowed(nil) = %v, want unchanged", got)
|
|
}
|
|
// 前缀通配
|
|
if got := FilterAllowed(models, []string{"glm-*"}); !reflect.DeepEqual(got, []string{"glm-4.7", "glm-4.7-air", "glm-4.6"}) {
|
|
t.Errorf("FilterAllowed(glm-*) = %v", got)
|
|
}
|
|
// 精确名大小写不敏感 + 通配混合
|
|
if got := FilterAllowed(models, []string{"GLM-4.7", "deepseek-*"}); !reflect.DeepEqual(got, []string{"glm-4.7", "deepseek-v4-flash"}) {
|
|
t.Errorf("FilterAllowed(mixed) = %v", got)
|
|
}
|
|
// 全不匹配
|
|
if got := FilterAllowed(models, []string{"claude-*"}); len(got) != 0 {
|
|
t.Errorf("FilterAllowed(claude-*) = %v, want empty", got)
|
|
}
|
|
}
|
|
|
|
func TestNormalizeAPIFormat(t *testing.T) {
|
|
cases := map[string]APIFormat{
|
|
"anthropic": FormatAnthropic,
|
|
"Anthropic_Messages": FormatAnthropic,
|
|
"openai": FormatChatCompletions,
|
|
"chat": FormatChatCompletions,
|
|
"chat_completions": FormatChatCompletions,
|
|
"Responses": FormatResponses,
|
|
"": "",
|
|
"graphql": "",
|
|
}
|
|
for in, want := range cases {
|
|
if got := NormalizeAPIFormat(in); got != want {
|
|
t.Errorf("NormalizeAPIFormat(%q) = %q, want %q", in, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestNewProviderFormats(t *testing.T) {
|
|
// 三种格式各自构造出对应 provider
|
|
p1, err := NewProvider(ProviderSpec{BaseURL: "https://x.com", APIFormat: FormatAnthropic})
|
|
if err != nil || p1 == nil {
|
|
t.Errorf("anthropic: %v", err)
|
|
}
|
|
p2, err := NewProvider(ProviderSpec{BaseURL: "https://x.com/v1", APIFormat: FormatChatCompletions})
|
|
if err != nil {
|
|
t.Errorf("chat: %v", err)
|
|
}
|
|
if _, ok := p2.(*OpenAIProvider); !ok {
|
|
t.Errorf("chat_completions should yield OpenAIProvider, got %T", p2)
|
|
}
|
|
p3, err := NewProvider(ProviderSpec{BaseURL: "https://x.com/v1", APIFormat: FormatResponses})
|
|
if err != nil {
|
|
t.Errorf("responses: %v", err)
|
|
}
|
|
if _, ok := p3.(*ResponsesProvider); !ok {
|
|
t.Errorf("responses should yield ResponsesProvider, got %T", p3)
|
|
}
|
|
// 未知格式报错
|
|
if _, err := NewProvider(ProviderSpec{BaseURL: "https://x.com", APIFormat: "graphql"}); err == nil {
|
|
t.Error("unknown format should error")
|
|
}
|
|
// BaseURL 含 anthropic 时自动推断
|
|
p4, _ := NewProvider(ProviderSpec{BaseURL: "https://api.anthropic.com"})
|
|
if _, ok := p4.(*AnthropicProvider); !ok {
|
|
t.Errorf("anthropic URL should infer AnthropicProvider, got %T", p4)
|
|
}
|
|
}
|
|
|
|
// TestMissingRegisteredModels:下架判定——大小写不敏感、通配条目不参与
|
|
// 判定(既不标下架也不算存活)、空目录不判定、原文保序去重。
|
|
func TestMissingRegisteredModels(t *testing.T) {
|
|
fetched := []string{"glm-4.7", "GLM-4.6", "cogview-4", "glm-4.5-air"}
|
|
cases := []struct {
|
|
name string
|
|
registered []string
|
|
fetched []string
|
|
want []string
|
|
}{
|
|
{
|
|
name: "精确匹配大小写不敏感",
|
|
registered: []string{"glm-4.7", "glm-4.6", "dead-model"},
|
|
fetched: fetched,
|
|
want: []string{"dead-model"},
|
|
},
|
|
{
|
|
name: "通配条目不参与判定",
|
|
registered: []string{"glm-*", "kling-*"},
|
|
fetched: fetched,
|
|
want: nil, // 模式无法对具体目录下结论:跳过,不标下架
|
|
},
|
|
{
|
|
name: "空目录不判定(拉取失败不误标)",
|
|
registered: []string{"glm-4.7"},
|
|
fetched: nil,
|
|
want: nil,
|
|
},
|
|
{
|
|
name: "保序去重、跳过空条目",
|
|
registered: []string{"b-dead", "", "a-dead", "B-DEAD"},
|
|
fetched: fetched,
|
|
want: []string{"b-dead", "a-dead"},
|
|
},
|
|
{
|
|
name: "全部存活返回 nil",
|
|
registered: []string{"GLM-4.7", "cogview-4"},
|
|
fetched: fetched,
|
|
want: nil,
|
|
},
|
|
}
|
|
for _, c := range cases {
|
|
got := MissingRegisteredModels(c.registered, c.fetched)
|
|
if len(got) != len(c.want) {
|
|
t.Errorf("%s: got %v, want %v", c.name, got, c.want)
|
|
continue
|
|
}
|
|
for i := range got {
|
|
if got[i] != c.want[i] {
|
|
t.Errorf("%s: got[%d]=%q, want %q", c.name, i, got[i], c.want[i])
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestFilterAllowed 与 MissingRegisteredModels 口径一致:同一个匹配函数。
|
|
func TestFilterAllowedWildcard(t *testing.T) {
|
|
got := FilterAllowed([]string{"glm-4.7", "cogview-4"}, []string{"glm-*"})
|
|
if len(got) != 1 || got[0] != "glm-4.7" {
|
|
t.Errorf("FilterAllowed = %v, want [glm-4.7]", got)
|
|
}
|
|
}
|