diff --git a/apps/gui/src/app/config/page.tsx b/apps/gui/src/app/config/page.tsx index 879d696..ebf21f7 100644 --- a/apps/gui/src/app/config/page.tsx +++ b/apps/gui/src/app/config/page.tsx @@ -10,8 +10,9 @@ import { getProviderMappings, setProviderMapping, updateProviderInstance, + getAvailableProviders, } from "@/app/play/actions"; -import type { LLMProviderInstance } from "@omnia/llm"; +import type { LLMProviderInstance, LLMProviderMeta } from "@omnia/llm"; interface ConfigStatus { apiKeySet: boolean; @@ -24,6 +25,7 @@ export default function ConfigPage() { const [config, setConfig] = useState(null); const [instances, setInstances] = useState([]); const [mappings, setMappings] = useState>({}); + const [availableProviders, setAvailableProviders] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); @@ -37,9 +39,11 @@ export default function ConfigPage() { useEffect(() => { if (selectedInstanceId === "new") { setEditName(""); - setEditProvider("google-genai"); + const defaultProvider = "google-genai"; + setEditProvider(defaultProvider); setEditKey(""); - setEditModel("gemini-2.5-flash"); + const pMeta = availableProviders.find((p) => p.id === defaultProvider); + setEditModel(pMeta?.defaultModel || "gemini-2.5-flash"); setEditIsActive(false); } else { const inst = instances.find((i) => i.id === selectedInstanceId); @@ -47,11 +51,20 @@ export default function ConfigPage() { setEditName(inst.name); setEditProvider(inst.providerName); setEditKey(""); - setEditModel(inst.modelName || "gemini-2.5-flash"); + const pMeta = availableProviders.find((p) => p.id === inst.providerName); + setEditModel(inst.modelName || pMeta?.defaultModel || "gemini-2.5-flash"); setEditIsActive(inst.isActive); } } - }, [selectedInstanceId, instances]); + }, [selectedInstanceId, instances, availableProviders]); + + const handleProviderChange = (providerId: string) => { + setEditProvider(providerId); + const pMeta = availableProviders.find((p) => p.id === providerId); + if (pMeta) { + setEditModel(pMeta.defaultModel); + } + }; const loadInstances = useCallback(async () => { try { @@ -79,6 +92,8 @@ export default function ConfigPage() { setConfig(result); await loadInstances(); await loadMappings(); + const provs = await getAvailableProviders(); + setAvailableProviders(provs); } catch (err) { setError(err instanceof Error ? err.message : String(err)); } finally { @@ -231,11 +246,19 @@ export default function ConfigPage() { + {editProvider && availableProviders.length > 0 && ( + + {availableProviders.find((p) => p.id === editProvider)?.description} + + )}
diff --git a/apps/gui/src/app/play/actions.ts b/apps/gui/src/app/play/actions.ts index 8f9423e..c36a26e 100644 --- a/apps/gui/src/app/play/actions.ts +++ b/apps/gui/src/app/play/actions.ts @@ -4,7 +4,7 @@ import path from "path"; import fs from "fs"; import { simulationManager } from "@/lib/simulation"; import type { SimSnapshot } from "@/lib/simulation"; -import { ProviderManager, LLMProviderInstance } from "@omnia/llm"; +import { ProviderManager, LLMProviderInstance, AVAILABLE_PROVIDERS, LLMProviderMeta } from "@omnia/llm"; function resolveScenarioPath(relative: string): string { const cwd = process.cwd(); @@ -274,3 +274,7 @@ export async function setProviderMapping( ): Promise { ProviderManager.setMapping(task, providerInstanceId); } + +export async function getAvailableProviders(): Promise { + return AVAILABLE_PROVIDERS; +} diff --git a/packages/llm/src/llm.ts b/packages/llm/src/llm.ts index 8e65d2c..5a1d3e8 100644 --- a/packages/llm/src/llm.ts +++ b/packages/llm/src/llm.ts @@ -45,3 +45,31 @@ export interface LLMProviderInstance { isActive: boolean; modelName?: string; } + +export interface LLMProviderMeta { + id: string; + displayName: string; + description: string; + defaultModel: string; +} + +export const AVAILABLE_PROVIDERS: LLMProviderMeta[] = [ + { + id: "google-genai", + displayName: "Google Gemini", + description: "Official Gemini integration using Google Gen AI SDK", + defaultModel: "gemini-2.5-flash", + }, + { + id: "openrouter", + displayName: "OpenRouter", + description: "Multi-model router supporting Anthropic, OpenAI, DeepSeek, and local models", + defaultModel: "google/gemini-2.5-flash", + }, + { + id: "mock", + displayName: "Mock LLM Provider", + description: "Stateless mock provider for testing and offline development", + defaultModel: "mock", + }, +]; diff --git a/packages/llm/src/providers/google-genai.ts b/packages/llm/src/providers/google-genai.ts index 5d0320a..17b0d1f 100644 --- a/packages/llm/src/providers/google-genai.ts +++ b/packages/llm/src/providers/google-genai.ts @@ -5,6 +5,11 @@ import { llmConfig } from "../config.js"; import { ProviderManager } from "../provider-manager.js"; export class GeminiProvider implements ILLMProvider { + static readonly providerId = "google-genai"; + static readonly displayName = "Google Gemini"; + static readonly description = "Official Gemini integration using Google Gen AI SDK"; + static readonly defaultModel = "gemini-2.5-flash"; + providerName = "Gemini"; private model: ChatGoogleGenerativeAI; lastCalls: LLMCallRecord[] = []; diff --git a/packages/llm/src/providers/mock.ts b/packages/llm/src/providers/mock.ts index 2f9715b..f11a90d 100644 --- a/packages/llm/src/providers/mock.ts +++ b/packages/llm/src/providers/mock.ts @@ -2,6 +2,11 @@ import { z } from "zod"; import { ILLMProvider, LLMRequest, LLMResponse, LLMCallRecord } from "../llm.js"; export class MockLLMProvider implements ILLMProvider { + static readonly providerId = "mock"; + static readonly displayName = "Mock LLM Provider"; + static readonly description = "Stateless mock provider for testing and offline development"; + static readonly defaultModel = "mock"; + providerName = "mock"; private callCount = 0; lastCalls: LLMCallRecord[] = []; diff --git a/packages/llm/src/providers/openrouter.ts b/packages/llm/src/providers/openrouter.ts index b57d1e9..200ac4e 100644 --- a/packages/llm/src/providers/openrouter.ts +++ b/packages/llm/src/providers/openrouter.ts @@ -5,6 +5,11 @@ import { llmConfig } from "../config.js"; import { ProviderManager } from "../provider-manager.js"; export class OpenRouterProvider implements ILLMProvider { + static readonly providerId = "openrouter"; + static readonly displayName = "OpenRouter"; + static readonly description = "Multi-model router supporting Anthropic, OpenAI, DeepSeek, and local models"; + static readonly defaultModel = "google/gemini-2.5-flash"; + providerName = "OpenRouter"; private model: ChatOpenRouter; lastCalls: LLMCallRecord[] = [];