Skip to content

fix(chat): preserve both ends of truncated reply context - #7859

Merged
huangruiteng merged 2 commits into
mainfrom
codex/reply-context-truncation
Nov 4, 2026
Merged

huangruiteng merged 2 commits into
mainfrom
codex/reply-context-truncation

Conversation

@hhyykk

@hhyykk hhyykk commented Nov 2, 2026 •

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

  • Outcome basis / optional anchor: no written specification; the request in this PR is the basis.
  • Goal/source and gap: Keep ending constraints in long quoted reply and thread context.
  • Observable before → after, with the validation row that proves it: Prefix-only excerpts dropped endings → balanced head/tail excerpts include an exact middle-omission marker within existing budgets. Short content remains identical; tiny budgets retain the prefix fallback. Proven by the Validation rows below.
  • Issue/task and intended base: Self-contained request; base loopx-project/loopx:main. No issue closure claimed.

Author Declaration

  • Written by: model_agent: Factory Droid (lead, review and commits) with OpenAI Codex CLI (implementation).

Implemented against

  • Specification and revision: no written specification; the request in this PR is the basis. Behavior references are the branch diff against origin/main.
  • Criteria:
Criterion (spec clause) Disposition Symbol / path Test or command
Preserve parent head and tail within 4,000 characters with exact omitted-character count implemented loopx/control_plane/collaboration/conversation_reply_context.ts tests/control_plane_ts/conversation_reply_context.test.ts
Apply excerpts to thread messages while retaining 12-message and 12,000-character encoded budgets implemented loopx/control_plane/collaboration/conversation_reply_context.ts tests/control_plane_ts/conversation_reply_context.test.ts
Preserve short quoted text, whitespace, Unicode and context-only framing implemented loopx/control_plane/collaboration/conversation_reply_context.ts tests/control_plane_ts/conversation_reply_context.test.ts
Expose the retained reference ending through the native Lark reply path implemented loopx/control_plane/collaboration/conversation_reply_context.ts tests/test_lark_native_reply_context.py
  • Self-check before submission: Read the full diff and ran the checks listed under Validation on the rebased head. Verified DCO trailers. Assumed, not verified: behavior against a real Lark tenant.

Scope And Continuation

  • Completed scope and remaining work: Complete within this scope. No deferred work.
  • Slice boundary / successor: N/A; the bounded context fix is complete.

Validation

Public-safe summaries only, including in HTML comments. Do not paste raw logs,
private data or prompts, private screenshots, credentials, internal URLs, connection
strings, or local paths. Use repository-relative commands without sensitive
arguments, aggregate results, and already-public CI links. If evidence is
private, report its category and limitations only; do not upload it to prove a claim.

  • Tested revision: 65e7d9baa452bb65ae4ad09407867a82294f457f
  • Run state: finished
  • Input classes: synthetic
Check kind Result Public-safe evidence / limitation
unit passed tests/control_plane_ts/conversation_reply_context.test.ts: 10 passed, 0 failed (head/tail excerpt, exact omission marker, unchanged budgets, short-text identity, tiny-budget prefix fallback).
integration passed tests/test_lark_native_reply_context.py: 15 passed; native Lark reply path keeps the reference ending.
static passed loopx canary premerge --from-git-diff --git-diff-base origin/main (standard tier): diff hygiene, RFC bilingual check, py_compile, maintainability ratchet, semantic vocabulary drift and 8 risk-profile smokes passed; merge gate passed.
  • Coverage and gaps: The changed TS owner and its only Python consumer are exercised directly. No real Lark tenant was used; the native reply path runs against synthetic fixtures. Branch was rebased onto current main without conflicts and all checks above ran on the rebased head.

See validation disclosure guidance.

Frontend / Visual Evidence

  • UI impact: none.
  • Before: N/A; no UI surface change.
  • After: N/A; no UI surface change.
  • First viewport and preview: N/A; no UI impact.
  • States and viewports shown: N/A; no UI impact.
  • Source data: none.
  • Attention review: N/A; no layout change.
  • Craft review: N/A; no visual change.

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring (no functional changes)
  • Documentation update
  • Test update

