DEV Community

Cover image for 🚀How I integrated an AI copilot into Dub.co (in a few minutes)🤖✨
uliyahoo Subscriber for CopilotKit

Posted on with Nevo David and David Asaolu • Edited on

🚀How I integrated an AI copilot into Dub.co (in a few minutes)🤖✨

In this article, you'll learn how to add an AI copilot to Dub.co, an open-source link management system. Using CopilotKit, you'll also learn how to easily create and delete short links, improving the overall user experience of the application.

You can use this as a case-study for how to easily add an AI copilot into any open-source application, not just Dub.co. This will easily make you seem like an AI coding Ninja.

Image description


What is an AI Copilot?

An AI copilot, is an in-app AI assistant that helps users answer questions and take actions inside an application. It brings LLM intelligence right into your application.

Some common form factors:

  • ChatBot: Context-aware in-app chatbots that can take actions in-app 💬
  • AI autocomplete: AI-powered textFields with context-aware autocomplete & insertions 📝
  • Co-Agents: In-app AI agents that can dynamically interact with your app & users 🤖

CopilotKit is the leading, most robust, and easiest to use open-source framework for building in-app AI copilots. You can have a fully custom AI copilot running in your app within minutes.

Copilot

Checkout CopilotKit ⭐️


Prerequisites

To fully understand this tutorial, you need to have a basic understanding of React or Next.js.

We'll also make use of the following:

  • CopilotKit - an open-source copilot framework for building custom AI chatbots, in-app AI agents, and text areas.
  • Docker - an open-source platform that uses containerization technology to make it easier to create, deploy, and run applications
  • Docker Compose - a software application for defining and running multi-container Docker applications.
  • Python >= 3.8 - for configuring Dub.co.
  • OpenAI API Key - to enable us to perform various tasks using the GPT models.

How to set up Dub.co on your local computer

Dub.co is an open-source link management platform that allows users to create, share, and track short links using their own custom domains. It was created by Steven Tey (formerly of Vercel).

To get started with setting up Dub.co on your local computer, follow these steps:

Clone the Dub.co GitHub repository by running the code snippet below.

git clone https://github.com/dubinc/dub.git
Enter fullscreen mode Exit fullscreen mode

Navigate into the dub folder and install the project dependencies:

pnpm install
Enter fullscreen mode Exit fullscreen mode

Within the apps/web folder, rename the .env.example file to .env.

Create a new Tinybird account, and copy your Admin Auth Token into the .env file.

TINYBIRD_API_KEY=<your_admin_auth_token>
Enter fullscreen mode Exit fullscreen mode

Navigate into the packages/tinybird directory and install the Tinybird CLI using the following command:

pip3 install tinybird-cli
Enter fullscreen mode Exit fullscreen mode

Execute the following command in your terminal and enter your Admin Auth Token when prompted to authenticate using the Tinybird CLI:

tb auth
Enter fullscreen mode Exit fullscreen mode

Publish the Tinybird datasource and endpoints by running the code snippet below:

tb push
Enter fullscreen mode Exit fullscreen mode

Create an Upstash database and copy the following credentials from the REST API section to the .env file:

UPSTASH_REDIS_REST_URL=<your_rest_url>
UPSTASH_REDIS_REST_TOKEN=<your_rest_token>
Enter fullscreen mode Exit fullscreen mode

Navigate to the QStash tab and copy the following credentials into the .env file.

QSTASH_TOKEN=
QSTASH_CURRENT_SIGNING_KEY=
QSTASH_NEXT_SIGNING_KEY=
Enter fullscreen mode Exit fullscreen mode

Next, within the apps/web directory, run the following command to start the Docker Compose stack:

docker-compose up
Enter fullscreen mode Exit fullscreen mode

Generate the Prisma client and create its database tables using the following commands:

npx prisma generate
npx prisma db push
Enter fullscreen mode Exit fullscreen mode

Dub.co supports multiple authentication methods. Create a GitHub app and copy the URL below as its callback URL.

http://localhost:8888/api/auth/callback/github
Enter fullscreen mode Exit fullscreen mode

Finally, start the development server:

pnpm dev
Enter fullscreen mode Exit fullscreen mode

Access the web application by navigating to http://localhost:8888 in your browser, create a workspace, and get started. If you encounter any issues, refer to the complete installation guide for detailed assistance.

Dub.co Overview


How to integrate CopilotKit to Dub.co

In this section, you'll learn how to add an AI copilot to Dub.co using CopilotKit.

Visit the OpenAI Developers' Platform and create a new secret key.

OpenAI Key

Add your newly generated secret key and specify the OpenAI model in your .env file as follows:

OPENAI_API_KEY=<YOUR_OPENAI_SECRET_KEY>
OPENAI_MODEL=gpt-4-1106-preview
Enter fullscreen mode Exit fullscreen mode

