Documentation

Vue Client SDK

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

Bash
npm install @modelriver/client

The Vue adapter is bundled with the core @modelriver/client library.

Implementation Example

Using the useModelRiver composable in a component:

VUE
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: true
17});
18 
19async function sendMessage() {
20 try {
21 // 1. Request a connection token from your backend
22 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 stream
30 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 Generate
69 </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.

VUE
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

  1. 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.
  2. Progressive Enhancement: Provide a graceful fallback for users with slow connections. Use the steps data to inform users that content is being generated.
  3. Structured Metadata: Use the response.data for JSON-LD or other structured data that search engines can use to enrich your page's search results.

Next Steps