remove rawAnthropicContent

This commit is contained in:
Andrew Pareles 2025-03-07 19:37:33 -08:00
parent 5ad5fe7014
commit 2b7df8c604
6 changed files with 49 additions and 68 deletions

View file

@ -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)}`

View file

@ -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 }) => {

View file

@ -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>

View file

@ -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 = {

View file

@ -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,

View file

@ -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,