Skip to content

fix(chat): load delegated originals by exact turn before paging - #7971

Merged
huangruiteng merged 3 commits into
mainfrom
codex/delegation-http-20261103-052642
Nov 3, 2026
Merged

huangruiteng merged 3 commits into
mainfrom
codex/delegation-http-20261103-052642

Conversation

@loopx-agent

@loopx-agent loopx-agent commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

展开委派的“原对话”时,客户端原来先读完整个 Session 的冻结历史,再筛选一轮。历史越长,越容易把一次完整原文读取变成多次无关投影和 HTTP 往返。本次在现有历史接口增加可选 turn_id,先按准确的原 Turn 选出全部消息,再分页与投影;前端沿原入口读取并核验完整结果。

复用 manager-context 历史/展示 owner 和 native Chat HTTP 组合层。Python 改动留在既有日志读取与传输适配边界;没有新增控制面决策 owner、权限、缓存、设置或执行入口。选定历史读取也不再恢复同 Session 中其它正在执行的轮次;普通 Chat 刷新保留原恢复行为。

  • Base: loopx-project/loopx:main at 6f90e561ee99a1ef2e3db4e90c94e3c767990c58; tested head: 9151bb2b9348518c4d74acebaa36fd6102ab7196。
  • 完整正文、附件、collaboration carrier、return delivery 和 provider reply context 由原 owner 保留。严格日志读取、冻结前缀及全量组装后才展示的规则不变。
  • 不透明游标绑定 Session + Turn;响应回显 message_page.turn_id。跨来源游标、丢失/错误 scope、混入其它 Turn、损坏日志和后续页失败均拒绝展示残片,重新展开可重试。
  • 新分页客户端需要配套服务端;旧版无分页的完整快照仍可本地筛选。不带 selector 的历史请求保持既有响应。合并后需一起构建/交付客户端和服务端;本 PR 尚未合并或安装。

Rebase And Self-Repair

  • 已 rebase 到最新 main,解决 browser fixture 与最新 smoke 行为之间的冲突,保留 main 对真实 submit control 的等待。
  • chat_server.py 因精确 Turn 参数、历史读取不触发恢复、selector 传递而净增 4 行;按预算决定把既有审阅 ceiling 从 2035 调整为 2039,any / dict_any ceiling 不变。
  • 最新 main 已独立完成 render_canonical_todo_sections 的同域 helper 提取,因此本 PR 在 rebase 时丢弃了重复实现。
  • issue-fix-pr-lifecycle-smoke 改为从 canonical list_goal_todos 校验完成 evidence,不再假设已完成 prose 必须留在 Markdown 展示层。

验证与可复现比较

同一自有合成 fixture:2,429 条消息、63 条委派、两个接收方,目标原文为完整 24,054 UTF-8 字节、两条可见消息。顺序交错运行 3 对真实 HTTP 读取,所有目标消息及元数据逐项一致:

存储 原路径 → 选定 Turn 响应字节 三次 warm 样本中位耗时
SQLite 13 次 → 1 次 711,920 → 30,796 262.78ms → 13.25ms
File 13 次 → 1 次 711,920 → 30,796 315.15ms → 12.91ms

这是每次展开原对话的局部比较。普通主对话启动仍按其完整历史读取;上述数字不包含实际已安装 App、真实 provider 全链路、冷启动或 p95,也没有证明委派清单慢读已解决。比较脚本和原始运行资料保留为私有临时证据,不进入仓库;fixture 的 --earlier-messages 选项供相同工作负载复现。

  • npm run build 通过(TypeScript、Vite、Chat 打包;既有大 chunk 提示保留)。File / SQLite 的完整 smoke:delegation-search 均通过,包含真实 HTTP 精确 Turn、24KB 完整原文、跨页失败、scope 污染、取消/迟到/关闭重开、中英文和窄屏。
  • npm run smoke:conversation-history 通过,覆盖真实 HTTP/store、完整分页、取消、旧完整快照与零读侧写入。
  • 五个相关 Python 测试文件 248 passed,覆盖当前恢复隔离和元数据一致性断言。
  • 标准 loopx canary premerge --from-git-diff --git-diff-base origin/main:19 selected checks passed,manual holds 0。
  • Ruff、Python compile、diff hygiene、semantic-vocabulary 与 bilingual RFC check 通过。没有查询、轮询或等待 GitHub CI,符合当前 wait_for_ci=false policy。
  • 未安装或重启真实 App,未运行手机和真实 provider;未改 PostgreSQL authority/store,因此没有 PostgreSQL 集成收益声明。

页面证据

