package api import ( "encoding/json" "net/http" "strconv" "strings" "time" "github.com/muyue/muyue/internal/memory" ) func (s *Server) ensureMemoryStore() (*memory.Store, error) { if s.memoryStore == nil { store, err := memory.NewStore() if err != nil { return nil, err } s.memoryStore = store } return s.memoryStore, nil } func (s *Server) handleMemoryList(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { writeError(w, "GET only", http.StatusMethodNotAllowed) return } store, err := s.ensureMemoryStore() if err != nil { writeError(w, "memory store: "+err.Error(), http.StatusInternalServerError) return } var memType memory.MemoryType if t := r.URL.Query().Get("type"); t != "" { memType = memory.MemoryType(t) } limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) offset, _ := strconv.Atoi(r.URL.Query().Get("offset")) memories, err := store.List(memType, limit, offset) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } count, _ := store.Count() writeJSON(w, map[string]interface{}{ "memories": memories, "count": len(memories), "total": count, }) } func (s *Server) handleMemoryCreate(w http.ResponseWriter, r *http.Request) { if r.Method != "POST" { writeError(w, "POST only", http.StatusMethodNotAllowed) return } var body struct { Type string `json:"type"` Key string `json:"key"` Content string `json:"content"` Tags string `json:"tags,omitempty"` Source string `json:"source,omitempty"` Confidence float64 `json:"confidence,omitempty"` } if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeError(w, "invalid request body", http.StatusBadRequest) return } if body.Key == "" || body.Content == "" { writeError(w, "key and content are required", http.StatusBadRequest) return } store, err := s.ensureMemoryStore() if err != nil { writeError(w, "memory store: "+err.Error(), http.StatusInternalServerError) return } memType := memory.MemoryType(body.Type) if memType == "" { memType = memory.TypeFact } m := &memory.Memory{ Type: memType, Key: body.Key, Content: body.Content, Tags: body.Tags, Source: body.Source, Confidence: body.Confidence, } if m.Confidence == 0 { m.Confidence = 0.5 } if err := store.Store(m); err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, map[string]interface{}{ "created": true, "memory": m, }) } func (s *Server) handleMemoryDelete(w http.ResponseWriter, r *http.Request) { if r.Method != "DELETE" { writeError(w, "DELETE only", http.StatusMethodNotAllowed) return } id := strings.TrimPrefix(r.URL.Path, "/api/memory/") if id == "" { writeError(w, "memory id required", http.StatusBadRequest) return } store, err := s.ensureMemoryStore() if err != nil { writeError(w, "memory store: "+err.Error(), http.StatusInternalServerError) return } if err := store.Delete(id); err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, map[string]interface{}{ "deleted": true, "id": id, }) } func (s *Server) handleMemoryOperation(w http.ResponseWriter, r *http.Request) { path := strings.TrimPrefix(r.URL.Path, "/api/memory/") if path == "" { s.handleMemoryList(w, r) return } switch r.Method { case "DELETE": s.handleMemoryDelete(w, r) case "GET": store, err := s.ensureMemoryStore() if err != nil { writeError(w, "memory store: "+err.Error(), http.StatusInternalServerError) return } m, err := store.Get(path) if err != nil { writeError(w, err.Error(), http.StatusNotFound) return } writeJSON(w, m) default: writeError(w, "method not allowed", http.StatusMethodNotAllowed) } } func (s *Server) handleMemorySearch(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { writeError(w, "GET only", http.StatusMethodNotAllowed) return } query := r.URL.Query().Get("q") if query == "" { writeError(w, "query parameter 'q' is required", http.StatusBadRequest) return } store, err := s.ensureMemoryStore() if err != nil { writeError(w, "memory store: "+err.Error(), http.StatusInternalServerError) return } limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) results, err := store.Search(query, limit) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, map[string]interface{}{ "results": results, "count": len(results), "query": query, }) } func (s *Server) handleMemoryRecall(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { writeError(w, "GET only", http.StatusMethodNotAllowed) return } query := r.URL.Query().Get("q") store, err := s.ensureMemoryStore() if err != nil { writeError(w, "memory store: "+err.Error(), http.StatusInternalServerError) return } injector := memory.NewInjector(store) contextBlock, err := injector.BuildContextBlock(query) if err != nil { writeError(w, err.Error(), http.StatusInternalServerError) return } writeJSON(w, map[string]interface{}{ "context": contextBlock, "query": query, }) } func (s *Server) handleMemoryContext(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" { writeError(w, "GET only", http.StatusMethodNotAllowed) return } store, err := s.ensureMemoryStore() if err != nil { writeError(w, "memory store: "+err.Error(), http.StatusInternalServerError) return } preferences, _ := store.RecallPreferences() facts, _ := store.RecallFacts() recentCutoff := time.Now().Add(-24 * time.Hour) recent, _ := store.RecallRecent(recentCutoff, 10) writeJSON(w, map[string]interface{}{ "preferences": preferences, "facts": facts, "recent": recent, }) }