AbsoluteJS

Angular AI

The AIStreamService injectable connects Angular components to the AI streaming WebSocket using Angular signals. Import from @absolutejs/ai/angular.

#AIStreamService

Inject AIStreamService and call connect() with the WebSocket path. It returns an object with Angular computed signals for messages, streaming state, and errors. The service is provided in root and manages connection lifecycle : calling connect() with the same path reuses the existing connection.

TS
import { Component, OnInit } from '@angular/core';
import { AIStreamService } from '@absolutejs/ai/angular';

@Component({
  selector: 'app-chat',
  template: `
    @for (msg of messages(); track msg.id) {
      <div>
        <strong>{{ msg.role }}:</strong> {{ msg.content }}
        @if (msg.thinking) {
          <details>
            <summary>Thinking</summary>
            <p>{{ msg.thinking }}</p>
          </details>
        }
      </div>
    }

    @if (streaming()) {
      <button (click)="cancel()">Stop</button>
    }
    @if (err()) {
      <p style="color: red">{{ err() }}</p>
    }
  `,
})
export class ChatComponent implements OnInit {
  private ai!: ReturnType<AIStreamService['connect']>;

  messages = () => this.ai?.messages() ?? [];
  streaming = () => this.ai?.isStreaming() ?? false;
  err = () => this.ai?.error() ?? null;

  constructor(private aiService: AIStreamService) {}

  ngOnInit() {
    this.ai = this.aiService.connect('/chat');
  }

  send(text: string) {
    this.ai.send(text);
  }

  cancel() {
    this.ai.cancel();
  }
}

#Return Type

TS
// AIStreamService.connect() return type (uses Angular signals)
{
  send: (content: string, attachments?: AIAttachment[]) => void;
  cancel: () => void;
  branch: (messageId: string, content: string) => void;

  messages: Signal<AIMessage[]>;   // Angular computed signal
  isStreaming: Signal<boolean>;    // Angular computed signal
  error: Signal<string | null>;   // Angular computed signal
}