Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0155nFCgCHtoA7jhSDGmZmMu
70 lines
7.5 KiB
Markdown
70 lines
7.5 KiB
Markdown
# PROGRESS · 历史对话标题、排序、分组与分页(2026-09-06)
|
||
|
||
工作树:`.worktrees/session-list-title-and-order-20260906`
|
||
分支:`codex/session-list-title-and-order-20260906`
|
||
基线:任务书写 `origin/staging` @ `985c3258`;开工时 `origin/staging` 已到 `d04990fc`(含 composer BUG-551/552),以当时远端为准。
|
||
|
||
`page.tsx` 收尾 **2035** 行(上限 2041)。未改迁移、未 bump Skill。5.1 起名走 `generateText` 可 mock;真实模型调用在本机测试里不打外部 API。客户端只引用 `session-title.ts` 纯函数,避免把 Mastra 打进 `/` 包。
|
||
|
||
| 任务 | 状态 | BUG |
|
||
| --- | --- | --- |
|
||
| 5.2 排序与 `updated_at` | 完成 | BUG-553 |
|
||
| 5.6 列表游标分页 | 完成 | — |
|
||
| 5.4 侧栏去资料前缀 | 完成 | — |
|
||
| 5.3 历史日期分组 | 完成 | — |
|
||
| 5.1 首轮模型起名 | 完成 | 不编 BUG |
|
||
| 5.5 BUG_HISTORY / CHANGELOG / DESIGN / VOICE | 完成 | — |
|
||
|
||
## 实现要点
|
||
|
||
- `sortSessions`:置顶优先,其次 `updatedAt` 倒序,相等保持原序。
|
||
- 元数据 PATCH 不再写 `updated_at`;客户端改名 / 收藏 / 归档 / 换模型不再 bump。
|
||
- `GET /api/sessions`:`limit` 默认 40(1–100),`before` 游标 `(updated_at,id)` 倒序,第一页合并全部置顶,后续页只有非置顶;`archived=1` 独立游标。
|
||
- 历史按本地午夜分成今天 / 昨天 / 最近 7 天 / 最近 30 天 / 更早;空组不渲染。滚到底哨兵静默续取,无「加载更多 / 没有更多」。
|
||
- 侧栏标题只显示会话标题;`chartProfileRole !== "self"` 时副标题显示资料名(含「资料已删除 · 」)。
|
||
- 咨询首轮且标题仍是自动值时,与主回答并行起名(8 秒 ref'd 超时,最多 30 token,不扣点)。合格标题经 `session.title` 事件下发,并按「标题仍等于本轮开始值」守卫写库。流结束前会等该事件,避免客户端完成 PATCH 把模型标题盖回去。
|
||
|
||
## 既有断言改动
|
||
|
||
| 文件 | 原值 | 新值 | 原因 |
|
||
| --- | --- | --- | --- |
|
||
| `home-profile.ts` / `chart-library-session` | `资料名 · 标题` | 标题单独一行;他人资料走副标题 | 侧栏前缀把主题挤没 |
|
||
| `page.tsx` `visibleSessions` | 只按 `pinned` 排 | `sortSessions`(置顶 + `updatedAt` 倒序) | BUG-553:刚聊过的不在最上面 |
|
||
| `metadataUpdateValues` | 每次 PATCH 写 `updated_at` | 返回值不含 `updated_at` | 改名收藏把旧会话顶上去 |
|
||
| `renameSession` | `{ ...session, title, updatedAt: timestamp() }` | `{ ...session, title }` | 同上 |
|
||
| `GET /api/sessions` | 一次返回全部元数据数组 | `{ sessions, nextCursor }`,默认 40 | 上千行 DOM;后续页静默续取 |
|
||
| `fetchSessions` / hydrate | `readSessions(payload)` | `readSessions(page.sessions)` + `nextCursor` | 分页响应形状 |
|
||
| `onToggleArchivedView` | 只翻转本地 `showArchivedSessions` | 重新取第一页(`archived=1`) | 归档改由服务端过滤 |
|
||
| `app-sidebar` 历史区 | `historySessions.map` 一根长列表 | `historyGroups.map` + 哨兵 | 今天 / 昨天 / 更早;无加载文案 |
|
||
| `use-consultation-run` 完成标题 | `reply.title && !isGenericSessionTitle(reply.title)` | `streamedTitle ?? reply.title` | 首轮模型标题经 `session.title` 事件到达 |
|
||
| `consult` session select | `...,session_type,messages` | 另加 `title,theme,chart_profile_role` | 起名判定需要当前标题与分析对象 |
|
||
| `agent.generate` token 上限 | 任务书写 `maxTokens` | `modelSettings.maxOutputTokens` | 当前 Mastra/AI SDK CallSettings 字段名 |
|
||
|
||
## 测试
|
||
|
||
| 命令 | 结果 |
|
||
| --- | --- |
|
||
| `npx tsx --test tests/sidebar-*.test.ts tests/chart-library-session.test.ts tests/chat-session-*.test.ts tests/agent-reply.test.ts tests/consultation-*.test.ts tests/session-*.test.ts tests/application-billing-contract.test.ts` | 355 pass / 0 fail |
|
||
| `./node_modules/.bin/tsc --noEmit` | 0 错 |
|
||
| 改动文件 eslint `--quiet` | 0 error |
|
||
| `page.tsx` | 2035 行(上限 2041) |
|
||
| `npm run build -- --webpack` | webpack 编译通过;类型检查仍停在既有 `dossierResponse` 路由导出(`api/rectification/cases/[caseId]`),与本单无关。本单曾误把 `metadataUpdateValues` 从 sessions `[id]` 路由再导出,已撤回。 |
|
||
| 全量 `npm test`(含 `database-*`) | 本机 Docker 库测多项 300s 超时 / 权限负例 ERROR,与本单无关;未当作本单回归。 |
|
||
|
||
## 验收(Claude,2026-09-06,对照 `TASK-session-list-title-and-order-20260906.md`)
|
||
|
||
共用门禁(`origin/staging` @ `e2f4b55c`,含五单全部提交):`tsc --noEmit` 0 错;`npm run lint` 0 error / 79 warning(全部既有);`npx tsx --test tests/*.test.ts` 2770 项 / pass 2729 / fail 29 / skipped 12——29 条失败全为环境缺口(25 条 Docker / rsync / pyyaml 缺失的库测与部署套件;2 条 `--experimental-test-module-mocks` 子进程在本机 Node 20 下解析不到 `@/` 别名,CI 为 Node 22;2 条 `beam-avatar` / `chat-composer-queue` 渲染用例因验收工作树里一个多余的 `node_modules/node_modules` 软链造成双份 React,删链后单独重跑通过);默认 `npm run build`(Turbopack)退出 0、`/` 为 `○ Static`、产物无 `/membership` 页;首屏 JS gzip-9(预渲染 `index.html` 引用脚本去重求和,与 09-02 口径一致)`d2a209d3` 519,437 B → `e2f4b55c` 522,617 B,**+3,180 B / +0.61%**,五单合计在 ±2% 内。执行方进度里「`next build --webpack` 停在 `dossierResponse` 导出类型」一事:`dc6598d7` 已去掉该 `export`,本次默认构建不再出现。
|
||
|
||
| 项 | 结论 | 依据 |
|
||
| --- | --- | --- |
|
||
| 5.1 起名 Agent:ref 计时器 8 s、30 token、清洗 6–14 汉字 / 拒换行 / 拒生日形态 | 通过 | `lib/session-title-agent.ts`、`lib/session-title.ts::sanitizeSessionTitle` |
|
||
| 5.1 只在首轮、非校正、非日期式标题时起名;与主回答并行、`session.title` 流事件 | 通过 | `shouldGenerateSessionTitle`;`use-consultation-run.ts` `streamedTitle ?? reply.title` |
|
||
| 5.1 **服务端守卫写库** | **未通过(P1)** | `api/consult/route.ts` L693 的 `expectedTitle` 取自 RPC 之前的 select;L531 `append_consultation_question` 已把空 / 「新对话」标题改写成 `left(question,14)‖'…'`(迁移 `20260901010000` L84–90);L710 `.eq("title", expectedTitle)` 因此对新会话恒匹配 0 行且无报错——服务端从不落库模型标题,只靠客户端结算时 PATCH。用户中途刷新 / 换设备时 `status` 路由回读的是问题截断标题。无测试覆盖此守卫。修复单 `TASK-session-title-guard-fix-20260906.md`(BUG-557) |
|
||
| 5.2 侧栏去「资料名 · 」前缀、他人资料小字副标题 | 通过 | `home-profile.ts::sessionSidebarTitle` / `sessionSidebarSubtitle` |
|
||
| 5.3 排序:置顶 + `updatedAt` 倒序;元数据 PATCH 不再推进 `updated_at`;客户端改名不再 `timestamp()` | 通过 | `session-metadata-update.ts` 只展开 patch 字段;`use-session-management.ts` 无 `updatedAt: timestamp()` |
|
||
| 5.4 今天 / 昨天 / 7 天 / 30 天 / 更早分组,收藏不分组 | 通过 | `lib/session-groups.ts::groupSessionsByRecency` |
|
||
| 5.5 游标分页 40 条、置顶首页全量、`archived=1`、滚到底静默续取 | 通过 | `api/sessions/route.ts`(`limit+1` 探测 `nextCursor`)、`app-sidebar.tsx` `IntersectionObserver`,无 spinner / 「加载更多」文案 |
|
||
| 5.6 BUG-553、CHANGELOG、testing 清单 | 通过 | — |
|
||
|
||
**结论:未通过(1 项 P1,其余通过)**。修复 SHA `a1956deb`;P1 修复单 `TASK-session-title-guard-fix-20260906.md`。
|