Checkpoint: Ajout de Google Gemini (gemini-2.0-flash) comme 3ème moteur IA : schéma DB mis à jour (enum aiProvider + colonne geminiApiKey dans userSettings et importSettings), llm.ts mis à jour avec routing vers l'API Google AI Studio (compatible OpenAI), fenêtre de configuration IA mise à jour avec 3 cartes (Mistral / Gemini / Manus) et champ clé API Gemini.

This commit is contained in:
Manus
2026-07-27 15:55:07 +00:00
parent 46a61fca0e
commit 827c9ec41e
10 changed files with 2289 additions and 13 deletions

View File

@@ -283,31 +283,45 @@ const normalizeResponseFormat = ({
/**
* Résout l'URL API en tenant compte des paramètres utilisateur (DB) en priorité sur les variables d'environnement.
*/
function resolveApiUrlWithSettings(settings?: { aiProvider?: string | null; mistralApiKey?: string | null; manusForgeApiKey?: string | null; manusForgeApiUrl?: string | null }): string {
function resolveApiUrlWithSettings(settings?: { aiProvider?: string | null; mistralApiKey?: string | null; manusForgeApiKey?: string | null; manusForgeApiUrl?: string | null; geminiApiKey?: string | null }): string {
const provider = settings?.aiProvider || "mistral";
if (provider === "mistral") {
return "https://api.mistral.ai/v1/chat/completions";
}
if (provider === "gemini") {
// Google AI Studio — interface compatible OpenAI
return "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions";
}
// Manus provider
const forgeUrl = settings?.manusForgeApiUrl || ENV.forgeApiUrl || "https://forge.manus.ai";
return `${forgeUrl.replace(/\/$/, "")}/v1/chat/completions`;
}
function getApiKeyWithSettings(settings?: { aiProvider?: string | null; mistralApiKey?: string | null; manusForgeApiKey?: string | null }): string {
function getApiKeyWithSettings(settings?: { aiProvider?: string | null; mistralApiKey?: string | null; manusForgeApiKey?: string | null; geminiApiKey?: string | null }): string {
const provider = settings?.aiProvider || "mistral";
if (provider === "mistral") {
return settings?.mistralApiKey || ENV.mistralApiKey || "";
}
if (provider === "gemini") {
return settings?.geminiApiKey || ENV.geminiApiKey || "";
}
return settings?.manusForgeApiKey || ENV.forgeApiKey || "";
}
function getModelForProvider(provider: string): string {
if (provider === "mistral") return "mistral-large-latest";
if (provider === "gemini") return "gemini-2.0-flash";
// Manus Forge → Gemini 2.5 Flash via proxy
return "gemini-2.5-flash";
}
/**
* Version de invokeLLM qui accepte les paramètres utilisateur depuis la DB
* pour choisir dynamiquement le moteur IA (Mistral ou Manus).
* pour choisir dynamiquement le moteur IA (Mistral, Manus ou Gemini).
*/
export async function invokeLLMWithUserSettings(
params: InvokeParams,
userSettings?: { aiProvider?: string | null; mistralApiKey?: string | null; manusForgeApiKey?: string | null; manusForgeApiUrl?: string | null }
userSettings?: { aiProvider?: string | null; mistralApiKey?: string | null; manusForgeApiKey?: string | null; manusForgeApiUrl?: string | null; geminiApiKey?: string | null }
): Promise<InvokeResult> {
const apiKey = getApiKeyWithSettings(userSettings);
if (!apiKey || apiKey.trim().length === 0) {
@@ -328,7 +342,7 @@ export async function invokeLLMWithUserSettings(
response_format,
} = params;
const model = isMistral ? "mistral-large-latest" : "gemini-2.5-flash";
const model = getModelForProvider(provider);
const payload: Record<string, unknown> = {
model,
@@ -342,7 +356,8 @@ export async function invokeLLMWithUserSettings(
payload.max_tokens = 32768;
if (!isMistral) {
// thinking uniquement pour Manus Forge (proxy Gemini)
if (provider === "manus") {
payload.thinking = { budget_tokens: 128 };
}