fix(web): guarantee unique assistant-ui thread message IDs#706
Merged
tiann merged 2 commits intoMay 26, 2026
Conversation
Suffix duplicate kind:id pairs before ExternalStore sync; skip duplicate hub rows in SessionChat normalization. Align outline scroll targets with the new user-text thread id shape. Closes tiann#704. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Findings
- [Major] Preserve converter cache keys for unchanged blocks — wrapping every
VisibleChatBlockin a new{ block, threadMessageId }object meansuseExternalMessageConvertercan no longer hit its WeakMap caches whenprops.blockschanges for a streaming update. The previous call used the stable reconciled block objects directly, so unchanged history was not re-converted; this line now passes fresh wrapper objects for the whole list and turns each append/update into a full visible-history conversion. Evidenceweb/src/lib/assistant-runtime.ts:599.
Suggested fix:const threadIdCacheRef = useRef(new WeakMap<VisibleChatBlock, BlockWithThreadMessageId>()) const blocksWithThreadIds = useMemo(() => { const seen = new Map<string, number>() return props.blocks.map((block) => { const base = `${block.kind}:${block.id}` const occurrence = seen.get(base) ?? 0 seen.set(base, occurrence + 1) const threadMessageId = occurrence === 0 ? base : `${base}~${occurrence}` const cached = threadIdCacheRef.current.get(block) if (cached?.threadMessageId === threadMessageId) return cached const next = { block, threadMessageId } threadIdCacheRef.current.set(block, next) return next }) }, [props.blocks])
Questions
- None.
Summary
- Review mode: initial
- One performance regression found in the new assistant-ui ID wrapping path. Residual risk: the new duplicate-id behavior needs a regression test that proves unchanged blocks retain converter cache identity across an append/update.
Testing
- Not run (automation)
HAPI Bot
WeakMap stable BlockWithThreadMessageId objects keyed on reconciled block refs so streaming appends do not invalidate assistant-ui converter caches (PR tiann#706 review). Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
Findings
- No issues found with confidence >= 80% in the modified lines.
Questions
- None.
Summary
- Review mode: follow-up after new commits
- The follow-up addresses the prior bot finding by reusing wrapper objects for unchanged
VisibleChatBlockreferences while keeping assistant-ui message IDs unique. Residual risk: I did not run the web test suite in this automation pass; coverage added in the PR targets the ID suffixing, wrapper reuse, and outline anchor rename paths.
Testing
- Not run (automation)
HAPI Bot
9 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.
Summary
${kind}:${id}) with~1,~2, … suffixes when the same kind+id repeats, so@assistant-ui/reactnever receives duplicate ids in the linear external-store array (fix(web): SessionChat crashes when assistant-ui receives duplicate thread message IDs #704).message.idrows when buildingnormalizedMessagesinSessionChat(defense in depth).targetMessageId/ outline item ids touser-text:…so outline scroll-to-message matches the new user thread message ids (regression that would otherwise break jump-to-message).Test plan
cd web && bun run test src/lib/assistant-runtime.test.ts src/chat/outline.test.ts src/components/AssistantChat/HappyThread.test.tsxbun typecheck(repo root)Made with Cursor