This commit is contained in:
Andrew Pareles 2025-02-23 16:58:43 -08:00
parent 2c2714273e
commit fd5e523434
5 changed files with 73 additions and 573 deletions

View file

@ -113,7 +113,7 @@
"files.insertFinalNewline": false
},
"[typescript]": {
"editor.defaultFormatter": "ms-vsliveshare.vsliveshare",
"editor.defaultFormatter": "vscode.typescript-language-features",
"editor.formatOnSave": true
},
"[javascript]": {

View file

@ -65,7 +65,7 @@ export const toLLMChatMessage = (c: ChatMessage): LLMChatMessage => {
}
type _InternalSendFIMMessage = {
export type LLMFIMMessage = {
prefix: string;
suffix: string;
stopTokens: string[];
@ -77,7 +77,7 @@ type SendLLMType = {
tools?: InternalToolInfo[];
} | {
messagesType: 'FIMMessage';
messages: _InternalSendFIMMessage;
messages: LLMFIMMessage;
tools?: undefined;
}
@ -118,38 +118,6 @@ export type EventLLMMessageOnFinalMessageParams = Parameters<OnFinalMessage>[0]
export type EventLLMMessageOnErrorParams = Parameters<OnError>[0] & { requestId: string }
export type _InternalSendLLMChatMessageFnType = (
params: {
aiInstructions: string;
onText: OnText;
onFinalMessage: OnFinalMessage;
onError: OnError;
providerName: ProviderName;
settingsOfProvider: SettingsOfProvider;
modelName: string;
_setAborter: (aborter: () => void) => void;
tools?: InternalToolInfo[],
messages: LLMChatMessage[];
}
) => void
export type _InternalSendLLMFIMMessageFnType = (
params: {
onText: OnText;
onFinalMessage: OnFinalMessage;
onError: OnError;
providerName: ProviderName;
settingsOfProvider: SettingsOfProvider;
modelName: string;
_setAborter: (aborter: () => void) => void;
messages: _InternalSendFIMMessage;
}
) => void
// service -> main -> internal -> event (back to main)
// (browser)
@ -190,10 +158,10 @@ export type OpenaiCompatibleModelResponse = {
// params to the true list fn
export type ModelListParams<modelResponse> = {
export type ModelListParams<ModelResponse> = {
providerName: ProviderName;
settingsOfProvider: SettingsOfProvider;
onSuccess: (param: { models: modelResponse[] }) => void;
onSuccess: (param: { models: ModelResponse[] }) => void;
onError: (param: { error: string }) => void;
}
@ -212,4 +180,3 @@ export type EventModelListOnErrorParams<modelResponse> = Parameters<ModelListPar
export type _InternalModelListFnType<modelResponse> = (params: ModelListParams<modelResponse>) => void

View file

@ -89,6 +89,13 @@ export const voidTools = {
export type ToolName = keyof typeof voidTools
export const toolNames = Object.keys(voidTools) as ToolName[]
const toolNamesSet = new Set<string>(toolNames)
export const isAToolName = (toolName: string): toolName is ToolName => {
const isAToolName = toolNamesSet.has(toolName)
return isAToolName
}
export type ToolParamNames<T extends ToolName> = keyof typeof voidTools[T]['params']
export type ToolParamsObj<T extends ToolName> = { [paramName in ToolParamNames<T>]: unknown }

View file

@ -5,8 +5,8 @@
import OpenAI from 'openai';
import { Model as OpenAIModel } from 'openai/resources/models.js';
import { _InternalModelListFnType, _InternalSendLLMFIMMessageFnType, _InternalSendLLMChatMessageFnType, OllamaModelResponse } from '../../common/llmMessageTypes.js';
import { InternalToolInfo, ToolName, toolNames } from '../../common/toolsService.js';
import { OllamaModelResponse, OnText, OnFinalMessage, OnError, LLMChatMessage, LLMFIMMessage, ModelListParams } from '../../common/llmMessageTypes.js';
import { InternalToolInfo, isAToolName } from '../../common/toolsService.js';
import { defaultProviderSettings, ProviderName, SettingsOfProvider } from '../../common/voidSettingsTypes.js';
import { prepareMessages } from './preprocessLLMMessages.js';
import Anthropic from '@anthropic-ai/sdk';
@ -80,12 +80,13 @@ type ProviderSettings = {
output: number;
cache_read?: number;
cache_write?: number;
};
}
supportsSystemMessage: false | 'system-role' | 'developer-role' | 'separated';
supportsTools: false | 'anthropic-style' | 'openai-style';
};
};
};
supportsFIM: false | 'TODO_FIM_FORMAT'
}
}
}
const openAIProviderSettings: ProviderSettings = {
@ -97,21 +98,24 @@ const openAIProviderSettings: ProviderSettings = {
FIMFormat: '',
modelOptions: {
"o1": {
'o1': {
contextWindow: 128_000,
cost: { input: 15.00, cache_read: 7.50, output: 60.00, },
supportsFIM: false,
supportsTools: false,
supportsSystemMessage: 'developer-role',
},
"o3-mini": {
'o3-mini': {
contextWindow: 200_000,
cost: { input: 1.10, cache_read: 0.55, output: 4.40, },
supportsFIM: false,
supportsTools: false,
supportsSystemMessage: 'developer-role',
},
"gpt-4o": {
'gpt-4o': {
contextWindow: 128_000,
cost: { input: 2.50, cache_read: 1.25, output: 10.00, },
supportsFIM: false,
supportsTools: 'openai-style',
supportsSystemMessage: 'system-role',
},
@ -134,6 +138,7 @@ const anthropicProviderSettings: ProviderSettings = {
"claude-3-5-sonnet-20241022": {
contextWindow: 200_000,
cost: { input: 3.00, cache_read: 0.30, cache_write: 3.75, output: 15.00 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'anthropic-style',
@ -141,17 +146,20 @@ const anthropicProviderSettings: ProviderSettings = {
"claude-3-5-haiku-20241022": {
contextWindow: 200_000,
cost: { input: 0.80, cache_read: 0.08, cache_write: 1.00, output: 4.00 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'anthropic-style',
},
"claude-3-opus-20240229": {
contextWindow: 200_000,
cost: { input: 15.00, cache_read: 1.50, cache_write: 18.75, output: 75.00 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'anthropic-style',
},
"claude-3-sonnet-20240229": {
contextWindow: 200_000, cost: { input: 3.00, output: 15.00 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'anthropic-style',
}
@ -168,30 +176,13 @@ const grokProviderSettings: ProviderSettings = {
FIMFormat: '',
modelOptions: {
"claude-3-5-sonnet-20241022": {
contextWindow: 200_000,
cost: { input: 3.00, cache_read: 0.30, cache_write: 3.75, output: 15.00 },
"grok-2-latest": {
contextWindow: 131_072,
cost: { input: 2.00, output: 10.00 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'anthropic-style',
supportsTools: 'openai-style',
},
"claude-3-5-haiku-20241022": {
contextWindow: 200_000,
cost: { input: 0.80, cache_read: 0.08, cache_write: 1.00, output: 4.00 },
supportsSystemMessage: 'system-role',
supportsTools: 'anthropic-style',
},
"claude-3-opus-20240229": {
contextWindow: 200_000,
cost: { input: 15.00, cache_read: 1.50, cache_write: 18.75, output: 75.00 },
supportsSystemMessage: 'system-role',
supportsTools: 'anthropic-style',
},
"claude-3-sonnet-20240229": {
contextWindow: 200_000, cost: { input: 3.00, output: 15.00 },
supportsSystemMessage: 'system-role',
supportsTools: 'anthropic-style',
}
}
}
@ -199,14 +190,22 @@ const grokProviderSettings: ProviderSettings = {
// helpers
const toolNamesSet = new Set<string>(toolNames)
const isAToolName = (toolName: string): toolName is ToolName => {
const isAToolName = toolNamesSet.has(toolName)
return isAToolName
type InternalCommonMessageParams = {
aiInstructions: string;
onText: OnText;
onFinalMessage: OnFinalMessage;
onError: OnError;
providerName: ProviderName;
settingsOfProvider: SettingsOfProvider;
modelName: string;
_setAborter: (aborter: () => void) => void;
}
type SendChatParams_Internal = InternalCommonMessageParams & { messages: LLMChatMessage[]; tools?: InternalToolInfo[] }
type SendFIMParams_Internal = InternalCommonMessageParams & { messages: LLMFIMMessage; }
export type ListParams_Internal<ModelResponse> = ModelListParams<ModelResponse>
// ------------ OPENAI-COMPATIBLE (HELPERS) ------------
const toOpenAICompatibleTool = (toolInfo: InternalToolInfo) => {
@ -251,7 +250,7 @@ const newOpenAICompatibleSDK = ({ settingsOfProvider, providerName }: { settings
else throw new Error(`Invalid providerName ${providerName}`)
}
export const _sendOpenAICompatibleChat: _InternalSendLLMChatMessageFnType = ({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, aiInstructions, tools: tools_ }) => {
export const _sendOpenAICompatibleChat = ({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, aiInstructions, tools: tools_ }: SendChatParams_Internal) => {
const { messages } = prepareMessages({ messages: messages_, aiInstructions, supportsSystemMessage: '', supportsTools: '', })
const tools = (supportsTools && ((tools_?.length ?? 0) !== 0)) ? tools_?.map(tool => toOpenAICompatibleTool(tool)) : undefined
@ -291,7 +290,7 @@ export const _sendOpenAICompatibleChat: _InternalSendLLMChatMessageFnType = ({ m
}
export const _openaiCompatibleList: _InternalModelListFnType<OpenAIModel> = async ({ onSuccess: onSuccess_, onError: onError_, settingsOfProvider, providerName }) => {
export const _openaiCompatibleList = async ({ onSuccess: onSuccess_, onError: onError_, settingsOfProvider, providerName }: ListParams_Internal<OpenAIModel>) => {
const onSuccess = ({ models }: { models: OpenAIModel[] }) => {
onSuccess_({ models })
}
@ -320,7 +319,7 @@ export const _openaiCompatibleList: _InternalModelListFnType<OpenAIModel> = asyn
// ------------ OPENAI ------------
export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = (params) => {
export const sendOpenAIChat = (params: SendChatParams_Internal) => {
return _sendOpenAICompatibleChat(params)
}
@ -346,7 +345,7 @@ const toolCallsFromAnthropicContent = (content: Anthropic.Messages.ContentBlock[
}).filter(t => !!t)
}
export const sendAnthropicChat: _InternalSendLLMChatMessageFnType = ({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, aiInstructions, tools: tools_ }) => {
export const sendAnthropicChat = ({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, aiInstructions, tools: tools_ }: SendChatParams_Internal) => {
const { messages, separateSystemMessageStr } = prepareMessages({ messages: messages_, aiInstructions, supportsSystemMessage: 'separated', supportsTools: 'anthropic-style', })
const thisConfig = settingsOfProvider.anthropic
@ -405,7 +404,7 @@ const newOllamaSDK = ({ endpoint }: { endpoint: string }) => {
return ollama
}
export const ollamaList: _InternalModelListFnType<OllamaModelResponse> = async ({ onSuccess: onSuccess_, onError: onError_, settingsOfProvider }) => {
export const ollamaList = async ({ onSuccess: onSuccess_, onError: onError_, settingsOfProvider }: ListParams_Internal<OllamaModelResponse>) => {
const onSuccess = ({ models }: { models: OllamaModelResponse[] }) => {
onSuccess_({ models })
}
@ -429,7 +428,7 @@ export const ollamaList: _InternalModelListFnType<OllamaModelResponse> = async (
}
}
export const sendOllamaFIM: _InternalSendLLMFIMMessageFnType = ({ messages, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }) => {
export const sendOllamaFIM = ({ messages, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }: SendFIMParams_Internal) => {
const thisConfig = settingsOfProvider.ollama
const ollama = newOllamaSDK({ endpoint: thisConfig.endpoint })
@ -462,7 +461,7 @@ export const sendOllamaFIM: _InternalSendLLMFIMMessageFnType = ({ messages, onFi
// ollama's implementation of openai-compatible SDK dumps all reasoning tokens out with message, and supports tools, so we can use it for chat!
export const sendOllamaMessage: _InternalSendLLMChatMessageFnType = (params) => {
export const sendOllamaChat = (params: SendChatParams_Internal) => {
return _sendOpenAICompatibleChat(params)
// TODO!!! filter out reasoning <think> tags...
}
@ -470,24 +469,24 @@ export const sendOllamaMessage: _InternalSendLLMChatMessageFnType = (params) =>
// ------------ OPENROUTER ------------
export const sendOpenRouterFIM: _InternalSendLLMFIMMessageFnType = ({ messages, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }) => {
export const sendOpenRouterFIM = ({ messages, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }: SendFIMParams_Internal) => {
// TODO!!!
}
export const sendOpenRouterChat: _InternalSendLLMChatMessageFnType = ({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, aiInstructions, tools: tools_ }) => {
// payload should have {include_reasoning: true} https://openrouter.ai/announcements/reasoning-tokens-for-thinking-models
// response.choices[0].delta.reasoning
export const sendOpenRouterChat = ({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, aiInstructions, tools: tools_ }: SendChatParams_Internal) => {
// reasoning: response.choices[0].delta.reasoning : payload should have {include_reasoning: true} https://openrouter.ai/announcements/reasoning-tokens-for-thinking-models
//
}
// ------------ OPENAI-COMPATIBLE ------------
export const openAICompatibleList: _InternalModelListFnType<OpenAIModel> = async (params) => {
export const openAICompatibleList = async (params: ListParams_Internal<OpenAIModel>) => {
return _openaiCompatibleList(params)
}
// TODO!!! FIM
// using openai's SDK is not ideal (your implementation might not do tools, reasoning, FIM etc correctly), talk to us for a custom integration
export const sendOpenAICompatibleChat: _InternalSendLLMChatMessageFnType = (params) => {
export const sendOpenAICompatibleChat = (params: SendChatParams_Internal) => {
return _sendOpenAICompatibleChat(params)
}
@ -496,13 +495,23 @@ export const sendOpenAICompatibleChat: _InternalSendLLMChatMessageFnType = (para
// TODO!!! FIM
// using openai's SDK is not ideal (your implementation might not do tools, reasoning, FIM etc correctly), talk to us for a custom integration
export const sendVLLMChat: _InternalSendLLMChatMessageFnType = (params) => {
export const sendVLLMChat = (params: SendChatParams_Internal) => {
return _sendOpenAICompatibleChat(params)
// response.choices[0].delta.reasoning_content // https://docs.vllm.ai/en/stable/features/reasoning_outputs.html#streaming-chat-completions
// reasoning: response.choices[0].delta.reasoning_content // https://docs.vllm.ai/en/stable/features/reasoning_outputs.html#streaming-chat-completions
}
// ------------ DEEPSEEK API ------------
export const sendDeepSeekAPIChat = (params: SendChatParams_Internal) => {
return _sendOpenAICompatibleChat(params)
// reasoning: response.choices[0].delta.reasoning_content // https://api-docs.deepseek.com/guides/reasoning_model
}
// ------------ GEMINI ------------
// ------------ MISTRAL ------------
// ------------ GROQ ------------
// ------------ GROK ------------

View file

@ -1,483 +0,0 @@
// /*--------------------------------------------------------------------------------------
// * Copyright 2025 Glass Devtools, Inc. All rights reserved.
// * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
// *--------------------------------------------------------------------------------------*/
// import Groq from 'groq-sdk';
// import { _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js';
// // Groq
// export const sendGroqChat: _InternalSendLLMChatMessageFnType = async ({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }) => {
// let fullText = '';
// const thisConfig = settingsOfProvider.groq
// const groq = new Groq({
// apiKey: thisConfig.apiKey,
// dangerouslyAllowBrowser: true
// });
// await groq.chat.completions
// .create({
// messages: messages,
// model: modelName,
// stream: true,
// })
// .then(async response => {
// _setAborter(() => response.controller.abort())
// // when receive text
// for await (const chunk of response) {
// const newText = chunk.choices[0]?.delta?.content || '';
// fullText += newText;
// onText({ newText, fullText });
// }
// onFinalMessage({ fullText, tools: [] });
// })
// .catch(error => {
// onError({ message: error + '', fullError: error });
// })
// };
// /*--------------------------------------------------------------------------------------
// * Copyright 2025 Glass Devtools, Inc. All rights reserved.
// * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
// *--------------------------------------------------------------------------------------*/
// import { Mistral } from '@mistralai/mistralai';
// import { _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js';
// // Mistral
// export const sendMistralChat: _InternalSendLLMChatMessageFnType = async ({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }) => {
// let fullText = '';
// const thisConfig = settingsOfProvider.mistral;
// const mistral = new Mistral({
// apiKey: thisConfig.apiKey,
// })
// await mistral.chat
// .stream({
// messages: messages,
// model: modelName,
// stream: true,
// })
// .then(async response => {
// // Mistral has a really nonstandard API - no interrupt and weird stream types
// _setAborter(() => { console.log('Mistral does not support interrupts! Further messages will just be ignored.') });
// // when receive text
// for await (const chunk of response) {
// const c = chunk.data.choices[0].delta.content || ''
// const newText = (
// typeof c === 'string' ? c
// : c?.map(c => c.type === 'text' ? c.text : c.type).join('\n')
// )
// fullText += newText;
// onText({ newText, fullText });
// }
// onFinalMessage({ fullText, tools: [] });
// })
// .catch(error => {
// onError({ message: error + '', fullError: error });
// })
// }
// export const recognizedModels = [
// // chat
// 'OpenAI 4o',
// 'Anthropic Claude',
// 'Llama 3.x',
// 'Deepseek Chat', // deepseek coder v2 is now merged into chat (V3) https://api-docs.deepseek.com/updates#deepseek-coder--deepseek-chat-upgraded-to-deepseek-v25-model
// 'xAI Grok',
// // 'xAI Grok',
// // 'Google Gemini, Gemma',
// // 'Microsoft Phi4',
// // coding (autocomplete)
// 'Alibaba Qwen2.5 Coder Instruct', // we recommend this over Qwen2.5
// 'Mistral Codestral',
// // thinking
// 'OpenAI o1',
// 'Deepseek R1',
// // general
// // 'Mixtral 8x7b'
// // 'Qwen2.5',
// ] as const
// type RecognizedModelName = (typeof recognizedModels)[number] | '<GENERAL>'
// export function recognizedModelOfModelName(modelName: string): RecognizedModelName {
// const lower = modelName.toLowerCase();
// if (lower.includes('gpt-4o'))
// return 'OpenAI 4o';
// if (lower.includes('claude'))
// return 'Anthropic Claude';
// if (lower.includes('llama'))
// return 'Llama 3.x';
// if (lower.includes('qwen2.5-coder'))
// return 'Alibaba Qwen2.5 Coder Instruct';
// if (lower.includes('mistral'))
// return 'Mistral Codestral';
// if (/\bo1\b/.test(lower) || /\bo3\b/.test(lower)) // o1, o3
// return 'OpenAI o1';
// if (lower.includes('deepseek-r1') || lower.includes('deepseek-reasoner'))
// return 'Deepseek R1';
// if (lower.includes('deepseek'))
// return 'Deepseek Chat'
// if (lower.includes('grok'))
// return 'xAI Grok'
// return '<GENERAL>';
// }
// const developerInfoAtProvider: { [providerName in ProviderName]: DeveloperInfoAtProvider } = {
// 'anthropic': {
// overrideSettingsForAllModels: {
// supportsSystemMessage: true,
// supportsTools: true,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: true,
// }
// },
// 'deepseek': {
// overrideSettingsForAllModels: {
// }
// },
// 'ollama': {
// },
// 'openRouter': {
// },
// 'openAICompatible': {
// },
// 'openAI': {
// },
// 'gemini': {
// },
// 'mistral': {
// },
// 'groq': {
// },
// 'xAI': {
// },
// 'vLLM': {
// },
// }
// export const developerInfoOfProviderName = (providerName: ProviderName): Partial<DeveloperInfoAtProvider> => {
// return developerInfoAtProvider[providerName] ?? {}
// }
// // providerName is optional, but gives some extra fallbacks if provided
// const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelName]: Omit<DeveloperInfoAtModel, '_recognizedModelName'> } = {
// 'OpenAI 4o': {
// supportsSystemMessage: true,
// supportsTools: true,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: true,
// _maxTokens: 4096,
// },
// 'Anthropic Claude': {
// supportsSystemMessage: true,
// supportsTools: false,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: false,
// _maxTokens: 4096,
// },
// 'Llama 3.x': {
// supportsSystemMessage: true,
// supportsTools: true,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: false,
// _maxTokens: 4096,
// },
// 'xAI Grok': {
// supportsSystemMessage: true,
// supportsTools: true,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: true,
// _maxTokens: 4096,
// },
// 'Deepseek Chat': {
// supportsSystemMessage: true,
// supportsTools: false,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: false,
// _maxTokens: 4096,
// },
// 'Alibaba Qwen2.5 Coder Instruct': {
// supportsSystemMessage: true,
// supportsTools: true,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: false,
// _maxTokens: 4096,
// },
// 'Mistral Codestral': {
// supportsSystemMessage: true,
// supportsTools: true,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: false,
// _maxTokens: 4096,
// },
// 'OpenAI o1': {
// supportsSystemMessage: 'developer',
// supportsTools: false,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: true,
// _maxTokens: 4096,
// },
// 'Deepseek R1': {
// supportsSystemMessage: false,
// supportsTools: false,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: false,
// _maxTokens: 4096,
// },
// '<GENERAL>': {
// supportsSystemMessage: false,
// supportsTools: false,
// _supportsAutocompleteFIM: false,
// _supportsStreaming: false,
// _maxTokens: 4096,
// },
// }
// export const developerInfoOfModelName = (modelName: string, overrides?: Partial<DeveloperInfoAtModel>): DeveloperInfoAtModel => {
// const recognizedModelName = recognizedModelOfModelName(modelName)
// return {
// _recognizedModelName: recognizedModelName,
// ...developerInfoOfRecognizedModelName[recognizedModelName],
// ...overrides
// }
// }
// // creates `modelInfo` from `modelNames`
// export const modelInfoOfAutodetectedModelNames = (defaultModelNames: string[], options: { existingModels: VoidModelInfo[] }) => {
// const { existingModels } = options
// const existingModelsMap: Record<string, VoidModelInfo> = {}
// for (const existingModel of existingModels) {
// existingModelsMap[existingModel.modelName] = existingModel
// }
// return defaultModelNames.map((modelName, i) => ({
// modelName,
// isDefault: true,
// isAutodetected: true,
// isHidden: !!existingModelsMap[modelName]?.isHidden,
// ...developerInfoOfModelName(modelName)
// }))
// }
// export const anthropicMaxPossibleTokens = (modelName: string) => {
// if (modelName === 'claude-3-5-sonnet-20241022'
// || modelName === 'claude-3-5-haiku-20241022')
// return 8192
// if (modelName === 'claude-3-opus-20240229'
// || modelName === 'claude-3-sonnet-20240229'
// || modelName === 'claude-3-haiku-20240307')
// return 4096
// return 1024 // return a reasonably small number if they're using a different model
// }
// // Ollama chat
// export const sendOllamaChat: _InternalSendLLMChatMessageFnType = ({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }) => {
// const thisConfig = settingsOfProvider.ollama
// // if endpoint is empty, normally ollama will send to 11434, but we want it to fail - the user should type it in
// if (!thisConfig.endpoint) throw new Error(`Ollama Endpoint was empty (please enter ${defaultProviderSettings.ollama.endpoint} if you want the default).`)
// let fullText = ''
// const ollama = new Ollama({ host: thisConfig.endpoint })
// ollama.chat({
// model: modelName,
// messages: messages,
// stream: true,
// // options: { num_predict: parseMaxTokensStr(thisConfig.maxTokens) } // this is max_tokens
// })
// .then(async stream => {
// _setAborter(() => stream.abort())
// // iterate through the stream
// for await (const chunk of stream) {
// const newText = chunk.message.content;
// // chunk.message.tool_calls[0].function.arguments
// fullText += newText;
// onText({ newText, fullText });
// }
// onFinalMessage({ fullText, tools: [] });
// })
// // when error/fail
// .catch((error) => {
// onError({ message: error + '', fullError: error })
// })
// };
// type NewParams = Pick<Parameters<_InternalSendLLMChatMessageFnType>[0] & Parameters<_InternalSendLLMFIMMessageFnType>[0], 'settingsOfProvider' | 'providerName'>
// const newOpenAI = ({ settingsOfProvider, providerName }: NewParams) => {
// if (providerName === 'openAI') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true
// })
// }
// else if (providerName === 'ollama') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// baseURL: `${thisConfig.endpoint}/v1`, apiKey: 'noop', dangerouslyAllowBrowser: true,
// })
// }
// else if (providerName === 'vLLM') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// baseURL: `${thisConfig.endpoint}/v1`, apiKey: 'noop', dangerouslyAllowBrowser: true,
// })
// }
// else if (providerName === 'openRouter') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// baseURL: 'https://openrouter.ai/api/v1', apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true,
// defaultHeaders: {
// 'HTTP-Referer': 'https://voideditor.com', // Optional, for including your app on openrouter.ai rankings.
// 'X-Title': 'Void Editor', // Optional. Shows in rankings on openrouter.ai.
// },
// })
// }
// else if (providerName === 'gemini') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// baseURL: 'https://generativelanguage.googleapis.com/v1beta/openai', apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true,
// })
// }
// else if (providerName === 'deepseek') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// baseURL: 'https://api.deepseek.com/v1', apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true,
// })
// }
// else if (providerName === 'openAICompatible') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// baseURL: thisConfig.endpoint, apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true,
// })
// }
// else if (providerName === 'mistral') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// baseURL: 'https://api.mistral.ai/v1', apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true,
// })
// }
// else if (providerName === 'groq') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// baseURL: 'https://api.groq.com/openai/v1', apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true,
// })
// }
// else if (providerName === 'xAI') {
// const thisConfig = settingsOfProvider[providerName]
// return new OpenAI({
// baseURL: 'https://api.x.ai/v1', apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true,
// })
// }
// else {
// console.error(`sendOpenAICompatibleMsg: invalid providerName: ${providerName}`)
// throw new Error(`Void providerName was invalid: ${providerName}`)
// }
// }