generative-ui

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

assistant-ui Generative UI

assistant-ui Generative UI

Always consult assistant-ui.com/llms.txt for the latest API.
Generative UI inverts the usual tool-rendering relationship. Instead of one hand-written component per tool call, you ship a vocabulary of components and let something assemble a tree from it: either the model, through the
present
tool, or your backend, through a message part or a LangGraph event.
@assistant-ui/react-generative-ui
ships a default vocabulary of 27 components (cards, facts, tables, charts, forms, controls) plus converters that turn the same tree into Slack Block Kit, a Microsoft Teams Adaptive Card, or an A2UI surface, so a composition built once can render in the browser and outside it.
请始终查阅 assistant-ui.com/llms.txt 获取最新API。
Generative UI 颠覆了常规的工具渲染关系。无需为每个工具调用手写单独组件,你只需提供一套组件词汇表,由模型通过
present
工具或后端通过消息片段、LangGraph事件来组装组件树。
@assistant-ui/react-generative-ui
内置了包含27个组件的默认词汇表(卡片、事实展示、表格、图表、表单、控件等),同时提供转换器可将同一组件树转换为Slack Block Kit、Microsoft Teams自适应卡片或A2UI界面,一次构建的组件组合可同时在浏览器及外部平台渲染。

References

参考资料

  • ./references/vocabulary.md -- the 27 default components and how to add your own with
    defineGenerativeComponents
  • ./references/actions.md --
    $action
    dispatch,
    createActionRegistry
    , and the
    $input
    shapes interactive components send back
  • ./references/renderers.md --
    MessagePrimitive.GenerativeUI
    and its allowlist, the Slack and Teams converters, and why the two spec shapes do not interchange
  • ./references/a2ui-openui.md -- A2UI surfaces over AG-UI and the third-party OpenUI integration
  • ./references/tokens.md -- the shared token arrays and how to restyle or override the vocabulary
  • ./references/vocabulary.md -- 27个默认组件介绍,以及如何使用
    defineGenerativeComponents
    添加自定义组件
  • ./references/actions.md --
    $action
    分发、
    createActionRegistry
    ,以及交互式组件返回的
    $input
    结构
  • ./references/renderers.md --
    MessagePrimitive.GenerativeUI
    及其允许列表、Slack和Teams转换器,以及两种规范结构无法互换的原因
  • ./references/a2ui-openui.md -- 基于AG-UI的A2UI界面,以及第三方OpenUI集成
  • ./references/tokens.md -- 共享令牌数组,以及如何重新样式化或覆盖组件词汇表

Which generative UI pattern?

选择哪种Generative UI模式?

