The ModelRiver Vue SDK provides a reactive useModelRiver composable designed for Vue 3 (Composition API). It handles all WebSocket orchestration and state synchronization so you can build AI-powered UIs with ease.
Installation
npm install @modelriver/clientThe Vue adapter is bundled with the core @modelriver/client library.
Implementation Example
Using the useModelRiver composable in a component:
1<script setup>2import { ref } from 'vue';3import { useModelRiver } from '@modelriver/client/vue';4 5const userInput = ref('');6 7const { 8 connect, 9 response, 10 error, 11 isConnected, 12 steps, 13 status 14} = useModelRiver({15 baseUrl: 'wss://api.modelriver.com/socket',16 persist: true17});18 19async function sendMessage() {20 try {21 // 1. Request a connection token from your backend22 const res = await fetch('/api/ai/chat', {23 method: 'POST',24 body: JSON.stringify({ message: userInput.value })25 });26 27 const { ws_token, channel_id } = await res.json();28 29 // 2. Start the real-time stream30 connect({ wsToken: ws_token, channelId: channel_id });31 userInput.value = '';32 } catch (e) {33 console.error('Failed to start AI request', e);34 }35}36</script>37 38<template>39 <div class="ai-chat-shell">40 <!-- Progress Indicator -->41 <ul class="progress-steps">42 <li v-for="step in steps" :key="step.id" :class="step.status">43 {{ step.name }}44 </li>45 </ul>46 47 <!-- AI Output -->48 <div class="output-window">49 <div v-if="status === 'loading'" class="loading-spinner">50 Processing...51 </div>52 <div v-if="response" class="content">53 {{ response.content }}54 </div>55 <div v-if="error" class="error-alert">56 {{ error }}57 </div>58 </div>59 60 <!-- Input Area -->61 <form @submit.prevent="sendMessage">62 <input 63 v-model="userInput" 64 placeholder="Ask AI anything..." 65 :disabled="status === 'loading'"66 />67 <button :disabled="!userInput || status === 'loading'">68 Generate69 </button>70 </form>71 </div>72</template>73 74<style scoped>75.success { color: green; }76.loading { color: blue; font-weight: bold; }77.error-alert { color: red; }78</style>Features for Vue Developers
Reactive Integration
The composable returns Ref and Computed properties that update automatically as data flows from the ModelRiver WebSocket. This works perfectly with Vue's reactivity system, ensuring zero manual DOM manipulation.
Error Handling
The error ref captures both network-level failures and AI-specific errors (like safety filtering or provider timeouts), allowing you to render conditional UI states easily.
Lifecycle Management
When the component unmounts, the composable closes the WebSocket connection and stops its timers, preventing leaks in single-page applications. A request that is still pending stays stored, so the next mount or page load resumes it (SDK 1.8.0+).
Reconnecting
The composable calls reconnect() on mount, so a request that was pending when the page reloaded resumes on its own if the reload happens within about 5 minutes. It also reconnects by itself after network drops; connectionState is 'reconnecting' meanwhile (SDK 1.8.0+). For longer gaps and ModelRiver restarts, pass getToken to fetch a new token from your backend. See Reconnecting.
Streaming Tokens and Live Sessions
The adapter tracks the request's steps and final response. For token-by-token text (async requests sent with "stream": true, SDK 1.6.0+), listen to the client's stream_* events; to follow a whole conversation live (session memory, SDK 1.7.0+), use subscribeToSession. Both come from the core package and work alongside the adapter. See Streaming Tokens and Live Sessions for the details.
1<script setup lang="ts">2import { onMounted, onUnmounted, ref } from 'vue';3import { ModelRiverClient, subscribeToSession, type SessionMessage } from '@modelriver/client';4 5const props = defineProps<{ chatId: string }>();6const messages = ref<SessionMessage[]>([]);7const streamed = ref('');8 9// The answer as it streams in. `ticket` is your backend's /v1/ai/async response.10const client = new ModelRiverClient({ persist: false });11client.on('stream_delta', (_chunk, soFar) => (streamed.value = soFar));12function follow(ticket) {13 client.connect({14 channelId: ticket.channel_id,15 wsToken: ticket.ws_token,16 websocketUrl: ticket.websocket_url,17 websocketChannel: ticket.websocket_channel,18 });19}20 21// The conversation, live.22let subscription: { close: () => void } | null = null;23onMounted(() => {24 subscription = subscribeToSession({25 getSubscription: () => fetch(`/api/chats/${props.chatId}/live`, { method: 'POST' }).then((r) => r.json()),26 onMessage: (message) => {27 if (!messages.value.some((m) => m.id === message.id)) messages.value.push(message);28 },29 });30});31onUnmounted(() => {32 subscription?.close();33 client.disconnect();34});35</script>Building SEO Friendly AI Apps with Vue
- Server-Side Rendering (SSR): While the AI stream is client-side, ensure the initial page layout and SEO meta tags are served via Nuxt.js or Vue SSR for search engine indexing.
- Progressive Enhancement: Provide a graceful fallback for users with slow connections. Use the
stepsdata to inform users that content is being generated. - Structured Metadata: Use the
response.datafor JSON-LD or other structured data that search engines can use to enrich your page's search results.
Next Steps
- Review Webhooks for backend-to-backend events.
- Learn about Observability to monitor your Vue app's AI performance.
- See the API Compatibility guide.