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 🙏

© 2025 – Pkg Stats / Ryan Hefner

react-native-ajora

v0.0.33

Published

The most complete AI agent UI for React Native

Readme

🤖 React Native Ajora

The most complete AI agent UI for React Native

npm version License: MIT TypeScript React Native

Build beautiful, intelligent chat interfaces with AI agents in React Native


✨ Features

  • 🎨 Beautiful UI Components - Pre-built, customizable chat components with modern design
  • 🧠 AI Agent Ready - Built specifically for AI agent interactions with streaming responses
  • 🎯 TypeScript Support - Full TypeScript definitions for all components and props
  • 🔧 Highly Customizable - Extensive prop system and render functions for complete customization
  • 💬 Rich Media Support - Full support for images,and files with lightbox viewing
  • 🧵 Thread Management - Multi-conversation support with persistent thread history
  • ⌨️ Smart Keyboard - Intelligent keyboard handling with React Native Keyboard Controller
  • 🎭 Smooth Animations - Native animations powered by React Native Reanimated 3
  • 🔌 Built-in AI Tools - Native tools including todo lists, and web search
  • 📎 File Upload System - Complete file upload
  • 📊 Thinking Indicators - Beautiful animated thinking indicators for AI processing states
  • 🔄 Function Calling - Full support for AI function calls with custom tool UI integration
  • 🎛️ Server/Client Tools - Support for both server-executed and client-side interactive tools
  • 🔄 Message Streaming - Real-time streaming message updates via Server-Sent Events

🚀 Quick Start

Installation

npm install react-native-ajora
# or
yarn add react-native-ajora

Peer Dependencies

Make sure you have these peer dependencies installed:

npm install @expo/vector-icons @expo/react-native-action-sheet react-native-keyboard-controller react-native-reanimated expo-document-picker expo-image-picker

Basic Usage

import React from "react";
import { SafeAreaView } from "react-native-safe-area-context";
import { Ajora, AjoraProvider } from "react-native-ajora";

const App = () => {
  return (
    <AjoraProvider
      baseUrl="http://localhost:3000" // Your backend server URL
      bearerToken="your-auth-token" // Optional authentication token
      debug={true} // Optional debug mode
    >
      <SafeAreaView style={{ flex: 1 }}>
        <Ajora
          showHeader={true}
          showThreads={true}
          isScrollToBottomEnabled={true}
          keyboardShouldPersistTaps="never"
          infiniteScroll={true}
          onSend={(messages) => {
            console.log("New messages:", messages);
          }}
          onUpload={async ({ file, onProgress, onSuccess, onError }) => {
            // Handle file upload with progress tracking
            try {
              const uploadedUrl = await uploadFile(file.fileUri, onProgress);
              onSuccess(uploadedUrl);
            } catch (error) {
              onError(error);
            }
          }}
        />
      </SafeAreaView>
    </AjoraProvider>
  );
};

export default App;

📖 Documentation

Core Components

Ajora

The main chat component that orchestrates all other components.

const App = () => {
  const onUpload = async ({
    file,
    onProgress,
    onSuccess,
    onError,
  }: OnUploadProps) => {
    try {
      const { fileUri, displayName, mimeType } = file;
      const uploadedUrl = await uploadToCloudinary(fileUri, onProgress);
      onProgress?.(100, true);
      onSuccess?.(uploadedUrl);
    } catch (error) {
      onError?.(error);
    }
  };
  return (
    <SafeAreaView style={{ flex: 1 }}>
      <Ajora
        isScrollToBottomEnabled
        keyboardShouldPersistTaps="never"
        infiniteScroll
        onUpload={onUpload}
      />
    </SafeAreaView>
  );
};

export default App;

Message Types

interface IMessage {
  _id: string;
  thread_id: string;
  role: "user" | "model";
  parts: Part[];
  createdAt?: string;
  updatedAt?: string;
}

// Part interface from @google/genai
interface Part {
  text?: string; // Text content
  inlineData?: {
    mimeType: string;
    data: string; // Base64 encoded data
  };
  fileData?: {
    mimeType: string;
    fileUri: string;
    displayName?: string;
  };
  functionCall?: FunctionCall; // AI tool/function call
  functionResponse?: FunctionResponse; // Tool response
}

interface FunctionCall {
  id?: string;
  args?: Record<string, unknown>;
  name?: string;
  response?: any; // Merged response data
}

interface FunctionResponse {
  id?: string;
  name?: string;
  response?: Record<string, unknown>;
}

Advanced Features

Thread Management

