Files
weichenandCursor f6813cc272 feat(api): add additive HTTP/SSE error envelopes
Public errors now emit code, safe message, and request_id while keeping the legacy error field. Raw SQL, paths, tokens, and XSS payloads are stripped; the frontend branches on code instead of substring matching.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-15 14:40:56 +00:00

74 lines
2.0 KiB
Go

package server
// chat_export_api.go — P3 聊天记录导出查询 API
//
// GET /api/v1/chat/export/messages?session_id=...&date_from=...&date_to=...&category=...
//
// 返回按条件过滤后的消息列表,支持客户端导出为 docx/xlsx 等格式。
import (
"net/http"
"strings"
"chat-agent-system/internal/app/chatflow"
"chat-agent-system/internal/ctxmgr"
"chat-agent-system/internal/replyexport"
)
func (s *Server) handleChatExportMessages(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
writeSafeError(w, r, http.StatusMethodNotAllowed, "Method Not Allowed")
return
}
user, ok := s.requireAuthenticatedUser(w, r)
if !ok {
return
}
sessionID := strings.TrimSpace(r.URL.Query().Get("session_id"))
if sessionID == "" {
writeSafeError(w, r, http.StatusBadRequest, "missing required query param 'session_id'")
return
}
if s.chatLog == nil {
writeSafeError(w, r, http.StatusServiceUnavailable, "context manager not initialized")
return
}
msgs, err := s.chatLog.Export(r.Context(), s.chatPrincipal(user, chatflow.ActionExport), chatflow.ExportQuery{
SessionID: sessionID,
DateFrom: strings.TrimSpace(r.URL.Query().Get("date_from")),
DateTo: strings.TrimSpace(r.URL.Query().Get("date_to")),
Category: strings.TrimSpace(r.URL.Query().Get("category")),
})
if err != nil {
s.writeChatLogError(w, err)
return
}
filtered := make([]ctxmgr.ChatMessageRecord, 0, len(msgs))
for _, m := range msgs {
hasCard := false
if m.Metadata != nil {
if _, exists := m.Metadata["interactive_card"]; exists {
hasCard = true
}
}
_, cap := replyexport.EvaluatePolicy(replyexport.PolicyOptions{
Role: m.Role,
Status: "completed",
Content: m.Content,
HasInteractiveCard: hasCard,
Revision: m.ContentRevision,
})
if cap.Policy == replyexport.PolicyNone {
continue
}
filtered = append(filtered, m)
}
writeJSONResponse(w, http.StatusOK, filtered)
}