@ixo/oracles-ui v4.0.3
@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 anid,title, andoracleName.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), theresolveUIComponentfunction 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:
Create a Custom UI Component that matches the tool’s name. For instance, a
CoinCardcomponent that displays cryptocurrency data.Export a Loading-Aware Component (Optional):
If your component can handle loading states, setComponent.prototype.canHandleLoadingState = true;. This tells the resolver to render the component with anisLoadingprop when the AI tool is still running.Register the Component in
uiComponentsprop passed touseListMessages: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:
Define Props and Loading States: Your component should accept props corresponding to the tool’s
args, and optionally anisLoadingprop if it can show a loading skeleton or spinner.Handle Loading Gracefully: If
isLoadingis true, return a loading state. If false, render the full component UI.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>
));