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

@smarthivelabs-devs/react-ai-nexus

v1.0.0

Published

React hooks for the SmartHive AI Nexus SDK

Readme

@smarthivelabs-devs/react-ai-nexus

React hooks and context provider for the SmartHive AI Nexus. Wraps @smarthivelabs-devs/ai-nexus in idiomatic React patterns — loading states, streaming, error handling, and cleanup are all managed for you.

What this package is: A React-specific layer. Use it in any React 18+ app (Vite, Create React App, Remix, etc.). For Next.js, also see @smarthivelabs-devs/next-ai-nexus. For React Native/Expo, see @smarthivelabs-devs/ai-nexus-expo.


Requirements

  • React ≥ 18
  • @smarthivelabs-devs/ai-nexus ≥ 1.0.0 (peer dependency)

Installation

npm install @smarthivelabs-devs/react-ai-nexus @smarthivelabs-devs/ai-nexus
# or
yarn add @smarthivelabs-devs/react-ai-nexus @smarthivelabs-devs/ai-nexus

Environment Setup

The React hooks never expose your API key to the browser directly — they operate through a client you configure server-side (or via a proxy if needed).

# Never put this in a .env file that ships to the browser (VITE_*, NEXT_PUBLIC_*, etc.)
# For browser-based apps, use next-ai-nexus proxy handler or your own backend relay.
AI_NEXUS_API_KEY=nexus_live_xxxxxxxxxxxxxxxxxxxx

# Optional — only if self-hosting
AI_NEXUS_BASE_URL=https://api.smarthivelabs.dev

For pure client-side apps (no server), point the client at a proxied endpoint:

// Calls your backend /api/nexus/* which injects the real key server-side
const nexus = new AiNexus({ apiKey: 'public', baseUrl: '/api/nexus' });

Setup — AiNexusProvider

Create one AiNexus client and wrap your app. All hooks read the client from context.

// main.tsx (or _app.tsx in Next.js Pages Router)
import { AiNexus } from '@smarthivelabs-devs/ai-nexus';
import { AiNexusProvider } from '@smarthivelabs-devs/react-ai-nexus';

const nexus = new AiNexus({
  apiKey: process.env.AI_NEXUS_API_KEY!,
  // In a browser app pointing at a proxy:
  // baseUrl: '/api/nexus',
});

export default function Root() {
  return (
    <AiNexusProvider client={nexus}>
      <App />
    </AiNexusProvider>
  );
}

All hooks below must be used inside a component tree wrapped by AiNexusProvider. If you forget, you'll get a clear error:

useAiNexus() must be called inside an <AiNexusProvider>.


Hook: useChat

Streaming chat with full message history, RAG support, and abort control.

import { useChat } from '@smarthivelabs-devs/react-ai-nexus';

function ChatWidget() {
  const [input, setInput] = useState('');

  const { messages, isLoading, error, append, reload, stop, setMessages } = useChat({
    model: 'gpt-4o',

    // Optional — inject retrieved documents into each user message automatically
    knowledgeBaseId: 'kb_xyz789',

    // Optional — prepended as the system message on every request
    systemPrompt: 'You are a helpful customer support agent.',

    // Optional — seed the conversation with existing messages
    initialMessages: [{ role: 'assistant', content: 'Hi! How can I help?' }],

    temperature: 0.7,   // optional — 0 to 2
    maxTokens: 1024,    // optional

    onFinish: (message) => {
      console.log('Assistant finished:', message.content);
    },
    onError: (err) => {
      console.error('Chat error:', err.message);
    },
  });

  return (
    <div>
      {messages.map((m, i) => (
        <div key={i} className={m.role === 'user' ? 'user' : 'assistant'}>
          {typeof m.content === 'string' ? m.content : '[multimodal]'}
        </div>
      ))}

      {isLoading && <span>Thinking...</span>}
      {error && <span className="error">{error.message}</span>}

      <input value={input} onChange={e => setInput(e.target.value)} />
      <button onClick={() => { append(input); setInput(''); }} disabled={isLoading}>
        Send
      </button>
      <button onClick={stop} disabled={!isLoading}>Stop</button>
      <button onClick={reload} disabled={isLoading || messages.length === 0}>Retry</button>
    </div>
  );
}

Return values:

| Field | Type | Description | |-------|------|-------------| | messages | ChatMessage[] | Full conversation history including the streaming assistant message | | isLoading | boolean | true while a request is in flight | | error | Error \| null | Last error, if any | | append(content) | (string) => Promise<void> | Add a user message and trigger a completion | | reload() | () => Promise<void> | Re-run the last user message | | stop() | () => void | Abort the current streaming response | | setMessages | Dispatch | Directly update the message list |


Hook: useAgent

Run a named agent with optional session continuity across multiple turns.

import { useAgent } from '@smarthivelabs-devs/react-ai-nexus';