截图的原始视觉版本为 f71be82be39c3f1a9648d9d32e3b2b27255496f9;真实打包页面 + 自有 File/SQLite HTTP fixture,所有画面均为合成数据。当前 head 在该视觉契约和最新 main 上重新构建,并重新通过 File/SQLite 桌面、窄屏、错误 scope、损坏日志与恢复 smoke。旧候选实测每次展开从 13 次无 selector 请求变成 1 次精确请求;24KB 正文完整。该数字不冒充当前安装态延迟。

默认列表首屏:混合待回复/待结论/待送达、多接收方及分页。

默认委派列表

完整原文桌面视图(前后显示一致;变化在读取路径):

完整原文桌面

390px 窄屏末尾:完整正文结束标记及回复可见,横向溢出 0px。

窄屏完整原文末尾

严格日志失败时显示恢复提示且没有残片;恢复来源后重新展开,两条完整消息均可读。

原文失败及重试入口

@mergify

mergify Bot commented Nov 3, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @loopx-agent.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Nov 3, 2026

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Reviewer: actor_kind=model_agent; model=gpt-6.1-sol; provider=OpenAI; reasoning_effort=max; declaration_source=runtime_reported

Request changes conclusion (author-owned PR; GitHub blocks formal self-review)

动机 / Motivation

在长会话的委派清单中展开准确原对话的人。先读完整 Session 再筛选原 Turn,变为在同一 HTTP owner 内先选 Turn 再完整分页。File/SQLite 2,526 条合成消息、63 条委派中,完整 24,056 UTF-8 字节原文及两条可见消息保持,13 次 HTTP 读取变成 1 次。不认证已安装 App、冷启动/p95、模型效果、委派清单全部慢读或发送/回传工作已经兑现。新增模块增长未在同一 diff 更新既有 ceiling:chat_server.py 从2035增至2039,当前 ceiling 仍2035。

改动思路 / Approach

复用 manager-context 历史、Chat HTTP 和前端既有原文读取 owner;Python 仅在现有 IO/投影边界增加过滤,未新增控制面决策。现有分页 helper 绑定 Session+Turn,前端核对回显和每条消息的 Turn,完整组装后才显示。旧版完整快照仍可本地筛选;带分页但没有准确 scope 的中间版本拒绝读取,需要配套交付客户端与服务端。

具体改动 / Changes

完整审阅10文件 +161/-19,并先按 既有语义交办规格 的 A28 判断;spec_ref:docs/architecture/rfcs/capable-manager-semantic-handoff-v0.zh-CN.md,spec_revision:feea5a6e56066eef87889d470d7991922f9f00ec。本次 A28 的相关读取切片通过:63条委派、两个接收方、2,526条消息,File/SQLite 的目标原文及所有投影元数据与全历史筛选完全一致。24,056 UTF-8字节正文、600次长段落、结束标记及回复完整;原路径13次/708,568响应字节,选定Turn为1次/28,858字节。这是合成局部读取比较,不外推安装或p95收益。

当前332项Python测试通过,历史客户端真实HTTP smoke、TypeScript/Vite和Chat打包通过。实际Ego检查1440/390页面、搜索定位、键盘展开、错误scope/后续页失败0残片、真实日志损坏及重新展开恢复;File和SQLite均可读。原文滚动时固定页脚保留,窄屏横向溢出0。当前公开图证标注f71,独立当前构建另做了实际整页检查。

对主干的风险 / Risks

[P2] 在同一PR收口新增模块 ceiling 失败。 loopx/chat_server.py:932 的必要分支使模块从2035增至2039行,既有 loopx/canary/module_metric_baseline.json 仍为2035。实际 premerge 的 module_ceiling_colocation 失败;immutable base/head 配对确认基线没有该新增模块债务,当前有。按 预算决定流程,保留有意义的严格读取/恢复隔离语义,说明新增4行的作用,在同一diff更新既有审阅ceiling或做有parity的局部整理,再跑原命令。无需为这4行启动无关重构或删安全语义。

完整premerge未通过:上述新增直接门和相应ratchet债务需修复;两端原有 render_canonical_todo_sections oversized finding相同且magnitude_regressions=0。issue-fix-pr-lifecycle 在两端同一fixture子命令均exit1,具体根因未进一步归因,保留为失败而非通过。其余选中risk/profile和公开边界检查通过。初次测试命令中不存在的文件路径已更正,后续实际332项结果独立保留。未重复作者的strict-mypy结果为自己的通过。

wait_for_ci=false,CI未查询、轮询或等待。上述阻塞来自当前本地必需检查;远端CI未知未产生阻塞。没有权限、计费、调度或发送语义变更;客户端/服务端配套与全历史严格读取成本保留。

我的整体评价 / Verdict

读取优化与失败恢复有独立证据,仍需在本PR补齐新增模块预算决定,当前结论 REQUEST_CHANGES。现有page helper和前端reader复用适量;更大控制面迁移不属于本次边界。当前可交付切片是完整原文的读取优化;预算门仍需在本 PR 收口。合并、安装及完整父目标验收分别由原owner处理。