Two questions separate the patterns: does the model compose the layout or do you bind it ahead of time, and does the UI originate from a tool call or from a part your backend emits.
PatternAPIBest for
The
present
tool
JSONGenerativeUI
+
present
The model composes dashboards, cards, and layouts from a vocabulary you ship
Tool UItoolkit
render
(see tools)
A widget tied to one tool call you already know about
Generative UI primitive
MessagePrimitive.GenerativeUI
+ allowlist
A backend that already emits
generative-ui
message parts
LangGraph data UI
makeAssistantDataUI
+
ui_message
LangGraph agents emitting UI on the LangGraph stream, see assistant-ui.com/docs/runtimes/langgraph/generative-ui
OpenUI
@openuidev/assistant-ui
, third party
Already invested in the OpenUI ecosystem and its component kit
The first two are tool-driven, so the model decides when UI appears; the LangGraph row is backend-driven, so your agent does.
present
and the generative UI primitive both take a JSON component tree, but in non-interchangeable shapes, see Spec shape differences. A tree built for
present
is also the shape the Slack, Teams, and A2UI converters accept.
区分不同模式可通过两个问题:是由模型组合布局,还是提前绑定布局;UI是源自工具调用,还是后端生成的消息片段。
模式API最佳适用场景
present
工具
JSONGenerativeUI
+
present
模型从你提供的词汇表中组合仪表盘、卡片及布局
工具UItoolkit
render
(详见 tools
与已知工具调用绑定的小部件
Generative UI原语
MessagePrimitive.GenerativeUI
+ 允许列表
已生成
generative-ui
消息片段的后端服务
LangGraph数据UI
makeAssistantDataUI
+
ui_message
LangGraph智能体在LangGraph流中输出UI,详见 assistant-ui.com/docs/runtimes/langgraph/generative-ui
OpenUI
@openuidev/assistant-ui
(第三方)
已投入OpenUI生态系统及其组件库的场景
前两种是工具驱动,由模型决定UI何时显示;LangGraph模式是后端驱动,由智能体控制。
present
和Generative UI原语均接收JSON组件树,但结构不可互换,详见 规范结构差异。为
present
构建的组件树同样适用于Slack、Teams和A2UI转换器。

Quick start

快速开始

Install the package, add the styled element, and enable the
"use generative"
compiler for your framework:
bash
npm install @assistant-ui/react-generative-ui
npx assistant-ui@latest add generative-ui
ts
import { withAui } from "@assistant-ui/next";

export default withAui({
  /* your Next config */
});
Vite and TanStack Start use
aui()
from
@assistant-ui/vite
(
plugins: [aui({ ... })]
); Expo and bare React Native use
const { withAui } = require("@assistant-ui/metro");
in
metro.config.js
. The directive lets one file declare tools that both the browser and your server route import: the compiler strips the browser-only halves from the server build and the schemas from the client build.
JSONGenerativeUI
turns a component library into the model-facing schema for
present
. Register the result on a toolkit like any other tool:
tsx
"use generative";

import { defineToolkit } from "@assistant-ui/react";
import {
  JSONGenerativeUI,
  defaultGenerativeUILibrary,
} from "@assistant-ui/react-generative-ui";

const generative = new JSONGenerativeUI({
  library: defaultGenerativeUILibrary,
});

export default defineToolkit({
  present: generative.present({ display: "standalone" }),
});
display: "standalone"
renders the result on its own surface, outside the chain-of-thought trace; omit it to render inline. The default vocabulary is already a working setup with no components of your own, see vocabulary.md for the full list and how to extend it.
Register the toolkit on the client through
AuiConfig
, and set
sendAutomaticallyWhen
so the run continues once the frontend tool resolves:
tsx
"use client";

import { AssistantRuntimeProvider, AuiConfig, Tools } from "@assistant-ui/react";
import { useChatRuntime } from "@assistant-ui/ai-sdk";
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
import toolkit from "./toolkit";

export function MyRuntimeProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const runtime = useChatRuntime({
    sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
  });
  const config = AuiConfig({ tools: Tools({ toolkit }) });

  return (
    <AssistantRuntimeProvider runtime={runtime} config={config}>
      {children}
    </AssistantRuntimeProvider>
  );
}
present
is a frontend tool: it resolves in the browser, and without
sendAutomaticallyWhen
the UI renders and the conversation stops before the model says anything else.
The route imports the same toolkit module. The compiler resolves that import to the server build, so only the schemas cross over and no browser code enters your server bundle:
ts
import { openai } from "@ai-sdk/openai";
import { AISDKToolkit } from "@assistant-ui/ai-sdk";
import { convertToModelMessages, stepCountIs, streamText } from "ai";
import toolkit from "@/app/toolkit";

const aiToolkit = new AISDKToolkit({ toolkit });

export async function POST(req: Request) {
  const { messages, tools } = await req.json();

  const result = streamText({
    model: openai("gpt-5.6-luna"),
    messages: await convertToModelMessages(messages),
    stopWhen: stepCountIs(10),
    tools: await aiToolkit.tools({ frontend: tools }),
  });

  return result.toUIMessageStreamResponse();
}
When no backend of yours imports the toolkit module, for example a cloud-hosted run, compile with
backendless: true
so the client keeps every schema uploadable, including
present
's:
ts
export default withAui({ ...yourConfig, aui: { backendless: true } });
安装包、添加样式元素,并为你的框架启用
"use generative"
编译器:
bash
npm install @assistant-ui/react-generative-ui
npx assistant-ui@latest add generative-ui
ts
import { withAui } from "@assistant-ui/next";

export default withAui({
  /* 你的Next配置 */
});
Vite和TanStack Start使用
@assistant-ui/vite
中的
aui()
plugins: [aui({ ... })]
);Expo和原生React Native在
metro.config.js
中使用
const { withAui } = require("@assistant-ui/metro");
。该指令允许单个文件声明浏览器和服务器路由均可导入的工具:编译器会从服务器构建中剥离仅浏览器端的代码,从客户端构建中剥离模式定义。
JSONGenerativeUI
将组件库转换为面向模型的
present
工具模式。像注册其他工具一样将结果注册到toolkit:
tsx
"use generative";

import { defineToolkit } from "@assistant-ui/react";
import {
  JSONGenerativeUI,
  defaultGenerativeUILibrary,
} from "@assistant-ui/react-generative-ui";

const generative = new JSONGenerativeUI({
  library: defaultGenerativeUILibrary,
});

