From d1210773e74d7fdefc64b50b542345e1d2932933 Mon Sep 17 00:00:00 2001 From: drjones Date: Thu, 13 Aug 2026 23:45:02 +0000 Subject: [PATCH] Switch AI tool generator from Gemini to local Ollama (gemma4:26b @ shadow-death .128) --- src/server/aiGenerator.ts | 51 +++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/server/aiGenerator.ts b/src/server/aiGenerator.ts index f45b0b3..6ea6750 100644 --- a/src/server/aiGenerator.ts +++ b/src/server/aiGenerator.ts @@ -1,16 +1,31 @@ -import { GoogleGenAI } from '@google/genai'; import { MCPServerDefinition, ToolDefinition } from '../types.js'; -let aiClient: GoogleGenAI | null = null; +const OLLAMA_HOST = process.env.OLLAMA_HOST || 'http://10.30.20.128:11434'; +const OLLAMA_MODEL = process.env.OLLAMA_MODEL || 'gemma4:26b'; -function getAIClient(): GoogleGenAI | null { - if (!aiClient) { - const key = process.env.GEMINI_API_KEY; - if (key && key !== 'MY_GEMINI_API_KEY') { - aiClient = new GoogleGenAI({ apiKey: key }); - } +async function callLocalModel(prompt: string): Promise { + const res = await fetch(`${OLLAMA_HOST}/api/chat`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + model: OLLAMA_MODEL, + messages: [{ role: 'user', content: prompt }], + stream: false, + format: 'json', + keep_alive: '30m', + options: { num_predict: 4096, temperature: 0.2 }, + }), + signal: AbortSignal.timeout(180000), + }); + if (!res.ok) { + throw new Error(`Ollama HTTP ${res.status} (${res.statusText})`); } - return aiClient; + const data = await res.json(); + let content = data?.message?.content || ''; + if (!content) content = data?.message?.thinking || ''; + content = content.trim(); + if (!content) throw new Error('Empty response from local model'); + return content; } export interface GeneratedMCPResponse { @@ -36,17 +51,8 @@ export interface GeneratedMCPResponse { } export async function generateMCPToolFromPrompt(prompt: string): Promise { - const ai = getAIClient(); - - if (!ai) { - // Fallback template generator when GEMINI_API_KEY is not configured - return generateFallbackMCP(prompt); - } - try { - const response = await ai.models.generateContent({ - model: 'gemini-2.5-flash', - contents: `You are an expert Model Context Protocol (MCP) tool builder. + const systemPrompt = `You are an expert Model Context Protocol (MCP) tool builder. Given the following user request or API prompt, construct a complete MCP Tool configuration in strict JSON. User Request: "${prompt}" @@ -75,15 +81,14 @@ Respond ONLY with valid JSON (no markdown ticks or commentary) matching this Typ "sampleArgs": { "param1": "sample_value" } } -Provide executable JavaScript code for customScript or accurate URL template for webhookConfig. Use fetch() if HTTP calls are needed inside customScript.`, - }); +Provide executable JavaScript code for customScript or accurate URL template for webhookConfig. Use fetch() if HTTP calls are needed inside customScript.`; - const rawText = response.text || ''; + const rawText = await callLocalModel(systemPrompt); const cleanJson = rawText.replace(/```json/g, '').replace(/```/g, '').trim(); const parsed = JSON.parse(cleanJson); return parsed; } catch (err) { - console.warn('Gemini API call failed, using heuristic fallback:', err); + console.warn('Local model generation failed, using heuristic fallback:', err); return generateFallbackMCP(prompt); } }