npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ai-universe/second-opinion-client

v2.1.1

Published

TypeScript client library for AI Universe MCP Server - Complete MCP tool access including multi-model consultation and conversation management

Downloads

75

Readme

@ai-universe/second-opinion-client

TypeScript/JavaScript client library for AI Universe MCP Server - Complete MCP tool access including multi-model consultation, conversation management, and authentication.

Features

  • 🤖 Multi-Model Consultation - Get opinions from Cerebras, Claude, Gemini, Perplexity, OpenAI, and Grok
  • 🔄 Intelligent Synthesis - AI-powered synthesis combining all model responses
  • 💬 Full Conversation Management - Send messages, list conversations, get history, delete conversations
  • 🔐 Firebase Authentication - Built-in authentication with Google sign-in
  • 📊 Rate Limit Management - Check and monitor your rate limits
  • 🏥 Health Checks - Server and conversation service health monitoring
  • 🛡️ Type-Safe - Full TypeScript support with comprehensive types
  • Flexible - Works in Node.js, browsers, and edge runtimes
  • 🎯 Simple API - Intuitive interface with sensible defaults
  • 📋 Complete MCP Access - All backend MCP tools exposed via clean API

Installation

npm install @ai-universe/second-opinion-client

or

yarn add @ai-universe/second-opinion-client

or

pnpm add @ai-universe/second-opinion-client

Quick Start

Basic Usage (Anonymous)

import { SecondOpinionClient } from '@ai-universe/second-opinion-client';

// Create client
const client = new SecondOpinionClient();

// Ask a question
const response = await client.ask('What is machine learning?');

// Access primary model response
console.log(response.primary.response);

// Access secondary opinions
response.secondaryOpinions?.forEach((opinion) => {
  console.log(`${opinion.modelDisplayName}: ${opinion.response}`);
});

// Access multi-model synthesis
console.log(response.synthesis?.response);

Authenticated Usage (Higher Rate Limits)

import { SecondOpinionClient } from '@ai-universe/second-opinion-client';

// Create client with Firebase config (example uses AI Universe production config)
const client = new SecondOpinionClient({
  firebaseConfig: {
    apiKey: 'AIzaSyDWT4aEG2UoKEtTxozniGC6uPZi1fgjtG8',
    authDomain: 'ai-universe-b3551.firebaseapp.com',
    projectId: 'ai-universe-b3551',
  },
});

// Sign in with Google
await client.signInWithGoogle();

// Now make requests with higher rate limits
const response = await client.ask('What is deep learning?');

Follow-up Questions (Conversation Threading)

// First question
const response1 = await client.ask('What is quantum computing?');

// Follow-up question in same conversation
const response2 = await client.ask({
  question: 'How does it differ from classical computing?',
  conversationId: response1.conversationId,
});

// Get conversation history
const history = await client.getConversationHistory(response1.conversationId);

API Reference

Constructor

new SecondOpinionClient(config?: SecondOpinionClientConfig)

Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | baseUrl | string | https://ai-universe-backend-final.onrender.com | Base URL of the AI Universe backend | | firebaseConfig | object | undefined | Firebase configuration for authentication | | timeout | number | 120000 (2 minutes) | Request timeout in milliseconds | | headers | object | {} | Custom headers to include in all requests | | debug | boolean | false | Enable debug logging |

Methods

ask(questionOrOptions)

Ask a question and get multi-model second opinions.

Parameters:

  • questionOrOptions: string | SecondOpinionRequestOptions

Simple Usage:

const response = await client.ask('What is AI?');

Advanced Usage:

const response = await client.ask({
  question: 'What is neural network architecture?',
  primaryModel: 'claude',              // Choose primary model
  secondaryModels: ['gemini', 'grok'], // Choose secondary models
  maxOpinions: 2,                      // Number of secondary opinions (0-10)
  conversationId: 'abc123',            // For follow-up questions
  userId: 'user-123',                  // Optional user ID
});

Request Options:

| Option | Type | Default | Description | |--------|------|---------|-------------| | question | string | required | The question to ask (max 320,000 chars) | | primaryModel | PrimaryModelName | 'cerebras' | Primary model to use | | secondaryModels | SecondaryModelName[] | Auto-selected | Secondary models to consult | | maxOpinions | number | 4 | Number of secondary opinions (0-10) | | conversationId | string | Auto-generated | Conversation ID for follow-ups | | userId | string | Auto-generated | User ID for tracking | | sessionId | string | undefined | Session ID for grouping |

