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

@foisit/react-wrapper

v2.4.4

Published

A powerful AI assistant library for React applications, providing seamless chatbot functionality and intelligent interactions for websites.

Readme

@foisit/react-wrapper

npm version License: MIT

The AI-Powered Conversational Assistant for React Applications

Transform your React app into an intelligent, voice-ready platform. Foisit provides a drop-in AI layer that understands natural language, manages multi-step workflows, and executes actions—all with zero backend required.

[!NOTE] > Voice Support Status: Voice recognition and responses are currently in development and will be released in a future update. The current version focuses on high-performance text-based interactions and AI intent matching.


Table of Contents


Features

  • Natural Language Understanding - AI-powered intent matching using GPT-4o mini (proxied securely)
  • Smart Slot Filling - Auto-generates forms for missing parameters
  • Critical Action Protection - Built-in confirmation dialogs for dangerous operations
  • Premium UI - Glassmorphic overlay with dark/light mode support
  • Zero Backend Required - Secure proxy architecture keeps API keys server-side
  • React Native - Uses Hooks, Context API, and modern React patterns
  • Type-Safe - Full TypeScript support with comprehensive types
  • Responsive - Works flawlessly on desktop and mobile

Installation

npm install @foisit/react-wrapper

Peer Dependencies

{
  "react": "^18.0.0",
  "react-dom": "^18.0.0"
}

Quick Start

Step 1: Wrap Your App

import React from 'react';
import { AssistantProvider } from '@foisit/react-wrapper';

const config = {
  introMessage: 'Welcome! How can I assist you today?',
  enableSmartIntent: true,
  commands: [
    {
      command: 'navigate to profile',
      action: () => {
        window.location.href = '/profile';
        return 'Navigating to profile...';
      },
    },
  ],
};

function App() {
  return (
    <AssistantProvider config={config}>
      <YourApp />
    </AssistantProvider>
  );
}

export default App;

Step 2: Use the Hook

import React from 'react';
import { useAssistant } from '@foisit/react-wrapper';

function MyComponent() {
  const assistant = useAssistant();

  return <button onClick={() => assistant.toggle()}>Open Assistant</button>;
}

Core Concepts

1. Commands

Commands are the building blocks of your assistant. Each command represents an action users can trigger through natural language.

{
  command: 'delete account',
  description: 'Permanently delete user account',
  action: () => accountService.delete()
}

2. Parameters (Slot Filling)

Define parameters and Foisit will automatically generate forms to collect them:

{
  command: 'create user',
  description: 'Create a new user account',
  parameters: [
    { name: 'username', type: 'string', required: true },
    { name: 'email', type: 'string', required: true },
    { name: 'age', type: 'number', required: false }
  ],
  action: (params) => userService.create(params)
}

Enterprise-safe param collection controls

  • collectRequiredViaForm (default: true): force missing/invalid required params to be collected via a form instead of conversational guessing.
  • allowAiParamExtraction (default: true): when false, ignore AI-extracted params and always prompt the user for required fields.

Example:

{
  command: 'secure create user',
  description: 'No AI guessing, form-only',
  collectRequiredViaForm: true,
  allowAiParamExtraction: false,
  parameters: [
    { name: 'fullName', type: 'string', required: true },
    { name: 'email', type: 'string', required: true },
    { name: 'age', type: 'number', required: true, min: 18 },
  ],
  action: (params) => userService.create(params),
}

Supported Parameter Types:

  • string - Text input
  • number - Numeric input
  • date - Date picker
  • select - Dropdown (static or async options)
  • file - File upload input

3. File Parameters

Collect files via the built-in form UI and receive them in your command action.

{
  command: 'upload file',
  description: 'Pick a file and return it to the action',
  parameters: [
    {
      name: 'attachment',
      type: 'file',
      required: true,
      accept: ['image/*', 'audio/*', 'video/*'],
      multiple: false,
      // delivery: 'file' | 'base64' (default: 'file')
      delivery: 'file',
    },
  ],
  action: async (params) => {
    const file = params?.attachment as File | undefined;
    if (!file) return { type: 'error', message: 'No file provided.' };
    return {
      type: 'success',
      message: `File received. Name: ${file.name}, Type: ${file.type || 'unknown'}, Size: ${file.size} bytes`,
    };
  },
}

FileParameter supports validations like maxFiles, maxSizeBytes, maxTotalBytes, and media/image constraints like maxDurationSec, maxWidth, and maxHeight.

4. Critical Actions

Protect dangerous operations with automatic confirmation dialogs:

{
  command: 'delete all data',
  critical: true, // Requires confirmation
  description: 'Permanently delete all application data',
  action: async () => {
    await dataService.deleteAll();
    return 'All data deleted successfully.';
  }
}

