mirror of
https://gitee.com/dify_ai/dify.git
synced 2024-12-01 10:48:37 +08:00
parent
9b8861e3e1
commit
e70482dfc0
@ -11,8 +11,9 @@ const Log: FC<LogProps> = ({
|
|||||||
logItem,
|
logItem,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { setCurrentLogItem, setShowPromptLogModal, setShowMessageLogModal } = useAppStore()
|
const { setCurrentLogItem, setShowPromptLogModal, setShowAgentLogModal, setShowMessageLogModal } = useAppStore()
|
||||||
const { workflow_run_id: runID } = logItem
|
const { workflow_run_id: runID, agent_thoughts } = logItem
|
||||||
|
const isAgent = agent_thoughts && agent_thoughts.length > 0
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -23,12 +24,14 @@ const Log: FC<LogProps> = ({
|
|||||||
setCurrentLogItem(logItem)
|
setCurrentLogItem(logItem)
|
||||||
if (runID)
|
if (runID)
|
||||||
setShowMessageLogModal(true)
|
setShowMessageLogModal(true)
|
||||||
|
else if (isAgent)
|
||||||
|
setShowAgentLogModal(true)
|
||||||
else
|
else
|
||||||
setShowPromptLogModal(true)
|
setShowPromptLogModal(true)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<File02 className='mr-1 w-4 h-4' />
|
<File02 className='mr-1 w-4 h-4' />
|
||||||
<div className='text-xs leading-4'>{runID ? t('appLog.viewLog') : t('appLog.promptLog')}</div>
|
<div className='text-xs leading-4'>{runID ? t('appLog.viewLog') : isAgent ? t('appLog.agentLog') : t('appLog.promptLog')}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,9 @@ export type IChatItem = {
|
|||||||
agent_thoughts?: ThoughtItem[]
|
agent_thoughts?: ThoughtItem[]
|
||||||
message_files?: VisionFile[]
|
message_files?: VisionFile[]
|
||||||
workflow_run_id?: string
|
workflow_run_id?: string
|
||||||
|
// for agent log
|
||||||
|
conversationId?: string
|
||||||
|
input?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export type MessageEnd = {
|
export type MessageEnd = {
|
||||||
|
@ -473,7 +473,7 @@ const Debug: FC<IDebug> = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{showPromptLogModal && (
|
{mode === AppType.completion && showPromptLogModal && (
|
||||||
<PromptLogModal
|
<PromptLogModal
|
||||||
width={width}
|
width={width}
|
||||||
currentLogItem={currentLogItem}
|
currentLogItem={currentLogItem}
|
||||||
|
@ -35,6 +35,7 @@ import ModelName from '@/app/components/header/account-setting/model-provider-pa
|
|||||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||||
import TextGeneration from '@/app/components/app/text-generate/item'
|
import TextGeneration from '@/app/components/app/text-generate/item'
|
||||||
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
|
import { addFileInfos, sortAgentSorts } from '@/app/components/tools/utils'
|
||||||
|
import AgentLogModal from '@/app/components/base/agent-log-modal'
|
||||||
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
||||||
import MessageLogModal from '@/app/components/base/message-log-modal'
|
import MessageLogModal from '@/app/components/base/message-log-modal'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
@ -76,7 +77,7 @@ const PARAM_MAP = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Format interface data for easy display
|
// Format interface data for easy display
|
||||||
const getFormattedChatList = (messages: ChatMessage[]) => {
|
const getFormattedChatList = (messages: ChatMessage[], conversationId: string) => {
|
||||||
const newChatList: IChatItem[] = []
|
const newChatList: IChatItem[] = []
|
||||||
messages.forEach((item: ChatMessage) => {
|
messages.forEach((item: ChatMessage) => {
|
||||||
newChatList.push({
|
newChatList.push({
|
||||||
@ -107,6 +108,11 @@ const getFormattedChatList = (messages: ChatMessage[]) => {
|
|||||||
: []),
|
: []),
|
||||||
],
|
],
|
||||||
workflow_run_id: item.workflow_run_id,
|
workflow_run_id: item.workflow_run_id,
|
||||||
|
conversationId,
|
||||||
|
input: {
|
||||||
|
inputs: item.inputs,
|
||||||
|
query: item.query,
|
||||||
|
},
|
||||||
more: {
|
more: {
|
||||||
time: dayjs.unix(item.created_at).format('hh:mm A'),
|
time: dayjs.unix(item.created_at).format('hh:mm A'),
|
||||||
tokens: item.answer_tokens + item.message_tokens,
|
tokens: item.answer_tokens + item.message_tokens,
|
||||||
@ -148,7 +154,7 @@ type IDetailPanel<T> = {
|
|||||||
|
|
||||||
function DetailPanel<T extends ChatConversationFullDetailResponse | CompletionConversationFullDetailResponse>({ detail, onFeedback }: IDetailPanel<T>) {
|
function DetailPanel<T extends ChatConversationFullDetailResponse | CompletionConversationFullDetailResponse>({ detail, onFeedback }: IDetailPanel<T>) {
|
||||||
const { onClose, appDetail } = useContext(DrawerContext)
|
const { onClose, appDetail } = useContext(DrawerContext)
|
||||||
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showMessageLogModal, setShowMessageLogModal } = useAppStore()
|
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal, showMessageLogModal, setShowMessageLogModal } = useAppStore()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [items, setItems] = React.useState<IChatItem[]>([])
|
const [items, setItems] = React.useState<IChatItem[]>([])
|
||||||
const [hasMore, setHasMore] = useState(true)
|
const [hasMore, setHasMore] = useState(true)
|
||||||
@ -172,7 +178,7 @@ function DetailPanel<T extends ChatConversationFullDetailResponse | CompletionCo
|
|||||||
const varValues = messageRes.data[0].inputs
|
const varValues = messageRes.data[0].inputs
|
||||||
setVarValues(varValues)
|
setVarValues(varValues)
|
||||||
}
|
}
|
||||||
const newItems = [...getFormattedChatList(messageRes.data), ...items]
|
const newItems = [...getFormattedChatList(messageRes.data, detail.id), ...items]
|
||||||
if (messageRes.has_more === false && detail?.model_config?.configs?.introduction) {
|
if (messageRes.has_more === false && detail?.model_config?.configs?.introduction) {
|
||||||
newItems.unshift({
|
newItems.unshift({
|
||||||
id: 'introduction',
|
id: 'introduction',
|
||||||
@ -401,6 +407,16 @@ function DetailPanel<T extends ChatConversationFullDetailResponse | CompletionCo
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{showAgentLogModal && (
|
||||||
|
<AgentLogModal
|
||||||
|
width={width}
|
||||||
|
currentLogItem={currentLogItem}
|
||||||
|
onCancel={() => {
|
||||||
|
setCurrentLogItem()
|
||||||
|
setShowAgentLogModal(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{showMessageLogModal && (
|
{showMessageLogModal && (
|
||||||
<MessageLogModal
|
<MessageLogModal
|
||||||
width={width}
|
width={width}
|
||||||
@ -607,7 +623,7 @@ const ConversationList: FC<IConversationList> = ({ logs, appDetail, onRefresh })
|
|||||||
onClose={onCloseDrawer}
|
onClose={onCloseDrawer}
|
||||||
mask={isMobile}
|
mask={isMobile}
|
||||||
footer={null}
|
footer={null}
|
||||||
panelClassname='mt-16 mx-2 sm:mr-2 mb-3 !p-0 !max-w-[640px] rounded-xl'
|
panelClassname='mt-16 mx-2 sm:mr-2 mb-4 !p-0 !max-w-[640px] rounded-xl'
|
||||||
>
|
>
|
||||||
<DrawerContext.Provider value={{
|
<DrawerContext.Provider value={{
|
||||||
onClose: onCloseDrawer,
|
onClose: onCloseDrawer,
|
||||||
|
@ -7,6 +7,7 @@ type State = {
|
|||||||
appSidebarExpand: string
|
appSidebarExpand: string
|
||||||
currentLogItem?: IChatItem
|
currentLogItem?: IChatItem
|
||||||
showPromptLogModal: boolean
|
showPromptLogModal: boolean
|
||||||
|
showAgentLogModal: boolean
|
||||||
showMessageLogModal: boolean
|
showMessageLogModal: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,6 +16,7 @@ type Action = {
|
|||||||
setAppSiderbarExpand: (state: string) => void
|
setAppSiderbarExpand: (state: string) => void
|
||||||
setCurrentLogItem: (item?: IChatItem) => void
|
setCurrentLogItem: (item?: IChatItem) => void
|
||||||
setShowPromptLogModal: (showPromptLogModal: boolean) => void
|
setShowPromptLogModal: (showPromptLogModal: boolean) => void
|
||||||
|
setShowAgentLogModal: (showAgentLogModal: boolean) => void
|
||||||
setShowMessageLogModal: (showMessageLogModal: boolean) => void
|
setShowMessageLogModal: (showMessageLogModal: boolean) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,6 +29,8 @@ export const useStore = create<State & Action>(set => ({
|
|||||||
setCurrentLogItem: currentLogItem => set(() => ({ currentLogItem })),
|
setCurrentLogItem: currentLogItem => set(() => ({ currentLogItem })),
|
||||||
showPromptLogModal: false,
|
showPromptLogModal: false,
|
||||||
setShowPromptLogModal: showPromptLogModal => set(() => ({ showPromptLogModal })),
|
setShowPromptLogModal: showPromptLogModal => set(() => ({ showPromptLogModal })),
|
||||||
|
showAgentLogModal: false,
|
||||||
|
setShowAgentLogModal: showAgentLogModal => set(() => ({ showAgentLogModal })),
|
||||||
showMessageLogModal: false,
|
showMessageLogModal: false,
|
||||||
setShowMessageLogModal: showMessageLogModal => set(() => ({ showMessageLogModal })),
|
setShowMessageLogModal: showMessageLogModal => set(() => ({ showMessageLogModal })),
|
||||||
}))
|
}))
|
||||||
|
132
web/app/components/base/agent-log-modal/detail.tsx
Normal file
132
web/app/components/base/agent-log-modal/detail.tsx
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||||
|
import { useContext } from 'use-context-selector'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { flatten, uniq } from 'lodash-es'
|
||||||
|
import cn from 'classnames'
|
||||||
|
import ResultPanel from './result'
|
||||||
|
import TracingPanel from './tracing'
|
||||||
|
import { ToastContext } from '@/app/components/base/toast'
|
||||||
|
import Loading from '@/app/components/base/loading'
|
||||||
|
import { fetchAgentLogDetail } from '@/service/log'
|
||||||
|
import type { AgentIteration, AgentLogDetailResponse } from '@/models/log'
|
||||||
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
import type { IChatItem } from '@/app/components/app/chat/type'
|
||||||
|
|
||||||
|
export type AgentLogDetailProps = {
|
||||||
|
activeTab?: 'DETAIL' | 'TRACING'
|
||||||
|
conversationID: string
|
||||||
|
log: IChatItem
|
||||||
|
messageID: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const AgentLogDetail: FC<AgentLogDetailProps> = ({
|
||||||
|
activeTab = 'DETAIL',
|
||||||
|
conversationID,
|
||||||
|
messageID,
|
||||||
|
log,
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { notify } = useContext(ToastContext)
|
||||||
|
const [currentTab, setCurrentTab] = useState<string>(activeTab)
|
||||||
|
const { appDetail } = useAppStore()
|
||||||
|
const [loading, setLoading] = useState<boolean>(true)
|
||||||
|
const [runDetail, setRunDetail] = useState<AgentLogDetailResponse>()
|
||||||
|
const [list, setList] = useState<AgentIteration[]>([])
|
||||||
|
|
||||||
|
const tools = useMemo(() => {
|
||||||
|
const res = uniq(flatten(runDetail?.iterations.map((iteration: any) => {
|
||||||
|
return iteration.tool_calls.map((tool: any) => tool.tool_name).filter(Boolean)
|
||||||
|
})).filter(Boolean))
|
||||||
|
return res
|
||||||
|
}, [runDetail])
|
||||||
|
|
||||||
|
const getLogDetail = useCallback(async (appID: string, conversationID: string, messageID: string) => {
|
||||||
|
try {
|
||||||
|
const res = await fetchAgentLogDetail({
|
||||||
|
appID,
|
||||||
|
params: {
|
||||||
|
conversation_id: conversationID,
|
||||||
|
message_id: messageID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
setRunDetail(res)
|
||||||
|
setList(res.iterations)
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
notify({
|
||||||
|
type: 'error',
|
||||||
|
message: `${err}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}, [notify])
|
||||||
|
|
||||||
|
const getData = async (appID: string, conversationID: string, messageID: string) => {
|
||||||
|
setLoading(true)
|
||||||
|
await getLogDetail(appID, conversationID, messageID)
|
||||||
|
setLoading(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const switchTab = async (tab: string) => {
|
||||||
|
setCurrentTab(tab)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// fetch data
|
||||||
|
if (appDetail)
|
||||||
|
getData(appDetail.id, conversationID, messageID)
|
||||||
|
}, [appDetail, conversationID, messageID])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='grow relative flex flex-col'>
|
||||||
|
{/* tab */}
|
||||||
|
<div className='shrink-0 flex items-center px-4 border-b-[0.5px] border-[rgba(0,0,0,0.05)]'>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'mr-6 py-3 border-b-2 border-transparent text-[13px] font-semibold leading-[18px] text-gray-400 cursor-pointer',
|
||||||
|
currentTab === 'DETAIL' && '!border-[rgb(21,94,239)] text-gray-700',
|
||||||
|
)}
|
||||||
|
onClick={() => switchTab('DETAIL')}
|
||||||
|
>{t('runLog.detail')}</div>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'mr-6 py-3 border-b-2 border-transparent text-[13px] font-semibold leading-[18px] text-gray-400 cursor-pointer',
|
||||||
|
currentTab === 'TRACING' && '!border-[rgb(21,94,239)] text-gray-700',
|
||||||
|
)}
|
||||||
|
onClick={() => switchTab('TRACING')}
|
||||||
|
>{t('runLog.tracing')}</div>
|
||||||
|
</div>
|
||||||
|
{/* panel detal */}
|
||||||
|
<div className={cn('grow bg-white h-0 overflow-y-auto rounded-b-2xl', currentTab !== 'DETAIL' && '!bg-gray-50')}>
|
||||||
|
{loading && (
|
||||||
|
<div className='flex h-full items-center justify-center bg-white'>
|
||||||
|
<Loading />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!loading && currentTab === 'DETAIL' && runDetail && (
|
||||||
|
<ResultPanel
|
||||||
|
inputs={log.input}
|
||||||
|
outputs={log.content}
|
||||||
|
status={runDetail.meta.status}
|
||||||
|
error={runDetail.meta.error}
|
||||||
|
elapsed_time={runDetail.meta.elapsed_time}
|
||||||
|
total_tokens={runDetail.meta.total_tokens}
|
||||||
|
created_at={runDetail.meta.start_time}
|
||||||
|
created_by={runDetail.meta.executor}
|
||||||
|
agentMode={runDetail.meta.agent_mode}
|
||||||
|
tools={tools}
|
||||||
|
iterations={runDetail.iterations.length}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!loading && currentTab === 'TRACING' && (
|
||||||
|
<TracingPanel
|
||||||
|
list={list}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AgentLogDetail
|
61
web/app/components/base/agent-log-modal/index.tsx
Normal file
61
web/app/components/base/agent-log-modal/index.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import type { FC } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import cn from 'classnames'
|
||||||
|
import { useEffect, useRef, useState } from 'react'
|
||||||
|
import { useClickAway } from 'ahooks'
|
||||||
|
import AgentLogDetail from './detail'
|
||||||
|
import { XClose } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
|
import type { IChatItem } from '@/app/components/app/chat/type'
|
||||||
|
|
||||||
|
type AgentLogModalProps = {
|
||||||
|
currentLogItem?: IChatItem
|
||||||
|
width: number
|
||||||
|
onCancel: () => void
|
||||||
|
}
|
||||||
|
const AgentLogModal: FC<AgentLogModalProps> = ({
|
||||||
|
currentLogItem,
|
||||||
|
width,
|
||||||
|
onCancel,
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const ref = useRef(null)
|
||||||
|
const [mounted, setMounted] = useState(false)
|
||||||
|
|
||||||
|
useClickAway(() => {
|
||||||
|
if (mounted)
|
||||||
|
onCancel()
|
||||||
|
}, ref)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setMounted(true)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!currentLogItem || !currentLogItem.conversationId)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn('relative flex flex-col py-3 bg-white border-[0.5px] border-gray-200 rounded-xl shadow-xl z-10')}
|
||||||
|
style={{
|
||||||
|
width: 480,
|
||||||
|
position: 'fixed',
|
||||||
|
top: 56 + 8,
|
||||||
|
left: 8 + (width - 480),
|
||||||
|
bottom: 16,
|
||||||
|
}}
|
||||||
|
ref={ref}
|
||||||
|
>
|
||||||
|
<h1 className='shrink-0 px-4 py-1 text-md font-semibold text-gray-900'>{t('appLog.runDetail.workflowTitle')}</h1>
|
||||||
|
<span className='absolute right-3 top-4 p-1 cursor-pointer z-20' onClick={onCancel}>
|
||||||
|
<XClose className='w-4 h-4 text-gray-500' />
|
||||||
|
</span>
|
||||||
|
<AgentLogDetail
|
||||||
|
conversationID={currentLogItem.conversationId}
|
||||||
|
messageID={currentLogItem.id}
|
||||||
|
log={currentLogItem}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AgentLogModal
|
50
web/app/components/base/agent-log-modal/iteration.tsx
Normal file
50
web/app/components/base/agent-log-modal/iteration.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
'use client'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import cn from 'classnames'
|
||||||
|
import ToolCall from './tool-call'
|
||||||
|
import type { AgentIteration } from '@/models/log'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
isFinal: boolean
|
||||||
|
index: number
|
||||||
|
iterationInfo: AgentIteration
|
||||||
|
}
|
||||||
|
|
||||||
|
const Iteration: FC<Props> = ({ iterationInfo, isFinal, index }) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn('px-4 py-2')}>
|
||||||
|
<div className='flex items-center'>
|
||||||
|
{isFinal && (
|
||||||
|
<div className='shrink-0 mr-3 text-gray-500 text-xs leading-[18px] font-semibold'>{t('appLog.agentLogDetail.finalProcessing')}</div>
|
||||||
|
)}
|
||||||
|
{!isFinal && (
|
||||||
|
<div className='shrink-0 mr-3 text-gray-500 text-xs leading-[18px] font-semibold'>{`${t('appLog.agentLogDetail.iteration').toUpperCase()} ${index}`}</div>
|
||||||
|
)}
|
||||||
|
<div className='grow h-[1px] bg-gradient-to-r from-[#f3f4f6] to-gray-50'></div>
|
||||||
|
</div>
|
||||||
|
<ToolCall
|
||||||
|
isLLM
|
||||||
|
isFinal={isFinal}
|
||||||
|
tokens={iterationInfo.tokens}
|
||||||
|
observation={iterationInfo.tool_raw.outputs}
|
||||||
|
finalAnswer={iterationInfo.thought}
|
||||||
|
toolCall={{
|
||||||
|
status: 'success',
|
||||||
|
tool_icon: null,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{iterationInfo.tool_calls.map((toolCall, index) => (
|
||||||
|
<ToolCall
|
||||||
|
isLLM={false}
|
||||||
|
key={index}
|
||||||
|
toolCall={toolCall}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Iteration
|
126
web/app/components/base/agent-log-modal/result.tsx
Normal file
126
web/app/components/base/agent-log-modal/result.tsx
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import StatusPanel from '@/app/components/workflow/run/status'
|
||||||
|
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||||
|
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||||
|
|
||||||
|
type ResultPanelProps = {
|
||||||
|
status: string
|
||||||
|
elapsed_time?: number
|
||||||
|
total_tokens?: number
|
||||||
|
error?: string
|
||||||
|
inputs?: any
|
||||||
|
outputs?: any
|
||||||
|
created_by?: string
|
||||||
|
created_at?: string
|
||||||
|
agentMode?: string
|
||||||
|
tools?: string[]
|
||||||
|
iterations?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const ResultPanel: FC<ResultPanelProps> = ({
|
||||||
|
status,
|
||||||
|
elapsed_time,
|
||||||
|
total_tokens,
|
||||||
|
error,
|
||||||
|
inputs,
|
||||||
|
outputs,
|
||||||
|
created_by,
|
||||||
|
created_at = 0,
|
||||||
|
agentMode,
|
||||||
|
tools,
|
||||||
|
iterations,
|
||||||
|
}) => {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='bg-white py-2'>
|
||||||
|
<div className='px-4 py-2'>
|
||||||
|
<StatusPanel
|
||||||
|
status='succeeded'
|
||||||
|
time={elapsed_time}
|
||||||
|
tokens={total_tokens}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='px-4 py-2 flex flex-col gap-2'>
|
||||||
|
<CodeEditor
|
||||||
|
readOnly
|
||||||
|
title={<div>INPUT</div>}
|
||||||
|
language={CodeLanguage.json}
|
||||||
|
value={inputs}
|
||||||
|
isJSONStringifyBeauty
|
||||||
|
/>
|
||||||
|
<CodeEditor
|
||||||
|
readOnly
|
||||||
|
title={<div>OUTPUT</div>}
|
||||||
|
language={CodeLanguage.json}
|
||||||
|
value={outputs}
|
||||||
|
isJSONStringifyBeauty
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='px-4 py-2'>
|
||||||
|
<div className='h-[0.5px] bg-black opacity-5' />
|
||||||
|
</div>
|
||||||
|
<div className='px-4 py-2'>
|
||||||
|
<div className='relative'>
|
||||||
|
<div className='h-6 leading-6 text-gray-500 text-xs font-medium'>{t('runLog.meta.title')}</div>
|
||||||
|
<div className='py-1'>
|
||||||
|
<div className='flex'>
|
||||||
|
<div className='shrink-0 w-[104px] px-2 py-[5px] text-gray-500 text-xs leading-[18px] truncate'>{t('runLog.meta.status')}</div>
|
||||||
|
<div className='grow px-2 py-[5px] text-gray-900 text-xs leading-[18px]'>
|
||||||
|
<span>SUCCESS</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex'>
|
||||||
|
<div className='shrink-0 w-[104px] px-2 py-[5px] text-gray-500 text-xs leading-[18px] truncate'>{t('runLog.meta.executor')}</div>
|
||||||
|
<div className='grow px-2 py-[5px] text-gray-900 text-xs leading-[18px]'>
|
||||||
|
<span>{created_by || 'N/A'}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex'>
|
||||||
|
<div className='shrink-0 w-[104px] px-2 py-[5px] text-gray-500 text-xs leading-[18px] truncate'>{t('runLog.meta.startTime')}</div>
|
||||||
|
<div className='grow px-2 py-[5px] text-gray-900 text-xs leading-[18px]'>
|
||||||
|
<span>{dayjs(created_at).format('YYYY-MM-DD hh:mm:ss')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex'>
|
||||||
|
<div className='shrink-0 w-[104px] px-2 py-[5px] text-gray-500 text-xs leading-[18px] truncate'>{t('runLog.meta.time')}</div>
|
||||||
|
<div className='grow px-2 py-[5px] text-gray-900 text-xs leading-[18px]'>
|
||||||
|
<span>{`${elapsed_time?.toFixed(3)}s`}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex'>
|
||||||
|
<div className='shrink-0 w-[104px] px-2 py-[5px] text-gray-500 text-xs leading-[18px] truncate'>{t('runLog.meta.tokens')}</div>
|
||||||
|
<div className='grow px-2 py-[5px] text-gray-900 text-xs leading-[18px]'>
|
||||||
|
<span>{`${total_tokens || 0} Tokens`}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex'>
|
||||||
|
<div className='shrink-0 w-[104px] px-2 py-[5px] text-gray-500 text-xs leading-[18px] truncate'>{t('appLog.agentLogDetail.agentMode')}</div>
|
||||||
|
<div className='grow px-2 py-[5px] text-gray-900 text-xs leading-[18px]'>
|
||||||
|
<span>{agentMode === 'function_call' ? t('appDebug.agent.agentModeType.functionCall') : t('appDebug.agent.agentModeType.ReACT')}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex'>
|
||||||
|
<div className='shrink-0 w-[104px] px-2 py-[5px] text-gray-500 text-xs leading-[18px] truncate'>{t('appLog.agentLogDetail.toolUsed')}</div>
|
||||||
|
<div className='grow px-2 py-[5px] text-gray-900 text-xs leading-[18px]'>
|
||||||
|
<span>{tools?.length ? tools?.join(', ') : 'Null'}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='flex'>
|
||||||
|
<div className='shrink-0 w-[104px] px-2 py-[5px] text-gray-500 text-xs leading-[18px] truncate'>{t('appLog.agentLogDetail.iterations')}</div>
|
||||||
|
<div className='grow px-2 py-[5px] text-gray-900 text-xs leading-[18px]'>
|
||||||
|
<span>{iterations}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ResultPanel
|
140
web/app/components/base/agent-log-modal/tool-call.tsx
Normal file
140
web/app/components/base/agent-log-modal/tool-call.tsx
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import cn from 'classnames'
|
||||||
|
import { useContext } from 'use-context-selector'
|
||||||
|
import BlockIcon from '@/app/components/workflow/block-icon'
|
||||||
|
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
|
||||||
|
import { CodeLanguage } from '@/app/components/workflow/nodes/code/types'
|
||||||
|
import { AlertCircle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
|
||||||
|
import { CheckCircle } from '@/app/components/base/icons/src/vender/line/general'
|
||||||
|
import { ChevronRight } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||||
|
import type { ToolCall } from '@/models/log'
|
||||||
|
import { BlockEnum } from '@/app/components/workflow/types'
|
||||||
|
import I18n from '@/context/i18n'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
toolCall: ToolCall
|
||||||
|
isLLM: boolean
|
||||||
|
isFinal?: boolean
|
||||||
|
tokens?: number
|
||||||
|
observation?: any
|
||||||
|
finalAnswer?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const ToolCallItem: FC<Props> = ({ toolCall, isLLM = false, isFinal, tokens, observation, finalAnswer }) => {
|
||||||
|
const [collapseState, setCollapseState] = useState<boolean>(true)
|
||||||
|
const { locale } = useContext(I18n)
|
||||||
|
const toolName = isLLM ? 'LLM' : (toolCall.tool_label[locale] || toolCall.tool_label[locale.replaceAll('-', '_')])
|
||||||
|
|
||||||
|
const getTime = (time: number) => {
|
||||||
|
if (time < 1)
|
||||||
|
return `${(time * 1000).toFixed(3)} ms`
|
||||||
|
if (time > 60)
|
||||||
|
return `${parseInt(Math.round(time / 60).toString())} m ${(time % 60).toFixed(3)} s`
|
||||||
|
return `${time.toFixed(3)} s`
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTokenCount = (tokens: number) => {
|
||||||
|
if (tokens < 1000)
|
||||||
|
return tokens
|
||||||
|
if (tokens >= 1000 && tokens < 1000000)
|
||||||
|
return `${parseFloat((tokens / 1000).toFixed(3))}K`
|
||||||
|
if (tokens >= 1000000)
|
||||||
|
return `${parseFloat((tokens / 1000000).toFixed(3))}M`
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn('py-1')}>
|
||||||
|
<div className={cn('group transition-all bg-white border border-gray-100 rounded-2xl shadow-xs hover:shadow-md')}>
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
'flex items-center py-3 pl-[6px] pr-3 cursor-pointer',
|
||||||
|
!collapseState && '!pb-2',
|
||||||
|
)}
|
||||||
|
onClick={() => setCollapseState(!collapseState)}
|
||||||
|
>
|
||||||
|
<ChevronRight
|
||||||
|
className={cn(
|
||||||
|
'shrink-0 w-3 h-3 mr-1 text-gray-400 transition-all group-hover:text-gray-500',
|
||||||
|
!collapseState && 'rotate-90',
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<BlockIcon className={cn('shrink-0 mr-2')} type={isLLM ? BlockEnum.LLM : BlockEnum.Tool} toolIcon={toolCall.tool_icon} />
|
||||||
|
<div className={cn(
|
||||||
|
'grow text-gray-700 text-[13px] leading-[16px] font-semibold truncate',
|
||||||
|
)} title={toolName}>{toolName}</div>
|
||||||
|
<div className='shrink-0 text-gray-500 text-xs leading-[18px]'>
|
||||||
|
{toolCall.time_cost && (
|
||||||
|
<span>{getTime(toolCall.time_cost || 0)}</span>
|
||||||
|
)}
|
||||||
|
{isLLM && (
|
||||||
|
<span>{`${getTokenCount(tokens || 0)} tokens`}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{toolCall.status === 'success' && (
|
||||||
|
<CheckCircle className='shrink-0 ml-2 w-3.5 h-3.5 text-[#12B76A]' />
|
||||||
|
)}
|
||||||
|
{toolCall.status === 'error' && (
|
||||||
|
<AlertCircle className='shrink-0 ml-2 w-3.5 h-3.5 text-[#F04438]' />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{!collapseState && (
|
||||||
|
<div className='pb-2'>
|
||||||
|
<div className={cn('px-[10px] py-1')}>
|
||||||
|
{toolCall.status === 'error' && (
|
||||||
|
<div className='px-3 py-[10px] bg-[#fef3f2] rounded-lg border-[0.5px] border-[rbga(0,0,0,0.05)] text-xs leading-[18px] text-[#d92d20] shadow-xs'>{toolCall.error}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{toolCall.tool_input && (
|
||||||
|
<div className={cn('px-[10px] py-1')}>
|
||||||
|
<CodeEditor
|
||||||
|
readOnly
|
||||||
|
title={<div>INPUT</div>}
|
||||||
|
language={CodeLanguage.json}
|
||||||
|
value={toolCall.tool_input}
|
||||||
|
isJSONStringifyBeauty
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{toolCall.tool_output && (
|
||||||
|
<div className={cn('px-[10px] py-1')}>
|
||||||
|
<CodeEditor
|
||||||
|
readOnly
|
||||||
|
title={<div>OUTPUT</div>}
|
||||||
|
language={CodeLanguage.json}
|
||||||
|
value={toolCall.tool_output}
|
||||||
|
isJSONStringifyBeauty
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isLLM && (
|
||||||
|
<div className={cn('px-[10px] py-1')}>
|
||||||
|
<CodeEditor
|
||||||
|
readOnly
|
||||||
|
title={<div>OBSERVATION</div>}
|
||||||
|
language={CodeLanguage.json}
|
||||||
|
value={observation}
|
||||||
|
isJSONStringifyBeauty
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{isLLM && (
|
||||||
|
<div className={cn('px-[10px] py-1')}>
|
||||||
|
<CodeEditor
|
||||||
|
readOnly
|
||||||
|
title={<div>{isFinal ? 'FINAL ANSWER' : 'THOUGHT'}</div>}
|
||||||
|
language={CodeLanguage.json}
|
||||||
|
value={finalAnswer}
|
||||||
|
isJSONStringifyBeauty
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToolCallItem
|
25
web/app/components/base/agent-log-modal/tracing.tsx
Normal file
25
web/app/components/base/agent-log-modal/tracing.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
'use client'
|
||||||
|
import type { FC } from 'react'
|
||||||
|
import Iteration from './iteration'
|
||||||
|
import type { AgentIteration } from '@/models/log'
|
||||||
|
|
||||||
|
type TracingPanelProps = {
|
||||||
|
list: AgentIteration[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const TracingPanel: FC<TracingPanelProps> = ({ list }) => {
|
||||||
|
return (
|
||||||
|
<div className='bg-gray-50'>
|
||||||
|
{list.map((iteration, index) => (
|
||||||
|
<Iteration
|
||||||
|
key={index}
|
||||||
|
index={index + 1}
|
||||||
|
isFinal={index + 1 === list.length}
|
||||||
|
iterationInfo={iteration}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TracingPanel
|
@ -322,6 +322,7 @@ export const useChat = (
|
|||||||
}
|
}
|
||||||
draft[index] = {
|
draft[index] = {
|
||||||
...draft[index],
|
...draft[index],
|
||||||
|
content: newResponseItem.answer,
|
||||||
log: [
|
log: [
|
||||||
...newResponseItem.message,
|
...newResponseItem.message,
|
||||||
...(newResponseItem.message[newResponseItem.message.length - 1].role !== 'assistant'
|
...(newResponseItem.message[newResponseItem.message.length - 1].role !== 'assistant'
|
||||||
@ -339,6 +340,12 @@ export const useChat = (
|
|||||||
tokens: newResponseItem.answer_tokens + newResponseItem.message_tokens,
|
tokens: newResponseItem.answer_tokens + newResponseItem.message_tokens,
|
||||||
latency: newResponseItem.provider_response_latency.toFixed(2),
|
latency: newResponseItem.provider_response_latency.toFixed(2),
|
||||||
},
|
},
|
||||||
|
// for agent log
|
||||||
|
conversationId: connversationId.current,
|
||||||
|
input: {
|
||||||
|
inputs: newResponseItem.inputs,
|
||||||
|
query: newResponseItem.query,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -26,6 +26,7 @@ import { ChatContextProvider } from './context'
|
|||||||
import type { Emoji } from '@/app/components/tools/types'
|
import type { Emoji } from '@/app/components/tools/types'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
import { StopCircle } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
|
import { StopCircle } from '@/app/components/base/icons/src/vender/solid/mediaAndDevices'
|
||||||
|
import AgentLogModal from '@/app/components/base/agent-log-modal'
|
||||||
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
import PromptLogModal from '@/app/components/base/prompt-log-modal'
|
||||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||||
|
|
||||||
@ -78,7 +79,7 @@ const Chat: FC<ChatProps> = ({
|
|||||||
chatAnswerContainerInner,
|
chatAnswerContainerInner,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal } = useAppStore()
|
const { currentLogItem, setCurrentLogItem, showPromptLogModal, setShowPromptLogModal, showAgentLogModal, setShowAgentLogModal } = useAppStore()
|
||||||
const [width, setWidth] = useState(0)
|
const [width, setWidth] = useState(0)
|
||||||
const chatContainerRef = useRef<HTMLDivElement>(null)
|
const chatContainerRef = useRef<HTMLDivElement>(null)
|
||||||
const chatContainerInnerRef = useRef<HTMLDivElement>(null)
|
const chatContainerInnerRef = useRef<HTMLDivElement>(null)
|
||||||
@ -259,6 +260,16 @@ const Chat: FC<ChatProps> = ({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{showAgentLogModal && (
|
||||||
|
<AgentLogModal
|
||||||
|
width={width}
|
||||||
|
currentLogItem={currentLogItem}
|
||||||
|
onCancel={() => {
|
||||||
|
setCurrentLogItem()
|
||||||
|
setShowAgentLogModal(false)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</ChatContextProvider>
|
</ChatContextProvider>
|
||||||
)
|
)
|
||||||
|
@ -59,6 +59,7 @@ export type WorkflowProcess = {
|
|||||||
export type ChatItem = IChatItem & {
|
export type ChatItem = IChatItem & {
|
||||||
isError?: boolean
|
isError?: boolean
|
||||||
workflowProcess?: WorkflowProcess
|
workflowProcess?: WorkflowProcess
|
||||||
|
conversationId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type OnSend = (message: string, files?: VisionFile[]) => void
|
export type OnSend = (message: string, files?: VisionFile[]) => void
|
||||||
|
@ -39,12 +39,12 @@ const MessageLogModal: FC<MessageLogModalProps> = ({
|
|||||||
<div
|
<div
|
||||||
className={cn('relative flex flex-col py-3 bg-white border-[0.5px] border-gray-200 rounded-xl shadow-xl z-10')}
|
className={cn('relative flex flex-col py-3 bg-white border-[0.5px] border-gray-200 rounded-xl shadow-xl z-10')}
|
||||||
style={{
|
style={{
|
||||||
width,
|
width: fixedWidth ? width : 480,
|
||||||
...(!fixedWidth
|
...(!fixedWidth
|
||||||
? {
|
? {
|
||||||
position: 'fixed',
|
position: 'fixed',
|
||||||
top: 56 + 8,
|
top: 56 + 8,
|
||||||
left: 8,
|
left: 8 + (width - 480),
|
||||||
bottom: 16,
|
bottom: 16,
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
|
@ -34,7 +34,13 @@ const PromptLogModal: FC<PromptLogModalProps> = ({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className='fixed top-16 left-2 bottom-2 flex flex-col bg-white border-[0.5px] border-gray-200 rounded-xl shadow-xl z-10'
|
className='fixed top-16 left-2 bottom-2 flex flex-col bg-white border-[0.5px] border-gray-200 rounded-xl shadow-xl z-10'
|
||||||
style={{ width }}
|
style={{
|
||||||
|
width: 480,
|
||||||
|
position: 'fixed',
|
||||||
|
top: 56 + 8,
|
||||||
|
left: 8 + (width - 480),
|
||||||
|
bottom: 16,
|
||||||
|
}}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
>
|
>
|
||||||
<div className='shrink-0 flex justify-between items-center pl-6 pr-5 h-14 border-b border-b-gray-100'>
|
<div className='shrink-0 flex justify-between items-center pl-6 pr-5 h-14 border-b border-b-gray-100'>
|
||||||
|
@ -64,6 +64,22 @@ const translation = {
|
|||||||
not_annotated: 'Nicht annotiert',
|
not_annotated: 'Nicht annotiert',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
workflowTitle: 'Workflow-Protokolle',
|
||||||
|
workflowSubtitle: 'Das Protokoll hat den Vorgang von Automate aufgezeichnet.',
|
||||||
|
runDetail: {
|
||||||
|
title: 'Konversationsprotokoll',
|
||||||
|
workflowTitle: 'Protokolldetail',
|
||||||
|
},
|
||||||
|
promptLog: 'Prompt-Protokoll',
|
||||||
|
agentLog: 'Agentenprotokoll',
|
||||||
|
viewLog: 'Protokoll anzeigen',
|
||||||
|
agentLogDetail: {
|
||||||
|
agentMode: 'Agentenmodus',
|
||||||
|
toolUsed: 'Verwendetes Werkzeug',
|
||||||
|
iterations: 'Iterationen',
|
||||||
|
iteration: 'Iteration',
|
||||||
|
finalProcessing: 'Endverarbeitung',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -77,7 +77,15 @@ const translation = {
|
|||||||
workflowTitle: 'Log Detail',
|
workflowTitle: 'Log Detail',
|
||||||
},
|
},
|
||||||
promptLog: 'Prompt Log',
|
promptLog: 'Prompt Log',
|
||||||
|
agentLog: 'Agent Log',
|
||||||
viewLog: 'View Log',
|
viewLog: 'View Log',
|
||||||
|
agentLogDetail: {
|
||||||
|
agentMode: 'Agent Mode',
|
||||||
|
toolUsed: 'Tool Used',
|
||||||
|
iterations: 'Iterations',
|
||||||
|
iteration: 'Iteration',
|
||||||
|
finalProcessing: 'Final Processing',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -77,7 +77,15 @@ const translation = {
|
|||||||
workflowTitle: 'Détail du journal',
|
workflowTitle: 'Détail du journal',
|
||||||
},
|
},
|
||||||
promptLog: 'Journal de consigne',
|
promptLog: 'Journal de consigne',
|
||||||
|
agentLog: 'Journal des agents',
|
||||||
viewLog: 'Voir le journal',
|
viewLog: 'Voir le journal',
|
||||||
|
agentLogDetail: {
|
||||||
|
agentMode: 'Mode Agent',
|
||||||
|
toolUsed: 'Outil utilisé',
|
||||||
|
iterations: 'Itérations',
|
||||||
|
iteration: 'Itération',
|
||||||
|
finalProcessing: 'Traitement final',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -77,7 +77,15 @@ const translation = {
|
|||||||
workflowTitle: 'ログの詳細',
|
workflowTitle: 'ログの詳細',
|
||||||
},
|
},
|
||||||
promptLog: 'プロンプトログ',
|
promptLog: 'プロンプトログ',
|
||||||
|
agentLog: 'エージェントログ',
|
||||||
viewLog: 'ログを表示',
|
viewLog: 'ログを表示',
|
||||||
|
agentLogDetail: {
|
||||||
|
agentMode: 'エージェントモード',
|
||||||
|
toolUsed: '使用したツール',
|
||||||
|
iterations: '反復',
|
||||||
|
iteration: '反復',
|
||||||
|
finalProcessing: '最終処理',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -77,7 +77,15 @@ const translation = {
|
|||||||
workflowTitle: 'Detalhes do Registro',
|
workflowTitle: 'Detalhes do Registro',
|
||||||
},
|
},
|
||||||
promptLog: 'Registro de Prompt',
|
promptLog: 'Registro de Prompt',
|
||||||
|
agentLog: 'Registro do agente',
|
||||||
viewLog: 'Ver Registro',
|
viewLog: 'Ver Registro',
|
||||||
|
agenteLogDetail: {
|
||||||
|
agentMode: 'Modo Agente',
|
||||||
|
toolUsed: 'Ferramenta usada',
|
||||||
|
iterações: 'Iterações',
|
||||||
|
iteração: 'Iteração',
|
||||||
|
finalProcessing: 'Processamento Final',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -77,7 +77,15 @@ const translation = {
|
|||||||
workflowTitle: 'Деталі Журналу',
|
workflowTitle: 'Деталі Журналу',
|
||||||
},
|
},
|
||||||
promptLog: 'Журнал Запитань',
|
promptLog: 'Журнал Запитань',
|
||||||
viewLog: 'Переглянути Журнал',
|
agentLog: 'Журнал агента',
|
||||||
|
viewLog: 'Переглянути журнал',
|
||||||
|
agentLogDetail: {
|
||||||
|
agentMode: 'Режим агента',
|
||||||
|
toolUsed: 'Використаний інструмент',
|
||||||
|
iterations: 'Ітерації',
|
||||||
|
iteration: 'Ітерація',
|
||||||
|
finalProcessing: 'Остаточна обробка',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -77,7 +77,15 @@ const translation = {
|
|||||||
workflowTitle: 'Chi Tiết Nhật Ký',
|
workflowTitle: 'Chi Tiết Nhật Ký',
|
||||||
},
|
},
|
||||||
promptLog: 'Nhật Ký Nhắc Nhở',
|
promptLog: 'Nhật Ký Nhắc Nhở',
|
||||||
viewLog: 'Xem Nhật Ký',
|
AgentLog: 'Nhật ký đại lý',
|
||||||
|
viewLog: 'Xem nhật ký',
|
||||||
|
agentLogDetail: {
|
||||||
|
AgentMode: 'Chế độ đại lý',
|
||||||
|
toolUsed: 'Công cụ được sử dụng',
|
||||||
|
iterations: 'Lặp lại',
|
||||||
|
iteration: 'Lặp lại',
|
||||||
|
finalProcessing: 'Xử lý cuối cùng',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -77,7 +77,15 @@ const translation = {
|
|||||||
workflowTitle: '日志详情',
|
workflowTitle: '日志详情',
|
||||||
},
|
},
|
||||||
promptLog: 'Prompt 日志',
|
promptLog: 'Prompt 日志',
|
||||||
|
agentLog: 'Agent 日志',
|
||||||
viewLog: '查看日志',
|
viewLog: '查看日志',
|
||||||
|
agentLogDetail: {
|
||||||
|
agentMode: 'Agent 模式',
|
||||||
|
toolUsed: '使用工具',
|
||||||
|
iterations: '迭代次数',
|
||||||
|
iteration: '迭代',
|
||||||
|
finalProcessing: '最终处理',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -4,6 +4,7 @@ import type {
|
|||||||
Edge,
|
Edge,
|
||||||
Node,
|
Node,
|
||||||
} from '@/app/components/workflow/types'
|
} from '@/app/components/workflow/types'
|
||||||
|
|
||||||
// Log type contains key:string conversation_id:string created_at:string quesiton:string answer:string
|
// Log type contains key:string conversation_id:string created_at:string quesiton:string answer:string
|
||||||
export type Conversation = {
|
export type Conversation = {
|
||||||
id: string
|
id: string
|
||||||
@ -292,3 +293,57 @@ export type WorkflowRunDetailResponse = {
|
|||||||
created_at: number
|
created_at: number
|
||||||
finished_at: number
|
finished_at: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AgentLogMeta = {
|
||||||
|
status: string
|
||||||
|
executor: string
|
||||||
|
start_time: string
|
||||||
|
elapsed_time: number
|
||||||
|
total_tokens: number
|
||||||
|
agent_mode: string
|
||||||
|
iterations: number
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ToolCall = {
|
||||||
|
status: string
|
||||||
|
error?: string | null
|
||||||
|
time_cost?: number
|
||||||
|
tool_icon: any
|
||||||
|
tool_input?: any
|
||||||
|
tool_output?: any
|
||||||
|
tool_name?: string
|
||||||
|
tool_label?: any
|
||||||
|
tool_parameters?: any
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AgentIteration = {
|
||||||
|
created_at: string
|
||||||
|
files: string[]
|
||||||
|
thought: string
|
||||||
|
tokens: number
|
||||||
|
tool_calls: ToolCall[]
|
||||||
|
tool_raw: {
|
||||||
|
inputs: string
|
||||||
|
outputs: string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AgentLogFile = {
|
||||||
|
id: string
|
||||||
|
type: string
|
||||||
|
url: string
|
||||||
|
name: string
|
||||||
|
belongs_to: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AgentLogDetailRequest = {
|
||||||
|
conversation_id: string
|
||||||
|
message_id: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AgentLogDetailResponse = {
|
||||||
|
meta: AgentLogMeta
|
||||||
|
iterations: AgentIteration[]
|
||||||
|
files: AgentLogFile[]
|
||||||
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import type { Fetcher } from 'swr'
|
import type { Fetcher } from 'swr'
|
||||||
import { get, post } from './base'
|
import { get, post } from './base'
|
||||||
import type {
|
import type {
|
||||||
|
AgentLogDetailRequest,
|
||||||
|
AgentLogDetailResponse,
|
||||||
AnnotationsCountResponse,
|
AnnotationsCountResponse,
|
||||||
ChatConversationFullDetailResponse,
|
ChatConversationFullDetailResponse,
|
||||||
ChatConversationsRequest,
|
ChatConversationsRequest,
|
||||||
@ -73,3 +75,7 @@ export const fetchRunDetail = ({ appID, runID }: { appID: string; runID: string
|
|||||||
export const fetchTracingList: Fetcher<NodeTracingListResponse, { url: string }> = ({ url }) => {
|
export const fetchTracingList: Fetcher<NodeTracingListResponse, { url: string }> = ({ url }) => {
|
||||||
return get<NodeTracingListResponse>(url)
|
return get<NodeTracingListResponse>(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const fetchAgentLogDetail = ({ appID, params }: { appID: string; params: AgentLogDetailRequest }) => {
|
||||||
|
return get<AgentLogDetailResponse>(`/apps/${appID}/agent/logs`, { params })
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user