feat(rich-text): add AI patch finalization API and harden BlockIdExtension (FCT-50714)#3781
feat(rich-text): add AI patch finalization API and harden BlockIdExtension (FCT-50714)#3781
Conversation
33b0015 to
db4a08c
Compare
✅ No New Circular DependenciesNo new circular dependencies detected. Current count: 0 |
📦 Alpha Package Version PublishedUse Use |
🔍 Visual review for your branch is published 🔍Here are the links to: |
packages/react/src/experimental/RichText/NotesTextEditor/applyPageDocumentPatch.test.ts
Show resolved
Hide resolved
packages/react/src/experimental/RichText/NotesTextEditor/applyPageDocumentPatch.ts
Outdated
Show resolved
Hide resolved
packages/react/src/experimental/RichText/NotesTextEditor/applyPageDocumentPatch.ts
Outdated
Show resolved
Hide resolved
packages/react/src/experimental/RichText/NotesTextEditor/index.spec.tsx
Outdated
Show resolved
Hide resolved
packages/react/src/experimental/RichText/NotesTextEditor/index.spec.tsx
Outdated
Show resolved
Hide resolved
packages/react/src/experimental/RichText/NotesTextEditor/index.spec.tsx
Outdated
Show resolved
Hide resolved
packages/react/src/experimental/RichText/CoreEditor/Extensions/BlockIdExtension/index.tsx
Outdated
Show resolved
Hide resolved
fa547ac to
05a5aa8
Compare
packages/react/src/experimental/RichText/NotesTextEditor/applyPageDocumentPatch.ts
Outdated
Show resolved
Hide resolved
packages/react/src/experimental/RichText/CoreEditor/Extensions/BlockIdExtension/index.tsx
Show resolved
Hide resolved
packages/react/src/experimental/RichText/NotesTextEditor/types.tsx
Outdated
Show resolved
Hide resolved
|
build |
1 similar comment
|
build |
|
build |
packages/react/src/sds/ai/F0AiChat/components/messages/MessagesContainer.tsx
Show resolved
Hide resolved
packages/react/src/sds/ai/F0AiChat/hooks/__tests__/useDebouncedFalseEdge.test.ts
Show resolved
Hide resolved
packages/react/src/sds/ai/F0AiChat/hooks/__tests__/useDebouncedFalseEdge.test.ts
Show resolved
Hide resolved
3450f28 to
50d2c63
Compare
|
Note Medium Risk Overview Hardens block ID handling: Improves AI chat follow-up UX by debouncing the false edge of Written by Cursor Bugbot for commit b60c97d. This will update automatically on new commits. Configure here. |
| onCreate: ({ editor }) => { | ||
| // Legacy documents may contain block nodes with `id: null` because the | ||
| // initial content load is not a `docChanged` transaction, so | ||
| // BlockIdExtension's appendTransaction never fires for it. Re-setting | ||
| // the content triggers a real transaction that lets the plugin assign | ||
| // proper nanoid strings to every block that still has a null id. | ||
| const initialSnapshot = getNotesTextEditorSnapshot(editor) | ||
|
|
||
| editor.commands.setContent(editor.getJSON()) | ||
|
|
||
| const normalizedSnapshot = getNotesTextEditorSnapshot(editor) | ||
|
|
||
| // Only notify the consumer when IDs were actually populated, so pages | ||
| // with already-valid content don't trigger a spurious onChange/autosave. | ||
| if ( | ||
| JSON.stringify(initialSnapshot.json) !== | ||
| JSON.stringify(normalizedSnapshot.json) | ||
| ) { | ||
| onChange(normalizedSnapshot) | ||
| } |
There was a problem hiding this comment.
onCreate always calls editor.commands.setContent(editor.getJSON()) even when there are no id: null blocks to normalize. This forces an extra ProseMirror transaction on every mount (potentially impacting startup performance/history/plugin state) and then does a full JSON.stringify comparison of the entire document. Consider first scanning the initial document for any block node with attrs.id == null and only then re-set content, so the normalization transaction (and stringify work) only runs for legacy documents that actually need it.
| interface NotesTextEditorHandle { | ||
| clear: () => void | ||
| focus: () => void | ||
| setContent: (content: string) => void | ||
| applyPageDocumentPatch: ( | ||
| patch: NotesTextEditorPageDocumentPatch | ||
| ) => NotesTextEditorSnapshot |
There was a problem hiding this comment.
PR description says NotesTextEditorHandle.applyPageDocumentPatch() returns a PageDocumentPatchResult, but the implementation/types define it as returning a NotesTextEditorSnapshot ({ json, html }). If downstream consumers (e.g. the referenced factorial PR) expect a different shape, this mismatch will be a breaking integration issue. Either update the PR description (and any external contracts) to match the snapshot return type, or adjust the handle method to return the documented result type.
Description
The One assistant co-creates page documents with users. This PR adds the editor-layer requirements that make that possible:
NotesTextEditorHandle.applyPageDocumentPatch()— the imperative API the frontend co-creation hook calls to apply a structured patch to the open Tiptap instance. This allows AI to work with blocks as per RFC.Null block ID population — legacy documents store some block IDs as
null; patches look up blocks by ID, so null IDs silently fail without this fix.BLOCK_NODE_TYPES_SETis also exported asReadonlySetto prevent caller mutation.BlockIdExtension.F0AiChat— the co-creation confirmation protocol usesfollowUp: true, which produces a tool-call-only assistant message followed immediately by a new empty message. This caused two concurrent spinners and a flickery thinking indicator. Fixed via auseDebouncedFalseEdgehook that smooths the ~10ms gap between followUp requests, and suppressed the empty placeholder when a turn already has active progress.Implementation details
fix(rich-text): harden BlockIdExtension — populate null block IDs and export ReadonlySetNull IDs populated via
onCreateround-trip inBlockIdExtension/index.tsx.BLOCK_NODE_TYPES_SETre-exported asReadonlySet<string>.feat(rich-text): add AI patch finalization API to NotesTextEditorHandleAdds
applyPageDocumentPatch(patch: PageDocumentPatch): PageDocumentPatchResultto the handle interface. Applies the patch as a Tiptap transaction. Called by factorial'susePageCoCreationhook after receiving a patch from the agent.fix(ai-chat): suppress double spinner and followUp flicker via useDebouncedFalseEdgeNew
useDebouncedFalseEdgehook smooths the isLoading gap between CopilotKit followUp requests. Suppresses the empty follow-up assistant placeholder when a turn already has active progress. Debounce delay reduced from 150ms to 40ms (below the 100ms human perception threshold). Must be published before the factorial-agent PR deploys to avoid the known regression.📦 Dependencies
Has to be merged before https://github.com/factorialco/factorial/pull/93214.
Note: there is another change that has introduced a need for
creditWarningtranslation to frontend. It fails without it.🏡 Context
feat(pages): add page document co-creation for onboarding policies