feat: add the streaming-reveal extension to @tiptap/ai-toolkit - #8109
feat: add the streaming-reveal extension to @tiptap/ai-toolkit#8109ozdemircibaris wants to merge 12 commits into
Conversation
🦋 Changeset detectedLatest commit: 696d2cf The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
✅ Deploy Preview for tiptap-embed ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository YAML (base), Organization UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughSummaryAdds
WalkthroughAdds ChangesStreaming reveal
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant RemoteYjsDoc
participant AiInsertReveal
participant TiptapEditor
RemoteYjsDoc->>AiInsertReveal: Apply remote Yjs insertion
AiInsertReveal->>AiInsertReveal: Track inserted text run
AiInsertReveal->>TiptapEditor: Schedule decoration render
TiptapEditor->>AiInsertReveal: Resolve document positions
AiInsertReveal-->>TiptapEditor: Render fading inline decoration
Suggested labels: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
packages/ai-toolkit/src/streaming-reveal.spec.ts (1)
157-167: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider fake timers for the expiry test.
This test relies on real wall-clock delays (30ms duration + 60ms wait) to prove expiry. It'll pass most of the time, but could get flaky on a slow/loaded CI runner.
vi.useFakeTimers()+vi.advanceTimersByTime()(or mockingDate.now) would make it deterministic.As per coding guidelines, "Add or update unit tests for deterministic user-visible behavior, preferring unit tests over end-to-end tests when appropriate."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ai-toolkit/src/streaming-reveal.spec.ts` around lines 157 - 167, Update the “drops the reveal once its duration has elapsed” test to use Vitest fake timers instead of real setTimeout delays. Enable fake timers before creating the editor, advance them beyond the configured duration to trigger expiry, assert the decoration is removed, and restore real timers afterward.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/ai-toolkit/src/streaming-reveal.spec.ts`:
- Around line 157-167: Update the “drops the reveal once its duration has
elapsed” test to use Vitest fake timers instead of real setTimeout delays.
Enable fake timers before creating the editor, advance them beyond the
configured duration to trigger expiry, assert the decoration is removed, and
restore real timers afterward.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: CHILL
Plan: Pro Plus
Run ID: d98bc6de-cc92-432c-96ad-6088a795f294
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (5)
.changeset/new-pots-admire.mdpackages/ai-toolkit/package.jsonpackages/ai-toolkit/src/streaming-reveal.spec.tspackages/ai-toolkit/src/streaming-reveal.tspackages/ai-toolkit/tsup.config.ts
bdbch
left a comment
There was a problem hiding this comment.
LGTM just a few nitpicks around comment lengths
| * Upper bound (chars) on a single revealed run. A normal streamed token is a | ||
| * few chars; this only guards against a mis-resolved relative position yielding | ||
| * an absurd range (e.g. spanning the whole document). |
There was a problem hiding this comment.
what exactly is a revealed run? Sometimes I think these comments should describe things more general so someone who doesn't already have a large grasp of the context of the feature can understand the code.
| // Seed the CSS animation from the run's real age so a re-render | ||
| // (y-tiptap rebuilds the doc on every token) resumes the fade at the | ||
| // correct point instead of restarting it. |
There was a problem hiding this comment.
| // Seed the CSS animation from the run's real age so a re-render | |
| // (y-tiptap rebuilds the doc on every token) resumes the fade at the | |
| // correct point instead of restarting it. | |
| // Offset the animation by the run's age so token updates resume the fade instead of restarting it. |
d6da91e
| /** | ||
| * Applies a remote (non-local) insert into the first paragraph's text, mimicking | ||
| * an AI streaming into the shared document from another peer. Uses a second Y.Doc | ||
| * synced from `ydoc` so the resulting transaction has `local === false`. | ||
| */ |
There was a problem hiding this comment.
| /** | |
| * Applies a remote (non-local) insert into the first paragraph's text, mimicking | |
| * an AI streaming into the shared document from another peer. Uses a second Y.Doc | |
| * synced from `ydoc` so the resulting transaction has `local === false`. | |
| */ | |
| /** Applies a remote insert via a synced second Y.Doc. */ |
| /** | ||
| * Upper bound (chars) on one revealed run: the text from a single streamed | ||
| * insert, usually a token of a few chars. This only guards against a | ||
| * mis-resolved relative position yielding an absurd range (e.g. spanning the | ||
| * whole document). | ||
| */ |
There was a problem hiding this comment.
| /** | |
| * Upper bound (chars) on one revealed run: the text from a single streamed | |
| * insert, usually a token of a few chars. This only guards against a | |
| * mis-resolved relative position yielding an absurd range (e.g. spanning the | |
| * whole document). | |
| */ | |
| /** Limits each revealed streamed insert to guard against mis-resolved positions spanning the document. */ |
| /** | ||
| * One freshly-inserted text run, anchored by Yjs relative positions so it stays | ||
| * valid across the whole-document rebuild that y-tiptap applies on every remote | ||
| * sync (a plain ProseMirror position would be collapsed by that rebuild). | ||
| */ |
There was a problem hiding this comment.
| /** | |
| * One freshly-inserted text run, anchored by Yjs relative positions so it stays | |
| * valid across the whole-document rebuild that y-tiptap applies on every remote | |
| * sync (a plain ProseMirror position would be collapsed by that rebuild). | |
| */ | |
| /** Anchors each inserted run with Yjs relative positions so it survives y-tiptap document rebuilds. */ |
| /** | ||
| * Fades in text inserted by remote Yjs transactions using view-only inline | ||
| * decorations anchored by relative positions. It never mutates the document, | ||
| * so it stays inert to accept/reject and to persistence, and local edits are | ||
| * ignored so a user's own typing does not fade. Requires the Collaboration | ||
| * extension and CSS on the configured `className` (default `ai-insert-reveal`). | ||
| */ |
There was a problem hiding this comment.
| /** | |
| * Fades in text inserted by remote Yjs transactions using view-only inline | |
| * decorations anchored by relative positions. It never mutates the document, | |
| * so it stays inert to accept/reject and to persistence, and local edits are | |
| * ignored so a user's own typing does not fade. Requires the Collaboration | |
| * extension and CSS on the configured `className` (default `ai-insert-reveal`). | |
| */ | |
| /** | |
| * Fades in remote Yjs inserts using view-only decorations, ignoring local edits and document persistence. | |
| * Requires Collaboration and CSS for `className` (default: `ai-insert-reveal`). | |
| */ |
There was a problem hiding this comment.
This part is outdated, but interestingly it doesn’t show as outdated
Fixes
N/A (new feature)
Changes and Review
AiInsertRevealextension (@tiptap/ai-toolkit/streaming-reveal): fades in text as the AI streams it into a collaborative document.revealAiText) orstreaming-reveal.spec.ts.Checklist
Responsibility