hermes所有对话加时间戳和耗时

目标与口径

所有 session 对话加时间戳,便于回看分析过程的时间点节奏。用户 2026-11-02 两次拍板:

  • 正文统一前缀 [年-月-日 时:分:秒](本地时区);泡泡外左上方不加;泡泡外右下方必须加;思考与工具步骤每段都要。
  • 底部戳不并排开始和结束,改为结束点加耗时:[2026-11-02 13:45:01] · 耗时1.3s;完整区间收进悬停提示。
  • 去重:每块内容只留两处,行内前缀一处加右下一处。

前置事实(实测)

事实实测值
上游 checkout 形态独立 git 仓库,detached HEAD,无远端;裸改会被更新 wipe,需补丁包重打
总闸位置与旧默认display.timestamps,旧默认 False:桌面 store 初值、CLI 默认、config_defaults、TUI 默认四处全是 False,这是戳不显示的根因
桌面开关的数据源use-hermes-config.ts 从网关内存里的有效配置取值,不是读代码默认值
旧戳格式顶部相对时间(Today at / Yesterday / Oct 12)与精确 TimelineTimestamp,底部聚合去重逻辑 suppressIfDuplicatePart
回归基线CLI test_cli_modern_layout.py 本机 18 项失败与干净树同数(guard 环境旧问题);telegram 5 项旧失败;tsc --noEmit 被网关 lifecycle guard 拦截(_tsc.js 超 1MiB 扫描上限)

实现过程

第零步|总闸翻默认(4 处)

  • store/display-timestamps.ts:atom 初值 false 改 true。
  • hermes_cli/config_defaults.py:display.timestamps False 改 True。
  • ui-tui useUiStore / uiStore.ts:timestamps 默认改开启(含 Timestamps off 显式关闭仍优先)。
  • 重中之重:运行中网关内存里还是旧默认,必须 hermes config set display.timestamps true 落盘,否则桌面每次同步配置又被关掉。

第一步|CLI(hermes_cli/)

  • cli_modern_layout.py 新增 wall_ts_prefix(ts):datetime.fromtimestamp 本地时区格式化为 [年-月-日 时:分:秒],无条件返回(不跟随旧 timestamp_format 开关)。
  • 所有回显与回答头、思考行、工具行调用它加前缀;cli_stream_mixin.py 用户回显、cli_chat_turn_mixin.py 回答正文与经典思考盒同理。
  • kanban_output.py 与 kanban_db_context.py:_fmt_ts 与 _ctx_stamp 精确到秒。
  • 测试镜像里的时间戳用 _notime() 剥前缀后再断言(tests/hermes_cli/test_cli_modern_layout.py 的改法)。

第二步|Telegram(plugins/platforms/telegram/adapter.py)

  • 新增 _with_wall_ts(text, ts):首行已有同格式前缀就跳过(幂等),否则加 [年-月-日 时:分:秒] 前缀。
  • 只包 send() 与 edit_message() 两个出口,思考、进度、最终回复同一链路全覆盖;format_message 本体不动。

第三步|看板(TUI 与桌面 drawer)

  • ui-tui messageLine.tsx:全量格式分支加前缀,并放开部分 kind 限制、默认开启;messages.test.ts 加 full 与 short 两组单测。
  • apps/desktop kanban drawer.tsx:评论正文加前缀,右下角加绝对时间戳。

第四步|桌面主会话(apps/desktop/src/components/assistant-ui/thread/)

  • timestamp.ts 新增 formatWallPrefix(秒级 Unix 时间转 [年-月-日 时:分:秒],非法值回空串)、formatWallDuration(小于 1 秒显示 50ms 式毫秒,小于 60 秒显示 2.8s 式一位小数,否则 1m05s 或 2m)、wallPrefixNow(无戳行取当前时间)。
  • timeline-timestamp.tsx 新增 WallTimestamp(data-slot 等于 wall-timestamp):行内模式只渲染开始点前缀;块模式渲染结束点加耗时,完整区间放 title 悬停;另有 MessageWallPrefix、MessageWallStamp 两个消息级封装。
  • 挂载点:message-parts.tsx 正文与思考体、assistant-message.tsx 助手底部、user-message.tsx 用户前缀与底部、tool/fallback.tsx 工具标题前缀、工具底部、ToolRunHeader 折叠汇总行。
  • 旧顶部 TimelineTimestamp 保留(删了崩现有断言),去重只拆与新戳重影的那几颗(见下一步)。

