### What problem does this PR solve? Fix: Add agent-log-list page And RAPTOR:Save directly after enabling, incomplete form submission #3221 ### Type of change - [x] Bug Fix (non-breaking change which fixes an issue)tags/v0.20.0
| @@ -0,0 +1,186 @@ | |||
| import { | |||
| endOfMonth, | |||
| endOfYear, | |||
| format, | |||
| startOfMonth, | |||
| startOfYear, | |||
| subDays, | |||
| subMonths, | |||
| subYears, | |||
| } from 'date-fns'; | |||
| import { useEffect, useId, useState } from 'react'; | |||
| import { Calendar, DateRange } from '@/components/originui/calendar'; | |||
| import { Button } from '@/components/ui/button'; | |||
| import { | |||
| Popover, | |||
| PopoverContent, | |||
| PopoverTrigger, | |||
| } from '@/components/ui/popover'; | |||
| import { cn } from '@/lib/utils'; | |||
| import { CalendarIcon } from 'lucide-react'; | |||
| const CalendarComp = ({ | |||
| selectDateRange, | |||
| onSelect, | |||
| ...props | |||
| }: ITimeRangePickerProps) => { | |||
| const today = new Date(); | |||
| const yesterday = { | |||
| from: subDays(today, 1), | |||
| to: subDays(today, 1), | |||
| }; | |||
| const last7Days = { | |||
| from: subDays(today, 6), | |||
| to: today, | |||
| }; | |||
| const last30Days = { | |||
| from: subDays(today, 29), | |||
| to: today, | |||
| }; | |||
| const monthToDate = { | |||
| from: startOfMonth(today), | |||
| to: today, | |||
| }; | |||
| const lastMonth = { | |||
| from: startOfMonth(subMonths(today, 1)), | |||
| to: endOfMonth(subMonths(today, 1)), | |||
| }; | |||
| const yearToDate = { | |||
| from: startOfYear(today), | |||
| to: today, | |||
| }; | |||
| const lastYear = { | |||
| from: startOfYear(subYears(today, 1)), | |||
| to: endOfYear(subYears(today, 1)), | |||
| }; | |||
| const dateRangeList = [ | |||
| { key: 'yestday', value: yesterday }, | |||
| { key: 'last7Days', value: last7Days }, | |||
| { key: 'last30Days', value: last30Days }, | |||
| { key: 'monthToDate', value: monthToDate }, | |||
| { key: 'lastMonth', value: lastMonth }, | |||
| { key: 'yearToDate', value: yearToDate }, | |||
| { key: 'lastYear', value: lastYear }, | |||
| ]; | |||
| const [month, setMonth] = useState(today); | |||
| const [date, setDate] = useState<DateRange>(selectDateRange || last7Days); | |||
| useEffect(() => { | |||
| onSelect?.(date); | |||
| }, [date, onSelect]); | |||
| return ( | |||
| <div> | |||
| <div className="rounded-md border"> | |||
| <div className="flex max-sm:flex-col"> | |||
| <div className="relative py-4 max-sm:order-1 max-sm:border-t sm:w-32"> | |||
| <div className="h-full sm:border-e"> | |||
| <div className="flex flex-col px-2 gap-2"> | |||
| <Button | |||
| variant="ghost" | |||
| size="sm" | |||
| className="w-full justify-start" | |||
| onClick={() => { | |||
| setDate({ | |||
| from: today, | |||
| to: today, | |||
| }); | |||
| setMonth(today); | |||
| }} | |||
| > | |||
| Today | |||
| </Button> | |||
| {dateRangeList.map((dateRange) => ( | |||
| <Button | |||
| key={dateRange.key} | |||
| variant="ghost" | |||
| size="sm" | |||
| className="w-full justify-start" | |||
| onClick={() => { | |||
| setDate(dateRange.value); | |||
| setMonth(dateRange.value.to); | |||
| }} | |||
| > | |||
| {dateRange.key} | |||
| </Button> | |||
| ))} | |||
| </div> | |||
| </div> | |||
| </div> | |||
| <Calendar | |||
| mode="range" | |||
| selected={date} | |||
| onSelect={(newDate) => { | |||
| if (newDate) { | |||
| setDate(newDate as DateRange); | |||
| } | |||
| }} | |||
| month={month} | |||
| onMonthChange={setMonth} | |||
| className="p-2" | |||
| {...props} | |||
| // disabled={[ | |||
| // { after: today }, // Dates before today | |||
| // ]} | |||
| /> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| ); | |||
| }; | |||
| export type ITimeRangePickerProps = { | |||
| onSelect: (e: DateRange) => void; | |||
| selectDateRange: DateRange; | |||
| className?: string; | |||
| }; | |||
| const TimeRangePicker = ({ | |||
| onSelect, | |||
| selectDateRange, | |||
| ...props | |||
| }: ITimeRangePickerProps) => { | |||
| const id = useId(); | |||
| const today = new Date(); | |||
| const [date, setDate] = useState<DateRange | undefined>( | |||
| selectDateRange || { from: today, to: today }, | |||
| ); | |||
| const onChange = (e: DateRange | undefined) => { | |||
| if (!e) return; | |||
| setDate(e); | |||
| onSelect?.(e); | |||
| }; | |||
| return ( | |||
| <Popover> | |||
| <PopoverTrigger asChild> | |||
| <Button | |||
| id={id} | |||
| variant="outline" | |||
| className="group bg-muted-foreground/10 hover:bg-muted-foreground/10 border-input w-full justify-between px-3 font-normal outline-offset-0 outline-none focus-visible:outline-[3px]" | |||
| > | |||
| <span className={cn('truncate', !date && 'text-muted-foreground')}> | |||
| {date?.from ? ( | |||
| date.to ? ( | |||
| <> | |||
| {format(date.from, 'LLL dd, y')} -{' '} | |||
| {format(date.to, 'LLL dd, y')} | |||
| </> | |||
| ) : ( | |||
| format(date.from, 'LLL dd, y') | |||
| ) | |||
| ) : ( | |||
| 'Pick a date range' | |||
| )} | |||
| </span> | |||
| <CalendarIcon | |||
| size={16} | |||
| className="text-muted-foreground/80 group-hover:text-foreground shrink-0 transition-colors" | |||
| aria-hidden="true" | |||
| /> | |||
| </Button> | |||
| </PopoverTrigger> | |||
| <PopoverContent className="w-auto p-2" align="start"> | |||
| <CalendarComp selectDateRange={date} onSelect={onChange} {...props} /> | |||
| </PopoverContent> | |||
| </Popover> | |||
| ); | |||
| }; | |||
| export default TimeRangePicker; | |||
| @@ -54,6 +54,13 @@ export const useNavigatePage = () => { | |||
| [navigate], | |||
| ); | |||
| const navigateToAgentLogs = useCallback( | |||
| (id: string) => () => { | |||
| navigate(`${Routes.AgentLogPage}/${id}`); | |||
| }, | |||
| [navigate], | |||
| ); | |||
| const navigateToAgentTemplates = useCallback(() => { | |||
| navigate(Routes.AgentTemplates); | |||
| }, [navigate]); | |||
| @@ -120,6 +127,7 @@ export const useNavigatePage = () => { | |||
| navigateToChunk, | |||
| navigateToAgents, | |||
| navigateToAgent, | |||
| navigateToAgentLogs, | |||
| navigateToAgentTemplates, | |||
| navigateToSearchList, | |||
| navigateToSearch, | |||
| @@ -1,13 +1,20 @@ | |||
| import { FileUploadProps } from '@/components/file-upload'; | |||
| import message from '@/components/ui/message'; | |||
| import { AgentGlobals } from '@/constants/agent'; | |||
| import { ITraceData } from '@/interfaces/database/agent'; | |||
| import { | |||
| IAgentLogsRequest, | |||
| IAgentLogsResponse, | |||
| ITraceData, | |||
| } from '@/interfaces/database/agent'; | |||
| import { DSL, IFlow, IFlowTemplate } from '@/interfaces/database/flow'; | |||
| import { IDebugSingleRequestBody } from '@/interfaces/request/agent'; | |||
| import i18n from '@/locales/config'; | |||
| import { BeginId } from '@/pages/agent/constant'; | |||
| import { useGetSharedChatSearchParams } from '@/pages/chat/shared-hooks'; | |||
| import agentService, { fetchTrace } from '@/services/agent-service'; | |||
| import agentService, { | |||
| fetchAgentLogsByCanvasId, | |||
| fetchTrace, | |||
| } from '@/services/agent-service'; | |||
| import api from '@/utils/api'; | |||
| import { buildMessageListWithUuid } from '@/utils/chat'; | |||
| import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; | |||
| @@ -558,3 +565,22 @@ export const useFetchAgentAvatar = (): { | |||
| return { data, loading, refetch }; | |||
| }; | |||
| export const useFetchAgentLog = (searchParams: IAgentLogsRequest) => { | |||
| const { id } = useParams(); | |||
| const { data, isFetching: loading } = useQuery<IAgentLogsResponse>({ | |||
| queryKey: ['fetchAgentLog', id, searchParams], | |||
| initialData: {} as IAgentLogsResponse, | |||
| gcTime: 0, | |||
| queryFn: async () => { | |||
| console.log('useFetchAgentLog', searchParams); | |||
| const { data } = await fetchAgentLogsByCanvasId(id as string, { | |||
| ...searchParams, | |||
| }); | |||
| return data?.data ?? []; | |||
| }, | |||
| }); | |||
| return { data, loading }; | |||
| }; | |||
| @@ -229,3 +229,38 @@ export interface ITraceData { | |||
| component_id: string; | |||
| trace: Array<Record<string, any>>; | |||
| } | |||
| export interface IAgentLogResponse { | |||
| id: string; | |||
| message: IAgentLogMessage[]; | |||
| update_date: string; | |||
| create_date: string; | |||
| update_time: number; | |||
| create_time: number; | |||
| round: number; | |||
| thumb_up: number; | |||
| errors: string; | |||
| source: string; | |||
| user_id: string; | |||
| dsl: string; | |||
| reference: IReference; | |||
| } | |||
| export interface IAgentLogsResponse { | |||
| total: number; | |||
| sessions: IAgentLogResponse[]; | |||
| } | |||
| export interface IAgentLogsRequest { | |||
| keywords?: string; | |||
| to_date?: string | Date; | |||
| from_date?: string | Date; | |||
| orderby?: string; | |||
| desc?: boolean; | |||
| page?: number; | |||
| page_size?: number; | |||
| } | |||
| export interface IAgentLogMessage { | |||
| content: string; | |||
| role: 'user' | 'assistant'; | |||
| id: string; | |||
| } | |||
| @@ -25,7 +25,6 @@ import { | |||
| CirclePlay, | |||
| Download, | |||
| History, | |||
| Key, | |||
| LaptopMinimalCheck, | |||
| Logs, | |||
| ScreenShare, | |||
| @@ -42,7 +41,6 @@ import { | |||
| useGetBeginNodeDataInputs, | |||
| useGetBeginNodeDataQueryIsSafe, | |||
| } from './hooks/use-get-begin-query'; | |||
| import { useOpenDocument } from './hooks/use-open-document'; | |||
| import { | |||
| useSaveGraph, | |||
| useSaveGraphBeforeOpeningDebugDrawer, | |||
| @@ -73,7 +71,7 @@ export default function Agent() { | |||
| const { t } = useTranslation(); | |||
| const { data: userInfo } = useFetchUserInfo(); | |||
| const openDocument = useOpenDocument(); | |||
| // const openDocument = useOpenDocument(); | |||
| const { | |||
| handleExportJson, | |||
| handleImportJson, | |||
| @@ -100,7 +98,7 @@ export default function Agent() { | |||
| const { showEmbedModal, hideEmbedModal, embedVisible, beta } = | |||
| useShowEmbedModal(); | |||
| const { navigateToAgentLogs } = useNavigatePage(); | |||
| const isBeginNodeDataQuerySafe = useGetBeginNodeDataQueryIsSafe(); | |||
| return ( | |||
| @@ -135,7 +133,10 @@ export default function Agent() { | |||
| <History /> | |||
| {t('flow.historyversion')} | |||
| </Button> | |||
| <Button variant={'secondary'}> | |||
| <Button | |||
| variant={'secondary'} | |||
| onClick={navigateToAgentLogs(id as string)} | |||
| > | |||
| <Logs /> | |||
| {t('flow.log')} | |||
| </Button> | |||
| @@ -147,11 +148,11 @@ export default function Agent() { | |||
| </Button> | |||
| </DropdownMenuTrigger> | |||
| <DropdownMenuContent> | |||
| <AgentDropdownMenuItem onClick={openDocument}> | |||
| {/* <AgentDropdownMenuItem onClick={openDocument}> | |||
| <Key /> | |||
| API | |||
| </AgentDropdownMenuItem> | |||
| <DropdownMenuSeparator /> | |||
| </AgentDropdownMenuItem> */} | |||
| {/* <DropdownMenuSeparator /> */} | |||
| <AgentDropdownMenuItem onClick={handleImportJson}> | |||
| <Download /> | |||
| {t('flow.import')} | |||
| @@ -0,0 +1,319 @@ | |||
| import TimeRangePicker from '@/components/originui/time-range-picker'; | |||
| import { PageHeader } from '@/components/page-header'; | |||
| import { | |||
| Breadcrumb, | |||
| BreadcrumbItem, | |||
| BreadcrumbLink, | |||
| BreadcrumbList, | |||
| BreadcrumbPage, | |||
| BreadcrumbSeparator, | |||
| } from '@/components/ui/breadcrumb'; | |||
| import { SearchInput } from '@/components/ui/input'; | |||
| import { RAGFlowPagination } from '@/components/ui/ragflow-pagination'; | |||
| import { Spin } from '@/components/ui/spin'; | |||
| import { useNavigatePage } from '@/hooks/logic-hooks/navigate-hooks'; | |||
| import { useFetchAgentLog } from '@/hooks/use-agent-request'; | |||
| import { IAgentLogResponse } from '@/interfaces/database/agent'; | |||
| import React, { useEffect, useState } from 'react'; | |||
| import { useParams } from 'umi'; | |||
| import { DateRange } from '../../components/originui/calendar/index'; | |||
| import { | |||
| Table, | |||
| TableBody, | |||
| TableCell, | |||
| TableHead, | |||
| TableHeader, | |||
| TableRow, | |||
| } from '../../components/ui/table'; | |||
| import { useFetchDataOnMount } from '../agent/hooks/use-fetch-data'; | |||
| const AgentLogPage: React.FC = () => { | |||
| const { navigateToAgentList, navigateToAgent } = useNavigatePage(); | |||
| const { flowDetail: agentDetail } = useFetchDataOnMount(); | |||
| const { id: canvasId } = useParams(); | |||
| const today = new Date(); | |||
| const init = { | |||
| keywords: '', | |||
| from_date: today, | |||
| to_date: today, | |||
| orderby: 'create_time', | |||
| desc: false, | |||
| page: 1, | |||
| page_size: 10, | |||
| }; | |||
| const [searchParams, setSearchParams] = useState(init); | |||
| const columns = [ | |||
| { | |||
| title: 'ID', | |||
| dataIndex: 'id', | |||
| key: 'id', | |||
| }, | |||
| { | |||
| title: 'Title', | |||
| dataIndex: 'title', | |||
| key: 'title', | |||
| render: (text, record: IAgentLogResponse) => ( | |||
| <span> | |||
| {record?.message?.length ? record?.message[0]?.content : ''} | |||
| </span> | |||
| ), | |||
| }, | |||
| { | |||
| title: 'State', | |||
| dataIndex: 'state', | |||
| key: 'state', | |||
| render: (text, record: IAgentLogResponse) => ( | |||
| <div | |||
| className="size-2 rounded-full" | |||
| style={{ backgroundColor: record.errors ? 'red' : 'green' }} | |||
| ></div> | |||
| ), | |||
| }, | |||
| { | |||
| title: 'Number', | |||
| dataIndex: 'round', | |||
| key: 'round', | |||
| }, | |||
| { | |||
| title: 'Latest Date', | |||
| dataIndex: 'update_date', | |||
| key: 'update_date', | |||
| sortable: true, | |||
| }, | |||
| { | |||
| title: 'Create Date', | |||
| dataIndex: 'create_date', | |||
| key: 'create_date', | |||
| sortable: true, | |||
| }, | |||
| ]; | |||
| const { data: logData, loading } = useFetchAgentLog(searchParams); | |||
| const { sessions: data, total } = logData || {}; | |||
| const [currentDate, setCurrentDate] = useState<DateRange>({ | |||
| from: searchParams.from_date, | |||
| to: searchParams.to_date, | |||
| }); | |||
| const [keywords, setKeywords] = useState(searchParams.keywords); | |||
| const handleDateRangeChange = ({ | |||
| from: startDate, | |||
| to: endDate, | |||
| }: DateRange) => { | |||
| setCurrentDate({ from: startDate, to: endDate }); | |||
| }; | |||
| const [pagination, setPagination] = useState<{ | |||
| current: number; | |||
| pageSize: number; | |||
| total: number; | |||
| }>({ | |||
| current: 1, | |||
| pageSize: 10, | |||
| total: total, | |||
| }); | |||
| useEffect(() => { | |||
| setPagination((pre) => { | |||
| return { | |||
| ...pre, | |||
| total: total, | |||
| }; | |||
| }); | |||
| }, [total]); | |||
| const [sortConfig, setSortConfig] = useState<{ | |||
| orderby: string; | |||
| desc: boolean; | |||
| } | null>({ orderby: init.orderby, desc: init.desc ? true : false }); | |||
| const handlePageChange = (current?: number, pageSize?: number) => { | |||
| console.log('current', current, 'pageSize', pageSize); | |||
| setPagination((pre) => { | |||
| return { | |||
| ...pre, | |||
| current: current ?? pre.current, | |||
| pageSize: pageSize ?? pre.pageSize, | |||
| }; | |||
| }); | |||
| }; | |||
| const handleSearch = () => { | |||
| setSearchParams((pre) => { | |||
| return { | |||
| ...pre, | |||
| from_date: currentDate.from as Date, | |||
| to_date: currentDate.to as Date, | |||
| page: pagination.current, | |||
| page_size: pagination.pageSize, | |||
| orderby: sortConfig?.orderby || '', | |||
| desc: sortConfig?.desc as boolean, | |||
| keywords: keywords, | |||
| }; | |||
| }); | |||
| }; | |||
| useEffect(() => { | |||
| handleSearch(); | |||
| }, [pagination.current, pagination.pageSize, sortConfig]); | |||
| // handle sort | |||
| const handleSort = (key: string) => { | |||
| let desc = false; | |||
| if (sortConfig && sortConfig.orderby === key) { | |||
| desc = !sortConfig.desc; | |||
| } | |||
| setSortConfig({ orderby: key, desc }); | |||
| }; | |||
| const handleReset = () => { | |||
| setSearchParams(init); | |||
| }; | |||
| return ( | |||
| <div className=" text-white"> | |||
| <PageHeader> | |||
| <Breadcrumb> | |||
| <BreadcrumbList> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbLink onClick={navigateToAgentList}> | |||
| Agent | |||
| </BreadcrumbLink> | |||
| </BreadcrumbItem> | |||
| <BreadcrumbSeparator /> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbLink onClick={navigateToAgent(canvasId as string)}> | |||
| {agentDetail.title} | |||
| </BreadcrumbLink> | |||
| </BreadcrumbItem> | |||
| <BreadcrumbSeparator /> | |||
| <BreadcrumbItem> | |||
| <BreadcrumbPage>Log</BreadcrumbPage> | |||
| </BreadcrumbItem> | |||
| </BreadcrumbList> | |||
| </Breadcrumb> | |||
| </PageHeader> | |||
| <div className="p-4"> | |||
| <div className="flex justify-between items-center"> | |||
| <h1 className="text-2xl font-bold mb-4">Log</h1> | |||
| <div className="flex justify-end space-x-2 mb-4"> | |||
| <div className="flex items-center space-x-2"> | |||
| <span>ID/Title</span> | |||
| <SearchInput | |||
| value={keywords} | |||
| onChange={(e) => { | |||
| setKeywords(e.target.value); | |||
| }} | |||
| className="w-32" | |||
| ></SearchInput> | |||
| </div> | |||
| <div className="flex items-center space-x-2"> | |||
| <span className="whitespace-nowrap">Latest Date</span> | |||
| <TimeRangePicker | |||
| onSelect={handleDateRangeChange} | |||
| selectDateRange={{ from: currentDate.from, to: currentDate.to }} | |||
| /> | |||
| </div> | |||
| <button | |||
| type="button" | |||
| className="bg-foreground text-text-title-invert px-4 py-1 rounded" | |||
| onClick={() => { | |||
| setPagination({ ...pagination, current: 1 }); | |||
| handleSearch(); | |||
| }} | |||
| > | |||
| Search | |||
| </button> | |||
| <button | |||
| type="button" | |||
| className="bg-transparent text-foreground px-4 py-1 rounded border" | |||
| onClick={() => handleReset()} | |||
| > | |||
| Reset | |||
| </button> | |||
| </div> | |||
| </div> | |||
| <div className="border rounded-md overflow-auto"> | |||
| {/* <div className="max-h-[500px] overflow-y-auto w-full"> */} | |||
| <Table rootClassName="max-h-[calc(100vh-200px)]"> | |||
| <TableHeader className="sticky top-0 bg-background z-10 shadow-sm"> | |||
| <TableRow> | |||
| {columns.map((column) => ( | |||
| <TableHead | |||
| key={column.dataIndex} | |||
| onClick={ | |||
| column.sortable | |||
| ? () => handleSort(column.dataIndex) | |||
| : undefined | |||
| } | |||
| className={ | |||
| column.sortable ? 'cursor-pointer hover:bg-muted/50' : '' | |||
| } | |||
| > | |||
| <div className="flex items-center"> | |||
| {column.title} | |||
| {column.sortable && | |||
| sortConfig?.orderby === column.dataIndex && ( | |||
| <span className="ml-1"> | |||
| {sortConfig.desc ? '↓' : '↑'} | |||
| </span> | |||
| )} | |||
| </div> | |||
| </TableHead> | |||
| ))} | |||
| </TableRow> | |||
| </TableHeader> | |||
| <TableBody> | |||
| {loading && ( | |||
| <TableRow> | |||
| <TableCell | |||
| colSpan={columns.length} | |||
| className="h-24 text-center" | |||
| > | |||
| <Spin size="large"> | |||
| <span className="sr-only">Loading...</span> | |||
| </Spin> | |||
| </TableCell> | |||
| </TableRow> | |||
| )} | |||
| {!loading && | |||
| data?.map((item) => ( | |||
| <TableRow key={item.id}> | |||
| {columns.map((column) => ( | |||
| <TableCell key={column.dataIndex}> | |||
| {column.render | |||
| ? column.render(item[column.dataIndex], item) | |||
| : item[column.dataIndex]} | |||
| </TableCell> | |||
| ))} | |||
| </TableRow> | |||
| ))} | |||
| {!loading && (!data || data.length === 0) && ( | |||
| <TableRow> | |||
| <TableCell | |||
| colSpan={columns.length} | |||
| className="h-24 text-center" | |||
| > | |||
| No data | |||
| </TableCell> | |||
| </TableRow> | |||
| )} | |||
| </TableBody> | |||
| </Table> | |||
| {/* </div> */} | |||
| </div> | |||
| <div className="flex justify-end mt-4 w-full"> | |||
| <div className="space-x-2"> | |||
| <RAGFlowPagination | |||
| {...pagination} | |||
| total={pagination.total} | |||
| onChange={(page, pageSize) => { | |||
| handlePageChange(page, pageSize); | |||
| }} | |||
| ></RAGFlowPagination> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| </div> | |||
| ); | |||
| }; | |||
| export default AgentLogPage; | |||
| @@ -88,13 +88,17 @@ export function ChunkMethodForm() { | |||
| let beValid = await form.formControl.trigger(); | |||
| if (beValid) { | |||
| // setSubmitLoading(true); | |||
| let postData = form.formState.values; | |||
| delete postData['avatar']; // has submitted in first form general | |||
| saveKnowledgeConfiguration({ | |||
| ...postData, | |||
| kb_id, | |||
| }); | |||
| // let postData = form.formState.values; | |||
| // console.log('submit form -->', form); | |||
| // delete postData['avatar']; // has submitted in first form general | |||
| form.handleSubmit(async (values) => { | |||
| console.log('saveKnowledgeConfiguration: ', values); | |||
| delete values['avatar']; | |||
| await saveKnowledgeConfiguration({ | |||
| kb_id, | |||
| ...values, | |||
| }); | |||
| })(); | |||
| } | |||
| } catch (e) { | |||
| console.log(e); | |||
| @@ -36,6 +36,7 @@ export enum Routes { | |||
| Result = '/result', | |||
| ResultView = `${Chunk}${Result}`, | |||
| KnowledgeGraph = '/knowledge-graph', | |||
| AgentLogPage = '/agent-log-page', | |||
| } | |||
| const routes = [ | |||
| @@ -244,6 +245,11 @@ const routes = [ | |||
| }, | |||
| ], | |||
| }, | |||
| { | |||
| path: `${Routes.AgentLogPage}/:id`, | |||
| layout: false, | |||
| component: `@/pages${Routes.Agents}${Routes.AgentLogPage}`, | |||
| }, | |||
| { | |||
| path: `${Routes.Agent}/:id`, | |||
| layout: false, | |||
| @@ -1,3 +1,4 @@ | |||
| import { IAgentLogsRequest } from '@/interfaces/database/agent'; | |||
| import api from '@/utils/api'; | |||
| import { registerNextServer } from '@/utils/register-server'; | |||
| import request from '@/utils/request'; | |||
| @@ -22,6 +23,7 @@ const { | |||
| fetchVersion, | |||
| fetchCanvas, | |||
| fetchAgentAvatar, | |||
| fetchAgentLogs, | |||
| } = api; | |||
| const methods = { | |||
| @@ -101,6 +103,10 @@ const methods = { | |||
| url: fetchAgentAvatar, | |||
| method: 'get', | |||
| }, | |||
| fetchAgentLogs: { | |||
| url: fetchAgentLogs, | |||
| method: 'get', | |||
| }, | |||
| } as const; | |||
| const agentService = registerNextServer<keyof typeof methods>(methods); | |||
| @@ -108,5 +114,11 @@ const agentService = registerNextServer<keyof typeof methods>(methods); | |||
| export const fetchTrace = (data: { canvas_id: string; message_id: string }) => { | |||
| return request.get(methods.trace.url, { params: data }); | |||
| }; | |||
| export const fetchAgentLogsByCanvasId = ( | |||
| canvasId: string, | |||
| params: IAgentLogsRequest, | |||
| ) => { | |||
| return request.get(methods.fetchAgentLogs.url(canvasId), { params: params }); | |||
| }; | |||
| export default agentService; | |||
| @@ -153,6 +153,8 @@ export default { | |||
| fetchCanvas: (id: string) => `${api_host}/canvas/get/${id}`, | |||
| fetchAgentAvatar: (id: string) => `${api_host}/canvas/getsse/${id}`, | |||
| uploadAgentFile: (id?: string) => `${api_host}/canvas/upload/${id}`, | |||
| fetchAgentLogs: (canvasId: string) => | |||
| `${api_host}/canvas/${canvasId}/sessions`, | |||
| // mcp server | |||
| listMcpServer: `${api_host}/mcp_server/list`, | |||
| @@ -32,3 +32,14 @@ export function formatPureDate(date: any) { | |||
| } | |||
| return dayjs(date).format('DD/MM/YYYY'); | |||
| } | |||
| export function formatStandardDate(date: any) { | |||
| if (!date) { | |||
| return ''; | |||
| } | |||
| const parsedDate = dayjs(date); | |||
| if (!parsedDate.isValid()) { | |||
| return ''; | |||
| } | |||
| return parsedDate.format('YYYY-MM-DD'); | |||
| } | |||