mirror of
https://github.com/langgenius/dify.git
synced 2026-05-09 21:28:25 +08:00
feat: llm node support tools
This commit is contained in:
parent
04f40303fd
commit
1d93f41fcf
@ -1,5 +1,5 @@
|
||||
import type { ToolCallItem } from '../../type'
|
||||
import ToolCallsItem from './item'
|
||||
import type { ToolCallItem } from '@/types/workflow'
|
||||
import ToolCallItemComponent from '@/app/components/workflow/run/llm-log/tool-call-item'
|
||||
|
||||
type ToolCallsProps = {
|
||||
toolCalls: ToolCallItem[]
|
||||
@ -8,9 +8,13 @@ const ToolCalls = ({
|
||||
toolCalls,
|
||||
}: ToolCallsProps) => {
|
||||
return (
|
||||
<div>
|
||||
<div className="my-1 space-y-1">
|
||||
{toolCalls.map((toolCall: ToolCallItem) => (
|
||||
<ToolCallsItem key={toolCall.tool_call_id} payload={toolCall} />
|
||||
<ToolCallItemComponent
|
||||
key={toolCall.tool_call_id}
|
||||
payload={toolCall}
|
||||
className="bg-background-gradient-bg-fill-chat-bubble-bg-2 shadow-none"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -45,7 +45,7 @@ const WorkflowProcessItem = ({
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'-mx-1 rounded-xl px-2.5',
|
||||
'rounded-xl px-2.5',
|
||||
collapse ? 'border-l-[0.25px] border-components-panel-border py-[7px]' : 'border-[0.5px] border-components-panel-border-subtle px-1 pb-1 pt-[7px]',
|
||||
running && !collapse && 'bg-background-section-burn',
|
||||
succeeded && !collapse && 'bg-state-success-hover',
|
||||
|
||||
@ -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 } from '@/types/workflow'
|
||||
import type { FileResponse, ToolCallItem } from '@/types/workflow'
|
||||
|
||||
export type MessageMore = {
|
||||
time: string
|
||||
@ -64,15 +64,9 @@ export type CitationItem = {
|
||||
word_count: number
|
||||
}
|
||||
|
||||
export type ToolCallItem = {
|
||||
is_thought?: boolean
|
||||
tool_call_id?: string
|
||||
tool_name?: string
|
||||
tool_arguments?: string
|
||||
tool_files?: string[]
|
||||
tool_error?: string
|
||||
tool_output?: string
|
||||
tool_elapsed_time?: number
|
||||
export type IconObject = {
|
||||
background: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export type IChatItem = {
|
||||
|
||||
@ -0,0 +1,4 @@
|
||||
<svg width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2 9.49479C0.782372 8.51826 0 7.01768 0 5.33333C0 2.38782 2.38782 0 5.33333 0C8.20841 0 10.5503 2.27504 10.6608 5.12305L11.888 6.96354C12.0843 7.25794 12.0161 7.65424 11.7331 7.86654L10.6667 8.66602V10C10.6667 10.7364 10.0697 11.3333 9.33333 11.3333H8V13.3333H6.66667V10.6667C6.66667 10.2985 6.96514 10 7.33333 10H9.33333V8.33333C9.33333 8.12349 9.43239 7.92603 9.60026 7.80013L10.4284 7.17838L9.44531 5.70312C9.3723 5.59361 9.33333 5.46495 9.33333 5.33333C9.33333 3.1242 7.54248 1.33333 5.33333 1.33333C3.1242 1.33333 1.33333 3.1242 1.33333 5.33333C1.33333 6.69202 2.0103 7.89261 3.04818 8.61654C3.2269 8.74119 3.33329 8.94552 3.33333 9.16341V13.3333H2V9.49479Z" fill="#354052"/>
|
||||
<path d="M6.04367 4.24012L5.6504 3.21778C5.59993 3.08657 5.47393 3 5.33333 3C5.19273 3 5.06673 3.08657 5.01627 3.21778L4.62303 4.24012C4.55531 4.41618 4.41618 4.55531 4.24012 4.62303L3.21778 5.01624C3.08657 5.0667 3 5.19276 3 5.33333C3 5.47393 3.08657 5.59993 3.21778 5.6504L4.24012 6.04367C4.41618 6.11133 4.55531 6.25047 4.62303 6.42653L5.01627 7.44887C5.06673 7.58007 5.19273 7.66667 5.33333 7.66667C5.47393 7.66667 5.59993 7.58007 5.6504 7.44887L6.04367 6.42653C6.11133 6.25047 6.25047 6.11133 6.42653 6.04367L7.44887 5.6504C7.58007 5.59993 7.66667 5.47393 7.66667 5.33333C7.66667 5.19276 7.58007 5.0667 7.44887 5.01624L6.42653 4.62303C6.25047 4.55531 6.11133 4.41618 6.04367 4.24012Z" fill="#354052"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,35 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "12",
|
||||
"height": "14",
|
||||
"viewBox": "0 0 12 14",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M2 9.49479C0.782372 8.51826 0 7.01768 0 5.33333C0 2.38782 2.38782 0 5.33333 0C8.20841 0 10.5503 2.27504 10.6608 5.12305L11.888 6.96354C12.0843 7.25794 12.0161 7.65424 11.7331 7.86654L10.6667 8.66602V10C10.6667 10.7364 10.0697 11.3333 9.33333 11.3333H8V13.3333H6.66667V10.6667C6.66667 10.2985 6.96514 10 7.33333 10H9.33333V8.33333C9.33333 8.12349 9.43239 7.92603 9.60026 7.80013L10.4284 7.17838L9.44531 5.70312C9.3723 5.59361 9.33333 5.46495 9.33333 5.33333C9.33333 3.1242 7.54248 1.33333 5.33333 1.33333C3.1242 1.33333 1.33333 3.1242 1.33333 5.33333C1.33333 6.69202 2.0103 7.89261 3.04818 8.61654C3.2269 8.74119 3.33329 8.94552 3.33333 9.16341V13.3333H2V9.49479Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
},
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"d": "M6.04367 4.24012L5.6504 3.21778C5.59993 3.08657 5.47393 3 5.33333 3C5.19273 3 5.06673 3.08657 5.01627 3.21778L4.62303 4.24012C4.55531 4.41618 4.41618 4.55531 4.24012 4.62303L3.21778 5.01624C3.08657 5.0667 3 5.19276 3 5.33333C3 5.47393 3.08657 5.59993 3.21778 5.6504L4.24012 6.04367C4.41618 6.11133 4.55531 6.25047 4.62303 6.42653L5.01627 7.44887C5.06673 7.58007 5.19273 7.66667 5.33333 7.66667C5.47393 7.66667 5.59993 7.58007 5.6504 7.44887L6.04367 6.42653C6.11133 6.25047 6.25047 6.11133 6.42653 6.04367L7.44887 5.6504C7.58007 5.59993 7.66667 5.47393 7.66667 5.33333C7.66667 5.19276 7.58007 5.0667 7.44887 5.01624L6.42653 4.62303C6.25047 4.55531 6.11133 4.41618 6.04367 4.24012Z",
|
||||
"fill": "currentColor"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "Thinking"
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import type { IconData } from '@/app/components/base/icons/IconBase'
|
||||
import * as React from 'react'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import data from './Thinking.json'
|
||||
|
||||
const Icon = (
|
||||
{
|
||||
ref,
|
||||
...props
|
||||
}: React.SVGProps<SVGSVGElement> & {
|
||||
ref?: React.RefObject<React.RefObject<HTMLOrSVGElement>>
|
||||
},
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />
|
||||
|
||||
Icon.displayName = 'Thinking'
|
||||
|
||||
export default Icon
|
||||
@ -24,6 +24,7 @@ export { default as ParameterExtractor } from './ParameterExtractor'
|
||||
export { default as QuestionClassifier } from './QuestionClassifier'
|
||||
export { default as Schedule } from './Schedule'
|
||||
export { default as TemplatingTransform } from './TemplatingTransform'
|
||||
export { default as Thinking } from './Thinking'
|
||||
export { default as TriggerAll } from './TriggerAll'
|
||||
export { default as VariableX } from './VariableX'
|
||||
export { default as WebhookLine } from './WebhookLine'
|
||||
|
||||
@ -2,6 +2,7 @@ import type { FC } from 'react'
|
||||
import {
|
||||
RiFileTextLine,
|
||||
RiFilmAiLine,
|
||||
RiHammerLine,
|
||||
RiImageCircleAiLine,
|
||||
RiVoiceAiFill,
|
||||
} from '@remixicon/react'
|
||||
@ -38,17 +39,33 @@ const FeatureIcon: FC<FeatureIconProps> = ({
|
||||
// )
|
||||
// }
|
||||
|
||||
// if (feature === ModelFeatureEnum.toolCall) {
|
||||
// return (
|
||||
// <Tooltip
|
||||
// popupContent={t('common.modelProvider.featureSupported', { feature: ModelFeatureTextEnum.toolCall })}
|
||||
// >
|
||||
// <ModelBadge className={`mr-0.5 !px-0 w-[18px] justify-center text-gray-500 ${className}`}>
|
||||
// <MagicWand className='w-3 h-3' />
|
||||
// </ModelBadge>
|
||||
// </Tooltip>
|
||||
// )
|
||||
// }
|
||||
if (feature === ModelFeatureEnum.toolCall) {
|
||||
if (showFeaturesLabel) {
|
||||
return (
|
||||
<ModelBadge className={cn('gap-x-0.5', className)}>
|
||||
<RiHammerLine className="size-3" />
|
||||
<span>{ModelFeatureTextEnum.toolCall}</span>
|
||||
</ModelBadge>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
popupContent={t('modelProvider.featureSupported', { ns: 'common', feature: ModelFeatureTextEnum.toolCall })}
|
||||
>
|
||||
<div className="inline-block cursor-help">
|
||||
<ModelBadge
|
||||
className={cn(
|
||||
'w-[18px] justify-center !px-0',
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<RiHammerLine className="size-3" />
|
||||
</ModelBadge>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
|
||||
// if (feature === ModelFeatureEnum.multiToolCall) {
|
||||
// return (
|
||||
|
||||
@ -96,6 +96,14 @@ const PopupItem: FC<PopupItemProps> = ({
|
||||
<div className='text-text-tertiary system-xs-regular'>{currentProvider?.description?.[language] || currentProvider?.description?.en_US}</div>
|
||||
)} */}
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{
|
||||
modelItem.features?.includes(ModelFeatureEnum.toolCall) && (
|
||||
<FeatureIcon
|
||||
feature={ModelFeatureEnum.toolCall}
|
||||
showFeaturesLabel
|
||||
/>
|
||||
)
|
||||
}
|
||||
{modelItem.model_type && (
|
||||
<ModelBadge>
|
||||
{modelTypeFormat(modelItem.model_type)}
|
||||
@ -118,7 +126,7 @@ const PopupItem: FC<PopupItemProps> = ({
|
||||
<div className="pt-2">
|
||||
<div className="system-2xs-medium-uppercase mb-1 text-text-tertiary">{t('model.capabilities', { ns: 'common' })}</div>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{modelItem.features?.map(feature => (
|
||||
{modelItem.features?.filter(feature => feature !== ModelFeatureEnum.toolCall).map(feature => (
|
||||
<FeatureIcon
|
||||
key={feature}
|
||||
feature={feature}
|
||||
|
||||
@ -275,6 +275,8 @@ export const useChat = (
|
||||
messageId,
|
||||
taskId,
|
||||
chunk_type,
|
||||
tool_icon,
|
||||
tool_icon_dark,
|
||||
tool_call_id,
|
||||
tool_name,
|
||||
tool_arguments,
|
||||
@ -288,9 +290,12 @@ export const useChat = (
|
||||
if (!responseItem.toolCalls)
|
||||
responseItem.toolCalls = []
|
||||
responseItem.toolCalls?.push({
|
||||
type: 'tool',
|
||||
tool_call_id,
|
||||
tool_name,
|
||||
tool_arguments,
|
||||
tool_icon,
|
||||
tool_icon_dark,
|
||||
tool_files,
|
||||
tool_error,
|
||||
tool_elapsed_time,
|
||||
@ -305,16 +310,22 @@ export const useChat = (
|
||||
}
|
||||
|
||||
if (chunk_type === 'thought_start') {
|
||||
console.log(message, 'xx1')
|
||||
responseItem.toolCalls?.push({
|
||||
is_thought: true,
|
||||
type: 'thought',
|
||||
tool_elapsed_time,
|
||||
})
|
||||
}
|
||||
|
||||
if (chunk_type === 'thought_end') {
|
||||
console.log(message, 'xx2')
|
||||
// const currentThoughtIndex = responseItem.toolCalls?.findIndex(item => item.is_thought) ?? -1
|
||||
// if (currentThoughtIndex > -1)
|
||||
// responseItem.toolCalls![currentThoughtIndex].tool_output = message
|
||||
}
|
||||
|
||||
if (chunk_type === 'thought') {
|
||||
const currentThoughtIndex = responseItem.toolCalls?.findIndex(item => item.is_thought) ?? -1
|
||||
if (currentThoughtIndex > -1)
|
||||
responseItem.toolCalls![currentThoughtIndex].tool_output = message
|
||||
console.log(message, 'xx3')
|
||||
}
|
||||
|
||||
if (messageId && !hasSetResponseId) {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type {
|
||||
AgentLogItemWithChildren,
|
||||
IterationDurationMap,
|
||||
LLMTraceItem,
|
||||
LoopDurationMap,
|
||||
LoopVariableMap,
|
||||
NodeTracing,
|
||||
@ -79,8 +80,18 @@ export const useLogs = () => {
|
||||
}
|
||||
}, [setAgentOrToolLogItemStack, setAgentOrToolLogListMap])
|
||||
|
||||
const [showLLMDetail, {
|
||||
setTrue: setShowLLMDetailTrue,
|
||||
setFalse: setShowLLMDetailFalse,
|
||||
}] = useBoolean(false)
|
||||
const [llmResultList, setLLMResultList] = useState<LLMTraceItem[]>([])
|
||||
const handleShowLLMDetail = useCallback((detail: LLMTraceItem[]) => {
|
||||
setShowLLMDetailTrue()
|
||||
setLLMResultList(detail)
|
||||
}, [setShowLLMDetailTrue, setLLMResultList])
|
||||
|
||||
return {
|
||||
showSpecialResultPanel: showRetryDetail || showIteratingDetail || showLoopingDetail || !!agentOrToolLogItemStack.length,
|
||||
showSpecialResultPanel: showRetryDetail || showIteratingDetail || showLoopingDetail || !!agentOrToolLogItemStack.length || showLLMDetail,
|
||||
showRetryDetail,
|
||||
setShowRetryDetailTrue,
|
||||
setShowRetryDetailFalse,
|
||||
@ -111,5 +122,12 @@ export const useLogs = () => {
|
||||
agentOrToolLogItemStack,
|
||||
agentOrToolLogListMap,
|
||||
handleShowAgentOrToolLog,
|
||||
|
||||
showLLMDetail,
|
||||
setShowLLMDetailTrue,
|
||||
setShowLLMDetailFalse,
|
||||
llmResultList,
|
||||
setLLMResultList,
|
||||
handleShowLLMDetail,
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,7 +153,7 @@ const RunPanel: FC<RunProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
{/* panel detail */}
|
||||
<div ref={ref} className={cn('relative h-0 grow overflow-y-auto rounded-b-xl bg-components-panel-bg')}>
|
||||
<div ref={ref} className={cn('relative h-0 grow overflow-y-auto rounded-b-xl bg-background-section')}>
|
||||
{loading && (
|
||||
<div className="flex h-full items-center justify-center bg-components-panel-bg">
|
||||
<Loading />
|
||||
@ -192,7 +192,7 @@ const RunPanel: FC<RunProps> = ({
|
||||
)}
|
||||
{!loading && currentTab === 'TRACING' && (
|
||||
<TracingPanel
|
||||
className="bg-background-section-burn"
|
||||
className="bg-background-section"
|
||||
list={list}
|
||||
/>
|
||||
)}
|
||||
|
||||
@ -1,37 +1,37 @@
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
import type { LLMTraceItem, NodeTracing } from '@/types/workflow'
|
||||
import {
|
||||
RiArrowRightSLine,
|
||||
RiRestartFill,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { Thinking } from '@/app/components/base/icons/src/vender/workflow'
|
||||
|
||||
type LLMLogTriggerProps = {
|
||||
nodeInfo: NodeTracing
|
||||
onShowLLMDetail: (detail: NodeTracing[]) => void
|
||||
onShowLLMDetail: (detail: LLMTraceItem[]) => void
|
||||
}
|
||||
const LLMLogTrigger = ({
|
||||
nodeInfo,
|
||||
onShowLLMDetail,
|
||||
}: LLMLogTriggerProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { retryDetail } = nodeInfo
|
||||
const llmTrace = nodeInfo?.execution_metadata?.llm_trace || []
|
||||
|
||||
const handleShowRetryResultList = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
const handleShowLLMDetail = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||
e.stopPropagation()
|
||||
e.nativeEvent.stopImmediatePropagation()
|
||||
onShowLLMDetail(retryDetail || [])
|
||||
onShowLLMDetail(llmTrace || [])
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
className="mb-1 flex w-full items-center justify-between"
|
||||
variant="tertiary"
|
||||
onClick={handleShowRetryResultList}
|
||||
onClick={handleShowLLMDetail}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<RiRestartFill className="mr-0.5 h-4 w-4 shrink-0 text-components-button-tertiary-text" />
|
||||
{t('nodes.common.retry.retries', { ns: 'workflow', num: retryDetail?.length })}
|
||||
<Thinking className="mr-[5px] h-4 w-4 shrink-0 text-components-button-tertiary-text" />
|
||||
{t('detail', { ns: 'runLog' })}
|
||||
</div>
|
||||
<RiArrowRightSLine className="h-4 w-4 shrink-0 text-components-button-tertiary-text" />
|
||||
</Button>
|
||||
|
||||
@ -1,16 +1,19 @@
|
||||
'use client'
|
||||
|
||||
import type { FC } from 'react'
|
||||
import type { NodeTracing } from '@/types/workflow'
|
||||
import type {
|
||||
LLMTraceItem,
|
||||
ToolCallItem,
|
||||
} from '@/types/workflow'
|
||||
import {
|
||||
RiArrowLeftLine,
|
||||
} from '@remixicon/react'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import TracingPanel from '../tracing-panel'
|
||||
import ToolCallItemComponent from '@/app/components/workflow/run/llm-log/tool-call-item'
|
||||
|
||||
type Props = {
|
||||
list: NodeTracing[]
|
||||
list: LLMTraceItem[]
|
||||
onBack: () => void
|
||||
}
|
||||
|
||||
@ -19,6 +22,18 @@ const LLMResultPanel: FC<Props> = ({
|
||||
onBack,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const formattedList = list.map(item => ({
|
||||
type: item.type,
|
||||
tool_call_id: item.provider,
|
||||
tool_name: item.name,
|
||||
tool_arguments: item.type === 'tool' ? item.output.arguments : undefined,
|
||||
tool_icon: item.icon,
|
||||
tool_icon_dark: item.icon_dark,
|
||||
tool_files: [],
|
||||
tool_error: item.error,
|
||||
tool_output: item.type === 'tool' ? item.output.output : item.output,
|
||||
tool_elapsed_time: item.duration,
|
||||
}))
|
||||
|
||||
return (
|
||||
<div>
|
||||
@ -33,13 +48,13 @@ const LLMResultPanel: FC<Props> = ({
|
||||
<RiArrowLeftLine className="mr-1 h-4 w-4" />
|
||||
{t('singleRun.back', { ns: 'workflow' })}
|
||||
</div>
|
||||
<TracingPanel
|
||||
list={list.map((item, index) => ({
|
||||
...item,
|
||||
title: `${t('nodes.common.retry.retry', { ns: 'workflow' })} ${index + 1}`,
|
||||
}))}
|
||||
className="bg-background-section-burn"
|
||||
/>
|
||||
<div className="space-y-1 p-2">
|
||||
{
|
||||
formattedList.map((item, index) => (
|
||||
<ToolCallItemComponent key={index} payload={item as ToolCallItem} />
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,30 +1,40 @@
|
||||
import type { ToolCallItem } from '../../type'
|
||||
import type { ToolCallItem } from '@/types/workflow'
|
||||
import {
|
||||
RiArrowDownSLine,
|
||||
} from '@remixicon/react'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
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 { BlockEnum } from '@/app/components/workflow/types'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type ToolCallsItemProps = {
|
||||
type ToolCallItemComponentProps = {
|
||||
className?: string
|
||||
payload: ToolCallItem
|
||||
}
|
||||
const ToolCallsItem = ({
|
||||
const ToolCallItemComponent = ({
|
||||
className,
|
||||
payload,
|
||||
}: ToolCallsItemProps) => {
|
||||
}: ToolCallItemComponentProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [expand, setExpand] = useState(false)
|
||||
return (
|
||||
<div
|
||||
className="rounded-xl bg-background-gradient-bg-fill-chat-bubble-bg-1 px-2 pb-1 pt-2"
|
||||
className={cn('rounded-[10px] border-[0.5px] border-components-panel-border bg-background-default-subtle px-2 pb-1 pt-2 shadow-xs', className)}
|
||||
>
|
||||
<div className="mb-1 flex cursor-pointer items-center hover:bg-background-gradient-bg-fill-chat-bubble-bg-2" onClick={() => setExpand(!expand)}>
|
||||
<div className="mr-1 h-5 w-5 grow truncate" title={payload.tool_name}>{payload.tool_name}</div>
|
||||
<BlockIcon
|
||||
type={BlockEnum.Tool}
|
||||
toolIcon={payload.tool_icon}
|
||||
className="mr-1 h-4 w-4 shrink-0"
|
||||
/>
|
||||
<div className="mr-1 grow truncate" title={payload.tool_name}>{payload.tool_name}</div>
|
||||
{
|
||||
!!payload.tool_elapsed_time && (
|
||||
<div className="system-xs-regular mr-1 shrink-0 text-text-tertiary">
|
||||
{payload.tool_elapsed_time?.toFixed(3)}
|
||||
{payload.tool_elapsed_time?.toFixed(1)}
|
||||
s
|
||||
</div>
|
||||
)
|
||||
@ -36,31 +46,40 @@ const ToolCallsItem = ({
|
||||
<div className="relative px-2 pl-9">
|
||||
<div className="absolute bottom-1 left-2 top-1 w-[1px] bg-divider-regular"></div>
|
||||
{
|
||||
payload.is_thought && (
|
||||
payload.type === 'thought' && typeof payload.tool_output === 'string' && (
|
||||
<div className="body-sm-medium text-text-tertiary">{payload.tool_output}</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!payload.is_thought && (
|
||||
payload.type === 'model' && (
|
||||
<CodeEditor
|
||||
readOnly
|
||||
title={<div>{t('common.input', { ns: 'workflow' })}</div>}
|
||||
title={<div>{t('common.data', { ns: 'workflow' })}</div>}
|
||||
language={CodeLanguage.json}
|
||||
value={JSON.parse(payload.tool_arguments || '{}')}
|
||||
value={payload.tool_output}
|
||||
isJSONStringifyBeauty
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
!payload.is_thought && (
|
||||
payload.type === 'tool' && (
|
||||
<CodeEditor
|
||||
readOnly
|
||||
title={<div>{t('common.input', { ns: 'workflow' })}</div>}
|
||||
language={CodeLanguage.json}
|
||||
value={payload.tool_arguments}
|
||||
isJSONStringifyBeauty
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
payload.type === 'tool' && (
|
||||
<CodeEditor
|
||||
readOnly
|
||||
className="mt-1"
|
||||
title={<div>{t('common.output', { ns: 'workflow' })}</div>}
|
||||
language={CodeLanguage.json}
|
||||
value={{
|
||||
answer: payload.tool_output,
|
||||
}}
|
||||
value={payload.tool_output}
|
||||
isJSONStringifyBeauty
|
||||
/>
|
||||
)
|
||||
@ -72,4 +91,4 @@ const ToolCallsItem = ({
|
||||
)
|
||||
}
|
||||
|
||||
export default ToolCallsItem
|
||||
export default ToolCallItemComponent
|
||||
@ -3,6 +3,7 @@ import type { FC } from 'react'
|
||||
import type {
|
||||
AgentLogItemWithChildren,
|
||||
IterationDurationMap,
|
||||
LLMTraceItem,
|
||||
LoopDurationMap,
|
||||
LoopVariableMap,
|
||||
NodeTracing,
|
||||
@ -44,7 +45,7 @@ type Props = {
|
||||
onShowLoopDetail?: (detail: NodeTracing[][], loopDurationMap: LoopDurationMap, loopVariableMap: LoopVariableMap) => void
|
||||
onShowRetryDetail?: (detail: NodeTracing[]) => void
|
||||
onShowAgentOrToolLog?: (detail?: AgentLogItemWithChildren) => void
|
||||
onShowLLMDetail?: (detail: NodeTracing[]) => void
|
||||
onShowLLMDetail?: (detail: LLMTraceItem[]) => void
|
||||
notShowIterationNav?: boolean
|
||||
notShowLoopNav?: boolean
|
||||
}
|
||||
@ -99,7 +100,7 @@ const NodePanel: FC<Props> = ({
|
||||
const isRetryNode = hasRetryNode(nodeInfo.node_type) && !!nodeInfo.retryDetail?.length
|
||||
const isAgentNode = nodeInfo.node_type === BlockEnum.Agent && !!nodeInfo.agentLog?.length
|
||||
const isToolNode = nodeInfo.node_type === BlockEnum.Tool && !!nodeInfo.agentLog?.length
|
||||
const isLLMNode = nodeInfo.node_type === BlockEnum.LLM && !!nodeInfo.generation_detail
|
||||
const isLLMNode = nodeInfo.node_type === BlockEnum.LLM && !!nodeInfo.execution_metadata?.llm_trace?.length
|
||||
|
||||
const inputsTitle = useMemo(() => {
|
||||
let text = t('common.input', { ns: 'workflow' })
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
import type { FC } from 'react'
|
||||
import type {
|
||||
AgentLogItemWithChildren,
|
||||
LLMTraceItem,
|
||||
NodeTracing,
|
||||
} from '@/types/workflow'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
@ -46,7 +47,7 @@ export type ResultPanelProps = {
|
||||
handleShowLoopResultList?: (detail: NodeTracing[][], loopDurationMap: any) => void
|
||||
onShowRetryDetail?: (detail: NodeTracing[]) => void
|
||||
handleShowAgentOrToolLog?: (detail?: AgentLogItemWithChildren) => void
|
||||
onShowLLMDetail?: (detail: NodeTracing[]) => void
|
||||
onShowLLMDetail?: (detail: LLMTraceItem[]) => void
|
||||
}
|
||||
|
||||
const ResultPanel: FC<ResultPanelProps> = ({
|
||||
@ -81,7 +82,7 @@ const ResultPanel: FC<ResultPanelProps> = ({
|
||||
const isRetryNode = hasRetryNode(nodeInfo?.node_type) && !!nodeInfo?.retryDetail?.length
|
||||
const isAgentNode = nodeInfo?.node_type === BlockEnum.Agent && !!nodeInfo?.agentLog?.length
|
||||
const isToolNode = nodeInfo?.node_type === BlockEnum.Tool && !!nodeInfo?.agentLog?.length
|
||||
const isLLMNode = nodeInfo?.node_type === BlockEnum.LLM && !!nodeInfo?.generation_detail
|
||||
const isLLMNode = nodeInfo?.node_type === BlockEnum.LLM && !!nodeInfo?.execution_metadata?.llm_trace?.length
|
||||
|
||||
return (
|
||||
<div className="bg-components-panel-bg py-2">
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import type {
|
||||
AgentLogItemWithChildren,
|
||||
IterationDurationMap,
|
||||
LLMTraceItem,
|
||||
LoopDurationMap,
|
||||
LoopVariableMap,
|
||||
NodeTracing,
|
||||
@ -33,7 +34,7 @@ export type SpecialResultPanelProps = {
|
||||
|
||||
showLLMDetail?: boolean
|
||||
setShowLLMDetailFalse?: () => void
|
||||
llmResultList?: NodeTracing[]
|
||||
llmResultList?: LLMTraceItem[]
|
||||
}
|
||||
const SpecialResultPanel = ({
|
||||
showRetryDetail,
|
||||
|
||||
@ -91,6 +91,11 @@ const TracingPanel: FC<TracingPanelProps> = ({
|
||||
agentOrToolLogItemStack,
|
||||
agentOrToolLogListMap,
|
||||
handleShowAgentOrToolLog,
|
||||
|
||||
showLLMDetail,
|
||||
setShowLLMDetailFalse,
|
||||
llmResultList,
|
||||
handleShowLLMDetail,
|
||||
} = useLogs()
|
||||
|
||||
const renderNode = (node: NodeTracing) => {
|
||||
@ -153,6 +158,7 @@ const TracingPanel: FC<TracingPanelProps> = ({
|
||||
onShowLoopDetail={handleShowLoopResultList}
|
||||
onShowRetryDetail={handleShowRetryResultList}
|
||||
onShowAgentOrToolLog={handleShowAgentOrToolLog}
|
||||
onShowLLMDetail={handleShowLLMDetail}
|
||||
hideInfo={hideNodeInfo}
|
||||
hideProcessDetail={hideNodeProcessDetail}
|
||||
/>
|
||||
@ -182,6 +188,10 @@ const TracingPanel: FC<TracingPanelProps> = ({
|
||||
agentOrToolLogItemStack={agentOrToolLogItemStack}
|
||||
agentOrToolLogListMap={agentOrToolLogListMap}
|
||||
handleShowAgentOrToolLog={handleShowAgentOrToolLog}
|
||||
|
||||
showLLMDetail={showLLMDetail}
|
||||
setShowLLMDetailFalse={setShowLLMDetailFalse}
|
||||
llmResultList={llmResultList}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -126,6 +126,7 @@
|
||||
"common.currentDraftUnpublished": "Current Draft Unpublished",
|
||||
"common.currentView": "Current View",
|
||||
"common.currentWorkflow": "Current Workflow",
|
||||
"common.data": "Data",
|
||||
"common.debugAndPreview": "Preview",
|
||||
"common.disconnect": "Disconnect",
|
||||
"common.duplicate": "Duplicate",
|
||||
|
||||
@ -126,6 +126,7 @@
|
||||
"common.currentDraftUnpublished": "当前草稿未发布",
|
||||
"common.currentView": "当前视图",
|
||||
"common.currentWorkflow": "整个工作流",
|
||||
"common.data": "数据",
|
||||
"common.debugAndPreview": "预览",
|
||||
"common.disconnect": "断开连接",
|
||||
"common.duplicate": "复制",
|
||||
|
||||
@ -34,16 +34,24 @@ import { getWebAppPassport } from './webapp-auth'
|
||||
|
||||
const TIME_OUT = 100000
|
||||
|
||||
export type IconObject = {
|
||||
background: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export type IOnDataMoreInfo = {
|
||||
conversationId?: string
|
||||
taskId?: string
|
||||
messageId: string
|
||||
errorMessage?: string
|
||||
errorCode?: string
|
||||
chunk_type?: 'text' | 'tool_call' | 'tool_result' | 'thought' | 'thought_start'
|
||||
chunk_type?: 'text' | 'tool_call' | 'tool_result' | 'thought' | 'thought_start' | 'thought_end'
|
||||
tool_call_id?: string
|
||||
tool_name?: string
|
||||
tool_arguments?: string
|
||||
tool_icon?: string | IconObject
|
||||
tool_icon_dark?: string | IconObject
|
||||
|
||||
tool_files?: string[]
|
||||
tool_error?: string
|
||||
tool_elapsed_time?: number
|
||||
@ -245,6 +253,8 @@ export const handleStream = (
|
||||
tool_call_id: bufferObj.tool_call_id,
|
||||
tool_name: bufferObj.tool_name,
|
||||
tool_arguments: bufferObj.tool_arguments,
|
||||
tool_icon: bufferObj.tool_icon,
|
||||
tool_icon_dark: bufferObj.tool_icon_dark,
|
||||
tool_files: bufferObj.tool_files,
|
||||
tool_error: bufferObj.tool_error,
|
||||
tool_elapsed_time: bufferObj.tool_elapsed_time,
|
||||
|
||||
@ -28,11 +28,33 @@ export type AgentLogItemWithChildren = AgentLogItem & {
|
||||
children: AgentLogItemWithChildren[]
|
||||
}
|
||||
|
||||
export type IconObject = {
|
||||
background: string
|
||||
content: string
|
||||
}
|
||||
|
||||
export type ToolCallItem = {
|
||||
type: 'model' | 'tool' | 'thought'
|
||||
tool_call_id?: string
|
||||
tool_name?: string
|
||||
tool_arguments?: string
|
||||
tool_icon?: string | IconObject
|
||||
tool_icon_dark?: string | IconObject
|
||||
tool_files?: string[]
|
||||
tool_error?: string
|
||||
tool_output?: Record<string, any> | string
|
||||
tool_elapsed_time?: number
|
||||
}
|
||||
|
||||
export type ToolCallDetail = {
|
||||
id: string
|
||||
name: string
|
||||
arguments: string
|
||||
result: string
|
||||
output: string
|
||||
files: string[]
|
||||
error: string
|
||||
elapsed_time?: number
|
||||
status: string
|
||||
}
|
||||
export type SequenceSegment
|
||||
= | { type: 'context', start: number, end: number }
|
||||
@ -45,6 +67,18 @@ export type LLMLogItem = {
|
||||
sequence: SequenceSegment[]
|
||||
}
|
||||
|
||||
export type LLMTraceItem = {
|
||||
type: 'model' | 'tool'
|
||||
duration: number
|
||||
output: Record<string, any>
|
||||
provider?: string
|
||||
name: string
|
||||
icon?: string | IconObject
|
||||
icon_dark?: string | IconObject
|
||||
error?: string
|
||||
status?: 'success' | 'error'
|
||||
}
|
||||
|
||||
export type NodeTracing = {
|
||||
id: string
|
||||
index: number
|
||||
@ -89,6 +123,7 @@ export type NodeTracing = {
|
||||
icon?: string
|
||||
}
|
||||
loop_variable_map?: Record<string, any>
|
||||
llm_trace?: LLMTraceItem[]
|
||||
}
|
||||
metadata: {
|
||||
iterator_length: number
|
||||
|
||||
Loading…
Reference in New Issue
Block a user