feat: configure dynamic providers via .env (#1108)

* Use backend API route to fetch dynamic models

# Conflicts:
#	app/components/chat/BaseChat.tsx

* Override ApiKeys if provided in frontend

* Remove obsolete artifact

* Transport api keys from client to server in header

* Cache static provider information

* Restore reading provider settings from cookie

* Reload only a single provider on api key change

* Transport apiKeys and providerSettings via cookies.

While doing this, introduce a simple helper function for cookies
This commit is contained in:
Oliver Jägle
2025-01-17 23:09:19 +01:00
committed by GitHub
parent 87ff81035f
commit e19644268c
8 changed files with 164 additions and 150 deletions

View File

@@ -1,6 +1,84 @@
import { json } from '@remix-run/cloudflare';
import { MODEL_LIST } from '~/utils/constants';
import { LLMManager } from '~/lib/modules/llm/manager';
import type { ModelInfo } from '~/lib/modules/llm/types';
import type { ProviderInfo } from '~/types/model';
import { getApiKeysFromCookie, getProviderSettingsFromCookie } from '~/lib/api/cookies';
export async function loader() {
return json(MODEL_LIST);
interface ModelsResponse {
modelList: ModelInfo[];
providers: ProviderInfo[];
defaultProvider: ProviderInfo;
}
let cachedProviders: ProviderInfo[] | null = null;
let cachedDefaultProvider: ProviderInfo | null = null;
function getProviderInfo(llmManager: LLMManager) {
if (!cachedProviders) {
cachedProviders = llmManager.getAllProviders().map((provider) => ({
name: provider.name,
staticModels: provider.staticModels,
getApiKeyLink: provider.getApiKeyLink,
labelForGetApiKey: provider.labelForGetApiKey,
icon: provider.icon,
}));
}
if (!cachedDefaultProvider) {
const defaultProvider = llmManager.getDefaultProvider();
cachedDefaultProvider = {
name: defaultProvider.name,
staticModels: defaultProvider.staticModels,
getApiKeyLink: defaultProvider.getApiKeyLink,
labelForGetApiKey: defaultProvider.labelForGetApiKey,
icon: defaultProvider.icon,
};
}
return { providers: cachedProviders, defaultProvider: cachedDefaultProvider };
}
export async function loader({
request,
params,
}: {
request: Request;
params: { provider?: string };
}): Promise<Response> {
const llmManager = LLMManager.getInstance(import.meta.env);
// Get client side maintained API keys and provider settings from cookies
const cookieHeader = request.headers.get('Cookie');
const apiKeys = getApiKeysFromCookie(cookieHeader);
const providerSettings = getProviderSettingsFromCookie(cookieHeader);
const { providers, defaultProvider } = getProviderInfo(llmManager);
let modelList: ModelInfo[] = [];
if (params.provider) {
// Only update models for the specific provider
const provider = llmManager.getProvider(params.provider);
if (provider) {
const staticModels = provider.staticModels;
const dynamicModels = provider.getDynamicModels
? await provider.getDynamicModels(apiKeys, providerSettings, import.meta.env)
: [];
modelList = [...staticModels, ...dynamicModels];
}
} else {
// Update all models
modelList = await llmManager.updateModelList({
apiKeys,
providerSettings,
serverEnv: import.meta.env,
});
}
return json<ModelsResponse>({
modelList,
providers,
defaultProvider,
});
}