@copilotkit/react-native

中文文档
1.86.0发布于 2026/11/11MITTypeScriptESM + CJS构建来源已验证近 30 天下载 15.1万

副驾驶Kit的无头回放原生装订. 提供轻量级提供商并再出口平台-不可知钩-没有DOM,CSS,或网络框架依赖性. 您用标准 React 本地组件构建聊天 UI .

中文使用文档
文档目录6 节
  1. 安装
  2. 圆柱体
  3. 快开始
  4. 基因UI(实验性)
  5. API 表面
  6. 文档

@ copilotkit/ 反应本地化

副驾驶Kit的无头回放原生装订. 提供轻量级提供商并再出口平台-不可知钩-没有DOM,CSS,或网络框架依赖性. 您用标准 React 本地组件构建聊天 UI .

安装

npm install @copilotkit/react-native "zod@^3.25"

每一个条目都需要 zod 3.25 或以后,同龄人依赖 @copilotkit/react-core。命令安装了 zod 3, 这是一种基因化的 UI 使用目录 child() 或者说 childList() 需要帮助.

圆柱体

React Industrial's JS runtime (Hermes) 缺少几个由CopilotKit所依赖的Web API. 导入多填充器 在任何其他代码之前 输入点 :

// index.js
import "@copilotkit/react-native/polyfills";

import { AppRegistry } from "react-native";
import App from "./App";
import { name as appName } from "./app.json";

AppRegistry.registerComponent(appName, () => App);

如果您已经填充了其中的一些 API, 您只能导入您需要的 :

import "@copilotkit/react-native/polyfills/streams";
import "@copilotkit/react-native/polyfills/encoding";
import "@copilotkit/react-native/polyfills/crypto";
import "@copilotkit/react-native/polyfills/dom";
import "@copilotkit/react-native/polyfills/location";

快开始

import {
  CopilotKitProvider,
  useAgent,
  useCopilotKit,
} from "@copilotkit/react-native/headless";

export default function App() {
  return (
    <CopilotKitProvider runtimeUrl="https://your-server/api/copilotkit">
      <ChatScreen />
    </CopilotKitProvider>
  );
}

再出口钩子从 @copilotkit/react-core数字 : useAgent, (中文(简体) ), useFrontendTool, (中文(简体) ), useComponent, (中文(简体) ), useHumanInTheLoop, (中文(简体) ), useInterrupt, (中文(简体) ), useSuggestions, (中文(简体) ), useConfigureSuggestions, (中文(简体) ), useAgentContext, (中文(简体) ), useThreads,以及 useCopilotKit。 。 。 .

基因UI(实验性)