export default defineToolkit({
  present: generative.present({ display: "standalone" }),
});
display: "standalone"
会将结果渲染在独立界面上,而非思维链追踪内;省略该参数则会内联渲染。默认词汇表无需自定义组件即可直接使用,完整列表及扩展方法详见 vocabulary.md
通过
AuiConfig
在客户端注册toolkit,并设置
sendAutomaticallyWhen
以便前端工具解析后继续运行:
tsx
"use client";

import { AssistantRuntimeProvider, AuiConfig, Tools } from "@assistant-ui/react";
import { useChatRuntime } from "@assistant-ui/ai-sdk";
import { lastAssistantMessageIsCompleteWithToolCalls } from "ai";
import toolkit from "./toolkit";

export function MyRuntimeProvider({
  children,
}: {
  children: React.ReactNode;
}) {
  const runtime = useChatRuntime({
    sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
  });
  const config = AuiConfig({ tools: Tools({ toolkit }) });

  return (
    <AssistantRuntimeProvider runtime={runtime} config={config}>
      {children}
    </AssistantRuntimeProvider>
  );
}
present
是前端工具:它在浏览器中解析,若未设置
sendAutomaticallyWhen
,UI渲染后对话会在模型输出其他内容前停止。
路由导入同一toolkit模块。编译器会将该导入解析为服务器构建版本,因此仅模式定义会跨端传输,浏览器代码不会进入服务器包:
ts
import { openai } from "@ai-sdk/openai";
import { AISDKToolkit } from "@assistant-ui/ai-sdk";
import { convertToModelMessages, stepCountIs, streamText } from "ai";
import toolkit from "@/app/toolkit";

const aiToolkit = new AISDKToolkit({ toolkit });

export async function POST(req: Request) {
  const { messages, tools } = await req.json();

  const result = streamText({
    model: openai("gpt-5.6-luna"),
    messages: await convertToModelMessages(messages),
    stopWhen: stepCountIs(10),
    tools: await aiToolkit.tools({ frontend: tools }),
  });

  return result.toUIMessageStreamResponse();
}
当你的后端未导入toolkit模块时(例如云托管运行环境),需使用
backendless: true
编译,以便客户端保留所有可上传的模式,包括
present
的模式:
ts
export default withAui({ ...yourConfig, aui: { backendless: true } });

Style it

样式定制

npx assistant-ui@latest add generative-ui
, run above, installs the shipped stylesheet plus
components/assistant-ui/elements/generative-ui.tsx
, which exports
styledGenerativeUILibrary
: the same 27 components with a real markdown renderer swapped in for the default plain-text one. It is a
"use client"
module, so wiring it into a
"use generative"
toolkit file follows the client-module rule in the gotchas below; see tokens.md for the exact override pattern, the
data-aui
styling hooks, and the token arrays.
上述执行的
npx assistant-ui@latest add generative-ui
会安装内置样式表及
components/assistant-ui/elements/generative-ui.tsx
,该文件导出
styledGenerativeUILibrary
:将默认纯文本渲染器替换为真实markdown渲染器的27个组件。它是
"use client"
模块,因此在
"use generative"
的toolkit文件中引入需遵循下方注意事项中的客户端模块规则;具体覆盖模式、
data-aui
样式钩子及令牌数组详见 tokens.md

Beyond present

进阶功能

  • Extend the vocabulary with your own components, or read back a model-produced tree for display: vocabulary.md.
  • Let rendered nodes call back into your app through
    $action
    : actions.md.
  • Render a
    generative-ui
    message part your backend already emits, with
    MessagePrimitive.GenerativeUI
    and a consumer-provided allowlist: renderers.md.
  • Post a tree to Slack or Microsoft Teams, or render an A2UI surface over AG-UI, or wire the third-party OpenUI integration: renderers.md and a2ui-openui.md.
  • 使用自定义组件扩展词汇表,或读取模型生成的组件树进行展示:vocabulary.md
  • 通过
    $action
    让渲染节点回调你的应用:actions.md
  • 渲染后端已生成的
    generative-ui
    消息片段,使用
    MessagePrimitive.GenerativeUI
    及用户提供的允许列表:renderers.md
  • 将组件树发布到Slack或Microsoft Teams,或在AG-UI上渲染A2UI界面,或接入第三方OpenUI集成:renderers.mda2ui-openui.md

Common Gotchas

常见问题

present
renders the UI, then the conversation just stops
  • present
    is a frontend tool; without
    sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls
    on
    useChatRuntime
    , the run never continues after it resolves.
