fix: use short config keys in RegisterDef, remove generics helpers

- qq, a2a, bili, files, rss: RegisterDef keys changed from
  namespaced (e.g. "plugin.qq.listen") to short flat keys ("listen")
- a2a, bili: Get() calls updated to match short keys
- rss: replaced readCfg generics with getSetting, added SetAutoRestart(true)
- files: already uses short key Get, only RegisterDef needed fixing
This commit is contained in:
root
2026-07-21 13:20:13 +08:00
parent 52dc22f86f
commit 1a3e72e899
7 changed files with 124 additions and 156 deletions

View File

@ -28,7 +28,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
tp := p.name + "_" tp := p.name + "_"
s.Settings().RegisterDef(sdk.ConfigDef{ s.Settings().RegisterDef(sdk.ConfigDef{
Key: "plugin." + p.name + ".listen", Default: "127.0.0.1:12000", Key: "listen", Default: "127.0.0.1:12000",
Type: "string", DisplayName: "监听地址", Type: "string", DisplayName: "监听地址",
Description: "A2A 服务端监听地址,设为空可禁用 HTTP 服务", Description: "A2A 服务端监听地址,设为空可禁用 HTTP 服务",
Category: p.name, Category: p.name,
@ -60,7 +60,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
}, p.handleA2ADiscover) }, p.handleA2ADiscover)
// Inbound HTTP server // Inbound HTTP server
if addr, _ := s.Settings().Get("plugin." + p.name + ".listen"); addr != nil { if addr, _ := s.Settings().Get("listen"); addr != nil {
if addrStr, ok := addr.(string); ok && addrStr != "" { if addrStr, ok := addr.(string); ok && addrStr != "" {
p.startServer(addrStr) p.startServer(addrStr)
} }

View File

@ -29,50 +29,48 @@ func NewPlugin(name string, config map[string]interface{}) (sdk.Plugin, error) {
func (p *Plugin) Name() string { return p.name } func (p *Plugin) Name() string { return p.name }
func readCfg[T string | int64 | float64](s sdk.SettingsAPI, key string, fallback T) T { func getSetting[T string | int64 | float64](s sdk.SettingsAPI, key string, def T) T {
v, err := s.Get(key) v, err := s.Get(key)
if err == nil && v != nil { if err != nil || v == nil {
if sv, ok := v.(string); ok && sv != "" { return def
switch any(fallback).(type) { }
case string: switch any(def).(type) {
return any(sv).(T) case string:
case int64: if sv, ok := v.(string); ok {
if n, err := strconv.ParseInt(sv, 10, 64); err == nil { return any(sv).(T)
return any(n).(T) }
} case int64:
case float64: switch n := v.(type) {
if n, err := strconv.ParseFloat(sv, 64); err == nil { case float64:
return any(n).(T) return any(int64(n)).(T)
} case int64:
return any(n).(T)
case string:
if i, err := strconv.ParseInt(n, 10, 64); err == nil {
return any(i).(T)
}
}
case float64:
switch n := v.(type) {
case float64:
return any(n).(T)
case int64:
return any(float64(n)).(T)
case string:
if f, err := strconv.ParseFloat(n, 64); err == nil {
return any(f).(T)
} }
} }
} }
v2, err2 := s.GetCore("plugin." + "ai_image" + "." + key) return def
if err2 == nil && v2 != nil {
if sv, ok := v2.(string); ok && sv != "" {
switch any(fallback).(type) {
case string:
return any(sv).(T)
case int64:
if n, err := strconv.ParseInt(sv, 10, 64); err == nil {
return any(n).(T)
}
case float64:
if n, err := strconv.ParseFloat(sv, 64); err == nil {
return any(n).(T)
}
}
}
}
return fallback
} }
func readArg[T string | int64 | float64](args map[string]interface{}, key string, fallback T) T { func getArg[T string | int64 | float64](args map[string]interface{}, key string, def T) T {
v, ok := args[key] v, ok := args[key]
if !ok || v == nil { if !ok || v == nil {
return fallback return def
} }
switch any(fallback).(type) { switch any(def).(type) {
case string: case string:
if s, ok := v.(string); ok { if s, ok := v.(string); ok {
return any(s).(T) return any(s).(T)
@ -100,40 +98,40 @@ func readArg[T string | int64 | float64](args map[string]interface{}, key string
} }
} }
} }
return fallback return def
} }
func (p *Plugin) Start(s *sdk.PluginSDK) error { func (p *Plugin) Start(s *sdk.PluginSDK) error {
s.SetAutoRestart(true)
p.sdk = s p.sdk = s
p.apiKey = readCfg(s.Settings(), "api_key", "")
p.provider = readCfg(s.Settings(), "provider", "openai")
p.model = readCfg(s.Settings(), "model", "dall-e-3")
p.size = readCfg(s.Settings(), "size", "1024x1024")
p.client = &http.Client{Timeout: 120 * time.Second} p.client = &http.Client{Timeout: 120 * time.Second}
s.Settings().RegisterDef(sdk.ConfigDef{ s.Settings().RegisterDef(sdk.ConfigDef{
Key: "plugin.ai_image.api_key", Default: "", Type: "string", Key: "api_key", Default: "", Type: "string",
DisplayName: "API Key", Description: "OpenAI / Stable Diffusion API Key", DisplayName: "API Key", Description: "OpenAI / Stable Diffusion API Key",
Category: "ai_image", Secret: true, Category: "ai_image", Secret: true,
}) })
s.Settings().RegisterDef(sdk.ConfigDef{ s.Settings().RegisterDef(sdk.ConfigDef{
Key: "plugin.ai_image.provider", Default: "openai", Type: "string", Key: "provider", Default: "openai", Type: "string",
DisplayName: "Provider", Description: "Image generation provider: openai / stability", DisplayName: "Provider", Description: "Image generation provider: openai / stability",
Category: "ai_image", Category: "ai_image",
}) })
s.Settings().RegisterDef(sdk.ConfigDef{ s.Settings().RegisterDef(sdk.ConfigDef{
Key: "plugin.ai_image.model", Default: "dall-e-3", Type: "string", Key: "model", Default: "dall-e-3", Type: "string",
DisplayName: "Model", Description: "Model name (dall-e-3, sd-xl, etc.)", DisplayName: "Model", Description: "Model name (dall-e-3, sd-xl, etc.)",
Category: "ai_image", Category: "ai_image",
}) })
s.Settings().RegisterDef(sdk.ConfigDef{ s.Settings().RegisterDef(sdk.ConfigDef{
Key: "plugin.ai_image.size", Default: "1024x1024", Type: "string", Key: "size", Default: "1024x1024", Type: "string",
DisplayName: "Size", Description: "Default image size (1024x1024, 1024x1792, 1792x1024)", DisplayName: "Size", Description: "Default image size (1024x1024, 1024x1792, 1792x1024)",
Category: "ai_image", Category: "ai_image",
}) })
p.apiKey = getSetting(s.Settings(), "api_key", "")
p.provider = getSetting(s.Settings(), "provider", "openai")
p.model = getSetting(s.Settings(), "model", "dall-e-3")
p.size = getSetting(s.Settings(), "size", "1024x1024")
tp := p.name + "_" tp := p.name + "_"
s.RegisterTool(tp+"generate", sdk.ToolDef{ s.RegisterTool(tp+"generate", sdk.ToolDef{
Name: tp + "generate", Description: "Generate image from text prompt using AI. Returns image URL.", Name: tp + "generate", Description: "Generate image from text prompt using AI. Returns image URL.",
@ -179,20 +177,20 @@ type openAIResp struct {
} }
func (p *Plugin) handleGenerate(args map[string]interface{}) (interface{}, error) { func (p *Plugin) handleGenerate(args map[string]interface{}) (interface{}, error) {
prompt := readArg(args, "prompt", "") prompt := getArg(args, "prompt", "")
if prompt == "" { if prompt == "" {
return map[string]interface{}{"isError": true, "content": "prompt is required"}, nil return map[string]interface{}{"isError": true, "content": "prompt is required"}, nil
} }
p.apiKey = readCfg(p.sdk.Settings(), "api_key", p.apiKey) key := getSetting(p.sdk.Settings(), "api_key", p.apiKey)
if p.apiKey == "" { if key == "" {
return map[string]interface{}{"isError": true, "content": "API key not configured. Set plugin.ai_image.api_key via CLI."}, nil return map[string]interface{}{"isError": true, "content": "API key not configured. Set plugin.ai_image.api_key via CLI."}, nil
} }
provider := readCfg(p.sdk.Settings(), "provider", p.provider) provider := getSetting(p.sdk.Settings(), "provider", p.provider)
model := readArg(args, "model", readCfg(p.sdk.Settings(), "model", p.model)) model := getArg(args, "model", getSetting(p.sdk.Settings(), "model", p.model))
size := readArg(args, "size", readCfg(p.sdk.Settings(), "size", p.size)) size := getArg(args, "size", getSetting(p.sdk.Settings(), "size", p.size))
n := readArg(args, "n", int64(1)) n := getArg(args, "n", int64(1))
if n < 1 { if n < 1 {
n = 1 n = 1
} }
@ -202,15 +200,15 @@ func (p *Plugin) handleGenerate(args map[string]interface{}) (interface{}, error
switch provider { switch provider {
case "openai": case "openai":
return p.generateOpenAI(prompt, model, size, int(n)) return p.generateOpenAI(prompt, model, size, int(n), key)
case "stability": case "stability":
return p.generateStability(prompt, model, size, int(n)) return p.generateStability(prompt, model, size, int(n), key)
default: default:
return map[string]interface{}{"isError": true, "content": "Unknown provider: " + provider + ". Supported: openai, stability"}, nil return map[string]interface{}{"isError": true, "content": "Unknown provider: " + provider + ". Supported: openai, stability"}, nil
} }
} }
func (p *Plugin) generateOpenAI(prompt, model, size string, n int) (interface{}, error) { func (p *Plugin) generateOpenAI(prompt, model, size string, n int, apiKey string) (interface{}, error) {
body := openAIReq{ body := openAIReq{
Model: model, Model: model,
Prompt: prompt, Prompt: prompt,
@ -222,7 +220,7 @@ func (p *Plugin) generateOpenAI(prompt, model, size string, n int) (interface{},
b, _ := json.Marshal(body) b, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", "https://api.openai.com/v1/images/generations", bytes.NewReader(b)) req, _ := http.NewRequest("POST", "https://api.openai.com/v1/images/generations", bytes.NewReader(b))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+p.apiKey) req.Header.Set("Authorization", "Bearer "+apiKey)
resp, err := p.client.Do(req) resp, err := p.client.Do(req)
if err != nil { if err != nil {
@ -279,7 +277,7 @@ type stabilityResp struct {
Message string `json:"message,omitempty"` Message string `json:"message,omitempty"`
} }
func (p *Plugin) generateStability(prompt, model, size string, n int) (interface{}, error) { func (p *Plugin) generateStability(prompt, model, size string, n int, apiKey string) (interface{}, error) {
width, height := 1024, 1024 width, height := 1024, 1024
if parts := strings.Split(size, "x"); len(parts) == 2 { if parts := strings.Split(size, "x"); len(parts) == 2 {
if w, err := strconv.Atoi(parts[0]); err == nil { if w, err := strconv.Atoi(parts[0]); err == nil {
@ -302,7 +300,7 @@ func (p *Plugin) generateStability(prompt, model, size string, n int) (interface
b, _ := json.Marshal(body) b, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", apiURL, bytes.NewReader(b)) req, _ := http.NewRequest("POST", apiURL, bytes.NewReader(b))
req.Header.Set("Content-Type", "application/json") req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+p.apiKey) req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Accept", "application/json") req.Header.Set("Accept", "application/json")
resp, err := p.client.Do(req) resp, err := p.client.Do(req)

View File

@ -25,7 +25,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
tp := p.name + "_" tp := p.name + "_"
s.Settings().RegisterDef(sdk.ConfigDef{ s.Settings().RegisterDef(sdk.ConfigDef{
Key: "plugin." + p.name + ".output_dir", Default: "/tmp/bili_videos", Key: "output_dir", Default: "/tmp/bili_videos",
Type: "string", DisplayName: "下载目录", Type: "string", DisplayName: "下载目录",
Description: "B站视频下载后的保存目录", Description: "B站视频下载后的保存目录",
Category: p.name, Category: p.name,
@ -81,7 +81,7 @@ func (p *Plugin) handleBiliVideo(args map[string]interface{}) (interface{}, erro
outputDir := "/tmp/bili_videos" outputDir := "/tmp/bili_videos"
if p.sdk != nil { if p.sdk != nil {
if v, _ := p.sdk.Settings().Get("plugin." + p.name + ".output_dir"); v != nil { if v, _ := p.sdk.Settings().Get("output_dir"); v != nil {
if s, ok := v.(string); ok && s != "" { if s, ok := v.(string); ok && s != "" {
outputDir = s outputDir = s
} }

View File

@ -25,7 +25,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
s.SetAutoRestart(true) s.SetAutoRestart(true)
p.sdk = s p.sdk = s
s.Settings().RegisterDef(sdk.ConfigDef{ s.Settings().RegisterDef(sdk.ConfigDef{
Key: "plugin.files.dir", Key: "dir",
Default: "/", Default: "/",
Type: "string", Type: "string",
DisplayName: "文件系统根目录", DisplayName: "文件系统根目录",

View File

@ -123,17 +123,17 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
s.SetAutoRestart(true) s.SetAutoRestart(true)
p.sdk = s p.sdk = s
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.listen", Default: "0.0.0.0:25580", Type: "string", DisplayName: "监听地址", Description: "Webhook HTTP 监听地址", Category: "qq"}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "listen", Default: "0.0.0.0:25580", Type: "string", DisplayName: "监听地址", Description: "Webhook HTTP 监听地址", Category: "qq"})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.napcat_url", Default: "http://127.0.0.1:3000", Type: "string", DisplayName: "NapCat 地址", Description: "NapCat HTTP API 基础 URL", Category: "qq"}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "napcat_url", Default: "http://127.0.0.1:3000", Type: "string", DisplayName: "NapCat 地址", Description: "NapCat HTTP API 基础 URL", Category: "qq"})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.admin", Default: "", Type: "string", DisplayName: "管理员 QQ", Description: "管理员 QQ 号,收到其消息时标记【重要!老大消息】", Category: "qq"}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "admin", Default: "", Type: "string", DisplayName: "管理员 QQ", Description: "管理员 QQ 号,收到其消息时标记【重要!老大消息】", Category: "qq"})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.dm_policy", Default: "open", Type: "string", DisplayName: "私聊策略", Description: "open / allowlist / disabled", Category: "qq", Options: []string{"open", "allowlist", "disabled"}}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "dm_policy", Default: "open", Type: "string", DisplayName: "私聊策略", Description: "open / allowlist / disabled", Category: "qq", Options: []string{"open", "allowlist", "disabled"}})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.allow_from", Default: "", Type: "string", DisplayName: "私聊白名单", Description: "允许私聊机器人的 QQ 号列表,逗号分隔", Category: "qq"}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "allow_from", Default: "", Type: "string", DisplayName: "私聊白名单", Description: "允许私聊机器人的 QQ 号列表,逗号分隔", Category: "qq"})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.group_policy", Default: "open", Type: "string", DisplayName: "群聊策略", Description: "open / allowlist / disabled", Category: "qq", Options: []string{"open", "allowlist", "disabled"}}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "group_policy", Default: "open", Type: "string", DisplayName: "群聊策略", Description: "open / allowlist / disabled", Category: "qq", Options: []string{"open", "allowlist", "disabled"}})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.group_allow_from", Default: "", Type: "string", DisplayName: "群聊白名单", Description: "允许接入的群号列表,逗号分隔", Category: "qq"}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "group_allow_from", Default: "", Type: "string", DisplayName: "群聊白名单", Description: "允许接入的群号列表,逗号分隔", Category: "qq"})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.forward_rules", Default: "[]", Type: "string", DisplayName: "转发规则", Description: "JSON 数组,每项 {group_id,host,port,password,template}。匹配的群消息通过 RCON 转发到 Minecraft。template 支持 {nickname} {message} 占位", Category: "qq"}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "forward_rules", Default: "[]", Type: "string", DisplayName: "转发规则", Description: "JSON 数组,每项 {group_id,host,port,password,template}。匹配的群消息通过 RCON 转发到 Minecraft。template 支持 {nickname} {message} 占位", Category: "qq"})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.files_dir", Default: "/home/newqqagent/agentfs/merged/qq_files", Type: "string", DisplayName: "文件存储目录", Description: "从QQ接收的文件保存目录(CQ file/image 自动下载到此目录)", Category: "qq"}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "files_dir", Default: "/home/newqqagent/agentfs/merged/qq_files", Type: "string", DisplayName: "文件存储目录", Description: "从QQ接收的文件保存目录(CQ file/image 自动下载到此目录)", Category: "qq"})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.remote_dir", Default: "/home/program/qq-workspace/remote", Type: "string", DisplayName: "NapCat容器共享目录", Description: "与NapCat容器共享的文件目录,主机路径。发文件时文件会复制到此目录,NapCat内部映射为/app/files/", Category: "qq"}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "remote_dir", Default: "/home/program/qq-workspace/remote", Type: "string", DisplayName: "NapCat容器共享目录", Description: "与NapCat容器共享的文件目录,主机路径。发文件时文件会复制到此目录,NapCat内部映射为/app/files/", Category: "qq"})
s.Settings().RegisterDef(sdk.ConfigDef{Key: "plugin.qq.agentfs_dir", Default: "/home/newqqagent/agentfs/merged", Type: "string", DisplayName: "AgentFS目录", Description: "文件读写的工作目录,read_document/video_download 等工具的默认工作目录", Category: "qq"}) s.Settings().RegisterDef(sdk.ConfigDef{Key: "agentfs_dir", Default: "/home/newqqagent/agentfs/merged", Type: "string", DisplayName: "AgentFS目录", Description: "文件读写的工作目录,read_document/video_download 等工具的默认工作目录", Category: "qq"})
settings := s.Settings() settings := s.Settings()

View File

@ -43,81 +43,61 @@ func NewPlugin(name string, config map[string]interface{}) (sdk.Plugin, error) {
func (p *Plugin) Name() string { return p.name } func (p *Plugin) Name() string { return p.name }
func readCfg[T string | int64 | float64](s sdk.SettingsAPI, key string, fallback T) T { func getSetting[T string | int64 | float64](s sdk.SettingsAPI, key string, fallback T) T {
v, err := s.Get(key) v, err := s.Get(key)
if err == nil && v != nil { if err != nil || v == nil {
if sv, ok := v.(string); ok && sv != "" { return fallback
switch any(fallback).(type) { }
case string: switch any(fallback).(type) {
return any(sv).(T) case string:
case int64: if sv, ok := v.(string); ok {
if n, err := strconv.ParseInt(sv, 10, 64); err == nil { return any(sv).(T)
return any(n).(T) }
} case int64:
case float64: switch val := v.(type) {
if n, err := strconv.ParseFloat(sv, 64); err == nil { case float64:
return any(n).(T) return any(int64(val)).(T)
} case string:
if n, err := strconv.ParseInt(val, 10, 64); err == nil {
return any(n).(T)
} }
} }
} case float64:
v2, err2 := s.GetCore("plugin." + "rss" + "." + key) switch val := v.(type) {
if err2 == nil && v2 != nil { case float64:
if sv, ok := v2.(string); ok && sv != "" { return any(val).(T)
switch any(fallback).(type) { case string:
case string: if n, err := strconv.ParseFloat(val, 64); err == nil {
return any(sv).(T) return any(n).(T)
case int64:
if n, err := strconv.ParseInt(sv, 10, 64); err == nil {
return any(n).(T)
}
case float64:
if n, err := strconv.ParseFloat(sv, 64); err == nil {
return any(n).(T)
}
} }
} }
} }
return fallback return fallback
} }
func readArg[T string | int64 | float64](args map[string]interface{}, key string, fallback T) T { func readArg(args map[string]interface{}, key string) string {
v, ok := args[key] if v, ok := args[key]; ok && v != nil {
if !ok || v == nil {
return fallback
}
switch any(fallback).(type) {
case string:
if s, ok := v.(string); ok { if s, ok := v.(string); ok {
return any(s).(T) return s
} }
case int64: }
return ""
}
func readArgInt(args map[string]interface{}, key string, fallback int) int {
if v, ok := args[key]; ok && v != nil {
switch n := v.(type) { switch n := v.(type) {
case float64: case float64:
return any(int64(n)).(T) return int(n)
case int64: case int64:
return any(n).(T) return int(n)
case string:
if i, err := strconv.ParseInt(n, 10, 64); err == nil {
return any(i).(T)
}
}
case float64:
switch n := v.(type) {
case float64:
return any(n).(T)
case int64:
return any(float64(n)).(T)
case string:
if f, err := strconv.ParseFloat(n, 64); err == nil {
return any(f).(T)
}
} }
} }
return fallback return fallback
} }
func (p *Plugin) Start(s *sdk.PluginSDK) error { func (p *Plugin) Start(s *sdk.PluginSDK) error {
s.SetAutoRestart(true)
p.sdk = s p.sdk = s
p.client = &http.Client{Timeout: 30 * time.Second} p.client = &http.Client{Timeout: 30 * time.Second}
p.fp = gofeed.NewParser() p.fp = gofeed.NewParser()
@ -134,7 +114,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
p.loadData() p.loadData()
s.Settings().RegisterDef(sdk.ConfigDef{ s.Settings().RegisterDef(sdk.ConfigDef{
Key: "plugin.rss.poll_interval", Default: "30", Type: "string", Key: "poll_interval", Default: "30", Type: "string",
DisplayName: "Poll Interval", Description: "Default polling interval in minutes (default: 30)", DisplayName: "Poll Interval", Description: "Default polling interval in minutes (default: 30)",
Category: "rss", Category: "rss",
}) })
@ -179,7 +159,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
}, },
}, p.handleCheckNow) }, p.handleCheckNow)
pollMin := int(readCfg(s.Settings(), "poll_interval", int64(30))) pollMin := int(getSetting(s.Settings(), "poll_interval", int64(30)))
if pollMin < 5 { if pollMin < 5 {
pollMin = 5 pollMin = 5
} }
@ -300,7 +280,7 @@ func (p *Plugin) checkFeed(sub FeedSub) {
} }
func (p *Plugin) handleSubscribe(args map[string]interface{}) (interface{}, error) { func (p *Plugin) handleSubscribe(args map[string]interface{}) (interface{}, error) {
url := readArg(args, "url", "") url := readArg(args, "url")
if url == "" { if url == "" {
return map[string]interface{}{"isError": true, "content": "URL is required"}, nil return map[string]interface{}{"isError": true, "content": "URL is required"}, nil
} }
@ -314,7 +294,7 @@ func (p *Plugin) handleSubscribe(args map[string]interface{}) (interface{}, erro
} }
p.mu.RUnlock() p.mu.RUnlock()
interval := int(readArg(args, "interval", int64(30))) interval := readArgInt(args, "interval", 30)
if interval < 5 { if interval < 5 {
interval = 5 interval = 5
} }
@ -360,7 +340,7 @@ func (p *Plugin) handleSubscribe(args map[string]interface{}) (interface{}, erro
} }
func (p *Plugin) handleUnsubscribe(args map[string]interface{}) (interface{}, error) { func (p *Plugin) handleUnsubscribe(args map[string]interface{}) (interface{}, error) {
url := readArg(args, "url", "") url := readArg(args, "url")
if url == "" { if url == "" {
return map[string]interface{}{"isError": true, "content": "URL is required"}, nil return map[string]interface{}{"isError": true, "content": "URL is required"}, nil
} }

View File

@ -32,18 +32,15 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
p.sdk = s p.sdk = s
p.client = &http.Client{Timeout: 15 * time.Second} p.client = &http.Client{Timeout: 15 * time.Second}
loc, err := s.Settings().Get("default_location") s.Settings().RegisterDef(sdk.ConfigDef{
if err == nil && loc != nil { Key: "default_location", Default: "", Type: "string",
if v, ok := loc.(string); ok && v != "" { DisplayName: "Default Location", Description: "Default city name for weather queries, e.g. Beijing",
p.defaultLoc = v Category: "weather",
} })
}
if p.defaultLoc == "" { if v, _ := s.Settings().Get("default_location"); v != nil {
v, err := s.Settings().GetCore("plugin.weather.default_location") if vs, ok := v.(string); ok {
if err == nil && v != nil { p.defaultLoc = vs
if vs, ok := v.(string); ok && vs != "" {
p.defaultLoc = vs
}
} }
} }
@ -51,14 +48,7 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
if dataHome == "" { if dataHome == "" {
dataHome = "/tmp" dataHome = "/tmp"
} }
dataDir := filepath.Join(dataHome, ".homeagent", "weather") os.MkdirAll(filepath.Join(dataHome, ".homeagent", "weather"), 0755)
os.MkdirAll(dataDir, 0755)
s.Settings().RegisterDef(sdk.ConfigDef{
Key: "plugin.weather.default_location", Default: "", Type: "string",
DisplayName: "Default Location", Description: "Default city name for weather queries, e.g. Beijing",
Category: "weather",
})
tp := p.name + "_" tp := p.name + "_"
s.RegisterTool(tp+"current", sdk.ToolDef{ s.RegisterTool(tp+"current", sdk.ToolDef{
@ -382,7 +372,7 @@ func (p *Plugin) handleSetLocation(args map[string]interface{}) (interface{}, er
return map[string]interface{}{"isError": true, "content": "Location is required"}, nil return map[string]interface{}{"isError": true, "content": "Location is required"}, nil
} }
p.sdk.Settings().SetCore("plugin.weather.default_location", loc) p.sdk.Settings().Set("default_location", loc)
p.defaultLoc = loc p.defaultLoc = loc
return map[string]interface{}{"content": fmt.Sprintf("Default location set to: %s", loc)}, nil return map[string]interface{}{"content": fmt.Sprintf("Default location set to: %s", loc)}, nil
} }