fix(chat): point floating window at the targeted chat - #1160
Open
yoruuuchan wants to merge 1 commit into
Open
Conversation
chat_with_agent opens the floating window through start_chat_service, which carries no chat id, and only afterwards routes the message with chat_id. The FLOATING runtime's currentChatId is kept in sync with the foreground chat, so the window stayed on the conversation the user was looking at while the message went to the target one. Follow the target chat with switchChatLocal on a targeted send. It only touches the floating runtime's local state and never writes back to the global current chat, so the main UI is unaffected. The MAIN runtime still does not switch, keeping a background send from yanking the conversation the user is reading.
5 tasks
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.
变更说明 / Description
工作流触发
chat_with_agent时,弹出的悬浮窗显示的是用户当前所在的对话,而不是chat_id指定的目标对话。本 PR 让悬浮窗在定向发送时跟随目标对话。背景与动机 / Context and motivation
chat_with_agent(内置包extended_chat,工作流节点extended_chat:chat_with_agent走的是同一份 JS)分两步工作:Tools.Chat.startService()→start_chat_service,构造FloatingChatService的 Intent 并setFloatingWindowVisible(true)。这个 Intent 只携带INITIAL_MODE/AUTO_ENTER_VOICE_CHAT/WAKE_LAUNCHED/AUTO_EXIT_AFTER_MS/KEEP_IF_EXISTS,没有任何 chat id。Tools.Chat.sendMessage(message, chatId, ...)→send_message_to_ai,目标 chat id 只出现在这一步。第 2 步通过
core.sendUserMessage(chatIdOverride = targetChatId)把消息正确投递到目标对话,但悬浮窗渲染的是chatCore.currentChatId。FLOATING runtime 是ChatSelectionMode.LOCAL_ONLY,启动时快照全局currentChatId,之后由ChatRuntimeHolder.registerChatSelectionSync(MAIN -> FLOATING)持续跟随主界面。因此目标 chat id 从未传到显示层,窗口停在前台对话 A 上,而消息实际发往 B。send_message_to_ai未指定runtime时默认走 FLOATING,所以chat_with_agent与 external chat 的chat_id+show_floating组合都是这个形状。改动范围 / Changes
StandardChatManagerTool.startMessageToAIStream:定向发送且 runtime 解析为 FLOATING 时,先调用既有的ChatServiceCore.switchChatLocal(targetChatId)让悬浮窗跟随目标对话,再发送消息。switchChatLocal只改 FLOATING runtime 的本地状态,不写回全局currentChatId,主界面不受影响,符合docs/doc-src/architecture/chat_runtime_foreground_service_plan.md中「FLOATING Core 只响应自己的切换」的约定。FloatingDisplayChatSelector:把「哪个 runtime 该跟随目标对话」的判定抽成纯函数,便于回归测试。MAIN runtime 明确返回 null,后台发送不会把用户正在读的对话顶掉;目标为空、为空白或与当前显示相同时也返回 null。runtimeSlot ?: ChatRuntimeSlot.FLOATING提为effectiveSlot,让 FLOATING 这个默认值只表达一次。FloatingDisplayChatSelectorTest,6 个用例。docs/doc-src/package-dev/chat.md:在sendMessage的options说明里补一条定向发送时的悬浮窗跟随行为。修在
startMessageToAIStream这个唯一汇聚点上,工作流、AI 直接调用send_message_to_ai、以及 external intent / HTTP / A2A 的定向流式发送一并覆盖,不需要改extended_chat的 TS 源与产物,因此不涉及sync_example_packages.py重新生成。明确不包含:#555 的第 2 项「后台静默执行 / 完全不弹悬浮窗」。那是独立的 feature,本 PR 不做,所以合并后 #555 不会自动关闭。
兼容性与风险 / Compatibility and risks
send_message_to_ai的参数 schema 不变,AI 侧提示词无需改动。chat_id且走 FLOATING runtime 的发送,现在会让悬浮窗切到该对话。这正是 issue 期望的行为。走 MAIN runtime 的发送行为不变。switchChatLocal是 fire-and-forget,与ChatRuntimeHolder.syncChatSelection和悬浮窗历史选择器的既有用法一致,未额外加等待。切换期间ChatHistoryDelegate.addMessageToChat仍会持久化消息,不会丢消息。关联 Issue / Related issue
Part of #555
只修复第 1 项「悬浮窗指向错误的对话」。第 2 项「静默后台执行」尚未实现,因此这里刻意不使用 Closes / Fixes / Resolves,避免合并后自动关闭整个 Issue。
验证方式 / Verification
需要说明的两点:
dev上,:app:testDebugUnitTest会在:app:compileDebugUnitTestKotlin阶段失败,原因是两个既有测试文件已经过期,与本 PR 无关:XaiProviderReasoningTest.kt引用了app/src/main中已不存在的XaiReasoningMapper和xaiModelSupportsReasoningEffort;DeepseekProviderMediaRoleTest.kt:244直接调用了OpenAIResponsesProvider中为protected的createRequestBody。为了跑通本次新增测试,我在本地临时把这两个文件移出源码树,跑完后原样还原,它们不在本 PR 的 diff 中。是否需要单独修,请维护者定夺。:app:compileDebugKotlin通过,改动为纯逻辑分支且有单测覆盖判定函数。android-tests.yml、android-build.yml只在 push 到main或手动触发时运行,pr-check.yml的pull_request目标是development,所以本 PR 面向dev不会有自动检查,上面的本地结果是唯一验证依据。证据 / Evidence
根因链路的关键代码位置,便于 review 时对照:
app/src/main/assets/packages/extended_chat.js:377与:420,startService()与sendMessage(..., chatId, ...)的调用顺序core/tools/defaultTool/standard/StandardChatManagerTool.kt的startChatService,Intent extras 中无 chat idapi/chat/ChatRuntimeHolder.kt的registerChatSelectionSync(MAIN -> FLOATING)services/core/ChatHistoryDelegate.kt的ChatSelectionMode.LOCAL_ONLY初始化分支ui/floating/ui/window/screen/FloatingChatWindowScreen.kt,悬浮窗按chatCore.currentChatId渲染检查清单 / Checklist
dev;如目标为main,我已说明这是维护者发布同步 / The target branch isdevfor regular work; if it ismain, I explained why this is a maintainer-led release syncCandidate checks覆盖改动范围,并会处理技术失败项 /Candidate checkscovers the change scope and technical failures will be addressed