mcpField
A
a2ui-renderer

a2ui-renderer

github.com/copilotkit开发38.3k2.7k 次安装今天更新
代码仓库

关于 a2ui-renderer

用于在 CopilotKit 应用中启用 A2UI 渲染的技能,说明运行时和客户端所需配置,并指出重复渲染、重复创建 surface 等实现问题。

主要功能

  1. 01启用运行时与客户端 A2UI
  2. 02使用自动渲染器检测
  3. 03说明 surface 更新模式
  4. 04介绍 action 清理要求
  5. 05指出常见配置错误

适用场景

  1. 01在 CopilotKit 应用中添加 A2UI
  2. 02同时配置运行时与客户端
  3. 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

评论

支持 Markdown