import { NextRequest, NextResponse } from "next/server";
import OpenAI from "openai";
import { transformStream } from "@crayonai/stream";
import { DBMessage, getMessageStore } from "./messageStore";
import { MCPClient } from "./mcp";
import { JSONSchema } from "openai/lib/jsonschema.mjs";
// Initialize MCP client
const mcpClient = new MCPClient();
interface RequestBody {
prompt: DBMessage;
threadId: string;
responseId: string;
}
async function ensureMCPConnection(): Promise<void> {
if (mcpClient.tools.length === 0) {
await mcpClient.connect();
}
}
export async function POST(req: NextRequest): Promise<NextResponse> {
const { prompt, threadId, responseId } = (await req.json()) as RequestBody;
const client = new OpenAI({
baseURL: "https://api.thesys.dev/v1/embed/",
apiKey: process.env.THESYS_API_KEY,
});
const messageStore = getMessageStore(threadId);
messageStore.addMessage(prompt);
// Ensure MCP connection is established
await ensureMCPConnection();
const llmStream = await client.beta.chat.completions.runTools({
model: "c1-nightly",
messages: messageStore.getOpenAICompatibleMessageList(),
tools: mcpClient.tools.map((tool) => ({
type: "function",
function: {
name: tool.function.name,
description: tool.function.description || "",
parameters: tool.function.parameters as unknown as JSONSchema,
parse: JSON.parse,
function: async (args: unknown) => {
const results = await mcpClient.runTool({
tool_call_id: tool.function.name + Date.now().toString(),
name: tool.function.name,
args: args as Record<string, unknown>,
});
return results.content;
},
},
})),
stream: true,
});
const responseStream = transformStream(
llmStream,
(chunk) => {
return chunk.choices[0].delta.content;
},
{
onEnd: ({ accumulated }) => {
const message = accumulated.filter((message) => message).join("");
messageStore.addMessage({
role: "assistant",
content: message,
id: responseId,
});
},
}
) as ReadableStream<string>;
return new NextResponse(responseStream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache, no-transform",
Connection: "keep-alive",
},
});
}