Next.js tutorial
This short tutorial shows how to implement a Continual AI Copilot in a basic Next.js template app. It's assumed you will not be using an existing Next.js application, but feel free to use an existing app if preferred!
Create a Next.js app
- If you don’t have Node.js installed, install it from here (opens in a new tab). You’ll need Node.js version 18 or higher.
- You’ll be using your own text editor and terminal app for this tutorial.
To create a Next.js app, open your terminal, cd into the directory you’d like to create the app in, and run the following command:
npx create-next-app@latest nextjs-blog --use-npm --example "https://github.com/vercel/next-learn/tree/main/basics/learn-starter"
Under the hood, this uses the tool called create-next-app (opens in a new tab), which bootstraps a Next.js app for you using this template (opens in a new tab).
If it doesn’t work, please take a look at this page (opens in a new tab).
Run the development server
You now have a new directory called nextjs-blog. cd into it and start the dev server:
cd nextjs-blog
pnpm run dev
This starts the "development server" on port 3000.
Let’s check to see if it’s working. Open http://localhost:3000 (opens in a new tab) from your browser.
Return to your code editor and open the pages/index.js
file where we'll drop in the Continual
Copilot React component. The copilot backend has not been created yet, but since we're already in
the frontend, let's start here and then go to the Continual console to create the copilot in
Continual.
Install the Continual frontend package
Download and install the @continual/react
package.
pnpm add @continual/react
Add the <Copilot/>
component to Home()
At the top of index.js
, import the necessary modules and set the Continual Copilot ID and
Continual API secret. Once we create the copilot in Continual, we'll create the .env file to store
these variables:
import { Copilot, CopilotProvider, useCopilotContext } from "@continual/react";
import "@continual/react/dist/styles.css";
const ContinualCopilotId = process.env.NEXT_PUBLIC_CONTINUAL_COPILOT_ID;
const ContinualSecret = process.env.NEXT_PUBLIC_CONTINUAL_SECRET;
In the Return
statement, wrap the entire app component with the <CopilotProvider/>
component:
return (
<div className={styles.container}>
<CopilotProvider copilotId={ContinualCopilotId} accessToken={ContinualSecret}>
{/* Your other app components here. */}
<Copilot />
</CopilotProvider>
</div>
);
The final frontend step is to create the .env
in preparation for our Copilot ID and Continual API
secret:
NEXT_PUBLIC_CONTINUAL_COPILOT_ID=my-copilot-id
NEXT_PUBLIC_CONTINUAL_SECRET=my-continual-api-secret
We need to create a copilot and api key in Continual to generate those values.
Create a Copilot in Continual
If you haven’t already, begin by signing up (opens in a new tab) for Continual.
If you plan to collaborate with other team members, create a team workspace by clicking Create Workspace in the workspace menu in the top left of the Continual console.
After signing up for Continual, create a copilot in the Continual Console (opens in a new tab) by clicking Copilots from the sidebar and then Create Copilot. Give it a name and choose a model. We recommend starting with OpenAI GPT 4 Omni but be sure to try out our other supported models.
After the copilot has been created, copy the copilotId
in the top right corner of the copilot page
and go paste it into your .env
file in place of my-copilot-id
.
Create an API key
Next, click on API Keys
and generate a Continual API key. We'll use the secret key to authenticate
your copilot in the Next.js application with the Continual backend. Copy the secret key and go paste
it into your .env
file in place of continual-api-secret
.
Boom! You should see a small chat icon on the bottom right of your Next.js app.
Click on it and say Hello!
We haven't connected any Knowledge Bases or Tools to this copilot. It only has the underlying LLM's general knowledge and the default global guidelines. The Global Guidelines allow you to customize the behavior of your copilot and add important additional context. We recommended adding and removing a bulleted list of behavioral guidelines and context based on the observed behavior of your copilot.
Customize Copilot Behavior by editing Global Guidelines
Return to the Continual Console and click on your copilot and then the Settings tab. Update the
first line of the default global guidelines to
You are a highly intelligent AI copilot embedded within an NextJS blog template application.
Now, tell the copilot to describe itself and observe the global guideline being applied.
Next, let's create and connect a Knowledge Base and a Tool.
Enable RAG with Continual Knowledge Bases
Knowledge bases are semantically indexed stores of information that copilots can access to provide users with accurate and up-to-date information, whether that is product documentation, FAQs, or user uploaded documents and data. This ensures that your copilot always has the most up-to-date information to provide to users.
In this tutorial, we can use the Next.js documentation (opens in a new tab) as an example.
Create a Knowledge Base
On the main page of your Next.js blog sample app, there are tiles with links to their documentation, interactive courses, examples, and Vercel. Click on the tile to the documentation and copy the link.
Return to the Continual Console, click on Knowledge Bases and create a new one. There are two knowledge base types: Unmanaged and Managed. Managed knowledge bases continuously sync from an external data source like a website, cloud storage bucket, or content repository. Unmanaged knowledge bases allow you to manually upload files and documents.
Choose a managed knowledge base and enter the Next.js documentation URL.
Choose the Raw HTTP crawler and click Connect.
Finally, click Create to create the knowledge base.
While the next.js documentation is being crawled, go onto the next step and create a Tool. We'll connect and test both Knowledge Bases and Tools after that.
Unlock Tool usage
Tools allow you to extend copilots by connecting them to APIs, whether your application's API or task-specific APIs to empower the copilot to perform new or better tasks. An external tool is defined using an OpenAPI specification, providing a standardized way to describe the API endpoints, parameters, and responses. In the future, Continual may support additional tool types.
Create a Tool
We're going to use the Continual API to create a Tool that allows the copilot to take action in the continual console.
Create a new Tool and give it a name. Choose "Service Bearer Token" for the authentication and paste in the Continual API Key you generated earlier. This would be your API key if we were making a Tool for your application. But we'll use a sample OpenAPI Specification of Continual's API for this example.
Copy the Continual API Specification Sample and paste it into the Tool Specification text box. Then click Create.
Continual API Specification Sample
{
"openapi": "3.0.3",
"info": {
"title": "Continual API",
"description": "OpenAPI compliant REST API for Continual. The public API is not currently stable and may change without notice. Use at your own risk. For more information, see the [Continual API documentation](https://docs.continual.ai).",
"version": "1.0.0"
},
"servers": [
{
"url": "https://console.continual.ai/api/v1"
}
],
"paths": {
"/copilots": {
"post": {
"operationId": "mutation.copilots.create",
"summary": "Create Copilot",
"description": "Creates a Copilot that can be used headlessly or via an embedded widget",
"tags": [
"Copilots"
],
"security": [
{
"Authorization": []
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"maxLength": 100,
"description": "The name of the Copilot. Maximum length of 100 characters."
},
"workspaceId": {
"type": "string",
"description": "The workspace ID."
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 user-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"modelProviderId": {
"type": "string",
"description": "The Model Provider ID used by this copilot."
},
"description": {
"type": "string",
"description": "The description of the Copilot."
},
"instructions": {
"type": "string",
"description": "The LLM instructions for the Copilot."
},
"anonymousAccessEnabled": {
"type": "boolean",
"description": "If enabled, users do not need to be authenticated."
},
"avatarType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The avatar type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"avatar": {
"type": "string",
"description": "The source for the Copilot avatar"
},
"chatIconType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The Copilot icon type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"chatIcon": {
"type": "string",
"description": "The source for the Copilot icon"
},
"chatUserInputPlaceholder": {
"type": "string",
"description": "The default user input prompt"
},
"chatGreetingMessage": {
"type": "string",
"description": "The copilot greeting message"
},
"displayFormat": {
"type": "string",
"enum": [
"popup",
"sidebar",
"inline",
"inline_fill",
"POPUP",
"SIDEBAR",
"INLINE",
"INLINE_FILL"
],
"description": "The display format the Copilot (\"popup\" | \"sidebar\" | \"inline\" | \"inline_fill\" | \"POPUP\" | \"SIDEBAR\" | \"INLINE\" | \"INLINE_FILL\")."
},
"model": {
"type": "string",
"description": "The Model used by this copilot."
}
},
"additionalProperties": false
}
}
}
},
"parameters": [],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Copilot ID."
},
"object": {
"type": "string",
"enum": [
"copilot"
],
"description": "The resource type."
},
"workspaceId": {
"type": "string",
"description": "The workspace ID."
},
"name": {
"type": "string",
"maxLength": 100,
"description": "The name of the Copilot. Maximum length of 100 characters."
},
"modelProviderId": {
"type": "string",
"description": "The Model Provider ID used by this copilot."
},
"model": {
"type": "string",
"description": "The Model used by this copilot."
},
"description": {
"type": "string",
"description": "The description of the Copilot."
},
"instructions": {
"type": "string",
"description": "The LLM instructions for the Copilot."
},
"displayFormat": {
"type": "string",
"enum": [
"popup",
"sidebar",
"inline",
"inline_fill",
"POPUP",
"SIDEBAR",
"INLINE",
"INLINE_FILL"
],
"description": "The display format the Copilot (\"popup\" | \"sidebar\" | \"inline\" | \"inline_fill\" | \"POPUP\" | \"SIDEBAR\" | \"INLINE\" | \"INLINE_FILL\")."
},
"anonymousAccessEnabled": {
"type": "boolean",
"description": "If enabled, users do not need to be authenticated."
},
"avatarType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The avatar type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"avatar": {
"type": "string",
"description": "The source for the Copilot avatar"
},
"chatIconType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The Copilot icon type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"chatIcon": {
"type": "string",
"description": "The source for the Copilot icon"
},
"chatUserInputPlaceholder": {
"type": "string",
"description": "The default user input prompt"
},
"chatGreetingMessage": {
"type": "string",
"description": "The copilot greeting message"
},
"updatedAt": {
"type": "string",
"format": "date-time",
"description": "Updated time."
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 user-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"createdAt": {
"type": "string",
"format": "date-time",
"description": "Created time."
}
},
"required": [
"id",
"object",
"workspaceId",
"displayFormat",
"updatedAt",
"metadata",
"createdAt"
],
"additionalProperties": false
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
},
"get": {
"operationId": "query.copilots.list",
"summary": "List Copilots",
"description": "Returns a list of Copilots for the workspace.",
"tags": [
"Copilots"
],
"security": [
{
"Authorization": []
}
],
"parameters": [
{
"name": "workspaceId",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Filter by workspace ID. Defaults to the currently active workspace."
},
{
"name": "order",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"asc",
"desc"
],
"default": "desc"
},
"description": "The order of the list. Defaults to `desc` by created date."
},
{
"name": "pageSize",
"in": "query",
"required": false,
"schema": {
"type": "number",
"minimum": 1,
"maximum": 1000,
"default": 30
},
"description": "The page size of the list. Defaults to 30."
},
{
"name": "nextPageToken",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "The page token of the list."
},
{
"name": "previousPageToken",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "The page token of the list."
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"object": {
"type": "string",
"enum": [
"list"
],
"description": "The object type of the list."
},
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Copilot ID."
},
"object": {
"type": "string",
"enum": [
"copilot"
],
"description": "The resource type."
},
"workspaceId": {
"type": "string",
"description": "The workspace ID."
},
"name": {
"type": "string",
"maxLength": 100,
"description": "The name of the Copilot. Maximum length of 100 characters."
},
"modelProviderId": {
"type": "string",
"description": "The Model Provider ID used by this copilot."
},
"model": {
"type": "string",
"description": "The Model used by this copilot."
},
"description": {
"type": "string",
"description": "The description of the Copilot."
},
"instructions": {
"type": "string",
"description": "The LLM instructions for the Copilot."
},
"displayFormat": {
"type": "string",
"enum": [
"popup",
"sidebar",
"inline",
"inline_fill",
"POPUP",
"SIDEBAR",
"INLINE",
"INLINE_FILL"
],
"description": "The display format the Copilot (\"popup\" | \"sidebar\" | \"inline\" | \"inline_fill\" | \"POPUP\" | \"SIDEBAR\" | \"INLINE\" | \"INLINE_FILL\")."
},
"anonymousAccessEnabled": {
"type": "boolean",
"description": "If enabled, users do not need to be authenticated."
},
"avatarType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The avatar type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"avatar": {
"type": "string",
"description": "The source for the Copilot avatar"
},
"chatIconType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The Copilot icon type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"chatIcon": {
"type": "string",
"description": "The source for the Copilot icon"
},
"chatUserInputPlaceholder": {
"type": "string",
"description": "The default user input prompt"
},
"chatGreetingMessage": {
"type": "string",
"description": "The copilot greeting message"
},
"updatedAt": {
"type": "string",
"format": "date-time",
"description": "Updated time."
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 user-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"createdAt": {
"type": "string",
"format": "date-time",
"description": "Created time."
}
},
"required": [
"id",
"object",
"workspaceId",
"displayFormat",
"updatedAt",
"metadata",
"createdAt"
],
"additionalProperties": false
},
"description": "The list of resources."
},
"nextPageToken": {
"type": "string",
"description": "The next page token of the list."
},
"previousPageToken": {
"type": "string",
"description": "The previous page token of the list."
}
},
"required": [
"object",
"data"
],
"additionalProperties": false
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
}
},
"/copilots/{id}": {
"patch": {
"operationId": "mutation.copilots.update",
"summary": "Update Copilot",
"description": "Update a Copilot.",
"tags": [
"Copilots"
],
"security": [
{
"Authorization": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"maxLength": 100,
"description": "The name of the Copilot. Maximum length of 100 characters."
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 user-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"modelProviderId": {
"type": "string",
"description": "The Model Provider ID used by this copilot."
},
"model": {
"type": "string",
"description": "The Model used by this copilot."
},
"description": {
"type": "string",
"description": "The description of the Copilot."
},
"instructions": {
"type": "string",
"description": "The LLM instructions for the Copilot."
},
"anonymousAccessEnabled": {
"type": "boolean",
"description": "If enabled, users do not need to be authenticated."
},
"avatarType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The avatar type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"avatar": {
"type": "string",
"description": "The source for the Copilot avatar"
},
"chatIconType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The Copilot icon type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"chatIcon": {
"type": "string",
"description": "The source for the Copilot icon"
},
"chatUserInputPlaceholder": {
"type": "string",
"description": "The default user input prompt"
},
"chatGreetingMessage": {
"type": "string",
"description": "The copilot greeting message"
},
"displayFormat": {
"type": "string",
"enum": [
"popup",
"sidebar",
"inline",
"inline_fill",
"POPUP",
"SIDEBAR",
"INLINE",
"INLINE_FILL"
],
"description": "The display format the Copilot (\"popup\" | \"sidebar\" | \"inline\" | \"inline_fill\" | \"POPUP\" | \"SIDEBAR\" | \"INLINE\" | \"INLINE_FILL\")."
}
},
"additionalProperties": false
}
}
}
},
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "The Copilot ID."
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Copilot ID."
},
"object": {
"type": "string",
"enum": [
"copilot"
],
"description": "The resource type."
},
"workspaceId": {
"type": "string",
"description": "The workspace ID."
},
"name": {
"type": "string",
"maxLength": 100,
"description": "The name of the Copilot. Maximum length of 100 characters."
},
"modelProviderId": {
"type": "string",
"description": "The Model Provider ID used by this copilot."
},
"model": {
"type": "string",
"description": "The Model used by this copilot."
},
"description": {
"type": "string",
"description": "The description of the Copilot."
},
"instructions": {
"type": "string",
"description": "The LLM instructions for the Copilot."
},
"displayFormat": {
"type": "string",
"enum": [
"popup",
"sidebar",
"inline",
"inline_fill",
"POPUP",
"SIDEBAR",
"INLINE",
"INLINE_FILL"
],
"description": "The display format the Copilot (\"popup\" | \"sidebar\" | \"inline\" | \"inline_fill\" | \"POPUP\" | \"SIDEBAR\" | \"INLINE\" | \"INLINE_FILL\")."
},
"anonymousAccessEnabled": {
"type": "boolean",
"description": "If enabled, users do not need to be authenticated."
},
"avatarType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The avatar type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"avatar": {
"type": "string",
"description": "The source for the Copilot avatar"
},
"chatIconType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The Copilot icon type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"chatIcon": {
"type": "string",
"description": "The source for the Copilot icon"
},
"chatUserInputPlaceholder": {
"type": "string",
"description": "The default user input prompt"
},
"chatGreetingMessage": {
"type": "string",
"description": "The copilot greeting message"
},
"updatedAt": {
"type": "string",
"format": "date-time",
"description": "Updated time."
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 user-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"createdAt": {
"type": "string",
"format": "date-time",
"description": "Created time."
}
},
"required": [
"id",
"object",
"workspaceId",
"displayFormat",
"updatedAt",
"metadata",
"createdAt"
],
"additionalProperties": false
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
},
"get": {
"operationId": "query.copilots.get",
"summary": "Get Copilot",
"description": "Returns a Copilot.",
"tags": [
"Copilots"
],
"security": [
{
"Authorization": []
}
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Copilot ID"
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The Copilot ID."
},
"object": {
"type": "string",
"enum": [
"copilot"
],
"description": "The resource type."
},
"workspaceId": {
"type": "string",
"description": "The workspace ID."
},
"name": {
"type": "string",
"maxLength": 100,
"description": "The name of the Copilot. Maximum length of 100 characters."
},
"modelProviderId": {
"type": "string",
"description": "The Model Provider ID used by this copilot."
},
"model": {
"type": "string",
"description": "The Model used by this copilot."
},
"description": {
"type": "string",
"description": "The description of the Copilot."
},
"instructions": {
"type": "string",
"description": "The LLM instructions for the Copilot."
},
"displayFormat": {
"type": "string",
"enum": [
"popup",
"sidebar",
"inline",
"inline_fill",
"POPUP",
"SIDEBAR",
"INLINE",
"INLINE_FILL"
],
"description": "The display format the Copilot (\"popup\" | \"sidebar\" | \"inline\" | \"inline_fill\" | \"POPUP\" | \"SIDEBAR\" | \"INLINE\" | \"INLINE_FILL\")."
},
"anonymousAccessEnabled": {
"type": "boolean",
"description": "If enabled, users do not need to be authenticated."
},
"avatarType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The avatar type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"avatar": {
"type": "string",
"description": "The source for the Copilot avatar"
},
"chatIconType": {
"type": "string",
"enum": [
"built-in",
"emoji",
"svg",
"url",
"BUILT_IN",
"EMOJI",
"SVG",
"URL"
],
"description": "The Copilot icon type (\"built-in\" | \"emoji\" | \"svg\" | \"url\" | \"BUILT_IN\" | \"EMOJI\" | \"SVG\" | \"URL\")"
},
"chatIcon": {
"type": "string",
"description": "The source for the Copilot icon"
},
"chatUserInputPlaceholder": {
"type": "string",
"description": "The default user input prompt"
},
"chatGreetingMessage": {
"type": "string",
"description": "The copilot greeting message"
},
"updatedAt": {
"type": "string",
"format": "date-time",
"description": "Updated time."
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 user-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"createdAt": {
"type": "string",
"format": "date-time",
"description": "Created time."
}
},
"required": [
"id",
"object",
"workspaceId",
"displayFormat",
"updatedAt",
"metadata",
"createdAt"
],
"additionalProperties": false
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
},
"delete": {
"operationId": "mutation.copilots.delete",
"summary": "Delete Copolot",
"description": "Delete a Copilot.",
"tags": [
"Copilots"
],
"security": [
{
"Authorization": []
}
],
"parameters": [
{
"name": "id",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "Copilot ID"
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
}
},
"/copilots/{copilotId}/threads": {
"get": {
"operationId": "query.copilots.listThreads",
"summary": "List Copilot Threads",
"description": "Returns a list of Threads for a Copilot.",
"tags": [
"Copilots"
],
"security": [
{
"Authorization": []
}
],
"parameters": [
{
"name": "copilotId",
"in": "path",
"required": true,
"schema": {
"type": "string"
},
"description": "The Copilot ID"
},
{
"name": "workspaceId",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "Filter by workspace ID. Defaults to the currently active workspace."
},
{
"name": "order",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"asc",
"desc"
],
"default": "desc"
},
"description": "The order of the list. Defaults to `desc` by created date."
},
{
"name": "pageSize",
"in": "query",
"required": false,
"schema": {
"type": "number",
"minimum": 1,
"maximum": 1000,
"default": 30
},
"description": "The page size of the list. Defaults to 30."
},
{
"name": "nextPageToken",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "The page token of the list."
},
{
"name": "previousPageToken",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "The page token of the list."
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"object": {
"type": "string",
"enum": [
"list"
],
"description": "The object type of the list."
},
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"workspaceId": {
"type": "string",
"description": "The workspace ID."
},
"copilotId": {
"type": "string",
"description": "The Copilot ID"
},
"threadId": {
"type": "string",
"description": "The Thread ID"
},
"copilotRuns": {
"type": "number",
"description": "The number of runs this Copilot has ran in this thread"
},
"createdAt": {
"type": "string",
"format": "date-time",
"description": "The first time a was run executed on this thread for this Copilot"
},
"updatedAt": {
"type": "string",
"format": "date-time",
"description": "The lastest time a run was executed on this thread for this Copilot"
}
},
"required": [
"workspaceId",
"copilotId",
"threadId",
"copilotRuns"
],
"additionalProperties": false
},
"description": "The list of resources."
},
"nextPageToken": {
"type": "string",
"description": "The next page token of the list."
},
"previousPageToken": {
"type": "string",
"description": "The previous page token of the list."
}
},
"required": [
"object",
"data"
],
"additionalProperties": false
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
}
},
"/knowledgebases/{knowledgeBaseId}/documents/upsert": {
"post": {
"operationId": "mutation.knowledgeBases.upsertDocuments",
"summary": "Upsert KnowledgeBase Documents",
"description": "Upserts KnowledgeBase documents to be stored as documents.",
"tags": [
"KnowledgeBase"
],
"security": [
{
"Authorization": []
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"docs": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"name": {
"type": "string"
},
"content": {
"type": "string"
},
"url": {
"type": "string"
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
}
}
},
"required": [
"name",
"content"
],
"additionalProperties": false
}
}
},
"required": [
"docs"
],
"additionalProperties": false
}
}
}
},
"parameters": [
{
"name": "knowledgeBaseId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The ingestion ID."
},
"workspaceId": {
"type": "string",
"description": "The workspace ID."
},
"knowledgeBaseId": {
"type": "string",
"description": "The knowledge base id"
},
"toolId": {
"type": "string",
"description": "The tool id"
},
"type": {
"type": "string",
"enum": [
"website",
"advancedWebsite",
"awsS3",
"azureBlobStorage",
"gcsBucket",
"document"
],
"description": "The type of the ingestion job."
},
"documentCount": {
"type": "number",
"description": "The number of ingested documents."
},
"finishedAt": {
"type": "string",
"format": "date-time",
"description": "Finished time."
},
"apifyRunIdExternal": {
"type": "string",
"description": "The apify run id"
},
"output": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "The ingestion output"
},
"error": {
"type": "string",
"default": "",
"description": "Contains the description of errors encountered by the ingestion job"
},
"state": {
"type": "string",
"enum": [
"pending",
"crawling",
"processing",
"success",
"error"
],
"description": "The state of the ingestion job"
},
"sourceDetails": {
"description": "The details about the knowledge base source"
},
"authInfo": {
"description": "The auth info to connect to the knowledge base source"
},
"documents": {
"type": "array",
"items": {
"type": "string"
},
"description": "The documents ingested by this job"
},
"updatedAt": {
"type": "string",
"format": "date-time",
"description": "Updated time."
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 user-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"createdAt": {
"type": "string",
"format": "date-time",
"description": "Created time."
}
},
"required": [
"id",
"workspaceId",
"state",
"updatedAt",
"metadata",
"createdAt"
],
"additionalProperties": false
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
}
},
"/documents": {
"post": {
"operationId": "mutation.documents.create",
"summary": "Create Document",
"description": "Create a Document.",
"tags": [
"Document"
],
"security": [
{
"Authorization": []
}
],
"requestBody": {
"required": false,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"maxLength": 100,
"description": "The title of the document. Maximum length of 100 characters."
},
"workspaceId": {
"type": "string",
"description": "The workspace ID."
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 user-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"content": {
"type": "string",
"description": "The content of the document."
},
"knowledgeBaseId": {
"type": "string",
"description": "The knowledge base id"
},
"externalId": {
"type": "string",
"description": "The external id used to uniquely identify a document in the source"
},
"systemMetadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 system-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"url": {
"type": "string",
"description": "The url to access the document"
},
"embeddingState": {
"type": "string",
"enum": [
"progress",
"success",
"error"
]
},
"contentType": {
"type": "string",
"description": "The content type of the document; e.g. application/pdf"
},
"embeddingDurationMs": {
"type": "number",
"description": "The embedding duration in milliseconds"
},
"chunkingDurationMs": {
"type": "number",
"description": "The chunking duration in milliseconds"
}
},
"additionalProperties": false
}
}
}
},
"parameters": [],
"responses": {
"200": {
"description": "Successful response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "The document key ID."
},
"object": {
"type": "string",
"enum": [
"document"
],
"description": "The resource type."
},
"workspaceId": {
"type": "string",
"description": "The workspace ID."
},
"knowledgeBaseId": {
"type": "string",
"description": "The knowledge base id"
},
"title": {
"type": "string",
"maxLength": 100,
"description": "The title of the document. Maximum length of 100 characters."
},
"content": {
"type": "string",
"description": "The content of the document."
},
"contentType": {
"type": "string",
"description": "The content type of the document; e.g. application/pdf"
},
"systemMetadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 system-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"url": {
"type": "string",
"description": "The url to access the document"
},
"externalId": {
"type": "string",
"description": "The external id used to uniquely identify a document in the source"
},
"modified": {
"type": "boolean",
"description": "Indicate whether a document has been modified"
},
"embeddingState": {
"type": "string",
"enum": [
"progress",
"success",
"error"
]
},
"embeddingDurationMs": {
"type": "number",
"description": "The embedding duration in milliseconds"
},
"chunkingDurationMs": {
"type": "number",
"description": "The chunking duration in milliseconds"
},
"contentHash": {
"type": "string",
"description": "The hash of content"
},
"updatedAt": {
"type": "string",
"format": "date-time",
"description": "Updated time."
},
"metadata": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"type": "string"
},
{
"type": "number"
}
]
},
"description": "Up to 20 user-defined metadata pairs can be attached to a resource. Keys can be a maximum of 100 characters."
},
"createdAt": {
"type": "string",
"format": "date-time",
"description": "Created time."
}
},
"required": [
"id",
"object",
"workspaceId",
"knowledgeBaseId",
"title",
"content",
"systemMetadata",
"modified",
"contentHash",
"updatedAt",
"metadata",
"createdAt"
],
"additionalProperties": false
}
}
}
},
"default": {
"$ref": "#/components/responses/error"
}
}
}
}
},
"components": {
"securitySchemes": {
"Authorization": {
"type": "http",
"scheme": "bearer"
}
},
"responses": {
"error": {
"description": "Error response",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string"
},
"code": {
"type": "string"
},
"issues": {
"type": "array",
"items": {
"type": "object",
"properties": {
"message": {
"type": "string"
}
},
"required": [
"message"
],
"additionalProperties": false
}
}
},
"required": [
"message",
"code"
],
"additionalProperties": false
}
}
}
}
}
},
"tags": [
{
"name": "API Keys"
},
{
"name": "Copilots"
}
],
"externalDocs": {
"url": "https://docs.continual.ai"
}
}
For simplicity, the example specification only has 3 API endpoints. We'll use /copilots/
for this
example.
Connect Knowledge Base and Tool to the Copilot
Return to our copilot overview page and select Integrations.
Connect the Next.js Documentation knowledge base and the Continual Console tool.
Go to Playground to try out queries.
Asking questions
Go to the copilot widget in the Next.js template app. Let's test whether our copilot can answer a
question from the Next.js documentation. Suppose the user hits this known error and asks:
How do I fix the error "No Script Component in Head"?
Compare the copilot's response to the source document: https://nextjs.org/docs/messages/no-script-component-in-head (opens in a new tab)
Let's use the copilot to make an API request to view our Continual Copilots. Instruct it to
List my copilots
.
Taking actions
Next, let's ask the copilot to take an action for us. Tell the copilot:
Update AI Copilot's greeting to "Howdy Partner"
. Be sure to use the copilot's name (e.g. AI
Copilot) when giving the instruction. Refresh the page to see the new greeting.
Troubleshooting copilot issues
Threads are a helpful feature in Continual that provide a full list of user-copilot conversations.
There is an Overview of the conversation, as the user experienced it, as well as a Traces view for debugging. Traces are for admins to track the execution flow, identify bottlenecks, and troubleshoot issues. The Trace view provides a detailed, hierarchical breakdown of a copilot's processing flow through Threads, Runs, and Steps. A Run within a Thread represents a single execution responding to a user prompt, encompassing the entire processing flow. Steps within a Run include Tool Calls and Message Creation, helping to verify information retrieval, identify performance issues, and evaluate message quality. With this information, admins can effectively analyze and optimize the Copilot's performance. Checkout the Traces documentation for more information.
Click on the Traces
tab and you'll see everything that occurred while testing the copilot.
The second column text describes each Run and Step. For example, you can see the user's two top level messages are "Hello!" and "describe yourself" in this thread. We can also see the first Step was to call the tool that searches all knowledge bases.