关于 a2ui-renderer
用于在 CopilotKit 应用中启用 A2UI 渲染的技能,说明运行时和客户端所需配置,并指出重复渲染、重复创建 surface 等实现问题。
主要功能
- 01启用运行时与客户端 A2UI
- 02使用自动渲染器检测
- 03说明 surface 更新模式
- 04介绍 action 清理要求
- 05指出常见配置错误
适用场景
- 01在 CopilotKit 应用中添加 A2UI
- 02同时配置运行时与客户端
- 03排查重复或闪烁的 UI 渲染
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ copilotkit/ copilotkit --skill a2ui-renderer安装后在 Claude Code 中输入/a2ui-renderer确认已加载。
详细介绍
本技能基于 copilotkit/react-core(了解 CopilotKit provider 基础)和
copilotkit/runtime(了解 CopilotRuntime 基础)构建。请先阅读这些内容。
设置
A2UI 分为两部分。运行时声明 a2ui 中间件;客户端在 provider 上启用
a2ui prop。两者都设置好后,/info 会标记 A2UI,客户端会自动挂载
createA2UIMessageRenderer —— 你不需要自己接入
renderActivityMessages。
运行时侧(app/routes/api.copilotkit.$.tsx)
import type { Route } from "./+types/api.copilotkit.$";
import {
CopilotRuntime,
createCopilotRuntimeHandler,
BuiltInAgent,
convertInputToTanStackAI,
} from "@copilotkit/runtime/v2";
import { chat } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
const agent = new BuiltInAgent({
type: "tanstack",
factory: ({ input, abortController }) => {
const { messages, systemPrompts } = convertInputToTanStackAI(input);
return chat({
adapter: openaiText("gpt-4o"),
messages,
systemPrompts,
abortController,
});
},
});
const runtime = new CopilotRuntime({
agents: { default: agent },
// Enabling this key causes /info to advertise A2UI to the client.
a2ui: {},
});
const handler = createCopilotRuntimeHandler({
runtime,
basePath: "/api/copilotkit",
});
export async function loader({ request }: Route.LoaderArgs) {
return handler(request);
}
export async function action({ request }: Route.ActionArgs) {
return handler(request);
}
客户端侧(app/root.tsx 或应用外壳)
import { CopilotKit, CopilotChat } from "@copilotkit/react-core/v2";
import "@copilotkit/react-core/v2/styles.css";
export default function App() {
return (
<CopilotKit
runtimeUrl="/api/copilotkit"
a2ui={{
theme: {
// Theme object forwarded to A2UIProvider → ThemeProvider.
// Tokens map to A2UI's basic catalog CSS vars.
colors: { primary: "#0ea5e9" },
},
}}
>
<CopilotChat agentId="default" className="h-full" />
</CopilotKit>
);
}
核心模式
自定义 catalog
传入自定义 catalog 以扩展内置组件集。createCatalog
和 extractSchema 让 Agent 看到它可以渲染哪些组件。
import { createCatalog } from "@copilotkit/a2ui-renderer";
import { z } from "zod";
const theme = { colors: { primary: "#0ea5e9" } };
// Definitions are platform-agnostic (Zod schemas + descriptions).
// Renderers are platform-specific (React components).
// TypeScript enforces that renderer keys match definition keys exactly.
const definitions = {
ProductCard: {
description: "A product card with title and price",
props: z.object({ title: z.string(), price: z.number() }),
},
};
const catalog = createCatalog(
definitions,
{
ProductCard: ({ props }) => (
<div className="rounded-xl border p-3">
<div className="font-medium">{props.title}</div>
<div className="text-sm text-muted-foreground">${props.price}</div>
</div>
),
},
{ includeBasicCatalog: true },
);
<CopilotKit runtimeUrl="/api/copilotkit" a2ui={{ theme, catalog }}>
<CopilotChat agentId="default" />
</CopilotKit>;
extractSchema(definitions) 可用于将 definitions 的 JSON 可序列化
视图传递给运行时的 a2ui.schema 配置 —— 它不是
通用类型辅助工具。类型参数在运行时会被擦除;Agent 需要
一个真实的运行时 schema 值(Zod)。
覆盖加载骨架屏
<CopilotKit
runtimeUrl="/api/copilotkit"
a2ui={{
theme,
loadingComponent: () => <div className="animate-pulse">Building UI…</div>,
}}
>
<CopilotChat agentId="default" />
</CopilotKit>
常见错误
CRITICAL 忘记 runtime.a2ui
错误:
// server
new CopilotRuntime({ agents: { default: agent } });
// client
<CopilotKit runtimeUrl="/api/copilotkit" a2ui={{ theme }} />;
正确:
// server
new CopilotRuntime({ agents: { default: agent }, a2ui: {} });
// client
<CopilotKit runtimeUrl="/api/copilotkit" a2ui={{ theme }} />;
没有 runtime.a2ui,/info 永远不会标记 A2UI,provider 的 a2ui prop
会静默无效 —— 渲染器永远不会挂载。
来源:packages/runtime/src/v2/runtime/core/runtime.ts:55-58,217,242
HIGH 为 A2UI 手动接入 renderActivityMessages
错误:
import { createA2UIMessageRenderer } from "@copilotkit/react-core/v2";
<CopilotKit
runtimeUrl="/api/copilotkit"
renderActivityMessages={[createA2UIMessageRenderer({ theme })]}
/>;
正确:
<CopilotKit runtimeUrl="/api/copilotkit" a2ui={{ theme }} />
CopilotKit provider 会通过 /info 自动检测运行时 A2UI 并注入
内置渲染器。通过 renderActivityMessages 传入它会重复渲染器,
并可能与自动注入的渲染器产生竞争。
来源:packages/react-core/src/v2/providers/CopilotKitProvider.tsx:188-222,294-296
MEDIUM 在每个快照上重复发出 createSurface
错误:
# Pseudocode — inside your agent generator. Exact API names/kwargs vary by
# A2UI SDK version; consult your SDK's docs for real call shapes.
async def agent_generator():
# agent re-emits createSurface operation on every state delta
async for update in stream:
yield a2ui.create_surface(surface_id="main", ...) # every tick
yield a2ui.update_components(...)
正确:
# Pseudocode — inside your agent generator.
# Emit createSurface once per surfaceId; use updateComponents / updateDataModel
# for changes.
async def agent_generator():
yield a2ui.create_surface(surface_id="main", ...) # once
async for update in stream:
yield a2ui.update_components(surface_id="main", ...)
MessageProcessor 会根据 surfaceId 去重,但重复发出是 Agent 侧的
bug —— 客户端会白白重新运行协调逻辑并出现闪烁。
来源:packages/react-core/src/v2/a2ui/A2UIMessageRenderer.tsx:218-226
MEDIUM 自定义 action 桥接未清理 a2uiAction
错误:
copilotkit.setProperties({ ...copilotkit.properties, a2uiAction: msg });
await copilotkit.runAgent({ agent });
// no finally — a2uiAction leaks into the next run's properties
正确:
try {
copilotkit.setProperties({ ...copilotkit.properties, a2uiAction: msg });
await copilotkit.runAgent({ agent });
} finally {
if (copilotkit.properties) {
const { a2uiAction, ...rest } = copilotkit.properties;
copilotkit.setProperties(rest);
}
}
内置桥接始终在 finally 中剥离 a2uiAction,并通过
copilotkit.properties 空值检查加以保护,以免在解构期间用 TypeError 掩盖
原始的 runAgent 错误。跳过清理会让之前的 action 附着在后续运行上。
来源:packages/react-core/src/v2/a2ui/A2UIMessageRenderer.tsx:146-167
MEDIUM 安装 @copilotkitnext/a2ui-renderer
错误:
import { createA2UIMessageRenderer } from "@copilotkitnext/a2ui-renderer";
正确:
// Low-level primitives (rarely needed — the CopilotKit provider's a2ui prop is the default path):
import {
A2UIProvider,
A2UIRenderer,
createCatalog,
} from "@copilotkit/a2ui-renderer";
// Auto-mounted renderer lives in react-core/v2:
import { createA2UIMessageRenderer } from "@copilotkit/react-core/v2";
此包以 @copilotkit/a2ui-renderer 发布,而不是
@copilotkitnext/a2ui-renderer。@copilotkitnext/ 作用域保留给
其他单独以该作用域发布的包 —— 不要假设它适用于
此处。
来源:packages/a2ui-renderer/package.json