function AgentPanel() {
  const { run, output, sessionId, isLoading, error, reset } = useAgent({
    agentId: 'agent_abc123',
    onFinish: (res) => console.log('Finished. Session:', res.sessionId),
    onError: (err) => console.error(err),
  });

  const handleAsk = async () => {
    // Pass custom context to the agent on each turn
    await run('What are my open tickets?', { userId: 'user_456', tier: 'pro' });
  };

  const handleFollowUp = async () => {
    // sessionId is preserved automatically — next run continues the same session
    await run('Show me only the critical ones.');
  };

  return (
    <div>
      {output && <p>{output}</p>}
      {sessionId && <small>Session: {sessionId}</small>}
      {isLoading && <span>Running agent...</span>}
      {error && <span className="error">{error.message}</span>}
      <button onClick={handleAsk} disabled={isLoading}>Ask</button>
      <button onClick={handleFollowUp} disabled={isLoading || !sessionId}>Follow up</button>
      <button onClick={reset}>New session</button>
    </div>
  );
}

Return values:

| Field | Type | Description | |-------|------|-------------| | run(input, context?) | (string, object?) => Promise<AgentsRunResponse> | Run the agent. Automatically uses sessionId from previous turn. | | output | string \| null | Last response text | | sessionId | string \| null | Current session ID (auto-maintained across turns) | | isLoading | boolean | true while agent is running | | error | Error \| null | Last error | | reset() | () => void | Clear output and start a fresh session next call |


Hook: useVoiceCall

Full realtime voice session lifecycle. Creates a LiveKit session, polls for transcripts, and handles recording.

import { useVoiceCall } from '@smarthivelabs-devs/react-ai-nexus';
import { Room } from 'livekit-client';

function VoiceCallPanel() {
  const roomRef = useRef<Room | null>(null);

  const {
    state,          // 'idle' | 'connecting' | 'active' | 'ending' | 'ended' | 'error'
    sessionId,
    livekitUrl,     // pass to livekit-client Room.connect()
    livekitToken,   // pass to livekit-client Room.connect()
    isMuted,
    toggleMute,
    transcript,     // TranscriptEntry[] — { role, text, timestamp }[]
    error,
    start,
    end,
    startRecording,
    stopRecording,
  } = useVoiceCall({
    agentId: 'agent_abc123',
    mode: 'voice',   // 'voice' | 'text' | 'duplex'
    features: ['transcription', 'tts', 'vad'],

    // How often to poll the server for new transcript entries (ms)
    // Default: 2000
    pollIntervalMs: 2_000,

    onTranscript: (entry) => {
      console.log(`${entry.role} [${entry.timestamp}]: ${entry.text}`);
    },
    onError: (err) => console.error('Voice call error:', err),
  });

  // Connect to LiveKit once the session is active
  useEffect(() => {
    if (state === 'active' && livekitUrl && livekitToken) {
      const room = new Room();
      roomRef.current = room;
      room.connect(livekitUrl, livekitToken).catch(console.error);
      return () => { void room.disconnect(); };
    }
  }, [state, livekitUrl, livekitToken]);

  const handleStopRecording = async () => {
    const url = await stopRecording('mp4');
    console.log('Recording available at:', url);
  };

  return (
    <div>
      <p>Status: <strong>{state}</strong></p>

      {state === 'idle' && (
        <button onClick={start}>Start call</button>
      )}
      {state === 'active' && (
        <>
          <button onClick={end}>End call</button>
          <button onClick={toggleMute}>{isMuted ? 'Unmute' : 'Mute'}</button>
          <button onClick={startRecording}>Record</button>
          <button onClick={handleStopRecording}>Stop recording</button>
        </>
      )}

      {error && <p className="error">{error.message}</p>}

      <div className="transcript">
        {transcript.map((t, i) => (
          <p key={i}><strong>{t.role}</strong>: {t.text}</p>
        ))}
      </div>
    </div>
  );
}

Return values:

| Field | Type | Description | |-------|------|-------------| | state | VoiceCallState | Current lifecycle state | | sessionId | string \| null | Session ID once active | | livekitUrl | string \| null | WebSocket URL for LiveKit room connection | | livekitToken | string \| null | JWT token for LiveKit room connection | | isMuted | boolean | Local mute state (you must wire this to your LiveKit participant) | | toggleMute() | () => void | Toggles isMuted | | transcript | TranscriptEntry[] | Running list of conversation turns | | error | Error \| null | Last error | | start() | () => Promise<void> | Create session, set livekitUrl/livekitToken, begin polling | | end() | () => Promise<void> | End session and stop polling | | startRecording() | () => Promise<void> | Start server-side recording | | stopRecording(format?) | (format?) => Promise<string \| null> | Stop recording, returns URL |

VoiceCallState transitions:

idle → connecting → active → ending → ended
                 ↘ error

Hook: useImages