@copilotkit/react-native/generative-ui 让代理制作您的目录 拥有本地组件 render_ui 工具。 安装 zod 3.25或以后: 包的每个条目都需要它 因为 @copilotkit/react-core 需求 作为同伴的依赖关系(@copilotkit/react-native 声明 zod 选项 端点 >=3.0.0 只因为缩小这个范围是一次突破 页:1 安装 zod 3 (npm install "zod@^3.25"用于目录 child() 或者说 childList():它们返回了zod 3个计划,这个zod 4个计划 无法维持。 运行时间默认不需要更改 : CopilotRuntime 添加 当应用程序发送至少包含一个组件的目录时的工具,除非 服务器集 generativeUI: false 或者限制它与 generativeUI: { agents: [...] }。此示例需要 home 代理在 运行时间: 一旦运行时间连接, useAgent 抛出没有它. /generative-ui 1.8.5.0或任何较早的版本 1.8.5.0之后释放的船舶.

import { useCallback, useEffect, useRef, useState } from "react";
import {
  ActivityIndicator,
  Pressable,
  ScrollView,
  Text,
  View,
} from "react-native";
import { z } from "zod";
import {
  CopilotKitCoreErrorCode,
  CopilotKitCoreRuntimeConnectionStatus,
  CopilotKitProvider,
  useAgent,
  useAgentContext,
  useCopilotKit,
} from "@copilotkit/react-native/headless";
import {
  GenerativeUIActivity,
  GenerativeUIProvider,
  createGenerativeUI,
  isGenerativeUIActivity,
  useGenerativeUIRuntime,
  type GenerativeUIActivityMessage,
} from "@copilotkit/react-native/generative-ui";

const ui = createGenerativeUI({
  id: "acme/bank@1",
  components: {
    BalanceCard: {
      component: ({ account, amount }: { account: string; amount: number }) => (
        <View>
          <Text>{account}</Text>
          <Text>{amount}</Text>
        </View>
      ),
      description:
        "The balance of one account. Copy the values from the context.",
      props: z.object({ account: z.string(), amount: z.number() }),
    },
  },
});

type CopilotKit = ReturnType<typeof useCopilotKit>["copilotkit"];
type Agent = ReturnType<typeof useAgent>["agent"];

/**
 * The errors that end a run. A failed tool call is not one of them
 * (TOOL_HANDLER_FAILED, TOOL_ARGUMENT_PARSE_FAILED): its error goes back to
 * the model as the result of the call, and the run goes on.
 */
const RUN_FAILURES: ReadonlySet<CopilotKitCoreErrorCode> = new Set([
  CopilotKitCoreErrorCode.AGENT_RUN_FAILED,
  CopilotKitCoreErrorCode.AGENT_RUN_FAILED_EVENT,
  CopilotKitCoreErrorCode.AGENT_RUN_ERROR_EVENT,
  CopilotKitCoreErrorCode.AGENT_THREAD_LOCKED,
]);

// Date.now() alone repeats within a millisecond; with a counter, ids do not.
let sent = 0;

/**
 * Sends one user message and runs the agent. Resolves with the run's error,
 * or undefined; it never rejects. It counts every run failure of this agent
 * while it waits, so start one run of an agent at a time.
 */
async function runTurn(copilotkit: CopilotKit, agent: Agent, content: string) {
  const before = agent.messages.map((message) => message.id);
  const { threadId } = agent;
  let failure: Error | undefined;
  const subscription = copilotkit.subscribe({
    onError: ({ error, code, context }) => {
      if (context.agentId === agent.agentId && RUN_FAILURES.has(code)) {
        failure ??= error;
      }
    },
  });
  try {
    sent += 1;
    agent.addMessage({
      id: `user-${Date.now()}-${sent}`,
      role: "user",
      content,
    });
    await copilotkit.runAgent({ agent });
  } catch (error) {
    failure ??= error instanceof Error ? error : new Error(String(error));
  } finally {
    subscription.unsubscribe();
  }
  try {
    if (failure) takeBack(agent, before, threadId);
  } catch (error) {
    console.error("Could not take the failed turn back:", error);
  }
  return failure;
}

/**
 * Removes the messages added since `before` (their ids), such as the user
 * message and a partial reply. It keeps the surfaces: the provider keeps
 * every surface that a run rendered, and the model still sees it, so the
 * screen shows it too.
 */
function takeBack(
  agent: Agent,
  before: readonly string[],
  threadId: string | undefined,
) {
  // The agent moved to another thread: those messages are not this turn's.
  if (agent.threadId !== threadId) return;
  const kept = new Set(before);
  agent.setMessages(
    agent.messages.filter(
      (message) => kept.has(message.id) || isGenerativeUIActivity(message),
    ),
  );
}

/**
 * An activity message that GenerativeUIActivity draws: its surface is aimed at
 * the chat (the target it shows) and the agent has not deleted it.
 */
function isChatSurface(message: GenerativeUIActivityMessage) {
  if (!isGenerativeUIActivity(message)) return false;
  const content = message.content as {
    target?: unknown;
    operations?: unknown;
  } | null;
  const operations = Array.isArray(content?.operations)
    ? content.operations
    : [];
  return (
    content?.target === "chat" &&
    !operations.some(
      (op) => typeof op === "object" && op !== null && "deleteSurface" in op,
    )
  );
}

/**
 * The chat surfaces that this device built, each message id with its operations,
 * to tell whether a run rendered or updated one here. The operations alone: each
 * call of the agent also refills the list of rejected operations, so a call whose
 * updates were all rejected changes the content but not the surface. A surface
 * whose createSurface the app rejected (`failed`) does not count: the app checks
 * the operations again, prop values included, and GenerativeUIActivity then shows
 * only an error line.
 */
function chatSurfaces(
  messages: readonly GenerativeUIActivityMessage[],
  failed: (surfaceId: string) => boolean,
) {
  const built = new Map<string | undefined, string>();
  for (const message of messages.filter(isChatSurface)) {
    const { surfaceId, operations } = message.content as {
      surfaceId?: unknown;
      operations?: unknown;
    };
    if (typeof surfaceId === "string" && failed(surfaceId)) continue;
    built.set(message.id, JSON.stringify(operations));
  }
  return built;
}

// Your app's data. The agent sees only what you give it with useAgentContext.
const accounts = [
  { account: "Chequing", amount: 3482.1 },
  { account: "Savings", amount: 6150 },
];

function Home() {
  const { copilotkit } = useCopilotKit();
  // Until the runtime connects, `agent` is a stand-in (`isReady` is false). The
  // registered agent replaces it, so a run started on the stand-in is lost.
  // Once the runtime has connected, useAgent throws if it has no `home` agent.
  const { agent, isReady } = useAgent({ agentId: "home" });
  const runtime = useGenerativeUIRuntime();
  // The thread it last checked: a ref, so StrictMode's second effect run sees it.
  const checkedThread = useRef<string | undefined>(undefined);
  const composing = useRef(false); // a ref, so a second tap is ignored at once
  const [checked, setChecked] = useState(false);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string>();

  useAgentContext({
    description:
      "The user's accounts. Show only these, with these exact balances.",
    value: accounts,
  });

  const failed = useCallback(
    (surfaceId: string) =>
      !!runtime?.manager.getFailedSurface(agent.threadId, surfaceId),
    [runtime, agent],
  );

  const compose = useCallback(async () => {
    // A stand-in agent (not ready) would lose the run.
    if (composing.current || !isReady) return;
    composing.current = true;
    setBusy(true);
    setError(undefined);
    try {
      const before = agent.messages.map((message) => message.id);
      const { threadId } = agent;
      const shownBefore = chatSurfaces(agent.messages, failed);
      const failure = await runTurn(copilotkit, agent, "Show my balances.");
      const shownAfter = chatSurfaces(agent.messages, failed);
      if (failure) {
        // runTurn took the prompt back, so a retry sends it once.
        setError(failure.message);
      } else if (
        ![...shownAfter].some(
          ([id, content]) => shownBefore.get(id) !== content,
        )
      ) {
        // This run rendered or updated nothing here. Take its prompt back too.
        takeBack(agent, before, threadId);
        setError("The agent rendered nothing for this screen.");
      }
    } catch (reason) {
      setError(reason instanceof Error ? reason.message : String(reason));
    } finally {
      composing.current = false;
      setBusy(false);
    }
  }, [agent, copilotkit, failed, isReady]);

  // The agent and its messages live in the core and outlive this screen. Run only
  // when the registered agent has no surface here yet and is not running, so a
  // screen that mounts again shows what it has instead of composing it again.
  // Check again when the agent moves to another thread, once it is not running
  // and no compose is under way (`busy` reruns this when one ends).
  useEffect(() => {
    if (
      !isReady ||
      busy ||
      composing.current ||
      agent.isRunning ||
      checkedThread.current === agent.threadId
    ) {
      return;
    }
    checkedThread.current = agent.threadId;
    setChecked(true);
    setError(undefined);
    if (chatSurfaces(agent.messages, failed).size === 0) {
      void compose();
    }
  }, [isReady, busy, agent, agent.threadId, agent.isRunning, compose, failed]);

  const surfaces = agent.messages.filter(isChatSurface);
  const built = chatSurfaces(agent.messages, failed);
  const unreachable =
    copilotkit.runtimeConnectionStatus ===
    CopilotKitCoreRuntimeConnectionStatus.Error;
  const waiting = !isReady || !checked || busy || agent.isRunning;

  return (
    <ScrollView contentContainerStyle={{ padding: 16 }}>
      {surfaces.map((message) => (
        <GenerativeUIActivity
          key={message.id}
          message={message}
          agent={agent}
        />
      ))}
      {unreachable ? (
        <Text accessibilityRole="alert">
          Can't reach the agent. Check the runtime URL.
        </Text>
      ) : waiting ? (
        <ActivityIndicator />
      ) : error || built.size === 0 ? (
        <Pressable accessibilityRole="button" onPress={() => void compose()}>
          <Text>
            Couldn't load your balances{error ? ` (${error})` : ""}. Tap to try
            again.
          </Text>
        </Pressable>
      ) : null}
    </ScrollView>
  );
}

export default function App() {
  return (
    <CopilotKitProvider runtimeUrl="https://your-server/api/copilotkit">
      <GenerativeUIProvider ui={ui}>
        <Home />
      </GenerativeUIProvider>
    </CopilotKitProvider>
  );
}

GenerativeUIActivity 使一个活动消息的表面在您自己的 信件列表或屏幕上没有聊天。 就像网络聊天,它只显示 面向聊天的表面; 通过 target 以显示另一个目标。 它让 无所事事(并在发展中发出警告) GenerativeUIProvider下,a 没有提供者 ui,或当代理人没有 threadId。示例显示 一个旋转器,一个无法到达的跑步时间 和与原因的重试。 运行失败 迅速被带回,但表面 它使停留: 提供者和 模特儿留着 文档添加聊天列表 . GenerativeUISurface 在应用程序中标出一个命名的地方; style 应用时 倒计时秀也。 只传送工具; 没有标准目录, 没有 theme 道具(a) theme 由 JavaScript 传递, 并随开发而放弃 (警告)和无 openUrl ( 它失败 ) “ 打开Url 无法在此访问 平台”和预建 CopilotChat 尚未绘制表面。 见 反应原生文件。 。 。 .

API 表面

根导入( E)@copilotkit/react-native这是v2 API. 和SDK的网络不同 /v2 子路径, 反应本地导出 直接取自包根的 v2 API.

根还再导出聊天组件和 useAttachments,哪个 进口 expo-document-picker 财务报告和审定财务报表 expo-file-system; Metro解决了它们 捆绑时间,所以从根部导入的应用程序必须同时安装两种. @copilotkit/react-native/headless 将提供者和钩子导出 这就是上面的"快起步"使用的原因.

文档

完整的设置指令、使用示例和故障排除,见 反应原生文件。 。 。 .

版本与发布记录

@copilotkit/react-native 共发布 160 个版本,首次发布于 2026/05/07;过去 12 个月发布了 160 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
1.86.0latest2026/11/11今天
2.0.0-rc.40next2026/11/11今天
2.0.0-rc.392026/11/10今天
2.0.0-rc.382026/11/10今天
2.0.0-rc.372026/11/091 天前
2.0.0-rc.362026/11/064 天前

其他发布通道:canary → 1.84.2-canary.openbot-intel-fixes,next → 2.0.0-rc.40。

关于 @copilotkit/react-native 的常见问题

@copilotkit/react-native 是什么?

副驾驶Kit的无头回放原生装订. 提供轻量级提供商并再出口平台-不可知钩-没有DOM,CSS,或网络框架依赖性. 您用标准 React 本地组件构建聊天 UI .

如何安装 @copilotkit/react-native?

在项目目录运行 npm install @copilotkit/react-native,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:react(^18 || ^19)、react-native(>=0.70)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@copilotkit/react-native 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@copilotkit/react-native 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@copilotkit/react-native 可以商用吗?

@copilotkit/react-native 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@copilotkit/react-native 的下载量有多少?

根据 npm 官方下载统计,@copilotkit/react-native 在 2026/10/11 – 2026/11/09 这 30 天内被下载 150,581 次,日均约 5,019 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@copilotkit/react-native 还在维护吗?

最新版本 1.86.0 发布于 2026/11/11(今天);至今共发布 160 个版本,其中过去 12 个月发布了 160 个;首次发布于 2026/05/07。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。