@@ -6,20 +6,28 @@
import { loggerService } from '@logger'
import { isImageEnhancementModel , isVisionModel } from '@renderer/config/models'
import type { Message , Model } from '@renderer/types'
import type { FileMessageBlock , ImageMessageBlock , ThinkingMessageBlock } from '@renderer/types/newMessage'
import type {
FileMessageBlock ,
ImageMessageBlock ,
ThinkingMessageBlock ,
ToolMessageBlock
} from '@renderer/types/newMessage'
import {
findFileBlocks ,
findImageBlocks ,
findThinkingBlocks ,
findToolBlocks ,
getMainTextContent
} from '@renderer/utils/messageUtils/find'
import type {
AssistantModelMessage ,
AssistantContent ,
FilePart ,
ImagePart ,
ModelMessage ,
SystemModelMessage ,
TextPart ,
ToolCallPart ,
ToolResultPart ,
UserModelMessage
} from 'ai'
@@ -40,10 +48,11 @@ export async function convertMessageToSdkParam(
const fileBlocks = findFileBlocks ( message )
const imageBlocks = findImageBlocks ( message )
const reasoningBlocks = findThinkingBlocks ( message )
const toolBlocks = findToolBlocks ( message )
if ( message . role === 'user' || message . role === 'system' ) {
return convertMessageToUserModelMessage ( content , fileBlocks , imageBlocks , isVisionModel , model )
} else {
return convertMessageToAssistantMode lMessage ( content , fileBlocks , reasoningBlocks , model )
return convertMessageToAssistantAndToo lMessages ( content , fileBlocks , toolBlocks , reasoningBlocks , model )
}
}
@@ -147,30 +156,65 @@ async function convertMessageToUserModelMessage(
}
}
/**
* 转换为助手模型消息
*/
async function convertMessageToAssistantModelMessage (
function convertToolBlockToToolCallPart ( toolBlock : ToolMessageBlock ) : ToolCallPart {
return {
type : 'tool-call' ,
toolCallId : toolBlock.toolId ,
toolName : toolBlock.toolName || 'unknown' ,
input : toolBlock.arguments || { }
}
}
function convertToolBlockToToolResultPart ( toolBlock : ToolMessageBlock ) : ToolResultPart {
const content = toolBlock . content
let output : ToolResultPart [ 'output' ]
if ( content === undefined || content === null ) {
output = { type : 'text' , value : '' }
} else if ( typeof content === 'string' ) {
output = { type : 'text' , value : content }
} else {
output = { type : 'json' , value : JSON.parse ( JSON . stringify ( content ) ) }
}
return {
type : 'tool-result' ,
toolCallId : toolBlock.toolId ,
toolName : toolBlock.toolName || 'unknown' ,
output
}
}
function hasToolResult ( toolBlock : ToolMessageBlock ) : boolean {
return toolBlock . content !== undefined && toolBlock . content !== null
}
async function convertMessageToAssistantAndToolMessages (
content : string ,
fileBlocks : FileMessageBlock [ ] ,
toolBlocks : ToolMessageBlock [ ] ,
thinkingBlocks : ThinkingMessageBlock [ ] ,
model? : Model
) : Promise < Assistant ModelMessage> {
const parts : Array < TextPart | FilePart > = [ ]
) : Promise < ModelMessage | ModelMessage[ ] > {
const assistantParts : AssistantContent = [ ]
// 添加文本内容
if ( content ) {
p arts. push ( { type : 'text' , text : content } )
assistantP arts. push ( { type : 'text' , text : content } )
}
// 添加推理内容
for ( const thinkingBlock of thinkingBlocks ) {
p arts. push ( { type : 'text ' , text : thinkingBlock.content } )
assistantP arts. push ( { type : 'reasoning ' , text : thinkingBlock.content } )
}
// 处理文件
for ( const fileBlock of fileBlocks ) {
// 优先尝试原生文件支持( PDF等)
if ( model ) {
const filePart = await convertFileBlockToFilePart ( fileBlock , model )
if ( filePart ) {
p arts. push ( filePart )
assistantP arts. push ( filePart )
continue
}
}
@@ -178,13 +222,33 @@ async function convertMessageToAssistantModelMessage(
// 回退到文本处理
const textPart = await convertFileBlockToTextPart ( fileBlock )
if ( textPart ) {
p arts. push ( textPart )
assistantP arts. push ( textPart )
}
}
// 如果没有 tool blocks, 直接返回 assistant 消息
if ( toolBlocks . length === 0 ) {
return {
role : 'assistant' ,
content : assistantParts
}
}
// 处理 tool blocks
// 将 tool calls 和 tool results 都添加到 assistant 消息的 content 中
for ( const toolBlock of toolBlocks ) {
// 添加 tool call
assistantParts . push ( convertToolBlockToToolCallPart ( toolBlock ) )
// 如果有结果,添加 tool result
if ( hasToolResult ( toolBlock ) ) {
assistantParts . push ( convertToolBlockToToolResultPart ( toolBlock ) )
}
}
return {
role : 'assistant' ,
content : p arts
content : assistantP arts
}
}