5. Select Parameters (Static)

Provide predefined options:

{
  command: 'set theme',
  parameters: [{
    name: 'theme',
    type: 'select',
    options: [
      { label: 'Light Mode', value: 'light' },
      { label: 'Dark Mode', value: 'dark' },
      { label: 'Auto', value: 'auto' }
    ]
  }],
  action: (params) => setTheme(params.theme)
}

6. Dynamic Select Parameters

Load options from APIs:

{
  command: 'assign to user',
  parameters: [{
    name: 'userId',
    type: 'select',
    getOptions: async () => {
      const users = await userService.getAll();
      return users.map(u => ({
        label: `${u.name} (${u.email})`,
        value: u.id
      }));
    }
  }],
  action: (params) => taskService.assign(params.userId)
}

API Reference

useAssistant() Hook

React hook for programmatic control:

Methods

toggle(onSubmit?, onClose?)

Opens or closes the assistant overlay.

const assistant = useAssistant();

// Basic usage
assistant.toggle();

// With callbacks
assistant.toggle(
  (userInput) => console.log('User said:', userInput),
  () => console.log('Assistant closed')
);
addCommand(command, action?)

Dynamically add or update a command at runtime. Commands added via addCommand take effect immediately; they are stored in memory for the current session. Re-register commands on app initialization if you need them after a full page reload.

// Add a simple command
assistant.addCommand('refresh data', async () => {
  await dataService.refresh();
  return 'Data refreshed!';
});

// Add a command with full config
assistant.addCommand({
  command: 'export report',
  description: 'Export data as PDF',
  parameters: [
    {
      name: 'format',
      type: 'select',
      options: [
        { label: 'PDF', value: 'pdf' },
        { label: 'Excel', value: 'xlsx' },
      ],
    },
  ],
  action: async (params) => {
    await reportService.export(params.format);
    return `Report exported as ${params.format}`;
  },
});

