refactor: seperate security.yml for store keys

This commit is contained in:
Cytown
2026-03-22 01:55:00 +08:00
parent 94fcb25039
commit e455eb5e67
68 changed files with 5313 additions and 1185 deletions
+1 -1
View File
@@ -430,7 +430,7 @@ func (s *appState) isActiveModelValid() bool {
if err != nil {
return false
}
hasKey := strings.TrimSpace(cfg.APIKey) != "" || strings.TrimSpace(cfg.AuthMethod) == "oauth"
hasKey := strings.TrimSpace(cfg.APIKey()) != "" || strings.TrimSpace(cfg.AuthMethod) == "oauth"
hasModel := strings.TrimSpace(cfg.Model) != ""
return hasKey && hasModel
}
@@ -112,8 +112,8 @@ func refreshChannelMenuFromState(menu *Menu, s *appState) {
func (s *appState) telegramForm() tview.Primitive {
cfg := &s.config.Channels.Telegram
form := baseChannelForm("Telegram", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
form.AddInputField("Token", cfg.Token, 128, nil, func(text string) {
cfg.Token = strings.TrimSpace(text)
form.AddInputField("Token", cfg.Token(), 128, nil, func(text string) {
cfg.SetToken(strings.TrimSpace(text))
})
form.AddInputField("Proxy", cfg.Proxy, 128, nil, func(text string) {
cfg.Proxy = strings.TrimSpace(text)
@@ -125,8 +125,8 @@ func (s *appState) telegramForm() tview.Primitive {
func (s *appState) discordForm() tview.Primitive {
cfg := &s.config.Channels.Discord
form := baseChannelForm("Discord", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
form.AddInputField("Token", cfg.Token, 128, nil, func(text string) {
cfg.Token = strings.TrimSpace(text)
form.AddInputField("Token", cfg.Token(), 128, nil, func(text string) {
cfg.SetToken(strings.TrimSpace(text))
})
form.AddCheckbox("Mention Only", cfg.MentionOnly, func(checked bool) {
cfg.MentionOnly = checked
@@ -141,8 +141,8 @@ func (s *appState) qqForm() tview.Primitive {
form.AddInputField("App ID", cfg.AppID, 64, nil, func(text string) {
cfg.AppID = strings.TrimSpace(text)
})
form.AddInputField("App Secret", cfg.AppSecret, 128, nil, func(text string) {
cfg.AppSecret = strings.TrimSpace(text)
form.AddInputField("App Secret", cfg.AppSecret(), 128, nil, func(text string) {
cfg.SetAppSecret(strings.TrimSpace(text))
})
addAllowFromField(form, &cfg.AllowFrom)
return wrapWithBack(form, s)
@@ -175,14 +175,14 @@ func (s *appState) feishuForm() tview.Primitive {
form.AddInputField("App ID", cfg.AppID, 64, nil, func(text string) {
cfg.AppID = strings.TrimSpace(text)
})
form.AddInputField("App Secret", cfg.AppSecret, 128, nil, func(text string) {
cfg.AppSecret = strings.TrimSpace(text)
form.AddInputField("App Secret", cfg.AppSecret(), 128, nil, func(text string) {
cfg.SetAppSecret(strings.TrimSpace(text))
})
form.AddInputField("Encrypt Key", cfg.EncryptKey, 128, nil, func(text string) {
cfg.EncryptKey = strings.TrimSpace(text)
form.AddInputField("Encrypt Key", cfg.EncryptKey(), 128, nil, func(text string) {
cfg.SetEncryptKey(strings.TrimSpace(text))
})
form.AddInputField("Verification Token", cfg.VerificationToken, 128, nil, func(text string) {
cfg.VerificationToken = strings.TrimSpace(text)
form.AddInputField("Verification Token", cfg.VerificationToken(), 128, nil, func(text string) {
cfg.SetVerificationToken(strings.TrimSpace(text))
})
addAllowFromField(form, &cfg.AllowFrom)
return wrapWithBack(form, s)
@@ -194,8 +194,8 @@ func (s *appState) dingtalkForm() tview.Primitive {
form.AddInputField("Client ID", cfg.ClientID, 64, nil, func(text string) {
cfg.ClientID = strings.TrimSpace(text)
})
form.AddInputField("Client Secret", cfg.ClientSecret, 128, nil, func(text string) {
cfg.ClientSecret = strings.TrimSpace(text)
form.AddInputField("Client Secret", cfg.ClientSecret(), 128, nil, func(text string) {
cfg.SetClientSecret(strings.TrimSpace(text))
})
addAllowFromField(form, &cfg.AllowFrom)
return wrapWithBack(form, s)
@@ -204,11 +204,11 @@ func (s *appState) dingtalkForm() tview.Primitive {
func (s *appState) slackForm() tview.Primitive {
cfg := &s.config.Channels.Slack
form := baseChannelForm("Slack", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
form.AddInputField("Bot Token", cfg.BotToken, 128, nil, func(text string) {
cfg.BotToken = strings.TrimSpace(text)
form.AddInputField("Bot Token", cfg.BotToken(), 128, nil, func(text string) {
cfg.SetBotToken(strings.TrimSpace(text))
})
form.AddInputField("App Token", cfg.AppToken, 128, nil, func(text string) {
cfg.AppToken = strings.TrimSpace(text)
form.AddInputField("App Token", cfg.AppToken(), 128, nil, func(text string) {
cfg.SetAppToken(strings.TrimSpace(text))
})
addAllowFromField(form, &cfg.AllowFrom)
return wrapWithBack(form, s)
@@ -217,11 +217,11 @@ func (s *appState) slackForm() tview.Primitive {
func (s *appState) lineForm() tview.Primitive {
cfg := &s.config.Channels.LINE
form := baseChannelForm("LINE", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
form.AddInputField("Channel Secret", cfg.ChannelSecret, 128, nil, func(text string) {
cfg.ChannelSecret = strings.TrimSpace(text)
form.AddInputField("Channel Secret", cfg.ChannelSecret(), 128, nil, func(text string) {
cfg.SetChannelSecret(strings.TrimSpace(text))
})
form.AddInputField("Channel Access Token", cfg.ChannelAccessToken, 128, nil, func(text string) {
cfg.ChannelAccessToken = strings.TrimSpace(text)
form.AddInputField("Channel Access Token", cfg.ChannelAccessToken(), 128, nil, func(text string) {
cfg.SetChannelAccessToken(strings.TrimSpace(text))
})
form.AddInputField("Webhook Host", cfg.WebhookHost, 64, nil, func(text string) {
cfg.WebhookHost = strings.TrimSpace(text)
@@ -243,8 +243,8 @@ func (s *appState) matrixForm() tview.Primitive {
form.AddInputField("User ID", cfg.UserID, 128, nil, func(text string) {
cfg.UserID = strings.TrimSpace(text)
})
form.AddInputField("Access Token", cfg.AccessToken, 128, nil, func(text string) {
cfg.AccessToken = strings.TrimSpace(text)
form.AddInputField("Access Token", cfg.AccessToken(), 128, nil, func(text string) {
cfg.SetAccessToken(strings.TrimSpace(text))
})
form.AddInputField("Device ID", cfg.DeviceID, 128, nil, func(text string) {
cfg.DeviceID = strings.TrimSpace(text)
@@ -262,8 +262,8 @@ func (s *appState) onebotForm() tview.Primitive {
form.AddInputField("WS URL", cfg.WSUrl, 128, nil, func(text string) {
cfg.WSUrl = strings.TrimSpace(text)
})
form.AddInputField("Access Token", cfg.AccessToken, 128, nil, func(text string) {
cfg.AccessToken = strings.TrimSpace(text)
form.AddInputField("Access Token", cfg.AccessToken(), 128, nil, func(text string) {
cfg.SetAccessToken(strings.TrimSpace(text))
})
addIntField(
form,
@@ -287,11 +287,11 @@ func (s *appState) onebotForm() tview.Primitive {
func (s *appState) wecomForm() tview.Primitive {
cfg := &s.config.Channels.WeCom
form := baseChannelForm("WeCom", cfg.Enabled, s.makeChannelOnEnabled(&cfg.Enabled))
form.AddInputField("Token", cfg.Token, 128, nil, func(text string) {
cfg.Token = strings.TrimSpace(text)
form.AddInputField("Token", cfg.Token(), 128, nil, func(text string) {
cfg.SetToken(strings.TrimSpace(text))
})
form.AddInputField("Encoding AES Key", cfg.EncodingAESKey, 128, nil, func(text string) {
cfg.EncodingAESKey = strings.TrimSpace(text)
form.AddInputField("Encoding AES Key", cfg.EncodingAESKey(), 128, nil, func(text string) {
cfg.SetEncodingAESKey(strings.TrimSpace(text))
})
form.AddInputField("Webhook URL", cfg.WebhookURL, 128, nil, func(text string) {
cfg.WebhookURL = strings.TrimSpace(text)
@@ -319,15 +319,15 @@ func (s *appState) wecomAppForm() tview.Primitive {
form.AddInputField("Corp ID", cfg.CorpID, 64, nil, func(text string) {
cfg.CorpID = strings.TrimSpace(text)
})
form.AddInputField("Corp Secret", cfg.CorpSecret, 128, nil, func(text string) {
cfg.CorpSecret = strings.TrimSpace(text)
form.AddInputField("Corp Secret", cfg.CorpSecret(), 128, nil, func(text string) {
cfg.SetCorpSecret(strings.TrimSpace(text))
})
addInt64Field(form, "Agent ID", cfg.AgentID, func(value int64) { cfg.AgentID = value })
form.AddInputField("Token", cfg.Token, 128, nil, func(text string) {
cfg.Token = strings.TrimSpace(text)
form.AddInputField("Token", cfg.Token(), 128, nil, func(text string) {
cfg.SetToken(strings.TrimSpace(text))
})
form.AddInputField("Encoding AES Key", cfg.EncodingAESKey, 128, nil, func(text string) {
cfg.EncodingAESKey = strings.TrimSpace(text)
form.AddInputField("Encoding AES Key", cfg.EncodingAESKey(), 128, nil, func(text string) {
cfg.SetEncodingAESKey(strings.TrimSpace(text))
})
form.AddInputField("Webhook Host", cfg.WebhookHost, 64, nil, func(text string) {
cfg.WebhookHost = strings.TrimSpace(text)
+11 -11
View File
@@ -49,7 +49,7 @@ func (s *appState) modelMenu() tview.Primitive {
Action: func() {
newName := s.nextAvailableModelName("new-model")
s.addModel(
picoclawconfig.ModelConfig{ModelName: newName, Model: "openai/gpt-5.4"},
&picoclawconfig.ModelConfig{ModelName: newName, Model: "openai/gpt-5.4"},
)
s.push(
fmt.Sprintf("model-%d", len(s.config.ModelList)-1),
@@ -90,7 +90,7 @@ func (s *appState) modelMenu() tview.Primitive {
}
func (s *appState) modelForm(index int) tview.Primitive {
model := &s.config.ModelList[index]
model := s.config.ModelList[index]
form := tview.NewForm()
form.SetBorder(true).SetTitle(fmt.Sprintf("Model: %s", model.ModelName))
@@ -131,8 +131,8 @@ func (s *appState) modelForm(index int) tview.Primitive {
refreshModelMenuFromState(menu, s)
}
})
addInput(form, "API Key", model.APIKey, func(value string) {
model.APIKey = value
addInput(form, "API Key", model.APIKey(), func(value string) {
model.SetAPIKey(value)
s.dirty = true
refreshMainMenuIfPresent(s)
if menu, ok := s.menus["model"]; ok {
@@ -215,7 +215,7 @@ func addIntInput(form *tview.Form, label string, value int, onChange func(int))
})
}
func (s *appState) addModel(model picoclawconfig.ModelConfig) {
func (s *appState) addModel(model *picoclawconfig.ModelConfig) {
s.config.ModelList = append(s.config.ModelList, model)
}
@@ -236,7 +236,7 @@ func modelStatusColor(valid bool, selected bool) *tcell.Color {
return &color
}
func refreshModelMenu(menu *Menu, currentModel string, models []picoclawconfig.ModelConfig) {
func refreshModelMenu(menu *Menu, currentModel string, models []*picoclawconfig.ModelConfig) {
for i, model := range models {
row := i
label := fmt.Sprintf("%s (%s)", model.ModelName, model.Model)
@@ -291,7 +291,7 @@ func refreshModelMenuFromState(menu *Menu, s *appState) {
Action: func() {
newName := s.nextAvailableModelName("new-model")
s.addModel(
picoclawconfig.ModelConfig{ModelName: newName, Model: "openai/gpt-5.4"},
&picoclawconfig.ModelConfig{ModelName: newName, Model: "openai/gpt-5.4"},
)
s.push(fmt.Sprintf("model-%d", len(s.config.ModelList)-1), s.modelForm(len(s.config.ModelList)-1))
},
@@ -300,8 +300,8 @@ func refreshModelMenuFromState(menu *Menu, s *appState) {
menu.applyItems(items)
}
func isModelValid(model picoclawconfig.ModelConfig) bool {
hasKey := strings.TrimSpace(model.APIKey) != "" ||
func isModelValid(model *picoclawconfig.ModelConfig) bool {
hasKey := strings.TrimSpace(model.APIKey()) != "" ||
strings.TrimSpace(model.AuthMethod) == "oauth"
hasModel := strings.TrimSpace(model.Model) != ""
return hasKey && hasModel
@@ -343,7 +343,7 @@ func (s *appState) testModel(model *picoclawconfig.ModelConfig) {
if model == nil {
return
}
if strings.TrimSpace(model.APIKey) == "" {
if strings.TrimSpace(model.APIKey()) == "" {
s.showMessage("Missing API Key", "Set api_key before testing")
return
}
@@ -375,7 +375,7 @@ func (s *appState) testModel(model *picoclawconfig.ModelConfig) {
return
}
request.Header.Set("Content-Type", "application/json")
request.Header.Set("Authorization", "Bearer "+strings.TrimSpace(model.APIKey))
request.Header.Set("Authorization", "Bearer "+strings.TrimSpace(model.APIKey()))
resp, err := client.Do(request)
if err != nil {
+5 -5
View File
@@ -68,7 +68,7 @@ func authLoginOpenAI(useDeviceCode bool) error {
// If no openai in ModelList, add it
if !foundOpenAI {
appCfg.ModelList = append(appCfg.ModelList, config.ModelConfig{
appCfg.ModelList = append(appCfg.ModelList, &config.ModelConfig{
ModelName: "gpt-5.4",
Model: "openai/gpt-5.4",
AuthMethod: "oauth",
@@ -139,7 +139,7 @@ func authLoginGoogleAntigravity() error {
// If no antigravity in ModelList, add it
if !foundAntigravity {
appCfg.ModelList = append(appCfg.ModelList, config.ModelConfig{
appCfg.ModelList = append(appCfg.ModelList, &config.ModelConfig{
ModelName: "gemini-flash",
Model: "antigravity/gemini-3-flash",
AuthMethod: "oauth",
@@ -213,7 +213,7 @@ func authLoginAnthropicSetupToken() error {
}
}
if !found {
appCfg.ModelList = append(appCfg.ModelList, config.ModelConfig{
appCfg.ModelList = append(appCfg.ModelList, &config.ModelConfig{
ModelName: defaultAnthropicModel,
Model: "anthropic/" + defaultAnthropicModel,
AuthMethod: "oauth",
@@ -289,7 +289,7 @@ func authLoginPasteToken(provider string) error {
}
}
if !found {
appCfg.ModelList = append(appCfg.ModelList, config.ModelConfig{
appCfg.ModelList = append(appCfg.ModelList, &config.ModelConfig{
ModelName: defaultAnthropicModel,
Model: "anthropic/" + defaultAnthropicModel,
AuthMethod: "token",
@@ -307,7 +307,7 @@ func authLoginPasteToken(provider string) error {
}
}
if !found {
appCfg.ModelList = append(appCfg.ModelList, config.ModelConfig{
appCfg.ModelList = append(appCfg.ModelList, &config.ModelConfig{
ModelName: "gpt-5.4",
Model: "openai/gpt-5.4",
AuthMethod: "token",
+2 -2
View File
@@ -81,7 +81,7 @@ func listAvailableModels(cfg *config.Config) {
if model.ModelName == defaultModel {
marker = "> "
}
if model.APIKey == "" {
if model.APIKey() == "" {
continue
}
fmt.Printf("%s- %s (%s)\n", marker, model.ModelName, model.Model)
@@ -92,7 +92,7 @@ func setDefaultModel(configPath string, cfg *config.Config, modelName string) er
// Validate that the model exists in model_list
modelFound := false
for _, model := range cfg.ModelList {
if model.APIKey != "" && model.ModelName == modelName {
if model.APIKey() != "" && model.ModelName == modelName {
modelFound = true
break
}
+111 -49
View File
@@ -58,17 +58,24 @@ func TestNewModelCommand(t *testing.T) {
}
func TestShowCurrentModel_WithDefaultModel(t *testing.T) {
cfg := &config.Config{
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "gpt-4",
},
},
ModelList: []config.ModelConfig{
{ModelName: "gpt-4", Model: "openai/gpt-4", APIKey: "test"},
{ModelName: "claude-3", Model: "anthropic/claude-3", APIKey: "test"},
ModelList: []*config.ModelConfig{
{ModelName: "gpt-4", Model: "openai/gpt-4"},
{ModelName: "claude-3", Model: "anthropic/claude-3"},
},
}
}).WithSecurity(&config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"gpt-4": {
APIKeys: []string{"test"},
},
"claude-3": {
APIKeys: []string{"test"},
},
}})
output := captureStdout(func() {
showCurrentModel(cfg)
@@ -81,16 +88,20 @@ func TestShowCurrentModel_WithDefaultModel(t *testing.T) {
}
func TestShowCurrentModel_NoDefaultModel(t *testing.T) {
cfg := &config.Config{
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "",
},
},
ModelList: []config.ModelConfig{
{ModelName: "gpt-4", Model: "openai/gpt-4", APIKey: "test"},
ModelList: []*config.ModelConfig{
{ModelName: "gpt-4", Model: "openai/gpt-4"},
},
}
}).WithSecurity(&config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"gpt-4": {
APIKeys: []string{"test"},
},
}})
output := captureStdout(func() {
showCurrentModel(cfg)
@@ -102,7 +113,7 @@ func TestShowCurrentModel_NoDefaultModel(t *testing.T) {
func TestListAvailableModels_Empty(t *testing.T) {
cfg := &config.Config{
ModelList: []config.ModelConfig{},
ModelList: []*config.ModelConfig{},
}
output := captureStdout(func() {
@@ -113,18 +124,25 @@ func TestListAvailableModels_Empty(t *testing.T) {
}
func TestListAvailableModels_WithModels(t *testing.T) {
cfg := &config.Config{
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "gpt-4",
},
},
ModelList: []config.ModelConfig{
{ModelName: "gpt-4", Model: "openai/gpt-4", APIKey: "test"},
{ModelName: "claude-3", Model: "anthropic/claude-3", APIKey: "test"},
{ModelName: "no-key-model", Model: "openai/test", APIKey: ""},
ModelList: []*config.ModelConfig{
{ModelName: "gpt-4", Model: "openai/gpt-4"},
{ModelName: "claude-3", Model: "anthropic/claude-3"},
{ModelName: "no-key-model", Model: "openai/test"},
},
}
}).WithSecurity(&config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"gpt-4": {
APIKeys: []string{"test"},
},
"claude-3": {
APIKeys: []string{"test"},
},
}})
output := captureStdout(func() {
listAvailableModels(cfg)
@@ -139,17 +157,24 @@ func TestListAvailableModels_WithModels(t *testing.T) {
func TestSetDefaultModel_ValidModel(t *testing.T) {
initTest(t)
cfg := &config.Config{
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "old-model",
},
},
ModelList: []config.ModelConfig{
{ModelName: "new-model", Model: "openai/new-model", APIKey: "test"},
{ModelName: "old-model", Model: "openai/old-model", APIKey: "test"},
ModelList: []*config.ModelConfig{
{ModelName: "new-model", Model: "openai/new-model"},
{ModelName: "old-model", Model: "openai/old-model"},
},
}
}).WithSecurity(&config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"new-model": {
APIKeys: []string{"test"},
},
"old-model": {
APIKeys: []string{"test"},
},
}})
output := captureStdout(func() {
err := setDefaultModel(configPath, cfg, "new-model")
@@ -167,16 +192,20 @@ func TestSetDefaultModel_ValidModel(t *testing.T) {
func TestSetDefaultModel_InvalidModel(t *testing.T) {
initTest(t)
cfg := &config.Config{
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "existing-model",
},
},
ModelList: []config.ModelConfig{
{ModelName: "existing-model", Model: "openai/existing", APIKey: "test"},
ModelList: []*config.ModelConfig{
{ModelName: "existing-model", Model: "openai/existing"},
},
}
}).WithSecurity(&config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"existing-model": {
APIKeys: []string{"test"},
},
}})
assert.Error(t, setDefaultModel(configPath, cfg, "nonexistent-model"))
}
@@ -184,17 +213,24 @@ func TestSetDefaultModel_InvalidModel(t *testing.T) {
func TestSetDefaultModel_ModelWithoutAPIKey(t *testing.T) {
initTest(t)
cfg := &config.Config{
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "existing-model",
},
},
ModelList: []config.ModelConfig{
{ModelName: "existing-model", Model: "openai/existing", APIKey: "test"},
{ModelName: "no-key-model", Model: "openai/nokey", APIKey: ""},
ModelList: []*config.ModelConfig{
{ModelName: "existing-model", Model: "openai/existing"},
{ModelName: "no-key-model", Model: "openai/nokey"},
},
}
}).WithSecurity(&config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"existing-model": {
APIKeys: []string{"test"},
},
"no-key-model": {
APIKeys: []string{""},
},
}})
assert.Error(t, setDefaultModel(configPath, cfg, "no-key-model"))
}
@@ -203,16 +239,20 @@ func TestSetDefaultModel_SaveConfigError(t *testing.T) {
// Use an invalid path to trigger save error
invalidPath := "/nonexistent/directory/config.json"
cfg := &config.Config{
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "old-model",
},
},
ModelList: []config.ModelConfig{
{ModelName: "new-model", Model: "openai/new-model", APIKey: "test"},
ModelList: []*config.ModelConfig{
{ModelName: "new-model", Model: "openai/new-model"},
},
}
}).WithSecurity(&config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"new-model": {
APIKeys: []string{"test"},
},
}})
err := setDefaultModel(invalidPath, cfg, "new-model")
@@ -244,16 +284,20 @@ func TestModelCommandExecution_Show(t *testing.T) {
initTest(t)
// Create a test config
cfg := &config.Config{
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "test-model",
},
},
ModelList: []config.ModelConfig{
{ModelName: "test-model", Model: "openai/test", APIKey: "test"},
ModelList: []*config.ModelConfig{
{ModelName: "test-model", Model: "openai/test"},
},
}
}).WithSecurity(&config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"test-model": {
APIKeys: []string{"test"},
},
}})
err := config.SaveConfig(configPath, cfg)
require.NoError(t, err)
@@ -271,17 +315,25 @@ func TestModelCommandExecution_Show(t *testing.T) {
func TestModelCommandExecution_Set(t *testing.T) {
initTest(t)
cfg := &config.Config{
sec := &config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"old-model": {
APIKeys: []string{"test"},
},
"new-model": {
APIKeys: []string{"test"},
},
}}
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "old-model",
},
},
ModelList: []config.ModelConfig{
{ModelName: "old-model", Model: "openai/old", APIKey: "test"},
{ModelName: "new-model", Model: "openai/new", APIKey: "test"},
ModelList: []*config.ModelConfig{
{ModelName: "old-model", Model: "openai/old"},
{ModelName: "new-model", Model: "openai/new"},
},
}
}).WithSecurity(sec)
err := config.SaveConfig(configPath, cfg)
require.NoError(t, err)
@@ -305,18 +357,28 @@ func TestModelCommandExecution_TooManyArgs(t *testing.T) {
}
func TestListAvailableModels_MarkerLogic(t *testing.T) {
cfg := &config.Config{
cfg := (&config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
ModelName: "middle-model",
},
},
ModelList: []config.ModelConfig{
{ModelName: "first-model", Model: "openai/first", APIKey: "test"},
{ModelName: "middle-model", Model: "openai/middle", APIKey: "test"},
{ModelName: "last-model", Model: "openai/last", APIKey: "test"},
ModelList: []*config.ModelConfig{
{ModelName: "first-model", Model: "openai/first"},
{ModelName: "middle-model", Model: "openai/middle"},
{ModelName: "last-model", Model: "openai/last"},
},
}
}).WithSecurity(&config.SecurityConfig{ModelList: map[string]config.ModelSecurityEntry{
"first-model": {
APIKeys: []string{"test"},
},
"middle-model": {
APIKeys: []string{"test"},
},
"last-model": {
APIKeys: []string{"test"},
},
}})
output := captureStdout(func() {
listAvailableModels(cfg)
+1 -1
View File
@@ -31,7 +31,7 @@ func NewSkillsCommand() *cobra.Command {
d.workspace = cfg.WorkspacePath()
installer, err := skills.NewSkillInstaller(
d.workspace,
cfg.Tools.Skills.Github.Token,
cfg.Tools.Skills.Github.Token(),
cfg.Tools.Skills.Github.Proxy,
)
if err != nil {
+24 -2
View File
@@ -64,9 +64,20 @@ func skillsInstallFromRegistry(cfg *config.Config, registryName, slug string) er
fmt.Printf("Installing skill '%s' from %s registry...\n", slug, registryName)
clawHubConfig := cfg.Tools.Skills.Registries.ClawHub
registryMgr := skills.NewRegistryManagerFromConfig(skills.RegistryConfig{
MaxConcurrentSearches: cfg.Tools.Skills.MaxConcurrentSearches,
ClawHub: skills.ClawHubConfig(cfg.Tools.Skills.Registries.ClawHub),
ClawHub: skills.ClawHubConfig{
Enabled: clawHubConfig.Enabled,
BaseURL: clawHubConfig.BaseURL,
AuthToken: clawHubConfig.AuthToken(),
SearchPath: clawHubConfig.SearchPath,
SkillsPath: clawHubConfig.SkillsPath,
DownloadPath: clawHubConfig.DownloadPath,
Timeout: clawHubConfig.Timeout,
MaxZipSize: clawHubConfig.MaxZipSize,
MaxResponseSize: clawHubConfig.MaxResponseSize,
},
})
registry := registryMgr.GetRegistry(registryName)
@@ -226,9 +237,20 @@ func skillsSearchCmd(query string) {
return
}
clawHubConfig := cfg.Tools.Skills.Registries.ClawHub
registryMgr := skills.NewRegistryManagerFromConfig(skills.RegistryConfig{
MaxConcurrentSearches: cfg.Tools.Skills.MaxConcurrentSearches,
ClawHub: skills.ClawHubConfig(cfg.Tools.Skills.Registries.ClawHub),
ClawHub: skills.ClawHubConfig{
Enabled: clawHubConfig.Enabled,
BaseURL: clawHubConfig.BaseURL,
AuthToken: clawHubConfig.AuthToken(),
SearchPath: clawHubConfig.SearchPath,
SkillsPath: clawHubConfig.SkillsPath,
DownloadPath: clawHubConfig.DownloadPath,
Timeout: clawHubConfig.Timeout,
MaxZipSize: clawHubConfig.MaxZipSize,
MaxResponseSize: clawHubConfig.MaxResponseSize,
},
})
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)