From af41d6a43932d9c91cdceb04acb4596e6cda5a38 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Sun, 16 Feb 2025 03:23:37 -0800 Subject: [PATCH] tool improvements --- .../contrib/void/browser/chatThreadService.ts | 12 ++++---- .../contrib/void/common/llmMessageTypes.ts | 2 +- .../contrib/void/common/voidSettingsTypes.ts | 28 +++++++++---------- .../electron-main/llmMessage/anthropic.ts | 9 ++++-- .../void/electron-main/llmMessage/openai.ts | 13 +++++---- .../llmMessage/processMessages.ts | 10 +++---- 6 files changed, 41 insertions(+), 33 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/chatThreadService.ts b/src/vs/workbench/contrib/void/browser/chatThreadService.ts index d3dedf84..4565b6a6 100644 --- a/src/vs/workbench/contrib/void/browser/chatThreadService.ts +++ b/src/vs/workbench/contrib/void/browser/chatThreadService.ts @@ -326,19 +326,21 @@ class ChatThreadService extends Disposable implements IChatThreadService { this._setStreamState(threadId, { messageSoFar: fullText }) }, onFinalMessage: async ({ fullText, tools }) => { - if (tools.length === 0) { + this._addMessageToThread(threadId, { role: 'assistant', content: fullText, displayContent: fullText, tool_calls: tools }) + + if ((tools?.length ?? 0) === 0) { this._finishStreamingTextMessage(threadId, fullText) } else { - for (const tool of tools) { + for (const tool of tools ?? []) { if (!(tool.name in this._toolsService.toolFns)) { - this._addMessageToThread(threadId, { role: 'tool', name: tool.name, params: tool.args, id: tool.id, content: `Error: This tool was not recognized, so it was not called.`, displayContent: `Error: tool not recognized.`, }) + this._addMessageToThread(threadId, { role: 'tool', name: tool.name, params: tool.params, id: tool.id, content: `Error: This tool was not recognized, so it was not called.`, displayContent: `Error: tool not recognized.`, }) } else { const toolName = tool.name as ToolName - const toolResult = await this._toolsService.toolFns[toolName](tool.args) + const toolResult = await this._toolsService.toolFns[toolName](tool.params) const string = this._toolsService.toolResultToString[toolName](toolResult as any) // typescript is so bad it doesn't even couple the type of ToolResult with the type of the function being called here - this._addMessageToThread(threadId, { role: 'tool', name: tool.name, params: tool.args, id: tool.id, content: string, displayContent: string, }) + this._addMessageToThread(threadId, { role: 'tool', name: tool.name, params: tool.params, id: tool.id, content: string, displayContent: string, }) shouldContinue = true } } diff --git a/src/vs/workbench/contrib/void/common/llmMessageTypes.ts b/src/vs/workbench/contrib/void/common/llmMessageTypes.ts index 68aafa64..e82da2cb 100644 --- a/src/vs/workbench/contrib/void/common/llmMessageTypes.ts +++ b/src/vs/workbench/contrib/void/common/llmMessageTypes.ts @@ -23,7 +23,7 @@ export const errorDetails = (fullError: Error | null): string | null => { } export type OnText = (p: { newText: string, fullText: string }) => void -export type OnFinalMessage = (p: { fullText: string, tools: { name: string, args: string, id: string, }[] }) => void // id is tool_use_id +export type OnFinalMessage = (p: { fullText: string, tools?: { name: string, params: string, id: string, }[] }) => void // id is tool_use_id export type OnError = (p: { message: string, fullError: Error | null }) => void export type AbortRef = { current: (() => void) | null } diff --git a/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts index 9bc1638d..0bbcfcde 100644 --- a/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts +++ b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts @@ -18,7 +18,7 @@ export type DeveloperInfoAtModel = { // UNUSED (coming soon): recognizedModelName: RecognizedModelName, // used to show user if model was auto-recognized supportsTools: boolean, // we will just do a string of tool use if it doesn't support - supportsSystemMessage: 'developer' | 'system' | false, // if null, we will just do a string of system message + 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 @@ -98,7 +98,7 @@ export function recognizedModelOfModelName(modelName: string): RecognizedModelNa const developerInfoAtProvider: { [providerName in ProviderName]: DeveloperInfoAtProvider } = { 'anthropic': { overrideSettingsForAllModels: { - supportsSystemMessage: 'system', + supportsSystemMessageRole: 'system', supportsTools: true, supportsAutocompleteFIM: false, supportsStreaming: true, @@ -106,7 +106,7 @@ const developerInfoAtProvider: { [providerName in ProviderName]: DeveloperInfoAt }, 'deepseek': { overrideSettingsForAllModels: { - supportsSystemMessage: false, + supportsSystemMessageRole: false, supportsTools: false, supportsAutocompleteFIM: false, supportsStreaming: true, @@ -137,15 +137,15 @@ export const developerInfoOfProviderName = (providerName: ProviderName): Partial // providerName is optional, but gives some extra fallbacks if provided const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelName]: Omit } = { 'OpenAI 4o': { - supportsSystemMessage: false, - supportsTools: false, + supportsSystemMessageRole: 'system', + supportsTools: true, supportsAutocompleteFIM: false, - supportsStreaming: false, + supportsStreaming: true, maxTokens: 4096, }, 'Anthropic Claude': { - supportsSystemMessage: false, + supportsSystemMessageRole: 'system', supportsTools: false, supportsAutocompleteFIM: false, supportsStreaming: false, @@ -153,7 +153,7 @@ const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelN }, 'Llama 3.x': { - supportsSystemMessage: false, + supportsSystemMessageRole: false, supportsTools: false, supportsAutocompleteFIM: false, supportsStreaming: false, @@ -161,7 +161,7 @@ const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelN }, 'Deepseek Chat': { - supportsSystemMessage: false, + supportsSystemMessageRole: false, supportsTools: false, supportsAutocompleteFIM: false, supportsStreaming: false, @@ -169,7 +169,7 @@ const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelN }, 'Alibaba Qwen2.5 Coder Instruct': { - supportsSystemMessage: false, + supportsSystemMessageRole: false, supportsTools: false, supportsAutocompleteFIM: false, supportsStreaming: false, @@ -177,7 +177,7 @@ const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelN }, 'Mistral Codestral': { - supportsSystemMessage: false, + supportsSystemMessageRole: false, supportsTools: false, supportsAutocompleteFIM: false, supportsStreaming: false, @@ -185,7 +185,7 @@ const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelN }, 'OpenAI o1, o3': { - supportsSystemMessage: false, + supportsSystemMessageRole: false, supportsTools: false, supportsAutocompleteFIM: false, supportsStreaming: false, @@ -193,7 +193,7 @@ const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelN }, 'Deepseek R1': { - supportsSystemMessage: false, + supportsSystemMessageRole: false, supportsTools: false, supportsAutocompleteFIM: false, supportsStreaming: false, @@ -201,7 +201,7 @@ const developerInfoOfRecognizedModelName: { [recognizedModel in RecognizedModelN }, '': { - supportsSystemMessage: false, + supportsSystemMessageRole: false, supportsTools: false, supportsAutocompleteFIM: false, supportsStreaming: false, diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts index b047a601..8d93b0f7 100644 --- a/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/anthropic.ts @@ -5,7 +5,7 @@ import Anthropic from '@anthropic-ai/sdk'; import { _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js'; -import { anthropicMaxPossibleTokens } from '../../common/voidSettingsTypes.js'; +import { anthropicMaxPossibleTokens, developerInfoOfModelName, developerInfoOfProviderName } from '../../common/voidSettingsTypes.js'; import { InternalToolInfo } from '../../common/toolsService.js'; import { addSystemMessageAndToolSupport } from './processMessages.js'; @@ -39,11 +39,14 @@ export const sendAnthropicChat: _InternalSendLLMChatMessageFnType = ({ messages: return } - const { messages, separateSystemMessageStr, devInfo } = addSystemMessageAndToolSupport(modelName, providerName, messages_, aiInstructions, { separateSystemMessage: true }) + const { messages, separateSystemMessageStr } = addSystemMessageAndToolSupport(modelName, providerName, messages_, aiInstructions, { separateSystemMessage: true }) + + const { overrideSettingsForAllModels } = developerInfoOfProviderName(providerName) + const { supportsTools } = developerInfoOfModelName(modelName, overrideSettingsForAllModels) const anthropic = new Anthropic({ apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true }); - const tools = devInfo?.supportsTools && (tools_?.length ?? 0) !== 0 ? tools_?.map(tool => toAnthropicTool(tool)) : undefined + const tools = (supportsTools && ((tools_?.length ?? 0) !== 0)) ? tools_?.map(tool => toAnthropicTool(tool)) : undefined const stream = anthropic.messages.stream({ system: separateSystemMessageStr, diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts index 60a66881..86c41a9c 100644 --- a/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/openai.ts @@ -8,6 +8,7 @@ import { _InternalModelListFnType, _InternalSendLLMFIMMessageFnType, _InternalSe import { Model } from 'openai/resources/models.js'; import { InternalToolInfo } from '../../common/toolsService.js'; import { addSystemMessageAndToolSupport } from './processMessages.js'; +import { developerInfoOfModelName, developerInfoOfProviderName } from '../../common/voidSettingsTypes.js'; // import { parseMaxTokensStr } from './util.js'; @@ -147,12 +148,14 @@ export const sendOpenAIFIM: _InternalSendLLMFIMMessageFnType = ({ messages, onTe export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = ({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, aiInstructions, tools: tools_ }) => { let fullText = '' - const toolCallOfIndex: { [index: string]: { name: string, args: string, id: string } } = {} + const toolCallOfIndex: { [index: string]: { name: string, params: string, id: string } } = {} - const { messages, devInfo } = addSystemMessageAndToolSupport(modelName, providerName, messages_, aiInstructions, { separateSystemMessage: false }) + const { overrideSettingsForAllModels } = developerInfoOfProviderName(providerName) + const { supportsTools } = developerInfoOfModelName(modelName, overrideSettingsForAllModels) - const tools = devInfo?.supportsTools && (tools_?.length ?? 0) !== 0 ? tools_?.map(tool => toOpenAITool(tool)) : undefined + const { messages } = addSystemMessageAndToolSupport(modelName, providerName, messages_, aiInstructions, { separateSystemMessage: false }) + const tools = (supportsTools && ((tools_?.length ?? 0) !== 0)) ? tools_?.map(tool => toOpenAITool(tool)) : undefined const openai: OpenAI = newOpenAI({ providerName, settingsOfProvider }) const options: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming = { @@ -175,9 +178,9 @@ export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = ({ messages: me // tool call for (const tool of chunk.choices[0]?.delta?.tool_calls ?? []) { const index = tool.index - if (!toolCallOfIndex[index]) toolCallOfIndex[index] = { name: '', args: '', id: '' } + if (!toolCallOfIndex[index]) toolCallOfIndex[index] = { name: '', params: '', id: '' } toolCallOfIndex[index].name += tool.function?.name ?? '' - toolCallOfIndex[index].args += tool.function?.arguments ?? ''; + toolCallOfIndex[index].params += tool.function?.arguments ?? ''; toolCallOfIndex[index].id = tool.id ?? '' } diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/processMessages.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/processMessages.ts index f6f6cd5e..2ae792fb 100644 --- a/src/vs/workbench/contrib/void/electron-main/llmMessage/processMessages.ts +++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/processMessages.ts @@ -1,7 +1,7 @@ import { LLMChatMessage } from '../../common/llmMessageTypes.js'; -import { DeveloperInfoAtModel, developerInfoOfModelName, developerInfoOfProviderName, ProviderName } from '../../common/voidSettingsTypes.js'; +import { developerInfoOfModelName, developerInfoOfProviderName, ProviderName } from '../../common/voidSettingsTypes.js'; import { deepClone } from '../../../../../base/common/objects.js'; @@ -9,13 +9,12 @@ import { deepClone } from '../../../../../base/common/objects.js'; // no matter whether the model supports a system message or not (or what format it supports), add it in some way // also take into account tools if the model doesn't support tool use -export const addSystemMessageAndToolSupport = (modelName: string, providerName: ProviderName, messages_: LLMChatMessage[], aiInstructions: string, { separateSystemMessage }: { separateSystemMessage: boolean }): { separateSystemMessageStr?: string, messages: any[], devInfo: DeveloperInfoAtModel } => { +export const addSystemMessageAndToolSupport = (modelName: string, providerName: ProviderName, messages_: LLMChatMessage[], aiInstructions: string, { separateSystemMessage }: { separateSystemMessage: boolean }): { separateSystemMessageStr?: string, messages: any[] } => { const messages = deepClone(messages_).map(m => ({ ...m, content: m.content.trim(), })) const { overrideSettingsForAllModels } = developerInfoOfProviderName(providerName) - const devInfo = developerInfoOfModelName(modelName, overrideSettingsForAllModels) - const { supportsSystemMessage, supportsTools } = devInfo + const { supportsSystemMessageRole: supportsSystemMessage, supportsTools } = developerInfoOfModelName(modelName, overrideSettingsForAllModels) // 1. SYSTEM MESSAGE // find system messages and concatenate them @@ -236,12 +235,13 @@ export const addSystemMessageAndToolSupport = (modelName: string, providerName: // TODO!!! + console.log('SYSMG', separateSystemMessage) + console.log('FINAL MESSAGES', finalMessages) return { separateSystemMessageStr, messages: finalMessages, - devInfo, } }