UIHeadless

Hooks Reference

All hooks exported by @aomi-labs/react. Every hook must be used inside AomiRuntimeProvider.

useAomiRuntime

The unified hook that combines all runtime APIs into a single interface. This is the primary way to interact with the Aomi runtime.

import { useAomiRuntime } from "@aomi-labs/react";

function MyComponent() {
  const aomi = useAomiRuntime();

  // User API
  aomi.user;                  // { address?, chainId?, isConnected, ensName? }
  aomi.setUser({ ... });
  aomi.getUserState();
  aomi.onUserStateChange((user) => { ... });

  // Thread API
  aomi.currentThreadId;       // string
  aomi.threadViewKey;          // number (use as React key)
  aomi.threadMetadata;         // Map<string, ThreadMetadata>
  aomi.getThreadMetadata(id);
  await aomi.createThread();
  await aomi.deleteThread(id);
  await aomi.renameThread(id, "New Title");
  await aomi.archiveThread(id);
  aomi.selectThread(id);

  // Chat API
  aomi.isRunning;              // boolean
  aomi.getMessages(threadId?); // ThreadMessageLike[]
  await aomi.sendMessage("Hello!");
  aomi.cancelGeneration();

  // Notification API
  aomi.notifications;                     // Notification[]
  aomi.showNotification({ type, title }); // returns notification ID
  aomi.dismissNotification(id);
  aomi.clearAllNotifications();

  // Wallet API
  aomi.pendingWalletRequests;  // WalletRequest[]
  aomi.startWalletRequest(id);
  aomi.resolveWalletRequest(id, { txHash });
  aomi.rejectWalletRequest(id, "reason");

  // Event API
  aomi.subscribe("event_type", callback);  // returns unsubscribe fn
  await aomi.sendSystemCommand({ type, sessionId, payload });
  aomi.sseStatus;              // "connected" | "connecting" | "disconnected"
}

Return Type: AomiRuntimeApi

type AomiRuntimeApi = {
  // User
  user: UserState;
  getUserState: () => UserState;
  setUser: (data: Partial<UserState>) => void;
  onUserStateChange: (cb: (user: UserState) => void) => () => void;

  // Thread
  currentThreadId: string;
  threadViewKey: number;
  threadMetadata: Map<string, ThreadMetadata>;
  getThreadMetadata: (id: string) => ThreadMetadata | undefined;
  createThread: () => Promise<string>;
  deleteThread: (id: string) => Promise<void>;
  renameThread: (id: string, title: string) => Promise<void>;
  archiveThread: (id: string) => Promise<void>;
  selectThread: (id: string) => void;

  // Chat
  isRunning: boolean;
  getMessages: (threadId?: string) => ThreadMessageLike[];
  sendMessage: (text: string) => Promise<void>;
  cancelGeneration: () => void;

  // Notifications
  notifications: Notification[];
  showNotification: (params: NotificationData) => string;
  dismissNotification: (id: string) => void;
  clearAllNotifications: () => void;

  // Wallet
  pendingWalletRequests: WalletRequest[];
  startWalletRequest: (id: string) => void;
  resolveWalletRequest: (id: string, result: WalletRequestResult) => void;
  rejectWalletRequest: (id: string, error?: string) => void;

  // Events
  subscribe: (type: string, cb: EventSubscriber) => () => void;
  sendSystemCommand: (event: Omit<OutboundEvent, "timestamp">) => Promise<void>;
  sseStatus: SSEStatus;
};

useUser

Wallet and user state management.

import { useUser } from "@aomi-labs/react";

function WalletStatus() {
  const { user, setUser, getUserState, onUserStateChange } = useUser();

  // Read state
  user.address;      // "0xABC..." | undefined
  user.chainId;      // 1 | undefined
  user.isConnected;  // boolean
  user.ensName;      // "vitalik.eth" | undefined

  // Update state (partial merge)
  setUser({ address: "0x...", chainId: 1, isConnected: true });

  // Synchronous getter (for callbacks)
  const current = getUserState();

  // Subscribe to changes
  const unsubscribe = onUserStateChange((newUser) => {
    console.log("User changed:", newUser);
  });
}

UserState Type

type UserState = {
  address?: string;
  chainId?: number;
  isConnected: boolean;
  ensName?: string;
};

useThreadContext

Low-level thread state management. Use useAomiRuntime for most cases; this hook is for building custom thread management UI.

import { useThreadContext } from "@aomi-labs/react";

