package api import ( "encoding/json" "net/http" "strings" "github.com/muyue/muyue/internal/skills" ) func (s *Server) handleSkillAutoCreate(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { writeError(w, "POST only", http.StatusMethodNotAllowed) return } var body struct { Snippets []struct { Role string `json:"role"` Content string `json:"content"` } `json:"snippets"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeError(w, "invalid request body", http.StatusBadRequest) return } var snippets []skills.ConversationSnippet for _, s := range body.Snippets { snippets = append(snippets, skills.ConversationSnippet{ Role: s.Role, Content: s.Content, }) } proposals := skills.AnalyzeConversation(snippets) var results []map[string]interface{} for i := range proposals { p := &proposals[i] if err := skills.SaveProposal(p); err != nil { continue } results = append(results, map[string]interface{}{ "name": p.Name, "description": p.Description, "confidence": p.Confidence, "category": p.Category, "tags": p.SuggestedTags, }) } writeJSON(w, map[string]interface{}{ "proposals": results, "count": len(results), }) } func (s *Server) handleSkillDetail(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/api/skills/detail/") if strings.HasSuffix(path, "/improve") { name := strings.TrimSuffix(path, "/improve") s.handleSkillImprove(w, r, name) return } if strings.HasSuffix(path, "/history") { name := strings.TrimSuffix(path, "/history") s.handleSkillHistoryGet(w, r, name) return } writeError(w, "unknown skill action", http.StatusNotFound) } func (s *Server) handleSkillImprove(w http.ResponseWriter, r *http.Request, name string) { if r.Method != "POST" { writeError(w, "POST only", http.StatusMethodNotAllowed) return } skill, err := skills.Get(name) if err != nil { writeError(w, err.Error(), http.StatusNotFound) return } var body struct { Context string `json:"context,omitempty"` Apply bool `json:"apply,omitempty"` } if r.Body != nil { json.NewDecoder(r.Body).Decode(&body) } improver, err := skills.NewSkillImprover() if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } suggestions, err := improver.Analyze(skill, body.Context) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } if body.Apply && len(suggestions) > 0 { if err := improver.ApplyImprovement(name, suggestions[0]); err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } updated, _ := skills.Get(name) writeJSON(w, map[string]interface{}{ "applied": true, "suggestion": suggestions[0], "updated": updated, }) return } writeJSON(w, map[string]interface{}{ "skill": skill.Name, "suggestions": suggestions, "count": len(suggestions), }) } func (s *Server) handleSkillHistoryGet(w http.ResponseWriter, r *http.Request, name string) { if r.Method != "GET" { writeError(w, "GET only", http.StatusMethodNotAllowed) return } improver, err := skills.NewSkillImprover() if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } history, err := improver.GetHistory(name) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, map[string]interface{}{ "skill": name, "history": history, "count": len(history), }) } func (s *Server) handleSkillProposals(w http.ResponseWriter, r *http.Request) { switch r.Method { case "GET": proposals, err := skills.LoadProposals() if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, map[string]interface{}{ "proposals": proposals, "count": len(proposals), }) case "POST": var body struct { Name string `json:"name"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeError(w, "invalid request body", http.StatusBadRequest) return } proposals, err := skills.LoadProposals() if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } var target *skills.AutoCreateProposal for i := range proposals { if proposals[i].Name == body.Name { target = &proposals[i] break } } if target == nil { writeError(w, "proposal not found", http.StatusNotFound) return } skill, err := skills.CreateFromProposal(target) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } skills.DeleteProposal(body.Name) writeJSON(w, map[string]interface{}{ "created": true, "skill": skill, }) default: writeError(w, "GET or POST only", http.StatusMethodNotAllowed) } }