mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
remove rawAnthropicContent
This commit is contained in:
parent
5ad5fe7014
commit
2b7df8c604
6 changed files with 49 additions and 68 deletions
|
|
@ -14,7 +14,7 @@ import { IRange } from '../../../../editor/common/core/range.js';
|
|||
import { ILLMMessageService } from '../common/llmMessageService.js';
|
||||
import { chat_userMessageContent, chat_systemMessage, chat_lastUserMessageWithFilesAdded, chat_selectionsString } from './prompt/prompts.js';
|
||||
import { InternalToolInfo, IToolsService, ToolCallParams, ToolResultType, ToolName, toolNamesThatRequireApproval, voidTools } from './toolsService.js';
|
||||
import { LLMChatMessage, toLLMChatMessage, ToolCallType } from '../common/llmMessageTypes.js';
|
||||
import { LLMChatMessage, ToolCallType } from '../common/llmMessageTypes.js';
|
||||
import { IWorkspaceContextService } from '../../../../platform/workspace/common/workspace.js';
|
||||
import { IVoidFileService } from '../common/voidFileService.js';
|
||||
import { generateUuid } from '../../../../base/common/uuid.js';
|
||||
|
|
@ -32,6 +32,23 @@ const findLastIndex = <T>(arr: T[], condition: (t: T) => boolean): number => {
|
|||
}
|
||||
|
||||
|
||||
|
||||
const toLLMChatMessage = (c: ChatMessage): LLMChatMessage | null => {
|
||||
if (c.role === 'user') {
|
||||
return { role: c.role, content: c.content || '(empty message)' }
|
||||
}
|
||||
else if (c.role === 'assistant')
|
||||
return { role: c.role, content: c.content || '(empty message)' }
|
||||
else if (c.role === 'tool')
|
||||
return { role: c.role, id: c.id, name: c.name, params: c.paramsStr, content: c.content || '(empty output)' }
|
||||
else if (c.role === 'tool_request')
|
||||
return null
|
||||
else {
|
||||
throw new Error(`Role ${(c as any).role} not recognized.`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// one of the square items that indicates a selection in a chat bubble (NOT a file, a Selection of text)
|
||||
export type CodeSelection = {
|
||||
type: 'Selection';
|
||||
|
|
@ -73,7 +90,7 @@ export type ToolRequestApproval<T extends ToolName> = {
|
|||
|
||||
// WARNING: changing this format is a big deal!!!!!! need to migrate old format to new format on users' computers so people don't get errors.
|
||||
export type ChatMessage =
|
||||
{
|
||||
| {
|
||||
role: 'user';
|
||||
content: string | null; // content displayed to the LLM on future calls - allowed to be '', will be replaced with (empty)
|
||||
displayContent: string | null; // content displayed to user - allowed to be '', will be ignored
|
||||
|
|
@ -460,6 +477,9 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
catch (e) {
|
||||
console.log('ERR2')
|
||||
|
||||
// TODO!!! test rejection
|
||||
// if (Math.random() > 0) throw new Error('TESTING')
|
||||
|
||||
const errorMessage = 'Tool call was rejected by the user.'
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: tool.paramsStr, id: tool.id, content: errorMessage, result: { type: 'error', value: errorMessage }, })
|
||||
res_()
|
||||
|
|
@ -486,7 +506,6 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
|
||||
console.log('H')
|
||||
toolResultStr = this._toolsService.stringOfResult[toolName](toolParams as any, toolResult as any)
|
||||
// if (Math.random() > 0) throw new Error('This is not an allowed repo.')
|
||||
|
||||
} catch (error) {
|
||||
const errorMessage = `Tool call succeeded, but there was an error stringifying the output.\n${getErrorMessage(error)}`
|
||||
|
|
|
|||
|
|
@ -1257,7 +1257,7 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
const title = toolNameToTitle[toolRequest.name]
|
||||
const { params } = toolRequest
|
||||
return <DropdownComponent title={title} desc1={`"${params.command}"`} icon={<Dot className={`stroke-orange-500`} />}
|
||||
// TODO!!! open the terminal with that ID
|
||||
// TODO!!! open the terminal with that ID
|
||||
/>
|
||||
},
|
||||
resultWrapper: ({ toolMessage }) => {
|
||||
|
|
|
|||
|
|
@ -459,7 +459,7 @@ export const FeaturesTab = () => {
|
|||
|
||||
<div className='w-full'>
|
||||
<h4 className={`text-base`}>{displayInfoOfFeatureName('Apply')}</h4>
|
||||
<div className='text-sm italic text-void-fg-3 my-1'>We recommend the smartest model you{`'`}ve got, like Claude 3.7 or GPT 4o.</div>
|
||||
<div className='text-sm italic text-void-fg-3 my-1'>We recommend using Claude 3.7 or GPT 4o.</div>
|
||||
<ModelDropdown featureName={'Apply'} />
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ export type LLMChatMessage = {
|
|||
} | {
|
||||
role: 'assistant',
|
||||
content: string; // text content
|
||||
rawAnthropicAssistantContent?: RawAnthropicAssistantContent[]; // used for anthropic signing
|
||||
} | {
|
||||
role: 'tool';
|
||||
content: string; // result
|
||||
|
|
@ -50,30 +49,13 @@ export type ToolCallType = {
|
|||
id: string;
|
||||
}
|
||||
|
||||
export type RawAnthropicAssistantContent = { type: 'thinking'; thinking: string; signature: string; } | { type: 'redacted_thinking'; data: string } | { type: 'text', text: string }
|
||||
|
||||
|
||||
export type OnText = (p: { fullText: string; fullReasoning: string }) => void
|
||||
export type OnFinalMessage = (p: { fullText: string, toolCalls?: ToolCallType[], fullReasoning?: string, rawAnthropicAssistantContent?: RawAnthropicAssistantContent[] }) => void // id is tool_use_id
|
||||
export type OnFinalMessage = (p: { fullText: string, toolCalls?: ToolCallType[], fullReasoning?: string }) => void // id is tool_use_id
|
||||
export type OnError = (p: { message: string, fullError: Error | null }) => void
|
||||
export type AbortRef = { current: (() => void) | null }
|
||||
|
||||
|
||||
export const toLLMChatMessage = (c: ChatMessage): LLMChatMessage | null => {
|
||||
if (c.role === 'user') {
|
||||
return { role: c.role, content: c.content || '(empty message)' }
|
||||
}
|
||||
else if (c.role === 'assistant')
|
||||
return { role: c.role, content: c.content || '(empty message)' }
|
||||
else if (c.role === 'tool')
|
||||
return { role: c.role, id: c.id, name: c.name, params: c.paramsStr, content: c.content || '(empty output)' }
|
||||
else if (c.role === 'tool_request')
|
||||
return null
|
||||
else {
|
||||
throw new Error(`Role ${(c as any).role} not recognized.`)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export type LLMFIMMessage = {
|
||||
prefix: string;
|
||||
|
|
@ -98,7 +80,7 @@ export type ServiceSendLLMMessageParams = {
|
|||
onError: OnError;
|
||||
logging: { loggingName: string, };
|
||||
useProviderFor: FeatureName;
|
||||
} & SendLLMType
|
||||
} & SendLLMType;
|
||||
|
||||
// params to the true sendLLMMessage function
|
||||
export type SendLLMMessageParams = {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||
*--------------------------------------------------------------------------------------*/
|
||||
|
||||
import { RawAnthropicAssistantContent, LLMChatMessage, LLMFIMMessage } from '../../common/llmMessageTypes.js';
|
||||
import { LLMChatMessage, LLMFIMMessage } from '../../common/llmMessageTypes.js';
|
||||
import { deepClone } from '../../../../../base/common/objects.js';
|
||||
|
||||
|
||||
|
|
@ -22,8 +22,7 @@ type InternalLLMChatMessage = {
|
|||
content: string;
|
||||
} | {
|
||||
role: 'assistant',
|
||||
content: string | (RawAnthropicAssistantContent | { type: 'text'; text: string })[];
|
||||
rawAnthropicAssistantContent?: RawAnthropicAssistantContent[] | undefined;
|
||||
content: string | ({ type: 'text'; text: string })[];
|
||||
} | {
|
||||
role: 'tool';
|
||||
content: string; // result
|
||||
|
|
@ -41,12 +40,12 @@ const prepareMessages_normalize = ({ messages: messages_ }: { messages: LLMChatM
|
|||
// remove duplicate roles
|
||||
for (let i = 1; i < messages.length; i += 1) {
|
||||
const curr = messages[i]
|
||||
const prev = messages[i - 1]
|
||||
// if found a repeated role, put the current content in the prev
|
||||
if ((curr.role === 'user' && prev.role === 'user') || (curr.role === 'assistant' && prev.role === 'assistant')) {
|
||||
prev.content += '\n' + curr.content
|
||||
continue
|
||||
}
|
||||
// const prev = messages[i - 1]
|
||||
// // if found a repeated role, put the current content in the prev
|
||||
// if ((curr.role === 'assistant' && prev.role === 'assistant')) {
|
||||
// prev.content += '\n' + curr.content
|
||||
// continue
|
||||
// }
|
||||
// add the message
|
||||
newMessages.push(curr)
|
||||
}
|
||||
|
|
@ -58,29 +57,6 @@ const prepareMessages_normalize = ({ messages: messages_ }: { messages: LLMChatM
|
|||
|
||||
|
||||
|
||||
// remove rawAnthropicAssistantContent, and make content equal to it if supportsAnthropicContent
|
||||
const prepareMessages_anthropicContent = ({ messages, supportsAnthropicContent }: { messages: LLMChatMessage[], supportsAnthropicContent: boolean }) => {
|
||||
const newMessages: InternalLLMChatMessage[] = []
|
||||
for (const m of messages) {
|
||||
if (m.role !== 'assistant') {
|
||||
newMessages.push(m)
|
||||
continue
|
||||
}
|
||||
let newMessage: InternalLLMChatMessage
|
||||
if (supportsAnthropicContent) {
|
||||
const newContent = m.rawAnthropicAssistantContent
|
||||
newMessage = { role: 'assistant', content: newContent ?? m.content }
|
||||
}
|
||||
else {
|
||||
newMessage = m
|
||||
}
|
||||
delete newMessage.rawAnthropicAssistantContent // important to delete this field
|
||||
newMessages.push(m)
|
||||
}
|
||||
return { messages: newMessages }
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// no matter whether the model supports a system message or not (or what format it supports), add it in some way
|
||||
|
|
@ -255,7 +231,6 @@ const prepareMessages_tools_anthropic = ({ messages }: { messages: InternalLLMCh
|
|||
Exclude<InternalLLMChatMessage, { role: 'assistant' | 'user' }> | {
|
||||
role: 'assistant',
|
||||
content: string | (
|
||||
| RawAnthropicAssistantContent
|
||||
| {
|
||||
type: 'text';
|
||||
text: string;
|
||||
|
|
@ -366,18 +341,15 @@ export const prepareMessages = ({
|
|||
aiInstructions,
|
||||
supportsSystemMessage,
|
||||
supportsTools,
|
||||
supportsAnthropicContent,
|
||||
}: {
|
||||
messages: LLMChatMessage[],
|
||||
aiInstructions: string,
|
||||
supportsSystemMessage: false | 'system-role' | 'developer-role' | 'separated',
|
||||
supportsTools: false | 'anthropic-style' | 'openai-style',
|
||||
supportsAnthropicContent: boolean,
|
||||
}) => {
|
||||
const { messages: messages1 } = prepareMessages_normalize({ messages })
|
||||
const { messages: messages2 } = prepareMessages_anthropicContent({ messages: messages1, supportsAnthropicContent })
|
||||
const { messages: messages3, separateSystemMessageStr } = prepareMessages_systemMessage({ messages: messages2, aiInstructions, supportsSystemMessage })
|
||||
const { messages: messages4 } = prepareMessages_tools({ messages: messages3, supportsTools })
|
||||
const { messages: messages2, separateSystemMessageStr } = prepareMessages_systemMessage({ messages: messages1, aiInstructions, supportsSystemMessage })
|
||||
const { messages: messages4 } = prepareMessages_tools({ messages: messages2, supportsTools })
|
||||
|
||||
return {
|
||||
messages: messages4 as any,
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ const _sendOpenAICompatibleChat = ({ messages: messages_, onText, onFinalMessage
|
|||
|
||||
const { providerReasoningIOSettings } = getProviderCapabilities(providerName)
|
||||
|
||||
const { messages } = prepareMessages({ messages: messages_, aiInstructions, supportsSystemMessage, supportsTools, supportsAnthropicContent: false }) // can change supportsAnthropicContent if e.g. OpenRouter starts supporting anthropic extended thinking
|
||||
const { messages } = prepareMessages({ messages: messages_, aiInstructions, supportsSystemMessage, supportsTools })
|
||||
const tools = (supportsTools && ((tools_?.length ?? 0) !== 0)) ? tools_?.map(tool => toOpenAICompatibleTool(tool)) : undefined
|
||||
|
||||
const includeInPayload = canIOReasoning ? providerReasoningIOSettings?.input?.includeInPayload || {} : {}
|
||||
|
|
@ -280,7 +280,7 @@ const toAnthropicTool = (toolInfo: InternalToolInfo) => {
|
|||
} satisfies Anthropic.Messages.Tool
|
||||
}
|
||||
|
||||
const toolCallsFrom_AnthropicContent = (content: Anthropic.Messages.ContentBlock[]): ToolCallsFrom_ReturnType => {
|
||||
const toolCallsFrom_Anthropic = (content: Anthropic.Messages.ContentBlock[]): ToolCallsFrom_ReturnType => {
|
||||
return content.map(c => {
|
||||
if (c.type !== 'tool_use') return null
|
||||
if (!isAToolName(c.name)) return null
|
||||
|
|
@ -301,7 +301,10 @@ const sendAnthropicChat = ({ messages: messages_, providerName, onText, onFinalM
|
|||
reasoningBudget,
|
||||
} = getModelSelectionState(providerName, modelName_, optionsOfModelSelection) // user's modelName_ here
|
||||
|
||||
const { messages, separateSystemMessageStr } = prepareMessages({ messages: messages_, aiInstructions, supportsSystemMessage, supportsTools, supportsAnthropicContent: true })
|
||||
const { messages, separateSystemMessageStr } = prepareMessages({ messages: messages_, aiInstructions, supportsSystemMessage, supportsTools })
|
||||
|
||||
|
||||
console.log('MESSAGES!!!!', JSON.stringify(messages, null, 5))
|
||||
|
||||
const thisConfig = settingsOfProvider.anthropic
|
||||
const anthropic = new Anthropic({ apiKey: thisConfig.apiKey, dangerouslyAllowBrowser: true });
|
||||
|
|
@ -370,8 +373,8 @@ const sendAnthropicChat = ({ messages: messages_, providerName, onText, onFinalM
|
|||
|
||||
// on done - (or when error/fail) - this is called AFTER last streamEvent
|
||||
stream.on('finalMessage', (response) => {
|
||||
const toolCalls = toolCallsFrom_AnthropicContent(response.content)
|
||||
onFinalMessage({ fullText, fullReasoning, toolCalls, rawAnthropicAssistantContent: response.content as any })
|
||||
const toolCalls = toolCallsFrom_Anthropic(response.content)
|
||||
onFinalMessage({ fullText, fullReasoning, toolCalls })
|
||||
})
|
||||
// on error
|
||||
stream.on('error', (error) => {
|
||||
|
|
@ -494,6 +497,11 @@ export const sendLLMMessageToProviderImplementation = {
|
|||
sendFIM: null,
|
||||
list: null,
|
||||
},
|
||||
// mistral: {
|
||||
// sendChat: , // TODO
|
||||
// sendFIM: , // TODO // https://docs.mistral.ai/api/#tag/fim
|
||||
// list: null,
|
||||
// },
|
||||
ollama: {
|
||||
sendChat: (params) => _sendOpenAICompatibleChat(params),
|
||||
sendFIM: sendOllamaFIM,
|
||||
|
|
|
|||
Loading…
Reference in a new issue