File size: 2,132 Bytes
f6678ab | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | import { streamText, convertToModelMessages } from "ai";
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
import type { Request, Response } from "express";
export const DEFAULT_MODEL = "google/gemini-2.5-flash";
export function getProvider() {
const apiKey = process.env.OPENROUTER_API_KEY;
if (!apiKey) {
throw new Error("OPENROUTER_API_KEY environment variable is required");
}
return createOpenRouter({ apiKey });
}
interface StreamChatOptions {
systemPrompt: string;
tools: Parameters<typeof streamText>[0]["tools"];
logPrefix: string;
}
export async function streamChatResponse(
req: Request,
res: Response,
{ systemPrompt, tools, logPrefix }: StreamChatOptions,
) {
try {
const { messages, context, model } = req.body;
if (!messages || !Array.isArray(messages)) {
res.status(400).json({ error: "messages array is required" });
return;
}
const provider = getProvider();
const modelId = model || process.env.OPENROUTER_MODEL || DEFAULT_MODEL;
const modelMessages = await convertToModelMessages(messages);
const result = streamText({
model: provider.chat(modelId),
system: systemPrompt,
messages: modelMessages,
tools,
});
const webResponse = result.toUIMessageStreamResponse({
onError: (error) => {
console.error(`[${logPrefix}] stream error:`, error);
return error instanceof Error ? error.message : "Stream error";
},
});
res.writeHead(
webResponse.status,
Object.fromEntries(webResponse.headers.entries()),
);
const reader = webResponse.body!.getReader();
const pump = async (): Promise<void> => {
const { done, value } = await reader.read();
if (done) {
res.end();
return;
}
res.write(value);
return pump();
};
await pump();
} catch (error: unknown) {
const message =
error instanceof Error ? error.message : "Internal server error";
console.error(`[${logPrefix}] error:`, message);
if (!res.headersSent) {
res.status(500).json({ error: message });
}
}
}
|