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_id

AomiFrame 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

PropTypeDefaultDescription
hideModelbooleanfalseHide the model selector dropdown
hideAppbooleanfalseHide the app/agent selector
hideApiKeybooleanfalseHide the API key input button
hideWalletbooleantrueHide the wallet connect button
hideNetworkbooleanfalseHide the network selector
classNamestring--Additional CSS classes
childrenReactNode--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:

EndpointMethodDescription
/api/chatPOSTSend a message
/api/stateGETPoll for state updates
/api/session/modelsGETGet available models
/api/session/appsGETGet authorized apps
/api/session/modelPOSTSet the active model
/api/sessionsGET/POSTList/create threads
/api/sessions/:idPATCH/DELETEUpdate/delete thread

See the API Reference for full endpoint documentation.

On this page