fix(chat): 去重翻页边界消息,避免 message list 无限循环 (#430)#787
Open
weiconghe wants to merge 1 commit into
Open
Conversation
weiconghe
force-pushed
the
fix/chat-message-boundary-dedup
branch
from
July 24, 2026 06:30
becf12a to
ffef434
Compare
上游 IM 接口使用含等号的时间边界(newer 为 >=、older 为 <=),按文档把 边界 createTime 作为下一页 --time 传入时,该消息会在之后每一页被重复 返回,导致 chat message list 无限翻页循环(DingTalk-Real-AI#430)。 在静态 chat handler 上对 list / list-direct / list-topic-replies 的响应做 边界去重:丢弃 result.messages 中 createTime 等于 --time 锚点的消息; shape 不匹配时原样返回,安全 no-op。 Closes DingTalk-Real-AI#430
weiconghe
force-pushed
the
fix/chat-message-boundary-dedup
branch
from
July 24, 2026 07:11
ffef434 to
5fd5fda
Compare
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.
Summary
chat message listpagination boundary de-duplication on the current static chat handler (internal/helpers/chat.go), so that paginating by feeding the previous page's boundarycreateTimeback as the next--timeno longer loops forever. The de-dup drops entries inresult.messageswhosecreateTimeequals the--timeanchor, applied tochat message list,chat message list-direct, andchat message list-topic-replies. The shared MCP-call core gains a nil-safeposttext hook (callMCPToolInternalOptsPost) so the response is filtered before rendering, preserving DryRun /--format json|table|raw/ error-classification behavior exactly.chat message list文档推荐的forward=true翻页方式会无限循环(v1.0.34) #430. The upstream IM API uses an inclusive time boundary (>=fornewer/forward=true,<=forolder/forward=false). The skill docs (written by fix: resolve real-machine QA findings across CLI, scripts and skill docs #572) tell the caller to reuse the boundarycreateTimeas the next--time; that exact-boundary message is then re-served on every subsequent page, sochat message list --direction older(or--forward) pagination loops, returning the same message again and again. fix: resolve real-machine QA findings across CLI, scripts and skill docs #572 mitigated this by recommending--direction older, but the strict boundary de-dup still had to be (re-)done on the static handler.This re-submits the intent of the closed #461, whose implementation lived on
internal/compat/chat_hooks.go/dynamic_commands.go— those files were removed by the #565 static-runtime refactor, so that PR could no longer merge. The dedup logic itself is relocated onto the current handler (internal/helpers/chat.go) and the new sharedposthook, with no dependency on the deletedcompatpackage.Verification
Exact
CHANGELOG.md-only check:N/A(this is a code change).make build—scripts/dev/build.sh(go build -o dws ./cmd) succeeds;dwsbinary builds. Also rango build ./...(whole module) clean.make lint—gofmtclean on all changed files;go vet ./internal/helpers/clean. (staticcheckis not installed in my local env; left to CI.)make test— partial locally; full suite left to CI. I ran the targeted set on Windows + Go 1.25.11:chat_dedup_test.go(de-dup logic + end-to-end via fake caller): all PASScallMCPToolInternalOptscoverage inhelpers_core_test.go/helpers_coverage_more_test.go(json/table/raw/devdoc, DryRun, unescape, error classification): all PASSChat/Message/ChatRecord-related tests ininternal/helpers/: PASS (3.77s)go test ./...was not completed locally — theinternal/helperspackage alone exceeds my local run budget on Windows (some pre-existing tests are slow). CI (Linux) runs the full suite.make policy— not run as a whole locally../scripts/policy/check-command-surface.sh --strictPASSes (command surface unchanged: no new commands/flags/help text)../scripts/policy/check-generated-drift.sh— pre-existing failure on cleanorigin/main, not introduced here. On a clean checkout oforigin/main(my changes stashed) this check already reportsinternal/cli/schema_agent_metadata is staleacross all products (aisearch/aitable/.../chat/contact/wiki…), so it is unrelated to this PR, which changes noCommandRegistry/command definition. Likely a Windows CRLF/path artifact or genuinely stale committed schemas; expecting Linux CI to match its current main behavior../scripts/policy/check-command-surface.sh --strict— PASS (covered above).Notes
internal/shortcut/chat,internal/shortcut/smart) calls these same tools viart.CallMCPData(a separate path, notcallMCPTool) and only reshapes a single page — it does not loop internally — so it is intentionally out of scope for [Bug]chat message list文档推荐的forward=true翻页方式会无限循环(v1.0.34) #430 (which is about thedws chat message listCLI command).internal/helpers/connect_chatrecord.gocallslist_conversation_message_v2only to resolve records by id, not as a user-facing pagination surface.--direction newer(forward=true) is fundamentally not paginatable toward older history (it always re-serves the newest N at/afterT); the de-dup's real value is on--direction older(forward=false), where pagination is valid except for the single exact-boundary repeat. The de-dup is applied uniformly (harmless onnewer), and is an exact-string match (createTime== anchor, after trim) so it only ever drops the verbatim-boundary message — i.e. precisely the loop case.dedupChatMessageBoundaryonly inspects top-levelresult.messages(never recurses into nestedforwardMessages, whosecreateTimeis a forwarded body, not a pagination boundary) and returns the original text verbatim on any parse/shape mismatch, so it is safe to apply unconditionally.skills/.../chat.mdin this PR: the generatedinternal/cli/schema_agent_metadata/index.jsoncarries asource_hashover the skill markdown, so even a one-line doc change forces amake generate-schemaregeneration, and that hash is not reliably reproducible on Windows (raw-byte hash, no CRLF normalization). The existing docs (from fix: resolve real-machine QA findings across CLI, scripts and skill docs #572) already recommend--direction older; the new auto-dedup behavior is documented in the code comments and this PR description. Happy to follow up with the doc line (+ regenerated schema) if you'd like it included here.