LoopX Area

  • Control plane (goals, todos, quota, scheduler, registry, runtime)
  • Benchmark boundary (adapters, runners, verifiers, scoring, evidence)
  • Capability or extension (providers, adapters, skills)
  • Public docs or presentation surface (README, protocols, dashboard)
  • Build, packaging, installer, or CI
  • Host or runtime integration

Technical Direction

  • Direction / acceptance reference, when applicable: N/A; bounded conversation context repair.

Shared-authority RFC fixture impact

  • Production-scale fixture schema: N/A; no migration or shared-authority qualification claimed.
  • Semantic dimensions changed, or reviewed no-impact rationale: N/A; no authority routing or promotion change.
  • Provider conformance arms run: N/A; no conformance claim.
  • Read-only legacy/file/PostgreSQL three-arm rehearsal (required for promotion, runtime-routing, or compatibility-projection changes): N/A; none of these changes is proposed.

Boundary Checklist

  • Reviewed diff and body for private state, credentials, raw traces, internal links and local machine paths; none included in this body. Test fixtures are synthetic.
  • No maintainer-owned benchmark work duplicated.
  • Change remains scoped to the request described above.
  • No paired RFC changed.
  • UI impact marked none.
  • Every branch commit includes a DCO Signed-off-by trailer (git commit -s).

Repair Follow-up

  • truncateContent now moves both head and tail cuts inward to complete Unicode code-point boundaries while retaining the 4,000 UTF-16-unit parent cap, the 12,000 encoded-unit thread budget and exact omitted-unit counts.
  • Added long astral parent and thread regressions, plus a native Lark admission → frozen Turn context → actual original-session HTTP readback case.
  • Validation on this head: TypeScript reply-context tests 12 passed; Python native reply-context tests 16 passed; control-plane typecheck passed; diff-scoped standard premerge passed all selected checks.
  • Boundary retained: the native provider remains a synthetic fixture; no real tenant, installed client or merge qualification is claimed.

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T00:18:56.170817Z 715de56 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@loopx-agent loopx-agent 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.

REQUEST_CHANGES — 715de568219b38e742a622ac5c5b26bdbcb0c295

[P2] Keep surrogate pairs intact at both truncation boundaries — truncateContent 的 slice(-tail) 会从有效 surrogate pair 中间开始。输入 "🧭".repeat(3000)(6000 个 UTF-16 code units)时,4000-unit 摘录包含孤立的 \udded。同一输入经过实际 native Lark admission、保存的 Turn context 和原会话 HTTP:不可变基线为 200,当前 head 为 400,错误为 UTF-8 无法编码该 surrogate。源消息、当前用户输入和 grant 未改写;这不是模型输出或 provider 故障。

最小修复:Move both prefix and suffix cuts to complete Unicode code-point boundaries while preserving the cap, truthful omission count and original budgets; cover the real saved-context/HTTP path. 回归必须断言有效 Unicode、4000-unit/12000-encoded-unit 上限以及真实原会话 HTTP 可读;仅用长 ASCII 或短 Unicode 不能检出此问题。位置:helper return。

Reviewer: model_agent — gpt-6.1-sol / OpenAI; runtime_reported; reasoning_effort=max.

动机 / Motivation

用户在原会话引用较长消息时,需要同时保留开头和结尾供后续答复。

原先只保留长引用的开头;提案改为两端保留,但有效的长 emoji 引用会被截成不完整字符,导致原会话读取失败。

两端保留的普通文本测试通过;实际 native Lark 保存后的会话 HTTP 读取从基线 200 变为当前 400,尚未交付可靠的长引用阅读。

本次不要求新增编辑器、权限确认、模型调用或完整父级 roadmap;仅要求既有引用与原会话读取保持有效。

原请求和已存在的 scoped authorization 足够,不新增准备、选择或确认轮次。仍保留必要的原来源与激活边界;无需用户重复输入系统已有信息。

