Oliver Jägle commited on
Commit
e196442
·
unverified ·
1 Parent(s): 87ff810

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

Browse files

* 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

app/components/chat/BaseChat.tsx CHANGED
@@ -3,13 +3,13 @@
3
  * Preventing TS checks with files presented in the video for a better presentation.
4
  */
5
  import type { Message } from 'ai';
6
- import React, { type RefCallback, useCallback, useEffect, useState } from 'react';
7
  import { ClientOnly } from 'remix-utils/client-only';
8
  import { Menu } from '~/components/sidebar/Menu.client';
9
  import { IconButton } from '~/components/ui/IconButton';
10
  import { Workbench } from '~/components/workbench/Workbench.client';
11
  import { classNames } from '~/utils/classNames';
12
- import { MODEL_LIST, PROVIDER_LIST, initializeModelList } from '~/utils/constants';
13
  import { Messages } from './Messages.client';
14
  import { SendButton } from './SendButton.client';
15
  import { APIKeyManager, getApiKeysFromCookies } from './APIKeyManager';
@@ -25,13 +25,13 @@ import GitCloneButton from './GitCloneButton';
25
  import FilePreview from './FilePreview';
26
  import { ModelSelector } from '~/components/chat/ModelSelector';
27
  import { SpeechRecognitionButton } from '~/components/chat/SpeechRecognition';
28
- import type { IProviderSetting, ProviderInfo } from '~/types/model';
29
  import { ScreenshotStateManager } from './ScreenshotStateManager';
30
  import { toast } from 'react-toastify';
31
  import StarterTemplates from './StarterTemplates';
32
  import type { ActionAlert } from '~/types/actions';
33
  import ChatAlert from './ChatAlert';
34
- import { LLMManager } from '~/lib/modules/llm/manager';
35
 
36
  const TEXTAREA_MIN_HEIGHT = 76;
37
 
