diff --git a/src/content/ai/ai-toolkit/agents/streaming.mdx b/src/content/ai/ai-toolkit/agents/streaming.mdx index 47dd1c713..574589851 100644 --- a/src/content/ai/ai-toolkit/agents/streaming.mdx +++ b/src/content/ai/ai-toolkit/agents/streaming.mdx @@ -190,7 +190,7 @@ See the [REST API reference](/ai/ai-toolkit/api-reference/rest-api#stream-a-tool Install these dependencies in your client app: ```bash -npm install @ai-sdk/react @tiptap/extension-collaboration @tiptap/react @tiptap/starter-kit @tiptap-pro/provider @tiptap/ai-toolkit ai yjs +npm install @ai-sdk/react @tiptap/extension-collaboration @tiptap/react @tiptap/starter-kit @tiptap-pro/provider @tiptap/ai-toolkit @tiptap/y-tiptap ai yjs ``` @@ -230,6 +230,66 @@ const { messages, sendMessage, status } = useChat({ }) ``` +## Fade in text as it streams + +Streamed text lands in the document token by token. The optional `AiInsertReveal` extension fades it in as it arrives, so the edit reads as a smooth reveal instead of text popping in. It is a view-only decoration: it adds no marks and never touches the document, so it stays inert to accept/reject and to persistence, and neither your own typing nor another collaborator's is faded. + +It builds on the client-side setup above: it reveals text that arrives through Collaboration, so it needs that setup. Import it from the `streaming-reveal` subpath and add it after `ServerAiToolkit`. It reads collaboration positions from `@tiptap/y-tiptap`, so install that too if it is not already a dependency. + +Pass your collaboration provider to it. The provider's awareness is how the AI is told apart from other collaborators, and without it nothing is revealed. + +```tsx +import { ServerAiToolkit, getEditorContext } from '@tiptap/ai-toolkit' +import { AiInsertReveal } from '@tiptap/ai-toolkit/streaming-reveal' + +const editor = useEditor({ + immediatelyRender: false, + extensions: [ + StarterKit.configure({ undoRedo: false }), + Collaboration.configure({ document: doc }), + ServerAiToolkit, + AiInsertReveal.configure({ provider }), + ], +}) +``` + +### CSS styles + +The extension adds the `ai-insert-reveal` class to each freshly-streamed run and seeds its `animation-delay` so the fade resumes at the right point across the per-token re-render. It ships no CSS. Add an animation for that class to define the effect. The class lands on an inline element, so animate properties that apply to one, such as `opacity`, `color` or `filter`. + +```css +.tiptap .ai-insert-reveal { + animation: ai-insert-reveal 380ms ease-out both; +} + +@keyframes ai-insert-reveal { + from { + opacity: 0.35; + } + to { + opacity: 1; + } +} + +@media (prefers-reduced-motion: reduce) { + .tiptap .ai-insert-reveal { + animation: none; + } +} +``` + +### Configuration + +| Option | Default | Description | +| ------------ | -------------------- | --------------------------------------------------------------------------------------------------------------- | +| `provider` | `null` | Your collaboration provider. Required: its awareness identifies the AI, and nothing is revealed without it. | +| `className` | `'ai-insert-reveal'` | Class applied to each streamed run. Change it to run a different effect or to avoid a collision. | +| `durationMs` | `550` | How long each run keeps its decoration. Keep it at or above your CSS animation duration so the fade can finish. | + +```ts +AiInsertReveal.configure({ provider, durationMs: 700 }) +``` + ## Stream as tracked changes To let users review streamed edits instead of applying them directly, add `reviewOptions` to the `start` message. The edit then appears as a tracked-change suggestion that's typed into the document in real time and that users can accept or reject.