Repository navigation
fix(chat): show the agent chip loading instead of ignoring taps - #15
Merged
Merged
Conversation
A local OpenCode with plugins takes ~25s on its first GET /agent after a start. During that time the mode chip had no agents and a tap only fired a silent background refresh, so the chip looked dead on every app start or runtime restart. Reproduced on an emulator with a proxy delaying the first /agent by 25s: the first 7 taps (26s) showed nothing. - RuntimeCatalogState.agentsLoading: true while agents are being read and none is on screen (load or the background retry), false once they arrive or the retries give up - the chip swaps its shield for a small spinner while loading - a tap always opens the menu: a disabled "Loading agents…" while loading, "Couldn't load agents. Tap to retry." once retries are over; agents that arrive while it is open replace the placeholder - strings in all 8 locales
- load()'s final write reads the agents inside the update, so a retry that succeeded between its fetch and write is no longer overwritten with an empty list (which also left the spinner running) - a retry tap on a never-connected runtime marks loading synchronously, so repeated taps cannot queue one full reconnect each - the spinner carries the loading content description for TalkBack - zh-CN uses 智能体 like the rest of the locale
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #13: after dp5 the user still reported "the build button often doesn't respond".
Cause. A local OpenCode with plugins takes ~25s on its first
GET /agentafter a start. During that window the mode chip had no agents, and a tap only fired a silent background refresh. The chip looked dead on every app start or runtime restart.Reproduced on an emulator with a proxy delaying the first
/agentby 25s. Before the fix, 7 taps over the first 26s showed nothing. Against a healthy server every tap works (30/30 across the chip's icon, text, arrow and edges), so the touch target is not the problem.Fix
RuntimeCatalogState.agentsLoading(surfaced asSettingsUiState.agentsLoading) is true while agents are being read and none is on screen. It goes false once they arrive or the retries give up.load()'s final write reads the agents inside the update, so a retry that lands between the fetch and the write is not overwritten (it also kept the spinner running).Verified
detekt spotlessCheck :app:testGithubDebugUnitTest :app:assembleGithubDebug, 1406 unit tests passing./agent: every tap at 8–23s showed "Loading agents…", and from 28s the menu listed orchestrator/build/plan.Pre-PR review
Reviewed at bf92cd2: APPROVE. Follow-up commit 08bec3e applies its suggestions:
It is verified locally (1406 tests) and on the emulator. Report:
判定: APPROVE
ブロッカー
なし
提案(非ブロッキング)
RuntimeCatalogRepository.kt:269-286と:337-346:ごくまれな競合で、スピナーが回り続けることがあります。同じランタイムでrefresh()している最中に、前から走っていた再試行 job が成功するケースです。load()が:267でmutableState.valueを読む。withAgents(list)を書き込む。load()が:269で state 全体を上書きし、agents が空、agentsLoading = trueになる。isActiveなので、:286のrefreshAgents()が:329で何も起動しない。agentsLoadingが加わったことで、見た目が「ずっと読み込み中」になりました。:269をmutableState.update { }にして、更新の時点でit.agentsFor(target)を見直す。または:286の判定を job の結果とは別に行う。RuntimeCatalogRepository.kt:318-322:接続に失敗した状態で失敗表示の項目やチップを連打すると、fullrefresh()がその回数だけ順番に積まれます。refresh()が起動したload()が mutex を取ってagentsLoading = trueにするまで、メニューは「Couldn't load…」のまま押せる状態です。この間に連打した分のload()が mutex の後ろに並び、それぞれが接続の再試行(約 15 秒)を最初から行います。refresh()を呼ぶ前に、同期的にmutableState.update { it.copy(agentsLoading = true) }をしておく。これで項目がすぐ無効になり、二重のタップも防げます。または full refresh の job を 1 本に絞る。ChatHomeScreen.kt:2053-2058:スピナーを表示している間は、盾アイコンのcontentDescription(cd_agent_mode)が消え、TalkBack はラベルの「build」しか読み上げません。Modifier.semantics { contentDescription = … }に既存のchat_agents_loadingを割り当てるのが簡単です。values-zh-rCN/strings.xml:481-482:「agent」が英語のまま残っています。同じファイルの既存の訳では「智能体」が使われているので(:449のdrawer_agents_title、:1040など)、そちらに揃えることを推奨します。例:「正在加载智能体…」「无法加载智能体,点按重试。」(句点の有無も他の言語に揃える)。RuntimeCatalogRepositoryTest.kt:415-417:runCurrent()では、load()の最初の/agent読み込みと最後の書き込みまで終わっています。このとき true になっているのは「再試行が控えている」ことによるもので、コメントの「Before the first read lands」とは意味が違います。assert 自体は正しいですが、コメントを直すか、listAgentsを suspend させて本当に読み込み前の状態を検証するとよいです。ランタイム切り替えや接続失敗でagentsLoadingが false に戻ることを確かめるテストもあると、固着の退行を防げます。チェック済み項目
git diffは実行していません。agentsLoading、chat_agents_*を grep し、該当箇所を直接読みました。detekt、spotless、テスト、エミュレータの結果は報告されたものに基づいています。agentsLoadingが固着する経路(見てほしい点 1):collectLatest(:93)が先にRuntimeCatalogState(runtime = target)で state を作り直すので、false に戻ります。切り替え前のランタイムのload()が cancel されたり、:178/:235の early return で抜けたりしても、その後の state は新しいランタイムのものです。:330):その job は書き込みに届かず、届いても:339/:342の id 確認で弾かれます。:212-217):既定値の false に戻ります。:344で false になります。:329でそのまま使われ、最後に書き込むので、固着しません。enabled = !loadingとonClick = onRefresh(見てほしい点 2):refreshAgents()が:332-334で同期的に loading にします。メニューは開いたまま Loading 表示に変わり、agents が入れば同じメニューが 3 項目になります(expandedは閉じません)。refresh()経由なので Loading 表示になるのが遅れます(提案 2)。chat_agents_loadingとchat_agents_load_failedが全 8 ロケール(values、ar、es、fr、ja、pt-rBR、ru、zh-rCN)にあることを grep で確認しました。英語のCouldn\'tはエスケープ済みで、他のロケールには未エスケープのアポストロフィはありません。Kotlin 側はstringResourceを使っていて、ハードコードした文字列はありません。"build"のフォールバックは既存のコードです。AndCodeApp.kt:1075→ChatHomeScreen.kt:186(既定値 false)→:667→ChatComposer:1302(既定値 false)→ModeChip:1671/2016。SettingsUiState.agentsLoading(SettingsViewModel.kt:55/222)も既定値付きです。ViewModel の依存は増えていないので、DI の変更は不要です。CircularProgressIndicatorは import 済みです(:79)。agentsFailureで改行を空白に置き換えている(:361-364)、health == nullかつ読み込み中なら再試行を起動しない(:318-322)。