@@ -102,35 +102,13 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
102
  ) => {
103
  const TEXTAREA_MAX_HEIGHT = chatStarted ? 400 : 200;
104
  const [apiKeys, setApiKeys] = useState<Record<string, string>>(getApiKeysFromCookies());
105
- const [modelList, setModelList] = useState(MODEL_LIST);
106
  const [isModelSettingsCollapsed, setIsModelSettingsCollapsed] = useState(false);
107
  const [isListening, setIsListening] = useState(false);
108
  const [recognition, setRecognition] = useState<SpeechRecognition | null>(null);
109
  const [transcript, setTranscript] = useState('');
110
  const [isModelLoading, setIsModelLoading] = useState<string | undefined>('all');
111
 
112
- const getProviderSettings = useCallback(() => {
113
- let providerSettings: Record<string, IProviderSetting> | undefined = undefined;
114
-
115
- try {
116
- const savedProviderSettings = Cookies.get('providers');
117
-
118
- if (savedProviderSettings) {
119
- const parsedProviderSettings = JSON.parse(savedProviderSettings);
120
-
121
- if (typeof parsedProviderSettings === 'object' && parsedProviderSettings !== null) {
122
- providerSettings = parsedProviderSettings;
123
- }
124
- }
125
- } catch (error) {
126
- console.error('Error loading Provider Settings from cookies:', error);
127
-
128
- // Clear invalid cookie data
129
- Cookies.remove('providers');
130
- }
131
-
132
- return providerSettings;
133
- }, []);
134
  useEffect(() => {
135
  console.log(transcript);
136
  }, [transcript]);
@@ -169,7 +147,6 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
169
 
170
  useEffect(() => {
171
  if (typeof window !== 'undefined') {
172
- const providerSettings = getProviderSettings();
173
  let parsedApiKeys: Record<string, string> | undefined = {};
174
 
175
  try {
@@ -177,17 +154,18 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
177
  setApiKeys(parsedApiKeys);
178
  } catch (error) {
179
  console.error('Error loading API keys from cookies:', error);
180
-
181
- // Clear invalid cookie data
182
  Cookies.remove('apiKeys');
183
  }
 
184
  setIsModelLoading('all');
185
- initializeModelList({ apiKeys: parsedApiKeys, providerSettings })
186
- .then((modelList) => {
187
- setModelList(modelList);
 
 
188
  })
189
  .catch((error) => {
190
- console.error('Error initializing model list:', error);
191
  })
192
  .finally(() => {
193
  setIsModelLoading(undefined);
@@ -200,29 +178,24 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
200
  setApiKeys(newApiKeys);
201
  Cookies.set('apiKeys', JSON.stringify(newApiKeys));
202
 
203
- const provider = LLMManager.getInstance(import.meta.env || process.env || {}).getProvider(providerName);
204
 
205
- if (provider && provider.getDynamicModels) {
206
- setIsModelLoading(providerName);
207
 
208
- try {
209
- const providerSettings = getProviderSettings();
210
- const staticModels = provider.staticModels;
211
- const dynamicModels = await provider.getDynamicModels(
212
- newApiKeys,
213
- providerSettings,
214
- import.meta.env || process.env || {},
215
- );
216
-
217
- setModelList((preModels) => {
218
- const filteredOutPreModels = preModels.filter((x) => x.provider !== providerName);
219
- return [...filteredOutPreModels, ...staticModels, ...dynamicModels];
220
- });
221
- } catch (error) {
222
- console.error('Error loading dynamic models:', error);
223
- }
224
- setIsModelLoading(undefined);
225
  }
 
 
 
 
 
 
 
226
  };
227
 
228
  const startListening = () => {
 
3
  * Preventing TS checks with files presented in the video for a better presentation.
4
  */
5
  import type { Message } from 'ai';
6
+ import React, { type RefCallback, useEffect, useState } from 'react';
7
  import { ClientOnly } from 'remix-utils/client-only';
8
  import { Menu } from '~/components/sidebar/Menu.client';
9
  import { IconButton } from '~/components/ui/IconButton';
10
  import { Workbench } from '~/components/workbench/Workbench.client';
11
  import { classNames } from '~/utils/classNames';
12
+ import { PROVIDER_LIST } from '~/utils/constants';
13
  import { Messages } from './Messages.client';
14
  import { SendButton } from './SendButton.client';
15
  import { APIKeyManager, getApiKeysFromCookies } from './APIKeyManager';
 
25
  import FilePreview from './FilePreview';
26
  import { ModelSelector } from '~/components/chat/ModelSelector';
27
  import { SpeechRecognitionButton } from '~/components/chat/SpeechRecognition';
28
+ import type { ProviderInfo } from '~/types/model';
29
  import { ScreenshotStateManager } from './ScreenshotStateManager';
30
  import { toast } from 'react-toastify';
31
  import StarterTemplates from './StarterTemplates';
32
  import type { ActionAlert } from '~/types/actions';
33
  import ChatAlert from './ChatAlert';
34
+ import type { ModelInfo } from '~/lib/modules/llm/types';
35
 
36
  const TEXTAREA_MIN_HEIGHT = 76;
37
 
 
102
  ) => {
103
  const TEXTAREA_MAX_HEIGHT = chatStarted ? 400 : 200;
104
  const [apiKeys, setApiKeys] = useState<Record<string, string>>(getApiKeysFromCookies());
105
+ const [modelList, setModelList] = useState<ModelInfo[]>([]);
106
  const [isModelSettingsCollapsed, setIsModelSettingsCollapsed] = useState(false);
107
  const [isListening, setIsListening] = useState(false);
108
  const [recognition, setRecognition] = useState<SpeechRecognition | null>(null);
109
  const [transcript, setTranscript] = useState('');
110
  const [isModelLoading, setIsModelLoading] = useState<string | undefined>('all');
111
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  useEffect(() => {
113
  console.log(transcript);
114
  }, [transcript]);
 
147
 
148
  useEffect(() => {
149
  if (typeof window !== 'undefined') {
 
150
  let parsedApiKeys: Record<string, string> | undefined = {};
151
 
152
  try {
 
154
  setApiKeys(parsedApiKeys);
155
  } catch (error) {
156
  console.error('Error loading API keys from cookies:', error);
 
 
157
  Cookies.remove('apiKeys');
158
  }
159
+
160
  setIsModelLoading('all');
161
+ fetch('/api/models')
162
+ .then((response) => response.json())
163
+ .then((data) => {
164
+ const typedData = data as { modelList: ModelInfo[] };
165
+ setModelList(typedData.modelList);
166
  })
167
  .catch((error) => {
168
+ console.error('Error fetching model list:', error);
169
  })
170
  .finally(() => {
171
  setIsModelLoading(undefined);
 
178
  setApiKeys(newApiKeys);
179
  Cookies.set('apiKeys', JSON.stringify(newApiKeys));
180
 
181
+ setIsModelLoading(providerName);
182
 
183
+ let providerModels: ModelInfo[] = [];
 
184
 
185
+ try {
186
+ const response = await fetch(`/api/models/${encodeURIComponent(providerName)}`);
187
+ const data = await response.json();
188
+ providerModels = (data as { modelList: ModelInfo[] }).modelList;
189
+ } catch (error) {
190
+ console.error('Error loading dynamic models for:', providerName, error);
 
 
 
 
 
 
 
 
 
 
 
191
  }
192
+
193
+ // Only update models for the specific provider
194
+ setModelList((prevModels) => {
195
+ const otherModels = prevModels.filter((model) => model.provider !== providerName);
196
+ return [...otherModels, ...providerModels];
197
+ });
198
+ setIsModelLoading(undefined);
199
  };
200
 
201
  const startListening = () => {
app/lib/api/cookies.ts ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ export function parseCookies(cookieHeader: string | null) {
2
+ const cookies: Record<string, string> = {};
3
+
4
+ if (!cookieHeader) {
5
+ return cookies;
6
+ }
7
+
8
+ // Split the cookie string by semicolons and spaces
9
+ const items = cookieHeader.split(';').map((cookie) => cookie.trim());
10
+
11
+ items.forEach((item) => {
12
+ const [name, ...rest] = item.split('=');
13
+
14
+ if (name && rest.length > 0) {
15
+ // Decode the name and value, and join value parts in case it contains '='
16
+ const decodedName = decodeURIComponent(name.trim());
17
+ const decodedValue = decodeURIComponent(rest.join('=').trim());
18
+ cookies[decodedName] = decodedValue;
19
+ }
20
+ });
21
+
22
+ return cookies;
23
+ }
24
+
25
+ export function getApiKeysFromCookie(cookieHeader: string | null): Record<string, string> {
26
+ const cookies = parseCookies(cookieHeader);
27
+ return cookies.apiKeys ? JSON.parse(cookies.apiKeys) : {};
28
+ }
29
+
30
+ export function getProviderSettingsFromCookie(cookieHeader: string | null): Record<string, any> {
31
+ const cookies = parseCookies(cookieHeader);
32
+ return cookies.providers ? JSON.parse(cookies.providers) : {};
33
+ }
app/lib/modules/llm/manager.ts CHANGED
@@ -83,7 +83,7 @@ export class LLMManager {
83
 
84
  let enabledProviders = Array.from(this._providers.values()).map((p) => p.name);
85
 
86
- if (providerSettings) {
87
  enabledProviders = enabledProviders.filter((p) => providerSettings[p].enabled);
88
  }
89
 
 
83
 
84
  let enabledProviders = Array.from(this._providers.values()).map((p) => p.name);
85
 
86
+ if (providerSettings && Object.keys(providerSettings).length > 0) {
87
  enabledProviders = enabledProviders.filter((p) => providerSettings[p].enabled);
88
  }
89
 
app/routes/api.enhancer.ts CHANGED
@@ -1,34 +1,13 @@
1
  import { type ActionFunctionArgs } from '@remix-run/cloudflare';
2
-
3
- //import { StreamingTextResponse, parseStreamPart } from 'ai';
4
  import { streamText } from '~/lib/.server/llm/stream-text';
5
  import { stripIndents } from '~/utils/stripIndent';
6
- import type { IProviderSetting, ProviderInfo } from '~/types/model';
 
7
 
8
  export async function action(args: ActionFunctionArgs) {
9
  return enhancerAction(args);
10
  }
11
 
12
- function parseCookies(cookieHeader: string) {
13
- const cookies: any = {};
14
-
15
- // Split the cookie string by semicolons and spaces
16
- const items = cookieHeader.split(';').map((cookie) => cookie.trim());
17
-
18
- items.forEach((item) => {
19
- const [name, ...rest] = item.split('=');
20
-
21
- if (name && rest) {
22
- // Decode the name and value, and join value parts in case it contains '='
23
- const decodedName = decodeURIComponent(name.trim());
24
- const decodedValue = decodeURIComponent(rest.join('=').trim());
25
- cookies[decodedName] = decodedValue;
26
- }
27
- });
28
-
29
- return cookies;
30
- }
31
-
32
  async function enhancerAction({ context, request }: ActionFunctionArgs) {
33
  const { message, model, provider } = await request.json<{
34
  message: string;
@@ -55,12 +34,8 @@ async function enhancerAction({ context, request }: ActionFunctionArgs) {
55
  }
56
 
57
  const cookieHeader = request.headers.get('Cookie');
58
-
59
- // Parse the cookie's value (returns an object or null if no cookie exists)
60
- const apiKeys = JSON.parse(parseCookies(cookieHeader || '').apiKeys || '{}');
61
- const providerSettings: Record<string, IProviderSetting> = JSON.parse(
62
- parseCookies(cookieHeader || '').providers || '{}',
63
- );
64
 
65
  try {
66
  const result = await streamText({
 
1
  import { type ActionFunctionArgs } from '@remix-run/cloudflare';
 
 
2
  import { streamText } from '~/lib/.server/llm/stream-text';
3
  import { stripIndents } from '~/utils/stripIndent';
4
+ import type { ProviderInfo } from '~/types/model';
5
+ import { getApiKeysFromCookie, getProviderSettingsFromCookie } from '~/lib/api/cookies';
6
 
7
  export async function action(args: ActionFunctionArgs) {
8
  return enhancerAction(args);
9
  }
10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  async function enhancerAction({ context, request }: ActionFunctionArgs) {
12
  const { message, model, provider } = await request.json<{
13
  message: string;
 
34
  }
35
 
36
  const cookieHeader = request.headers.get('Cookie');
37
+ const apiKeys = getApiKeysFromCookie(cookieHeader);
38
+ const providerSettings = getProviderSettingsFromCookie(cookieHeader);
 
 
 
 
39
 
40
  try {
41
  const result = await streamText({
app/routes/api.llmcall.ts CHANGED
@@ -1,34 +1,24 @@
1
  import { type ActionFunctionArgs } from '@remix-run/cloudflare';
2
-
3
- //import { StreamingTextResponse, parseStreamPart } from 'ai';
4
  import { streamText } from '~/lib/.server/llm/stream-text';
5
  import type { IProviderSetting, ProviderInfo } from '~/types/model';
6
  import { generateText } from 'ai';
7
- import { getModelList, PROVIDER_LIST } from '~/utils/constants';
8
  import { MAX_TOKENS } from '~/lib/.server/llm/constants';
 
 
 
9
 
10
  export async function action(args: ActionFunctionArgs) {
11
  return llmCallAction(args);
12
  }
13
 
14
- function parseCookies(cookieHeader: string) {
15
- const cookies: any = {};
16
-
17
- // Split the cookie string by semicolons and spaces
18
- const items = cookieHeader.split(';').map((cookie) => cookie.trim());
19
-
20
- items.forEach((item) => {
21
- const [name, ...rest] = item.split('=');
22
-
23
- if (name && rest) {
24
- // Decode the name and value, and join value parts in case it contains '='
25
- const decodedName = decodeURIComponent(name.trim());
26
- const decodedValue = decodeURIComponent(rest.join('=').trim());
27
- cookies[decodedName] = decodedValue;
28
- }
29
- });
30
-
31
- return cookies;
32
  }
33
 
34
  async function llmCallAction({ context, request }: ActionFunctionArgs) {
@@ -58,12 +48,8 @@ async function llmCallAction({ context, request }: ActionFunctionArgs) {
58
  }
59
 
60
  const cookieHeader = request.headers.get('Cookie');
61
-
62
- // Parse the cookie's value (returns an object or null if no cookie exists)
63
- const apiKeys = JSON.parse(parseCookies(cookieHeader || '').apiKeys || '{}');
64
- const providerSettings: Record<string, IProviderSetting> = JSON.parse(
65
- parseCookies(cookieHeader || '').providers || '{}',
66
- );
67
 
68
  if (streamOutput) {
69
  try {
@@ -105,8 +91,8 @@ async function llmCallAction({ context, request }: ActionFunctionArgs) {
105
  }
106
  } else {
107
  try {
108
- const MODEL_LIST = await getModelList({ apiKeys, providerSettings, serverEnv: context.cloudflare.env as any });
109
- const modelDetails = MODEL_LIST.find((m) => m.name === model);
110
 
111
  if (!modelDetails) {
112
  throw new Error('Model not found');
 
1
  import { type ActionFunctionArgs } from '@remix-run/cloudflare';
 
 
2
  import { streamText } from '~/lib/.server/llm/stream-text';
3
  import type { IProviderSetting, ProviderInfo } from '~/types/model';
4
  import { generateText } from 'ai';
5
+ import { PROVIDER_LIST } from '~/utils/constants';
6
  import { MAX_TOKENS } from '~/lib/.server/llm/constants';
7
+ import { LLMManager } from '~/lib/modules/llm/manager';
8
+ import type { ModelInfo } from '~/lib/modules/llm/types';
9
+ import { getApiKeysFromCookie, getProviderSettingsFromCookie } from '~/lib/api/cookies';
10
 
11
  export async function action(args: ActionFunctionArgs) {
12
  return llmCallAction(args);
13
  }
14
 
15
+ async function getModelList(options: {
16
+ apiKeys?: Record<string, string>;
17
+ providerSettings?: Record<string, IProviderSetting>;
18
+ serverEnv?: Record<string, string>;
19
+ }) {
20
+ const llmManager = LLMManager.getInstance(import.meta.env);
21
+ return llmManager.updateModelList(options);
 
 
 
 
 
 
 
 
 
 
 
22
  }
23
 
24
  async function llmCallAction({ context, request }: ActionFunctionArgs) {
 
48
  }
49
 
50
  const cookieHeader = request.headers.get('Cookie');
51
+ const apiKeys = getApiKeysFromCookie(cookieHeader);
52
+ const providerSettings = getProviderSettingsFromCookie(cookieHeader);
 
 
 
 
53
 
54
  if (streamOutput) {
55
  try {
 
91
  }
92
  } else {
93
  try {
94
+ const models = await getModelList({ apiKeys, providerSettings, serverEnv: context.cloudflare.env as any });
95
+ const modelDetails = models.find((m: ModelInfo) => m.name === model);
96
 
97
  if (!modelDetails) {
98
  throw new Error('Model not found');
app/routes/api.models.$provider.ts ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ import { loader } from './api.models';
2
+ export { loader };
app/routes/api.models.ts CHANGED
@@ -1,6 +1,84 @@
1
  import { json } from '@remix-run/cloudflare';
2
- import { MODEL_LIST } from '~/utils/constants';
 
 
 
3
 
4
- export async function loader() {
5
- return json(MODEL_LIST);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  }
 
1
  import { json } from '@remix-run/cloudflare';
2
+ import { LLMManager } from '~/lib/modules/llm/manager';
3
+ import type { ModelInfo } from '~/lib/modules/llm/types';
4
+ import type { ProviderInfo } from '~/types/model';
5
+ import { getApiKeysFromCookie, getProviderSettingsFromCookie } from '~/lib/api/cookies';
6
 
7
+ interface ModelsResponse {
8
+ modelList: ModelInfo[];
9
+ providers: ProviderInfo[];
10
+ defaultProvider: ProviderInfo;
11
+ }
12
+
13
+ let cachedProviders: ProviderInfo[] | null = null;
14
+ let cachedDefaultProvider: ProviderInfo | null = null;
15
+
16
+ function getProviderInfo(llmManager: LLMManager) {
17
+ if (!cachedProviders) {
18
+ cachedProviders = llmManager.getAllProviders().map((provider) => ({
19
+ name: provider.name,
20
+ staticModels: provider.staticModels,
21
+ getApiKeyLink: provider.getApiKeyLink,
22
+ labelForGetApiKey: provider.labelForGetApiKey,
23
+ icon: provider.icon,
24
+ }));
25
+ }
26
+
27
+ if (!cachedDefaultProvider) {
28
+ const defaultProvider = llmManager.getDefaultProvider();
29
+ cachedDefaultProvider = {
30
+ name: defaultProvider.name,
31
+ staticModels: defaultProvider.staticModels,
32
+ getApiKeyLink: defaultProvider.getApiKeyLink,
33
+ labelForGetApiKey: defaultProvider.labelForGetApiKey,
34
+ icon: defaultProvider.icon,
35
+ };
36
+ }
37
+
38
+ return { providers: cachedProviders, defaultProvider: cachedDefaultProvider };
39
+ }
40
+
41
+ export async function loader({
42
+ request,
43
+ params,
44
+ }: {
45
+ request: Request;
46
+ params: { provider?: string };
47
+ }): Promise<Response> {
48
+ const llmManager = LLMManager.getInstance(import.meta.env);
49
+
50
+ // Get client side maintained API keys and provider settings from cookies
51
+ const cookieHeader = request.headers.get('Cookie');
52
+ const apiKeys = getApiKeysFromCookie(cookieHeader);
53
+ const providerSettings = getProviderSettingsFromCookie(cookieHeader);
54
+
55
+ const { providers, defaultProvider } = getProviderInfo(llmManager);
56
+
57
+ let modelList: ModelInfo[] = [];
58
+
59
+ if (params.provider) {
60
+ // Only update models for the specific provider
61
+ const provider = llmManager.getProvider(params.provider);
62
+
63
+ if (provider) {
64
+ const staticModels = provider.staticModels;
65
+ const dynamicModels = provider.getDynamicModels
66
+ ? await provider.getDynamicModels(apiKeys, providerSettings, import.meta.env)
67
+ : [];
68
+ modelList = [...staticModels, ...dynamicModels];
69
+ }
70
+ } else {
71
+ // Update all models
72
+ modelList = await llmManager.updateModelList({
73
+ apiKeys,
74
+ providerSettings,
75
+ serverEnv: import.meta.env,
76
+ });
77
+ }
78
+
79
+ return json<ModelsResponse>({
80
+ modelList,
81
+ providers,
82
+ defaultProvider,
83
+ });
84
  }
app/utils/constants.ts CHANGED
@@ -1,7 +1,4 @@
1
- import type { IProviderSetting } from '~/types/model';
2
-
3
  import { LLMManager } from '~/lib/modules/llm/manager';
4
- import type { ModelInfo } from '~/lib/modules/llm/types';
5
  import type { Template } from '~/types/template';
6
 
7
  export const WORK_DIR_NAME = 'project';
@@ -17,9 +14,7 @@ const llmManager = LLMManager.getInstance(import.meta.env);
17
  export const PROVIDER_LIST = llmManager.getAllProviders();
18
  export const DEFAULT_PROVIDER = llmManager.getDefaultProvider();
19
 
20
- let MODEL_LIST = llmManager.getModelList();
21
-
22
- const providerBaseUrlEnvKeys: Record<string, { baseUrlKey?: string; apiTokenKey?: string }> = {};
23
  PROVIDER_LIST.forEach((provider) => {
24
  providerBaseUrlEnvKeys[provider.name] = {
25
  baseUrlKey: provider.config.baseUrlKey,
@@ -27,34 +22,6 @@ PROVIDER_LIST.forEach((provider) => {
27
  };
28
  });
29
 
30
- // Export the getModelList function using the manager
31
- export async function getModelList(options: {
32
- apiKeys?: Record<string, string>;
33
- providerSettings?: Record<string, IProviderSetting>;
34
- serverEnv?: Record<string, string>;
35
- }) {
36
- return await llmManager.updateModelList(options);
37
- }
38
-
39
- async function initializeModelList(options: {
40
- env?: Record<string, string>;
41
- providerSettings?: Record<string, IProviderSetting>;
42
- apiKeys?: Record<string, string>;
43
- }): Promise<ModelInfo[]> {
44
- const { providerSettings, apiKeys, env } = options;
45
- const list = await getModelList({
46
- apiKeys,
47
- providerSettings,
48
- serverEnv: env,
49
- });
50
- MODEL_LIST = list || MODEL_LIST;
51
-
52
- return list;
53
- }
54
-
55
- // initializeModelList({})
56
- export { initializeModelList, providerBaseUrlEnvKeys, MODEL_LIST };
57
-
58
  // starter Templates
59
 
60
  export const STARTER_TEMPLATES: Template[] = [
 
 
 
1
  import { LLMManager } from '~/lib/modules/llm/manager';
 
2
  import type { Template } from '~/types/template';
3
 
4
  export const WORK_DIR_NAME = 'project';
 
14
  export const PROVIDER_LIST = llmManager.getAllProviders();
15
  export const DEFAULT_PROVIDER = llmManager.getDefaultProvider();
16
 
17
+ export const providerBaseUrlEnvKeys: Record<string, { baseUrlKey?: string; apiTokenKey?: string }> = {};
 
 
18
  PROVIDER_LIST.forEach((provider) => {
19
  providerBaseUrlEnvKeys[provider.name] = {
20
  baseUrlKey: provider.config.baseUrlKey,
 
22
  };
23
  });
24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  // starter Templates
26
 
27
  export const STARTER_TEMPLATES: Template[] = [