package main import ( "encoding/json" "errors" "io" "net/http" "strconv" "strings" ) const ( sessionSnapshotItems = 24 sessionSnapshotBytes = 8 << 20 ) type sessionSnapshot struct { SessionID string `json:"session_id"` Messages []json.RawMessage `json:"messages"` TotalMessages int `json:"total_messages"` } // boundSessionSnapshot caps only the continuity fallback response. Native // WebUI requests remain untouched, including when an older backend ignores // its optional `limit` query parameter. func boundSessionSnapshot(response *http.Response) error { request := response.Request if request == nil || response.StatusCode != http.StatusOK || request.URL.Query().Get("hermes_fallback") != "1" || !strings.HasPrefix(request.URL.Path, "/api/sessions/") || !strings.HasSuffix(request.URL.Path, "/messages") { return nil } body, err := io.ReadAll(io.LimitReader(response.Body, sessionSnapshotBytes+1)) if err != nil { return err } _ = response.Body.Close() if len(body) > sessionSnapshotBytes { return errors.New("session snapshot exceeds safe response limit") } var payload sessionSnapshot if err := json.Unmarshal(body, &payload); err != nil || payload.Messages == nil { return errors.New("session snapshot is malformed") } total := len(payload.Messages) if payload.TotalMessages > total { total = payload.TotalMessages } if len(payload.Messages) > sessionSnapshotItems { payload.Messages = payload.Messages[len(payload.Messages)-sessionSnapshotItems:] } payload.TotalMessages = total body, err = json.Marshal(payload) if err != nil { return err } response.Body = io.NopCloser(strings.NewReader(string(body))) response.ContentLength = int64(len(body)) response.Header.Set("Content-Length", strconv.Itoa(len(body))) response.Header.Set("Content-Type", "application/json; charset=utf-8") response.Header.Set("Cache-Control", "no-store") response.Header.Del("ETag") return nil }