feat(activity): 任务会话历史反向分页 + SSE 可靠性整改
后端:
- ActivityPage(会话过滤 main/plan/intent + before 反向分页)、ActivityMaxID
(任务级快照游标)、ListByKindPage(Intent 列表分页,突破固定 300 上限)
- 新增 GET /api/exploration/activity/history(items/snapshot_cursor/
earliest_cursor/has_more);snapshot_cursor 为任务级游标
- streamActivity:一次 2000 → 循环补偿追平;输出标准 SSE id 行;支持
Last-Event-ID;补偿查询错误记录日志并关闭连接
- intents 支持分页形态(?before/?page → {items,has_more}),无参数保持旧裸数组
- 新增 idx_act_worker(exploration_id, worker, id) 支撑 Main/Plan 反向翻页
(schema.sql 幂等,旧库启动自动补建,无迁移)
前端:
- sessions-tab 单一 allActivity → 分会话缓存;首屏只加载 Main 最新页并据其
快照游标建唯一任务级 SSE;Plan/Worker 点击懒加载
- 统一 mergeBySeq 合并去重;未激活会话只维护 lastTs/unread;向上滚动分页
加载旧历史并保持滚动位置;每会话内存上限裁剪
- 按 session_key 写各自缓存 + 每 key 请求令牌防会话切换串数据;SSE 连接状态
可见、加载失败可重试,异常不再静默为"暂无消息"
- api 新增 activityHistory / intentsPage
测试:db/activity_page_test.go 覆盖多 Agent 过滤、反向翻页无重复无遗漏、
快照游标、Intent 超页分页(已对真实 PostgreSQL 通过)
This commit is contained in:
1 parent
95aba396c2
commit
79493d5a4a
6 files changed
+906
-130
No files matched your search
@@ -247,6 +247,36 @@ export const api = {
|
||||
return get<{ items: Activity[]; cursor: number }>(`/exploration/activity?${q.toString()}`).then((r) => ({ items: arr(r.items), cursor: r.cursor ?? 0 }));
|
||||
},
|
||||
activityDetail: (id: number, task?: string) => get<{ detail: string }>(`/exploration/activity/${id}${tq(task)}`),
|
||||
// Reverse-paginated session history. session = "main" | "plan" | "intent:<id>".
|
||||
// before=0 → latest page; before=<id> → the older page ending before that id.
|
||||
// snapshotCursor is the TASK-level max id at query time — open the task SSE at
|
||||
// since=snapshotCursor so history (id≤cursor) and the live tail (id>cursor) meet
|
||||
// gap-free. hasMore = still-older steps exist (drives scroll-up loading).
|
||||
activityHistory: (task: string, session: string, before = 0, limit = 200) => {
|
||||
const q = new URLSearchParams({ session, limit: String(limit) });
|
||||
if (task) q.set("task", task);
|
||||
if (before > 0) q.set("before", String(before));
|
||||
return get<{ items: Activity[]; snapshot_cursor: number; earliest_cursor: number; has_more: boolean }>(
|
||||
`/exploration/activity/history?${q.toString()}`,
|
||||
).then((r) => ({
|
||||
items: arr(r.items),
|
||||
snapshotCursor: r.snapshot_cursor ?? 0,
|
||||
earliestCursor: r.earliest_cursor ?? 0,
|
||||
hasMore: !!r.has_more,
|
||||
}));
|
||||
},
|
||||
// Paged worker (intent) session list — reaches past the legacy fixed 300 cap.
|
||||
// before=0 → newest page; before=<id> → older page. has_more = older intents exist.
|
||||
intentsPage: (task: string, before = 0, limit = 300) => {
|
||||
const q = new URLSearchParams({ limit: String(limit) });
|
||||
if (task) q.set("task", task);
|
||||
q.set("before", String(before > 0 ? before : 0));
|
||||
q.set("page", "1"); // marker so the backend returns the paged {items,has_more} shape
|
||||
return get<{ items: TaskNode[]; has_more: boolean }>(`/exploration/intents?${q.toString()}`).then((r) => ({
|
||||
items: arr(r.items),
|
||||
hasMore: !!r.has_more,
|
||||
}));
|
||||
},
|
||||
|
||||
// ---- traffic / audit / report / chat ----
|
||||
audit: (task?: string) => get<Audit>(`/audit${tq(task)}`),
|
||||
|
||||
Reference in new issue
Block a user