package server // chat_unread_api.go — P3 / Step 2 双轨制未读消息与位点推进 API // // GET /api/v1/chat/unread?session_id=...&user_id=...&since_message_id=... // POST /api/v1/chat/read import ( "encoding/json" "net/http" "strconv" "chat-agent-system/internal/ctxmgr" ) func (s *Server) handleChatUnread(w http.ResponseWriter, r *http.Request) { sessionID := r.URL.Query().Get("session_id") if sessionID == "" { http.Error(w, "missing session_id", http.StatusBadRequest) return } var userID int64 if uStr := r.URL.Query().Get("user_id"); uStr != "" { if uid, err := strconv.ParseInt(uStr, 10, 64); err == nil { userID = uid } } var sinceID int64 if sinceStr := r.URL.Query().Get("since_message_id"); sinceStr != "" { if id, err := strconv.ParseInt(sinceStr, 10, 64); err == nil { sinceID = id } } if s.svc == nil || s.svc.ContextManager() == nil { writeJSONResponse(w, http.StatusOK, ctxmgr.ChatUnreadSummary{ Total: 0, NextMessageID: 0, UnreadMessageIDs: []int64{}, Items: []ctxmgr.UnreadDayItem{}, }) return } summary, err := s.svc.ContextManager().GetChatUnreadSummary(r.Context(), sessionID, userID, sinceID) if err != nil { writeJSONResponse(w, http.StatusOK, ctxmgr.ChatUnreadSummary{ Total: 0, NextMessageID: 0, UnreadMessageIDs: []int64{}, Items: []ctxmgr.UnreadDayItem{}, }) return } writeJSONResponse(w, http.StatusOK, summary) } func (s *Server) handleChatRead(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } var req ctxmgr.MarkChatReadRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "invalid request body: "+err.Error(), http.StatusBadRequest) return } if req.SessionID == "" { http.Error(w, "missing session_id", http.StatusBadRequest) return } if s.svc == nil || s.svc.ContextManager() == nil { http.Error(w, "context manager not initialized", http.StatusInternalServerError) return } pos, err := s.svc.ContextManager().MarkChatRead(r.Context(), req) if err != nil { http.Error(w, "mark chat read failed: "+err.Error(), http.StatusInternalServerError) return } writeJSONResponse(w, http.StatusOK, map[string]any{ "ok": true, "session_id": pos.SessionID, "user_id": pos.UserID, "last_read_message_id": pos.LastReadMessageID, "dismissed_unread_ids": pos.DismissedUnreadIDs, "updated_at": pos.UpdatedAt, }) }