fix: history messages toolcalls

This commit is contained in:
zxhlyh
2026-01-20 17:36:57 +08:00
parent 33e96fd11a
commit 0e66b51ca0
5 changed files with 113 additions and 12 deletions

View File

@ -42,7 +42,7 @@ import {
import { TransferMethod } from '@/types/app'
import { addFileInfos, sortAgentSorts } from '../../../tools/utils'
import { CONVERSATION_ID_INFO } from '../constants'
import { buildChatItemTree, getProcessedSystemVariablesFromUrlParams, getRawInputsFromUrlParams, getRawUserVariablesFromUrlParams } from '../utils'
import { buildChatItemTree, buildToolCallsFromHistorySequence, getProcessedSystemVariablesFromUrlParams, getRawInputsFromUrlParams, getRawUserVariablesFromUrlParams } from '../utils'
function getFormattedChatList(messages: any[]) {
const newChatList: ChatItem[] = []
@ -58,7 +58,8 @@ function getFormattedChatList(messages: any[]) {
const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || []
newChatList.push({
id: item.id,
content: item.answer,
content: buildToolCallsFromHistorySequence(item).message,
toolCalls: buildToolCallsFromHistorySequence(item).toolCalls,
agent_thoughts: addFileInfos(item.agent_thoughts ? sortAgentSorts(item.agent_thoughts) : item.agent_thoughts, item.message_files),
feedback: item.feedback,
isAnswer: true,

View File

@ -2,7 +2,7 @@ import type { FileEntity } from '@/app/components/base/file-uploader/types'
import type { TypeWithI18N } from '@/app/components/header/account-setting/model-provider-page/declarations'
import type { InputVarType } from '@/app/components/workflow/types'
import type { Annotation, MessageRating } from '@/models/log'
import type { FileResponse, ToolCallItem } from '@/types/workflow'
import type { FileResponse, IconObject, ToolCallItem } from '@/types/workflow'
export type MessageMore = {
time: string
@ -148,3 +148,39 @@ export type InputForm = {
hide: boolean
[key: string]: any
}
export type ToolCallDetail = {
id: string
name: string
arguments: string
result: string
elapsed_time?: number
icon?: string | IconObject
icon_dark?: string | IconObject
}
export type SequenceSegment = | { type: 'content', start: number, end: number }
| { type: 'reasoning', index: number }
| { type: 'tool_call', index: number }
export type GenerationDetail = {
reasoning_content?: string[]
tool_calls?: ToolCallDetail[]
sequence?: SequenceSegment[]
}
export type ChatMessageRes = {
id: string
parent_message_id?: string | null
workflow_run_id?: string
answer?: string
query: string
message_files: {
id: string
type: string
url: string
belongs_to: string
}[]
feedback?: FeedbackType
metadata?: Metadata
generation_detail?: GenerationDetail
}

View File

@ -1,5 +1,7 @@
import type { IChatItem } from './chat/type'
import type { ChatMessageRes, IChatItem } from './chat/type'
import type { ChatItem, ChatItemInTree } from './types'
import type { ToolCallItem } from '@/types/workflow'
import { v4 as uuidV4 } from 'uuid'
import { UUID_NIL } from './constants'
async function decodeBase64AndDecompress(base64String: string) {
@ -232,8 +234,66 @@ function getThreadMessages(tree: ChatItemInTree[], targetMessageId?: string): Ch
return ret
}
const buildToolCallsFromHistorySequence = (message: ChatMessageRes): {
toolCalls: ToolCallItem[]
message: string
} => {
const { answer, generation_detail } = message
if (!generation_detail) {
return { toolCalls: [], message: answer || '' }
}
const { reasoning_content = [], tool_calls = [], sequence = [] } = generation_detail
const toolCalls: ToolCallItem[] = []
let answerMessage = ''
sequence.forEach((segment) => {
switch (segment.type) {
case 'content': {
const text = answer?.substring(segment.start, segment.end)
if (text?.trim()) {
answerMessage += text
}
break
}
case 'reasoning': {
const reasoning = reasoning_content[segment.index]
if (reasoning) {
toolCalls.push({
id: uuidV4(),
type: 'thought',
thoughtOutput: reasoning,
thoughtCompleted: true,
})
}
break
}
case 'tool_call': {
const toolCall = tool_calls[segment.index]
if (toolCall) {
toolCalls.push({
id: uuidV4(),
type: 'tool',
toolName: toolCall.name,
toolArguments: toolCall.arguments,
toolOutput: toolCall.result,
toolDuration: toolCall.elapsed_time,
toolIcon: toolCall.icon,
toolIconDark: toolCall.icon_dark,
})
}
break
}
}
})
return { toolCalls, message: answerMessage || '' }
}
export {
buildChatItemTree,
buildToolCallsFromHistorySequence,
getLastAnswer,
getProcessedInputsFromUrlParams,
getProcessedSystemVariablesFromUrlParams,

View File

@ -1,4 +1,7 @@
import type { IChatItem } from '@/app/components/base/chat/chat/type'
import type {
ChatMessageRes,
IChatItem,
} from '@/app/components/base/chat/chat/type'
import type { ChatItem, ChatItemInTree } from '@/app/components/base/chat/types'
import { RiCloseLine } from '@remixicon/react'
import {
@ -9,7 +12,7 @@ import {
} from 'react'
import { useStore as useAppStore } from '@/app/components/app/store'
import Chat from '@/app/components/base/chat/chat'
import { buildChatItemTree, getThreadMessages } from '@/app/components/base/chat/utils'
import { buildChatItemTree, buildToolCallsFromHistorySequence, getThreadMessages } from '@/app/components/base/chat/utils'
import { getProcessedFilesFromResponse } from '@/app/components/base/file-uploader/utils'
import Loading from '@/app/components/base/loading'
import { fetchConversationMessages } from '@/service/debug'
@ -21,10 +24,10 @@ import {
import { formatWorkflowRunIdentifier } from '../../utils'
import UserInput from './user-input'
function getFormattedChatList(messages: any[]) {
function getFormattedChatList(messages: ChatMessageRes[]) {
const res: ChatItem[] = []
messages.forEach((item: any) => {
const questionFiles = item.message_files?.filter((file: any) => file.belongs_to === 'user') || []
messages.forEach((item: ChatMessageRes) => {
const questionFiles = item.message_files?.filter(file => file.belongs_to === 'user') || []
res.push({
id: `question-${item.id}`,
content: item.query,
@ -35,7 +38,8 @@ function getFormattedChatList(messages: any[]) {
const answerFiles = item.message_files?.filter((file: any) => file.belongs_to === 'assistant') || []
res.push({
id: item.id,
content: item.answer,
content: buildToolCallsFromHistorySequence(item).message,
toolCalls: buildToolCallsFromHistorySequence(item).toolCalls,
feedback: item.feedback,
isAnswer: true,
citation: item.metadata?.retriever_resources,
@ -63,7 +67,7 @@ const ChatRecord = () => {
setFetched(false)
const res = await fetchConversationMessages(appDetail.id, currentConversationID)
const newAllChatItems = getFormattedChatList((res as any).data)
const newAllChatItems = getFormattedChatList((res as any).data as ChatMessageRes[])
const tree = buildChatItemTree(newAllChatItems)
setChatItemTree(tree)