Available Models:

  • Primary Models: cerebras, grok, claude, gemini, perplexity, openai
  • Secondary Models: gemini, perplexity, openai, grok, cerebras

Response:

interface SecondOpinionResponse {
  // Core response data
  primary: ModelOpinion;
  secondaryOpinions?: ModelOpinion[];
  synthesis: Synthesis | null;

  // Conversation tracking
  conversationId: string;
  conversationCreated?: boolean;
  conversationTitle?: string | null;

  // Summary statistics
  summary?: {
    totalModels: number;
    totalTokens: number;
    totalCost: number;
    totalLatencyMs: number;
  };

  // Latency breakdown
  latency?: {
    totalMs: number;
    primary?: number;
    secondary?: number;
    synthesis?: number;
  };

  // Additional metadata
  metadata?: object;
  persistenceStatus?: object;
  thinkingLog?: Array<object>;
}

Model Opinion Structure:

interface ModelOpinion {
  model: string;                    // Model name
  modelDisplayName?: string;        // Human-readable name
  response: string;                 // Model's response
  tokensUsed?: number;             // Tokens consumed
  latencyMs?: number;              // Response time
  cost?: number;                   // API cost
  citations?: CitationSource[];    // Search citations (Perplexity)
  error?: boolean;                 // Error flag
}

Authentication Methods

signInWithGoogle()

Sign in with Google using Firebase Authentication.

const authState = await client.signInWithGoogle();
console.log('User:', authState.user?.displayName);
signOut()

Sign out the current user.

await client.signOut();
getAuthState()

Get current authentication state.

const authState = await client.getAuthState();
if (authState.isAuthenticated) {
  console.log('User:', authState.user?.email);
  console.log('Token expires:', new Date(authState.expiresAt!));
}
isAuthenticated()

Check if user is currently authenticated.

if (client.isAuthenticated()) {
  console.log('User is signed in');
}
onAuthStateChange(callback)

Listen to authentication state changes.

const unsubscribe = client.onAuthStateChange((state) => {
  console.log('Auth state changed:', state.isAuthenticated);
});

// Later, stop listening
unsubscribe();

Conversation Methods

getConversationHistory(conversationId)

Get all messages in a conversation.

const history = await client.getConversationHistory('conversation-id');
history.forEach((message) => {
  console.log(`${message.role}: ${message.content}`);
});
listConversations(userId?)

List user's conversations.

const conversations = await client.listConversations();
conversations.forEach((conv) => {
  console.log(`${conv.title} - ${conv.messageCount} messages`);
});
sendMessage(options)

Send a message to a conversation.

const response = await client.sendMessage({
  content: 'Hello, world!',
  conversationId: 'conv-123', // Optional, auto-creates if omitted
  role: 'user', // Optional, defaults to 'user'
  title: 'My Conversation', // Optional
  metadata: { source: 'web' }, // Optional
});

console.log('Message ID:', response.message.id);
console.log('Assistant reply:', response.assistantMessage?.content);
deleteConversation(conversationId, userId)

Delete a conversation.

await client.deleteConversation('conversation-id', 'user-id');
conversationHealth()

Check conversation service health.

const health = await client.conversationHealth();
console.log('Status:', health.status); // 'healthy' or 'unhealthy'

Authentication & Rate Limiting

getFirebaseInfo()

Get Firebase authentication setup instructions.

const info = await client.getFirebaseInfo();
console.log('Instructions:', info.instructions);
console.log('Config:', info.config);
getRateLimitStatus()

Get current rate limit status (requires authentication).

// Must be authenticated first
await client.signInWithGoogle();

const status = await client.getRateLimitStatus();
console.log('Limit:', status.limit);
console.log('Remaining:', status.remaining);
console.log('Resets at:', new Date(status.resetTime));

Server Health

getServerHealth()

Get MCP server health status (includes all tools).

const health = await client.getServerHealth();
console.log('Server status:', health.status);
console.log('Version:', health.version);
console.log('Services:', health.services);
checkHealth()

Check HTTP server health (simple health check endpoint).

const health = await client.checkHealth();
console.log('Status:', health.status); // 'healthy' or 'unhealthy'

Usage Examples

Example 1: Simple Question

const client = new SecondOpinionClient();
const response = await client.ask('What is machine learning?');