The model never learns about
present
on a cloud-hosted backend
  • The client build skips uploading frontend and human schemas because it assumes your backend imported the same toolkit module. Compile with
    aui: { backendless: true }
    when no server of yours does.
styledGenerativeUILibrary
breaks the
"use generative"
build
  • It is a
    "use client"
    module. A
    "use generative"
    file may reference it only as the inline
    render
    value inside a
    defineGenerativeComponents
    call, never as a spread, a top-level constant, or the
    library
    option directly. Passing it straight to
    library
    works only in a plain file with no
    "use generative"
    directive; see tokens.md.
A
generative-ui
message part renders nothing
  • The default shadcn
    Thread
    does not wire
    MessagePrimitive.GenerativeUI
    . Opt in explicitly in your message renderer; see renderers.md.
Unknown component name: silent drop versus thrown error
  • The
    present
    tool path drops an unrecognized
    $type
    and warns in development. The generative UI primitive throws a typed
    GenerativeUIRenderError
    unless you pass
    Fallback
    . Neither boundary constrains the props those components receive; validate
    href
    /
    src
    values yourself and never forward agent-supplied props into
    dangerouslySetInnerHTML
    .
Slack or Teams output does not match the browser
  • Conversion is total but lossy: read the returned
    warnings
    array. Only a
    $type
    tree built for
    present
    converts; the primitive's
    { component, props }
    shape has no Slack, Teams, or A2UI converter.
useChatRuntime
never emits a native
generative-ui
part
  • The AI SDK maps tool results to
    tool-call
    parts, not
    generative-ui
    parts. Bridge with a
    render_gui
    tool whose result you parse into a spec yourself (the docs call that helper
    parseRenderGuiResult
    ; it is not a package export); see renderers.md.
present
渲染UI后,对话直接停止
  • present
    是前端工具;若
    useChatRuntime
    未设置
    sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls
    ,解析后运行不会继续。
云托管后端中模型无法识别
present
  • 客户端构建会跳过上传前端和人工模式,因为默认假设你的后端导入了同一toolkit模块。当你的服务器未导入时,需使用
    aui: { backendless: true }
    编译。
styledGenerativeUILibrary
破坏
"use generative"
构建
  • 它是
    "use client"
    模块。
    "use generative"
    文件仅可在
    defineGenerativeComponents
    调用的内联
    render
    值中引用它,不可作为展开值、顶层常量或直接作为
    library
    选项。仅在无
    "use generative"
    指令的普通文件中,才可直接将其传入
    library
    ;详见 tokens.md
generative-ui
消息片段无渲染内容
  • 默认的shadcn
    Thread
    未关联
    MessagePrimitive.GenerativeUI
    。需在消息渲染器中显式启用;详见 renderers.md
未知组件名称:静默丢弃还是抛出错误
  • present
    工具路径会丢弃未识别的
    $type
    并在开发环境中发出警告。Generative UI原语会抛出类型化的
    GenerativeUIRenderError
    ,除非你传入
    Fallback
    。两者均不会限制组件接收的属性;请自行验证
    href
    /
    src
    值,切勿将智能体提供的属性传入
    dangerouslySetInnerHTML
Slack或Teams输出与浏览器不一致
  • 转换是完整但有损耗的:请读取返回的
    warnings
    数组。仅为
    present
    构建的
    $type
    组件树可被转换;原语的
    { component, props }
    结构无Slack、Teams或A2UI转换器。
useChatRuntime
从未生成原生
generative-ui
片段
  • AI SDK会将工具结果映射为
    tool-call
    片段,而非
    generative-ui
    片段。需通过
    render_gui
    工具桥接,自行将其结果解析为规范(文档中称该辅助工具为
    parseRenderGuiResult
    ,并非包导出);详见 renderers.md

Related Skills

相关技能

  • tools -- toolkit authoring, the
    "use generative"
    compiler, and tool UI for a widget tied to one specific tool call
  • elements -- installing the
    generative-ui
    styled element and the rest of the catalog
  • primitives --
    MessagePrimitive
    and the other unstyled building blocks
  • runtime --
    AuiConfig
    ,
    Tools
    , and the rest of the config plumbing
  • tools -- toolkit编写、
    "use generative"
    编译器,以及与特定工具调用绑定的工具UI
  • elements -- 安装
    generative-ui
    样式元素及其他组件目录
  • primitives --
    MessagePrimitive
    及其他未样式化基础组件
  • runtime --
    AuiConfig
    Tools
    及其他配置相关内容