import { Anthropic } from "@anthropic-ai/sdk" import * as vscode from "vscode" /** * Safely converts a value into a plain object. */ function asObjectSafe(value: any): object { // Handle null/undefined if (!value) { return {} } try { // Handle strings that might be JSON if (typeof value === "string") { return JSON.parse(value) } // Handle pre-existing objects if (typeof value === "object") { return Object.assign({}, value) } return {} } catch (error) { console.warn("Roo Code : Failed to parse object:", error) return {} } } export function convertToVsCodeLmMessages( anthropicMessages: Anthropic.Messages.MessageParam[], ): vscode.LanguageModelChatMessage[] { const vsCodeLmMessages: vscode.LanguageModelChatMessage[] = [] for (const anthropicMessage of anthropicMessages) { // Handle simple string messages if (typeof anthropicMessage.content === "string") { vsCodeLmMessages.push( anthropicMessage.role === "assistant" ? vscode.LanguageModelChatMessage.Assistant(anthropicMessage.content) : vscode.LanguageModelChatMessage.User(anthropicMessage.content), ) continue } // Handle complex message structures switch (anthropicMessage.role) { case "user": { const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce<{ nonToolMessages: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[] toolMessages: Anthropic.ToolResultBlockParam[] }>( (acc, part) => { if (part.type === "tool_result") { acc.toolMessages.push(part) } else if (part.type === "text" || part.type === "image") { acc.nonToolMessages.push(part) } return acc }, { nonToolMessages: [], toolMessages: [] }, ) // Process tool messages first then non-tool messages const contentParts = [ // Convert tool messages to ToolResultParts ...toolMessages.map((toolMessage) => { // Process tool result content into TextParts const toolContentParts: vscode.LanguageModelTextPart[] = typeof toolMessage.content === "string" ? [new vscode.LanguageModelTextPart(toolMessage.content)] : (toolMessage.content?.map((part) => { if (part.type === "image") { return new vscode.LanguageModelTextPart( `[Image (${part.source?.type || "Unknown source-type"}): ${part.source?.media_type || "unknown media-type"} not supported by VSCode LM API]`, ) } return new vscode.LanguageModelTextPart(part.text) }) ?? [new vscode.LanguageModelTextPart("")]) return new vscode.LanguageModelToolResultPart(toolMessage.tool_use_id, toolContentParts) }), // Convert non-tool messages to TextParts after tool messages ...nonToolMessages.map((part) => { if (part.type === "image") { return new vscode.LanguageModelTextPart( `[Image (${part.source?.type || "Unknown source-type"}): ${part.source?.media_type || "unknown media-type"} not supported by VSCode LM API]`, ) } return new vscode.LanguageModelTextPart(part.text) }), ] // Add single user message with all content parts vsCodeLmMessages.push(vscode.LanguageModelChatMessage.User(contentParts)) break } case "assistant": { const { nonToolMessages, toolMessages } = anthropicMessage.content.reduce<{ nonToolMessages: (Anthropic.TextBlockParam | Anthropic.ImageBlockParam)[] toolMessages: Anthropic.ToolUseBlockParam[] }>( (acc, part) => { if (part.type === "tool_use") { acc.toolMessages.push(part) } else if (part.type === "text" || part.type === "image") { acc.nonToolMessages.push(part) } return acc }, { nonToolMessages: [], toolMessages: [] }, ) // Process tool messages first then non-tool messages const contentParts = [ // Convert tool messages to ToolCallParts first ...toolMessages.map( (toolMessage) => new vscode.LanguageModelToolCallPart( toolMessage.id, toolMessage.name, asObjectSafe(toolMessage.input), ), ), // Convert non-tool messages to TextParts after tool messages ...nonToolMessages.map((part) => { if (part.type === "image") { return new vscode.LanguageModelTextPart("[Image generation not supported by VSCode LM API]") } return new vscode.LanguageModelTextPart(part.text) }), ] // Add the assistant message to the list of messages vsCodeLmMessages.push(vscode.LanguageModelChatMessage.Assistant(contentParts)) break } } } return vsCodeLmMessages } export function convertToAnthropicRole(vsCodeLmMessageRole: vscode.LanguageModelChatMessageRole): string | null { switch (vsCodeLmMessageRole) { case vscode.LanguageModelChatMessageRole.Assistant: return "assistant" case vscode.LanguageModelChatMessageRole.User: return "user" default: return null } }