feat: update chat, settings, prompts and system info modules
This commit is contained in:
@@ -38,6 +38,12 @@ func handleChat(piClient *rpc.Client) gin.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// Intercept slash commands before forwarding to agent.
|
||||
if dispatch := services.TrySlashDispatch(req.Message); dispatch.Handled {
|
||||
dispatchSlashCommand(c, dispatch, piClient)
|
||||
return
|
||||
}
|
||||
|
||||
// normalize streamingBehavior: only "steer" / "followUp" are forwarded
|
||||
if req.StreamingBehavior != "steer" && req.StreamingBehavior != "followUp" {
|
||||
req.StreamingBehavior = ""
|
||||
@@ -52,6 +58,95 @@ func handleChat(piClient *rpc.Client) gin.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// dispatchSlashCommand handles slash commands intercepted from /api/chat.
|
||||
func dispatchSlashCommand(c *gin.Context, d services.SlashDispatchResult, piClient *rpc.Client) {
|
||||
// Unsupported command (not in the whitelist)
|
||||
if d.Message != "" {
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true, "slash": true, "message": d.Message})
|
||||
return
|
||||
}
|
||||
|
||||
switch d.Command {
|
||||
case "new":
|
||||
slashNew(c, piClient)
|
||||
case "reload":
|
||||
slashReload(c, piClient)
|
||||
case "copy":
|
||||
slashCopy(c, piClient)
|
||||
default:
|
||||
// Forward to agent as a prompt; SSE events carry the result back.
|
||||
msg := "/" + d.Command
|
||||
if d.Args != "" {
|
||||
msg += " " + d.Args
|
||||
}
|
||||
if err := piClient.SubmitPrompt(models.ChatRequest{Message: msg}); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, models.ErrorResponse{Error: err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusAccepted, gin.H{"ok": true, "slash": true, "accepted": true})
|
||||
}
|
||||
}
|
||||
|
||||
func slashNew(c *gin.Context, piClient *rpc.Client) {
|
||||
resp, err := piClient.SendCmd(models.RPCCommand{Type: "new_session"})
|
||||
if err != nil || !resp.Success {
|
||||
msg := "新建会话失败"
|
||||
if err != nil {
|
||||
msg = err.Error()
|
||||
} else if resp.Error != "" {
|
||||
msg = resp.Error
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, models.ErrorResponse{Error: msg})
|
||||
return
|
||||
}
|
||||
out := gin.H{"ok": true, "slash": true, "action": "new_session"}
|
||||
if state, serr := piClient.SendCmd(models.RPCCommand{Type: "get_state"}); serr == nil && state.Success {
|
||||
var sd struct {
|
||||
SessionFile string `json:"sessionFile"`
|
||||
}
|
||||
if json.Unmarshal(state.Data, &sd) == nil && sd.SessionFile != "" {
|
||||
out["sessionFile"] = sd.SessionFile
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, out)
|
||||
}
|
||||
|
||||
func slashReload(c *gin.Context, piClient *rpc.Client) {
|
||||
reloadAgent(piClient)
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true, "slash": true, "action": "reload_sessions", "message": "已重新加载"})
|
||||
}
|
||||
|
||||
func slashCopy(c *gin.Context, piClient *rpc.Client) {
|
||||
resp, err := piClient.SendCmd(models.RPCCommand{Type: "get_messages"})
|
||||
if err != nil || !resp.Success {
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true, "slash": true, "message": "获取消息失败"})
|
||||
return
|
||||
}
|
||||
var msgs []struct {
|
||||
Role string `json:"role"`
|
||||
Content any `json:"content"`
|
||||
}
|
||||
if json.Unmarshal(resp.Data, &msgs) != nil {
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true, "slash": true, "message": "没有可复制的消息"})
|
||||
return
|
||||
}
|
||||
for i := len(msgs) - 1; i >= 0; i-- {
|
||||
if msgs[i].Role == "assistant" {
|
||||
text := ""
|
||||
switch v := msgs[i].Content.(type) {
|
||||
case string:
|
||||
text = v
|
||||
default:
|
||||
b, _ := json.Marshal(v)
|
||||
text = string(b)
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true, "slash": true, "action": "copy", "message": text})
|
||||
return
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"ok": true, "slash": true, "message": "没有助手消息可复制"})
|
||||
}
|
||||
|
||||
func handleSteer(piClient *rpc.Client) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var req models.ChatRequest
|
||||
|
||||
Reference in New Issue
Block a user