> ## Documentation Index
> Fetch the complete documentation index at: https://aomilabs-victor-docs-redirect-build-overview.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Headless Library

> Build custom chat UIs with the @aomi-labs/react headless library. Runtime logic, state management, hooks, and an API client with zero UI opinions for builders.

`@aomi-labs/react` provides runtime logic, state management, hooks, and an API client with zero UI opinions. Use it to build completely custom interfaces or integrate Aomi logic into existing applications.

Use the headless React library when you need a custom layout, branded components, or a non-chat interaction model.

## Installation

```bash theme={null}
npm install @aomi-labs/react
```

Or using pnpm:

```bash theme={null}
pnpm install @aomi-labs/react
```

### Peer Dependencies

```json theme={null}
{
  "@assistant-ui/react": "^0.11.0",
  "react": "^18.0.0 || ^19.0.0",
  "react-dom": "^18.0.0 || ^19.0.0",
  "wagmi": "^2.0.0",
  "viem": "^2.0.0"
}
```

`wagmi` and `viem` are optional peer dependencies. Install them only if your app uses wallet connection; skip them for read only or non-wallet UIs.

## What's Included

### Providers

| Export                        | Description                                                                   |
| ----------------------------- | ----------------------------------------------------------------------------- |
| `AomiRuntimeProvider`         | Top-level provider that connects to the Aomi backend and sets up all contexts |
| `ThreadContextProvider`       | Thread state management (messages, metadata, thread switching)                |
| `ExtUserProvider`             | Wallet/user state (address, chain, connection status)                         |
| `NotificationContextProvider` | Toast notification state                                                      |
| `EventContextProvider`        | SSE subscription and system event dispatch                                    |
| `ControlContextProvider`      | Model/app/API key selection state                                             |

### Hooks

| Hook                       | Description                                                                                     |
| -------------------------- | ----------------------------------------------------------------------------------------------- |
| `useAomiRuntime`           | Unified API combining all sub-contexts (threads, messages, user, events, notifications, wallet) |
| `useUser`                  | Wallet/user state and setters                                                                   |
| `useThreadContext`         | Current thread ID, messages map, metadata map                                                   |
| `useCurrentThreadMessages` | Messages for the active thread                                                                  |
| `useCurrentThreadMetadata` | Metadata (title, status) for the active thread                                                  |
| `useControl`               | Model/app/API key state and selection                                                           |
| `useNotification`          | Show, dismiss, and list notifications                                                           |
| `useEventContext`          | SSE subscription and outbound event dispatch                                                    |
| `useWalletHandler`         | Handle wallet transaction and signing requests                                                  |
| `useNotificationHandler`   | Process notification events from the backend                                                    |

### API Client

| Export       | Description                                                                                          |
| ------------ | ---------------------------------------------------------------------------------------------------- |
| `AomiClient` | Direct HTTP client for the Aomi backend (usable outside React), re-exported from `@aomi-labs/client` |

### Utilities

| Export             | Description                                           |
| ------------------ | ----------------------------------------------------- |
| `cn`               | Class name merger (clsx + tailwind-merge)             |
| `formatAddress`    | Truncates wallet addresses for display (`0xABC...12`) |
| `getNetworkName`   | Resolves chain ID to human-readable network name      |
| `getChainInfo`     | Returns chain metadata (name, ticker, explorer URL)   |
| `SUPPORTED_CHAINS` | Array of supported chain configurations               |

### Types

```ts theme={null}
import type {
  AomiRuntimeApi,
  AomiMessage,
  ThreadMetadata,
  ThreadControlState,
  UserState,
  ControlState,
  Notification,
  NotificationType,
  WalletRequest,
  WalletTxPayload,
  WalletEip712Payload,
  InboundEvent,
  SSEStatus,
} from "@aomi-labs/react";
```

## Basic Setup

Wrap your app with `AomiRuntimeProvider`:

```tsx theme={null}
import { AomiRuntimeProvider } from "@aomi-labs/react";

function App() {
  return (
    <AomiRuntimeProvider backendUrl="https://api.aomi.dev">
      <YourCustomUI />
    </AomiRuntimeProvider>
  );
}
```

`AomiRuntimeProvider` internally sets up all nested providers (ThreadContext, UserContext, NotificationContext, EventContext, ControlContext), so you get the full runtime with a single wrapper.

### Provider Hierarchy

`AomiRuntimeProvider` wraps your app with a hierarchy of context providers:

```
AomiRuntimeProvider
└── ThreadContextProvider             ← Thread state (messages, metadata, switching)
    └── NotificationContextProvider   ← Toast notifications
        └── ExtUserProvider           ← Wallet/user state
            └── ControlContextProvider    ← Model/app/API key
                └── EventContextProvider  ← SSE + system events
                    └── {children}
```

Each layer provides specific functionality through its own hook:

| Context      | Hook               | Provides                                         |
| ------------ | ------------------ | ------------------------------------------------ |
| Thread       | `useThreadContext` | Thread ID, messages, metadata, thread operations |
| User         | `useUser`          | Wallet address, chain ID, connection status      |
| Notification | `useNotification`  | Show/dismiss notifications                       |
| Control      | `useControl`       | Model selection, app, API key                    |
| Event        | `useEventContext`  | SSE subscription, outbound events                |
| **Unified**  | `useAomiRuntime`   | **All of the above in one hook**                 |

## Runtime Provider

`AomiRuntimeProvider` is the top-level provider that connects your React app to the Aomi backend. It sets up all contexts needed for chat, threads, user state, notifications, and events.

### Props

| Prop         | Type        | Default                   | Description                 |
| ------------ | ----------- | ------------------------- | --------------------------- |
| `backendUrl` | `string`    | `"http://localhost:8080"` | URL of the Aomi backend API |
| `children`   | `ReactNode` | --                        | Your application components |

### Typical Provider Hierarchy

In a Next.js App Router project, place `AomiRuntimeProvider` inside your wagmi and query providers:

```tsx theme={null}
// app/providers.tsx
"use client";

import { WagmiProvider } from "wagmi";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { AomiRuntimeProvider } from "@aomi-labs/react";
import { wagmiConfig } from "./wagmi-config";

const queryClient = new QueryClient();

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <WagmiProvider config={wagmiConfig}>
      <QueryClientProvider client={queryClient}>
        <AomiRuntimeProvider
          backendUrl={process.env.NEXT_PUBLIC_BACKEND_URL}
        >
          {children}
        </AomiRuntimeProvider>
      </QueryClientProvider>
    </WagmiProvider>
  );
}
```

```tsx theme={null}
// app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}
```

### Without Wallet Support

If your application does not need wallet functionality, skip the wagmi providers entirely:

```tsx theme={null}
import { AomiRuntimeProvider } from "@aomi-labs/react";

export function Providers({ children }) {
  return (
    <AomiRuntimeProvider backendUrl="https://api.aomi.dev">
      {children}
    </AomiRuntimeProvider>
  );
}
```

The `ConnectButton` control and runtime transaction handler will simply be inactive.

### Using AomiClient Directly

For non-React code or server-side use, you can use the `AomiClient` class without any providers. Construct it with an options object, not a bare URL:

```ts theme={null}
import { AomiClient } from "@aomi-labs/react";

const client = new AomiClient({ baseUrl: "https://api.aomi.dev" });

// List threads for a wallet address
const threads = await client.listThreads(sessionId, publicKey);

// Send a message
await client.sendMessage(sessionId, message, { app, apiKey });

// Get available models
const models = await client.getModels(sessionId);
```

## When to Use Headless vs Widget

