Files
HomeAgent/internal/plugins/openclaw/plugin.go
root 239a22899b fix: 模型思考模式配置 + Unicode 截断 + 审计修复 (13 files)
模型模式:
- 新增 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 退出路径
2026-07-03 20:46:04 +08:00

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
}