Switch AI tool generator from Gemini to local Ollama (gemma4:26b @ shadow-death .128)

This commit is contained in:
drjones
2026-08-13 23:45:02 +00:00
parent 33a9957dcc
commit d1210773e7

View File

@@ -1,16 +1,31 @@
import { GoogleGenAI } from '@google/genai';
import { MCPServerDefinition, ToolDefinition } from '../types.js'; 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 { async function callLocalModel(prompt: string): Promise<string> {
if (!aiClient) { const res = await fetch(`${OLLAMA_HOST}/api/chat`, {
const key = process.env.GEMINI_API_KEY; method: 'POST',
if (key && key !== 'MY_GEMINI_API_KEY') { headers: { 'Content-Type': 'application/json' },
aiClient = new GoogleGenAI({ apiKey: key }); 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 { export interface GeneratedMCPResponse {
@@ -36,17 +51,8 @@ export interface GeneratedMCPResponse {
} }
export async function generateMCPToolFromPrompt(prompt: string): Promise<GeneratedMCPResponse> { export async function generateMCPToolFromPrompt(prompt: string): Promise<GeneratedMCPResponse> {
const ai = getAIClient();
if (!ai) {
// Fallback template generator when GEMINI_API_KEY is not configured
return generateFallbackMCP(prompt);
}
try { try {
const response = await ai.models.generateContent({ const systemPrompt = `You are an expert Model Context Protocol (MCP) tool builder.
model: 'gemini-2.5-flash',
contents: `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. Given the following user request or API prompt, construct a complete MCP Tool configuration in strict JSON.
User Request: "${prompt}" User Request: "${prompt}"
@@ -75,15 +81,14 @@ Respond ONLY with valid JSON (no markdown ticks or commentary) matching this Typ
"sampleArgs": { "param1": "sample_value" } "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 cleanJson = rawText.replace(/```json/g, '').replace(/```/g, '').trim();
const parsed = JSON.parse(cleanJson); const parsed = JSON.parse(cleanJson);
return parsed; return parsed;
} catch (err) { } 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); return generateFallbackMCP(prompt);
} }
} }