console.log('Primary:', response.primary.response);
console.log('Synthesis:', response.synthesis?.response);

Example 2: Custom Model Selection

const response = await client.ask({
  question: 'What are the latest AI trends?',
  primaryModel: 'perplexity',  // Good for recent info
  secondaryModels: ['claude', 'gemini'],
  maxOpinions: 2,
});

Example 3: Primary-Only Mode (No Synthesis)

const response = await client.ask({
  question: 'Quick factual question',
  maxOpinions: 0,  // Skip secondary opinions and synthesis
});
// Only response.primary will be populated

Example 4: Multi-Turn Conversation

// Start conversation
const r1 = await client.ask('What is blockchain?');

// Follow-up questions
const r2 = await client.ask({
  question: 'How does it ensure security?',
  conversationId: r1.conversationId,
});

const r3 = await client.ask({
  question: 'What are practical applications?',
  conversationId: r1.conversationId,
});

// Get full history
const history = await client.getConversationHistory(r1.conversationId);

Example 5: Error Handling

import {
  SecondOpinionClient,
  ValidationError,
  RateLimitError,
  NetworkError,
  TimeoutError,
} from '@ai-universe/second-opinion-client';

const client = new SecondOpinionClient();

try {
  const response = await client.ask('What is AI?');
} catch (error) {
  if (error instanceof ValidationError) {
    console.error('Invalid request:', error.message);
  } else if (error instanceof RateLimitError) {
    console.error('Rate limit exceeded. Retry after:', error.retryAfter);
  } else if (error instanceof NetworkError) {
    console.error('Network error:', error.message);
  } else if (error instanceof TimeoutError) {
    console.error('Request timed out');
  } else {
    console.error('Unknown error:', error);
  }
}

Example 6: Custom Configuration

const client = new SecondOpinionClient({
  baseUrl: 'http://localhost:2000',  // Local development
  timeout: 60000,                     // 1 minute timeout
  debug: true,                        // Enable debug logs
  headers: {
    'X-Custom-Header': 'value',
  },
});

Example 7: Accessing Citations (Perplexity)

const response = await client.ask({
  question: 'What are recent breakthroughs in AI?',
  primaryModel: 'perplexity',  // Includes citations
});

response.primary.citations?.forEach((citation) => {
  console.log(`${citation.title}: ${citation.url}`);
});

Rate Limits

| User Type | Rate Limit | |-----------|------------| | Anonymous | 10 requests / 5 minutes | | Authenticated | 50 requests / 5 minutes | | Admin | 1000 requests / 5 minutes |

Recommendation: Use authentication for production applications to get higher rate limits.

Error Types

| Error Class | Description | |-------------|-------------| | ValidationError | Request validation failed (empty question, invalid params, etc.) | | RateLimitError | Rate limit exceeded (includes retryAfter in seconds) | | AuthenticationError | Firebase authentication failed | | NetworkError | Network request failed | | TimeoutError | Request exceeded timeout limit | | ApiError | API returned error response (includes status code) | | SecondOpinionClientError | Base error class for all client errors |

TypeScript Support

This library is written in TypeScript and provides full type definitions.

import type {
  SecondOpinionResponse,
  ModelOpinion,
  Synthesis,
  CitationSource,
  AuthState,
  Conversation,
} from '@ai-universe/second-opinion-client';

Browser Support

This library works in modern browsers with ES2020+ support. For older browsers, use a transpiler like Babel.

Note: Firebase Authentication requires browser environment for Google sign-in popup.

Node.js Support

Requires Node.js 18 or later.

Note: Firebase Authentication in Node.js requires additional setup for OAuth flow. Consider using the CLI authentication tool from the main AI Universe repository for server-side usage.

Environment Variables (Optional)

For authenticated usage examples:

export AI_UNIVERSE_FIREBASE_API_KEY="your-api-key"
export AI_UNIVERSE_FIREBASE_AUTH_DOMAIN="your-auth-domain"
export AI_UNIVERSE_FIREBASE_PROJECT_ID="your-project-id"

Development

Build

npm run build

Test

npm test

Lint

npm run lint

Clean

npm run clean

Examples

See the examples/ directory for complete working examples:

  • basic-usage.ts - Anonymous usage examples
  • authenticated-usage.ts - Firebase authentication examples

License

MIT

Support

For issues and questions:

Credits

Built by the AI Universe Team with ❤️