Tutorial: Get started with the new OpenAI Assistants API

Ralf Elfving
4 min readNov 7, 2023

OpenAI released the new Assistants API today, which opens up a lot of new opportunities. I put together this scrappy NodeJS tutorial on the day of the release to hopefully help people get started more quickly. Watch the video and use the resources below to build your first Assistant.

UPDATE

I’ve released two updated, better and more comprehensive tutorials I suggest you use instead.

  • Re-use assistants between runs: Similar to this tutorial, but with better logic that re-use assistants between runs, more robust error handling. Check it out here.
  • Web-based chat interface: Instead of running Node locally, you create a web-based chat interface, with Assistant and thread state creation and state management. You can fork and have it up and running in three minutes by following this tutorial.

Find this article useful? I’ve published many other OpenAI and coding tutorials on my Medium account and on my YouTube channel.

Resources

Before you start, you need these things set up on your

  • NodeJS*
  • OpenAI npm 4.16.1 or later (yarn add openai)
  • Readline npm (yarn add readline)
  • dotenv npm (yarn dotenv)
  • An OpenAPI key

* Myself and other experienced a dependency issue with OpenAI’s node module and the latest Node version (21) today. I resolved this by downgrading NodeJS to 20.9.0. I did not check if the issue was resolved before recording the tutorial, but if you need to downgrade you can do this by running:

n 20.9.0

Lastly, I would strongly suggest you review OpenAI’s Assistants API documentation, because several new concepts are introduced.

Start coding

Create a file and name it “.env’, and add the following line to it. Don’t forget to replace the text with your OpenAI API key which you can get from your OpenAI developer account.

OPENAI_API_KEY="REPLACE WITH YOUR OPENAI API KEY HERE"

Next, create another file and name it e.g. mathTeacher.js. The name doesn’t really matter, it’s just what you’ll run from your terminal later. Paste the following code into it.


// import the required dependencies
require("dotenv").config();
const OpenAI = require("openai");
const readline = require("readline").createInterface({
input: process.stdin,
output: process.stdout,
});

// Create a OpenAI connection
const secretKey = process.env.OPENAI_API_KEY;
const openai = new OpenAI({
apiKey: secretKey,
});

async function askQuestion(question) {
return new Promise((resolve, reject) => {
readline.question(question, (answer) => {
resolve(answer);
});
});
}

async function main() {
try {
const assistant = await openai.beta.assistants.create({
name: "Math Tutor",
instructions:
"You are a personal math tutor. Write and run code to answer math questions.",
tools: [{ type: "code_interpreter" }],
model: "gpt-4-1106-preview",
});

// Log the first greeting
console.log(
"\nHello there, I'm your personal math tutor. Ask some complicated questions.\n"
);

// Create a thread
const thread = await openai.beta.threads.create();

// Use keepAsking as state for keep asking questions
let keepAsking = true;
while (keepAsking) {
const userQuestion = await askQuestion("\nWhat is your question? ");

// Pass in the user question into the existing thread
await openai.beta.threads.messages.create(thread.id, {
role: "user",
content: userQuestion,
});

// Use runs to wait for the assistant response and then retrieve it
const run = await openai.beta.threads.runs.create(thread.id, {
assistant_id: assistant.id,
});

let runStatus = await openai.beta.threads.runs.retrieve(
thread.id,
run.id
);

// Polling mechanism to see if runStatus is completed
// This should be made more robust.
while (runStatus.status !== "completed") {
await new Promise((resolve) => setTimeout(resolve, 2000));
runStatus = await openai.beta.threads.runs.retrieve(thread.id, run.id);
}

// Get the last assistant message from the messages array
const messages = await openai.beta.threads.messages.list(thread.id);

// Find the last message for the current run
const lastMessageForRun = messages.data
.filter(
(message) => message.run_id === run.id && message.role === "assistant"
)
.pop();

// If an assistant message is found, console.log() it
if (lastMessageForRun) {
console.log(`${lastMessageForRun.content[0].text.value} \n`);
}

// Then ask if the user wants to ask another question and update keepAsking state
const continueAsking = await askQuestion(
"Do you want to ask another question? (yes/no) "
);
keepAsking = continueAsking.toLowerCase() === "yes";

// If the keepAsking state is falsy show an ending message
if (!keepAsking) {
console.log("Alrighty then, I hope you learned something!\n");
}
}

// close the readline
readline.close();
} catch (error) {
console.error(error);
}
}

// Call the main function
main();

This code was scrappily put together in little time and briefly explained in the video above, and there’s plenty of room for improvement. There’s definitely flaws in the polling mechanism, but hopefully it’s a start that you can build on.

I suggest you read the OpenAI Assistants documentation to understand what the code does. As an example you only need to create an assistant once, and then you can create that assistant by creating new threads as needed. I’ll explain this in more detail in a future video.

Run your code

To run your code, open up your terminal and navigate to the folder where you saved your files. Run the mathTeacher.js file from it

node mathTeacher.js

Want more?

I hope this tutorial was useful. If it was, please consider liking it on YouTube, subscribing to my channel, or following me on Twitter or LinkedIn.

I’ll hopefully be putting out a few more OpenAI tutorials in the coming weeks, so make sure to subscribe or check back in.

--

--