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;
};