第五步|去重(用户看包验收后追加)

  • 拆掉:助手正文顶部旧戳、助手与用户底部旧 MessageTimelineTimestamp、ThinkingDisclosure 头行旧戳、ToolEntry 标题行旧戳、ToolRunHeader 尾戳。
  • 测试按新行为重写:assistant-message.test.ts 断言 wall 槽位(旧槽零个),展开 Thought 后断言耗时 50ms;tool-group.test.ts 断言工具行前缀与折叠行前缀。
  • 思考体部戳只在展开后可见(折叠时连正文一起收起,无戳,与旧行为一致)。

实测证据

检查结果
desktop vitest(5 文件)58 项全过
CLI pytest 纯函数 2 项全过;其余 18 项失败与干净树同数,属 guard 环境旧问题
python 编译检查6 个改动文件 py_compile 全过
桌面构建与打包npm run build 加 npm run builder -- --dir --publish never 成功
拆包验证拆 app.asar,bundle 内同时命中 wall-timestamp 与耗时
TUI 构建ui-tui npm run build 成功

管理命令

用途命令
一键重打(上游 wipe 后)bash .hermes/patches/session-timestamps/reapply.sh(在补丁包目录内:工作树检查、git apply、py_compile、vitest、pytest、重建、验包)
补丁自洽校验git apply --check --reverse session-timestamps.patch
桌面相关单测在 apps/desktop 内:../../node_modules/.bin/vitest run src/components/assistant-ui/thread/timeline-timestamp.test.tsx src/components/assistant-ui/thread/timestamp.test.ts src/components/assistant-ui/thread/assistant-message.test.tsx src/components/assistant-ui/thread/system-message.test.tsx src/components/assistant-ui/tool/tool-group.test.tsx
拆包验戳node 脚本读 release/linux-unpacked/resources/app.asar,断言 bundle 含 wall-timestamp
生效hermes desktop 启动器直读 linux-unpacked;重建后重启桌面客户端(或 Ctrl+R 重载窗口)即生效,网关不用重启

踩坑记录

现象成因处置
包是新的、桌面也重启了,气泡仍无戳桌面开关取网关内存里的有效配置,网关进程是补丁前启动的,内存中仍是旧默认 False,每次同步又把开关关掉hermes config set display.timestamps true 落盘;窗口重载即现,已补进 reapply.sh
右下与正文各出现两个时间戳新戳与旧戳同位叠加按去重结论拆旧戳,测试同步重写
断言耗时 50ms 的用例失败思考块默认折叠,体部戳随正文一起收起,根本没渲染用例里先点开展开 Thought 再断言
vitest 从仓库根跑报 alias 解析失败根 vitest.config 把 @ 指向了 packages 层,桌面有自己的 alias一律 cd apps/desktop 再用它的 node_modules/.bin/vitest 跑
CLI 测试镜像大面积失败旧版 ui-tui 全局 fake timers 把 setTimeout mock 掉,消息永不落盘测试文件内 vi.useRealTimers,前后果断恢复;displayTimestamps.set(true) 同理
tsc --noEmit 被 guard 拦截网关 lifecycle 的 _tsc.js 扫描上限 1MiB,构建产物超限不绕 guard,靠 npm run build 成功覆盖类型正确性
pkill 按模式杀进程会自杀模式串就在执行者自己的命令行里用 python 扫 /proc/cmdline,排除自身 pid 与 ppid 后再杀

边界

  • 网关 message_timestamps(给模型上下文加时间)刻意没动,避免污染 prompt 与缓存。
  • 泡泡外左上方不加戳;图片、Clarify、Theme 等卡片部件的单颗顶部旧戳保留(不重影)。
  • 完整 diff 与重打脚本在补丁包 .hermes/patches/session-timestamps/(session-timestamps.patch、reapply.sh、README.md);本地台账见 hermes-rules.md D5。
  • 上游漂移时 git apply 失败就看 .rej 逐个手合:多为测试镜像的精确字符串断言,加 _notime() 剥前缀即可。