package main import ( "encoding/json" ) // RPC methods for the optional AI modules (see modules.go). func (r *rpcCtx) modulesRPC() { var p struct { ID string `json:"id"` Engine string `json:"engine"` Action string `json:"action"` Tail int `json:"tail"` Path string `json:"path"` } if len(r.m.Params) > 0 && json.Unmarshal(r.m.Params, &p) != nil { r.fail("invalid parameters") return } switch r.m.Method { case "modules.list": r.ok(moduleManager.Overview(r.cfg)) case "modules.install": if err := moduleManager.Install(r.cfg, p.ID); err != nil { r.fail("%v", err) return } r.ok(map[string]any{"id": p.ID, "started": true}) case "modules.file_delete": if err := moduleManager.DeleteExtra(r.cfg, p.Engine, p.Path); err != nil { r.fail("%v", err) return } r.ok(map[string]any{"engine": p.Engine, "path": p.Path}) case "modules.remove": if err := moduleManager.Remove(r.cfg, p.ID); err != nil { r.fail("%v", err) return } r.ok(map[string]any{"id": p.ID}) case "modules.engine": cat, err := loadCatalog() if err != nil { r.fail("%v", err) return } if _, ok := cat.Engine(p.Engine); !ok { r.fail("unknown engine") return } rn, err := pickModRunner(r.cfg) if err != nil { r.fail("%v", err) return } switch p.Action { case "start": if len(capabilitiesUsing(cat, readModuleState(r.cfg), p.Engine)) == 0 { r.fail("no module that uses this engine is installed") return } err = rn.Start(p.Engine) if err == nil { setPinned(r.cfg, p.Engine, true) // started by hand: it stays until stopped by hand lastEngineErr.Delete(p.Engine) } case "stop": err = rn.Stop(p.Engine) setPinned(r.cfg, p.Engine, false) case "logs": r.ok(rn.Logs(p.Engine, p.Tail)) return default: r.fail("unknown action") return } if err != nil { r.fail("%v", err) return } r.ok(nil) } }