Files
Hayden Bleasel 30cbcfec97 Migrate to Oxlint (#357)
* Migrate to oxlint / oxfmt

* Initial fixes

* Misc fixes

* Temporary fixes

* Update Ultracite

* Update .oxlintrc.json

* Update .oxlintrc.json

* Start running manual fixes

* Update .oxlintrc.json

* AI Fixes Part 2

* AI Fixes Part 3

* AI Fixes Part 4

* AI Fixes Part 5

* AI Fixes Part 6

* AI Fixes Part 7

* AI Fixes Part 8

* AI Fixes Part 9

* AI Fixes Part 10

* AI Fixes Part 11

* AI Fixes Part 12

* Fix tests

* Lint / test fixes

* Update chat.tsx

* Fix AI SDK React version

* Misc fixes

* Build fixes
2026-02-04 08:00:41 -08:00

119 lines
2.8 KiB
TypeScript

import {
convertToModelMessages,
createUIMessageStream,
createUIMessageStreamResponse,
stepCountIs,
streamText,
} from "ai";
import type { MyUIMessage } from "./types";
import { createTools } from "./tools";
import { createSystemPrompt } from "./utils";
export const maxDuration = 800;
interface RequestBody {
messages: MyUIMessage[];
currentRoute: string;
pageContext?: {
title: string;
url: string;
content: string;
};
}
export async function POST(req: Request) {
try {
const { messages, currentRoute, pageContext }: RequestBody =
await req.json();
// Filter out UI-only page context messages (they're just visual feedback)
const actualMessages = messages.filter(
(msg) => !msg.metadata?.isPageContext
);
// If pageContext is provided, prepend it to the last user message
let processedMessages = actualMessages;
if (pageContext && actualMessages.length > 0) {
const lastMessage = actualMessages.at(-1);
if (!lastMessage) {
return new Response(
JSON.stringify({
error: "No last message found",
}),
{ status: 500 }
);
}
if (lastMessage.role === "user") {
// Extract text content from the message parts
const userQuestion = lastMessage.parts
.filter((part) => part.type === "text")
.map((part) => part.text)
.join("\n");
processedMessages = [
...actualMessages.slice(0, -1),
{
...lastMessage,
parts: [
{
text: `Here's the content from the current page:
**Page:** ${pageContext.title}
**URL:** ${pageContext.url}
---
${pageContext.content}
---
User question: ${userQuestion}`,
type: "text",
},
],
},
];
}
}
const stream = createUIMessageStream({
execute: async ({ writer }) => {
const result = streamText({
messages: await convertToModelMessages(processedMessages),
model: "openai/gpt-4.1-mini",
prepareStep: ({ stepNumber }) => {
if (stepNumber === 0) {
return { toolChoice: { toolName: "search_docs", type: "tool" } };
}
},
stopWhen: stepCountIs(10),
system: createSystemPrompt(currentRoute),
tools: createTools(writer),
});
writer.merge(result.toUIMessageStream());
},
originalMessages: messages,
});
return createUIMessageStreamResponse({ stream });
} catch (error) {
console.error("AI chat API error:", error);
return new Response(
JSON.stringify({
error: "Failed to process chat request. Please try again.",
}),
{
headers: { "Content-Type": "application/json" },
status: 500,
}
);
}
}