Navigate into the app/api folder and create a copilotkit directory containing a route.ts file.

cd app/api
mkdir copilotkit && cd copilotkit
touch route.ts
Enter fullscreen mode Exit fullscreen mode

Copy the following the following code snippet into the api/copilotkit/route.ts file:

import { CopilotRuntime, OpenAIAdapter } from "@copilotkit/backend";

export const runtime = "edge";

export async function POST(req: Request): Promise<Response> {
  const copilotKit = new CopilotRuntime({});
  const openaiModel = process.env["OPENAI_MODEL"];
  return copilotKit.response(req, new OpenAIAdapter({ model: openaiModel }));
}
Enter fullscreen mode Exit fullscreen mode

The CopilotKitRuntime instance accept users’ requests and make decisions using the OpenAI model.

To connect Dub.co to the backend API route, update the page.tsx within the app.dub.co/(dashboard)/[slug] as show below:

"use client";
import WorkspaceLinksClient from "./page-client";
import { CopilotKit } from "@copilotkit/react-core";
import { CopilotPopup } from "@copilotkit/react-ui";
import "@copilotkit/react-ui/styles.css";

export default function WorkspaceLinks() {
  return (
    <CopilotKit runtimeUrl="/api/copilotkit/">
      <WorkspaceLinksClient />;
      <CopilotPopup
        instructions="Help the user create and delete links from the workspace"
        defaultOpen={true}
        labels={{
          title: "Dub.co Copilot",
          initial:
            "Hello there! I can help you create, edit, and delete short links in your workspace.",
        }}
        clickOutsideToClose={false}
      ></CopilotPopup>
    </CopilotKit>
  );
}
Enter fullscreen mode Exit fullscreen mode

The CopilotKit component wraps the entire application and accepts a runtimeUrl prop containing a link to the API endpoint. The CopilotKitPopup component adds a chatbot sidebar panel to the application, enabling us to provide various instructions to CopilotKit.

Dub.co with CopilotKit


How to perform various actions using CopilotKit

CopilotKit provides two hooks that enable us to handle user's request and plug into the application state: useCopilotAction and useCopilotReadable.

The useCopilotAction hook allows you to define actions to be carried out by CopilotKit. It accepts an object containing the following parameters:

  • name - the action's name.
  • description - the action's description.
  • parameters - an array containing the list of the required parameters.
  • render - the default custom function or string.
  • handler - the executable function that is triggered by the action.
useCopilotAction({
  name: "sayHello",
  description: "Say hello to someone.",
  parameters: [
    {
      name: "name",
      type: "string",
      description: "name of the person to say greet",
    },
  ],
  render: "Process greeting message...",
  handler: async ({ name }) => {
    alert(`Hello, ${name}!`);
  },
});
Enter fullscreen mode Exit fullscreen mode

The useCopilotReadable hook passes the application state into CopilotKit.

import { useCopilotReadable } from "@copilotkit/react-core";

const myAppState = "...";
useCopilotReadable({
  description: "The current state of the app",
  value: myAppState,
});
Enter fullscreen mode Exit fullscreen mode

Now, let's plug the application states into CopilotKit to perform various actions, such as creating and deleting the short links.

Navigate into the ui/links/links-container.tsx folder and update the LinksContainer function as shown below:

export default function LinksContainer({
  AddEditLinkButton,
}: {
  AddEditLinkButton: () => JSX.Element;
}) {
  const { viewMode, sort, showArchived } = useContext(LinksDisplayContext);
  const { links, isValidating } = useLinks({ sort, showArchived });
  const { data: count } = useLinksCount({ showArchived });
  //👇🏻 React state for all links
  const [updatedLinks, setUpdatedLinks] = useState<ResponseLink[]>(links || []);

  //👇🏻 update the state with all the links
  useEffect(() => {
    setUpdatedLinks(links || []);
  }, [links]);

  useCopilotReadable({
    description:
      "This is the list of links you have saved. You can click on a link to view it, or use the search bar to find a specific link.",
    value: updatedLinks,
  });

  return (
    <MaxWidthWrapper className="grid gap-y-2">
      <LinksList
        AddEditLinkButton={AddEditLinkButton}
        links={links}
        count={count}
        loading={isValidating}
        compact={viewMode === "rows"}
      />
      <DeleteLinkModal />
    </MaxWidthWrapper>
  );
}
Enter fullscreen mode Exit fullscreen mode

The updatedLinks React state stores the links created within the application and the useCopilotReadable passes the links into CopilotKit.

Below the useCopilotReadable hook, add the following code snippet to allow users to delete links from the application:

useCopilotAction({
  name: "deleteShortLink",
  description: "delete a link from the database via its ID",
  parameters: [
    {
      name: "id",
      type: "string",
      description: "The ID of a short link",
      required: true,
    },
  ],
  render: "Deleting link...",
  handler: async ({ id }) => {
    if (!id) return;
    const link = updatedLinks?.find((link) => link.id === id);
    if (!link) return;
    setSelectedLink(link);
    setShowDeleteLinkModal(true);
  },
});
Enter fullscreen mode Exit fullscreen mode

