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

@coreexl/mentor

v0.1.1

Published

A fully customizable, reusable mentor/chat interface component built with React, Next.js, and TypeScript

Downloads

65

Readme

@coreexl/mentor

A fully customizable, reusable mentor/chat interface component built with React, Next.js, and TypeScript. Features real-time AI voice and text chat with WebRTC integration via Pipecat AI.

Features

  • Voice & Text Chat: Seamlessly switch between voice and text interactions
  • Tool/Function Calling: Execute custom functions via LLM tool calls with visual status indicators
  • Auto-resize Input: Chat input automatically grows with content
  • Fully Customizable: Configure agent name, title, description, and avatar
  • Real-time Audio: WebRTC-powered voice communication with AI
  • Responsive Design: Mobile-first design with smooth animations
  • TypeScript Support: Full type safety and IntelliSense
  • Easy Integration: Drop-in component with minimal setup

Installation

npm install @coreexl/mentor

Quick Start

1. Set Environment Variables (Strongly Recommended)

Environment variables are the preferred method for configuration as they:

  • Keep sensitive data like access keys secure
  • Allow easy configuration across different environments (dev, staging, production)
  • Reduce code duplication and hardcoded values
  • Can be managed through your deployment platform

Create a .env.local file in your project root:

# Required: Your CoreEXL access key
NEXT_PUBLIC_ACCESS_KEY=your_access_key_here

# Required: Your server URL
NEXT_PUBLIC_COREEXL_MENTOR_SERVER=https://your-server-url.com

2. Basic Usage (Using Environment Variables)

import { MentorPage } from '@coreexl/mentor'
import '@coreexl/mentor/mentor.css'

function App() {
  return (
    <MentorPage
      // No need to pass accessKey or serverUrl - they're read from env vars!
      agentName="Coach Sarah"
      agentTitle="Learning Assistant"
      systemPrompt="You are Sarah, a helpful learning coach who assists students with their studies. Be encouraging and provide clear explanations."
      avatarSrc="/coach-sarah-avatar.jpg"
      userId="user123"
      onConnect={() => console.log('Connected to mentor')}
      onMessage={(msg) => console.log('New message:', msg)}
      onVoiceChange={(voice) => console.log('Voice changed to:', voice)}
    />
  )
}

🔒 Security Best Practice: Always use environment variables for sensitive configuration like access keys. Only use props for dynamic values that change at runtime.

Advanced Usage

Using Props Instead of Environment Variables

While environment variables are recommended, you can pass configuration as props when necessary (e.g., for dynamic values that change at runtime):

<MentorPage
  accessKey="your-access-key"  // ⚠️ Avoid hardcoding - use env vars instead
  serverUrl="https://your-server-url.com"  // ⚠️ Prefer env vars
  agentName="Coach Sarah"
  agentTitle="Learning Assistant"
  systemPrompt="Your custom prompt here..."
  // ... other props
/>

Override Environment Variables

Props take precedence over environment variables when you need runtime flexibility:

<MentorPage
  accessKey="runtime-access-key" // Overrides NEXT_PUBLIC_ACCESS_KEY
  serverUrl="https://different-server.com" // Overrides NEXT_PUBLIC_COREEXL_MENTOR_SERVER
  agentName="Dynamic Agent"
  // ... other props
/>

Event Handling

<MentorPage
  agentName="Coach Timothy"
  onConnect={() => console.log('Mentor connected!')}
  onDisconnect={() => console.log('Mentor disconnected')}
  onMessage={(message) => console.log('Message received:', message)}
  onVoiceChange={(voice) => console.log('Voice changed to:', voice)}
/>

Tool/Function Calling

Enable the AI mentor to execute custom functions:

import { MentorPage, Tool, ToolCall } from '@coreexl/mentor'

const tools: Tool[] = [
  {
    type: 'function',
    function: {
      name: 'get_weather',
      description: 'Get current weather for a location',
      parameters: {
        type: 'object',
        properties: {
          location: { type: 'string', description: 'City name' }
        },
        required: ['location']
      }
    }
  }
]

const handleToolCall = async (toolCall: ToolCall) => {
  if (toolCall.name === 'get_weather') {
    const { location } = toolCall.arguments as { location: string }
    const weather = await fetchWeather(location)
    return { temperature: weather.temp, conditions: weather.conditions }
  }
}

<MentorPage
  agentName="Weather Assistant"
  tools={tools}
  onToolCall={handleToolCall}
  toolCallAutoDismiss={true} // Auto-hide tool status after 5 seconds (default: true)
/>

Responsive Design

The component is fully responsive and adapts to different screen sizes:

  • Mobile: Optimized touch interface with larger buttons
  • Tablet: Balanced layout with appropriate spacing
  • Desktop: Full feature set with optimal viewing experience

Responsive Breakpoints

// The component uses Tailwind's responsive prefixes internally:
// - sm: 640px
// - md: 768px
// - lg: 1024px
// - xl: 1280px

Common Use Cases

1. Full-Page Learning Assistant

import { MentorPage } from '@coreexl/mentor'
import '@coreexl/mentor/mentor.css'

