I’m working on a codebase that uses the Next.js Pages Router
. However, I can’t seem to find any documentation supporting the use of the useAssistant
hook from the Vercel ai/sdk with the Pages
Router
. I understand that it’s recommended to use the App Router API for this purpose, but for this project, I’ve been asked to stick with the Pages.
I’m receiving a 200 response from the POST request when connecting to the GPT assistant when I insert an input, however, no output is being returned. Could someone help to resolve this issue? Thanks!
I have the following piece of code in the directory pages/api/assistant/index.tsx
<code>import { NextApiRequest, NextApiResponse } from "next";
import { AssistantResponse } from "ai";
import OpenAI from "openai";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY || "",
// Allow streaming responses up to 30 seconds
export const maxDuration = 30;
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed" });
const threadId = input.threadId ?? (await openai.beta.threads.create({})).id;
const createdMessage = await openai.beta.threads.messages.create(threadId, {
{ threadId, messageId: createdMessage.id },
async ({ forwardStream, sendDataMessage }) => {
let runStream = openai.beta.threads.runs.stream(threadId, {
process.env.ASSISTANT_ID ??
throw new Error("ASSISTANT_ID is not set");
let runResult = await forwardStream(runStream);
runResult?.status === "requires_action" &&
runResult.required_action?.type === "submit_tool_outputs"
const tool_outputs = runResult.required_action.submit_tool_outputs.tool_calls.map(
const parameters = JSON.parse(toolCall.function.arguments);
switch (toolCall.function.name) {
// configure your tool calls here
throw new Error(`Unknown tool call function: ${toolCall.function.name}`);
runResult = await forwardStream(
openai.beta.threads.runs.submitToolOutputsStream(threadId, runResult.id, {
res.status(200).json({ threadId, messageId: createdMessage.id });
console.error("Error handling request:", error);
res.status(500).json({ error: "Internal Server Error" });
<code>import { NextApiRequest, NextApiResponse } from "next";
import { AssistantResponse } from "ai";
import OpenAI from "openai";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY || "",
});
// Allow streaming responses up to 30 seconds
export const maxDuration = 30;
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed" });
}
try {
const input: {
threadId: string | null;
message: string;
} = req.body;
const threadId = input.threadId ?? (await openai.beta.threads.create({})).id;
const createdMessage = await openai.beta.threads.messages.create(threadId, {
role: "user",
content: input.message,
});
await AssistantResponse(
{ threadId, messageId: createdMessage.id },
async ({ forwardStream, sendDataMessage }) => {
let runStream = openai.beta.threads.runs.stream(threadId, {
assistant_id:
process.env.ASSISTANT_ID ??
(() => {
throw new Error("ASSISTANT_ID is not set");
})(),
});
let runResult = await forwardStream(runStream);
while (
runResult?.status === "requires_action" &&
runResult.required_action?.type === "submit_tool_outputs"
) {
const tool_outputs = runResult.required_action.submit_tool_outputs.tool_calls.map(
(toolCall: any) => {
const parameters = JSON.parse(toolCall.function.arguments);
switch (toolCall.function.name) {
// configure your tool calls here
default:
throw new Error(`Unknown tool call function: ${toolCall.function.name}`);
}
},
);
runResult = await forwardStream(
openai.beta.threads.runs.submitToolOutputsStream(threadId, runResult.id, {
tool_outputs,
}),
);
}
},
);
res.status(200).json({ threadId, messageId: createdMessage.id });
} catch (error) {
console.error("Error handling request:", error);
res.status(500).json({ error: "Internal Server Error" });
}
}
</code>
import { NextApiRequest, NextApiResponse } from "next";
import { AssistantResponse } from "ai";
import OpenAI from "openai";
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY || "",
});
// Allow streaming responses up to 30 seconds
export const maxDuration = 30;
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "POST") {
return res.status(405).json({ error: "Method not allowed" });
}
try {
const input: {
threadId: string | null;
message: string;
} = req.body;
const threadId = input.threadId ?? (await openai.beta.threads.create({})).id;
const createdMessage = await openai.beta.threads.messages.create(threadId, {
role: "user",
content: input.message,
});
await AssistantResponse(
{ threadId, messageId: createdMessage.id },
async ({ forwardStream, sendDataMessage }) => {
let runStream = openai.beta.threads.runs.stream(threadId, {
assistant_id:
process.env.ASSISTANT_ID ??
(() => {
throw new Error("ASSISTANT_ID is not set");
})(),
});
let runResult = await forwardStream(runStream);
while (
runResult?.status === "requires_action" &&
runResult.required_action?.type === "submit_tool_outputs"
) {
const tool_outputs = runResult.required_action.submit_tool_outputs.tool_calls.map(
(toolCall: any) => {
const parameters = JSON.parse(toolCall.function.arguments);
switch (toolCall.function.name) {
// configure your tool calls here
default:
throw new Error(`Unknown tool call function: ${toolCall.function.name}`);
}
},
);
runResult = await forwardStream(
openai.beta.threads.runs.submitToolOutputsStream(threadId, runResult.id, {
tool_outputs,
}),
);
}
},
);
res.status(200).json({ threadId, messageId: createdMessage.id });
} catch (error) {
console.error("Error handling request:", error);
res.status(500).json({ error: "Internal Server Error" });
}
}
Then I have the output in a component like so components/Statistics.tsx
<code>const { status, messages, setInput, input, submitMessage, handleInputChange } = useAssistant({
const whatsWorking = messages
.filter((m) => m.role === "assistant")
const parsedContent = parseContent(m.content);
return parsedContent ? parsedContent.whatsWorking : "loading...";
const whatNeedsImproving = messages
.filter((m) => m.role === "assistant")
const parsedContent = parseContent(m.content);
return parsedContent ? parsedContent.whatsNeedsImproving : "loading...";
console.log("this is the working message", whatsWorking);
console.log("this is the working message", whatNeedsImproving);
<Grid container spacing={3}>
<Grid item md={6} xs={12}>
<form onSubmit={submitMessage}>
<input value={input} onChange={handleInputChange} />
<button type="submit">submit</button>
<Grid item md={6} xs={12}>
info={whatNeedsImproving}
<code>const { status, messages, setInput, input, submitMessage, handleInputChange } = useAssistant({
api: "/api/assistant",
});
const whatsWorking = messages
.filter((m) => m.role === "assistant")
.map((m) => {
const parsedContent = parseContent(m.content);
return parsedContent ? parsedContent.whatsWorking : "loading...";
});
const whatNeedsImproving = messages
.filter((m) => m.role === "assistant")
.map((m) => {
const parsedContent = parseContent(m.content);
return parsedContent ? parsedContent.whatsNeedsImproving : "loading...";
});
console.log("this is the working message", whatsWorking);
console.log("this is the working message", whatNeedsImproving);
eturn (
<Grid container spacing={3}>
<Grid item md={6} xs={12}>
<form onSubmit={submitMessage}>
<input value={input} onChange={handleInputChange} />
<button type="submit">submit</button>
</form>
<Box
info={whatsWorking}
/>
</Grid>
<Grid item md={6} xs={12}>
<Box
info={whatNeedsImproving}
/>
</Grid>
</code>
const { status, messages, setInput, input, submitMessage, handleInputChange } = useAssistant({
api: "/api/assistant",
});
const whatsWorking = messages
.filter((m) => m.role === "assistant")
.map((m) => {
const parsedContent = parseContent(m.content);
return parsedContent ? parsedContent.whatsWorking : "loading...";
});
const whatNeedsImproving = messages
.filter((m) => m.role === "assistant")
.map((m) => {
const parsedContent = parseContent(m.content);
return parsedContent ? parsedContent.whatsNeedsImproving : "loading...";
});
console.log("this is the working message", whatsWorking);
console.log("this is the working message", whatNeedsImproving);
eturn (
<Grid container spacing={3}>
<Grid item md={6} xs={12}>
<form onSubmit={submitMessage}>
<input value={input} onChange={handleInputChange} />
<button type="submit">submit</button>
</form>
<Box
info={whatsWorking}
/>
</Grid>
<Grid item md={6} xs={12}>
<Box
info={whatNeedsImproving}
/>
</Grid>