fix(settings): 切换 LLM/ASR preset UI 不刷新 (#219)#220
Conversation
底层 providers HashMap 已是 per-provider,bug 完全在前端两个 onChange:
1) Race
setLlmProvider(id) / setAsrProvider(id) 是同步 React state 改动,
CredentialField 用 `key={`${provider}:api_key`}` 强制重挂载、读后端
ark.api_key —— 但此时 await setActive*Provider 还没跑,root.active.llm
还是旧值,lookup_account 落到旧 entry。把 await setActive 移到
setLlm/AsrProvider 之前修。
2) 覆盖
旧实现无条件 setCredential('ark.endpoint', preset.baseUrl),把用户在
该 provider 上之前自定义的 baseUrl 覆盖掉。改成「仅在 entry 该字段
为空」才填默认值,保留用户自定义。ASR 端的 endpoint + model 同款修。
不动 persistence schema、不动 IPC、不动 coordinator。
Closes #219
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1accecbd57
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // 不再无条件覆盖用户自定义值。 | ||
| const onLlmProviderChange = async (id: LlmPresetId) => { | ||
| setLlmProvider(id); | ||
| await setActiveLlmProvider(id); |
There was a problem hiding this comment.
Update provider selection state before awaiting async work
onLlmProviderChange now waits on multiple async IPC calls before calling setLlmProvider. Because this is a controlled <select>, delaying the state update until after await makes the displayed selection depend on async completion order rather than the latest user input. If the user switches providers quickly, an earlier request that resolves later can overwrite a newer choice and leave the UI showing a stale provider.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
已修复 P2,commit 1eec2fa。
按反馈把 provider state 拆成两个:
*Provider立即跟随用户输入,驱动 `` —— 受控反馈始终是最新选择 committed*Provider 仅在所有 await 完成后 commit,驱动 `CredentialField` 的 key 与 placeholder/preset 渲染 加 *SwitchSeqRef 守卫:每次进 handler 自增,每段 await 后比对,发现已有更新的 switch 在飞就 abort 当前 commit 三类回归路径都堵上了: 单次切换:`` 立即响应;CredentialField 等后端 active 切完才 remount 读正确 entry(issue fix(settings): 切换 LLM/ASR preset 时凭据 UI 显示旧 active 的内容(race + 覆盖) #219 fix 保留)- 快速连点两次:只有最后一次的 commit 落地,旧请求晚到也不会覆盖
- 渲染期间 placeholder:跟着 committed 走,避免「`` 已经是 DeepSeek 但 placeholder 还显示 ARK 默认 URL」的不一致 `tsc + vite build` 通过。
PR Reviewer Guide 🔍(Review updated until commit 1eec2fa)Here are some key observations to aid the review process:
|
Codex P2: 上一版把 setLlmProvider/setAsrProvider 挪到所有 await 之后, 受控 <select> 的 value 现在依赖 IPC 完成顺序——用户连点两次时,先发的 请求晚到会用旧 id 覆盖最新的 setProvider,UI 卡在错误选项上。 修法(state 二分): - *Provider:立即跟随用户输入,驱动 <select> - committed*Provider:仅在所有 await 完成后才 commit,驱动 CredentialField 的 key 与 placeholder/preset 的渲染 - *SwitchSeqRef:每次进入 handler 自增,每段 await 后比对,发现已有更新的 switch 在飞就 abort 当前 commit,stale write 保护 效果: - 用户切换 <select> 立刻看到新选项(受控反馈正确) - CredentialField 等到后端 active 真切完才 remount 读 entry(issue #219 修复保留) - 100ms 内连点两次:只有最后那次的 commit 落地,UI 不会被旧请求覆盖
|
Persistent review updated to latest commit 1eec2fa |
包含自 1.2.13 以来的修复与新功能: - feat(autostart): 跨端开机自启 (#194) - feat(asr): SiliconFlow / GLM-ASR / Groq / OpenAI Whisper preset (#212) - fix(qa): Windows / Linux 划词追问浮窗 Esc + 拖拽 + 文案 (#205 / #206) - fix(settings): preset 切换 race + per-provider 凭据隔离 (#219 / #220) - fix(overview): 概览整屏适配 + 嵌套 scroller 细滚动条 (#243 / #248) - 一系列 Windows IME (TSF) 模块 (#233 / #240 等)
User description
Closes #219
Summary
设置页切换 LLM / ASR 供应商时,凭据输入框显示的还是旧 active provider 的 key/model/endpoint —— 用户以为切换没生效,实际是前端 race。底层 providers HashMap 已经是 per-provider,不需要改后端。
根因(两条 bug 在同一函数)
改动
Settings.tsx 两个 handler,共 +20/-8:
不动 persistence schema、不动 IPC、不动 coordinator。
Test plan
PR Type
Bug fix
Description
Fix race: switch backend active before UI remounts
Preserve user overrides: default endpoint/model only if empty
Handle rapid switches: split state and sequence ref to abort stale
Credential field keys now use committed provider for correct reads
Diagram Walkthrough
flowchart LR A["User selects new provider in <select>"] B["Immediate setLlmProvider → UI reflects choice"] C["Increment sequence ref (seq = ++ref)"] D["await setActiveLlmProvider(id)"] E{"seq matches?"} F["await updatePrefs(next)"] G{"endpoint/field empty?"} H["setCredential(default) only if empty"] I["setCommittedLlmProvider(id)"] J["CredentialField remounts with correct key"] K["Abort: stale request, do not commit"] A --> B B --> C C --> D D --> E E -- yes --> F E -- no --> K F --> E E -- yes --> G G -- yes --> H G -- no --> E H --> E E -- yes --> I I --> JFile Walkthrough
Settings.tsx
Fix stale credential display and overwrite protection in providerswitch handlersopenless-all/app/src/pages/Settings.tsx
committedLlmProvider/committedAsrProviderstate to defercredential remount until backend active provider is set
llmSwitchSeqRef/asrSwitchSeqRefto abort stale async flows onrapid switches
setActive*ProviderandupdatePrefsbefore commit; defaultendpoint/model only written if current value is empty
CredentialFieldkeys,ProviderToolskey, and volcengineconditional to use
committed*Providerinstead of immediate statepresetlookups and placeholder logic now derive from committedprovider, preventing placeholder/credential mismatch