mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
add xAI and update system/tool information and system prompt
This commit is contained in:
parent
8a8ed1ac56
commit
366dbf0b52
8 changed files with 123 additions and 77 deletions
|
|
@ -16,6 +16,7 @@ import { IModelService } from '../../../../editor/common/services/model.js';
|
|||
import { chat_userMessage, chat_systemMessage } from './prompt/prompts.js';
|
||||
import { InternalToolInfo, IToolsService, ToolFns, ToolName, voidTools } from '../common/toolsService.js';
|
||||
import { toLLMChatMessage } from '../common/llmMessageTypes.js';
|
||||
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
|
||||
|
||||
// one of the square items that indicates a selection in a chat bubble (NOT a file, a Selection of text)
|
||||
export type CodeSelection = {
|
||||
|
|
@ -161,6 +162,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
@IModelService private readonly _modelService: IModelService,
|
||||
@ILLMMessageService private readonly _llmMessageService: ILLMMessageService,
|
||||
@IToolsService private readonly _toolsService: IToolsService,
|
||||
@IWorkspaceContextService private readonly _workspaceContextService: IWorkspaceContextService,
|
||||
) {
|
||||
super()
|
||||
|
||||
|
|
@ -312,7 +314,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
useProviderFor: 'Ctrl+L',
|
||||
logging: { loggingName: `Agent` },
|
||||
messages: [
|
||||
{ role: 'system', content: chat_systemMessage },
|
||||
{ role: 'system', content: chat_systemMessage(this._workspaceContextService.getWorkspace().folders.map(f => f.uri.fsPath)) },
|
||||
...this.getCurrentThread().messages.map(m => (toLLMChatMessage(m))),
|
||||
],
|
||||
|
||||
|
|
|
|||
|
|
@ -15,13 +15,14 @@ import { os } from '../helpers/systemInfo.js';
|
|||
// this is just for ease of readability
|
||||
export const tripleTick = ['```', '```']
|
||||
|
||||
export const chat_systemMessage = `\
|
||||
export const chat_systemMessage = (workspaces: string[]) => `\
|
||||
You are a coding assistant. You are given a list of instructions to follow \`INSTRUCTIONS\`, and optionally a list of relevant files \`FILES\`, and selections inside of files \`SELECTIONS\`.
|
||||
|
||||
Please respond to the user's query.
|
||||
|
||||
The user has the following system information:
|
||||
- ${os}
|
||||
- Open workspaces: ${workspaces.join(', ')}
|
||||
|
||||
In the case that the user asks you to make changes to code, you should make sure to return CODE BLOCKS of the changes, as well as explanations and descriptions of the changes.
|
||||
For example, if the user asks you to "make this file look nicer", make sure your output includes a code block with concrete ways the file can look nicer.
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ export const CodeSpan = ({ children, className }: { children: React.ReactNode, c
|
|||
</code>
|
||||
}
|
||||
|
||||
const RenderToken = ({ token, nested = false, noSpace = false, chatMessageLocation: chatLocation, tokenIdx }: { token: Token | string, nested?: boolean, noSpace?: boolean, chatMessageLocation?: ChatMessageLocation, tokenIdx: string }): JSX.Element => {
|
||||
const RenderToken = ({ token, nested = false, noSpace = false, chatMessageLocation, tokenIdx }: { token: Token | string, nested?: boolean, noSpace?: boolean, chatMessageLocation?: ChatMessageLocation, tokenIdx: string }): JSX.Element => {
|
||||
|
||||
|
||||
// deal with built-in tokens first (assume marked token)
|
||||
|
|
@ -111,16 +111,17 @@ const RenderToken = ({ token, nested = false, noSpace = false, chatMessageLocati
|
|||
if (t.type === "code") {
|
||||
const isCodeblockClosed = t.raw?.startsWith('```') && t.raw?.endsWith('```');
|
||||
|
||||
const applyBoxId = getApplyBoxId({
|
||||
threadId: chatLocation!.threadId,
|
||||
messageIdx: chatLocation!.messageIdx,
|
||||
// this should never be
|
||||
const applyBoxId = chatMessageLocation ? getApplyBoxId({
|
||||
threadId: chatMessageLocation.threadId,
|
||||
messageIdx: chatMessageLocation.messageIdx,
|
||||
tokenIdx: tokenIdx,
|
||||
})
|
||||
}) : null
|
||||
|
||||
return <BlockCode
|
||||
initValue={t.text}
|
||||
language={t.lang === undefined ? undefined : nameToVscodeLanguage[t.lang]}
|
||||
buttonsOnHover={<ApplyButtonsOnHover applyStr={t.text} applyBoxId={applyBoxId} />}
|
||||
buttonsOnHover={applyBoxId && <ApplyButtonsOnHover applyStr={t.text} applyBoxId={applyBoxId} />}
|
||||
/>
|
||||
}
|
||||
|
||||
|
|
@ -195,7 +196,7 @@ const RenderToken = ({ token, nested = false, noSpace = false, chatMessageLocati
|
|||
<input type="checkbox" checked={item.checked} readOnly className="mr-2 form-checkbox" />
|
||||
)}
|
||||
<span className="ml-1">
|
||||
<ChatMarkdownRender string={item.text} nested={true} />
|
||||
<ChatMarkdownRender chatMessageLocation={chatMessageLocation} string={item.text} nested={true} />
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -175,6 +175,9 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
|
|||
// A HACK BECAUSE WE ADDED MISTRAL (did not exist before, comes before readS)
|
||||
...{ mistral: defaultSettingsOfProvider.mistral },
|
||||
|
||||
// A HACK BECAUSE WE ADDED XAI (did not exist before, comes before readS)
|
||||
...{ mistral: defaultSettingsOfProvider.xAI },
|
||||
|
||||
...readS.settingsOfProvider,
|
||||
|
||||
// A HACK BECAUSE WE ADDED NEW GEMINI MODELS (existed before, comes after readS)
|
||||
|
|
|
|||
|
|
@ -11,17 +11,15 @@ import { VoidSettingsState } from './voidSettingsService.js'
|
|||
// developer info used in sendLLMMessage
|
||||
export type DeveloperInfoAtModel = {
|
||||
// USED:
|
||||
|
||||
// TODO!!! think tokens - deepseek
|
||||
|
||||
// TODO!!!!
|
||||
// UNUSED (coming soon):
|
||||
recognizedModelName: RecognizedModelName, // used to show user if model was auto-recognized
|
||||
supportsSystemMessage: 'developer' | boolean, // if null, we will just do a string of system message. this is independent from separateSystemMessage, which takes priority and is passed directly in each provider's implementation.
|
||||
supportsTools: boolean, // we will just do a string of tool use if it doesn't support
|
||||
supportsSystemMessageRole: 'developer' | 'system' | false, // if null, we will just do a string of system message. this is independent from separateSystemMessage, which takes priority and is passed directly in each provider's implementation.
|
||||
supportsAutocompleteFIM: boolean, // we will just do a description of FIM if it doens't support <|fim_hole|>
|
||||
supportsStreaming: boolean, // (o1 does NOT) we will just dump the final result if doesn't support it
|
||||
maxTokens: number, // required
|
||||
|
||||
// UNUSED (coming soon):
|
||||
// TODO!!! think tokens - deepseek
|
||||
_recognizedModelName: RecognizedModelName, // used to show user if model was auto-recognized
|
||||
_supportsStreaming: boolean, // we will just dump the final result if doesn't support it
|
||||
_supportsAutocompleteFIM: boolean, // we will just do a description of FIM if it doens't support <|fim_hole|>
|
||||
_maxTokens: number, // required
|
||||
}
|
||||
|
||||
export type DeveloperInfoAtProvider = {
|
||||
|
|
@ -49,6 +47,7 @@ export const recognizedModels = [
|
|||
'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',
|
||||
|
|
@ -59,7 +58,7 @@ export const recognizedModels = [
|
|||
'Mistral Codestral',
|
||||
|
||||
// thinking
|
||||
'OpenAI o1, o3',
|
||||
'OpenAI o1',
|
||||
'Deepseek R1',
|
||||
|
||||
// general
|
||||
|
|
@ -85,11 +84,13 @@ export function recognizedModelOfModelName(modelName: string): RecognizedModelNa
|
|||
if (lower.includes('mistral'))
|
||||
return 'Mistral Codestral';
|
||||
if (/\bo1\b/.test(lower) || /\bo3\b/.test(lower)) // o1, o3
|
||||
return 'OpenAI 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>';
|
||||
}
|
||||
|
|
@ -98,18 +99,14 @@ export function recognizedModelOfModelName(modelName: string): RecognizedModelNa
|
|||
const developerInfoAtProvider: { [providerName in ProviderName]: DeveloperInfoAtProvider } = {
|
||||
'anthropic': {
|
||||
overrideSettingsForAllModels: {
|
||||
supportsSystemMessageRole: 'system',
|
||||
supportsSystemMessage: true,
|
||||
supportsTools: true,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: true,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: true,
|
||||
}
|
||||
},
|
||||
'deepseek': {
|
||||
overrideSettingsForAllModels: {
|
||||
supportsSystemMessageRole: false,
|
||||
supportsTools: false,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: true,
|
||||
}
|
||||
},
|
||||
'ollama': {
|
||||
|
|
@ -126,6 +123,8 @@ const developerInfoAtProvider: { [providerName in ProviderName]: DeveloperInfoAt
|
|||
},
|
||||
'groq': {
|
||||
},
|
||||
'xAI': {
|
||||
},
|
||||
}
|
||||
export const developerInfoOfProviderName = (providerName: ProviderName): Partial<DeveloperInfoAtProvider> => {
|
||||
return developerInfoAtProvider[providerName] ?? {}
|
||||
|
|
@ -135,83 +134,93 @@ export const developerInfoOfProviderName = (providerName: ProviderName): Partial
|
|||
|
||||
|
||||
// providerName is optional, but gives some extra fallbacks if provided
|
||||
const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelName]: Omit<DeveloperInfoAtModel, 'recognizedModelName'> } = {
|
||||
const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelName]: Omit<DeveloperInfoAtModel, '_recognizedModelName'> } = {
|
||||
'OpenAI 4o': {
|
||||
supportsSystemMessageRole: 'system',
|
||||
supportsSystemMessage: true,
|
||||
supportsTools: true,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: true,
|
||||
maxTokens: 4096,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: true,
|
||||
_maxTokens: 4096,
|
||||
},
|
||||
|
||||
'Anthropic Claude': {
|
||||
supportsSystemMessageRole: 'system',
|
||||
supportsSystemMessage: true,
|
||||
supportsTools: false,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: false,
|
||||
maxTokens: 4096,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: false,
|
||||
_maxTokens: 4096,
|
||||
},
|
||||
|
||||
'Llama 3.x': {
|
||||
supportsSystemMessageRole: false,
|
||||
supportsTools: false,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: false,
|
||||
maxTokens: 4096,
|
||||
supportsSystemMessage: true,
|
||||
supportsTools: true,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: false,
|
||||
_maxTokens: 4096,
|
||||
},
|
||||
|
||||
'xAI Grok': {
|
||||
supportsSystemMessage: true,
|
||||
supportsTools: true,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: true,
|
||||
_maxTokens: 4096,
|
||||
|
||||
},
|
||||
|
||||
'Deepseek Chat': {
|
||||
supportsSystemMessageRole: false,
|
||||
supportsSystemMessage: true,
|
||||
supportsTools: false,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: false,
|
||||
maxTokens: 4096,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: false,
|
||||
_maxTokens: 4096,
|
||||
},
|
||||
|
||||
'Alibaba Qwen2.5 Coder Instruct': {
|
||||
supportsSystemMessageRole: false,
|
||||
supportsTools: false,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: false,
|
||||
maxTokens: 4096,
|
||||
supportsSystemMessage: true,
|
||||
supportsTools: true,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: false,
|
||||
_maxTokens: 4096,
|
||||
},
|
||||
|
||||
'Mistral Codestral': {
|
||||
supportsSystemMessageRole: false,
|
||||
supportsTools: false,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: false,
|
||||
maxTokens: 4096,
|
||||
supportsSystemMessage: true,
|
||||
supportsTools: true,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: false,
|
||||
_maxTokens: 4096,
|
||||
},
|
||||
|
||||
'OpenAI o1, o3': {
|
||||
supportsSystemMessageRole: false,
|
||||
'OpenAI o1': {
|
||||
supportsSystemMessage: 'developer',
|
||||
supportsTools: false,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: false,
|
||||
maxTokens: 4096,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: true,
|
||||
_maxTokens: 4096,
|
||||
},
|
||||
|
||||
'Deepseek R1': {
|
||||
supportsSystemMessageRole: false,
|
||||
supportsSystemMessage: false,
|
||||
supportsTools: false,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: false,
|
||||
maxTokens: 4096,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: false,
|
||||
_maxTokens: 4096,
|
||||
},
|
||||
|
||||
|
||||
'<GENERAL>': {
|
||||
supportsSystemMessageRole: false,
|
||||
supportsSystemMessage: false,
|
||||
supportsTools: false,
|
||||
supportsAutocompleteFIM: false,
|
||||
supportsStreaming: false,
|
||||
maxTokens: 4096,
|
||||
_supportsAutocompleteFIM: false,
|
||||
_supportsStreaming: false,
|
||||
_maxTokens: 4096,
|
||||
},
|
||||
}
|
||||
export const developerInfoOfModelName = (modelName: string, overrides?: Partial<DeveloperInfoAtModel>): DeveloperInfoAtModel => {
|
||||
const recognizedModelName = recognizedModelOfModelName(modelName)
|
||||
return {
|
||||
recognizedModelName: recognizedModelName,
|
||||
_recognizedModelName: recognizedModelName,
|
||||
...developerInfoOfRecognizedModelName[recognizedModelName],
|
||||
...overrides
|
||||
}
|
||||
|
|
@ -323,6 +332,10 @@ export const defaultMistralModels = modelInfoOfDefaultModelNames([
|
|||
"mistral-small-latest",
|
||||
])
|
||||
|
||||
export const defaultXAIModels = modelInfoOfDefaultModelNames([
|
||||
'grok-2-latest',
|
||||
'grok-3-latest',
|
||||
])
|
||||
// export const parseMaxTokensStr = (maxTokensStr: string) => {
|
||||
// // parse the string but only if the full string is a valid number, eg parseInt('100abc') should return NaN
|
||||
// const int = isNaN(Number(maxTokensStr)) ? undefined : parseInt(maxTokensStr)
|
||||
|
|
@ -378,6 +391,9 @@ export const defaultProviderSettings = {
|
|||
},
|
||||
mistral: {
|
||||
apiKey: ''
|
||||
},
|
||||
xAI: {
|
||||
apiKey: ''
|
||||
}
|
||||
} as const
|
||||
|
||||
|
|
@ -446,7 +462,6 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn
|
|||
else if (providerName === 'ollama') {
|
||||
return {
|
||||
title: 'Ollama',
|
||||
|
||||
}
|
||||
}
|
||||
else if (providerName === 'openAICompatible') {
|
||||
|
|
@ -469,6 +484,12 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn
|
|||
title: 'Mistral API',
|
||||
}
|
||||
}
|
||||
else if (providerName === 'xAI') {
|
||||
return {
|
||||
title: 'xAI API',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throw new Error(`descOfProviderName: Unknown provider name: "${providerName}"`)
|
||||
}
|
||||
|
|
@ -493,7 +514,8 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
|
|||
providerName === 'groq' ? 'gsk_key...' :
|
||||
providerName === 'mistral' ? 'key...' :
|
||||
providerName === 'openAICompatible' ? 'sk-key...' :
|
||||
'',
|
||||
providerName === 'xAI' ? 'xai-key...' :
|
||||
'',
|
||||
|
||||
subTextMd: providerName === 'anthropic' ? 'Get your [API Key here](https://console.anthropic.com/settings/keys).' :
|
||||
providerName === 'openAI' ? 'Get your [API Key here](https://platform.openai.com/api-keys).' :
|
||||
|
|
@ -502,8 +524,9 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
|
|||
providerName === 'gemini' ? 'Get your [API Key here](https://aistudio.google.com/apikey).' :
|
||||
providerName === 'groq' ? 'Get your [API Key here](https://console.groq.com/keys).' :
|
||||
providerName === 'mistral' ? 'Get your [API Key here](https://console.mistral.ai/api-keys/).' :
|
||||
providerName === 'openAICompatible' ? undefined :
|
||||
'',
|
||||
providerName === 'xAI' ? 'Get your [API Key here](https://console.x.ai).' :
|
||||
providerName === 'openAICompatible' ? undefined :
|
||||
'',
|
||||
}
|
||||
}
|
||||
else if (settingName === 'endpoint') {
|
||||
|
|
@ -574,6 +597,9 @@ export const voidInitModelOptions = {
|
|||
},
|
||||
mistral: {
|
||||
models: defaultMistralModels,
|
||||
},
|
||||
xAI: {
|
||||
models: defaultXAIModels,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -610,6 +636,12 @@ export const defaultSettingsOfProvider: SettingsOfProvider = {
|
|||
...voidInitModelOptions.mistral,
|
||||
_didFillInProviderSettings: undefined,
|
||||
},
|
||||
xAI: {
|
||||
...defaultCustomSettings,
|
||||
...defaultProviderSettings.xAI,
|
||||
...voidInitModelOptions.xAI,
|
||||
_didFillInProviderSettings: undefined,
|
||||
},
|
||||
groq: { // aggregator
|
||||
...defaultCustomSettings,
|
||||
...defaultProviderSettings.groq,
|
||||
|
|
|
|||
|
|
@ -91,9 +91,15 @@ const newOpenAI = ({ settingsOfProvider, providerName }: NewParams) => {
|
|||
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(`providerName was invalid: ${providerName}`)
|
||||
throw new Error(`Void providerName was invalid: ${providerName}`)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export const addSystemMessageAndToolSupport = (modelName: string, providerName:
|
|||
const messages = deepClone(messages_).map(m => ({ ...m, content: m.content.trim(), }))
|
||||
|
||||
const { overrideSettingsForAllModels } = developerInfoOfProviderName(providerName)
|
||||
const { supportsSystemMessageRole: supportsSystemMessage, supportsTools } = developerInfoOfModelName(modelName, overrideSettingsForAllModels)
|
||||
const { supportsSystemMessage, supportsTools } = developerInfoOfModelName(modelName, overrideSettingsForAllModels)
|
||||
|
||||
// 1. SYSTEM MESSAGE
|
||||
// find system messages and concatenate them
|
||||
|
|
@ -52,7 +52,7 @@ export const addSystemMessageAndToolSupport = (modelName: string, providerName:
|
|||
if (separateSystemMessage)
|
||||
separateSystemMessageStr = systemMessageStr
|
||||
else {
|
||||
newMessages.unshift({ role: supportsSystemMessage, content: systemMessageStr }) // add new first message
|
||||
newMessages.unshift({ role: supportsSystemMessage === 'developer' ? 'developer' : 'system', content: systemMessageStr }) // add new first message
|
||||
}
|
||||
}
|
||||
// if does not support system message
|
||||
|
|
|
|||
|
|
@ -103,6 +103,7 @@ export const sendLLMMessage = ({
|
|||
case 'ollama':
|
||||
case 'groq':
|
||||
case 'gemini':
|
||||
case 'xAI':
|
||||
if (messagesType === 'FIMMessage') onFinalMessage({ fullText: 'TODO - OpenAI FIM', toolCalls: [] })
|
||||
else /* */ sendOpenAIChat({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, aiInstructions, tools });
|
||||
break;
|
||||
|
|
|
|||
Loading…
Reference in a new issue