Generate images with automatic job polling. The hook handles the queued → processing → completed lifecycle.

import { useImages } from '@smarthivelabs-devs/react-ai-nexus';

function ImageGenerator() {
  const { generate, job, isLoading, error } = useImages();

  const handleGenerate = async () => {
    const result = await generate({
      prompt: 'A serene Japanese garden at dawn',
      size: '1024x1024',
      quality: 'hd',
      style: 'natural',
    });
    // result.status === 'completed' here
    console.log(result.data?.[0]?.url);
  };

  return (
    <div>
      <button onClick={handleGenerate} disabled={isLoading}>
        {isLoading ? `Generating... (${job?.status})` : 'Generate'}
      </button>
      {error && <p className="error">{error.message}</p>}
      {job?.status === 'completed' && job.data?.[0]?.url && (
        <img src={job.data[0].url} alt="Generated" />
      )}
    </div>
  );
}

Return values:

| Field | Type | Description | |-------|------|-------------| | generate(params) | (ImagesGenerateParams) => Promise<ImageJob> | Start generation and poll until complete | | job | ImageJob \| null | Live job state (updates every 2 s during processing) | | isLoading | boolean | true while generating or polling | | error | Error \| null | Last error |


Hook: useModeration

Check content before sending it to other APIs or storing it.

import { useModeration } from '@smarthivelabs-devs/react-ai-nexus';

function CommentForm() {
  const { moderate, result, isLoading } = useModeration();
  const [text, setText] = useState('');

  const handleSubmit = async () => {
    const check = await moderate({ input: text });
    if (check.flagged) {
      alert('Content violates policy');
      return;
    }
    // safe to submit
  };

  return (
    <div>
      <textarea value={text} onChange={e => setText(e.target.value)} />
      {result?.flagged && <p className="warning">Content flagged</p>}
      <button onClick={handleSubmit} disabled={isLoading}>Submit</button>
    </div>
  );
}

Hook: useDocuments

Manage a knowledge base: list, ingest, and delete documents.

import { useDocuments } from '@smarthivelabs-devs/react-ai-nexus';

function KnowledgeBasePanel() {
  const { documents, ingest, remove, refresh, isLoading, error } = useDocuments({
    knowledgeBaseId: 'kb_xyz789',  // optional — scope to one KB
    autoFetch: true,               // auto-load on mount (default: true)
  });

  const handleIngest = async () => {
    await ingest({
      storageUrl: 'https://storage.example.com/q1-report.pdf',
      knowledgeBaseId: 'kb_xyz789',
      metadata: { quarter: 'Q1 2026' },
    });
    // list refreshes automatically after ingest
  };

  return (
    <div>
      <button onClick={handleIngest}>Add Document</button>
      <button onClick={refresh}>Refresh</button>
      {isLoading && <span>Loading...</span>}
      {error && <span className="error">{error.message}</span>}
      <ul>
        {documents.map(doc => (
          <li key={doc.documentId}>
            {doc.filename ?? doc.documentId} — {doc.status}
            {doc.status === 'completed' && ` (${doc.chunkCount} chunks)`}
            <button onClick={() => remove(doc.documentId)}>Delete</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

Hook: useEmbeddings

Generate embeddings on demand.

import { useEmbeddings } from '@smarthivelabs-devs/react-ai-nexus';

function EmbeddingsDemo() {
  const { embed, embeddings, isLoading, error } = useEmbeddings();

  const handleEmbed = async () => {
    await embed({
      model: 'text-embedding-3-small',
      input: ['Hello world', 'Goodbye world'],
    });
  };

  return (
    <div>
      <button onClick={handleEmbed} disabled={isLoading}>Embed</button>
      {embeddings && (
        <p>Got {embeddings.data.length} embeddings of size {embeddings.data[0]?.embedding.length}</p>
      )}
    </div>
  );
}

Direct Client Access

For anything not covered by the hooks, call the underlying client directly:

import { useAiNexus } from '@smarthivelabs-devs/react-ai-nexus';

function HealthBadge() {
  const nexus = useAiNexus();
  const [status, setStatus] = useState<string>('checking...');

  useEffect(() => {
    nexus.health.check().then(h => setStatus(h.status));
  }, [nexus]);

  return <span className={`badge badge-${status}`}>{status}</span>;
}

TypeScript

All hook option and return types are exported:

import type {
  UseChatOptions, UseChatReturn,
  UseAgentOptions, UseAgentReturn,
  UseVoiceCallOptions, UseVoiceCallReturn, VoiceCallState, TranscriptEntry,
  UseImagesReturn,
  UseModerationReturn,
  UseDocumentsOptions, UseDocumentsReturn,
} from '@smarthivelabs-devs/react-ai-nexus';

// Shared types from the core SDK
import type { ChatMessage, ImageJob, ModelProfile } from '@smarthivelabs-devs/ai-nexus';

License

MIT — © SmartHive Labs