Skip to content

[Bug]: ChatPanel freezes on links due to a ProseMirror DOM mutation loop #192

Description

@mydmdm

What happened?

ChatPanel can freeze the browser UI while opening an existing Agent conversation or during an ongoing conversation. In the first observed case, the panel never finished displaying its first history message. In another conversation, the UI became unresponsive during normal use, noticed when attempting to resize the panel. Resizing has not been established as the trigger.

Clicks, scrolling, and panel resizing stop responding, while the server and external Agent continue working. Console may show no errors. Pausing JavaScript in DevTools allowed the pending UI to become visible and exposed a ProseMirror DOM parsing stack.

Expected behavior

Opening or streaming chat messages containing links must not cause repeated editor updates or block browser interaction. Links must remain clickable without initiating a canvas node drag.

Reproduction and evidence

Observed application scenarios

  1. Open an existing Agent conversation containing rendered links, or continue a conversation until linked content is rendered.
  2. Observe whether ChatPanel stops painting or the page stops responding.
  3. When frozen, pause JavaScript in DevTools Sources and inspect the call stack.

The reported incidents occurred with external Agents, both after restarting the server and during a new conversation. Each affected live message has not been individually inspected, so the precise link trigger for every reported incident remains to be confirmed. This is not assumed to be external-Agent-specific.

Confirmed isolated reproduction

A bounded, in-memory Chromium reproduction used the repository's installed ProseMirror dependencies, an editable editor with one paragraph containing one ordinary link, and the same plugin view/update callback as Huabu. No network, long history, active Agent, or streaming updates were required.

  • Current callback: 21 plugin callbacks and 20 class writes, reaching an explicitly imposed safety cap that stopped further writes.
  • With a classList.contains('nodrag') guard: 2 plugin callbacks and 1 class write, then settled without reaching the cap.

No repository source changes or new test files were made during this investigation.

Diagnosis

Affected revision: fbe1fd4943febb9f50a6fbc0d8092e0df6a5d93d.

markPreviewLinksNoDrag() unconditionally calls anchor.classList.add('nodrag') for every a[href].

The preview plugin runs this operation both on creation and on every editor view update. Chat message previews enable block dragging, which makes their underlying ProseMirror editor editable even though user text editing is suppressed by the preview wrapper.

In Chromium, adding an already-present class still produces an attribute mutation notification. ProseMirror observes the link attribute mutation, marks the affected DOM dirty, parses it, and updates its view. That invokes the plugin again, which writes the same class again. The feedback loop can monopolize the main thread without throwing an exception:

plugin view/update
  -> classList.add('nodrag')
  -> MutationObserver
  -> DOMObserver.flush
  -> readDOMChange / parseBetween / DOMParser.parse
  -> editor view update
  -> plugin view/update again

The guard makes the operation DOM-idempotent, not merely visually idempotent.

Browser stack and server observations

Captured while the affected page was frozen:

addAll (vendor-editor-Ch4SPCCI.js:5)
addElementByRule (vendor-editor-Ch4SPCCI.js:5)
addElement (vendor-editor-Ch4SPCCI.js:4)
addDOM (vendor-editor-Ch4SPCCI.js:3)
addAll (vendor-editor-Ch4SPCCI.js:5)
parse (vendor-editor-Ch4SPCCI.js:3)
sK (vendor-editor-Ch4SPCCI.js:12)
cK (vendor-editor-Ch4SPCCI.js:12)
(anonymous) (vendor-editor-Ch4SPCCI.js:12)
flush (vendor-editor-Ch4SPCCI.js:12)
observer (vendor-editor-Ch4SPCCI.js:12)

The history page requests completed with HTTP 200 in approximately 5-7 ms; capability-cache requests also completed successfully. During the separate live-conversation incident, Agent events continued and a profiles request completed in approximately 3 ms. These observations do not support a blocked history endpoint as the cause of these freezes.

Suggested fix and acceptance criteria

  • Make preview link annotation idempotent: do not write the class attribute when nodrag is already present. A ProseMirror-owned decoration/schema approach is another option if needed, but a broad editor refactor is not required to address the demonstrated loop.
  • Cover both the initial mount of linked history and links introduced through subsequent content updates.
  • Ensure link-free and linked previews settle rather than generating an unbounded sequence of observer-driven view updates.
  • Preserve link navigation and block-drag behavior; do not disable CSP, delete history, or change Agent lifecycle contracts as a workaround.

Scope and provenance

This is an independent frontend/editor bug discovered while testing #163 / PR #178. The unconditional link-class annotation originated in commit 54d1e6cbf78a8465aa3663fa30b207cc503f00d3 ("Fix clickable links in canvas previews", #136), already incorporated from main. It was not introduced by the server-owned Agent Node FSM changes. Track and fix it separately from #163.

Environment

Browser-based Huabu; precise affected browser/OS version was not supplied. The isolated reproduction used Chromium. Installed editor packages at the investigated revision include Milkdown 7.21.2 and ProseMirror View 1.41.9.

Report hygiene

  • Searched for existing nodrag and open freeze issues; no matching report was found.
  • Omitted credentials, private conversation content, host addresses, and local user paths.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions