mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-04 00:03:59 +00:00
feat: waiter CLI remote mode calls REST API directly for management commands
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@ -28,6 +29,7 @@ Server commands (sent to agent):
|
|||||||
/plugin info <name> plugin details
|
/plugin info <name> plugin details
|
||||||
/memory query <text> query graph memory
|
/memory query <text> query graph memory
|
||||||
/knowledge list knowledge base
|
/knowledge list knowledge base
|
||||||
|
/knowledge delete <name> delete knowledge item
|
||||||
/agents list agents
|
/agents list agents
|
||||||
/chat <text> send to agent
|
/chat <text> send to agent
|
||||||
|
|
||||||
@ -64,7 +66,136 @@ Any other text is sent to the agent directly.`)
|
|||||||
reconnect()
|
reconnect()
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
case cmd == "/status":
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("GET", "/api/v1/status", "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send("/status")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case cmd == "/kernel":
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("GET", "/api/v1/kernel", "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send("/kernel")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case strings.HasPrefix(cmd, "/settings set "):
|
||||||
|
parts := strings.SplitN(cmd[14:], " ", 2)
|
||||||
|
if len(parts) < 2 {
|
||||||
|
fmt.Println("usage: /settings set <key> <value>")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
body := fmt.Sprintf(`{"%s":%q}`, parts[0], parts[1])
|
||||||
|
rc.DoAPI("PUT", "/api/v1/settings", body)
|
||||||
|
fmt.Println("ok")
|
||||||
|
} else {
|
||||||
|
state.Send(cmd[1:])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case strings.HasPrefix(cmd, "/settings"):
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("GET", "/api/v1/settings", "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send(cmd[1:])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case cmd == "/plugin list":
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("GET", "/api/v1/plugins", "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send("/plugin list")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case strings.HasPrefix(cmd, "/plugin install "):
|
||||||
|
url := strings.TrimSpace(cmd[16:])
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
body := fmt.Sprintf(`{"url":%q}`, url)
|
||||||
|
d, _ := rc.DoAPI("POST", "/api/v1/plugins", body)
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send(cmd[1:])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case strings.HasPrefix(cmd, "/plugin remove "):
|
||||||
|
name := strings.TrimSpace(cmd[15:])
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("DELETE", "/api/v1/plugins/"+name, "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send(cmd[1:])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case strings.HasPrefix(cmd, "/plugin info "):
|
||||||
|
name := strings.TrimSpace(cmd[13:])
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("GET", "/api/v1/plugins/"+name, "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send(cmd[1:])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case strings.HasPrefix(cmd, "/memory query "):
|
||||||
|
q := strings.TrimSpace(cmd[14:])
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("GET", "/api/v1/memory?query="+q, "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send(cmd[1:])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case strings.HasPrefix(cmd, "/knowledge delete "):
|
||||||
|
name := strings.TrimSpace(cmd[18:])
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("DELETE", "/api/v1/knowledge/"+name, "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send(cmd[1:])
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case cmd == "/knowledge":
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("GET", "/api/v1/knowledge", "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send("/knowledge")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
|
case cmd == "/agents":
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
d, _ := rc.DoAPI("GET", "/api/v1/agents", "")
|
||||||
|
printJSON(d)
|
||||||
|
} else {
|
||||||
|
state.Send("/agents")
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printJSON(d map[string]interface{}) {
|
||||||
|
if d == nil {
|
||||||
|
fmt.Println("(no data)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b, _ := json.MarshalIndent(d, "", " ")
|
||||||
|
fmt.Println(string(b))
|
||||||
|
}
|
||||||
|
|||||||
@ -76,11 +76,11 @@ func (c *localConn) Close() error {
|
|||||||
|
|
||||||
func dialRemote(baseURL, apiKey string) (Conn, error) {
|
func dialRemote(baseURL, apiKey string) (Conn, error) {
|
||||||
baseURL = strings.TrimRight(baseURL, "/")
|
baseURL = strings.TrimRight(baseURL, "/")
|
||||||
return &remoteConn{url: baseURL + "/api/v1/chat", apiKey: apiKey}, nil
|
return &remoteConn{baseURL: baseURL, apiKey: apiKey}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type remoteConn struct {
|
type remoteConn struct {
|
||||||
url string
|
baseURL string
|
||||||
apiKey string
|
apiKey string
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
buf []string
|
buf []string
|
||||||
@ -88,7 +88,7 @@ type remoteConn struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *remoteConn) Send(line string) error {
|
func (c *remoteConn) Send(line string) error {
|
||||||
req, err := http.NewRequest("POST", c.url, strings.NewReader(
|
req, err := http.NewRequest("POST", c.baseURL+"/api/v1/chat", strings.NewReader(
|
||||||
fmt.Sprintf(`{"message":%q}`, line),
|
fmt.Sprintf(`{"message":%q}`, line),
|
||||||
))
|
))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -117,6 +117,31 @@ func (c *remoteConn) Send(line string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *remoteConn) DoAPI(method, path string, body string) (map[string]interface{}, error) {
|
||||||
|
var bodyReader io.Reader
|
||||||
|
if body != "" {
|
||||||
|
bodyReader = strings.NewReader(body)
|
||||||
|
}
|
||||||
|
req, err := http.NewRequest(method, c.baseURL+path, bodyReader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
if c.apiKey != "" {
|
||||||
|
req.Header.Set("X-API-Key", c.apiKey)
|
||||||
|
}
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
var result map[string]interface{}
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (c *remoteConn) ReadLine() (string, error) {
|
func (c *remoteConn) ReadLine() (string, error) {
|
||||||
c.mu.Lock()
|
c.mu.Lock()
|
||||||
defer c.mu.Unlock()
|
defer c.mu.Unlock()
|
||||||
|
|||||||
@ -41,6 +41,15 @@ func (s *State) Connected() bool {
|
|||||||
return s.conn != nil
|
return s.conn != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *State) RemoteConn() *remoteConn {
|
||||||
|
s.mu.Lock()
|
||||||
|
defer s.mu.Unlock()
|
||||||
|
if rc, ok := s.conn.(*remoteConn); ok {
|
||||||
|
return rc
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *State) Send(line string) error {
|
func (s *State) Send(line string) error {
|
||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
c := s.conn
|
c := s.conn
|
||||||
|
|||||||
Reference in New Issue
Block a user