Documentation

Angular Client SDK

The ModelRiver Angular SDK provides a robust, Observable-based service wrapper for the ModelRiver client. It integrates seamlessly with Angular's dependency injection and Change Detection systems.

Installation

Bash
npm install @modelriver/client

The Angular service is part of the standard @modelriver/client distribution.

Setup and Usage

1. provide the service

You can provide the ModelRiverService at the component or module level.

TYPESCRIPT
1import { Component } from '@angular/core';
2import { ModelRiverService } from '@modelriver/client/angular';
3import { CommonModule } from '@angular/common';
4import { FormsModule } from '@angular/forms';
5 
6@Component({
7 selector: 'app-ai-terminal',
8 standalone: true,
9 imports: [CommonModule, FormsModule],
10 providers: [ModelRiverService],
11 template: `
12 <div class="terminal">
13 <!-- Progress Bar -->
14 <div class="progress">
15 <div *ngFor="let step of modelRiver.steps$ | async"
16 [class]="'pill ' + step.status">
17 {{ step.name }}
18 </div>
19 </div>
20 
21 <!-- AI Stream -->
22 <div class="stream-output">
23 <p *ngIf="modelRiver.response$ | async as res">
24 {{ res.content }}
25 </p>
26 <div *ngIf="(modelRiver.status$ | async) === 'loading'">
27 Generating...
28 </div>
29 </div>
30 
31 <!-- Controls -->
32 <div class="input-row">
33 <input [(ngModel)]="prompt" [disabled]="(modelRiver.status$ | async) === 'loading'">
34 <button (click)="submit()" [disabled]="!prompt">Run AI</button>
35 </div>
36 
37 <p class="error" *ngIf="modelRiver.error$ | async as err">{{ err }}</p>
38 </div>
39 `
40})
41export class AiTerminalComponent {
42 prompt = '';
43 
44 constructor(public modelRiver: ModelRiverService) {
45 this.modelRiver.init({
46 baseUrl: 'wss://api.modelriver.com/socket'
47 });
48 }
49 
50 async submit() {
51 // 1. Get token from your backend
52 const { ws_token } = await this.myBackendService.generate(this.prompt);
53
54 // 2. Start streaming
55 this.modelRiver.connect({ wsToken: ws_token });
56 }
57}

Features for Enterprise Angular Apps

Type Safety

The Angular SDK is written in TypeScript and provides interfaces for all ModelRiver payloads (AIResponse, WorkflowStep, etc.), ensuring your AI integration is type-safe from end-to-end.

Observable Streams

Every state in the SDK is exposed as an Observable (response$, status$, steps$, error$). This allows you to use the async pipe in templates or compose complex logic using RxJS operators.

Global Configuration

You can initialize the ModelRiverService once in your AppModule or AppConfig to share configuration (like baseUrl) across multiple components.

Reconnecting

init() calls reconnect(), so a request that was pending when the page reloaded resumes on its own if the reload happens within about 5 minutes. The service also reconnects by itself after network drops; connectionState$ emits 'reconnecting' meanwhile (SDK 1.8.0+). For longer gaps and ModelRiver restarts, pass getToken to init() to fetch a new token from your backend. See Reconnecting.

Streaming Tokens and Live Sessions

The service 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.

TYPESCRIPT
1import { Component, Input, NgZone, OnDestroy, OnInit, signal } from '@angular/core';
2import { subscribeToSession, type SessionMessage, type SessionSubscription } from '@modelriver/client';
3 
4@Component({ selector: 'app-live-chat', template: '...' })
5export class LiveChatComponent implements OnInit, OnDestroy {
6 @Input() chatId!: string;
7 messages = signal<SessionMessage[]>([]);
8 private subscription?: SessionSubscription;
9 
10 constructor(private zone: NgZone) {}
11 
12 ngOnInit() {
13 this.subscription = subscribeToSession({
14 getSubscription: () => fetch(`/api/chats/${this.chatId}/live`, { method: 'POST' }).then((r) => r.json()),
15 onMessage: (message) => this.zone.run(() => this.messages.update((list) => [...list, message])),
16 });
17 }
18 
19 ngOnDestroy() {
20 this.subscription?.close();
21 }
22}

For streamed tokens, create a ModelRiverClient and listen to stream_delta the same way (client.on('stream_delta', (chunk, text) => ...)).

SEO Best Practices for AI in Angular

  1. Angular Universal (SSR): Use SSR to ensure the static parts of your AI dashboard are searchable and load instantly for crawlers.
  2. OnPush Change Detection: The ModelRiverService triggers change detection efficiently, supporting the OnPush strategy for high-performance AI interfaces.
  3. Canonical Links: Ensure each AI-generated page/route has a proper canonical URL to manage content duplication if you allow users to share AI results.

Next Steps