# Adapters
URL: /docs/ink/adapters

Attachment, title generation, and storage adapters for React Ink.

> For AI agents: a documentation index is available at [llms.txt](/llms.txt). Use `.md` for canonical markdown pages; `.mdx` is kept as a backwards-compatible alias on supported URL paths.

Adapters customize runtime behavior. They can be passed as options to `useLocalRuntime` or `useRemoteThreadListRuntime`.

## createFileStorageAdapter

A `RemoteThreadListAdapter` that persists threads and messages to a local directory. See [Custom Backend → Option 2](/docs/ink/custom-backend#option-2-local-file-persistence) for usage.

```
import { createFileStorageAdapter } from "@assistant-ui/react-ink";

const adapter = createFileStorageAdapter({
  dir: "/path/to/threads",
});
```

## Attachment adapters

`SimpleTextAttachmentAdapter` and `SimpleImageAttachmentAdapter` work the same in the terminal as on web and React Native. Text contents are sent to the model wrapped in `<attachment name=...>` tags, and images are sent as base64 data URLs.

```
import {
  CompositeAttachmentAdapter,
  SimpleImageAttachmentAdapter,
  SimpleTextAttachmentAdapter,
  useLocalRuntime,
} from "@assistant-ui/react-ink";

const runtime = useLocalRuntime(chatModelAdapter, {
  adapters: {
    attachments: new CompositeAttachmentAdapter([
      new SimpleTextAttachmentAdapter(),
      new SimpleImageAttachmentAdapter(),
    ]),
  },
});
```

## TitleGenerationAdapter

Produces a thread title from a thread's messages. Pass one as the `titleGenerator` option to `createFileStorageAdapter`, or call it from a custom `RemoteThreadListAdapter`.

```
type TitleGenerationAdapter = {
  generateTitle(messages: readonly ThreadMessage[]): Promise<string>;
};
```

`createSimpleTitleAdapter` is the built-in implementation; it derives the title from the first user message, truncated to 50 characters.

```
import {
  createFileStorageAdapter,
  createSimpleTitleAdapter,
} from "@assistant-ui/react-ink";

const adapter = createFileStorageAdapter({
  dir: "/path/to/threads",
  titleGenerator: createSimpleTitleAdapter(),
});
```

## RemoteThreadListAdapter

Title generation is configured via the `generateTitle` method on `RemoteThreadListAdapter`. See the [Custom Backend](/docs/ink/custom-backend) page for a full example.

```
import type { RemoteThreadListAdapter } from "@assistant-ui/react-ink";
import { createAssistantStream } from "assistant-stream";

const myAdapter: RemoteThreadListAdapter = {
  // ... other methods ...

  async generateTitle(remoteId, unstable_messages) {
    return createAssistantStream(async (controller) => {
      const res = await fetch(`/api/threads/${remoteId}/title`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ messages: unstable_messages }),
      });
      const { title } = await res.json();
      controller.appendText(title);
    });
  },
};
```

## Which option to choose?

|                               | ChatModelAdapter + `useLocalRuntime` | RemoteThreadListAdapter + `useRemoteThreadListRuntime` |
| ----------------------------- | ------------------------------------ | ------------------------------------------------------ |
| **Thread storage**            | In-memory                            | Your backend                                           |
| **Message storage**           | In-memory                            | In-memory (can add history adapter for server-side)    |
| **Cross-session persistence** | No                                   | Yes                                                    |
| **Setup complexity**          | Minimal                              | Moderate                                               |
| **Best for**                  | CLI tools, demos, prototypes         | Production apps with persistence                       |