Skip to content

chore(frontend): upgrade Lexical 0.40 → 0.46#4922

Merged
ardaerzin merged 5 commits into
big-agentsfrom
chore/lexical-upgrade-review
Jun 28, 2026
Merged

chore(frontend): upgrade Lexical 0.40 → 0.46#4922
ardaerzin merged 5 commits into
big-agentsfrom
chore/lexical-upgrade-review

Conversation

@ardaerzin

Copy link
Copy Markdown
Contributor

What

Upgrades Lexical from ^0.40.0 to ^0.46.0 (core + all @lexical/*
packages) across oss, ee, and @agenta/{ui,entities,entity-ui}, and
fixes a pre-existing token-typeahead crash uncovered while testing it.

Two commits, independently reviewable:

  1. chore: the upgrade — version bumps + lockfile + one mechanical code fix.
  2. fix: token typeahead infinite-loop — pre-existing bug (reproduces on 0.40), bundled because it surfaced during upgrade QA.

The upgrade (0.41 → 0.46 reviewed)

The editor is not vanilla Lexical — it's built on the experimental
extension system (defineExtension/configExtension/LexicalExtensionComposer),
with 10 custom nodes, 12 extensions, custom markdown transformers, and a
token system. Every breaking change across 0.41–0.46 was mapped to our usage.

Only one code change was required:
tableRow.getChildren<TableCellNode>()getChildren() as TableCellNode[]
(0.46 removed unsafe type params on node-traversal methods).

Confirmed not affecting us (evidenced): Prism extraction (0.42 — we use
@lexical/code-shiki + our own prism tokenizer), shiki externalization
(0.43 — shiki already a direct dep), OffsetView/$createChildrenArray
(0.44), toggleLink/insertList/removeList removals (0.46), and the
$getNearestNodeFromDOMNode root-return change (we only pass cell elements).

Verification

  • @agenta/ui, @agenta/entity-ui, @agenta/entities — tsc + lint clean.
  • oss tsc — zero new Lexical-related errors.
  • Live smoke (playground): markdown, tables, horizontal rules, lists, inline
    code, tokens + variable propagation, table cell/row resize — all correct.

The bundled fix (token typeahead loop)

Editing across a fenced code block with mixed { / {{ braces while
{{tokens}} exist could crash the editor (React "Maximum update depth
exceeded"). Pre-existing — reproduces identically on 0.40, so it does not
block the upgrade, but it's a real crash worth fixing.

  • Cause: TokenTypeaheadPlugin called React setState synchronously
    inside a Lexical registerUpdateListener; a burst of commits drove
    setState → re-render → commit past React's depth limit. TokenPlugin's
    node transform also scheduled a nested editor.update() to move the caret.
  • Fix: apply the typeahead React state in a coalesced queueMicrotask
    (never synchronously inside the commit), and reposition the caret
    synchronously via navigateCursor instead of a nested update.

Verification

The previously-deterministic crash recipe and heavy-stress variants no longer
crash; caret behavior is unchanged (auto-close {{+name keeps caret inside;
manual {{name}}+text lands after the token).

Test plan

  • CI tsc + lint
  • Smoke the editor: tokens, code blocks, markdown tables/HR, table resize
  • Confirm the typeahead crash recipe no longer reproduces

Bump lexical core + all @lexical/* packages from ^0.40.0 to ^0.46.0
across oss, ee, and the @agenta/{ui,entities,entity-ui} packages
(plus the root @lexical/eslint-plugin).

The only code change required across the editor (10 custom nodes, 12
extensions, plugins, markdown transformers) is one mechanical fix for
the 0.46 removal of unsafe type parameters on node-traversal methods:
TableCellResizerPlugin used tableRow.getChildren<TableCellNode>(), now
getChildren() as TableCellNode[].
Editing across a fenced code block with mixed { / {{ braces while
{{tokens}} exist could crash the editor with React "Maximum update
depth exceeded". Pre-existing (reproduces on 0.40), surfaced during
lexical upgrade testing.

Root cause: TokenTypeaheadPlugin called React setState (setAnchor/
setInputQuery) synchronously inside a Lexical registerUpdateListener. A
burst of commits drove setState → re-render → commit past React's depth
limit. A contributing factor was TokenPlugin.$transformNode scheduling
a nested editor.update() from inside a node transform to reposition the
caret, spawning extra commits.

Fix:
- TokenTypeaheadPlugin: compute the anchor synchronously but apply React
  state in a coalesced queueMicrotask, identity-stable, never inside the
  commit — no commit burst can exceed React's update-depth limit.
- TokenPlugin: reposition the caret synchronously via navigateCursor
  instead of a nested editor.update() (behaviorally identical).

Verified: crash recipe + heavy stress no longer crash; auto-close and
manual-close caret behavior unchanged.
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jun 28, 2026
@vercel

vercel Bot commented Jun 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Ready Ready Preview, Comment Jun 28, 2026 10:40pm

Request Review

@dosubot dosubot Bot added bug Something isn't working dependencies Dependencies Frontend labels Jun 28, 2026
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4c1702e8-e071-40aa-a55c-5c7cb6c07515

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

All @lexical/* and lexical package versions are bumped from ^0.40.0 to ^0.46.0 across the workspace. Editor plugin code is updated for Lexical compatibility, including table row typing, token caret handling, and deferred typeahead state updates.

Changes

Lexical 0.46 Upgrade

Layer / File(s) Summary
Dependency version bumps
web/package.json, web/ee/package.json, web/oss/package.json, web/packages/agenta-entities/package.json, web/packages/agenta-entity-ui/package.json, web/packages/agenta-ui/package.json
Workspace package manifests update @lexical/*, @lexical/eslint-plugin, @lexical/code-shiki, and lexical version constraints from ^0.40.0 to ^0.46.0.
Editor compatibility adjustments
web/packages/agenta-ui/src/Editor/plugins/markdown/TableCellResizerPlugin.tsx, web/packages/agenta-ui/src/Editor/plugins/token/TokenPlugin.tsx
TableCellResizerPlugin changes its row-cell collection typing, and TokenPlugin replaces nested editor.update() selection handling with synchronous selection checks and cursor navigation.
Token typeahead scheduling
web/packages/agenta-ui/src/Editor/plugins/token/TokenTypeaheadPlugin.tsx
TokenTypeaheadPlugin adds microtask-based scheduling for anchor and query updates, and routes selection, click-outside, and escape handling through the new scheduler.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 60.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: upgrading Lexical in the frontend.
Description check ✅ Passed The description is directly related to the Lexical upgrade and token typeahead fix in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/lexical-upgrade-review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f318c75c-11c1-4cd3-8133-ab21eefe776f

📥 Commits

Reviewing files that changed from the base of the PR and between ebc4ec1 and d773f32.

⛔ Files ignored due to path filters (1)
  • web/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • web/ee/package.json
  • web/oss/package.json
  • web/package.json
  • web/packages/agenta-entities/package.json
  • web/packages/agenta-entity-ui/package.json
  • web/packages/agenta-ui/package.json
  • web/packages/agenta-ui/src/Editor/plugins/markdown/TableCellResizerPlugin.tsx
  • web/packages/agenta-ui/src/Editor/plugins/token/TokenPlugin.tsx
  • web/packages/agenta-ui/src/Editor/plugins/token/TokenTypeaheadPlugin.tsx

Comment thread web/packages/agenta-ui/src/Editor/plugins/token/TokenTypeaheadPlugin.tsx Outdated
…nnel

Addresses a review finding: after selecting a suggestion, the deferred
microtask could re-anchor and reopen the menu right after selectOption
closed it (the listener re-anchors on the caret position selectOption
sets, and the deferred flush ran after the synchronous setAnchor(null)).

Unify all anchor/query writers (update listener, selection, escape,
click-outside) behind a single scheduleTypeahead → flushTypeahead
channel. The last write before the microtask wins, so selectOption's
close — which runs after the listener — wins by construction. Keeps the
React update out of the synchronous Lexical commit (crash guard) and
removes the need for ad-hoc suppression flags.
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Jun 28, 2026
@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 413b1ac1-433c-4a62-93ba-5978444e5f49

📥 Commits

Reviewing files that changed from the base of the PR and between d773f32 and a1fdd86.

📒 Files selected for processing (1)
  • web/packages/agenta-ui/src/Editor/plugins/token/TokenTypeaheadPlugin.tsx

Comment thread web/packages/agenta-ui/src/Editor/plugins/token/TokenTypeaheadPlugin.tsx Outdated
The lifted flushTypeahead used a component-scoped mountedRef (init true,
set false on unmount) that was never reset in effect setup. Under React
StrictMode's mount → cleanup → remount cycle it stayed false, so the
flush bailed permanently in dev and the typeahead menu could stop
opening. On React 19 a useState setter after unmount is a harmless no-op,
so the guard was unnecessary machinery — removed it rather than patching
the reset, eliminating the StrictMode footgun.
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jun 28, 2026
@ardaerzin

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 71eb4c64-31b5-48f8-a1fe-e9854a911001

📥 Commits

Reviewing files that changed from the base of the PR and between a1fdd86 and 66faca5.

📒 Files selected for processing (1)
  • web/packages/agenta-ui/src/Editor/plugins/token/TokenTypeaheadPlugin.tsx

Comment on lines +150 to +152
// No mounted-guard needed: on React 19 a useState setter after unmount is a
// harmless no-op, and the microtask is one-shot. A mounted ref here would
// also have to be reset in effect setup to survive StrictMode's remount.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Verify the React versions declared across web package manifests.
rg -n '"react"\s*:\s*"[^"]+"|"react-dom"\s*:\s*"[^"]+"' web -g package.json

Repository: Agenta-AI/agenta

Length of output: 1128


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== web/packages/agenta-ui/package.json =="
sed -n '1,140p' web/packages/agenta-ui/package.json

echo
echo "== workspace react declarations =="
rg -n '"react"\s*:\s*"[^"]+"|"react-dom"\s*:\s*"[^"]+"' web -g package.json

Repository: Agenta-AI/agenta

Length of output: 5484


Use a version-neutral explanation here. This package supports React >=18.0.0, so the note shouldn’t hinge on “React 19”; keep the StrictMode/microtask rationale, but drop the version-specific claim.

@agenta/ui supports React >=18.0.0, so the rationale shouldn't pin to
React 19. setState-after-unmount is a no-op on the supported range; keep
the StrictMode/microtask reasoning without the version-specific claim.
@ardaerzin ardaerzin merged commit 16c865b into big-agents Jun 28, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working dependencies Dependencies Frontend size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant