mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 17:38:10 +00:00
模型模式: - 新增 LLMConfig/Source.ThinkingEnabled 配置,通过 ExtraBody 控制 DeepSeek thinking mode,默认关闭 - SeedDefaults/ToConfig 读写 core.llm.thinking_enabled - deepseek.lua 移除硬编码 temperature=0 Unicode 截断: - truncateStr 改按 rune 计数,修复中文截断乱码 审计修复 (Critical): - graph.go: defer rows.Close 在 for 循环 → 显式 Close (连接池泄漏) - cli/openclaw/plugin.go: bare type assertion → comma-ok (panic) - channel.go: payload["type"].(string) → comma-ok (panic) - webui/handler.go: .(string) → fmt.Sprint (panic) - agent.go: 添加 nil provider 错误返回 审计修复 (High): - events/bus.go: copy handler slice under RLock (data race) - webui/handler.go: SSE 通过 channel 串行化写入 (data race) - timer/plugin.go: time.Sleep → select with stopCh (Stop 阻塞) - provider.go: stream ch <- 添加 select ctx.Done (goroutine 泄漏) - main.go: outputCh goroutine 添加 ctx.Done 退出路径
93 lines
2.2 KiB
Go
93 lines
2.2 KiB
Go
package openclaw
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"gitcode.com/JianFeeeee/HomeAgent/internal/plugin"
|
|
sdk "gitcode.com/JianFeeeee/HomeAgent/internal/sdk"
|
|
)
|
|
|
|
// SkillsDir 由 main.go 在 Load() 前设置,指向 SKILL.md 存放目录。
|
|
var SkillsDir string
|
|
|
|
func init() {
|
|
plugin.RegisterFactory("openclaw", func(name string, config map[string]interface{}) (sdk.Plugin, error) {
|
|
dir := SkillsDir
|
|
if dir == "" {
|
|
dataDir, ok := config["data_dir"].(string)
|
|
if !ok {
|
|
return nil, fmt.Errorf("openclaw plugin: config missing 'data_dir' or not a string")
|
|
}
|
|
dir = filepath.Join(dataDir, "skills")
|
|
}
|
|
return New(name, dir), nil
|
|
})
|
|
}
|
|
|
|
type Plugin struct {
|
|
name string
|
|
skillsDir string
|
|
skills []*plugin.SKILLPlugin
|
|
}
|
|
|
|
func New(name, skillsDir string) *Plugin {
|
|
return &Plugin{
|
|
name: name,
|
|
skillsDir: skillsDir,
|
|
}
|
|
}
|
|
|
|
func (p *Plugin) Name() string { return p.name }
|
|
|
|
func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
|
entries, err := os.ReadDir(p.skillsDir)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil
|
|
}
|
|
return fmt.Errorf("read skills dir %s: %w", p.skillsDir, err)
|
|
}
|
|
|
|
for _, entry := range entries {
|
|
skillPath := filepath.Join(p.skillsDir, entry.Name())
|
|
sk, err := plugin.LoadSKILL(skillPath)
|
|
if err != nil {
|
|
log.Printf("[openclaw] load skill %s: %v", entry.Name(), err)
|
|
continue
|
|
}
|
|
p.skills = append(p.skills, sk)
|
|
|
|
// Register each tool defined in the SKILL
|
|
for _, td := range sk.Tools() {
|
|
name := td.Name
|
|
def := sdk.ToolDef{
|
|
Name: name,
|
|
Description: td.Description,
|
|
Parameters: td.Parameters,
|
|
}
|
|
// SKILL tools are informational (advisory) — no handler
|
|
if err := s.RegisterTool(name, def, nil); err != nil {
|
|
log.Printf("[openclaw] register tool %s: %v", name, err)
|
|
}
|
|
}
|
|
|
|
// Register IO config as a channel if defined
|
|
if iocfg := sk.IOConfig(); iocfg != nil {
|
|
log.Printf("[openclaw] skill %s io: type=%s in=%s out=%s caps=%v",
|
|
sk.Name(), iocfg.Type, iocfg.InputRoute, iocfg.OutputRoute, iocfg.OutputCaps)
|
|
}
|
|
|
|
log.Printf("[openclaw] loaded skill: %s v%s", sk.Name(), sk.Version())
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (p *Plugin) Stop() error {
|
|
p.skills = nil
|
|
return nil
|
|
}
|