feat(lark): 会话卡展示当前模型与推理强度 - #780
Conversation
从 TRAE 运行转录同步当前 model 和 reasoning effort,并在飞书会话卡 usage 行展示。修复 plain_text 标题泄露 mention 标签,同时补齐 runtime 变更刷新和回归测试。 Co-authored-by: TRAE CLI <noreply@bytedance.com>
deepcoldy
left a comment
There was a problem hiding this comment.
复审结论:请求修改。当前实现的核心链路能工作,但以下问题需要在合并前收口。
-
[P1] Codex 的“当前推理强度”仍是启动快照,
/effort后会显示错误值。getDaemonStreamingCardUsageSnapshot()对 effort 的非 TRAE fallback 是ds.session.reasoningEffort;而/effort是 raw passthrough,不会修改 Session。当前只有 TRAE bridge 会发active_runtime,Codex 的thread_settings_appliedtracker 也没有把 effort 发布给 daemon。因此 Codex 从xhigh切到low后,卡片仍会长期显示xhigh(从未配置时则一直不显示)。同理,Codex/model的 settings 事件虽带 model 并触发 PATCH,但ds.codexServiceTier.model没进入 model 选择链,PATCH 当下仍可能用旧的 usage model。建议把 Codex executor-confirmed model/effort 一并接入 generation-bound runtime snapshot,而不是回退到冻结的 Session 配置。 -
[P1] stale-worker guard 只挡旧尾包,没有在 rollout/worker generation 切换时清空旧 runtime。
activeModel/activeReasoningEffort只在收到下一条active_runtime时更新;codexBridgeDetachFile()、daemon 的killWorker()/forkWorker()都不清,stopCodexBridge()也只是重置 worker 本地 publisher,没有向 daemon 发 null。可复现窗口是 TRAE/new/重新 attach 已拿到新 SID 但新 rollout 尚未出现:旧 bridge 已 detach,期间的 screen update 会继续用上一代ds.activeModel,若 attach 最终失败则会一直错。建议在 daemon worker-generation 变更时同步清内存态,并在同 worker 的 rollout detach/stop 发布显式 clear;恢复静默期只清状态、不碰旧卡即可。 -
[P2]
usageDisplay=footer/off仍先做原生 usage I/O,结果随后被丢弃。 新代码在检查resolveUsageDisplay()前无条件调用getDaemonSessionUsageSnapshot();但非 streaming 分支返回context/tokens: null,而 renderer 又明确禁止 runtime-only 行,所以这次读对 UI 没有任何作用。该函数位于 ready/status edge、10 秒 screenshot refresh、limit/exit 等多条重渲染路径;fresh:true还会绕过 miss/reparse throttle,TRAE/Aiden 可触发目录扫描,Codex 每次也会做多次同步 stat。请恢复“先判 display、再读 transcript”的短路;若产品要在 off/footer 也显示 runtime,则需先改 renderer 契约,而不是白读。 -
[P2] TRAE 每次 attach 都从 offset 0 全量 JSON.parse rollout,长会话恢复退化为 O(file size)。
readLatestTraexRuntime()全文件扫描且没有大小上限,并被codexBridgeAttach()无条件调用。原先baseline-existing只需baselineJsonlCursor()的 64 KiB 尾探针;现在 daemon 恢复/worker restart 会全量扫每个存量 TRAE 会话。split-live本来就会structuredBridgeIngestPath(..., 0),当前还会再全量读一遍。建议对 settings 做反向有界扫描,或直接复用已经 drain 出来的TraexDrainResult,并加长 rollout 回归测试。 -
[P2] model fallback 实际改变了所有支持 native usage 的 CLI,且会直接展示内部代号。
snapshot.tokens.model现在优先于Session.model,不只 TRAE/Codex;仓库现有 Relay fixture 就是ark/relay-code,会原样出现在用户卡片。对带长 provider/route 前缀的模型,20 字符前缀截断还可能只留下相同前缀、丢掉真正可区分的后缀。这与 PR 描述“其它 CLI 保持不变”不一致。建议只对有用户态 display contract 的 CLI 启用 transcript model,或增加 per-CLI normalize/display policy,并至少补 Relay/Claude-family 的行为测试与影响面说明。
关于 fresh TRAE PID:我暂未把“SID 半成品”列为独立 blocker——只有进程已经持有完整 rollout 路径后才会解析出 UUID,SID 本身是稳定的。但 codexAdoptPendingPid 现在也承载 fresh-managed discovery,1 秒 poller 会在 submit confirmation 之前持久化 findTraexRolloutByPid() 返回的第一个 open rollout;该 finder 对多 rollout FD 是 first-wins。建议改成语义明确的 pending PID 字段,并补 fresh/no-input、多个 owned rollout、sandbox late-leaf 的行为测试;目前新增测试只是 source-string wiring,覆盖不到提前持久化的语义。
验证:
pnpm build:通过- PR 描述列出的 9 个测试文件:533 tests passed
pnpm test:13,250 tests passed;1 个无关 suite 的beforeAll在全量并发下超时- 单独复跑
test/group-join-shared-routing.test.ts:15 tests passed
针对会话卡「当前模型/推理强度」的五处收口: ① Codex 现在跟随 in-session /model、/effort:thread_settings_applied 里本就带 reasoning_effort(顶层与 collaboration_mode.settings 双写),扩展 codex transcript 解析并加入 CodexThreadSettings.reasoningEffort;codex_service_tier handler 把快照的 model/effort 灌入 ds.activeModel/activeReasoningEffort, 复用既有 service-tier tracker,无需新增 IPC 通道。 ② worker 换代(respawn/角色切换)时,在清 codexServiceTier 处一并清 activeModel/activeReasoningEffort/pendingActiveRuntimeCardRefresh,避免新 worker 首次观测前的空窗残留旧模型/强度尾巴。 ③ getDaemonStreamingCardUsageSnapshot 把转录磁盘读推迟到 non-streaming 提前 返回之后,usageDisplay=footer/off 的 bot 不再每 tick 白读一次转录再丢弃。 ④ readLatestTraexRuntime 改为有界后向扫描(4MiB 上限,对齐 usage 侧转录字节 护栏),命中 model+effort 即停;split-live attach 复用自身 drain 的运行时 观测,消除对同一 rollout 的二次全量 parse。 ⑤ 流式卡模型不再回退 snapshot.tokens.model:该字段是转录原始 model,relay 类 CLI 会是内部路由代号(如 ark/relay-code),不应展示给用户。模型仅来自已接线 的执行态运行时或用户配置的启动 model;并移除随之失效的 tokens.model 字段。 影响面:动到共享渲染路径与 core/worker-pool、worker 结构化桥接与 codex/traex transcript 读取。native-usage 展示的 CLI(claude/gemini/relay 等)不再泄漏原始 model;footer/off 的 bot 去掉每 tick 白读;Codex 卡片现反映 in-session 切换。 验证:pnpm build 通过;新增/改动单测覆盖 Codex effort 解析、tier 快照 effort 去重、TRAE 有界后向扫描(含 offset 0 命中与大文件扫回尾部)、split-live 单次 扫描与换代清态、原始模型不外泄;全量非-e2e 单测 13273 passed / 0 failed。
上一轮收口把 Codex 的 model/effort 接在 thread_settings_applied 上,但该 事件在多数会话里根本不写(实测最近 10 个 rollout 大多 thread_settings_applied=0), effort 实际写在每个 turn 都有的 turn_context 里。导致正常起的 codex bot 卡片 只显示模型、看不到推理强度。 改为与 TRAE 对齐: - codex-transcript: drainCodexRollout 增量解析 turn_context(payload.model/ effort 及 collaboration_mode.settings 兜底),latest-wins 产出 latestModel/ latestReasoningEffort;新增 readLatestCodexRuntime 有界后向扫描(4MiB 上限, 排除未换行的半写行)供 attach/restore bootstrap。 - worker: split-live / 增量 ingest / baseline 三处都经既有 active_runtime 通道 发布 Codex 运行时(与 TRAE 同一路径)。 - worker-pool: codex_service_tier handler 不再兼写 activeModel/ activeReasoningEffort,收敛为仅驱动 ⚡ tier 徽标,避免与 active_runtime 写入 竞争、被缺失的 thread_settings_applied 清成空。 验证: pnpm build 通过;新增 turn_context 解析 / latest-wins / 增量范围 / readLatestCodexRuntime tail 命中与半写行排除等单测,并更新受影响的 source-lock 测试;全量非-e2e 单测 13282 passed / 0 failed;对 turn_context matcher 做变异 可翻红 6 例。
卡片渲染运行时模型名时,剥掉开头的 `provider/` 路由命名空间(如 model_hub/es1_orange_o48 → es1_orange_o48),只展示裸模型名,不把中转层的 内部命名空间露给用户。仅当前缀是干净的单段 token(字母数字/._-)紧跟一个斜杠 时才剥离;无斜杠(gpt-5.6-sol)或含斜杠的任意文本原样返回,不误伤。 验证: pnpm build 通过;md-card 单测新增 provider 前缀剥离(含无斜杠不变、 多段仅剥首段)用例,全文件 118 passed。
改了什么
model与reasoning effort,并通过 worker IPC 同步到 daemon/model或/effort导致运行时配置变化时,主动刷新当前 streaming cardplain_text卡片标题错误显示转义后的<at ...>mention 标签为什么
会话卡此前只能看到上下文与 token 使用量,无法确认当前实际运行的模型/推理强度;同时由带 mention 的消息生成标题时,
plain_text使用 markdown 转义会把原始标签和反斜杠显示出来。影响面
验证
pnpm buildpnpm exec vitest run --project unit test/card-builder.test.ts test/md-card.test.ts test/message-parser.test.ts test/streaming-card-usage-arg.test.ts test/worker-ready-display-mode.test.ts test/cost-calculator.test.ts test/traex-transcript.test.ts test/traex-worker-bridge-wiring.test.ts test/usage-refresh-timer-wiring.test.ts