Angular Integration
This guide covers integrating Diosc into Angular applications, including services, modules, and Angular Universal SSR.
Basic Setup
Installation
npm install @diosc-ai/client
Configure Custom Elements Schema
Tell Angular to allow diosc-* and ai-* elements in app.module.ts:
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
declarations: [AppComponent],
imports: [BrowserModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA], // Allow web components
bootstrap: [AppComponent]
})
export class AppModule {}
For standalone components (Angular 14+):
@Component({
selector: 'app-root',
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `<diosc-chat />`
})
export class AppComponent {}
Basic Component
import { Component, OnInit, OnDestroy } from '@angular/core';
import { loadDiosc, type DioscFunction } from '@diosc-ai/client';
import { environment } from '../environments/environment';
@Component({
selector: 'app-root',
template: `
<div class="app">
<h1>My Application</h1>
<diosc-chat></diosc-chat>
</div>
`
})
export class AppComponent implements OnInit, OnDestroy {
private diosc: DioscFunction;
async ngOnInit() {
this.diosc = await loadDiosc({
backendUrl: environment.dioscUrl,
apiKey: environment.dioscApiKey,
});
// Push auth to connect
this.diosc('auth', {
headers: { Authorization: `Bearer ${this.getToken()}` },
userId: this.getUserId(),
});
}
ngOnDestroy() {
this.diosc?.('auth', null);
}
private getToken(): string { /* ... */ }
private getUserId(): string { /* ... */ }
}
Diosc Service
Create a service to manage Diosc across your application:
// services/diosc.service.ts
import { Injectable, OnDestroy } from '@angular/core';
import { BehaviorSubject, Subject } from 'rxjs';
import { loadDiosc, type DioscFunction } from '@diosc-ai/client';
@Injectable({
providedIn: 'root'
})
export class DioscService implements OnDestroy {
private diosc: DioscFunction | null = null;
private unsubscribers: (() => void)[] = [];
// Observables for components to subscribe to
private connectedSubject = new BehaviorSubject<boolean>(false);
private streamingSubject = new BehaviorSubject<boolean>(false);
private errorSubject = new Subject<{ code: string; message: string }>();
isConnected$ = this.connectedSubject.asObservable();
isStreaming$ = this.streamingSubject.asObservable();
error$ = this.errorSubject.asObservable();
async initialize(backendUrl: string, apiKey: string) {
this.diosc = await loadDiosc({ backendUrl, apiKey });
this.setupEventListeners();
}
private setupEventListeners() {
if (!this.diosc) return;
this.unsubscribers = [
this.diosc('on', 'authenticated', () => {
this.connectedSubject.next(true);
}),
this.diosc('on', 'disconnected', () => {
this.connectedSubject.next(false);
}),
this.diosc('on', 'stream:start', () => {
this.streamingSubject.next(true);
}),
this.diosc('on', 'stream:end', () => {
this.streamingSubject.next(false);
}),
this.diosc('on', 'session:error', (err: { code: string; message: string }) => {
this.errorSubject.next(err);
})
];
}
pushAuth(token: string, userId: string, tenantId?: string) {
this.diosc?.('auth', {
headers: { Authorization: `Bearer ${token}` },
userId,
tenantId,
});
}
logout() {
this.diosc?.('auth', null);
}
sendMessage(content: string) {
this.diosc?.('invoke', content);
}
startNewSession() {
this.diosc?.('startNewSession');
}
ngOnDestroy() {
this.unsubscribers.forEach(unsub => unsub());
this.diosc?.('auth', null);
}
}
Using the Service
// app.component.ts
import { Component, OnInit } from '@angular/core';
import { DioscService } from './services/diosc.service';
import { AuthService } from './services/auth.service';
import { environment } from '../environments/environment';
@Component({
selector: 'app-root',
template: `
<app-header></app-header>
<router-outlet></router-outlet>
<diosc-chat></diosc-chat>
`
})
export class AppComponent implements OnInit {
constructor(
private dioscService: DioscService,
private authService: AuthService
) {}
async ngOnInit() {
// Initialize Diosc
await this.dioscService.initialize(
environment.dioscUrl,
environment.dioscApiKey
);
// Push auth when token is available
this.authService.token$.subscribe(token => {
if (token) {
this.dioscService.pushAuth(token, this.authService.getUserId());
} else {
this.dioscService.logout();
}
});
}
}
Page Context with Router
Update page context on route changes using a navigation observer:
// services/diosc-router.service.ts
import { Injectable } from '@angular/core';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter } from 'rxjs/operators';
import { type DioscFunction } from '@diosc-ai/client';
@Injectable({
providedIn: 'root'
})
export class DioscRouterService {
private diosc: DioscFunction | null = null;
constructor(
private router: Router,
private route: ActivatedRoute
) {}
initialize(diosc: DioscFunction) {
this.diosc = diosc;
// Register navigation observer
this.diosc('observe', 'navigation', (notify) => {
// Emit current path immediately
notify({ path: this.router.url });
// Subscribe to route changes
const sub = this.router.events.pipe(
filter(event => event instanceof NavigationEnd)
).subscribe((event: NavigationEnd) => {
notify({ path: event.urlAfterRedirects });
});
return () => sub.unsubscribe(); // Cleanup
});
}
}
Initialize in app.component.ts:
constructor(
private dioscService: DioscService,
private dioscRouterService: DioscRouterService
) {}
async ngOnInit() {
await this.dioscService.initialize(environment.dioscUrl, environment.dioscApiKey);
this.dioscRouterService.initialize(this.dioscService.getDiosc());
}
Angular Universal (SSR)
Diosc requires browser APIs and won't work during SSR.
Platform Check
import { Component, OnInit, PLATFORM_ID, Inject } from '@angular/core';
import { isPlatformBrowser } from '@angular/common';
@Component({
selector: 'app-root',
template: `
<diosc-chat *ngIf="isBrowser"></diosc-chat>
`
})
export class AppComponent implements OnInit {
isBrowser: boolean;
constructor(@Inject(PLATFORM_ID) platformId: Object) {
this.isBrowser = isPlatformBrowser(platformId);
}
async ngOnInit() {
if (this.isBrowser) {
const { loadDiosc } = await import('@diosc-ai/client');
const diosc = await loadDiosc({ /* ... */ });
// ...
}
}
}
RxJS Integration
Convert Diosc events to RxJS observables:
// services/diosc-events.service.ts
import { Injectable } from '@angular/core';
import { Observable, fromEventPattern } from 'rxjs';
import type { DioscFunction } from '@diosc-ai/client';
@Injectable({
providedIn: 'root'
})
export class DioscEventsService {
private diosc: DioscFunction;
initialize(diosc: DioscFunction) {
this.diosc = diosc;
}
streamChunk$(): Observable<{ content: string }> {
return this.createEventObservable('stream:chunk');
}
toolStarted$(): Observable<{ toolName: string; toolCallId: string }> {
return this.createEventObservable('tool:started');
}
toolCompleted$(): Observable<{ toolName: string; durationMs: number }> {
return this.createEventObservable('tool:completed');
}
approvalRequest$(): Observable<{ toolCalls: Array<{ name: string }> }> {
return this.createEventObservable('approval:request');
}
sessionError$(): Observable<{ code: string; message: string }> {
return this.createEventObservable('session:error');
}
private createEventObservable<T>(eventName: string): Observable<T> {
return fromEventPattern<T>(
(handler) => this.diosc('on', eventName, handler),
(handler, unsubscribe) => unsubscribe()
);
}
}
Usage:
@Component({ ... })
export class MyComponent implements OnInit, OnDestroy {
private subscription!: Subscription;
constructor(private dioscEvents: DioscEventsService) {}
ngOnInit() {
this.subscription = this.dioscEvents.toolStarted$().subscribe(({ toolName }) => {
console.log('Tool executing:', toolName);
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
Standalone Components (Angular 14+)
import { Component, CUSTOM_ELEMENTS_SCHEMA, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { loadDiosc, type DioscFunction } from '@diosc-ai/client';
@Component({
selector: 'app-diosc-chat',
standalone: true,
imports: [CommonModule],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<div class="chat-wrapper">
<diosc-chat></diosc-chat>
</div>
`
})
export class DioscChatComponent implements OnInit, OnDestroy {
private diosc: DioscFunction;
async ngOnInit() {
this.diosc = await loadDiosc({
backendUrl: 'https://your-hub.example.com',
apiKey: 'your-api-key'
});
this.diosc('auth', {
headers: { Authorization: `Bearer ${this.getToken()}` },
userId: this.getUserId(),
});
}
ngOnDestroy() {
this.diosc?.('auth', null);
}
private getToken(): string { /* ... */ }
private getUserId(): string { /* ... */ }
}
Environment Configuration
// environments/environment.ts
export const environment = {
production: false,
dioscUrl: 'http://localhost:3333',
dioscApiKey: 'dev-api-key'
};
// environments/environment.prod.ts
export const environment = {
production: true,
dioscUrl: 'https://your-hub.example.com',
dioscApiKey: 'prod-api-key'
};
Troubleshooting
'diosc-chat' is not a known element
Add CUSTOM_ELEMENTS_SCHEMA to your module or component:
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
SSR Build Errors
Wrap browser-only code with platform checks:
if (isPlatformBrowser(this.platformId)) {
// Browser-only code
}
Zone.js Issues
Diosc events may run outside Angular's zone:
import { NgZone } from '@angular/core';
constructor(private ngZone: NgZone) {}
ngOnInit() {
diosc('on', 'stream:chunk', ({ content }) => {
this.ngZone.run(() => {
this.streamContent += content;
});
});
}
Memory Leaks
Always clean up subscriptions and event listeners:
ngOnDestroy() {
this.subscriptions.forEach(sub => sub.unsubscribe());
this.unsubscribers.forEach(unsub => unsub());
this.diosc?.('auth', null);
}
Next Steps
- Vanilla JS Integration - No-framework approach
- Common Integration Patterns - Framework-agnostic patterns
- Client SDK Reference - Complete API reference