import { Thread } from "react-native-ajora";

<Ajora
  showHeader={true}
  showThreads={true}
  onThreadSelect={(thread: Thread) => {
    console.log("Selected thread:", thread);
    // Thread switching is handled automatically
  }}
  onNewThread={() => {
    console.log("Creating new thread");
    // New thread creation is handled automatically
  }}
  onHeaderMenuPress={() => {
    // Custom header menu action (opens thread drawer by default)
  }}
  onHeaderPlusPress={() => {
    // Custom plus button action (creates new thread by default)
  }}
/>;

Built-in AI Tools

The library includes several native tools that work out of the box:

These tools are automatically available:

  • todo_list: Interactive todo list management
  • search_web: Web search functionality

The AI can use these tools automatically in function calls

Custom Tools Integration

// Create custom tool UI components
const CustomTimeTool = ({ request, submitQuery, onResponse }) => {
  const { tool } = request;
  const { timezone } = tool.args || {};

  return (
    <View>
      <Text>Getting time for: {timezone}</Text>
      {/* Your custom tool UI */}
    </View>
  );
};

<Ajora
  tools={() => [
    <CustomTimeTool key="get_current_time" toolName="get_current_time" />,
  ]}
/>;

API Service

The ApiService class provides a comprehensive interface for communicating with AI agent servers via REST endpoints and Server-Sent Events (SSE) for real-time streaming.

Configuration

import { ApiService } from "react-native-ajora";

const apiService = new ApiService({
  baseUrl: "https://your-api-server.com",
  bearerToken: "your-auth-token", // Optional
  debug: true, // Optional, enables detailed logging
});

Base URL Handling

The baseUrl you provide is intelligently processed:

  • Automatic /api appending: If your URL doesn't contain /api anywhere, it will be automatically appended

    • "https://myserver.com""https://myserver.com/api"
    • "https://myserver.com/v1""https://myserver.com/v1/api"
  • Preserves existing API paths: If your URL already contains /api, it remains unchanged

    • "https://myserver.com/api""https://myserver.com/api"
    • "https://myserver.com/api/v3/agent""https://myserver.com/api/v3/agent"
  • Trailing slash normalization: Trailing slashes are automatically removed for consistency

Streaming Responses

const cleanup = apiService.streamResponse(
  {
    type: "text",
    message: {
      _id: "1",
      role: "user",
      parts: [{ text: "Hello, AI!" }],
      createdAt: new Date(),
    },
  },
  {
    onChunk: (event) => {
      console.log("New message chunk:", event.message);
    },
    onFunctionResponse: (event) => {
      console.log("Tool response:", event.message);
    },
    onComplete: (event) => {
      console.log("Stream completed");
    },
    onError: (error) => {
      console.error("Stream error:", error);
    },
  }
);

// Clean up when done
cleanup();

Thread Management

// Get all threads
const threads = await apiService.getThreads();

// Create a new thread
const newThread = await apiService.createThread("My New Conversation");

// Get messages from a thread
const { messages, pagination } = await apiService.getMessages(
  "thread-id",
  20,
  0
);

Current Feature Support

✅ Currently Supported:

  • Text Messages: Full support for text-based conversations
  • Image Messages: Upload and display images in conversations with lightbox viewing
  • File Attachments: Support for document and file sharing (PDF, etc.)
  • Tool/Function Calls: Complete integration with AI tools and function calling
  • Server-Sent Events: Real-time streaming responses
  • Thread Management: Multi-conversation support
  • Authentication: Bearer token support
  • File Upload Progress: Real-time upload progress tracking with error handling

Custom Styling

<Ajora
  messagesContainerStyle={{
    backgroundColor: "#f0f0f0",
  }}
  renderBubble={(props) => <CustomBubble {...props} />}
  renderInputToolbar={(props) => <CustomInputToolbar {...props} />}
  renderMessage={(props) => <CustomMessage {...props} />}
  renderMessageText={(props) => <CustomMessageText {...props} />}
  renderHeader={(props) => <CustomHeader {...props} />}
  renderThread={(props) => <CustomThread {...props} />}
  renderMessageActions={(props) => <CustomMessageActions {...props} />}
/>

Using the Hook Directly

For advanced use cases, you can use the useAjora hook directly:

import { useAjora } from "react-native-ajora";

const MyCustomChat = () => {
  const ajora = useAjora({
    baseUrl: "http://localhost:3000",
    bearerToken: "your-token",
    debug: true,
  });

  const {
    messagesByThread,
    threads,
    activeThreadId,
    isThinking,
    submitQuery,
    addNewThread,
    switchThread,
    stopStreaming,
    regenerateMessage,
  } = ajora;

  return (
    // Your custom chat UI
  );
};