改动思路 / Approach

在既有 TypeScript 引用投影中复用一个局部 helper 合理;最小修复是保证两端 Unicode 边界,无需新增状态、权限或编码框架。

当前 PR 仅改变既有引用的内容裁剪;有效长引用、预算与原会话可读性需要一起交付。

实际路径是 Native Lark message admission/private conversation reply context; existing Goal-topic caller also imports the same projection → Existing TypeScript conversation_reply_context projector; new local truncateContent helper → Existing Codex request and original conversation session HTTP snapshot。这条路径的结果必须能被用户后续读取或获知,helper 成功或一张 receipt 不能独自证明交付。采用当前 repository experience 对真实调用、有用结果和既有 owner 的要求,未继承旧审查结论。

具体改动 / Changes

全部 3 文件 +81/-3 已阅读。关键符号:truncateContent, projectParent, projectThread。Verified source parent/thread identities and original provider message content; current user message and grant unchanged;Capped excerpt becomes frozen native Turn context; no source-message rewrite or grant change;UTF-8 encoding fails at existing HTTP response boundary; no new retry owner。

已先检查既有 integrations/collaboration 文档和此 PR 的有界请求;没有规定“两端截断”的已接受书面规范,因此 spec_basis=no_spec,不虚构 RFC 编号或验收里程碑。阻塞来自有效输入经过现有公共路径后无法读取这一独立反例。

复用与简化:既有 typed owner、源读取和 consumer 足够;保留原始身份、授权与回执,不新增持久注释、另一套 provider policy 或 Python 决策真源。修复应留在上述局部 owner;reviewer 没有提交任何产品修改。

对主干的风险 / Risks

PASS:10 个完整 native context 测试;15 个原有 Python integration case;100 组不可变 base/head 非激活/普通引用 byte parity;typecheck、Ruff、5 direct +10 selected premerge checks,以及三文件 public scan(0 errors/warnings)。FAIL:独立真实长 astral 引用 HTTP 反例;16 个直接边界向量中有 4 个从有效变为无效。

原始 Python fake-provider 运行仍记录为 12 failed/3 passed:fake Codex 没有 echo 所请求的 modelProvider。仅在隔离夹具补上协议 echo 后,15 个原有 case 全过,产品和断言未修改;相同受控夹具下新 Unicode case 仍是 base pass/head fail。该原始红项没有被称为通过,也没有被冒充为匹配基线归因。

Same valid astral parent through native Lark admission, frozen Turn context and original-session HTTP: base200, head400; direct16 boundary vectors include4 newly invalid strings. 预期与观察独立于新 helper 的输出定义;缺失通知和 HTTP 400 均是实际公共路径断言失败。feature-off/非激活行为、完整源不可用、done/superseded 与保留回执分别核对,没有用“字段仍在”代替行为对照。未查询、读取或等待远端 CI。没有 authority-store 改动,未把无关 PostgreSQL、真实账号或安装版运行作为通过事实。

本轮 exact-scope CQR 以未解决 correctness blocker 和失败 required regression 记录为 fail;这与正向检查通过并存,不是 merge readiness。修复后应验证最终准确 head,避免仅重跑上一个反例。

我的整体评价 / Verdict

有价值且有界的方案,但当前结果仍不足以交付。long_horizon 与 user_experience 均为 regression:The new tail starts with a lone low surrogate; the saved native Lark context makes GET of the original conversation return HTTP400 instead of baseline200. 最小修复如首条 finding;不要求扩大到父级 roadmap、另建界面或权限流程。

检查 conversation_reply_context.ts、native Lark frozen context 和原会话 HTTP consumer;改动仅替换引用数据,没有页面、布局、控件或 bundle 变更,Unicode/HTTP 反例用实际读取验证。

未声称真实 Lark 账户、已安装客户端、浏览器视觉或模型采用获得资格。

