Overview

As discussed in the introduction, developing AI applications is a pragmatic approach requiring to start simple and iterate towards complexity.

Following this approach, this first version of our Code Assistant will be able to explain a given code file:

const filePath = join(process.cwd(), `files/example.ts`);
const code = readFileSync(filePath, "utf-8");

const { lastMessage } = await codeAssistant.run(`What the following code does?

${code}
`);

console.log(lastMessage({ type: "text" }).content);
// This file (example.ts) is a TypeScript module that provides a collection of type-safe sorting helper functions. It contains five main sorting utility functions:

// 1. `sortNumbers(numbers: number[], descending = false)`
//    - Sorts an array of numbers in ascending (default) or descending order
//    - Takes an array of numbers and an optional boolean to determine sort direction

// 2. `sortStrings(strings: string[], options)`
//    - Sorts strings alphabetically with customizable options
//    - Options include:
//      - caseSensitive (default: false)
//      - descending (default: false)

// ...

To implement this capability, we will build a AI workflow leveraging a first important concept of AgentKit:

  • Agents: Agents act as a wrapper around the LLM (ex: Anthropic), providing a structured way to interact with it.

Let’s start our Code Assistant by installing the required dependencies:

Setup

Follow the below steps to setup your project:

npm init

You are now set up, let’s implement the first version of our Code Assistant.

Implementing our Code Assistant v1

Our first version of our Code Assistant takes the shape of a RAG workflow. A RAG workflow is a specific type of AI workflow that genrally consist of two steps: retrieval (fetching relevant information) and generation (creating a response with a LLM).

Our Code Assistant will have following two steps:

  • A retrieval step reads the content of a local file specified by the user.
  • A generation step uses Anthropic to analyze the code and provide a detailed explanation of what it does.

Let’s start by implementing the retrieval step.

The retrieval step: loading the code file

We earlier downloaded the example.ts file locally, let’s load it in our code by creating a index.ts file:

import { readFileSync } from "fs";
import { join } from "path";

async function main() {
  // First step: Retrieval
  const filePath = join(process.cwd(), `files/example.ts`);
  const code = readFileSync(filePath, "utf-8");
}

main();

Our example code is now ready to be analyzed. Let’s now implement the generation step.

The generation step using AgentKit’s Agent

As covered in the introduction, AgentKit’s createAgent() is a wrapper around the LLM, providing a structured way to interact with it with 3 main properties:

  • name: A unique identifier for the agent.
  • system: A description of the agent’s purpose.
  • model: The LLM to use.

Let’s add configure our Agent with Anthropic’s claude-3-5-sonnet-latest model by updating our index.ts file:

import { readFileSync } from "fs";
import { join } from "path";
import { anthropic, createAgent } from "@inngest/agent-kit";

const codeAssistant = createAgent({
  name: "code_assistant",
  system:
    "An AI assistant that helps answer questions about code by reading and analyzing files",
  model: anthropic({
    model: "claude-3-5-sonnet-latest",
    max_tokens: 4096,
  }),
});


async function main() {
  // First step: Retrieval
  const filePath = join(process.cwd(), `files/example.ts`);
  const code = readFileSync(filePath, "utf-8");
}

main();

Let’s now update our main() function to use our codeAssistant Agent in the generation step:

/* eslint-disable */
import { readFileSync } from "fs";
import { join } from "path";
import { anthropic, createAgent } from "@inngest/agent-kit";

// Create the code assistant agent
const codeAssistant = createAgent({
  name: "code_assistant",
  system:
    "An AI assistant that helps answer questions about code by reading and analyzing files",
  model: anthropic({
    model: "claude-3-5-sonnet-latest",
    max_tokens: 4096,
  }),
});

async function main() {
  // First step: Retrieval
  const filePath = join(process.cwd(), `files/example.ts`);
  const code = readFileSync(filePath, "utf-8");
  // Second step: Generation
  const { output } = await codeAssistant.run(`What the following code does?

  ${code}
  `);
  const lastMessage = output[output.length - 1];
  const content =
    lastMessage?.type === "text" ? (lastMessage?.content as string) : "";
  console.log(content);
}

main();

Let’s review the above code:

  1. We load the example.ts file in memory.
  2. We invoke our Code Assistant using the codeAssistant.run() method.
  3. We retrieve the last message from the output array.
  4. We log the content of the last message to the console.

Let’s now look at our assistant explanation.

Running our Code Assistant v1

First, go to your Anthropic dashboard and create a new API key.

Then, run the following command to execute our Code Assistant:

ANTHROPIC_API_KEY=<your-api-key> npm run start

The following output should be displayed in your terminal:

This code is a collection of type-safe sorting utility functions written in TypeScript. Here's a breakdown of each function:

1. `sortNumbers(numbers: number[], descending = false)`
- Sorts an array of numbers in ascending (default) or descending order
- Returns a new sorted array without modifying the original

2. `sortStrings(strings: string[], options)`
- Sorts an array of strings alphabetically
- Accepts options for case sensitivity and sort direction
- Default behavior is case-insensitive ascending order
- Returns a new sorted array

3. `sortByKey<T>(items: T[], key: keyof T, descending = false)`
- Sorts an array of objects by a specific key
- Handles both number and string values
- Generic type T ensures type safety
- Returns a new sorted array

4. `sortByMultipleKeys<T>(items: T[], sortKeys: Array<...>)`
- Sorts an array of objects by multiple keys in order
- Each key can have its own sort configuration (descending, case sensitivity)
- Continues to next key if values are equal
- Returns a new sorted array

...

Congratulations! You’ve just built your first AI workflow using AgentKit.

What we’ve learned so far

Let’s recap what we’ve learned so far:

  • A RAG workflow is a specific type of AI workflow that generally consist of two steps: retrieval (fetching relevant information) and generation (creating a response with a LLM).
    • Note that most RAG workflows in production consist of more than two steps and combine multiple sources of information and generation steps. You can see an example in this blog post.
  • AgentKit’s createAgent() is a wrapper around the LLM, providing a structured way to interact with a LLM model.
    • The use of a single Agent is often sufficient to power chatbots or extract structured data from a given text.

Next steps

Our Code Assistant v1 is a static AI workflow that only works with the example.ts file.

In the next version of our Code Assistant, we will make it dynamic by allowing the user to specify the file to analyze and also enable our Agent to perform more complete analysis.

Code Assistant v2: Complex code analysis

Our next Code Assistant version will rely on Agentic workflows to perform more complex code analysis.