Server Integration

The library expects a server that handles AI agent interactions:

// Server endpoints expected:
// GET /api/threads - Get user's conversation threads
// POST /api/threads - Create new thread
// GET /api/threads/:id/messages - Get messages for thread
// GET /api/stream - Stream AI response via Server-Sent Events (SSE)

// Example message format for API:
const userMessage = {
  type: "text", // or "attachement", "function_response", "regenerate"
  message: {
    _id: "unique-id",
    thread_id: "thread-id",
    role: "user",
    parts: [{ text: "Hello!" }],
    createdAt: new Date().toISOString(),
  },
  mode: "assistant", // or "agent"
};

🎨 Screenshots

Chat Interface Beautiful chat interface with AI agent

Thread Management Multi-thread conversation management

Advanced Features Advanced AI agent features and tools

Custom Styling Customizable interface and theming

🔧 Configuration

Keyboard Handling

<Ajora
  keyboardShouldPersistTaps="never" // "always" | "never" | "handled"
  focusOnInputWhenOpeningKeyboard={true}
  isKeyboardInternallyHandled={true}
  bottomOffset={0} // Distance from screen bottom
/>

Event Callbacks

<Ajora
  onSend={(messages) => console.log("Sent:", messages)}
  onLoadEarlier={() => console.log("Loading earlier messages")}
  onPress={(context, message) => console.log("Message pressed")}
  onLongPress={(context, message) => console.log("Message long pressed")}
  onInputTextChanged={(text) => console.log("Input changed:", text)}
  onPressActionButton={() => console.log("Action button pressed")}
/>

🛠️ Development

Prerequisites

  • Node.js >= 18
  • React Native development environment
  • Expo CLI (for example app)

Setup

  1. Clone the repository:
git clone https://github.com/habasefa/react-native-ajora.git
cd react-native-ajora
  1. Install dependencies:
npm install
  1. Start the example app:
npm start

Building

npm run build

📚 Examples

Check out the included example applications:

Example App (example-app/)

  • Complete Expo App - Full React Native app with Ajora integration
  • Native Tools Demo - Showcases built-in AI tools (todo, search, confirm)
  • Thread Management - Multi-conversation interface
  • Custom Styling - Themed components and layouts
  • Media Support - Image, audio, and file message examples with upload functionality

Example Server (example-server/)

  • Node.js Backend - Complete server implementation for AI agents
  • Gemini AI Integration - Example using Google's Gemini AI
  • Tool Execution - Server-side tool handling
  • SSE Streaming - Real-time message streaming
  • Database Integration - Message and thread persistence
  • File Upload Handling - Complete file upload system with progress tracking

To run the examples:

# Install dependencies
npm install

# Start the example server
cd example-server
npm install && npm start

# In another terminal, start the example app
cd example-app
npm install && npm start

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

📋 API Reference

Key Exports

// Main Components
import {
  Ajora, // Main chat component
  AjoraProvider, // Context provider
  useAjora, // State management hook
} from "react-native-ajora";

// UI Components
import {
  Actions, // Action button component
  Bubble, // Message bubble component
  Composer, // Text input component
  InputToolbar, // Input toolbar container
  LoadEarlier, // Load earlier button
  Message, // Individual message component
  MessageContainer, // Messages list container
  MessageImage, // Image message component
  MessageText, // Text message component
  Send, // Send button component
} from "react-native-ajora";

// Types
import type {
  IMessage, // Core message interface
  Part, // Message part interface
  FunctionCall, // Function call interface
  FunctionResponse, // Function response interface
  Thread, // Thread interface
  AjoraProps, // Main component props
  AjoraState, // Hook state type
} from "react-native-ajora";

Native Tools

// Built-in tools available to AI agents:
const nativeTools = [
  "todo_list", // Interactive todo list management
  "search_web", // Web search functionality
  "search_document", // Document search capabilities
];

🙏 Acknowledgments

  • Built with ❤️ for the React Native community
  • Inspired by modern chat interfaces and AI agent UIs
  • Special thanks to Farid and react-native-giftedchat contributors
  • Powered by React Native Reanimated, Expo Vector Icons, and other amazing open source libraries

📞 Support


Made with ❤️ by Habtamu Asefa

⭐ Star us on GitHub📖 Documentation🐛 Report Bug✨ Request Feature