mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-04 00:03:59 +00:00
refactor: migrate built-in plugins to SDK-only interface
- Six-phase plan complete: webui/cli/healthcheck/pluginmgr/clawhubadapter now interact with the kernel exclusively via internal/sdk interfaces; all Configure() calls and package-level global injection removed - buildSDK in internal/plugin/registry.go is the single assembly point - Add internal/sdk/events.go exporting event types/constants - Fix ProviderManager cooldown sharing: LuaAdaptedProvider.Name() now returns the source name instead of lua_<adapter>, so multiple sources sharing an adapter (single script load via shared VM AdapterCache) no longer share failure-cooldown state - Verified: build/vet/tests green, deployed to homeagent.service with full plugin capability testing via local OpenAI-compatible mock
This commit is contained in:
@ -31,18 +31,11 @@ var pySimulatorSrc string
|
||||
//go:embed simulator/openclaw_cli.js
|
||||
var openclawCliSrc string
|
||||
|
||||
var SkillsDir string
|
||||
var SimulatorDir string
|
||||
|
||||
func init() {
|
||||
plugin.RegisterPluginMeta("clawhubadapter", "ClawHub 适配器", "ClawHub Adapter")
|
||||
plugin.RegisterFactory("clawhubadapter", 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("clawhubadapter plugin: config missing 'data_dir' or not a string")
|
||||
}
|
||||
dir := ""
|
||||
if dataDir, ok := config["data_dir"].(string); ok && dataDir != "" {
|
||||
dir = filepath.Join(dataDir, "skills")
|
||||
}
|
||||
return New(name, dir), nil
|
||||
@ -63,8 +56,8 @@ type Plugin struct {
|
||||
}
|
||||
|
||||
func New(name, skillsDir string) *Plugin {
|
||||
sd := SimulatorDir
|
||||
if sd == "" {
|
||||
sd := ""
|
||||
if skillsDir != "" {
|
||||
sd = filepath.Join(skillsDir, ".simulator")
|
||||
}
|
||||
return &Plugin{
|
||||
@ -100,6 +93,20 @@ func (p *Plugin) Start(s *sdk.PluginSDK) error {
|
||||
p.simulatorDir = s
|
||||
}
|
||||
}
|
||||
// 默认目录:内核 data_dir 下 skills 目录(与配置 core.daemon.data_dir 对齐)
|
||||
if p.skillsDir == "" {
|
||||
if v, _ := s.Settings().GetCore("daemon.data_dir"); v != nil {
|
||||
if dir, ok := v.(string); ok && dir != "" {
|
||||
p.skillsDir = filepath.Join(dir, "skills")
|
||||
}
|
||||
}
|
||||
}
|
||||
if p.skillsDir == "" {
|
||||
p.skillsDir = filepath.Join("data", "skills")
|
||||
}
|
||||
if p.simulatorDir == "" {
|
||||
p.simulatorDir = filepath.Join(p.skillsDir, ".simulator")
|
||||
}
|
||||
|
||||
// Launch OC plugin manager first (handles OC-format plugin installation and lifecycle)
|
||||
os.MkdirAll(p.skillsDir, 0755)
|
||||
@ -283,7 +290,7 @@ func (p *Plugin) launchManager(s *sdk.PluginSDK) error {
|
||||
// Ensure skills dir exists for the manager to scan
|
||||
os.MkdirAll(p.skillsDir, 0755)
|
||||
|
||||
sp, err := launchProcess("node", managerPath, p.skillsDir, "manager")
|
||||
sp, err := launchProcess("node", managerPath, p.skillsDir, "manager", p.simulatorDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("launch manager: %w", err)
|
||||
}
|
||||
@ -775,7 +782,7 @@ func (p *Plugin) loadPySidecar(s *sdk.PluginSDK, dir, name string) error {
|
||||
}
|
||||
}
|
||||
|
||||
sp, err := launchProcess(pythonBin, simPath, dir, name)
|
||||
sp, err := launchProcess(pythonBin, simPath, dir, name, p.simulatorDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("launch pysimulator: %w", err)
|
||||
}
|
||||
@ -808,7 +815,7 @@ func (p *Plugin) loadPySidecar(s *sdk.PluginSDK, dir, name string) error {
|
||||
}
|
||||
|
||||
func (p *Plugin) loadSidecar(s *sdk.PluginSDK, dir, name string) error {
|
||||
sp, err := launchSidecar(dir, name)
|
||||
sp, err := launchSidecar(dir, name, p.simulatorDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("launch: %w", err)
|
||||
}
|
||||
|
||||
@ -143,15 +143,15 @@ func (s *sidecarProcess) NotifyChan() <-chan OCNotification {
|
||||
return s.notifyCh
|
||||
}
|
||||
|
||||
func launchSidecar(dir, name string) (*sidecarProcess, error) {
|
||||
func launchSidecar(dir, name, simDir string) (*sidecarProcess, error) {
|
||||
mainJS := filepath.Join(dir, "main.js")
|
||||
if _, err := os.Stat(mainJS); os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return launchProcess("node", mainJS, dir, name)
|
||||
return launchProcess("node", mainJS, dir, name, simDir)
|
||||
}
|
||||
|
||||
func launchProcess(bin, arg, dir, name string) (*sidecarProcess, error) {
|
||||
func launchProcess(bin, arg, dir, name, simDir string) (*sidecarProcess, error) {
|
||||
nodePath := bin
|
||||
if bin == "node" {
|
||||
if p := os.Getenv("NODE_PATH"); p != "" {
|
||||
@ -164,8 +164,8 @@ func launchProcess(bin, arg, dir, name string) (*sidecarProcess, error) {
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
// Add openclaw CLI bin dir to PATH so subprocesses can exec 'openclaw' command
|
||||
if SimulatorDir != "" {
|
||||
binDir := filepath.Join(SimulatorDir, "bin")
|
||||
if simDir != "" {
|
||||
binDir := filepath.Join(simDir, "bin")
|
||||
if info, err := os.Stat(binDir); err == nil && info.IsDir() {
|
||||
env := os.Environ()
|
||||
binDirPath := binDir + string(os.PathListSeparator)
|
||||
|
||||
@ -26,10 +26,12 @@ func (m *mockSettings) RegisterDef(def pubsdk.ConfigDef) {}
|
||||
func (m *mockSettings) Defs(prefix string) []*pubsdk.ConfigDef { return nil }
|
||||
func (m *mockSettings) Dump() map[string]interface{} { return nil }
|
||||
func (m *mockSettings) Plugins() []string { return nil }
|
||||
func (m *mockSettings) DefsCore(prefix string) []*sdk.ConfigDef { return nil }
|
||||
func (m *mockSettings) DefsPlugin(plugin, prefix string) []*sdk.ConfigDef { return nil }
|
||||
|
||||
func TestLaunchSidecarNoMainJS(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
sp, err := launchSidecar(tmpDir, "nonexistent")
|
||||
sp, err := launchSidecar(tmpDir, "nonexistent", "")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
@ -50,7 +52,7 @@ func TestLaunchSidecarAndListTools(t *testing.T) {
|
||||
t.Fatalf("write test plugin: %v", err)
|
||||
}
|
||||
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin")
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin", "")
|
||||
if err != nil {
|
||||
t.Fatalf("launch sidecar: %v", err)
|
||||
}
|
||||
@ -92,7 +94,7 @@ func TestCallEchoTool(t *testing.T) {
|
||||
t.Fatalf("write test plugin: %v", err)
|
||||
}
|
||||
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin")
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin", "")
|
||||
if err != nil {
|
||||
t.Fatalf("launch sidecar: %v", err)
|
||||
}
|
||||
@ -124,7 +126,7 @@ func TestCallAddTool(t *testing.T) {
|
||||
t.Fatalf("write test plugin: %v", err)
|
||||
}
|
||||
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin")
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin", "")
|
||||
if err != nil {
|
||||
t.Fatalf("launch sidecar: %v", err)
|
||||
}
|
||||
@ -157,7 +159,7 @@ func TestCallNonexistentTool(t *testing.T) {
|
||||
t.Fatalf("write test plugin: %v", err)
|
||||
}
|
||||
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin")
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin", "")
|
||||
if err != nil {
|
||||
t.Fatalf("launch sidecar: %v", err)
|
||||
}
|
||||
@ -182,7 +184,7 @@ func TestConcurrentCalls(t *testing.T) {
|
||||
t.Fatalf("write test plugin: %v", err)
|
||||
}
|
||||
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin")
|
||||
sp, err := launchSidecar(tmpDir, "echoplugin", "")
|
||||
if err != nil {
|
||||
t.Fatalf("launch sidecar: %v", err)
|
||||
}
|
||||
@ -217,7 +219,7 @@ func launchSimulator(t *testing.T, pluginDir, name string) *sidecarProcess {
|
||||
if err != nil {
|
||||
t.Fatalf("abs simulator path: %v", err)
|
||||
}
|
||||
sp, err := launchProcess("node", simPath, pluginDir, name)
|
||||
sp, err := launchProcess("node", simPath, pluginDir, name, "")
|
||||
if err != nil {
|
||||
t.Fatalf("launch simulator for %s: %v", name, err)
|
||||
}
|
||||
@ -338,8 +340,6 @@ func TestLoadOCPluginViaPluginStart(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
SimulatorDir = filepath.Join(t.TempDir(), ".simulator")
|
||||
|
||||
p := New("openclaw", skillsDir)
|
||||
|
||||
var registeredTools []string
|
||||
|
||||
Reference in New Issue
Block a user