Menu

Techniques

Actions

A key capability of Copilot.js is to intelligently trigger actions in your app, based on the user's prompt.

Exposing actions

Consider the example of a drawing app, which has functions for manipulating shapes such as createShape, updateShape, and so on:

Copilot invokes actions in your app

Together, these 6 functions form an API that Copilot will invoke, to accomplish the user's prompt. This API is typically implemented inside a "store", using Redux or Zustand.

To expose this API to Copilot, simply set the context.actions property:

// App.jsx
import store from './store' // Your application's store.
import { CopilotProvider, CopilotChat } from '@copilotjs/react'
import '@copilotjs/styles/default.css'

export default function App() {
  return (
    <CopilotProvider
      context={{
        // A map between each action's name and its function.
        actions: {
          createShape: store.createShape,
          updateShape: store.updateShape,
          deleteShape: store.deleteShape,
          getShape: store.getShape,
          listShapes: store.listShapes,
          deleteAllShapes: store.deleteAllShapes,
        },
        actionTypes: '...',
      }}
      // ...
    >
      <CopilotChat />
    </CopilotProvider>
  )
}

Action types

Exposing actions to the Copilot is not sufficient. We must also provide type definitions for all actions, so the Copilot knows exactly how to invoke them.

For our drawing app example, let's create a separate actionTypes.ts file:

// actionTypes.ts
// -------------------- Actions --------------------
type createShape = (shape: Shape) => ShapeWithId
type updateShape = (shapeId: string, updatedShape: Partial<Shape>) => void
type deleteShape = (shapeId: string) => void
type getShape = (shapeId: string) => ShapeWithId
type listShapes = (filters: Partial<ShapeWithId>) => ShapeWithId[]
type deleteAllShapes = () => void

// -------------------- Shapes --------------------
type Shape = Square | Circle
type Circle = { type: 'circle'; x: number; y: number; radius: number }
type Square = { type: 'square'; x: number; y: number; length: number }

// Extend shapes with IDs
type ShapeWithId = SquareWithId | CircleWithId
type CircleWithId = Circle & { id: string }
type SquareWithId = Square & { id: string }

Importing the action types

Once we define the actionTypes.ts file, we must pass its contents as a string to the Copilot's context.actionTypes property. There are different ways to achieve this, depending on your bundler.

With Vite

With Vite, you can keep a separate actionTypes.ts file (with the benefit of syntax highlighting), and use the ?raw suffix to conveniently import the file contents as a string:

// App.jsx
import actionTypes from './actionTypes.ts?raw' // Import the whole file as raw string.
...
<CopilotProvider
  context={{ actionTypes: actionTypes, actions: {} }}
  // ...
>
  <CopilotChat />
</CopilotProvider>
// actionTypes.ts
type createShape = ...

With any bundler

A universal method that works with any bundler is to store the type definitions in a plain string, then import it as a regular variable. However, you lose the syntax highlighting for the Typescript definitions.

// App.jsx
import { actionTypes } from './actionTypes' // Import the string variable.
...
<CopilotProvider
  context={{ actionTypes: actionTypes, actions: {} }}
  // ...
>
  <CopilotChat />
</CopilotProvider>
// actionTypes.ts
export const actionTypes = `
type createShape = ...
`
Previous
How it works
Next
State