Files
Cyrene_v2/internal/runtime/history/list_after.go
T
AskaEth f43751fd07
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(history): 消息正向增量拉取(A5) — GET /sessions/{id}/messages?after=
- history/list_after.go: ListAfter(升序, created_at>after, 走覆盖索引, rowid兜底同毫秒)
- HistoryStore 新增 ListAfter(store+fakes同步)
- gateway history.go: handleListMessages解析after分流; after+before互斥400; 负数/非数字400
- 新增测试(list_after/history_after), build/vet/test绿+交叉编译
- Docs/api-client v0.26 + api-reference §3.4 同步
2026-09-08 21:49:12 +08:00

48 lines
1.8 KiB
Go

package history
import (
"context"
"fmt"
)
// ListAfter returns up to limit messages for sessionID strictly newer than after
// (created_at > after) in oldest-first order, for forward incremental catch-up: a
// client that reconnected passes the newest createdAt it has already seen and pulls
// only what it missed, however many messages that is (the "before" cursor only walks
// backwards and cannot recover a gap larger than one page). When platform is non-empty
// the page is further restricted to messages carrying that source platform, exactly as
// in List. rowid breaks created_at ties so messages written in the same millisecond
// keep their insertion order. The returned slice is non-nil; limit is clamped to
// [1, maxPageLimit].
func (s *Store) ListAfter(ctx context.Context, sessionID string, after int64, limit int, platform string) ([]Message, error) {
limit = clampLimit(limit)
query := `SELECT id, session_id, role, content, mode, mood, image, thinking, platform, device_id, sender_name, adapter_id, created_at
FROM chat_messages WHERE session_id = ? AND created_at > ?`
args := []any{sessionID, after}
if platform != "" {
query += ` AND platform = ?`
args = append(args, platform)
}
query += ` ORDER BY created_at ASC, rowid ASC LIMIT ?`
args = append(args, limit)
rows, err := s.db.QueryContext(ctx, query, args...)
if err != nil {
return nil, fmt.Errorf("history: list after %s: %w", sessionID, err)
}
defer func() { _ = rows.Close() }()
msgs := make([]Message, 0)
for rows.Next() {
m, err := scanMessage(rows)
if err != nil {
return nil, fmt.Errorf("history: scan list after %s: %w", sessionID, err)
}
msgs = append(msgs, m)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("history: iterate list after %s: %w", sessionID, err)
}
return msgs, nil
}