mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-04 00:03:59 +00:00
feat(cli): /persona 与 /agents 对齐 WebUI(复用已开放的 SDK 面)
- /persona:读写 core.agent.personal_prompt / core.internal.persona_initialized; 插件 SDK 的 Settings() 满足 internal/config.PersonaKV,与 WebUI 同一实现。 GET 等价返回 initialized/current_prompt/file_override;/persona set <mode> [内容] 写。 - /agents:改用 supervisor.ListAgents()(WebUI /agents 同源),此前只回一个 agent_id、驻留子信息全丢。 - waiter 侧 /persona 在 local/remote 两条路都接上,/help 补齐。
This commit is contained in:
@ -47,6 +47,7 @@ Server commands (local 与 remote 行为一致):
|
|||||||
/adapters remove <name> remove a Lua adapter
|
/adapters remove <name> remove a Lua adapter
|
||||||
/network network status + LLM endpoints
|
/network network status + LLM endpoints
|
||||||
/runtime scheduler / residents / channel topology
|
/runtime scheduler / residents / channel topology
|
||||||
|
/persona show persona (/persona set default|custom|later [text])
|
||||||
/agents list agents
|
/agents list agents
|
||||||
/chat <text> send to agent
|
/chat <text> send to agent
|
||||||
|
|
||||||
@ -330,6 +331,28 @@ Any other text is sent to the agent directly.`)
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
case cmd == "/persona" || strings.HasPrefix(cmd, "/persona set "):
|
||||||
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
|
if strings.HasPrefix(cmd, "/persona set ") {
|
||||||
|
rest := strings.TrimSpace(cmd[13:])
|
||||||
|
mode := rest
|
||||||
|
content := ""
|
||||||
|
if idx := strings.IndexByte(rest, ' '); idx > 0 {
|
||||||
|
mode = rest[:idx]
|
||||||
|
content = strings.TrimSpace(rest[idx+1:])
|
||||||
|
}
|
||||||
|
body := fmt.Sprintf(`{"mode":%q,"content":%q}`, mode, content)
|
||||||
|
d, _ := rc.DoAPI("POST", "/api/v1/persona", body)
|
||||||
|
printJSON(out, d)
|
||||||
|
} else {
|
||||||
|
d, _ := rc.DoAPI("GET", "/api/v1/persona", "")
|
||||||
|
printJSON(out, d)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.Send(cmd)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
|
||||||
case cmd == "/runtime":
|
case cmd == "/runtime":
|
||||||
if rc := state.RemoteConn(); rc != nil {
|
if rc := state.RemoteConn(); rc != nil {
|
||||||
d, _ := rc.DoAPI("GET", "/api/v1/runtime", "")
|
d, _ := rc.DoAPI("GET", "/api/v1/runtime", "")
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"gitcode.com/JianFeeeee/HomeAgent/internal/config"
|
||||||
"gitcode.com/JianFeeeee/HomeAgent/internal/plugin"
|
"gitcode.com/JianFeeeee/HomeAgent/internal/plugin"
|
||||||
sdk "gitcode.com/JianFeeeee/HomeAgent/internal/sdk"
|
sdk "gitcode.com/JianFeeeee/HomeAgent/internal/sdk"
|
||||||
)
|
)
|
||||||
@ -317,6 +318,8 @@ func (p *Plugin) handleBuiltin(conn net.Conn, line string, s *sdk.PluginSDK) boo
|
|||||||
p.cmdNetwork(conn, s)
|
p.cmdNetwork(conn, s)
|
||||||
case "/runtime":
|
case "/runtime":
|
||||||
p.cmdRuntime(conn, s)
|
p.cmdRuntime(conn, s)
|
||||||
|
case "/persona":
|
||||||
|
p.cmdPersona(conn, parts, s)
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -354,7 +357,8 @@ func (p *Plugin) cmdHelp(conn net.Conn) {
|
|||||||
/adapters remove <name> 卸载适配器
|
/adapters remove <name> 卸载适配器
|
||||||
/network 网络状态与 LLM 端点
|
/network 网络状态与 LLM 端点
|
||||||
/runtime 调度器/驻留子/通道拓扑快照
|
/runtime 调度器/驻留子/通道拓扑快照
|
||||||
/agents 当前 Agent 信息
|
/persona 当前人格设定(/persona set <mode> [内容] 修改)
|
||||||
|
/agents 列出 Agent
|
||||||
|
|
||||||
其他文本直接发送给 Agent 处理。`,
|
其他文本直接发送给 Agent 处理。`,
|
||||||
})
|
})
|
||||||
@ -826,6 +830,52 @@ func (p *Plugin) cmdAdapters(conn net.Conn, parts []string, s *sdk.PluginSDK) {
|
|||||||
writeJSONContent(conn, map[string]interface{}{"adapters": ad.List()})
|
writeJSONContent(conn, map[string]interface{}{"adapters": ad.List()})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ======== /persona ========
|
||||||
|
|
||||||
|
// cmdPersona 与 WebUI 的 GET/POST /api/v1/persona 同口径。
|
||||||
|
//
|
||||||
|
// 人格的读写落在 core.agent.personal_prompt / core.internal.persona_initialized
|
||||||
|
// 两个配置键上,而插件 SDK 的 Settings() 恰好满足 internal/config.PersonaKV
|
||||||
|
// (GetCore/SetCore)—— WebUI 也是直接把 settings 传进去的,所以内部插件同样能做。
|
||||||
|
func (p *Plugin) cmdPersona(conn net.Conn, parts []string, s *sdk.PluginSDK) {
|
||||||
|
sett := s.Settings()
|
||||||
|
if sett == nil {
|
||||||
|
writeLine(conn, map[string]interface{}{"type": "error", "error": "settings not available"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(parts) >= 2 && parts[1] == "set" {
|
||||||
|
if len(parts) < 3 {
|
||||||
|
writeLine(conn, map[string]interface{}{"type": "response", "content": "用法: /persona set default|custom|later [内容]"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mode := parts[2]
|
||||||
|
content := strings.Join(parts[3:], " ")
|
||||||
|
restart, err := config.SetPersonaKV(sett, mode, content)
|
||||||
|
if err != nil {
|
||||||
|
writeLine(conn, map[string]interface{}{"type": "error", "error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJSONContent(conn, map[string]interface{}{
|
||||||
|
"status": "ok", "mode": mode, "restart_required": restart,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 存在人格文件时它优先(与 WebUI 一致,路径取 core.daemon.data_dir)
|
||||||
|
fileOverride := false
|
||||||
|
if v, err := sett.GetCore("core.daemon.data_dir"); err == nil {
|
||||||
|
if dir, ok := v.(string); ok && dir != "" {
|
||||||
|
if _, statErr := os.Stat(filepath.Join(dir, "personal", "personal.md")); statErr == nil {
|
||||||
|
fileOverride = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeJSONContent(conn, map[string]interface{}{
|
||||||
|
"initialized": config.PersonaInitializedKV(sett),
|
||||||
|
"current_prompt": config.CurrentPersonaKV(sett),
|
||||||
|
"file_override": fileOverride,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// ======== /runtime ========
|
// ======== /runtime ========
|
||||||
|
|
||||||
// cmdRuntime 与 WebUI 的 GET /api/v1/runtime 同口径。
|
// cmdRuntime 与 WebUI 的 GET /api/v1/runtime 同口径。
|
||||||
@ -872,15 +922,24 @@ func (p *Plugin) cmdNetwork(conn net.Conn, s *sdk.PluginSDK) {
|
|||||||
|
|
||||||
// ======== /agents ========
|
// ======== /agents ========
|
||||||
|
|
||||||
|
// cmdAgents 与 WebUI 的 GET /api/v1/agents 同口径:返回受监管的 agent 列表。
|
||||||
|
// 之前只回了内核自己的 agent_id,驻留子信息全丢——而这正是 supervisor 对插件
|
||||||
|
// 已经开放的 ListAgents()。
|
||||||
func (p *Plugin) cmdAgents(conn net.Conn, s *sdk.PluginSDK) {
|
func (p *Plugin) cmdAgents(conn net.Conn, s *sdk.PluginSDK) {
|
||||||
|
if sup := s.Supervisor(); sup != nil {
|
||||||
|
if agents := sup.ListAgents(); len(agents) > 0 {
|
||||||
|
writeJSONContent(conn, map[string]interface{}{"agents": agents})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 退化:supervisor 不可用时至少给出内核 agent_id
|
||||||
st := s.Status()
|
st := s.Status()
|
||||||
if st == nil {
|
if st == nil {
|
||||||
writeLine(conn, map[string]interface{}{"type": "error", "error": "status provider not available"})
|
writeLine(conn, map[string]interface{}{"type": "error", "error": "status provider not available"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ks := st.GetKernelStatus()
|
ks := st.GetKernelStatus()
|
||||||
data, _ := json.MarshalIndent(map[string]string{"agent_id": ks.AgentID}, "", " ")
|
writeJSONContent(conn, map[string]interface{}{"agents": []interface{}{map[string]string{"id": ks.AgentID, "state": "running"}}})
|
||||||
writeLine(conn, map[string]interface{}{"type": "response", "content": string(data)})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======== helpers ========
|
// ======== helpers ========
|
||||||
|
|||||||
Reference in New Issue
Block a user