Improve chat navigation, model selection, and streaming

This commit is contained in:
Rami Bitar
2026-09-16 13:14:55 -04:00
parent 8790cfb1e2
commit dd04493e25
73 changed files with 1272 additions and 1367 deletions
+23 -30
View File
@@ -4,16 +4,20 @@ import {
stepCountIs,
pruneMessages,
} from 'ai';
import { createOpenRouter } from '@openrouter/ai-sdk-provider';
import { tools } from '@/chat.config';
import { getChatModel } from '@/services/chat/model';
import { getChatInstructions } from '@/services/chat/instructions';
import { chatTools } from '@/services/chat/tools';
import { isOpenRouterModelId } from '@/lib/openrouter';
const openrouter = createOpenRouter({
apiKey: process.env.OPENROUTER_API_KEY,
});
export const maxDuration = 300;
export async function POST(request: Request) {
try {
const { messages } = await request.json();
const { messages, modelId } = await request.json();
if (modelId !== undefined && !isOpenRouterModelId(modelId)) {
return Response.json({ error: 'Select a supported model' }, { status: 400 });
}
if (!process.env.OPENROUTER_API_KEY) {
return Response.json(
@@ -22,30 +26,11 @@ export async function POST(request: Request) {
);
}
const model = openrouter(
process.env.OPENROUTER_MODEL || 'openai/gpt-5.6-luna-pro'
);
const model = getChatModel(modelId);
const webSearchEnabled = Boolean(process.env.FIRECRAWL_API_KEY);
const instructions = webSearchEnabled
? `You are an expert ChatGPT Agent with real-time access to the internet.
Your capabilities:
- Search the web using Firecrawl to find up-to-date information
- Fetch and read full web pages to extract detailed content
- Synthesize information from multiple sources into clear, accurate answers
- Cite your sources inline so the user can verify information
Guidelines:
- Always search the web before answering questions that require current or factual information
- Use multiple searches when needed to get comprehensive answers
- Cross-reference sources for accuracy
- Structure your responses clearly with headings, bullet points, and citations where appropriate
- When fetching pages, extract only the relevant information
- Be transparent about the sources you used
- Today's date is ${new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}`
: `You are a helpful AI research assistant. Answer clearly and accurately. You do not have live web access, so be transparent when a question requires current information. Today's date is ${new Date().toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}.`;
const instructions = getChatInstructions(webSearchEnabled);
const convertedMessages = await convertToModelMessages(messages);
@@ -55,12 +40,16 @@ Guidelines:
toolCalls: 'none',
});
const result = await streamText({
const result = streamText({
model,
instructions,
messages: prunedMessages,
tools: webSearchEnabled ? tools : {},
abortSignal: request.signal,
tools: webSearchEnabled ? chatTools : {},
stopWhen: stepCountIs(20),
onError: ({ error }) => {
if (!request.signal.aborted) console.error('Chat stream error:', error);
},
providerOptions: {
openrouter: {
reasoning: {
@@ -71,7 +60,11 @@ Guidelines:
},
});
return result.toUIMessageStreamResponse({ sendReasoning: true });
return result.toUIMessageStreamResponse({
sendReasoning: true,
headers: { 'Cache-Control': 'no-cache, no-transform' },
onError: () => 'The response was interrupted. Please try again.',
});
} catch (error) {
console.error('Chat API error:', error);
return new Response(
+2
View File
@@ -0,0 +1,2 @@
<!-- Generated from RiOpenaiLine in @remixicon/react. -->
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64"><rect width="64" height="64" rx="16" fill="#000000"></rect><svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" width="44" height="44" fill="#ffffff" x="10" y="10" class="remixicon "><path d="M11 4C11.6487 4 12.2498 4.20569 12.7411 4.55646C11.4486 5.22914 10.2602 6.07623 8.99996 6.80385L9.99996 8.5359C11.575 7.62654 13.0517 6.48541 14.7608 5.83037C16.1134 5.31198 17.681 5.83976 18.4282 7.13398C18.7526 7.69582 18.8749 8.31917 18.8168 8.92006C17.588 8.13708 16.2602 7.53146 15 6.80385L14 8.5359C15.575 9.44525 17.3016 10.1536 18.7234 11.3061C19.8487 12.2183 20.1754 13.8398 19.4282 15.134C19.1037 15.696 18.6249 16.1137 18.0752 16.3638C18.1385 14.9081 18 13.4553 18 12H16C16 13.8184 16.2498 15.6685 15.9626 17.4758C15.7353 18.9063 14.4944 20 13 20C12.351 20 11.7498 19.7942 11.2584 19.4432C12.5508 18.7701 13.7396 17.9238 15 17.1962L14 15.4641C12.4252 16.3733 10.9478 17.5147 9.23912 18.1696C7.88657 18.688 6.31898 18.1602 5.57176 16.866C5.24729 16.304 5.12493 15.6805 5.18316 15.0794C6.41224 15.8621 7.73964 16.4685 8.99997 17.1962L9.99997 15.4641C8.42517 14.5549 6.69801 13.8462 5.27649 12.6939C4.15128 11.7817 3.82455 10.1602 4.57176 8.86602C4.89624 8.30402 5.37506 7.88628 5.9247 7.63618C5.86145 9.09192 5.99997 10.5447 5.99997 12H7.99997C7.99997 10.1816 7.75013 8.33148 8.03733 6.52422C8.26467 5.09369 9.50554 4 11 4ZM14.7925 3.74171C13.8765 2.67659 12.5176 2 11 2C8.7782 2 6.89621 3.44833 6.24435 5.45243C4.86393 5.71314 3.59851 6.55175 2.83971 7.86602C1.72883 9.79013 2.04213 12.1442 3.4518 13.7107C2.98737 15.0366 3.08092 16.5518 3.83971 17.866C4.95059 19.7901 7.14589 20.6958 9.20742 20.2583C10.1234 21.3234 11.4824 22 13 22C15.2217 22 17.1037 20.5517 17.7556 18.5476C19.136 18.2869 20.4014 17.4482 21.1602 16.134C22.2711 14.2099 21.9578 11.8559 20.5481 10.2893C21.0126 8.96345 20.919 7.44825 20.1602 6.13398C19.0493 4.20987 16.854 3.30419 14.7925 3.74171Z"></path></svg></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

+21 -2
View File
@@ -3,9 +3,28 @@ import type { Metadata } from 'next';
import { ThemeProvider } from '@/components/theme-provider';
import './globals.css';
const title = 'ChatGPT Agent | AI Chat & Research Assistant';
const description =
'Ask questions, explore ideas, and get clear AI answers with streaming responses, optional web research, file attachments, and saved conversations.';
export const metadata: Metadata = {
title: 'ChatGPT Agent',
description: 'A ChatGPT-powered assistant for clear, useful answers.',
applicationName: 'ChatGPT Agent',
title: {
default: title,
template: '%s | ChatGPT Agent',
},
description,
openGraph: {
type: 'website',
siteName: 'ChatGPT Agent',
title,
description,
},
twitter: {
card: 'summary',
title,
description,
},
};
export default function RootLayout({
+7 -1
View File
@@ -1,5 +1,11 @@
import { ChatAgent } from "@/components/chat/ChatAgent";
import { getDefaultChatModelId } from "@/services/chat/model";
export default function ChatPage() {
return <ChatAgent webSearchEnabled={Boolean(process.env.FIRECRAWL_API_KEY)} />;
return (
<ChatAgent
webSearchEnabled={Boolean(process.env.FIRECRAWL_API_KEY)}
defaultModelId={getDefaultChatModelId()}
/>
);
}