mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
tools should work!
This commit is contained in:
parent
131493b5e1
commit
7244d433dd
9 changed files with 322 additions and 206 deletions
|
|
@ -14,7 +14,7 @@ import { IRange } from '../../../../editor/common/core/range.js';
|
|||
import { ILLMMessageService } from '../common/llmMessageService.js';
|
||||
import { IModelService } from '../../../../editor/common/services/model.js';
|
||||
import { chat_userMessage, chat_systemMessage } from './prompt/prompts.js';
|
||||
import { IToolsService, ToolName, voidTools } from '../common/toolsService.js';
|
||||
import { InternalToolInfo, IToolsService, ToolName, voidTools } from '../common/toolsService.js';
|
||||
import { toLLMChatMessage } from '../common/llmMessageTypes.js';
|
||||
|
||||
// one of the square items that indicates a selection in a chat bubble (NOT a file, a Selection of text)
|
||||
|
|
@ -66,10 +66,10 @@ export type ChatMessage =
|
|||
| {
|
||||
role: 'tool';
|
||||
name: string; // internal use
|
||||
params: string | null; // internal use
|
||||
params: string; // internal use
|
||||
id: string; // apis require this tool use id
|
||||
content: string | null; // summary of the tool to the LLM
|
||||
displayContent: string | null; // text message of result
|
||||
content: string; // result
|
||||
displayContent: string; // text message of result
|
||||
}
|
||||
|
||||
// a 'thread' means a chat message history
|
||||
|
|
@ -296,6 +296,10 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
this._setStreamState(threadId, { error: undefined })
|
||||
|
||||
|
||||
const tools: InternalToolInfo[] | undefined = (
|
||||
chatMode === 'chat' ? undefined
|
||||
: chatMode === 'agent' ? Object.keys(voidTools).map(toolName => voidTools[toolName as ToolName])
|
||||
: undefined)
|
||||
|
||||
// agent loop
|
||||
const agentLoop = async () => {
|
||||
|
|
@ -316,8 +320,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
...this.getCurrentThread().messages.map(m => (toLLMChatMessage(m))),
|
||||
],
|
||||
|
||||
// TODO!!!!! make this change on 'agent' | 'chat'
|
||||
tools: Object.keys(voidTools).map(toolName => voidTools[toolName as ToolName]),
|
||||
tools: tools,
|
||||
|
||||
onText: ({ fullText }) => {
|
||||
this._setStreamState(threadId, { messageSoFar: fullText })
|
||||
|
|
|
|||
|
|
@ -1261,6 +1261,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
if (!(blockNum in diffareaidOfBlockNum)) {
|
||||
const foundInCode = findTextInCode(block.orig, fileContents)
|
||||
if (typeof foundInCode === 'string') {
|
||||
// TODO!!! log and retry
|
||||
console.log('NOT FOUND IN CODE!!!!', foundInCode)
|
||||
continue
|
||||
}
|
||||
|
|
@ -1305,7 +1306,7 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
this._refreshStylesAndDiffsInURI(uri)
|
||||
},
|
||||
onFinalMessage: async ({ fullText }) => {
|
||||
console.log('/* ONFIN */', fullText)
|
||||
console.log('/* ON FINALMESSAGE */', fullText)
|
||||
|
||||
// 1. wait 500ms and fix lint errors - call lint error workflow
|
||||
// (update react state to say "Fixing errors")
|
||||
|
|
@ -1325,8 +1326,6 @@ class EditCodeService extends Disposable implements IEditCodeService {
|
|||
onDone(false)
|
||||
},
|
||||
onError: (e) => {
|
||||
console.log('/* ERRRRRR */')
|
||||
|
||||
console.log('ERROR', e);
|
||||
onDone(true)
|
||||
},
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ export const AIInstructionsBox = () => {
|
|||
return <VoidInputBox2
|
||||
className='min-h-[81px] p-3 rounded-sm'
|
||||
initValue={voidSettingsState.globalSettings.aiInstructions}
|
||||
placeholder={`Do not change my indentation or delete my comments. When writing TS or JS, do not add ;'s. Respond to all queries in French. `}
|
||||
placeholder={`Do not change my indentation or delete my comments. When writing TS or JS, do not add ;'s. Write new code using Rust if possible. `}
|
||||
multiline
|
||||
onChangeText={(newText) => {
|
||||
voidSettingsService.setGlobalSetting('aiInstructions', newText)
|
||||
|
|
|
|||
|
|
@ -32,12 +32,13 @@ export type LLMChatMessage = {
|
|||
content: string;
|
||||
} | {
|
||||
role: 'assistant',
|
||||
tool_calls?: { name: string, id: string, params: string }[];
|
||||
content: string;
|
||||
} | {
|
||||
role: 'tool';
|
||||
content: string; // result
|
||||
name: string;
|
||||
params: string;
|
||||
id: string;
|
||||
content: string;
|
||||
}
|
||||
|
||||
export const toLLMChatMessage = (c: ChatMessage): LLMChatMessage => {
|
||||
|
|
@ -45,21 +46,15 @@ export const toLLMChatMessage = (c: ChatMessage): LLMChatMessage => {
|
|||
return { role: c.role, content: c.content ?? '(empty)' }
|
||||
}
|
||||
else if (c.role === 'assistant')
|
||||
return { role: c.role, tool_calls: c.tool_calls, content: c.content ?? '(empty model output)' }
|
||||
return { role: c.role, content: c.content ?? '(empty model output)' }
|
||||
else if (c.role === 'tool')
|
||||
return { role: c.role, id: c.id, content: c.content ?? '(empty output)' }
|
||||
return { role: c.role, id: c.id, name: c.name, params: c.params, content: c.content ?? '(empty output)' }
|
||||
else {
|
||||
throw 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export type _InternalLLMChatMessage = {
|
||||
role: any;
|
||||
id?: any;
|
||||
content: string;
|
||||
}
|
||||
|
||||
type _InternalSendFIMMessage = {
|
||||
prefix: string;
|
||||
suffix: string;
|
||||
|
|
@ -115,6 +110,8 @@ export type EventLLMMessageOnErrorParams = Parameters<OnError>[0] & { requestId:
|
|||
|
||||
export type _InternalSendLLMChatMessageFnType = (
|
||||
params: {
|
||||
aiInstructions: string;
|
||||
|
||||
onText: OnText;
|
||||
onFinalMessage: OnFinalMessage;
|
||||
onError: OnError;
|
||||
|
|
|
|||
|
|
@ -1,177 +0,0 @@
|
|||
import { _InternalLLMChatMessage, LLMChatMessage } from '../../common/llmMessageTypes.js';
|
||||
import { DeveloperInfoAtModel, developerInfoOfModelName, developerInfoOfProviderName, ProviderName } from '../../common/voidSettingsTypes.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[], { separateSystemMessage }: { separateSystemMessage: boolean }): { separateSystemMessageStr?: string, messages: _InternalLLMChatMessage[], devInfo: DeveloperInfoAtModel } => {
|
||||
|
||||
const messages: _InternalLLMChatMessage[] = messages_.map(m => ({ ...m, content: m.content.trim(), }))
|
||||
|
||||
const { overrideSettingsForAllModels } = developerInfoOfProviderName(providerName)
|
||||
const devInfo = developerInfoOfModelName(modelName, overrideSettingsForAllModels)
|
||||
const { supportsSystemMessage } = devInfo
|
||||
|
||||
// 1. SYSTEM MESSAGE
|
||||
// find system messages and concatenate them
|
||||
let systemMessageStr = messages
|
||||
.filter(msg => msg.role === 'system')
|
||||
.map(msg => msg.content)
|
||||
.join('\n') || undefined;
|
||||
|
||||
let separateSystemMessageStr: string | undefined = undefined
|
||||
|
||||
// remove all system messages
|
||||
const newMessages: _InternalLLMChatMessage[] = messages.filter(msg => msg.role !== 'system')
|
||||
|
||||
|
||||
// if (!supportsTools) {
|
||||
// if (!systemMessageStr) systemMessageStr = ''
|
||||
// systemMessageStr += '' // TODO!!! add tool use system message here
|
||||
// }
|
||||
|
||||
|
||||
if (systemMessageStr) {
|
||||
// if supports system message
|
||||
if (supportsSystemMessage) {
|
||||
if (separateSystemMessage)
|
||||
separateSystemMessageStr = systemMessageStr
|
||||
else {
|
||||
newMessages.unshift({ role: supportsSystemMessage, content: systemMessageStr }) // add new first message
|
||||
}
|
||||
}
|
||||
// if does not support system message
|
||||
else {
|
||||
if (supportsSystemMessage) {
|
||||
if (newMessages.length === 0)
|
||||
newMessages.push({ role: 'user', content: systemMessageStr })
|
||||
// add system mesasges to first message (should be a user message)
|
||||
else {
|
||||
const newFirstMessage = {
|
||||
role: newMessages[0].role,
|
||||
content: (''
|
||||
+ '<SYSTEM_MESSAGE>\n'
|
||||
+ systemMessageStr
|
||||
+ '\n'
|
||||
+ '</SYSTEM_MESSAGE>\n'
|
||||
+ newMessages[0].content
|
||||
)
|
||||
}
|
||||
newMessages.splice(0, 1) // delete first message
|
||||
newMessages.unshift(newFirstMessage) // add new first message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
separateSystemMessageStr,
|
||||
messages: newMessages,
|
||||
devInfo,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// const { maxTokens, supportsTools, supportsAutocompleteFIM, supportsStreaming, } = developerInfoOfModelName(recognizedModel)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// let index = 0;
|
||||
// while (index < newMessages.length) {
|
||||
|
||||
// merge tool with the previous assistant and the following user message
|
||||
|
||||
// take prev message and add
|
||||
/*
|
||||
openai assistant message will have: https://platform.openai.com/docs/guides/function-calling#function-calling-steps
|
||||
"tool_calls":[
|
||||
{
|
||||
"id": "call_12345xyz",
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_weather",
|
||||
"arguments": "{\"latitude\":48.8566,\"longitude\":2.3522}"
|
||||
}
|
||||
}]
|
||||
|
||||
openai user response will be:
|
||||
{
|
||||
"role": "tool",
|
||||
"tool_call_id": tool_call.id,
|
||||
"content": str(result)
|
||||
}
|
||||
|
||||
anthropic assistant message will have: https://docs.anthropic.com/en/docs/build-with-claude/tool-use#tool-use-examples
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "<thinking>I need to call the get_weather function, and the user wants SF, which is likely San Francisco, CA.</thinking>"
|
||||
},
|
||||
{
|
||||
"type": "tool_use",
|
||||
"id": "toolu_01A09q90qw90lq917835lq9",
|
||||
"name": "get_weather",
|
||||
"input": {"location": "San Francisco, CA", "unit": "celsius"}
|
||||
}
|
||||
]
|
||||
|
||||
anthropic user message response will be:
|
||||
"content": [
|
||||
{
|
||||
"type": "tool_result",
|
||||
"tool_use_id": "toolu_01A09q90qw90lq917835lq9",
|
||||
"content": "15 degrees"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
ACCORDING TO 4o: gemini: similar to openai, but function_call, and only 1 call per message (no id because only 1 message)
|
||||
gemini request: {
|
||||
"role": "assistant",
|
||||
"content": null,
|
||||
"function_call": {
|
||||
"name": "get_weather",
|
||||
"arguments": {
|
||||
"latitude": 48.8566,
|
||||
"longitude": 2.3522
|
||||
}
|
||||
}
|
||||
}
|
||||
gemini response:
|
||||
{
|
||||
"role": "assistant",
|
||||
"function_response": {
|
||||
"name": "get_weather",
|
||||
"response": {
|
||||
"temperature": "15°C",
|
||||
"condition": "Cloudy"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ anthropic
|
||||
|
||||
+ openai-compat (4)
|
||||
+ gemini
|
||||
|
||||
ollama
|
||||
|
||||
|
||||
mistral: same as openai
|
||||
|
||||
*/
|
||||
|
|
@ -7,7 +7,7 @@ import Anthropic from '@anthropic-ai/sdk';
|
|||
import { _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js';
|
||||
import { anthropicMaxPossibleTokens } from '../../common/voidSettingsTypes.js';
|
||||
import { InternalToolInfo } from '../../common/toolsService.js';
|
||||
import { addSystemMessageAndToolSupport } from './addSupport.js';
|
||||
import { addSystemMessageAndToolSupport } from './processMessages.js';
|
||||
|
||||
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ export const toAnthropicTool = (toolInfo: InternalToolInfo) => {
|
|||
|
||||
|
||||
|
||||
export const sendAnthropicChat: _InternalSendLLMChatMessageFnType = ({ messages: messages_, providerName, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, tools: tools_ }) => {
|
||||
export const sendAnthropicChat: _InternalSendLLMChatMessageFnType = ({ messages: messages_, providerName, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, aiInstructions, tools: tools_ }) => {
|
||||
|
||||
const thisConfig = settingsOfProvider.anthropic
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ export const sendAnthropicChat: _InternalSendLLMChatMessageFnType = ({ messages:
|
|||
return
|
||||
}
|
||||
|
||||
const { messages, separateSystemMessageStr, devInfo } = addSystemMessageAndToolSupport(modelName, providerName, messages_, { separateSystemMessage: true })
|
||||
const { messages, separateSystemMessageStr, devInfo } = addSystemMessageAndToolSupport(modelName, providerName, messages_, aiInstructions, { separateSystemMessage: true })
|
||||
|
||||
const anthropic = new Anthropic({ apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true });
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import OpenAI from 'openai';
|
|||
import { _InternalModelListFnType, _InternalSendLLMFIMMessageFnType, _InternalSendLLMChatMessageFnType } from '../../common/llmMessageTypes.js';
|
||||
import { Model } from 'openai/resources/models.js';
|
||||
import { InternalToolInfo } from '../../common/toolsService.js';
|
||||
import { addSystemMessageAndToolSupport } from './addSupport.js';
|
||||
import { addSystemMessageAndToolSupport } from './processMessages.js';
|
||||
// import { parseMaxTokensStr } from './util.js';
|
||||
|
||||
|
||||
|
|
@ -144,12 +144,12 @@ export const sendOpenAIFIM: _InternalSendLLMFIMMessageFnType = ({ messages, onTe
|
|||
|
||||
|
||||
// OpenAI, OpenRouter, OpenAICompatible
|
||||
export const sendOpenAIChat: _InternalSendLLMChatMessageFnType = ({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, tools: tools_ }) => {
|
||||
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 { messages, devInfo } = addSystemMessageAndToolSupport(modelName, providerName, messages_, { separateSystemMessage: false })
|
||||
const { messages, devInfo } = addSystemMessageAndToolSupport(modelName, providerName, messages_, aiInstructions, { separateSystemMessage: false })
|
||||
|
||||
const tools = devInfo?.supportsTools && (tools_?.length ?? 0) !== 0 ? tools_?.map(tool => toOpenAITool(tool)) : undefined
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,294 @@
|
|||
|
||||
|
||||
import { LLMChatMessage } from '../../common/llmMessageTypes.js';
|
||||
import { DeveloperInfoAtModel, developerInfoOfModelName, developerInfoOfProviderName, ProviderName } from '../../common/voidSettingsTypes.js';
|
||||
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 } => {
|
||||
|
||||
const messages = deepClone(messages_).map(m => ({ ...m, content: m.content.trim(), }))
|
||||
|
||||
const { overrideSettingsForAllModels } = developerInfoOfProviderName(providerName)
|
||||
const devInfo = developerInfoOfModelName(modelName, overrideSettingsForAllModels)
|
||||
const { supportsSystemMessage, supportsTools } = devInfo
|
||||
|
||||
// 1. SYSTEM MESSAGE
|
||||
// find system messages and concatenate them
|
||||
let systemMessageStr = messages
|
||||
.filter(msg => msg.role === 'system')
|
||||
.map(msg => msg.content)
|
||||
.join('\n') || undefined;
|
||||
|
||||
if (aiInstructions)
|
||||
systemMessageStr = `${(systemMessageStr ? `${systemMessageStr}\n\n` : '')}GUIDELINES\n${aiInstructions}`
|
||||
|
||||
|
||||
let separateSystemMessageStr: string | undefined = undefined
|
||||
|
||||
// remove all system messages
|
||||
const newMessages: (LLMChatMessage | { role: 'developer', content: string })[] = messages.filter(msg => msg.role !== 'system')
|
||||
|
||||
|
||||
// if (!supportsTools) {
|
||||
// if (!systemMessageStr) systemMessageStr = ''
|
||||
// systemMessageStr += '' // TODO!!! add tool use system message here
|
||||
// }
|
||||
|
||||
|
||||
if (systemMessageStr) {
|
||||
// if supports system message
|
||||
if (supportsSystemMessage) {
|
||||
if (separateSystemMessage)
|
||||
separateSystemMessageStr = systemMessageStr
|
||||
else {
|
||||
newMessages.unshift({ role: supportsSystemMessage, content: systemMessageStr }) // add new first message
|
||||
}
|
||||
}
|
||||
// if does not support system message
|
||||
else {
|
||||
if (supportsSystemMessage) {
|
||||
if (newMessages.length === 0)
|
||||
newMessages.push({ role: 'user', content: systemMessageStr })
|
||||
// add system mesasges to first message (should be a user message)
|
||||
else {
|
||||
const newFirstMessage = {
|
||||
role: 'user',
|
||||
content: (''
|
||||
+ '<SYSTEM_MESSAGE>\n'
|
||||
+ systemMessageStr
|
||||
+ '\n'
|
||||
+ '</SYSTEM_MESSAGE>\n'
|
||||
+ newMessages[0].content
|
||||
)
|
||||
} as const
|
||||
newMessages.splice(0, 1) // delete first message
|
||||
newMessages.unshift(newFirstMessage) // add new first message
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// 2. MAKE TOOLS FORMAT CORRECT in messages
|
||||
let finalMessages: any[]
|
||||
if (!supportsTools) {
|
||||
// do nothing
|
||||
finalMessages = newMessages
|
||||
}
|
||||
|
||||
// anthropic assistant message will have: https://docs.anthropic.com/en/docs/build-with-claude/tool-use#tool-use-examples
|
||||
// "content": [
|
||||
// {
|
||||
// "type": "text",
|
||||
// "text": "<thinking>I need to call the get_weather function, and the user wants SF, which is likely San Francisco, CA.</thinking>"
|
||||
// },
|
||||
// {
|
||||
// "type": "tool_use",
|
||||
// "id": "toolu_01A09q90qw90lq917835lq9",
|
||||
// "name": "get_weather",
|
||||
// "input": { "location": "San Francisco, CA", "unit": "celsius" }
|
||||
// }
|
||||
// ]
|
||||
|
||||
// anthropic user message response will be:
|
||||
// "content": [
|
||||
// {
|
||||
// "type": "tool_result",
|
||||
// "tool_use_id": "toolu_01A09q90qw90lq917835lq9",
|
||||
// "content": "15 degrees"
|
||||
// }
|
||||
// ]
|
||||
|
||||
|
||||
else if (providerName === 'anthropic') { // convert role:'tool' to anthropic's type
|
||||
const newMessagesTools: (
|
||||
Exclude<typeof newMessages[0], { role: 'assistant' | 'user' }> | {
|
||||
role: 'assistant',
|
||||
content: string | ({
|
||||
type: 'text';
|
||||
text: string;
|
||||
} | {
|
||||
type: 'tool_use';
|
||||
name: string;
|
||||
input: string;
|
||||
id: string;
|
||||
})[]
|
||||
} | {
|
||||
role: 'user',
|
||||
content: string | ({
|
||||
type: 'text';
|
||||
text: string;
|
||||
} | {
|
||||
type: 'tool_response';
|
||||
tool_use_id: string;
|
||||
content: string;
|
||||
})[]
|
||||
}
|
||||
)[] = newMessages;
|
||||
|
||||
|
||||
for (let i = 0; i < newMessagesTools.length; i += 1) {
|
||||
const currMsg = newMessagesTools[i]
|
||||
|
||||
if (currMsg.role !== 'tool') continue
|
||||
|
||||
const prevMsg = 0 <= i - 1 && i - 1 <= newMessagesTools.length ? newMessagesTools[i - 1] : undefined
|
||||
const nextMsg = 0 <= i + 1 && i + 1 <= newMessagesTools.length ? newMessagesTools[i + 1] : undefined
|
||||
|
||||
if (prevMsg?.role === 'assistant') {
|
||||
if (typeof prevMsg.content === 'string') prevMsg.content = [{ type: 'text', text: typeof prevMsg.content }]
|
||||
prevMsg.content.push({ type: 'tool_use', name: currMsg.name, input: currMsg.params, id: currMsg.id })
|
||||
}
|
||||
if (nextMsg?.role === 'user') {
|
||||
if (typeof nextMsg.content === 'string') nextMsg.content = [{ type: 'text', text: typeof nextMsg.content }]
|
||||
nextMsg.content.push({ type: 'tool_response', tool_use_id: currMsg.id, content: currMsg.content })
|
||||
}
|
||||
}
|
||||
finalMessages = newMessagesTools
|
||||
}
|
||||
|
||||
// openai assistant message will have: https://platform.openai.com/docs/guides/function-calling#function-calling-steps
|
||||
// "tool_calls":[
|
||||
// {
|
||||
// "type": "function",
|
||||
// "id": "call_12345xyz",
|
||||
// "function": {
|
||||
// "name": "get_weather",
|
||||
// "arguments": "{\"latitude\":48.8566,\"longitude\":2.3522}"
|
||||
// }
|
||||
// }]
|
||||
|
||||
// openai user response will be:
|
||||
// {
|
||||
// "role": "tool",
|
||||
// "tool_call_id": tool_call.id,
|
||||
// "content": str(result)
|
||||
// }
|
||||
|
||||
// treat all other providers like openai tool message for now
|
||||
else {
|
||||
|
||||
const newMessagesTools: (
|
||||
Exclude<typeof newMessages[0], { role: 'assistant' | 'tool' }> | {
|
||||
role: 'assistant',
|
||||
content: string;
|
||||
tool_calls?: {
|
||||
type: 'function';
|
||||
id: string;
|
||||
function: {
|
||||
name: string;
|
||||
arguments: string;
|
||||
}
|
||||
}[]
|
||||
} | {
|
||||
role: 'tool',
|
||||
id: string; // old val
|
||||
tool_call_id: string; // new val
|
||||
content: string;
|
||||
}
|
||||
)[] = [];
|
||||
|
||||
for (let i = 0; i < newMessages.length; i += 1) {
|
||||
const currMsg = newMessages[i]
|
||||
|
||||
if (currMsg.role !== 'tool') {
|
||||
newMessagesTools.push(currMsg)
|
||||
continue
|
||||
}
|
||||
|
||||
// edit previous assistant message to have called the tool
|
||||
const prevMsg = 0 <= i - 1 && i - 1 <= newMessagesTools.length ? newMessagesTools[i - 1] : undefined
|
||||
if (prevMsg?.role === 'assistant') {
|
||||
prevMsg.tool_calls = [{
|
||||
type: 'function',
|
||||
id: currMsg.id,
|
||||
function: {
|
||||
name: currMsg.name,
|
||||
arguments: currMsg.params
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
// add the tool
|
||||
newMessagesTools.push({
|
||||
role: 'tool',
|
||||
id: currMsg.id,
|
||||
content: currMsg.content,
|
||||
tool_call_id: currMsg.id,
|
||||
})
|
||||
}
|
||||
finalMessages = newMessagesTools
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// 3. CROP MESSAGES SO EVERYTHING FITS IN CONTEXT
|
||||
// TODO!!!
|
||||
|
||||
|
||||
|
||||
|
||||
return {
|
||||
separateSystemMessageStr,
|
||||
messages: finalMessages,
|
||||
devInfo,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
|
||||
ACCORDING TO 4o: gemini: similar to openai, but function_call, and only 1 call per message (no id because only 1 message)
|
||||
gemini request: {
|
||||
"role": "assistant",
|
||||
"content": null,
|
||||
"function_call": {
|
||||
"name": "get_weather",
|
||||
"arguments": {
|
||||
"latitude": 48.8566,
|
||||
"longitude": 2.3522
|
||||
}
|
||||
}
|
||||
}
|
||||
gemini response:
|
||||
{
|
||||
"role": "assistant",
|
||||
"function_response": {
|
||||
"name": "get_weather",
|
||||
"response": {
|
||||
"temperature": "15°C",
|
||||
"condition": "Cloudy"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+ anthropic
|
||||
|
||||
+ openai-compat (4)
|
||||
+ gemini
|
||||
|
||||
ollama
|
||||
|
||||
|
||||
mistral: same as openai
|
||||
|
||||
*/
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||
*--------------------------------------------------------------------------------------*/
|
||||
|
||||
import { SendLLMMessageParams, OnText, OnFinalMessage, OnError, _InternalLLMChatMessage } from '../../common/llmMessageTypes.js';
|
||||
import { SendLLMMessageParams, OnText, OnFinalMessage, OnError } from '../../common/llmMessageTypes.js';
|
||||
import { IMetricsService } from '../../common/metricsService.js';
|
||||
import { displayInfoOfProviderName } from '../../common/voidSettingsTypes.js';
|
||||
|
||||
|
|
@ -104,11 +104,11 @@ export const sendLLMMessage = ({
|
|||
case 'groq':
|
||||
case 'gemini':
|
||||
if (messagesType === 'FIMMessage') onFinalMessage({ fullText: 'TODO - OpenAI FIM', tools: [] })
|
||||
else /* */ sendOpenAIChat({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, tools });
|
||||
else /* */ sendOpenAIChat({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, aiInstructions, tools });
|
||||
break;
|
||||
case 'anthropic':
|
||||
if (messagesType === 'FIMMessage') onFinalMessage({ fullText: 'TODO - Anthropic FIM', tools: [] })
|
||||
else /* */ sendAnthropicChat({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, tools });
|
||||
else /* */ sendAnthropicChat({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName, aiInstructions, tools });
|
||||
break;
|
||||
default:
|
||||
onError({ message: `Error: Void provider was "${providerName}", which is not recognized.`, fullError: null })
|
||||
|
|
|
|||
Loading…
Reference in a new issue