Skip to content

feat(compact): item 16 压缩重试倒计时 + 卡顿提示 (CC 2.1.228) - #108

Merged
dahai80 merged 1 commit into
mainfrom
feat/compact-retry-stall-item16
Aug 20, 2026
Merged

feat(compact): item 16 压缩重试倒计时 + 卡顿提示 (CC 2.1.228)#108
dahai80 merged 1 commit into
mainfrom
feat/compact-retry-stall-item16

Conversation

@dahai80

@dahai80 dahai80 commented Aug 20, 2026

Copy link
Copy Markdown
Owner

背景 (closes #107)

enhance-0819.md item 16 (CC 2.1.228): compact 期间用户只见静态 spinner Compacting conversation (REPL.tsx:3366), 无任何重试/耗时可见性。后端有 PTL 截断重试循环 (compact.ts 主 + partial 路径, 各最多 MAX_PTL_RETRIES=3), 重试时仅 logEvent("tengu_compact_ptl_retry") 写遥测, 不 emit 用户可见 progress。

LLM-summary compact 单次流可合法 30s+ 无 token (MLX 大上下文摘要慢), 用户无法区分 "正常慢" vs "卡住重试中"。

改动 (3 文件 + 1 test, surgical)

src/Tool.tsCompactProgressEvent 加 2 变体 (纯类型):

  • compact_retry {attempt, maxRetries, reason} — reason ∈ prompt_too_long | mlx_memory | mlx_server_error
  • compact_stall {elapsedMs}

src/services/compact/compact.ts

  • startCompactStallTimer(context, startTime, intervalMs=10s) helper: setInterval emit compact_stall, 返 clear fn
  • 两 PTL 循环 (compactConversation 主 + partialCompactConversation) 各 emit compact_retry (复用已算的 isEmptyMlxOom/isMlxServerError/PTL 判定, 不重判)
  • 两 compact 函数 try 前声明 clearStallTimer, compact_start 后启, 现有 finally clear (覆盖 throw + hook-blocked 早 return, 防泄漏)

src/screens/REPL.tsxonCompactProgress switch 加 compact_retry/compact_stall case, 走现有 spinnerMessage 单通道:

  • retry: Compacting (retry {attempt}/{maxRetries}: {reason})
  • stall: elapsedMs >= FUSION_COMPACT_STALL_HINT_MS (default 30s, fail-open) → Compacting conversation — running {formatDuration(elapsedMs)}, large context summaries can take a while

设计决策

  • 无 feature-flag: 纯可见性, 不改 compact 逻辑/默认行为。重试/stall 仍发生, 只现在用户看得见。
  • 不复用 loadingStartTimeRef: 指 query 起点非 compact 起点 (compact 在 turn 中途触发), elapsed 含 turn 前段不准。compact 自带 startTime。
  • stall 用 setInterval 而非 stream 钩子: streamCompactSummary 是 black-box async, 不暴露 per-token callback。侵入内部反 Rule 3。interval 在 compact 函数作用域自管, clear 随 compact_end/throw。
  • retry + stall 走同一 spinnerMessage: retry 即时覆盖动词文本, stall 追加耗时。retry 瞬时, stall 30s 才显, 时序不撞。

验证

  • typecheck 0 errors
  • 4 新单测 (compactProgress.test.ts): emit 递增 / clear 防泄漏 / no-callback no-op / interval 边界 — 全 pass
  • 全 214 单测 pass (无回归)
  • build + build:dev:full pass
  • changed 文件 lint clean (REPL.tsx pre-existing 74 errors 非本 PR 引入, 均在既有行)

Co-Authored-By: Claude Fable 5 noreply@anthropic.com

compact 期间用户只见静态 spinner, 无重试/耗时可见性。MLX 大上下文摘要
单次流可 30s+ 无 token, 用户无法区分 "正常慢" vs "卡住重试中"。

扩展 CompactProgressEvent 2 新变体:
- compact_retry {attempt, maxRetries, reason}: 截断重试发生时 emit,
  reason 复用已算的 isEmptyMlxOom/isMlxServerError/PTL 判定不重判
  (prompt_too_long/mlx_memory/mlx_server_error)。主 + partial 两 PTL 循环各 emit。
- compact_stall {elapsedMs}: 周期 emit (default 10s interval), 前端超
  FUSION_COMPACT_STALL_HINT_MS (default 30s) 显耗时提示。

startCompactStallTimer helper: setInterval emit compact_stall, 返 clear fn,
两 compact 函数 try 前声明 + compact_start 启 + 现有 finally clear
(覆盖 throw + hook-blocked 早 return, 防泄漏)。不复用 REPL
loadingStartTimeRef (指 query 起点非 compact 起点, elapsed 不准)。

REPL.tsx onCompactProgress switch 加 compact_retry/compact_stall case,
走现有 spinnerMessage 单通道 (Rule 2 简化, 不引新 state)。无 feature-flag
(纯可见性增强, 默认行为不变)。

验证: typecheck 0 / 4 新单测 pass / 全 214 pass / build + build:dev:full pass /
changed 文件 lint clean。closes #107

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dahai80
dahai80 merged commit dd0e3b8 into main Aug 20, 2026
1 check passed
@dahai80
dahai80 deleted the feat/compact-retry-stall-item16 branch August 20, 2026 23:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 压缩重试倒计时 + 卡顿提示 (item 16, CC 2.1.228)

1 participant