Files
MuyueWorkspace/internal/api/handlers_chat.go
Augustin 04b0fff791
All checks were successful
Beta Release / beta (push) Successful in 44s
refactor(api): split monolithic handlers.go into focused modules
Break down the 627-line handlers.go into specialized modules:
- handlers_chat.go: chat and streaming endpoints
- handlers_config.go: configuration endpoints
- handlers_common.go: shared utilities
- handlers_info.go: info and status endpoints
- handlers_terminal.go: terminal/shell endpoints
- handlers_tools.go: tool-related endpoints

Also includes config improvements, orchestrator enhancements, and
web component updates.

💘 Generated with Crush

Assisted-by: MiniMax-M2.7 via Crush <crush@charm.land>
2026-04-22 18:34:14 +02:00

143 lines
3.8 KiB
Go

package api
import (
"encoding/json"
"net/http"
"github.com/muyue/muyue/internal/orchestrator"
)
func (s *Server) handleChat(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
writeError(w, "POST only", http.StatusMethodNotAllowed)
return
}
var body struct {
Message string `json:"message"`
Stream bool `json:"stream"`
}
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
writeError(w, err.Error(), http.StatusBadRequest)
return
}
if body.Message == "" {
writeError(w, "no message", http.StatusBadRequest)
return
}
s.convStore.Add("user", body.Message)
if s.convStore.NeedsSummarization() {
s.autoSummarize()
}
orb, err := orchestrator.New(s.config)
if err != nil {
writeError(w, err.Error(), http.StatusServiceUnavailable)
return
}
orb.SetSystemPrompt(`Tu es l'orchestrateur IA de Muyue Studio. Tu aides l'utilisateur dans ses tâches de développement logiciel. Tu peux :
|- Créer et gérer des plans de développement étape par étape
|- Proposer des agents (outils comme Crush, Claude Code, etc.) pour exécuter des tâches spécifiques
|- Suivre la progression de tâches multi-étapes
|- Suggérer des modifications de fichiers, des revues de code, et des décisions d'architecture
Sois concis, actionnable, et structuré. Quand tu proposes un plan, utilise des étapes numérotées claires. Quand tu références des fichiers, utilise des chemins relatifs. Tu es intégré dans l'application desktop Muyue.`)
if body.Stream {
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.WriteHeader(http.StatusOK)
flusher, canFlush := w.(http.Flusher)
result, err := orb.SendStream(body.Message, func(chunk string) {
data, _ := json.Marshal(map[string]string{"content": chunk})
w.Write([]byte("data: " + string(data) + "\n\n"))
if canFlush {
flusher.Flush()
}
})
if err != nil {
data, _ := json.Marshal(map[string]string{"error": err.Error()})
w.Write([]byte("data: " + string(data) + "\n\n"))
if canFlush {
flusher.Flush()
}
return
}
s.convStore.Add("assistant", result)
data, _ := json.Marshal(map[string]string{"done": "true"})
w.Write([]byte("data: " + string(data) + "\n\n"))
if canFlush {
flusher.Flush()
}
return
}
result, err := orb.Send(body.Message)
if err != nil {
writeError(w, err.Error(), http.StatusInternalServerError)
return
}
s.convStore.Add("assistant", result)
writeJSON(w, map[string]string{"content": result})
}
func (s *Server) autoSummarize() {
messages := s.convStore.Get()
if len(messages) < 10 {
return
}
half := len(messages) / 2
var oldText string
for _, m := range messages[:half] {
oldText += m.Role + ": " + m.Content + "\n\n"
}
summary := s.convStore.GetSummary()
if summary != "" {
oldText = "Résumé précédent:\n" + summary + "\n\nNouveaux échanges:\n" + oldText
}
orb, err := orchestrator.New(s.config)
if err != nil {
return
}
orb.SetSystemPrompt(summarizePrompt)
result, err := orb.Send(oldText)
if err != nil {
return
}
s.convStore.SetSummary(result)
s.convStore.TrimOld(len(messages) - half)
s.convStore.Add("system", "[Conversation résumée automatiquement]")
}
func (s *Server) handleChatHistory(w http.ResponseWriter, r *http.Request) {
if r.Method != "GET" {
writeError(w, "GET only", http.StatusMethodNotAllowed)
return
}
messages := s.convStore.Get()
writeJSON(w, map[string]interface{}{
"messages": messages,
"tokens": s.convStore.ApproxTokenCount(),
})
}
func (s *Server) handleChatClear(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
writeError(w, "POST only", http.StatusMethodNotAllowed)
return
}
s.convStore.Clear()
writeJSON(w, map[string]string{"status": "ok"})
}