UIWidget
Configuration
Configure behavior, runtime options, and component props for the Aomi widget.
Environment Variables
Set these in your .env file:
# Backend API URL (required)
NEXT_PUBLIC_BACKEND_URL=https://api.example.com
# Optional: Para API key for a Para-backed wallet bridge
NEXT_PUBLIC_PARA_API_KEY=your_para_api_key
# Optional: WalletConnect project ID for external wallets in the Para modal
NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID=your_walletconnect_project_idAomiFrame Props
Basic Configuration
import { AomiFrame } from "@/components/aomi-frame";
<AomiFrame
width="100%"
height="600px"
backendUrl="https://api.example.com"
walletPosition="footer"
/>;Wallet Position Options
// Wallet button in sidebar footer (default)
<AomiFrame walletPosition="footer" />
// Wallet button in sidebar header
<AomiFrame walletPosition="header" />
// No wallet button in sidebar (use ControlBar wallet instead)
<AomiFrame walletPosition={null} />Custom Layout with Compound Components
import { AomiFrame } from "@/components/aomi-frame";
<AomiFrame.Root height="600px" backendUrl="https://api.example.com">
<AomiFrame.Header
withControl={true}
controlBarProps={{
hideModel: false,
hideApp: false,
hideApiKey: true,
hideWallet: false,
}}
/>
<AomiFrame.Composer />
</AomiFrame.Root>;Control Bar in Composer Area
Place the control bar above the input instead of in the header:
<AomiFrame.Root height="600px">
<AomiFrame.Header withControl={false} />
<AomiFrame.Composer
withControl={true}
controlBarProps={{ hideWallet: true }}
/>
</AomiFrame.Root>ControlBar Configuration
Show/Hide Controls
import { ControlBar } from "@/components/control-bar";
// Full control bar (all controls visible)
<ControlBar />
// Minimal: just model and app
<ControlBar hideApiKey hideWallet />
// Custom: hide defaults, add your own
<ControlBar hideModel hideApp hideApiKey hideWallet>
<MyCustomModelPicker />
<MyCustomWalletButton />
</ControlBar>ControlBar Props Reference
| Prop | Type | Default | Description |
|---|---|---|---|
hideModel | boolean | false | Hide the model selector dropdown |
hideApp | boolean | false | Hide the app/agent selector |
hideApiKey | boolean | false | Hide the API key input button |
hideWallet | boolean | true | Hide the wallet connect button |
hideNetwork | boolean | false | Hide the network selector |
className | string | -- | Additional CSS classes |
children | ReactNode | -- | Custom controls to append |
Control State Management
Access the control state with the useControl hook:
import { useControl } from "@aomi-labs/react";
function MyComponent() {
const {
state, // Global control state
setApiKey, // Update API key
getAvailableModels, // Fetch available models from backend
getAuthorizedApps, // Fetch authorized apps from backend
onModelSelect, // Select a model for the current thread
onAppSelect, // Select an app for the current thread
getCurrentThreadControl, // Get current thread's control state
isProcessing, // Whether model/app switching is disabled
getControlState, // Get state synchronously (for callbacks)
onControlStateChange, // Subscribe to state changes
} = useControl();
// Read global state
console.log(state.apiKey); // "sk-..." | null
console.log(state.availableModels); // ["claude-sonnet-4-20250514", "gpt-4o", ...]
console.log(state.authorizedApps); // ["default", "defi", ...]
console.log(state.defaultModel); // "claude-sonnet-4-20250514"
console.log(state.defaultApp); // "default"
// Read per-thread control
const threadControl = getCurrentThreadControl();
console.log(threadControl.model); // Selected model for this thread
console.log(threadControl.app); // Selected app for this thread
// Update state
setApiKey("sk-new-key");
await onModelSelect("gpt-4o");
onAppSelect("defi");
}Control State Shape
type ControlState = {
apiKey: string | null;
availableModels: string[];
authorizedApps: string[];
defaultModel: string | null;
defaultApp: string | null;
};Runtime API
Access the full runtime API with useAomiRuntime:
import { useAomiRuntime } from "@aomi-labs/react";
function MyComponent() {
const api = useAomiRuntime();
// Thread management
const threadId = api.currentThreadId;
await api.createThread();
api.selectThread("thread-123");
await api.deleteThread("thread-123");
await api.renameThread("thread-123", "New Title");
// Messages
const messages = api.getMessages(threadId);
await api.sendMessage("Hello!");
const isGenerating = api.isRunning;
api.cancelGeneration();
// User state
const user = api.user;
api.setUser({ address: "0x...", chainId: 1, isConnected: true });
// Notifications
api.showNotification({ type: "success", title: "Done!" });
api.dismissNotification("notification-id");
api.clearAllNotifications();
// Events
const unsubscribe = api.subscribe("wallet_tx_request", (event) => {
console.log(event);
});
await api.sendSystemCommand({
type: "custom:action",
sessionId: threadId,
payload: { data: "value" },
});
}Para Wallet Provider
Wallet integration requires Para for the connect/manage flow and wagmi-compatible connectors under the hood. Configure it in your app providers:
// app/providers.tsx
import "@getpara/react-sdk/styles.css";
import { ParaProvider, Environment } from "@getpara/react-sdk";
import { http } from "viem";
import { mainnet, polygon } from "wagmi/chains";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
const walletConnectProjectId =
process.env.NEXT_PUBLIC_WALLETCONNECT_PROJECT_ID ??
process.env.NEXT_PUBLIC_PROJECT_ID;
export function Providers({ children }) {
return (
<QueryClientProvider client={queryClient}>
<ParaProvider
paraClientConfig={{
apiKey: process.env.NEXT_PUBLIC_PARA_API_KEY!,
env:
(process.env.NEXT_PUBLIC_PARA_ENVIRONMENT as
| Environment
| undefined) ?? Environment.BETA,
}}
config={{ appName: "Your App" }}
paraModalConfig={{
disableEmailLogin: true,
oAuthMethods: ["GOOGLE"],
}}
externalWalletConfig={{
appDescription: "Your app description",
appUrl: "https://your-app.com",
wallets: [
"WALLETCONNECT",
"METAMASK",
"COINBASE",
"RAINBOW",
"RABBY",
],
walletConnect: {
projectId: walletConnectProjectId!,
},
evmConnector: {
config: {
chains: [mainnet, polygon],
transports: {
[mainnet.id]: http(),
[polygon.id]: http(),
},
ssr: true,
},
},
}}
>
{children}
</ParaProvider>
</QueryClientProvider>
);
}Feature Flags
Use props to toggle features:
// Hide all controls for a minimal UI
<AomiFrame.Root>
<AomiFrame.Header withControl={false} />
<AomiFrame.Composer />
</AomiFrame.Root>
// Hide wallet for non-web3 apps
<AomiFrame.Root walletPosition={null}>
<AomiFrame.Header controlBarProps={{ hideWallet: true }} />
<AomiFrame.Composer />
</AomiFrame.Root>
// API-key only mode (no wallet, no app)
<AomiFrame.Root walletPosition={null}>
<AomiFrame.Header
withControl
controlBarProps={{
hideModel: true,
hideApp: true,
hideWallet: true,
hideNetwork: true,
}}
/>
<AomiFrame.Composer />
</AomiFrame.Root>Backend Endpoints
The widget communicates with your backend via these endpoints:
| Endpoint | Method | Description |
|---|---|---|
/api/chat | POST | Send a message |
/api/state | GET | Poll for state updates |
/api/session/models | GET | Get available models |
/api/session/apps | GET | Get authorized apps |
/api/session/model | POST | Set the active model |
/api/sessions | GET/POST | List/create threads |
/api/sessions/:id | PATCH/DELETE | Update/delete thread |
See the API Reference for full endpoint documentation.