Deleting links with CopilotKit

To allow users to create links using the AI copilot, navigate to the index.tsx file within the modals/add-edit-link-modal directory and update the useAddEditLinkModal function as shown below:

export function useAddEditLinkModal({
  props,
  duplicateProps,
  homepageDemo,
}: {
  props?: LinkWithTagsProps;
  duplicateProps?: LinkWithTagsProps;
  homepageDemo?: boolean;
} = {}) {
  const [updatedProps, setUpdatedProps] = useState(props || DEFAULT_LINK_PROPS);
  const [showAddEditLinkModal, setShowAddEditLinkModal] = useState(false);
  const [generatingRandomKey, setGeneratingRandomKey] = useState(false);
  const [keyError, setKeyError] = useState<string | null>(null);
  const { id: workspaceId } = useWorkspace();
  const { primaryDomain } = useDomains();

  const getKey = async (domain: string) => {
    setKeyError(null);
    setGeneratingRandomKey(true);
    const res = await fetch(
      `/api/links/random?domain=${domain}&workspaceId=${workspaceId}`,
    );
    const key = await res.json();
    return key;
  };

  useCopilotAction({
    name: "createNewLink",
    description: "Create a new link",
    parameters: [
      {
        name: "url",
        type: "string",
        description: "The destination URL for the short link",
        required: true,
      },
    ],
    render: "Loading...",
    handler: async ({ url }) => {
      const key = await getKey(primaryDomain);
      setUpdatedProps((prev) => ({
        ...prev,
        url,
        domain: primaryDomain,
        key,
        id: "",
      }));
      setGeneratingRandomKey(false);
      setShowAddEditLinkModal(true);
    },
  });

  const AddEditLinkModalCallback = useCallback(() => {
    return (
      <AddEditLinkModal
        showAddEditLinkModal={showAddEditLinkModal}
        setShowAddEditLinkModal={setShowAddEditLinkModal}
        props={updatedProps}
        keyError={keyError}
        setKeyError={setKeyError}
        generatingRandomKey={generatingRandomKey}
        setGeneratingRandomKey={setGeneratingRandomKey}
        duplicateProps={duplicateProps}
        homepageDemo={homepageDemo}
      />
    );
  }, [showAddEditLinkModal, setShowAddEditLinkModal]);

  //👉🏻 other functions
}
Enter fullscreen mode Exit fullscreen mode
  • From the code snippet provided:
    • The updatedProps state contains the data structure for each link.
    • The getKey() function generates a unique key that is also included in the short links created.
    • The useCopilotAction function accepts the URL to be shortened and displays a modal that allows the user to confirm and save the link.

Create links using CopilotKit

Congratulations! You have successfully integrated CopilotKit into Dub.co. You can access the source code in this GitHub repository.

Here is a short video showing how CopilotKit works with Dub.co:


Conclusion

CopilotKit is an incredible tool that allows you to add AI Copilots to your products within minutes. Whether you're interested in AI chatbots and assistants or automating complex tasks, CopilotKit makes it easy.

If you need to build an AI product or integrate an AI tool into your software applications, you should consider CopilotKit.

You can find the source code for this tutorial on GitHub:

https://github.com/dha-stix/dub-with-copilotkit

Thank you for reading!

👀 @steventey

Top comments (9)

Collapse
 
anmolbaranwal profile image
Anmol Baranwal

Whoa! It looks very creative tbh. I loved that confirmation before deleting which is similar to GitHub, so nothing is performed directly by copilot. I've used Dub.co for short links before but I never imagined we could create such a cool app :)

Collapse
 
uliyahoo profile image
uliyahoo

Big shout to @arshadayvid & @nevodavid for helping me put this together and for @steventey for creating a great open source project with Dub.co 😬

Collapse
 
arshadayvid profile image
David Asaolu

Totally agree. Dub.co is a great project! 🔥
Enjoyed worked on the integration🫶

Collapse
 
arshadayvid profile image
David Asaolu

Awesome piece 🫶🙂‍↔️🔥

Collapse
 
dawoodkarim profile image
dawoodkarim

This looks sick

Collapse
 
the_greatbonnie profile image
Bonnie

This is a Cool project to build with CopilotKit.

Let me give it a try.

Collapse
 
nevodavid profile image
Nevo David

We should shortlink that article link also :D

Collapse
 
harry-123 profile image
Harry

Lmao, is that an 8-bit t3.gg on the cover?

Collapse
 
nathan_tarbert profile image
Nathan Tarbert • Edited

This looks like an enjoyable project that showcases CopilotKits powerful capabilities, and what better platform to showcase on than Dub.co!