mirror of
https://github.com/fosrl/docs-v2.git
synced 2026-09-27 00:09:07 +02:00
port mintlify to fumadocs
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
import {
|
||||
convertToModelMessages,
|
||||
createUIMessageStreamResponse,
|
||||
stepCountIs,
|
||||
streamText,
|
||||
toUIMessageStream,
|
||||
type SystemModelMessage,
|
||||
} from 'ai';
|
||||
import type { ChatUIMessage } from '@/components/ai/search';
|
||||
import { AIConfigError, getModel } from '@/lib/ai/model';
|
||||
import { getSystemPrompt } from '@/lib/ai/prompt';
|
||||
import { checkRateLimit, clientKey } from '@/lib/ai/rate-limit';
|
||||
import { tools } from '@/lib/ai/tools';
|
||||
|
||||
export const maxDuration = 120;
|
||||
|
||||
const MAX_MESSAGES = 30;
|
||||
const MAX_MESSAGE_CHARS = 8_000;
|
||||
|
||||
function json(status: number, message: string, headers?: HeadersInit) {
|
||||
return Response.json({ error: message }, { status, headers });
|
||||
}
|
||||
|
||||
export async function POST(req: Request) {
|
||||
const limit = checkRateLimit(clientKey(req));
|
||||
if (!limit.ok) {
|
||||
return json(429, `Too many questions, try again in ${limit.retryAfter}s.`, {
|
||||
'Retry-After': String(limit.retryAfter),
|
||||
});
|
||||
}
|
||||
|
||||
let config;
|
||||
try {
|
||||
config = getModel();
|
||||
} catch (e) {
|
||||
if (e instanceof AIConfigError) return json(503, e.message);
|
||||
throw e;
|
||||
}
|
||||
|
||||
const body = (await req.json().catch(() => null)) as { messages?: ChatUIMessage[] } | null;
|
||||
const messages = (body?.messages ?? []).slice(-MAX_MESSAGES);
|
||||
const tooLong = messages.some((m) =>
|
||||
m.parts.some((p) => p.type === 'text' && p.text.length > MAX_MESSAGE_CHARS),
|
||||
);
|
||||
if (messages.length === 0 || tooLong) return json(400, 'Invalid or too long message.');
|
||||
|
||||
const instructions: SystemModelMessage = {
|
||||
role: 'system',
|
||||
content: getSystemPrompt(),
|
||||
// the system prompt is large and identical across requests
|
||||
providerOptions: { anthropic: { cacheControl: { type: 'ephemeral' } } },
|
||||
};
|
||||
|
||||
const result = streamText({
|
||||
model: config.model,
|
||||
stopWhen: stepCountIs(8),
|
||||
tools,
|
||||
toolChoice: 'auto',
|
||||
instructions,
|
||||
messages: await convertToModelMessages<ChatUIMessage>(messages, {
|
||||
convertDataPart(part) {
|
||||
if (part.type === 'data-client')
|
||||
return {
|
||||
type: 'text',
|
||||
text: `[Client Context: ${JSON.stringify(part.data)}]`,
|
||||
};
|
||||
},
|
||||
}),
|
||||
onError({ error }) {
|
||||
console.error('[api/chat]', error);
|
||||
},
|
||||
});
|
||||
|
||||
return createUIMessageStreamResponse({
|
||||
stream: toUIMessageStream({
|
||||
stream: result.stream,
|
||||
onError: () => 'The assistant hit an error. Please try again.',
|
||||
}),
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user