export default function LearningPage() {
  return (
    <div className="h-screen w-screen">
      <MentorPage
        agentName="Professor AI"
        agentTitle="Computer Science Tutor"
        systemPrompt="You are an expert computer science tutor..."
      />
    </div>
  )
}

2. Embedded Chat Widget

<div className="fixed bottom-4 right-4 z-50">
  <MentorPage
    agentName="Support Agent"
    styles={{
      container: {
        height: '500px',
        width: '380px'
      }
    }}
  />
</div>

3. Side-by-Side with Content

<div className="flex h-screen">
  <div className="w-1/2 p-4">
    {/* Your content here */}
  </div>
  <div className="w-1/2">
    <MentorPage agentName="Study Buddy" />
  </div>
</div>

Props

| Prop | Type | Required | Description | |------|------|----------|-------------| | accessKey | string | Conditional* | Your CoreEXL access key (prefer NEXT_PUBLIC_ACCESS_KEY env var) | | serverUrl | string | Conditional* | Your server URL (prefer NEXT_PUBLIC_COREEXL_MENTOR_SERVER env var) | | agentName | string | No | Name of the AI mentor (default: "Coach Timothy") | | agentTitle | string | No | Title/role of the mentor (default: "Concept Coach") | | systemPrompt | string | No | Custom instructions for the AI mentor | | avatarSrc | string | No | URL for mentor's avatar image | | userId | string | No | Unique identifier for the user | | styles | MentorPageStyles | No | Style customization for layout and components | | className | string | No | Additional CSS classes for root container | | debug | boolean | No | Enable debug logging (default: false) | | tools | Tool[] | No | Tool/function definitions for LLM to call | | onToolCall | (toolCall: ToolCall) => Promise<unknown> | No | Handler for tool calls from LLM | | toolCallAutoDismiss | boolean | No | Auto-hide tool status in chat (default: true) | | onConnect | () => void | No | Callback when voice connection establishes | | onDisconnect | () => void | No | Callback when voice connection ends | | onMessage | (message: MentorMessage) => void | No | Callback for new messages | | onVoiceChange | (voice: VoiceName) => void | No | Callback when voice changes |

Customization

Container Styling

By default, the component uses 100% width and height to fill its parent container. You can customize the layout and appearance using the styles prop:

<MentorPage
  agentName="Coach Sarah"
  styles={{
    container: {
      height: '600px',        // Default: '100%'
      width: '800px',         // Default: '100%'
      maxWidth: '1200px',     // Optional max width
      minHeight: '400px',     // Default: '100%'
      padding: '20px',        // Optional padding
      className: 'custom-container' // Additional CSS classes
    },
    chatPanel: {
      height: '500px',        // Optional fixed height
      className: 'custom-chat-panel'
    },
    voicePanel: {
      height: '500px',        // Optional fixed height
      className: 'custom-voice-panel'
    },
    inputArea: {
      className: 'custom-input' // Style the input area
    },
    messageList: {
      maxHeight: '400px',     // Control message list scroll height
      className: 'custom-messages'
    }
  }}
/>

Full-Screen Example

// Full viewport height and width (default behavior)
<div style={{ height: '100vh', width: '100vw' }}>
  <MentorPage agentName="Coach Sarah" />
</div>

Embedded Widget Example

// Fixed size embedded widget
<MentorPage
  agentName="Coach Sarah"
  styles={{
    container: {
      height: '500px',
      width: '400px',
      maxWidth: '100%'
    }
  }}
/>

Custom CSS Classes

You can apply custom CSS classes at multiple levels:

<MentorPage
  agentName="Coach Sarah"
  className="my-root-class"  // Root container
  styles={{
    container: { className: 'my-container' },
    chatPanel: { className: 'my-chat' },
    voicePanel: { className: 'my-voice' },
    inputArea: { className: 'my-input' },
    messageList: { className: 'my-messages' }
  }}
/>

TypeScript Types

interface MentorMessage {
  id: string;
  text: string;
  timestamp: number;
  isUser: boolean;
}

type VoiceName = 'Arjun' | 'Priya' | 'Raj' | 'Ananya';

interface Tool {
  type: 'function';
  function: {
    name: string;
    description?: string;
    parameters?: {
      type: 'object';
      properties?: Record<string, ToolParameter>;
      required?: string[];
    };
  };
}

interface ToolCall {
  id: string;
  name: string;
  arguments: Record<string, unknown>;
}

interface MentorPageStyles {
  container?: {
    height?: string;
    width?: string;
    maxWidth?: string;
    minHeight?: string;
    padding?: string;
    className?: string;
  };
  chatPanel?: {
    height?: string;
    className?: string;
  };
  voicePanel?: {
    height?: string;
    className?: string;
  };
  inputArea?: {
    className?: string;
  };
  messageList?: {
    maxHeight?: string;
    className?: string;
  };
}

* Required if not set via environment variables. The component prioritizes environment variables (NEXT_PUBLIC_ACCESS_KEY and NEXT_PUBLIC_COREEXL_MENTOR_SERVER) over props. We strongly recommend using environment variables for security and maintainability.

Development

# Build the package
npm run build

# Test locally
npm run preview