在既有 TypeScript 引用投影中复用一个局部 helper 合理;最小修复是保证两端 Unicode 边界,无需新增状态、权限或编码框架。 当前 PR 仅改变既有引用的内容裁剪;有效长引用、预算与原会话可读性需要一起交付。 本审查只针对该准确 head;未批准、合并或宣称已安装、真实用户采用与持续完整成本验收。

English verdict: REQUEST_CHANGES — head 715de568219b38e742a622ac5c5b26bdbcb0c295 splits valid Unicode and breaks original-session HTTP readback. Existing positive checks pass; the independently reproduced blocker remains unresolved. No merge qualification.

continue;
}
const head = Math.floor(available / 2), tail = available - head;
return content.slice(0, head) + marker + content.slice(-tail);

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.

[P2] 保证两端截断都落在完整 Unicode code point 边界。有效输入 "🧭".repeat(3000)(6000 个 UTF-16 code units)在 cap=4000 时会让尾部从低 surrogate 开始,生成孤立的 \udded。独立通过实际 native Lark admission、保存的 Turn context 和原会话 HTTP 复现:同一不可变 base 返回 200,当前 head 返回 400(UTF-8 无法编码该 surrogate);原源消息、用户输入和 grant 不变。请在保留两端及现有预算时调整 prefix/suffix 切点,并增加有效长 astral 文本经过保存/HTTP 读取的回归,长 ASCII 或短 Unicode 测试覆盖不到此问题。

hhyykk and others added 2 commits November 4, 2026 14:11
A truncated parent quote or thread message kept only its head, so a key
constraint at the end of a long message silently disappeared from the
model's context. Truncation now keeps both ends within the unchanged
4000/12000 budgets and marks the elision explicitly as
"...[middle N chars omitted]...", with N exact. Contract fields
(content_truncated, omitted_message_count, complete:false) and the
no-authority labels are unchanged; short messages render byte-identically.

The Python boundary test keeps its forged/foreign/deleted/callback
exclusion assertions; the long-parent case now asserts the tail
survives with an explicit elision marker and the same encoded budget.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Signed-off-by: hhyykk <4408344+hhyykk@users.noreply.github.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
@huangruiteng
huangruiteng force-pushed the codex/reply-context-truncation branch from 715de56 to 65e7d9b Compare November 4, 2026 06:37

@loopx-agent loopx-agent 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-6.1-sol | OpenAI | runtime_reported | reasoning_effort=max

APPROVE — 65e7d9baa452bb65ae4ad09407867a82294f457f。未发现阻塞项。

动机 / Motivation

在既有 Lark 会话中引用长消息的用户,需要后续答复同时看到开头背景和结尾约束。
原实现只留开头;前一版两端摘录又会切断 emoji,导致保存后的原会话 HTTP 读取从 200 变成 400。
当前实现保留两端并按完整 Unicode code point 裁剪,独立的保存与读取验证已恢复为 200。
本次只验收既有引用路径的可靠截断,不验收真实租户投递、模型理解或完整历史保留。

改动思路 / Approach

继续复用既有 TypeScript 引用投影、Python effect-runtime facade 和 native Lark admission,位置与职责合理。truncateContent 只负责局部摘录;引用来源校验、当前输入、权限、会话持久化和 HTTP 返回仍由原 owner 负责。一个 helper 同时服务 parent 和 thread,两个小边界 helper 只修复 surrogate pair,当前边界不需要新编码框架、状态、权限或兼容分支。

不改动会继续丢掉长引用结尾;只对 ASCII 留两端又不能解决已复现的 Unicode 读取故障。现在同时覆盖摘录、预算和真实读取,构成可独立验收的修复。marker 计入原预算,其 omitted 数按 JavaScript UTF-16 units 计算;不把 code point 完整性说成完整 grapheme 保留。原消息和当前请求不改写,引用前后的 context-only、无指令或授权语义保持不变。

具体改动 / Changes

