The Bitte AI Chat component is a React component that enables AI-powered chat interactions in your application. It supports both NEAR Protocol and EVM blockchain interactions through wallet integrations, allowing users to interact with smart contracts and perform transactions directly through the chat interface.
Import and use BitteAiChat in your react app and select the agent that you would like to use, browse the available agents and their respective ids on the registry
The apiUrl corresponds to a proxy to not expose your api key on the client
import {BitteAiChat} from "@bitte-ai/chat";
import '@bitte-ai/chat/styles.css';
<BitteAiChat
agentId="your-agent-id"
apiUrl="/api/chat"
/>
3. Setup API Route
Create an API route in your Next.js application to proxy requests to the Bitte API to not expose your key.
Nextjs app router implementation:
import type { NextApiRequest, NextApiResponse } from 'next';
const {
BITTE_API_KEY,
BITTE_API_URL = 'https://ai-runtime-446257178793.europe-west1.run.app/chat',
} = process.env;
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
try {
const data = req.body;
const requestInit: RequestInit = {
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${BITTE_API_KEY}`,
},
};
const upstreamResponse = await fetch(`${BITTE_API_URL}`, requestInit);
res.statusCode = upstreamResponse.status;
for (const [key, value] of Object.entries(upstreamResponse.headers)) {
if (key.toLowerCase() !== 'content-encoding') {
res.setHeader(key, value as string);
}
}
res.setHeader('Content-Type', upstreamResponse.headers.get('Content-Type') || 'application/json');
if (!upstreamResponse.body) {
return res.end();
}
const reader = upstreamResponse.body.getReader();
async function readChunk() {
const { done, value } = await reader.read();
if (done) {
return res.end();
}
res.write(value);
await readChunk();
}
await readChunk();
} catch (error) {
console.error('Error in chat API route:', error);
res.status(500).json({ error: 'Internal Server Error' });
}
}
At this point the chat should already work but to be able to send transactions you will need to add a wallet connection
4. Add wallet connection
NEAR Integration
You can integrate with NEAR using either the NEAR Wallet Selector or a direct account connection. If you want to be able to send near transacitons through the chat you will need to define at least one of these
import { Account } from "near-api-js";
// get near account instance from near-api-js by instantiating a keypair
<BitteAiChat
agentId="your-agent-id"
apiUrl="/api/chat"
wallet={{ near: { account: nearAccount } }}
/>
SUI Integration
SUI integration uses WalletConnect with wagmi hooks:
interface BitteAiChatProps {
agentId: string; // ID of the AI agent to use
apiUrl: string; // Your API route path (e.g., "/api/chat")
historyApiUrl?: string; // Your history API route to keep context when signing transactions
wallet?: WalletOptions; // Wallet configuration
colors?: ChatComponentColors;
options?: {
agentName?: string; // Custom agent name
agentImage?: string; // Custom agent image URL
chatId?: string; // Custom chat ID
prompt?: string // Custom Initial prompt
localAgent?: {
pluginId: string;
accountId: string;
spec: BitteOpenAPISpec;
};
placeholderText?: string;
colors?: ChatComponentColors;
customComponents?: {
welcomeMessageComponent?: React.JSX.Element;
mobileInputExtraButton?: React.JSX.Element;
messageContainer?: React.ComponentType<MessageGroupComponentProps>;
chatContainer?: React.ComponentType<ChatContainerComponentProps>;
inputContainer?: React.ComponentType<InputContainerProps>;
sendButtonComponent?: React.ComponentType<SendButtonComponentProps>;
loadingIndicator?: React.ComponentType<LoadingIndicatorComponentProps>;
};
};
customToolComponents?: CustomToolComponent[];
}
export interface ReactToolComponent {
name: string;
component: React.ComponentType<CustomToolComponentProps>;
}
// Update CustomToolComponent type to align with BitteTool from primitives.ts
export type CustomToolComponent =
| PortfolioTool
| TransferTool
| SwapTool
| ReactToolComponent;
Custom Components
The BitteAiChat component provides several UI elements that can be customized via the customComponents under options prop. This enables full control over the appearance and behavior of key parts of the chat interface by passing in your own React components.
Available Custom Components
You can override the following built-in UI components:
✅ Tip: All custom components are optional. If not provided, the default components will be used.
Custom Tool Components
The BitteAiChat component supports embedding interactive, data-driven tools directly into the chat UI through the customToolComponents prop. These tools allow users to interact with structured data returned by your agent’s API, such as portfolios, token swaps, or custom workflows.
How Tool Rendering Works
When your AI agent responds with a message that includes a data field , and that data matches a known type (like PortfolioResponse, TransferFTData, etc.), the chat interface can automatically render the corresponding tool component — as long as a tool is registered in customToolComponents with a matching name.
The name must match:
The operation name in your agent’s OpenAPI spec
The name field in the tool component configuration
There is no need to wrap the response in a tool object — the chat package dynamically maps the data to the corresponding component based on the configured name and type.
Pre-Configured Tools
The @bitte-ai/chat package comes with built-in support for the following tools:
get-portfolio
swap
transfer-ft
As long as:
The agent's API response includes a data field that matches the correct type (PortfolioResponse, SwapFTData, or TransferFTData — all from @bitte-ai/types)
The OpenAPI spec defines the route using one of the above names (i.e. get-portfolio, swap, or transfer-ft as operation IDs or paths)
...then the matching tool UI will automatically be rendered — no manual configuration required.
These tools are auto-wired and will display a default UI out-of-the-box. You only need to use customToolComponents if you want to override these default UIs or add custom tools.
Example: Registering Tool Components
const customToolComponents = [
{
name: 'get-portfolio', // This should match the operationId or route name from your OpenAPI spec
component: (props) => (
<TokenList data={props.data as PortfolioResponse} />
),
},
{
name: 'swap',
component: (props) => (
<Swap data={props.data as SwapFTData} />
),
},
{
name: 'transfer-ft',
component: (props) => (
<Transfer data={props.data as TransferFTData} />
),
},
{
name: 'my-custom-tool',
component: (props) => <MyCustomComponent data={props.data} />,
},
];
The component can be customized using the colors prop:
type ChatComponentColors = {
generalBackground?: string; // Chat container background
messageBackground?: string; // Message bubble background
textColor?: string; // Text color
buttonColor?: string; // Button color
borderColor?: string; // Border color
};
Browser Redirects (Optional)
if you're having issues with your app or wallet containing redirects you can optionally use a history api to maintain context
Create an API route in your Next.js application that will allow your app if you want to save chat context when signing a transaction after getting redirected to the wallet.