diff --git a/web/src/components/ui/accordion.tsx b/web/src/components/ui/accordion.tsx index 67ab212d2..08a3659a7 100644 --- a/web/src/components/ui/accordion.tsx +++ b/web/src/components/ui/accordion.tsx @@ -28,8 +28,11 @@ function AccordionItem({ function AccordionTrigger({ className, children, + hideDownIcon = false, ...props -}: React.ComponentProps) { +}: React.ComponentProps & { + hideDownIcon?: boolean; +}) { return ( {children} - + {!hideDownIcon && ( + + )} ); diff --git a/web/src/locales/en.ts b/web/src/locales/en.ts index ecdab4b30..7a5ce123a 100644 --- a/web/src/locales/en.ts +++ b/web/src/locales/en.ts @@ -1322,6 +1322,7 @@ This delimiter is used to split the input text into several text pieces echo of logTimeline: { begin: 'Ready to begin', agent: 'Agent is thinking', + userFillUp: 'Waiting for you', retrieval: 'Looking up knowledge', message: 'Agent says', awaitResponse: 'Waiting for you', diff --git a/web/src/locales/zh.ts b/web/src/locales/zh.ts index 736b13376..7d2d7783e 100644 --- a/web/src/locales/zh.ts +++ b/web/src/locales/zh.ts @@ -1265,6 +1265,7 @@ General:实体和关系提取提示来自 GitHub - microsoft/graphrag:基于 subject: '主题', logTimeline: { begin: '准备开始', + userFillUp: '等你输入', agent: '智能体正在思考', retrieval: '查找知识', message: '回复', diff --git a/web/src/pages/agent/chat/box.tsx b/web/src/pages/agent/chat/box.tsx index 9fd1d2db5..9206e5de3 100644 --- a/web/src/pages/agent/chat/box.tsx +++ b/web/src/pages/agent/chat/box.tsx @@ -13,14 +13,11 @@ import { useUploadCanvasFileWithProgress, } from '@/hooks/use-agent-request'; import { useFetchUserInfo } from '@/hooks/user-setting-hooks'; -import { Message } from '@/interfaces/database/chat'; import { buildMessageUuidWithRole } from '@/utils/chat'; -import { get } from 'lodash'; -import { memo, useCallback, useMemo } from 'react'; +import { memo, useCallback } from 'react'; import { useParams } from 'umi'; import DebugContent from '../debug-content'; -import { BeginQuery } from '../interface'; -import { buildBeginQueryWithObject } from '../utils'; +import { useAwaitCompentData } from '../hooks/use-chat-logic'; function AgentChatBox() { const { @@ -43,33 +40,12 @@ function AgentChatBox() { const { data: canvasInfo } = useFetchAgent(); const { id: canvasId } = useParams(); const { uploadCanvasFile, loading } = useUploadCanvasFileWithProgress(); - const getInputs = useCallback((message: Message) => { - return get(message, 'data.inputs', {}) as Record; - }, []); - const buildInputList = useCallback( - (message: Message) => { - return Object.entries(getInputs(message)).map(([key, val]) => { - return { - ...val, - key, - }; - }); - }, - [getInputs], - ); - - const handleOk = useCallback( - (message: Message) => (values: BeginQuery[]) => { - const inputs = getInputs(message); - const nextInputs = buildBeginQueryWithObject(inputs, values); - sendFormMessage({ - inputs: nextInputs, - id: canvasId, - }); - }, - [canvasId, getInputs, sendFormMessage], - ); + const { buildInputList, handleOk, isWaitting } = useAwaitCompentData({ + derivedMessages, + sendFormMessage, + canvasId: canvasId as string, + }); const handleUploadFile: NonNullable = useCallback( @@ -79,16 +55,7 @@ function AgentChatBox() { }, [appendUploadResponseList, uploadCanvasFile], ); - const isWaitting = useMemo(() => { - const temp = derivedMessages?.some((message, i) => { - const flag = - message.role === MessageType.Assistant && - derivedMessages.length - 1 === i && - message.data; - return flag; - }); - return temp; - }, [derivedMessages]); + return ( <>
diff --git a/web/src/pages/agent/chat/use-send-agent-message.ts b/web/src/pages/agent/chat/use-send-agent-message.ts index 96d4dbf72..ed0785ff2 100644 --- a/web/src/pages/agent/chat/use-send-agent-message.ts +++ b/web/src/pages/agent/chat/use-send-agent-message.ts @@ -269,7 +269,7 @@ export const useSendAgentMessage = ( const sendFormMessage = useCallback( (body: { id?: string; inputs: Record }) => { - send(body); + send({ ...body, session_id: sessionId }); addNewestOneQuestion({ content: Object.entries(body.inputs) .map(([key, val]) => `${key}: ${val.value}`) @@ -277,7 +277,7 @@ export const useSendAgentMessage = ( role: MessageType.User, }); }, - [addNewestOneQuestion, send], + [addNewestOneQuestion, send, sessionId], ); // reset session diff --git a/web/src/pages/agent/hooks/use-chat-logic.ts b/web/src/pages/agent/hooks/use-chat-logic.ts new file mode 100644 index 000000000..42b0533cb --- /dev/null +++ b/web/src/pages/agent/hooks/use-chat-logic.ts @@ -0,0 +1,60 @@ +import { MessageType } from '@/constants/chat'; +import { Message } from '@/interfaces/database/chat'; +import { IMessage } from '@/pages/chat/interface'; +import { get } from 'lodash'; +import { useCallback, useMemo } from 'react'; +import { BeginQuery } from '../interface'; +import { buildBeginQueryWithObject } from '../utils'; +type IAwaitCompentData = { + derivedMessages: IMessage[]; + sendFormMessage: (params: { + inputs: Record; + id: string; + }) => void; + canvasId: string; +}; +const useAwaitCompentData = (props: IAwaitCompentData) => { + const { derivedMessages, sendFormMessage, canvasId } = props; + + const getInputs = useCallback((message: Message) => { + return get(message, 'data.inputs', {}) as Record; + }, []); + + const buildInputList = useCallback( + (message: Message) => { + return Object.entries(getInputs(message)).map(([key, val]) => { + return { + ...val, + key, + }; + }); + }, + [getInputs], + ); + + const handleOk = useCallback( + (message: Message) => (values: BeginQuery[]) => { + const inputs = getInputs(message); + const nextInputs = buildBeginQueryWithObject(inputs, values); + sendFormMessage({ + inputs: nextInputs, + id: canvasId, + }); + }, + [getInputs, sendFormMessage, canvasId], + ); + + const isWaitting = useMemo(() => { + const temp = derivedMessages?.some((message, i) => { + const flag = + message.role === MessageType.Assistant && + derivedMessages.length - 1 === i && + message.data; + return flag; + }); + return temp; + }, [derivedMessages]); + return { getInputs, buildInputList, handleOk, isWaitting }; +}; + +export { useAwaitCompentData }; diff --git a/web/src/pages/agent/log-sheet/toolTimelineItem.tsx b/web/src/pages/agent/log-sheet/toolTimelineItem.tsx index 45bcfc0f3..a143447d0 100644 --- a/web/src/pages/agent/log-sheet/toolTimelineItem.tsx +++ b/web/src/pages/agent/log-sheet/toolTimelineItem.tsx @@ -14,24 +14,37 @@ import { import { cn } from '@/lib/utils'; import { isEmpty } from 'lodash'; import { Operator } from '../constant'; -import OperatorIcon from '../operator-icon'; +import OperatorIcon, { SVGIconMap } from '../operator-icon'; import { JsonViewer, toLowerCaseStringAndDeleteChar, typeMap, } from './workFlowTimeline'; -const capitalizeWords = (str: string, separator: string = '_'): string => { - if (!str) return ''; +type IToolIcon = + | Operator.ArXiv + | Operator.GitHub + | Operator.Bing + | Operator.DuckDuckGo + | Operator.Google + | Operator.GoogleScholar + | Operator.PubMed + | Operator.TavilyExtract + | Operator.TavilySearch + | Operator.Wikipedia + | Operator.YahooFinance + | Operator.WenCai + | Operator.Crawler; - return str - .split(separator) - .map((word) => { - return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); - }) - .join(' '); +const capitalizeWords = (str: string, separator: string = '_'): string[] => { + if (!str) return ['']; + + const resultStrArr = str.split(separator).map((word) => { + return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase(); + }); + return resultStrArr; }; const changeToolName = (toolName: any) => { - const name = 'Agent ' + capitalizeWords(toolName); + const name = 'Agent ' + capitalizeWords(toolName).join(' '); return name; }; const ToolTimelineItem = ({ @@ -61,6 +74,8 @@ const ToolTimelineItem = ({ return ( <> {filteredTools?.map((tool, idx) => { + const toolName = capitalizeWords(tool.tool_name, '_').join(''); + return ( @@ -119,12 +138,14 @@ const ToolTimelineItem = ({ className="bg-background-card px-3" > - +
{!isShare && ( {parentName(tool.path) + ' '} - {capitalizeWords(tool.tool_name, '_')} + {capitalizeWords(tool.tool_name, '_').join(' ')} )} {isShare && ( @@ -142,7 +163,7 @@ const ToolTimelineItem = ({ Online @@ -161,7 +182,7 @@ const ToolTimelineItem = ({ )} {isShare && !isEmpty(tool.arguments) && ( -
+
{tool && tool.arguments && Object.entries(tool.arguments).length && @@ -171,8 +192,8 @@ const ToolTimelineItem = ({
{key}
-
- {val || ''} +
+ {val as string}
); diff --git a/web/src/pages/agent/log-sheet/workFlowTimeline.tsx b/web/src/pages/agent/log-sheet/workFlowTimeline.tsx index cba6e5bbe..c0fc70051 100644 --- a/web/src/pages/agent/log-sheet/workFlowTimeline.tsx +++ b/web/src/pages/agent/log-sheet/workFlowTimeline.tsx @@ -51,7 +51,7 @@ export function JsonViewer({ src={data} displaySize collapseStringsAfterLength={100000000000} - className="w-full h-[200px] break-words overflow-auto scrollbar-auto p-2 bg-slate-800" + className="w-full h-[200px] break-words overflow-auto scrollbar-auto p-2 bg-muted" />
); @@ -81,11 +81,21 @@ export const typeMap = { httpRequest: t('flow.logTimeline.httpRequest'), wenCai: t('flow.logTimeline.wenCai'), yahooFinance: t('flow.logTimeline.yahooFinance'), + userFillUp: t('flow.logTimeline.userFillUp'), }; export const toLowerCaseStringAndDeleteChar = ( str: string, char: string = '_', ) => str.toLowerCase().replace(/ /g, '').replaceAll(char, ''); + +// Convert all keys in typeMap to lowercase and output the new typeMap +export const typeMapLowerCase = Object.fromEntries( + Object.entries(typeMap).map(([key, value]) => [ + toLowerCaseStringAndDeleteChar(key), + value, + ]), +); + function getInputsOrOutputs( nodeEventList: INodeData[], field: 'inputs' | 'outputs', @@ -247,16 +257,19 @@ export const WorkFlowTimeline = ({ className="bg-background-card px-3" > - +
{!isShare && getNodeName(x.data?.component_name)} {isShare && - typeMap[ + (typeMapLowerCase[ toLowerCaseStringAndDeleteChar( nodeLabel, ) as keyof typeof typeMap - ]} + ] ?? + nodeLabel)} {x.data.elapsed_time?.toString().slice(0, 6)} @@ -294,7 +307,7 @@ export const WorkFlowTimeline = ({ {isShare && x.data?.thoughts && (
-
+
{x.data.thoughts || ''} diff --git a/web/src/pages/agent/operator-icon.tsx b/web/src/pages/agent/operator-icon.tsx index 5500bf4b3..cf8d9af4a 100644 --- a/web/src/pages/agent/operator-icon.tsx +++ b/web/src/pages/agent/operator-icon.tsx @@ -38,7 +38,7 @@ export const OperatorIconMap = { [Operator.Email]: 'sendemail-0', }; -const SVGIconMap = { +export const SVGIconMap = { [Operator.ArXiv]: ArxivIcon, [Operator.GitHub]: GithubIcon, [Operator.Bing]: BingIcon, diff --git a/web/src/pages/agents/agent-log-page.tsx b/web/src/pages/agents/agent-log-page.tsx index 9ec106487..c4ce9f33a 100644 --- a/web/src/pages/agents/agent-log-page.tsx +++ b/web/src/pages/agents/agent-log-page.tsx @@ -231,7 +231,7 @@ const AgentLogPage: React.FC = () => {

Log

-
+
ID/Title { appendUploadResponseList, parameterDialogVisible, showParameterDialog, + sendFormMessage, ok, resetSession, } = useSendNextSharedMessage(addEventList); - + const { buildInputList, handleOk, isWaitting } = useAwaitCompentData({ + derivedMessages, + sendFormMessage, + canvasId: conversationId as string, + }); const sendDisabled = useSendButtonDisabled(value); const appConf = useFetchAppConf(); const { data: inputsData } = useFetchExternalAgentInputs(); @@ -171,7 +178,28 @@ const ChatContainer = () => { showLoudspeaker={false} showLog={false} sendLoading={sendLoading} - > + > + {message.role === MessageType.Assistant && + derivedMessages.length - 1 === i && ( + + )} + {message.role === MessageType.Assistant && + derivedMessages.length - 1 !== i && ( +
+
{message?.data?.tips}
+ +
+ {buildInputList(message)?.map((item) => item.value)} +
+
+ )} + ); })}
@@ -182,15 +210,15 @@ const ChatContainer = () => {
diff --git a/web/tailwind.css b/web/tailwind.css index 42543ef20..5319fe028 100644 --- a/web/tailwind.css +++ b/web/tailwind.css @@ -246,7 +246,7 @@ @layer utilities { .scrollbar-auto { /* hide scrollbar */ - scrollbar-width: thin; + scrollbar-width: none; scrollbar-color: transparent transparent; }