react-native
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chineseassistant-ui React Native
assistant-ui React Native
Always consult assistant-ui.com/llms.txt for the latest API.
@assistant-ui/react-nativeViewTextPressableTextInputFlatList@assistant-ui/ai-sdk请始终查阅assistant-ui.com/llms.txt获取最新API。
@assistant-ui/react-nativeViewTextPressableTextInputFlatList@assistant-ui/ai-sdkContents
目录
References
参考资料
- ./references/primitives.md -- native primitive namespaces and their parts
- ./references/hooks.md -- state, runtime, tool, and scoped-provider hooks
- ./references/adapters.md -- local persistence, attachments, and remote thread lists
- ./references/custom-backend.md -- a streaming model adapter and a backend-owned thread list
- ./references/migration.md -- moving a web runtime to a native UI layer
- ./references/primitives.md -- 原生原语命名空间及其组成部分
- ./references/hooks.md -- 状态、运行时、工具和作用域提供者钩子
- ./references/adapters.md -- 本地持久化、附件和远程线程列表
- ./references/custom-backend.md -- 流式模型适配器和后端托管的线程列表
- ./references/migration.md -- 将网页运行时迁移到原生UI层
Quick start
快速开始
Start from the maintained Expo example:
sh
npx assistant-ui@latest create --example with-expo my-app
cd my-appSet an endpoint that the app can reach. It must be an absolute URL. A physical device cannot resolve its own localhost to your development server.
dotenv
EXPO_PUBLIC_CHAT_ENDPOINT_URL="https://api.example.com/api/chat"Start Expo:
sh
npx expo start从官方维护的Expo示例项目开始:
sh
npx assistant-ui@latest create --example with-expo my-app
cd my-app设置应用可访问的端点,必须为绝对URL。物理设备无法将自身的localhost解析到你的开发服务器。
dotenv
EXPO_PUBLIC_CHAT_ENDPOINT_URL="https://api.example.com/api/chat"启动Expo:
sh
npx expo startManual setup
手动设置
Install the native runtime and its AI SDK v7 peer packages in an existing Expo app:
sh
npx expo install @assistant-ui/react-native @assistant-ui/ai-sdk ai@^7 @ai-sdk/react@^4Host the model route separately. The native app posts UI messages to that route through ; the route converts them asynchronously for AI SDK v7 and returns a UI message stream.
AssistantChatTransportts
import { openai } from "@ai-sdk/openai";
import { convertToModelMessages, streamText } from "ai";
export async function POST(request: Request) {
const { messages } = await request.json();
const result = streamText({
model: openai("gpt-5.6-luna"),
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}Create the runtime in a hook. Keep the endpoint in the public Expo environment so the compiled app can reach it.
tsx
import {
AssistantChatTransport,
useChatRuntime,
} from "@assistant-ui/ai-sdk";
const chatEndpoint = process.env.EXPO_PUBLIC_CHAT_ENDPOINT_URL;
export function useAppRuntime() {
if (!chatEndpoint) {
throw new Error("EXPO_PUBLIC_CHAT_ENDPOINT_URL is required");
}
return useChatRuntime({
transport: new AssistantChatTransport({ api: chatEndpoint }),
});
}AssistantChatTransportfrontendTools@assistant-ui/ai-sdk在现有Expo应用中安装原生运行时及其AI SDK v7依赖包:
sh
npx expo install @assistant-ui/react-native @assistant-ui/ai-sdk ai@^7 @ai-sdk/react@^4单独托管模型路由。原生应用通过向该路由发送UI消息;路由会将消息异步转换为AI SDK v7兼容格式,并返回UI消息流。
AssistantChatTransportts
import { openai } from "@ai-sdk/openai";
import { convertToModelMessages, streamText } from "ai";
export async function POST(request: Request) {
const { messages } = await request.json();
const result = streamText({
model: openai("gpt-5.6-luna"),
messages: await convertToModelMessages(messages),
});
return result.toUIMessageStreamResponse();
}在钩子中创建运行时。将端点保存在Expo公共环境变量中,以便编译后的应用可以访问它。
tsx
import {
AssistantChatTransport,
useChatRuntime,
} from "@assistant-ui/ai-sdk";
const chatEndpoint = process.env.EXPO_PUBLIC_CHAT_ENDPOINT_URL;
export function useAppRuntime() {
if (!chatEndpoint) {
throw new Error("EXPO_PUBLIC_CHAT_ENDPOINT_URL is required");
}
return useChatRuntime({
transport: new AssistantChatTransport({ api: chatEndpoint }),
});
}AssistantChatTransport@assistant-ui/ai-sdkfrontendToolsNative chat composition
原生聊天组合
Put the runtime under the native , then compose the thread and composer from primitives. is the current list primitive and scopes each row to the corresponding message.
AssistantRuntimeProviderThreadPrimitive.MessagesFlatListtsx
import {
AssistantRuntimeProvider,
AuiIf,
ComposerPrimitive,
MessagePrimitive,
ThreadPrimitive,
useAuiState,
} from "@assistant-ui/react-native";
import { Text, View } from "react-native";
import { useAppRuntime } from "./use-app-runtime";
function MessageRow() {
const role = useAuiState((s) => s.message.role);
return (
<View
style={{
alignSelf: role === "user" ? "flex-end" : "flex-start",
backgroundColor: role === "user" ? "#007aff" : "#f0f0f0",
borderRadius: 16,
margin: 8,
padding: 12,
}}
>
<MessagePrimitive.Content />
</View>
);
}
function Composer() {
return (
<ComposerPrimitive.Root style={{ flexDirection: "row", gap: 8, padding: 12 }}>
<ComposerPrimitive.Input
multiline
placeholder="Message..."
style={{ borderWidth: 1, borderRadius: 20, flex: 1, padding: 10 }}
/>
<ComposerPrimitive.Send>
<Text>Send</Text>
</ComposerPrimitive.Send>
</ComposerPrimitive.Root>
);
}
function ChatScreen() {
return (
<ThreadPrimitive.Root style={{ flex: 1 }}>
<AuiIf condition={(s) => s.thread.isEmpty}>
<Text style={{ padding: 16 }}>Send a message to begin.</Text>
</AuiIf>
<ThreadPrimitive.MessagesFlatList autoScroll>
{() => <MessageRow />}
</ThreadPrimitive.MessagesFlatList>
<Composer />
</ThreadPrimitive.Root>
);
}
export default function App() {
const runtime = useAppRuntime();
return (
<AssistantRuntimeProvider runtime={runtime}>
<ChatScreen />
</AssistantRuntimeProvider>
);
}MessagePrimitive.ContentTextrenderTextMessagePrimitive.PartsKeyboardAvoidingViewUse inside primitive scopes for reactive values. Use with no arguments for imperative actions such as and . Keep selectors to primitives or stable references instead of constructing an object or array in the selector.
useAuiStateuseAui()aui.composer.send()aui.thread.cancelRun()将运行时置于原生之下,然后使用原语组合线程和编辑器。是当前的列表原语,会将每一行与对应的消息绑定作用域。
AssistantRuntimeProviderThreadPrimitive.MessagesFlatListtsx
import {
AssistantRuntimeProvider,
AuiIf,
ComposerPrimitive,
MessagePrimitive,
ThreadPrimitive,
useAuiState,
} from "@assistant-ui/react-native";
import { Text, View } from "react-native";
import { useAppRuntime } from "./use-app-runtime";
function MessageRow() {
const role = useAuiState((s) => s.message.role);
return (
<View
style={{
alignSelf: role === "user" ? "flex-end" : "flex-start",
backgroundColor: role === "user" ? "#007aff" : "#f0f0f0",
borderRadius: 16,
margin: 8,
padding: 12,
}}
>
<MessagePrimitive.Content />
</View>
);
}
function Composer() {
return (
<ComposerPrimitive.Root style={{ flexDirection: "row", gap: 8, padding: 12 }}>
<ComposerPrimitive.Input
multiline
placeholder="Message..."
style={{ borderWidth: 1, borderRadius: 20, flex: 1, padding: 10 }}
/>
<ComposerPrimitive.Send>
<Text>Send</Text>
</ComposerPrimitive.Send>
</ComposerPrimitive.Root>
);
}
function ChatScreen() {
return (
<ThreadPrimitive.Root style={{ flex: 1 }}>
<AuiIf condition={(s) => s.thread.isEmpty}>
<Text style={{ padding: 16 }}>Send a message to begin.</Text>
</AuiIf>
<ThreadPrimitive.MessagesFlatList autoScroll>
{() => <MessageRow />}
</ThreadPrimitive.MessagesFlatList>
<Composer />
</ThreadPrimitive.Root>
);
}
export default function App() {
const runtime = useAppRuntime();
return (
<AssistantRuntimeProvider runtime={runtime}>
<ChatScreen />
</AssistantRuntimeProvider>
);
}MessagePrimitive.ContentTextrenderTextMessagePrimitive.PartsKeyboardAvoidingView在原语作用域内使用获取响应式值。使用无参数的执行命令式操作,例如和。选择器应指向原语或稳定引用,而非在选择器中构造对象或数组。
useAuiStateuseAui()aui.composer.send()aui.thread.cancelRun()Generative toolkits
生成式工具包
Metro"use generative"@assistant-ui/metrogetDefaultConfigexpo/metro-config@react-native/metro-configjs
const { getDefaultConfig } = require("expo/metro-config");
const { withAui } = require("@assistant-ui/metro");
module.exports = withAui(getDefaultConfig(__dirname));For a backendless toolkit, pass the option through the wrapper so frontend and human tool schemas remain uploadable:
auijs
module.exports = withAui({
...getDefaultConfig(__dirname),
aui: { backendless: true },
});Write the toolkit against , including native and renderers. The directive makes the compiler infer tool kind from . The tools skill covers backend, frontend, human, provider, external, and stub tool semantics.
@assistant-ui/react-nativeViewText"use generative"executeMetro"use generative"@assistant-ui/metroexpo/metro-configgetDefaultConfig@react-native/metro-configjs
const { getDefaultConfig } = require("expo/metro-config");
const { withAui } = require("@assistant-ui/metro");
module.exports = withAui(getDefaultConfig(__dirname));对于无后端工具包,通过包装器传递选项,确保前端和人工工具模式保持可上传状态:
auijs
module.exports = withAui({
...getDefaultConfig(__dirname),
aui: { backendless: true },
});针对编写工具包,包括原生和渲染器。指令使编译器从推断工具类型。tools技能涵盖后端、前端、人工、提供者、外部和存根工具的语义。
@assistant-ui/react-nativeViewText"use generative"executeCommon Gotchas
常见问题
The mobile app posts to /api/chat and never reaches the server
- Native apps have no browser origin for relative requests. Set to the complete route URL.
EXPO_PUBLIC_CHAT_ENDPOINT_URL - Use a host reachable from the simulator or physical device. Device localhost is the device itself.
The provider is mounted but primitives throw or show no state
- Create the runtime with or another supported runtime hook, then pass it as
useChatRuntimetoruntime={runtime}.AssistantRuntimeProvider - Render primitives below that provider. Message, part, attachment, queue, suggestion, and thread-list-item primitives also need their corresponding parent render scope.
A web Thread or an Elements import does not render in the Expo app
- The shadcn Elements catalog is DOM and Tailwind based. Build the native UI with primitives and React Native styles.
@assistant-ui/react-native
The message list does not stay at the bottom
- Use with
ThreadPrimitive.MessagesFlatListfor new screens.autoScrollis retained for compatibility and defaults its auto-scroll options to false.ThreadPrimitive.Messages
Toolkits compile as ordinary modules or tool schemas never reach the model
- Add to
withAuibefore usingMetro."use generative" - Import the identical generative module in the server build. If there is no server build, set .
aui: { backendless: true }
Markdown appears as literal asterisks and fences
- uses native
MessagePrimitive.Contentby default. Supply a native Markdown renderer throughText.renderText
移动应用向/api/chat发送请求但无法连接到服务器
- 原生应用没有浏览器源来处理相对请求。请将设置为完整的路由URL。
EXPO_PUBLIC_CHAT_ENDPOINT_URL - 使用模拟器或物理设备可访问的主机。设备的localhost指向设备自身。
提供者已挂载但原语抛出错误或无状态显示
- 使用或其他受支持的运行时钩子创建运行时,然后将其作为
useChatRuntime传递给runtime={runtime}。AssistantRuntimeProvider - 在该提供者下方渲染原语。消息、片段、附件、队列、建议和线程列表项原语还需要对应的父渲染作用域。
网页Thread或Elements导入无法在Expo应用中渲染
- shadcn Elements目录基于DOM和Tailwind构建。请使用原语和React Native样式构建原生UI。
@assistant-ui/react-native
消息列表无法保持在底部
- 对于新界面,使用带有的
autoScroll。ThreadPrimitive.MessagesFlatList仅为兼容保留,其自动滚动选项默认设为false。ThreadPrimitive.Messages
工具包编译为普通模块或工具模式从未传递到模型
- 在使用之前,将
"use generative"添加到withAui配置中。Metro - 在服务器构建中导入完全相同的生成式模块。如果没有服务器构建,请设置。
aui: { backendless: true }
Markdown显示为字面星号和围栏
- 默认使用原生
MessagePrimitive.Content。请通过Text提供原生Markdown渲染器。renderText
Related Skills
相关技能
- setup -- ,
create, and configure assistant-ui web projectsinitialize - primitives -- DOM primitives for web applications, not React Native UI
- runtime -- runtime behavior and backend transport concepts shared with native
- tools -- generative toolkits, their backend route, and custom tool UI
- setup -- 、
create和配置assistant-ui网页项目initialize - primitives -- 用于网页应用的DOM原语,不适用于React Native UI
- runtime -- 与原生共享的运行时行为和后端传输概念
- tools -- 生成式工具包、其后端路由和自定义工具UI