> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thesys.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Integrating C1 with CopilotKit

> Build Generative UI copilots with CopilotKit & Thesys C1

This guide demonstrates how to integrate **C1 by Thesys** with **CopilotKit** - the open-source
Agentic Application Framework for building in-app AI Copilots, CoAgents, and Generative UI agents.
Leveraging Agentic Generative UI, shared state, human-in-the-loop (HITL) patterns,
and the AG-UI protocol, this integration enables the creation of customizable, real-time, and production-ready AI copilots within your application.

<Note>
  This guide assumes you have basic knowledge of CopilotKit.
  You'll also need a Thesys API key from the [C1 Console](https://console.thesys.dev/keys).
</Note>

<Steps>
  <Step title="Create a new CopilotKit project">
    ```bash theme={null}
    npx create-next-app@latest my-copilot-app
    ```
  </Step>

  <Step title="Install CopilotKit Runtime with OpenAI">
    ```bash theme={null}
    npm install --save @copilotkit/runtime openai@4.85.1
    ```

    ```ts app/api/completion/route.ts theme={null}
    import {
      CopilotRuntime,
      OpenAIAdapter,
      copilotRuntimeNextJSAppRouterEndpoint,
    } from "@copilotkit/runtime";
    import OpenAI from "openai";

    import { NextRequest } from "next/server";

    const openai = new OpenAI({
      baseURL: "https://api.thesys.dev/v1/embed",
      apiKey: process.env.THESYS_API_KEY,
    });
    const serviceAdapter = new OpenAIAdapter({
      openai,
      model: "c1/anthropic/claude-sonnet-4/v-20250815",
    });
    const runtime = new CopilotRuntime();

    export const POST = async (req: NextRequest) => {
      const { handleRequest } = copilotRuntimeNextJSAppRouterEndpoint({
        runtime,
        serviceAdapter,
        endpoint: "/api/chat",
      });

      return handleRequest(req);
    };
    ```
  </Step>

  <Step title="Create a Copilot">
    In this guide we will be using the `CopilotSidebar` component to create a sidebar copilot.
    But you can easily replace it with `CopilotChat` or `CopilotPopup` to create a chat or popup copilot.

    ```bash theme={null}
    npm install --save @thesysai/genui-sdk @crayonai/react-ui @copilotkit/react-core @copilotkit/react-ui
    ```

    ```tsx app/layout.tsx theme={null}
    import "./globals.css";
    import { ReactNode } from "react";
    import { CopilotKit } from "@copilotkit/react-core";

    export default function RootLayout({ children }: { children: ReactNode }) {
      return (
        <html lang="en">
          <body>
            <CopilotKit runtimeUrl="/api/chat">{children}</CopilotKit>
          </body>
        </html>
      );
    }
    ```

    ```tsx app/page.tsx theme={null}
    "use client";

    import { C1Component, ThemeProvider } from "@thesysai/genui-sdk";
    import {
      CopilotSidebar,
      ImageRenderer,
      UserMessage,
    } from "@copilotkit/react-ui";
    import "@copilotkit/react-ui/styles.css";
    import "@crayonai/react-ui/styles/index.css";
    import { useCopilotChat } from "@copilotkit/react-core";
    import { MessageRole, TextMessage } from "@copilotkit/runtime-client-gql";

    const AssistantMessageRenderer = ({ message, isGenerating }: any) => {
      const { appendMessage } = useCopilotChat();
      // In the Assistant Message, render the C1Component rather than rendering a markdown message.
      return (
        <C1Component
          c1Response={message?.content || ""}
          isStreaming={isGenerating}
          onAction={(action) => {
            appendMessage(
              new TextMessage({
                role: MessageRole.User,
                // Action is a object with 2 keys: llmFriendlyMessage and humanFriendlyMessage.
                // We stringify it because the content field of CopilotKit is a string.
                content: JSON.stringify(action),
              })
            );
          }}
        />
      );
    };

    const UserMessageRenderer = ({ message }: any) => {
      // Since content can either be a string or a json object (in the case of an Action)
      // we need to parse it and extract the humanFriendlyMessage incase its a json object.
      let content = message?.content;
      try {
        const { humanFriendlyMessage } = JSON.parse(message?.content || "{}");
        content = humanFriendlyMessage;
      } catch (error) {}
      return (
        <UserMessage
          message={{ ...message, content }}
          ImageRenderer={ImageRenderer}
          rawData=""
        />
      );
    };

    export default function Page() {
      return (
        <ThemeProvider>
          <CopilotSidebar
            defaultOpen
            instructions={
              "You are assisting the user as best as you can. Answer in the best way possible given the data you have."
            }
            // Override the default UserMessage and AssistantMessage components to install
            // C1 Components.
            UserMessage={UserMessageRenderer}
            AssistantMessage={AssistantMessageRenderer}
          />
        </ThemeProvider>
      );
    }

    ```
  </Step>

  <Step title="Run the app">
    ```bash theme={null}
    export THESYS_API_KEY=<your-api-key>
    npm run dev
    ```
  </Step>
</Steps>

<Card title="View the code" icon="github" href="https://github.com/thesysdev/examples/tree/main/copilotkit">
  Find more examples and complete code on our GitHub repository.
</Card>