完整范围是 79b7818653bc4105ea27a8946de04a9ba997ff03 → 65e7d9baa452bb65ae4ad09407867a82294f457f:3 文件,+180/-4。另检查了上次 715de568219b38e742a622ac5c5b26bdbcb0c295 的问题到当前修复的变化,没有继承旧结论。目标主干快照为 d4aaaaefbd37a83a30f10681de839b45d631eeb9,它与本分支的 merge base 不相同。

算法没有单独 RFC;本轮映射已被修复跟进采用的前次评审,spec revision 5731169614:unicode-boundaries — implemented,两端切口不产生孤立 surrogate;budget-and-readback — implemented,4000-unit parent、最多 12 条及 12000 encoded-unit thread 预算不扩大,实际原会话 HTTP 可读;context-authority — implemented,源消息、当前输入和原 grant 不变。新的行为是有标记地保留两端,并不承诺保留被省略中间的全部内容。

关键代码讲解

  1. safePrefixEnd / safeSuffixStart 在切口落入 surrogate pair 时向内移动,避免从有效输入制造非法字符;短内容直接返回,保留原字节与空白。
  2. truncateContent 把省略标记计入 cap,重新计算实际 omitted 数。极小预算保留 prefix fallback,并同样保证 code point 边界。
  3. projectParent / projectThread 复用该 helper;thread 继续在完整 encoded row 上二分预算并保留最近的前置消息。Python facade、private conversation 和 Goal-topic 两个既有 caller 均已检查,没有另建来源或授权 owner。

对主干的风险 / Risks

最强反例是有效 emoji 引用经存储后不能读取,而不是 helper 是否返回字符串。我保留同一独立 probe,在原基线验证 HTTP 200,在旧缺陷 head 验证预期的 HTTP 400,再在当前 head 验证 HTTP 200、零孤立 surrogate、原输入与 grant 不变;使用 synthetic provider 和实际 native Turn/session HTTP owner,没有调用真实模型或租户。初版配对脚本曾因我使用错误 route 字段而失败,两边相同;修正到真实 facade 的 source_conversation_id 后重新执行,未将该脚本错误归因于 PR。

验证 结果
TypeScript reply-context PASS,12 项,含 thread、短文、错误来源与预算
native Lark 测试与独立 frozen-context/HTTP probe PASS,17 项
七组相同输入经真实 Python facade → TS runtime PASS;短文、非回复、错误来源完全相同,长文四组为已声明摘录变化
control-plane typecheck、changed Python test Ruff PASS
standard diff-selected premerge PASS,5 direct、10 selected checks
strict change-quality PASS,精确当前 scope 已记录

没有 opt-in/default-off 声明;这是既有引用路径的修复。没有新增 actor、权限或共享状态 vocabulary,既有 typed status 继续复用。真实租户、安装后模型采用、完整跨平台资格仍 UNVERIFIED;没有读取或等待远端 CI。恢复非法源 Unicode、grapheme 分割和完整历史检索均不在本次承诺中。

我的整体评价 / Verdict

APPROVE。长程连续使用的相关判断为 improved:当前修复消除了一个会阻断后续会话读取的确定性故障,同时保留原预算和原 owner。用户体验判断为 improved:结尾约束可见,原会话可读,用户不需要新增配置、重复输入、确认或手工恢复。这个结论限于已验证路径,没有推断模型能遵守全部引用内容或节省长期成本。

视觉检查不适用:本次改动为引用数据裁剪与会话读取,不改变渲染布局;真实租户展示与安装后采用未验证。保留现有 helper 和调用边界已足够简洁,未发现需要当前修复承担的额外重构。Approval 是精确 head 的评审结论,合并策略、旧 review 的有效状态和维护者合并权限另行处理。

English verdict: APPROVE at 65e7d9baa452bb65ae4ad09407867a82294f457f. The reproduced Unicode readback defect is fixed; budgets and existing authority boundaries remain intact.

@huangruiteng
huangruiteng merged commit dfc26ad into main Nov 4, 2026
34 of 44 checks passed
@huangruiteng
huangruiteng deleted the codex/reply-context-truncation branch November 4, 2026 14:02
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.

3 participants