已检查当前源码的默认、展开、窄屏与失败恢复整页;合成数据和模拟边界已明确。不认证已安装 App、冷启动/p95、模型效果、委派清单全部慢读或发送/回传工作已经兑现。

English verdict: REQUEST_CHANGES f71be82. Complete scoped history and recovery pass independent local validation; settle the newly crossed module ceiling in this diff. CI was not consulted.

loopx-agent and others added 3 commits November 3, 2026 23:53
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng
huangruiteng force-pushed the codex/delegation-http-20261103-052642 branch from f71be82 to 9151bb2 Compare November 3, 2026 16:04
@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Nov 3, 2026

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewer: model_agent · GPT-5 · OpenAI · self_reported

动机 / Motivation

在个人工作台中展开委派原对话的主人,以及承载历史读取的 Chat HTTP、manager-context projection 与 File/SQLite store。

当前会先下载整个 Session 的历史,再在客户端筛出 source_turn_id。Session 越长,这个动作就会把越多无关 Turn 带过严格日志投影、分页和 HTTP;同一条原对话却仍只需要一个 Turn 的完整正文。同一个长历史 Session 中,旧路径先读取整个 Session 再筛选,新路径携带 turn_id 只投影并分页目标 Turn,最后仍组装完整可见消息。

本次沿既有历史入口传入可选 turn_id:服务端仍先做严格 Session 快照,但按准确 Turn 选出全部消息后才分页;客户端继续完整拼装这一 Turn,并核对服务端回显、每页 cursor 和每条消息的 Turn。File/SQLite 打包 smoke 均显示完整正文、附件、collaboration 和 return metadata,错误 Turn、外来消息、跨 scope cursor、损坏日志和后续页失败均拒绝残片。

这是一个完整的有界切片:普通主对话仍读取完整历史,不带 turn_id 的请求保持旧响应和旧恢复行为;不新增持久缓存、索引、权限、provider 或已安装 App 性能结论。它也不声称解决所有委派列表慢读。

改动思路 / Approach

入口仍是 OriginalRequest -> fetchChatSessionHistory -> GET /api/chat/sessions/<session>;权威数据仍是 File/SQLite ChatStore 中的 Session、Turn、严格 append journal 和已有 collaboration/return metadata。turn_id 只是历史选择器,不携带权限。

新路径没有第二套历史 owner,selector 只放在既有 projection/page 边界。project_chat_session_snapshot 继续读取同一份严格 Session 快照,只在既有 page_chat_messages 前筛出目标 Turn;page_chat_messages 的 opaque cursor 在 scoped read 中绑定 Session + Turn。HTTP composition root 负责拒绝缺少 page limit、重复或空 selector 的请求,并在历史读取时跳过 recover_exited_turn,避免展开旧对话顺带恢复同 Session 的另一执行。

客户端只在全部页都满足 message_page.turn_id、消息 turn_id、offset、total、digest 和 completeness 后返回 snapshot;旧服务端返回的完整无分页快照仍可本地筛选。交付精确 Turn 原对话读取和失败恢复,不建设通用历史索引或 provider 迁移。

具体改动 / Changes

相对 6f90e561ee99a1ef2e3db4e90c94e3c767990c58,当前 head 修改 12 个文件,+162/-21:3 个运行时 owner、3 个前端/reader 文件、1 个协议文档、fixture/browser/Python 回归,以及 2 个同 diff 门禁收口。没有新增持久字段、配置、后台 worker 或权限入口。

规格引用:docs/architecture/rfcs/capable-manager-semantic-handoff-v0.zh-CN.md,revision 6f90e561ee99a1ef2e3db4e90c94e3c767990c58。其中 A28 要求长详情、分页、快照变化及历史 Turn 冲突下全部获准原文可达、不混快照、不藏记录且不绕来源门;该条在当前 head 标记为 implemented,由精确 Turn projection、Session+Turn cursor、客户端完整性验证和 File/SQLite 失败恢复 smoke 覆盖。

关键代码讲解

  • chat_history.py:12 的 page_chat_messages 复用原有 opaque cursor,在 scoped read 中把 source identity 从 Session 扩展为 [Session, Turn];跨 scope 或 digest 变化直接拒绝,并在 message_page 回显 Turn。
  • roundtrip.py:336 的 project_chat_session_snapshot 要求 selector 与分页同时出现,先验证 Turn 属于该 Session,再从严格快照筛选消息后分页;完整消息、附件和 return-delivery 投影仍由原 owner 生成。
  • chat_server.py:922 的 _session_snapshot 接受可选 turn_id,拒绝不完整的参数组合;只有历史 scoped read 跳过 exited-Turn recovery,普通 Chat refresh 仍执行原恢复路径。
  • chat.ts:976 的 fetchChatSessionHistory 逐页核对 message_page.turn_id、每条消息的 Turn、offset/total/digest 和 cursor 不重复,任何残片都不会返回给 UI;无分页的旧完整快照仍兼容。
  • conversation-requests.tsx:161 的 OriginalRequest 只把已有的 source_turn_id 传给 reader,仍保留 abort、active guard 和现有可见内容渲染。

