mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-24 10:40:07 +08:00
fix: Ensure tool call results are included in the conversation context (#7463)
* refactor(aiCore): 统一消息内容处理逻辑,优化工具调用结果显示 重构各AI客户端的消息内容处理逻辑,使用新的getContentWithTools函数统一处理 将blocks参数重命名为block以符合语义 使用MessageBlockType枚举替代硬编码字符串 * fix(aiCore): 修复工具调用结果消息的格式问题 调整工具调用结果消息的换行格式,使其显示更清晰 * refactor(aiCore): 将getContentWithTools工具函数移至messageUtils模块 重构代码,将getContentWithTools函数从aiCore/clients/utils.ts移动到messageUtils/find.ts模块中 统一消息处理工具函数的存放位置,提高代码组织性 删除不再使用的utils.ts文件 * refactor(aiCore): 统一使用getMessageContent获取消息内容 将各API客户端中直接调用getContentWithTools改为通过基类的getMessageContent方法获取消息内容,保持行为一致性 * fix(find): 移除冗余的条件判断
This commit is contained in:
parent
c37176fe98
commit
68d0b13a64
@ -37,7 +37,7 @@ import {
|
||||
} from '@renderer/types/sdk'
|
||||
import { isJSON, parseJSON } from '@renderer/utils'
|
||||
import { addAbortController, removeAbortController } from '@renderer/utils/abortController'
|
||||
import { findFileBlocks, getMainTextContent } from '@renderer/utils/messageUtils/find'
|
||||
import { findFileBlocks, getContentWithTools, getMainTextContent } from '@renderer/utils/messageUtils/find'
|
||||
import { defaultTimeout } from '@shared/config/constant'
|
||||
import Logger from 'electron-log/renderer'
|
||||
import { isEmpty } from 'lodash'
|
||||
@ -209,7 +209,7 @@ export abstract class BaseApiClient<
|
||||
}
|
||||
|
||||
public async getMessageContent(message: Message): Promise<string> {
|
||||
const content = getMainTextContent(message)
|
||||
const content = getContentWithTools(message)
|
||||
if (isEmpty(content)) {
|
||||
return ''
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ import {
|
||||
TextDeltaChunk,
|
||||
ThinkingDeltaChunk
|
||||
} from '@renderer/types/chunk'
|
||||
import type { Message } from '@renderer/types/newMessage'
|
||||
import { type Message } from '@renderer/types/newMessage'
|
||||
import {
|
||||
AnthropicSdkMessageParam,
|
||||
AnthropicSdkParams,
|
||||
|
||||
@ -243,6 +243,7 @@ export class GeminiAPIClient extends BaseApiClient<
|
||||
private async convertMessageToSdkParam(message: Message): Promise<Content> {
|
||||
const role = message.role === 'user' ? 'user' : 'model'
|
||||
const parts: Part[] = [{ text: await this.getMessageContent(message) }]
|
||||
|
||||
// Add any generated images from previous responses
|
||||
const imageBlocks = findImageBlocks(message)
|
||||
for (const imageBlock of imageBlocks) {
|
||||
|
||||
@ -8,7 +8,7 @@ interface Props {
|
||||
}
|
||||
|
||||
const ToolBlock: React.FC<Props> = ({ block }) => {
|
||||
return <MessageTools blocks={block} />
|
||||
return <MessageTools block={block} />
|
||||
}
|
||||
|
||||
export default React.memo(ToolBlock)
|
||||
|
||||
@ -8,17 +8,17 @@ import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
interface Props {
|
||||
blocks: ToolMessageBlock
|
||||
block: ToolMessageBlock
|
||||
}
|
||||
|
||||
const MessageTools: FC<Props> = ({ blocks }) => {
|
||||
const MessageTools: FC<Props> = ({ block }) => {
|
||||
const [activeKeys, setActiveKeys] = useState<string[]>([])
|
||||
const [copiedMap, setCopiedMap] = useState<Record<string, boolean>>({})
|
||||
const [expandedResponse, setExpandedResponse] = useState<{ content: string; title: string } | null>(null)
|
||||
const { t } = useTranslation()
|
||||
const { messageFont, fontSize } = useSettings()
|
||||
|
||||
const toolResponse = blocks.metadata?.rawMcpToolResponse
|
||||
const toolResponse = block.metadata?.rawMcpToolResponse
|
||||
|
||||
const resultString = useMemo(() => {
|
||||
try {
|
||||
|
||||
@ -195,13 +195,50 @@ export const findTranslationBlocks = (message: Message): TranslationMessageBlock
|
||||
const translationBlocks: TranslationMessageBlock[] = []
|
||||
for (const blockId of message.blocks) {
|
||||
const block = messageBlocksSelectors.selectById(state, blockId)
|
||||
if (block && block.type === 'translation') {
|
||||
if (block && block.type === MessageBlockType.TRANSLATION) {
|
||||
translationBlocks.push(block as TranslationMessageBlock)
|
||||
}
|
||||
}
|
||||
return translationBlocks
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造带工具调用结果的消息内容
|
||||
* @param blocks
|
||||
* @returns
|
||||
*/
|
||||
export function getContentWithTools(message: Message) {
|
||||
const blocks = findAllBlocks(message)
|
||||
let constructedContent = ''
|
||||
for (const block of blocks) {
|
||||
if (block.type === MessageBlockType.MAIN_TEXT || block.type === MessageBlockType.TOOL) {
|
||||
if (block.type === MessageBlockType.MAIN_TEXT) {
|
||||
constructedContent += block.content
|
||||
} else if (block.type === MessageBlockType.TOOL) {
|
||||
// 如果是工具调用结果,为其添加文本消息
|
||||
let resultString =
|
||||
'\n\nAssistant called a tool.\nTool Name:' +
|
||||
block.metadata?.rawMcpToolResponse?.tool.name +
|
||||
'\nTool call result: \n```json\n'
|
||||
try {
|
||||
resultString += JSON.stringify(
|
||||
{
|
||||
params: block.metadata?.rawMcpToolResponse?.arguments,
|
||||
response: block.metadata?.rawMcpToolResponse?.response
|
||||
},
|
||||
null,
|
||||
2
|
||||
)
|
||||
} catch (e) {
|
||||
resultString += 'Invalid Result'
|
||||
}
|
||||
constructedContent += resultString + '\n```\n\n'
|
||||
}
|
||||
}
|
||||
}
|
||||
return constructedContent
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the WebSearchMessageBlock associated with a given message.
|
||||
* Assumes only one web search block per message.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user