function ThreadManager() {
  const {
    currentThreadId,
    setCurrentThreadId,
    threadViewKey,
    bumpThreadViewKey,
    allThreads,             // Map<string, ThreadMessageLike[]>
    allThreadsMetadata,     // Map<string, ThreadMetadata>
    getThreadMessages,
    setThreadMessages,
    getThreadMetadata,
    updateThreadMetadata,
  } = useThreadContext();

  // Get messages for current thread
  const messages = getThreadMessages(currentThreadId);

  // Get metadata
  const meta = getThreadMetadata(currentThreadId);
  console.log(meta?.title, meta?.status, meta?.lastActiveAt);
}

Convenience Hooks

import {
  useCurrentThreadMessages,
  useCurrentThreadMetadata,
} from "@aomi-labs/react";

// Messages for the active thread (memoized)
const messages = useCurrentThreadMessages();

// Metadata for the active thread (memoized)
const metadata = useCurrentThreadMetadata();

useControl

Model, app, and API key state management.

import { useControl } from "@aomi-labs/react";

function ControlPanel() {
  const {
    state,                    // ControlState
    setApiKey,                // (apiKey: string | null) => void
    getAvailableModels,       // () => Promise<string[]>
    getAuthorizedApps,        // () => Promise<string[]>
    onModelSelect,            // (model: string) => Promise<void>
    onAppSelect,              // (app: string) => void
    getCurrentThreadControl,  // () => ThreadControlState
    isProcessing,             // boolean
    getControlState,          // () => ControlState (synchronous)
    onControlStateChange,     // (cb) => unsubscribe
  } = useControl();

  // Global state
  state.apiKey;                // string | null
  state.availableModels;       // string[]
  state.authorizedApps;        // string[]
  state.defaultModel;          // string | null
  state.defaultApp;            // string | null

  // Per-thread state
  const tc = getCurrentThreadControl();
  tc.model;      // string | null
  tc.app;        // string | null
}

ControlState Type

type ControlState = {
  apiKey: string | null;
  availableModels: string[];
  authorizedApps: string[];
  defaultModel: string | null;
  defaultApp: string | null;
};

useNotification

Toast notification management.

import { useNotification } from "@aomi-labs/react";

function NotificationExample() {
  const {
    notifications,        // Notification[]
    showNotification,     // (params) => id
    dismissNotification,  // (id) => void
    clearAll,             // () => void
  } = useNotification();

  // Show a notification
  const id = showNotification({
    type: "success",        // "notice" | "success" | "error" | "wallet"
    title: "Transaction sent",
    message: "0x123...abc",  // optional
    duration: 5000,          // optional, milliseconds
  });

  // Dismiss
  dismissNotification(id);
}

Notification Type

type Notification = {
  id: string;
  type: "notice" | "success" | "error" | "wallet";
  title: string;
  message?: string;
  duration?: number;
  timestamp: number;
};

useEventContext

SSE (Server-Sent Events) subscription and outbound event dispatch.

import { useEventContext } from "@aomi-labs/react";

function EventListener() {
  const {
    subscribe,              // (type, callback) => unsubscribe
    sendOutboundSystem,     // (event) => Promise<void>
    dispatchInboundSystem,  // (sessionId, events) => void
    sseStatus,              // "connected" | "connecting" | "disconnected"
  } = useEventContext();

  // Subscribe to inbound events by type
  useEffect(() => {
    const unsubscribe = subscribe("wallet_tx_request", (event) => {
      console.log("Wallet request received:", event.payload);
    });
    return unsubscribe;
  }, [subscribe]);

  // Send an outbound event to the backend
  await sendOutboundSystem({
    type: "wallet:tx_complete",
    sessionId: "thread-123",
    payload: { txHash: "0x...", status: "success" },
  });
}

useWalletHandler

Handles wallet transaction requests and EIP-712 signing requests from the AI backend.

import { useWalletHandler } from "@aomi-labs/react";

function WalletHandler() {
  const {
    pendingRequests,   // WalletRequest[]
    startProcessing,   // (id) => void
    resolveRequest,    // (id, result) => void
    rejectRequest,     // (id, error?) => void
  } = useWalletHandler({
    sessionId: currentThreadId,
    onRequestComplete: () => {
      // Called after resolve/reject sends the outbound event
    },
  });

  // Process a transaction request
  for (const req of pendingRequests) {
    if (req.kind === "transaction") {
      // req.payload: WalletTxPayload
      startProcessing(req.id);
      // ... execute transaction with wagmi ...
      resolveRequest(req.id, { txHash: "0x..." });
    }

    if (req.kind === "eip712_sign") {
      // req.payload: WalletEip712Payload
      startProcessing(req.id);
      // ... sign typed data ...
      resolveRequest(req.id, { signature: "0x..." });
    }
  }
}

WalletRequest Type

type WalletRequest = {
  id: string;
  kind: "transaction" | "eip712_sign";
  status: "pending" | "processing";
  payload: WalletTxPayload | WalletEip712Payload;
  timestamp: number;
};

On this page