同 diff 还处理了两个实际门禁结果:chat_server.py 为 query 分支、恢复隔离和 selector 传递净增 4 行,因此把审阅 ceiling 从 2035 调到 2039,未新增 any/dict_any 债;issue-fix-pr-lifecycle-smoke 改为从 canonical list_goal_todos 校验完成 evidence,而不是假设展示层 Markdown 仍携带已完成 prose。后者是当前 main 已有 contract 的 smoke 修复,不改变产品代码。

对主干的风险 / Risks

最强风险是错误 Turn 或残片被展示成原对话。当前实现从 HTTP 参数、Turn 归属、Session+Turn cursor、页面 digest、每条消息 Turn 到完整分页逐层拒绝;新测试覆盖 wrong-turn echo、foreign message、跨 scope cursor、损坏日志和后续页 503,浏览器均显示错误入口而不是部分正文。

第二个风险是历史读取意外恢复同 Session 的另一活跃 Turn。turn_id 路径明确跳过 recover_exited_turn,同时断言 unscoped Chat refresh 仍调用原恢复;File/SQLite smoke 也验证读取期间没有新 Turn 或 provider 写入副作用。错误 choice 仍返回现有 400/404/503,可由重新展开恢复。

兼容性风险是 scoped client 必须与支持该字段的服务端一起交付。当前采用 co-deployed additive contract:旧请求字段、旧完整 snapshot 和普通历史路径保持;带分页却没有准确 scope 的中间响应会被客户端拒绝,而不是静默本地兜底。

当前验证:

  • pytest tests/test_chat_conversation_bindings.py tests/test_manager_context_roundtrip.py tests/test_chat_process_recovery.py tests/test_chat_agent_model_http.py tests/test_chat_transport_composition.py -q:248 passed。
  • npm run build:TypeScript、Vite 和 Chat bundle PASS;仅保留既有大 chunk warning。
  • npm run smoke:conversation-history:PASS,覆盖真实 HTTP/store、完整分页、取消、旧完整快照与零读侧写入。
  • LOOPX_REQUEST_STORAGE=sqlite|file npm run smoke:delegation-search:两者 PASS,覆盖完整 24KB 原文、错误 scope、损坏日志、重试、桌面和 390px。
  • 标准 premerge:19 selected checks PASS,manual holds 0;Ruff、py_compile、diff hygiene、semantic-vocabulary 和 bilingual RFC check PASS。

语义与 CI 对齐

该 PR 复用既有 loopx_chat_message_page_v1、Session/Turn 词汇、strict snapshot 和 recovery admission,只在同一 page contract 上增加可选 selector,没有创建新 authority、执行生命周期或共享决策词汇。没有查询或等待 GitHub CI;managed policy 为 wait_for_ci=false。未安装/重启真实 App,也未运行手机和真实 provider;这是剩余的端到端证据缺口。

我的整体评价 / Verdict

APPROVE。 当前精确 head 没有阻塞 finding。长期任务维度改善:展开原对话不再反复读取和投影同一 Session 中与源 Turn 无关的全部历史。用户体验维度改善:长会话中的原文更快到达,同时完整正文、附件、错误与恢复入口不变;视觉层级和文案没有变化。

代码量集中在既有 owner 和独立负例,生产机制只有一个可选 selector、一个 scoped cursor identity 和一个 recovery 条件;没有需要在本 PR 新建索引或缓存。兼容性由 co-deployed scoped contract 加旧 unscoped/完整 snapshot parity 覆盖。剩余风险是安装态、手机和真实 provider 的延迟/采用尚未验证,不能把合成 File/SQLite 结果外推为生产 p95。

English verdict: APPROVE — head 9151bb2b9348518c4d74acebaa36fd6102ab7196 reads only the selected historical Turn before paging while preserving complete content, cursor scope, ordinary history recovery, legacy snapshot behavior and File/SQLite failure recovery. No blocking finding remains; installed-App/mobile/real-provider latency remains unverified.

@huangruiteng
huangruiteng merged commit d769d13 into main Nov 3, 2026
27 of 50 checks passed
@huangruiteng
huangruiteng deleted the codex/delegation-http-20261103-052642 branch November 3, 2026 16:23
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.

2 participants