@redhat-cloud-services/ai-client-common
Common interfaces and utilities for AI client packages in the Red Hat Cloud Services ecosystem.
Features
- Standardized AI Client Interface - Common
IAIClient
interface for all AI services
- Conversation Management - Standard conversation interface with locking support
- Dependency Injection - Interfaces for custom fetch implementations and streaming handlers
- TypeScript Support - Comprehensive type definitions for AI client development
- Error Handling - Base error classes with validation error support
- Streaming Support - Generic streaming handler interface for real-time responses
- Zero Dependencies - Pure TypeScript interfaces with no runtime dependencies
Installation
npm install @redhat-cloud-services/ai-client-common
Core Interfaces
IAIClient Interface
All AI clients in this workspace implement the IAIClient
interface:
import { IAIClient, ClientInitLimitation, IInitErrorResponse } from '@redhat-cloud-services/ai-client-common';
interface IAIClient<AP extends Record<string, unknown> = Record<string, unknown>, TChunk = unknown> {
constructor(config: IBaseClientConfig<TChunk>);
init(): Promise<{
initialConversationId: string;
conversations: IConversation[];
limitation?: ClientInitLimitation;
error?: IInitErrorResponse;
}>;
sendMessage<TChunk = unknown, T extends Record<string, unknown> = Record<string, unknown>>(
conversationId: string,
message: string,
options?: ISendMessageOptions<T>
): Promise<TChunk | IMessageResponse<AP> | void>;
getDefaultStreamingHandler<TChunk = unknown>(): IStreamingHandler<TChunk> | undefined;
getConversationHistory(conversationId: string, options?: IRequestOptions): Promise<IConversationHistoryResponse<AP>>;
healthCheck(options?: IRequestOptions): Promise<unknown>;
getServiceStatus?(options?: IRequestOptions): Promise<unknown>;
createNewConversation(): Promise<IConversation>;
getInitOptions(): ClientInitOptions;
}
Dependency Injection
Custom Fetch Implementation
Important: Do NOT set 'Content-Type'
headers in your fetchFunction - AI clients manage these internally based on endpoint requirements.
import { IFetchFunction } from '@redhat-cloud-services/ai-client-common';
const customFetch: IFetchFunction = async (input, init) => {
const token = await getAuthToken();
return fetch(input, {
...init,
headers: {
...init?.headers,
'Authorization': `Bearer ${token}`,
},
});
};
Base Client Configuration
import { IBaseClientConfig } from '@redhat-cloud-services/ai-client-common';
const config: IBaseClientConfig = {
baseUrl: 'https://your-ai-service.com',
fetchFunction: customFetch,
defaultStreamingHandler: new CustomStreamingHandler(),
initOptions: {
initializeNewConversation: false
}
};
Lazy Conversation Initialization
The ClientInitOptions
interface provides control over when conversations are created during client initialization.
import { ClientInitOptions } from '@redhat-cloud-services/ai-client-common';
interface ClientInitOptions {
initializeNewConversation?: boolean;
}
Default Behavior (initializeNewConversation: true):
- Client automatically creates/finds a conversation during
init()
- Provides immediate conversation for users to start chatting
- Suitable for most chat interfaces
Lazy Initialization (initializeNewConversation: false):
- Client initializes without creating conversations
- Conversations created only when needed (e.g., first message sent)
- Useful for performance optimization and conditional conversation creation
All AI clients implementing IAIClient
provide this configuration via the getInitOptions()
method.
Client Initialization Responses
The init()
method returns additional information about client limitations and errors:
import { ClientInitLimitation, IInitErrorResponse } from '@redhat-cloud-services/ai-client-common';
type ClientInitLimitation = {
reason: string;
detail?: string;
};
interface IInitErrorResponse {
message: string;
status: number;
}
function isInitErrorResponse(obj: unknown): obj is IInitErrorResponse;
Streaming Support
The streaming interface has been updated to standardize chunk handling across all AI clients. The afterChunk
callback now receives an IStreamChunk
object with standardized structure.
IStreamChunk Interface
import { IStreamChunk } from '@redhat-cloud-services/ai-client-common';
interface IStreamChunk<T extends Record<string, unknown> = Record<string, unknown>> {
answer: string;
additionalAttributes: T;
}
Implementing a Custom Streaming Handler
import { IStreamingHandler, AfterChunkCallback, IStreamChunk } from '@redhat-cloud-services/ai-client-common';
class CustomStreamingHandler<TChunk = unknown> implements IStreamingHandler<TChunk> {
onChunk(chunk: TChunk, afterChunk?: AfterChunkCallback): void {
console.log('Received chunk:', chunk);
if (afterChunk) {
afterChunk({
answer: extractAnswer(chunk),
additionalAttributes: extractAttributes(chunk)
});
}
}
onStart?(conversationId?: string, messageId?: string): void {
console.log('Stream started', { conversationId, messageId });
}
onComplete?(finalChunk: TChunk): void {
console.log('Stream completed:', finalChunk);
}
onError?(error: Error): void {
console.error('Stream error:', error);
}
onAbort?(): void {
console.log('Stream aborted');
}
}
Streaming Request Options
import { ISendMessageOptions, IStreamChunk } from '@redhat-cloud-services/ai-client-common';
const streamingOptions: ISendMessageOptions = {
stream: true,
headers: { 'Custom-Header': 'value' },
signal: abortController.signal,
afterChunk: (chunk: IStreamChunk) => {
console.log('Answer:', chunk.answer);
console.log('Additional data:', chunk.additionalAttributes);
updateUI(chunk.answer);
}
};
Error Handling
Base Error Classes
import {
AIClientError,
AIClientValidationError
} from '@redhat-cloud-services/ai-client-common';
try {
const response = await client.sendMessage(conversationId, message);
} catch (error) {
if (error instanceof AIClientValidationError) {
console.error('Validation errors:', error.validationErrors);
error.validationErrors.forEach(validationError => {
console.log(`Field: ${validationError.loc.join('.')}`);
console.log(`Message: ${validationError.msg}`);
console.log(`Type: ${validationError.type}`);
});
} else if (error instanceof AIClientError) {
console.error(`API Error ${error.status}: ${error.message}`);
console.error('Response data:', error.data);
} else {
console.error('Unexpected error:', error);
}
}
Type Definitions
Request and Response Types
import {
IRequestOptions,
IMessageResponse,
IConversationHistoryResponse,
IConversation
} from '@redhat-cloud-services/ai-client-common';
const options: IRequestOptions = {
headers: { 'Custom-Header': 'value' },
signal: new AbortController().signal
};
interface IMessageResponse<AP = Record<string, unknown>> {
messageId: string;
answer: string;
conversationId: string;
date?: string;
additionalAttributes?: AP;
}
interface IConversation {
id: string;
title: string;
locked: boolean;
}
Compatible Packages
This package provides the foundation for:
Building
Run nx build ai-client-common
to build the library.
Running unit tests
Run nx test ai-client-common
to execute the unit tests via Jest.
Development
This package follows the workspace standards:
- Strict TypeScript with no
any
types
- Zero runtime dependencies
- Comprehensive interface definitions