Copilots

Copilots

Copilots are AI assistants embedded within your application that can answer questions, retrieve information, provide suggestions, and accelerate workflows by using application data and APIs. You can create copilots in the Continual console and configure them to connect to models, knowledge bases, and tools to provide a powerful conversational assistant that is deeply integrated with your application.

Copilots can be integrated into your application using:

How copilots work

Copilots connect Knowledge bases, Tools, and Models to provide responses that are accurate, relevant, and actionable within the context of your application.

ResourceDescriptionDetails
CopilotAI assistants that interact with users and provide responsesCopilots
ModelAI models that power natural language understanding and generationModels
Knowledge BaseData sources that copilots can query for informationKnowledge Bases
ToolApplication APIs and services that copilots can interact withTools

User interactions with a copilot occur within a thread. Threads consist of messages exchanged between users and copilots. Threads can support multiple users and copilots communicating with each other, although typically a thread will consist of a single user and a single copilot. Runs and steps capture the execution of a copilot to process a user message and generate a response.

ResourceDescription
ThreadA conversation between users and copilots, consisting of messages
MessageAn individual piece of communication within a thread, sent by either a user or copilot
RunA single execution of a copilot to process a user message and generate a response
StepAn individual action performed by a copilot during a run, such as API calls or knowledge base queries

Continual copilots are similar to the OpenAI Assistant API but support multiple model providers, direct connectivity with frontend applications, and full extensibility by developers.

Creating a copilot

To create a new copilot, navigate to the Copilots tab in the Continual console and click Create copilot. Give your copilot a name, description, base instructions, and select the model to power its natural language and reasoning abilities. You can then configure its knowledge bases, tools, appearance and other settings.

Guiding behavior

A copilots behavior can be controlled by setting instructions. Instructions become part of the model's system prompt and provide high-level guidance and context to your copilot. We recommend adding a bulleted list of behavioral guidelines and context based on the observed behavior of your copilot.

Adding knowledge

Connecting Knowledge bases to your copilot allows it to draw upon curated information such as product documentation to provide accurate and relevant responses. In the knowledge bases section of the copilot's integrations tab, you can add knowledge bases from a variety of sources, includin websites or blob storage. The copilot will intelligently retrieve pertinent information from these sources based on the user's queries. To learn more about knowledge bases, including advanced features like metadata filtering, see Knowledge bases.

Adding skills

Using Tools, copilots can be connected to your application's backend APIs to perform useful actions and access real-time information on behalf of users. In the tools section of a copilot's integrations tab, you can define API endpoints using an OpenAPI specification that the copilot can use to either retrieve information or take actions. To learn more about tools, see Tools.

A critical part of adding skills to your copilot is to ensure that the copilot has the appropriate permissions to access the data and perform the actions on behalf of the user.

Embedding a copilot

The @continual/react package provides pre-built React components and hooks to effortlessly embed a copilot into your React application. The <Copilot> component offers a plug-and-play converational UI, while the React hooks allow you build custom features using the copilot API from your frontend. For even more avanced you cases, you can use the REST API.

To embed a copilot in your React application, install the @continual/react package and add the <Copilot> component to your application root:

import { Copilot, CopilotProvider } from "@continual/react";
import "@continual/react/dist/styles.css";
 
const copilotId = process.env.CONTINUAL_COPILOT_ID;
 
export function App() {
  return (
    <CopilotProvider copilotId={copilotId}>
      {/* Your other app components here. */}
      <Copilot />
    </CopilotProvider>
  );
}

The <CopilotProvider> is responsible managing global configuration and state. The <Copilot> component is the conversational UI that allows users to interact with the copilot. For more details, see the @continual/react documentation.

Customizing appearance

Copilot appearance can be configured in two places:

  1. In the Continual console.
  2. In your application code.

When appearance is configured in the Continual console, the copilot component running in your application will automatically load these settings when it initializes. When appearance is configured in your application code, these settings will override any settings made in the Continual console.

Customizing in the console

Copilot appearance can be set in the Appearance tab of a copilot page. Give your copilot a custom greeting message, chat icon, and display format.

Customizing with code

There are three levels of customization available:

  1. Appearance Props: quickly customize basic UI elements

  2. CSS styling: define the look and feel of the copilot using CSS

  3. Customizing Prebuilt Components: use subcomponents to make a completely custom
    copilot UI.

Appearance props

The following properties can be used to control the visual appearance of the copilot component.

Display format

The <Copilot /> component has four built-in display formats:

  • POPUP (default) - Displays the copilot toggle and window as a floating popup at the bottom right of your application's screen.

  • SIDEBAR - Displays the copilot as a floating window pane on the right side of your application

  • INLINE - Looks the same as POPUP but is positioned within the parent element instead of being fixed to the bottom right of the screen

  • INLINE_FILL - Functions the same as INLINE but stretches to the width and height of the parent element

To configure the display mode in your application code, set the displayFormat property of the <CopilotProvider /> config parameter:

<CopilotProvider config={{ displayFormat: "POPUP" }}>
  <Copilot />
</CopilotProvider>

Avatars and icons

The Copilot avatar and icon can be configured in your application code.

Built-in icons
<CopilotProvider
  config={{
    config: {
      chatIconType: "BUILT_IN",
      chatIcon: "sparkles",
      avatarType: "BUILT_IN",
      avatar: "sparkles",
    },
  }}
/>
Image URLs
<CopilotProvider
  config={{
    config: {
      chatIconType: "URL",
      chatIcon: "my_app.jpg",
      avatarType: "URL",
      avatar: "my_app.jpg",
    },
  }}
