import { streamText } from 'ai' import { createOpenAI } from '@ai-sdk/openai' import { generatePayloadLocalTools } from '../tools/payloadLocal.js' import { createMcpTools } from '../tools/mcpAdapter.js' import { generateMemoryTools } from '../tools/memoryDb.js' import type { PayloadRequest } from 'payload' const openrouter = createOpenAI({ baseURL: 'https://openrouter.ai/api/v1', apiKey: process.env.OPENROUTER_API_KEY || 'dummy_key', }) export const handleMcpChat = async (req: PayloadRequest) => { if (!req.user) { return Response.json({ error: 'Unauthorized. You must be logged in to use AI Chat.' }, { status: 401 }) } const { messages } = (await req.json?.() || { messages: [] }) as { messages: any[] } // 1. Check AI Permissions for req.user // In a real implementation this looks up the global or collection for permissions const allowedCollections = ['users'] // Stub let activeTools: Record = {} // 2. Generate Payload Local Tools if (allowedCollections.length > 0) { const payloadTools = generatePayloadLocalTools(req.payload, req, allowedCollections) activeTools = { ...activeTools, ...payloadTools } } // 3. Connect External MCPs const allowedMcpServers: string[] = [] // Stub if (allowedMcpServers.includes('gitea')) { try { const { tools: giteaTools } = await createMcpTools({ name: 'gitea', command: 'npx', args: ['-y', '@modelcontextprotocol/server-gitea', '--url', 'https://git.mintel.int', '--token', process.env.GITEA_TOKEN || ''] }) activeTools = { ...activeTools, ...giteaTools } } catch (e) { console.error('Failed to connect to Gitea MCP', e) } } // 4. Inject Memory Database Tools // We provide the user ID so memory is partitioned per user const memoryTools = generateMemoryTools(req.user.id) activeTools = { ...activeTools, ...memoryTools } // 5. Build prompt to ensure it asks before saving const memorySystemPrompt = ` You have access to a long-term vector memory database (Qdrant). If the user says "speicher das", "merk dir das", "vergiss das nicht" etc., you MUST use the save_memory tool. If the user shares important context but doesn't explicitly ask you to remember it, you should ask "Soll ich mir das für die Zukunft merken?" before saving it. Do not ask for trivial things. ` try { const result = streamText({ // @ts-ignore - AI SDK type mismatch model: openrouter('google/gemini-3.0-flash'), messages, tools: activeTools, system: `You are a helpful Payload CMS MCP Assistant orchestrating the local Mintel ecosystem. You only have access to tools explicitly granted by the Admin. You cannot do anything outside these tools. Always explain what you are doing. ${memorySystemPrompt}` }) return result.toTextStreamResponse() } catch (error) { console.error("AI Error:", error) return Response.json({ error: 'Failed to process AI request' }, { status: 500 }) } }