4.0.3 • Published 9 months ago

@ixo/oracles-ui v4.0.3

Weekly downloads
-
License
-
Repository
-
Last release
9 months ago

@ixo/oracles-ui

Introduction

@ixo/oracles-ui is a set of React hooks and utilities designed to integrate conversational AI (e.g., Guru AI) into your applications. It helps developers:

  • Manage and switch between multiple AI chat sessions.
  • Send messages and receive real-time streamed responses.
  • Dynamically render custom UI components (e.g., cards, forms, data viewers) driven by the AI’s output.
  • Maintain a seamless and interactive user experience across both web and mobile (React Native) platforms.

Installation

pnpm add @ixo/oracles-ui

(You may also use npm or yarn.)

Getting Started

To start, wrap your application in the UseOraclesProvider component:

import { UseOraclesProvider } from '@ixo/oracles-ui';

function App() {
  return (
   <UseOraclesProvider
      apiKey="key"
      apiURL="url">
      {/* Your application code */}
    </UseOraclesProvider>
  );
}

This sets up the necessary context for the hooks and components.


Core Hooks Overview

The package provides several core hooks to handle sessions, messages, and direct communication with the AI.

1. useChatSessionsList

Purpose: Fetch and manage a list of available chat sessions, as well as create new sessions.

Returned Values:

  • sessions: An array of session objects, each containing an id, title, and oracleName.
  • isLoading: Boolean indicating if sessions are currently loading.
  • error: Any error that occurred during the session fetch.
  • revalidate: A function to manually refresh the session list.
  • createSession: A function to create a new session.

Endpoints:

  • POST <API_URL>/sessions/list (fetch sessions)
  • POST <API_URL>/sessions/create (create new session)

Usage Example:

const {
  sessions,
  isLoading,
  error,
  revalidate,
  createSession,
} = useChatSessionsList({
  apiURL: 'https://api.example.com',
  apiKey: 'your-api-key',
  did: 'your-did',
  matrixAccessToken: 'your-matrix-access-token',
  oracle: 'guru',
});

2. useAskOracle

Purpose: Send messages to the AI and receive responses in real-time.

Returned Values:

  • sendMessage: An async function to send a message to the Oracle.
  • isSending: Boolean indicating if a message is currently being sent.
  • error: Any error encountered while sending the message.

Endpoints:

  • POST apiURL/<oracle>/stream (send messages and receive streamed responses)

Usage Example:

const { sendMessage, isSending, error } = useAskOracle({
  apiURL: 'https://api.example.com',
  apiKey: 'your-api-key',
  did: 'your-did',
  matrixAccessToken: 'your-matrix-access-token',
  sessionId: 'your-session-id',
  oracle: 'guru',
});

Then you can call:

await sendMessage('Hello, Guru!');

3. useListMessages

Purpose: Retrieve and maintain a list of messages for a specific session, including real-time updates over WebSockets.

Returned Values:

  • messages: An array of messages that may include text or dynamically rendered components.
  • isLoading: Boolean indicating if messages are being fetched.
  • error: Any error encountered while fetching messages.
  • connectionId: The current WebSocket connection ID.

Endpoints:

  • GET apiURL/<oracle>/messages (fetch messages)
  • WebSocket: socketURL (connect for live updates)

Usage Example:

const { messages, isLoading, error, connectionId } = useListMessages({
  apiURL: 'https://api.example.com',
  apiKey: 'your-api-key',
  did: 'your-did',
  matrixAccessToken: 'your-matrix-access-token',
  sessionId: 'your-session-id',
  oracle: 'guru',
  uiComponents: {
    // Register your custom UI components here
    'credential_card': CredentialCard,
    'CoinCard': CoinCard,
  },
  socketURL: 'http://localhost:3000', // Socket.io server URL
});

Dynamic UI Components

One of the core features of @ixo/oracles-ui is the ability to dynamically render custom UI components in response to AI events (tool calls).

  • When the AI emits a tool call (e.g., CoinCard), the resolveUIComponent function returns a React node that can be displayed directly in your UI.
  • If the tool call is “running,” the component can indicate a loading state if it supports it. Otherwise, a placeholder UI will be shown until it’s complete.

How to Integrate Components:

  1. Create a Custom UI Component that matches the tool’s name. For instance, a CoinCard component that displays cryptocurrency data.

  2. Export a Loading-Aware Component (Optional):
    If your component can handle loading states, set Component.prototype.canHandleLoadingState = true;. This tells the resolver to render the component with an isLoading prop when the AI tool is still running.

  3. Register the Component in uiComponents prop passed to useListMessages:

    const components = {
      'CoinCard': CoinCard,
    };
    
    const { messages } = useListMessages({
      ...config,
      uiComponents: components,
    });

Note on Rendering:
You don’t need to manually call resolveUIComponent yourself. The useListMessages hook handles it internally. When a tool call message appears, it will automatically resolve the appropriate component and return a React node in messages.

Example of Rendering Messages and Components

Below is a simplified web-based chat interface example. Notice that we directly render message.content. If message.content is a React node (from a resolved UI component), it will be displayed as such.

function ChatInterface({ messages, ...props }) {
  return (
    <div className="chat-container">
      <div className="messages">
        {messages.map((message) => (
          <div key={message.id} className={message.type === 'human' ? 'human' : 'ai'}>
            {/* If the content is a string, show text. If it's a component, it's already a React node. */}
            {typeof message.content === 'string' ? (
              <Markdown>{message.content}</Markdown>
            ) : (
              message.content
            )}
          </div>
        ))}
      </div>
      {/* Input and other UI elements */}
    </div>
  );
}

Building Components for the Library

To leverage the library’s dynamic rendering:

  1. Define Props and Loading States: Your component should accept props corresponding to the tool’s args, and optionally an isLoading prop if it can show a loading skeleton or spinner.

  2. Handle Loading Gracefully: If isLoading is true, return a loading state. If false, render the full component UI.

  3. Export Your Component and Register it:

    CoinCard.prototype.canHandleLoadingState = true;
    export function CoinCard(props) {
      if (props.isLoading) {
        return <CoinCardSkeleton />;
      }
      return <div>Your card content here...</div>;
    }

    Then pass it in uiComponents:

    useListMessages({
      ...config,
      uiComponents: {
        'CoinCard': CoinCard,
      },
    });

Platform Differences (Web vs. Mobile)

Code and Hooks Are the Same:
The hooks (useAskOracle, useChatSessionsList, useListMessages) and core logic are platform-agnostic. They work the same in React DOM and React Native/Expo environments.

UI Components and Rendering:

  • Web (React DOM): Use standard web components like <div>, <button>, and <input>.
  • Mobile (React Native / Expo): Use <View>, <Text>, <TouchableOpacity>, <TextInput>, and so forth.

Example for Mobile:

// Similar logic as web, just different UI components
const { messages } = useListMessages({...config, uiComponents: { 'CoinCard': CoinCard }});

// When rendering messages:
messages.map((message) => (
  <View key={message.id}>
    {typeof message.content === 'string' ? (
      <Text>{message.content}</Text>
    ) : (
      // message.content is a React node (e.g., <CoinCard ... />)
      message.content
    )}
  </View>
));
4.0.3

9 months ago

4.0.2

12 months ago

4.0.1

12 months ago

4.0.0

12 months ago

2.0.1

12 months ago

2.0.0

12 months ago

1.0.0

1 year ago