Repository navigation
feat(chat): find original messages in loaded conversations - #8676
steven-kid wants to merge 2 commits into
Conversation
Signed-off-by: Yuchao Wang <stevenkid404@gmail.com>
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
评审提交 d748ab8b6c9953ea7519b74ab6aa783bcfc81d80,对照当前主干 eba8a7f95f54fe09cb3dcc28bb1f55443898bbed。十个变更路径的 merge base 为 09886ba7afec07dba709229cc9dfb7fabf15d03a。
[P2] 重新定位唯一命中时,键盘和箭头都不会跳回。 在长对话中搜索只有一条匹配的早期消息。第一次成功定位后滚到最新消息,再按 Enter。也可先手动折叠唯一命中的长答复,再按下一条或 Shift+Enter。 界面仍显示 1 / 1 且按钮可用,Enter 后目标仍在视口之外。长答复在 1200 和 390 像素下保持折叠,匹配的尾段仍不可读。清空再输入同一查询会重新展开。 在现有阅读组件中区分持续选中的消息与一次显式导航动作。即使消息身份相同,也让按键或箭头请求展开并滚到原消息。 跳转逻辑
动机 / Motivation
在管家或 Goal 对话中回找早期要求、答复和验收文字的读者。 主干可展开长回复,折叠时浏览器查找无法触及正文。读者需要逐条打开早期记录,才能确认一段要求出自哪条消息。 候选能从当前已加载文本定位第一次命中,展开原答复,并在旧页补齐后保留同一个 Session 和 Message。 本轮覆盖打包的本地 Chat、合成会话和真实历史 GET。已安装 WebView、Lark 与附件内容待各自入口验证。
改动思路 / Approach
当前 PR 只在打包 Chat 中查找并定位已加载的消息,不需要新增 API 或搜索存储。 查找复用原历史请求、时间顺序和 Session/Message 键。查找只筛选当前已加载的消息,计数以消息为单位。将一次跳转动作交给现有消息阅读组件,保留已加载搜索、持久消息身份和历史请求三个现有职责。 旧页补载可以改变命中的相对位置,原身份仍可继续选中。对同一消息的第二次跳转也应传递给已有的滚动和展开逻辑。 时间线阅读入口
具体改动 / Changes
关键代码讲解
conversationMessageKey 复用来源身份,ConversationFind.move 按匹配总数循环。唯一命中时算出的索引保持原值。时间线只在选择键变化后滚动,HistoricalMessageText 只在 focused 变化后打开。测试使用现有 Chat HTTP 和一次性 store,并新增打包浏览器入口。工作流把入口接到现有打包分片,用户指南补充加载范围、快捷键和两张合成截图。 查找组件 原文展开 打包验证
按当前主干的 App 验收矩阵,Scope 已实现,历史从 16 条补至 25 条时仍保留原 Session/Message。Authority 已实现,同文本的另一会话排除,查找前后 HTTP 请求记录相同,原 store 不变,Turn 为零。Result 仍缺同一命中的再次跳转。Packaging 的桌面和窄屏布局可用,已启用的键盘导航在上述负例失败。PR 说明引用的 roadmap 提供产品方向,本次判定采用具体 App 验收行。 App 验收矩阵 产品路线图
对主干的风险 / Risks
主干用同样的合成历史读到 25 条消息,尚无应用内 Find。候选首次选中并展开原答复。另用短命中排除长文渲染影响,滚离唯一命中后 Enter 仍未把原消息带回视口。扩展现有 conversation-find browser smoke。搜索唯一旧消息,滚走后按 Enter 检查实际视口,再折叠并用箭头或 Shift+Enter 检查原文恢复。同时覆盖历史补载与零写入。 用户指南
语义与 CI 对齐
打包双语 smoke、TypeScript、构建与来源校验、fixture lint、22 项工作流检查均通过。Standard premerge 五项直接、十二项选中自动检查无失败,仍有两项人工复核。真实浏览器的重复定位负例保持失败。托管 CI 未查询。
我的整体评价 / Verdict
请求修改。已加载文本搜索减少回找原资料的成本,补载与读权限沿用原有边界。请让重复导航也能展开原消息并恢复实际阅读位置。相关状态可留在现有前端阅读组件,使用原消息身份与本次导航动作即可。1200 × 900 和 390 × 900 中,搜索栏在滚动时可用,长回复保持中文与英文换行,首个命中可展开,页面没有横向溢出。首次定位显示消息顶部,测试用的尾段需继续滚动。手动折叠后再次导航在两种宽度都仍显示原文节选。 本轮覆盖打包的本地 Chat、合成会话和真实历史 GET。已安装 WebView、Lark 与附件内容待各自入口验证。
English verdict: REQUEST_CHANGES. On d748ab8, explicit navigation to the sole match cannot bring it back into view or reopen its original text after collapse.
| trigger.current?.focus(); | ||
| } | ||
| function move(offset: number) { | ||
| if (matches.length) setSelected(conversationMessageKey(matches[(index + offset + matches.length) % matches.length])); |
There was a problem hiding this comment.
[P2] 重新定位唯一命中时,键盘和箭头都不会跳回。 在长对话中搜索只有一条匹配的早期消息。第一次成功定位后滚到最新消息,再按 Enter。也可先手动折叠唯一命中的长答复,再按下一条或 Shift+Enter。 界面仍显示 1 / 1 且按钮可用,Enter 后目标仍在视口之外。长答复在 1200 和 390 像素下保持折叠,匹配的尾段仍不可读。清空再输入同一查询会重新展开。 在现有阅读组件中区分持续选中的消息与一次显式导航动作。即使消息身份相同,也让按键或箭头请求展开并滚到原消息。 扩展现有 conversation-find browser smoke。搜索唯一旧消息,滚走后按 Enter 检查实际视口,再折叠并用箭头或 Shift+Enter 检查原文恢复。同时覆盖历史补载与零写入。
There was a problem hiding this comment.
已在 a68e4df 修复。稳定的消息身份继续负责选择和历史补载;每次显式 Enter / Shift+Enter / 箭头导航另产生一次导航请求,即使命中 ID 不变,也会先展开原文再滚回目标,不必清空查询。
独立复现:旧 head d748ab8 的新增测试在唯一旧短消息滚走后按 Enter 时超时;旧精确合并版本的隔离折叠测试也在按箭头后无法重新显示原文尾段。修复后现有 conversation-find browser smoke 全部通过,覆盖中英文、1200/390 宽度、唯一短消息滚回、长答复折叠后箭头/Shift+Enter 再展开、历史补载身份保持、原 store 不变及零 Turn。
另通过完整 Chat 构建(TypeScript/Vite/manifest)、现有 451 条消息分页及绑定恢复浏览器回归、CSS token 检查和 git diff --check。没有扩入此前独立归因的上游 CI 问题;新提交 CI 尚待结果。
Signed-off-by: Yuchao Wang <stevenkid404@gmail.com>
Long conversations can hide an earlier requirement or result behind folded replies. Browser Find cannot reliably reach that text. Find in conversation now searches the original loaded message text, opens matching historical answers and moves between messages without leaving the conversation or sending work.
Written by: OpenAI Codex.
Implemented against
Specification: the bounded reader behavior described above, informed by
docs/architecture/rfcs/loopx-overall-roadmap-v0.mdS2 (App conversation/readback) at09886ba7afec07dba709229cc9dfb7fabf15d03a. This supports C8's readable-result direction without claiming controller/worker runtime qualification.channel-timeline.tsx, existing history ownerconversation-find.tsxconversation-find.cssScope: complete within this bounded reader. Server-side search, attachment/tool search, Lark controls and the broader C1/controller-worker work remain outside it. Open work #8266, #8484 and #8670 addresses different execution/return boundaries; existing delegation and Task search are retained. No new task tracker or parallel authority is introduced.
Reuse: the existing conversation history, original message identity, full-answer renderer and read-position callback remain the owners. Simplification: one local reader component; no search store, indexing service, API or new semantic vocabulary.
Validation
09886ba7afec07dba709229cc9dfb7fabf15d03ad748ab8b6c9953ea7519b74ab6aa783bcfc81d80(identical final sources tested before commit).python scripts/chat_bundle.py buildnpm run smoke:conversation-findnode smoke/conversation-return-browser-smoke.mjs --pagination-onlynode scripts/check-css-custom-properties.mjs dashboardpython -m unittest discover -s scripts/ci -p 'test_*.py'git diff --checkBaseline qualification: on a clean detached worktree at
09886ba7afec07dba709229cc9dfb7fabf15d03a,loopx canary premerge --changed-file .github/workflows/python-tests.yml --git-diff-base 09886ba7afec07dba709229cc9dfb7fabf15d03a --timeout-seconds 300 --format jsonreproduced the samefixture cleanup failed: managed runtime still exitingresult. The selected CLI script returned 0 and printed success on both baseline and candidate (91.548s and 82.873s respectively); its standalone baseline run also passed. Both CLI comparison reference variables were pinned to that baseline. This establishes a pre-existing local canary cleanup limitation, not successful cleanup or a green merge gate. The frontend change does not repair that separate lifecycle issue.Initial browser checks caught mismatched test labels and asynchronous selection readback; these were corrected and the final packaged scenarios passed. Initial local setup lacked the headless browser, which was installed before qualification. An initial pytest command named nonexistent paths and ran no tests; it is not counted as validation.
Visual evidence
Packaged browser with synthetic messages, tested revision above. The original folded answer remains readable; the selected instruction has a visible outline. Desktop retains surrounding context; the narrow layout gives the input its own row. These images are also used by the maintained workspace user guide, rather than retained as a standalone execution capture pack.
Release Artifacts follow-up (2026-11-13)
Run
43387985538, attempt 1, failed in browser partition 2/3 atgoal-hierarchy.mjs:103,126:research_lens survives workspace navigation, actualnull, expectedgraph. The tested PR head remainsd748ab8b6c9953ea7519b74ab6aa783bcfc81d80.Independent comparison in clean detached worktrees:
40c12f37e961b6ce5b3cd20722992ef647f1a568: packaged build passed; isolatedgoal-hierarchyfailed with the same assertion and values.eba8a7f95f54fe09cb3dcc28bb1f55443898bbed: packaged build passed; the same isolated scenario failed with the same assertion and values.python scripts/chat_bundle.py build, thenLOOPX_PERSONAL_WORKSPACE_PACKAGED=1 LOOPX_PERSONAL_WORKSPACE_SCENARIO=goal-hierarchy node examples/personal-workspace-browser-smoke.mjswith the same Python/Playwright dependencies, distinct local ports and Node 24.19.0. This qualifies locally built packaged assets over the production Chat server, not CI's installed-wheel environment or its Node 24.22.2.The fixture seeds
research_goal=calibration, selectsresearch, then expects all research parameters to remain. Upstream commit09886ba7afec07dba709229cc9dfb7fabf15d03a(#8650) changedselectGoalto preserve research parameters only when(research_goal ?? goalId) === destinationGoalId. Selectingresearchtherefore clears the calibration bookmark. The fixture and navigation owner are identical between the exact base and merge. This is a reproduced upstream test/behavior contract conflict, independent of conversation Find; resolving the intended cross-Goal bookmark semantics belongs with that owner. No unrelated navigation change or CI rerun was made here.Other newly reported Python Tests failures remain unqualified by this bounded investigation; this evidence does not establish their cause or a green merge gate.
Python Tests follow-up: independent baseline checks
Run
43387985694remains attempt 1 at the same head. The two browser partition-2 failures report the same already-qualified hierarchy assertion above; no duplicate full-suite rerun was made.For the remaining two reported failures, both exact detached worktrees (
40c12f37e961b6ce5b3cd20722992ef647f1a568and clean upstreameba8a7f95f54fe09cb3dcc28bb1f55443898bbed) independently reproduce:python -m mypy(mypy 1.20.2):loopx/capabilities/decision_context/runtime.py:207: Returning Any from function declared to return ContextProvider | None [no-any-return], one error among 17 checked source files. The package export forbuild_context_providerresolves through__getattr__ -> Any, introduced by upstream31ff0569843390413330e67be67f570b2d03650b(fix(runtime): defer unselected context and retirement implementations #8671); the underlying factory has a typed return. These owners are identical between baseline and candidate.node --experimental-strip-types apps/presentation/dashboard/smoke/delegation-read-cancel.ts, using each worktree's previously verified packaged assets and real disposable owners: both fail at line 214 with actual write requests[]versus four expectedPOST /api/chat/sessionsmanagerresume_latestrequests. Both reach the final File-reader request assertion; neither reaches SQLite or subsequent store assertions. This establishes the same pre-existing baseline mismatch, but does not establish which recovery guard suppresses the POSTs or whether the product behavior or fixture expectation should change. No success claim is made for this smoke. Node was 24.19.0 locally, versus CI's reported 24.22.2.These two failures are independently qualified as present without this patch; no unrelated backend/type/navigation changes, new commits or CI reruns were made. Remaining pending jobs are not qualified by these comparisons.