Skip to content

fix: models.dev UI 永久卡在 loading 态(拉取失败后标记状态并触发重绘)#282

Open
zerx-lab wants to merge 2 commits into
mainfrom
fix/issue-145-models-dev-loading-stuck
Open

fix: models.dev UI 永久卡在 loading 态(拉取失败后标记状态并触发重绘)#282
zerx-lab wants to merge 2 commits into
mainfrom
fix/issue-145-models-dev-loading-stuck

Conversation

@zerx-lab

Copy link
Copy Markdown
Owner

关联 Issue

Fixes #145

问题点(确定性描述)

根因app/src/settings_view/ai_page.rs:3405

// 修复前 — Err 分支只 log,不更新状态、不触发重绘
Err(e) => log::warn!("[models.dev] 拉取失败: {e}"),

EnsureModelsDevLoaded action 的 Err 分支既没有更新 models_dev 内部状态,也没有调用 ctx.notify(),导致 widget 永远无法离开 cached() == None → 渲染 settings-agent-providers-loading-catalog("正在拉取…")的死循环。关闭再重开设置页也无效——每次都重触发同一条失败路径,UI 永远显示 loading 占位。

复现证据(引用自 Step 2)

位置 代码片段 说明
models_dev.rs:114-120 State { catalog, loaded_at } State 无任何失败标志
ai_page.rs:3403-3406 Err(e) => log::warn!(...) 失败仅 log,无状态更新、无 notify
agent_providers_widget.rs:1463-1478 match models_dev::cached() { None => loading text } None 分支无论是 loading 还是 failed 一律显示 loading 文字

规模声明

  • 修改文件数:3(≤ 3 ✅)
  • 修改行数:32(≤ 50 ✅)
  • 影响面:models_dev::cached() 等函数的已知调用方 4 处,均无需联动修改
  • 无新依赖、无 API/schema/auth/并发变更

修改文件清单

文件 行号 改动说明
app/src/ai/agent_providers/models_dev.rs 121, 141-152, 271 State 增加 last_fetch_failed: bool;新增 last_fetch_failed() / mark_fetch_failed();fetch 成功时重置为 false
app/src/settings_view/ai_page.rs 3405-3409, 3420-3424 EnsureModelsDevLoadedRefreshModelsDevErr 分支:调用 mark_fetch_failed() + ctx.notify()
app/src/settings_view/agent_providers_widget.rs 1464-1472 None 分支按 last_fetch_failed() 区分"正在加载"与"已失败",失败时复用 catalog-empty 文字(含"点[刷新目录]重试"指引)

验证

本地环境依赖缓存未就绪(容器内 cargo check 因 git 依赖源不可达而失败),无法运行完整编译。代码正确性通过以下人工验证:

  1. bool 字段有 Default = false#[derive(Default)] 自动初始化为正确初值
  2. use crate::ai::agent_providers::models_dev; 在两个 action handler 各自 arm 的块作用域内均已存在,闭包内的 models_dev::mark_fetch_failed() 在编译期可正确解析
  3. ctx.notify() 与同文件其他 Err 后的 ctx.notify() 调用模式完全一致
  4. widget 中 models_dev::last_fetch_failed() 调用位于已有 use crate::ai::agent_providers::models_dev;(line 1424)的作用域内

影响面

  • 调用方影响:models_dev::cached() 的 4 处调用方(agent_providers_widget.rs:1463ai_page.rs:3427ai_page.rs:3458)均不受新增字段影响,无需联动改动
  • 新增的 last_fetch_failed() / mark_fetch_failed() 仅作 crate 内部使用
  • #[derive(Default)] 保证新字段 last_fetch_failed 初值为 false,与原有语义(未发生失败)一致,无 breaking change

Generated by Claude Code

Fixes #145

根因: app/src/settings_view/ai_page.rs:3405 的 EnsureModelsDevLoaded
Err 分支只 log::warn! 而不更新状态、不调用 ctx.notify(),导致 widget
永远无法离开 "正在拉取…" 的 loading 占位文字。

改动要点:
- models_dev.rs: State 增加 last_fetch_failed: bool,新增
  last_fetch_failed() / mark_fetch_failed() 公开函数,fetch 成功时重置为 false
- ai_page.rs: EnsureModelsDevLoaded 与 RefreshModelsDev 的 Err 分支
  调用 mark_fetch_failed() + ctx.notify() 以触发 UI 重绘
- agent_providers_widget.rs: None 分支按 last_fetch_failed() 区分
  "正在加载" 与 "已失败",失败时复用 catalog-empty 文字(含"点[刷新目录]重试"指引)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MZspQZ4xceDmp3sdbEPXJP

@zerx-lab zerx-lab left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(详见 inline comments 和下方总结 comment)

— 由 Claude Routine 自动生成;如需复评请 @ 维护者人工触发。


Generated by Claude Code

Comment thread app/src/settings_view/agent_providers_widget.rs Outdated

Copy link
Copy Markdown
Owner Author

Review 总结

整体判断:倾向 Approve。逻辑清晰,修复路径与现有代码模式对称,无阻塞问题。


阻塞问题

无。


建议

  • i18n 键语义(见 inline comment):settings-agent-providers-catalog-empty 的翻译如果表达的是「目录内容为空」而不是「拉取出错」,用户可能会误解错误原因。建议核查翻译字符串;若语义不符,可新增专用键(如 settings-agent-providers-catalog-fetch-failed)。

看起来不错的地方

  • #[derive(Default)] 保证 last_fetch_failed 初值为 false,无 breaking change
  • mark_fetch_failed() + ctx.notify() 在两处 Err 分支的写法与同文件其他错误处理完全对称
  • fetch_and_cache 成功时主动重置 last_fetch_failed = false,状态机转换正确
  • 修改面控制在 3 文件 / 32 行,影响面最小化

— 由 Claude Routine 自动生成;如需复评请 @ 维护者人工触发。


Generated by Claude Code

响应 #282 review 意见:`catalog-empty` 语义为「目录拉取成功但无内容」,
不应复用于网络拉取失败场景。新增 `settings-agent-providers-catalog-fetch-failed`
键(含 en / zh-CN / ja 三语翻译),widget 失败态改用新键。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MZspQZ4xceDmp3sdbEPXJP

Copy link
Copy Markdown
Owner Author

本次 webhook 触发时 head commit(e0bcd88)与已完成的 review 一致,无新增改动,跳过重复 review。


Generated by Claude Code

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.

AI 设置页: models.dev 首次拉取失败后 UI 永久卡在 loading 态

2 participants