Dynamic Updates (Add / Remove / Update commands at runtime) ✅

  • addCommand registers or can replace commands for the current session.
  • removeCommand(commandPhrase) removes a registered command immediately.
  • For one-off commands created inside components, unregister them in a cleanup effect (React's useEffect cleanup) to avoid leaking commands.

Example — add/remove a temporary command:

useEffect(() => {
  assistant.addCommand('temp action', () => 'Temp action');
  return () => assistant.removeCommand('temp action');
}, [assistant]);

Notes:

  • If a command has optional params and is invoked with no params, you may return a form InteractiveResponse to prompt for the values.
  • Commands are not persisted across reloads by default; store and re-register them if needed.
removeCommand(commandPhrase)

Remove a registered command.

assistant.removeCommand('delete account');
getCommands()

Get list of all registered command names.

const commands = assistant.getCommands();
console.log('Available commands:', commands);

Configuration Options

AssistantConfig

interface AssistantConfig {
  // Activation keyword (optional)
  activationCommand?: string;

  // Welcome message shown when assistant opens
  introMessage?: string;

  // Response for unrecognized inputs
  fallbackResponse?: string;

  // Enable AI-powered natural language understanding
  enableSmartIntent?: boolean;

  // Input field placeholder text
  inputPlaceholder?: string;

  // List of commands
  commands: AssistantCommand[];

  // Floating button configuration
  floatingButton?: {
    visible?: boolean;
    tooltip?: string;
    customHtml?: string;
    position?: { bottom: string; right: string };
  };
}

Advanced Usage

Example 1: Multi-Step Booking System with State

import React, { useState } from 'react';
import { useAssistant, AssistantProvider } from '@foisit/react-wrapper';

function BookingApp() {
  const [bookings, setBookings] = useState([]);
  const assistant = useAssistant();

  React.useEffect(() => {
    assistant.addCommand({
      command: 'book appointment',
      description: 'Schedule a new appointment',
      parameters: [
        {
          name: 'service',
          type: 'select',
          required: true,
          getOptions: async () => {
            const services = await fetch('/api/services').then((r) => r.json());
            return services.map((s) => ({
              label: s.name,
              value: s.id,
            }));
          },
        },
        {
          name: 'date',
          type: 'date',
          required: true,
        },
        {
          name: 'notes',
          type: 'string',
          required: false,
        },
      ],
      action: async (params) => {
        const booking = await fetch('/api/bookings', {
          method: 'POST',
          body: JSON.stringify(params),
        }).then((r) => r.json());

        setBookings((prev) => [...prev, booking]);
        return {
          type: 'success',
          message: `✅ Appointment booked for ${params.date}!`,
        };
      },
    });
  }, [assistant]);

  return (
    <div>
      <h1>My Bookings: {bookings.length}</h1>
      <button onClick={() => assistant.toggle()}>Book New Appointment</button>
    </div>
  );
}

Example 2: E-Commerce with React Router

import { useNavigate } from 'react-router-dom';
import { useAssistant } from '@foisit/react-wrapper';

function ProductSearch() {
  const navigate = useNavigate();
  const assistant = useAssistant();

  React.useEffect(() => {
    assistant.addCommand({
      command: 'search products',
      parameters: [
        { name: 'query', type: 'string', required: true },
        {
          name: 'category',
          type: 'select',
          required: false,
          options: [
            { label: 'Electronics', value: 'electronics' },
            { label: 'Clothing', value: 'clothing' },
            { label: 'Books', value: 'books' },
          ],
        },
        { name: 'minPrice', type: 'number', required: false },
      ],
      action: async (params) => {
        const results = await searchProducts(params);
        navigate(`/products?q=${params.query}`);
        return `Found ${results.length} products matching "${params.query}"`;
      },
    });
  }, [assistant, navigate]);

  return <div>Search component</div>;
}

Example 3: Form Validation with State Management

import { useState } from 'react';
import { useAssistant } from '@foisit/react-wrapper';

function AccountManager() {
  const [user, setUser] = useState(null);
  const assistant = useAssistant();

  React.useEffect(() => {
    assistant.addCommand({
      command: 'create account',
      parameters: [
        { name: 'email', type: 'string', required: true },
        { name: 'password', type: 'string', required: true },
        { name: 'age', type: 'number', required: true },
      ],
      action: async (params) => {
        // Validation
        if (params.age < 18) {
          return {
            type: 'error',
            message: '❌ You must be 18 or older to create an account.',
          };
        }

        if (!params.email.includes('@')) {
          return {
            type: 'error',
            message: '❌ Please provide a valid email address.',
          };
        }

        // Create account
        try {
          const newUser = await authService.register(params);
          setUser(newUser);
          return {
            type: 'success',
            message: '✅ Account created successfully! You can now log in.',
          };
        } catch (error) {
          return {
            type: 'error',
            message: `❌ Registration failed: ${error.message}`,
          };
        }
      },
    });
  }, [assistant]);

  return <div>{user ? `Welcome ${user.email}` : 'No user'}</div>;
}

TypeScript Support

Full Type Definitions

// Type-safe command definition
const myCommand: AssistantCommand = {
  command: 'update settings',
  description: 'Update user preferences',
  parameters: [
    {
      name: 'theme',
      type: 'select',
      required: true,
      options: [
        { label: 'Light', value: 'light' },
        { label: 'Dark', value: 'dark' },
      ],
    },
  ],
  action: async (params: { theme: string }): Promise<InteractiveResponse> => {
    await settingsService.update(params.theme);
    return {
      type: 'success',
      message: `Theme updated to ${params.theme}`,
    };
  },
};

Hook Types

import { useAssistant } from '@foisit/react-wrapper';

const assistant = useAssistant();
// assistant is typed as AssistantServiceType

Best Practices

1. Cleanup Effects

Always clean up commands when components unmount:

useEffect(() => {
  assistant.addCommand('temp command', () => 'Done');

  return () => {
    assistant.removeCommand('temp command');
  };
}, [assistant]);

2. Dependency Management

Include all dependencies in useEffect:

useEffect(() => {
  assistant.addCommand('navigate', () => {
    navigate('/page'); // Uses navigate from React Router
  });
}, [assistant, navigate]); // ✅ Include navigate

3. State Updates

Use functional updates for state changes:

action: async () => {
  setItems((prev) => [...prev, newItem]); // ✅ Functional update
  return 'Item added';
};

4. Error Boundaries

Wrap your app with error boundaries:

<ErrorBoundary>
  <AssistantProvider config={config}>
    <App />
  </AssistantProvider>
</ErrorBoundary>

Testing

Unit Testing with React Testing Library

import { render, screen } from '@testing-library/react';
import { AssistantProvider } from '@foisit/react-wrapper';

test('renders assistant', () => {
  render(
    <AssistantProvider config={{ commands: [] }}>
      <App />
    </AssistantProvider>
  );

  // Test your app with assistant
});

Related Packages


Troubleshooting

Hook error: "useAssistant must be used within AssistantProvider"

Make sure your component is wrapped with <AssistantProvider>.

Commands not executing

Check browser console for errors. Ensure action functions are returning values or promises.

TypeScript errors

Make sure you're using React 18+ and have proper type definitions.


License

MIT © Foisit


Contributing

Contributions are welcome! Please read our Contributing Guide first.


Support


Made with ❤️ by the Foisit Team