/>
Image data URIs
const CopilotIconJpgAsDataUri = "data:image/jpeg;base64,...";
<CopilotProvider
  config={{
    config: {
      chatIconType: "URL",
      chatIcon: CopilotIconJpgAsDataUri,
      avatarType: "URL",
      avatar: CopilotIconJpgAsDataUri,
    },
  }}
/>;
SVG data URIs
import { renderToStaticMarkup } from "react-dom/server";
 
const IconAsSvg = () => (
    <svg ...>...</svg>
)
 
const IconSvgAsString = renderToStaticMarkup(<IconAsSvg />);
 
const IconSvgAsDataUri = `data:image/svg+xml,${encodeURIComponent(
  IconSvgAsString
)}`;
 
<CopilotProvider
  config={{
    config: {
      chatIconType: "URL",
      chatIcon: IconSvgAsDataUri,
      avatarType: "URL",
      avatar: IconSvgAsDataUri,
    },
  }}
/>;
Emojis
const CopilotIconJpgAsDataUri = "data:image/jpeg;base64,...";
<CopilotProvider
  config={{
    config: {
      chatIconType: "EMOJI",
      chatIcon: "🚀",
      avatarType: "EMOJI",
      avatar: "🚀",
    },
  }}
/>;

CSS Styling

Setting the theme with CSS

The overall copilot theme can be styled via CSS variables:

app.tsx
<style>
:root {
  --cai-color-primary: 241 91.1% 64.7%;
}
</style>
 
<Copilot />;

Available theme variables are:

--cai-color-primary
--cai-color-primary-contrast

Styling components with CSS

To set custom CSS styling on <Copilot /> components, target the built-in class names:

MyCopilotStyles.css
.cai .continual__copilot__toggle {
  background-color: red;
}
app.tsx
import "./MyCopilotStyles.css";
 
<Copilot />;

Available built-in class names are:

continual__copilot
continual__copilot__toggle
continual__copilot__window
continual__copilot__window__messenger
continual__copilot__window__messenger__header
continual__copilot__window__messenger__session
cai-avatar-copilot
cai-avatar-user
continual__copilot__window__messenger__user_input
continual__copilot__window__messenger__footer

Class names are under active development. We expect significant changes soon.

If you have more than one instance of Copilot in your application, constrain the styling with an additional className:

App.css
.copilot_1.cai .continual__copilot__toggle {
  background-color: red;
}
app.tsx
import "./App.css";
 
<Copilot className="copilot_1" />;

Customizing your Copilot

Using the <Copilot /> component is the quickest and easiest way to integrate your copilot.

But if you need more control over where and how the copilot UI components are rendered, you can omit using <Copilot/> and instead use the individual UI components.

For example, to render the copilot toggle component in your application header, while rendering the copilot window in your existing sidebar:

import { CopilotProvider, CopilotToggle, CopilotWindow } from "@continual/react";
import "@continual/react/dist/styles.css";
 
function App() {
  return (
    <>
      <CopilotProvider copilotId={ContinualCopilotId}>
        <Header>
          <CopilotToggle />
        </Header>
        <Sidebar>
          <CopilotWindow />
        </Sidebar>
        <Content>{/* the rest of your application */}</Content>
      </CopilotProvider>
    </>
  );
}

Securing a copilot

Continual Access Tokens are used to verify a user's identity when interacting with a copilot. They are JWT tokens signed with the copilot's secret key. The access token must contain the copilot ID (iss claim) and user ID (identity claim).

To enable authentication, generate the access token on your backend server and pass it to the <CopilotProvider> component:

const accessToken = generateAccessToken(userId, copilotId, copilotSecretKey);
 
<CopilotProvider accessToken={accessToken}>
  <Copilot />
</CopilotProvider>;

Adding client context

Client context is additional information you can send to the copilot from your application. Client context is included as part of a user message that is sent to the copilot.

You can use client context to inform the copilot about the state of your application, what page or screen the user is on, and what the content on the page or screen is.

Setting application level context

If your application keeps track of application level context such as who is logged in, what the active organization unit is, etc., you can set this at the <CopilotProvider /> component level:

_app.tsx
import { Copilot } from "@continual/react";
 
const user = api.user(...);
const organization = api.organization(...)
 
<CopilotProvider
    context={{
        user: {
            fullName: user?.fullName,
            location: user?.location,
        },
        organization: {
            id: organization?.id,
            name: organization?.name,
        },
    }}
/>

Setting page-level context

If you'd also like to send page or screen specific information to the copilot, such as the contents of the screen whenever the user is navigating through your application, you can set this at the page level using the useCopilotContext hook:

page.tsx
import { useCopilotContext } from "@continual/react";
 
const [copilotContext, setCopilotContext] = useCopilotContext();
 
products = api.load(...)
 
useEffect(() => {
    setCopilotContext((c) => {
        return {
            ...c,
            screen: {
                content: ["A list of products", ...products],
            },
        };
    });
}, [products]);

Context content

It is up to you to decide what client context you'd like to send to the copilot. If you don't want your copilot to respond to information that is on the user's screen or page, don't send any client context. If you'd like the copilot to provide detailed responses based on what the user has on their page or screen, send as much data in the client context as is appropriate.

Context format

The format and data type of the client context is up to you to decide, based on what you want to send, and how you want to manage it.

You can send a simple string:

<CopilotProvider context="I am on the products page" />

You can also send a complex JSON object:

<CopilotProvider
    context={{
        pageUrl: "/products",
        pageTitle: "List of products",
        pageContents: [...products.map(p => ({title: p.title, description: p.description price: p.price}))]
    }}
/>

In either case the copilot will take the contents of the context field, stringify it, and use it as context to its reasoning process.

Custom UIs

If you don't want to use the pre-built UI components, you can also use React hooks or the the Continual REST API in a headless way to build your own components.