| Scenario                                | Recommendation                         |
| --------------------------------------- | -------------------------------------- |
| Standard chat interface needed quickly  | Widget                                 |
| Existing design system, custom look     | Headless                               |
| Non-Next.js React app                   | Headless                               |
| Server-side API calls (no React)        | Headless (`AomiClient` class directly) |
| Want to start fast, customize later     | Widget (edit source files)             |
| Embedding in an existing complex layout | Headless                               |

## Custom UI Tutorial

Build a complete chat interface from scratch:

1. Create a `MessageList` component that renders messages using `useThreadContext`
2. Create a `ChatInput` component that sends messages via `useAomiRuntime`
3. Create a `ThreadSwitcher` to manage multiple conversations
4. Compose them into your page layout

The key design principle: state lives in the library, components are pure presentational.

## Handler Utilities

### Wallet Handler

The `useWalletHandler` hook processes wallet transaction and signing requests from the backend:

```tsx theme={null}
import { useWalletHandler } from "@aomi-labs/react";

function WalletHandler() {
  const { pendingRequests, startRequest, resolveRequest, rejectRequest } =
    useWalletHandler({ getSession: () => getCurrentSession() });

  // Each request has a `kind`: "transaction" | "eip712_sign" | "solana_sign".
  // Resolve with a matching result kind, or call rejectRequest(id).

  return null; // Renders nothing — drive the requests programmatically
}
```

See the [Hooks Reference](/guides/headless/hooks) for the full `useWalletHandler` API and result shapes.

### Notification Handler

The `useNotificationHandler` hook processes notification events from the backend:

```tsx theme={null}
import { useNotificationHandler } from "@aomi-labs/react";

function NotificationListener() {
  const { notifications, unhandledCount, markDone } = useNotificationHandler({
    onNotification: (n) => {
      // Trigger your own toast or banner UI when a notification arrives
    },
  });

  // notifications: every notification received, newest first
  // unhandledCount: how many are not yet marked done
  // markDone(id): mark one as handled

  return null;
}
```

## Event System Details

### Event Types

The event context handles inbound events streamed from the backend over SSE, and lets you send outbound system messages back to the backend:

| Direction       | How                                                   | Description                                           |
| --------------- | ----------------------------------------------------- | ----------------------------------------------------- |
| Server → Client | `subscribe(type, handler)` delivers an `InboundEvent` | System notifications, wallet requests, status updates |
| Client → Server | `sendOutboundSystem({ type, sessionId, payload })`    | UI state and system commands sent to the backend      |

### Subscription

```tsx theme={null}
import { useEffect } from "react";
import { useEventContext } from "@aomi-labs/react";

function EventSubscriber() {
  const { subscribe, sseStatus } = useEventContext();

  useEffect(() => {
    // subscribe(eventType, handler) returns an unsubscribe function
    const unsubscribe = subscribe("wallet_tx_request", (event) => {
      console.log(event.payload);
    });
    return unsubscribe;
  }, [subscribe]);

  // sseStatus — "connected" | "connecting" | "disconnected"
  return (
    <div className="text-xs text-white/40">
      SSE: {sseStatus}
    </div>
  );
}
```

### Sending Outbound System Messages

To send a system message back to the backend, use `sendOutboundSystem`. It takes an object with `type`, `sessionId`, and `payload`:

```tsx theme={null}
import { useEventContext } from "@aomi-labs/react";

function useTxComplete(sessionId: string) {
  const { sendOutboundSystem } = useEventContext();

  const notifyTxComplete = async (txHash: string) => {
    await sendOutboundSystem({
      type: "wallet:tx_complete",
      sessionId,
      payload: { txHash, status: "success" },
    });
  };

  return { notifyTxComplete };
}
```

## Next Steps

* [Hooks Reference](/guides/headless/hooks): complete hook API
* [Build Custom UI](/guides/headless/build-custom-ui): full example from scratch
* [Custom Tools](/guides/custom-tools): extend Aomi with your own tools
