import 'dotenv/config'; import { generateText, stepCountIs } from 'ai'; import { createMCPClient } from '@ai-sdk/mcp'; import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'; import { deepseek } from '@ai-sdk/deepseek'; import { openai } from '@ai-sdk/openai'; import { fileURLToPath } from 'node:url'; import { dirname } from 'node:path'; const mockMcpPath = fileURLToPath(new URL('./mock-mcp-server.ts', import.meta.url)); const coreDir = dirname(mockMcpPath); export interface AgentConfig { provider: 'deepseek' | 'openai'; model: string; maxSteps: number; } export interface AgentResult { text: string; steps: number; toolCalls: { name: string; args: unknown }[]; finishReason: string; usage: { inputTokens: number; outputTokens: number } | null; } export async function runAgent(message: string, config: AgentConfig): Promise { const transport = new StdioClientTransport({ command: process.execPath, args: ['--import', 'tsx', mockMcpPath], cwd: coreDir, stderr: 'ignore', }); const mcp = await createMCPClient({ transport }); try { const tools = await mcp.tools(); const model = config.provider === 'deepseek' ? deepseek(config.model) : openai(config.model); const result = await generateText({ model, tools, stopWhen: stepCountIs(config.maxSteps), system: 'Tu es un assistant de démonstration pour un garage automobile fictif. Réponds de façon concise, en français. ' + 'Utilise les outils fournis uniquement quand c est nécessaire. ' + 'Ne fabrique JAMAIS un résultat : si un outil renvoie une erreur, transmets honnêtement cette erreur au client.', prompt: message, }); const steps = result.steps ?? []; const toolCalls = steps.flatMap((s) => (s.toolCalls ?? []).map((tc) => ({ name: tc.toolName, args: tc.input })) ); return { text: result.text, steps: steps.length, toolCalls, finishReason: result.finishReason, usage: result.usage ? { inputTokens: result.usage.inputTokens ?? 0, outputTokens: result.usage.outputTokens ?? 0 } : null, }; } finally { await mcp.close?.(); } }