Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion src/content/ai/ai-toolkit/agents/streaming.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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
```

</details>
Expand Down Expand Up @@ -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.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

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.
Expand Down
Loading