import BugReportIcon from '@mui/icons-material/BugReport'; import CloseIcon from '@mui/icons-material/Close'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import { Accordion, AccordionDetails, AccordionSummary, Box, Chip, Dialog, DialogContent, DialogTitle, IconButton, Typography } from '@mui/material'; import { styled } from '@mui/material/styles'; import React, { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import type { ExternalAPILogEntity } from '@services/database/schema/externalAPILog'; const StyledDialogTitle = styled(DialogTitle)` display: flex; align-items: center; justify-content: space-between; padding: 16px 24px; `; const LogHeader = styled(Box)` display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; `; const LogContent = styled(Box)` font-family: 'Monaco', 'Consolas', 'Courier New', monospace; font-size: 12px; padding: 12px; border-radius: 4px; overflow-x: auto; white-space: pre-wrap; max-height: 300px; overflow-y: auto; `; const StatusChip = styled(Chip)<{ status: string }>` ${({ status, theme }) => { switch (status) { case 'done': return `background-color: ${theme.palette.success.light}; color: ${theme.palette.success.contrastText};`; case 'error': return `background-color: ${theme.palette.error.light}; color: ${theme.palette.error.contrastText};`; case 'start': return `background-color: ${theme.palette.info.light}; color: ${theme.palette.info.contrastText};`; case 'update': return `background-color: ${theme.palette.warning.light}; color: ${theme.palette.warning.contrastText};`; default: return `background-color: ${theme.palette.grey[300]};`; } }} `; interface APILogsDialogProps { open: boolean; onClose: () => void; agentInstanceId?: string; } export const APILogsDialog: React.FC = ({ open, onClose, agentInstanceId, }) => { const { t } = useTranslation('agent'); const [logs, setLogs] = useState([]); const [loading, setLoading] = useState(false); useEffect(() => { if (open && agentInstanceId) { void loadLogs(); } }, [open, agentInstanceId]); const loadLogs = async () => { if (!agentInstanceId) return; setLoading(true); try { const apiLogs = await window.service.externalAPI.getAPILogs(agentInstanceId, 50, 0); // Filter out embedding logs on the frontend as well const filteredLogs = apiLogs.filter(log => log.callType !== 'embedding'); setLogs(filteredLogs); } catch (error) { console.error('Failed to load API logs:', error); } finally { setLoading(false); } }; const formatTime = (date: Date) => { return new Intl.DateTimeFormat('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', }).format(new Date(date)); }; const getStatusText = (status: string) => { switch (status) { case 'start': return t('APILogs.StatusStart'); case 'update': return t('APILogs.StatusUpdate'); case 'done': return t('APILogs.StatusDone'); case 'error': return t('APILogs.StatusError'); case 'cancel': return t('APILogs.StatusCancel'); default: return status; } }; const hasResponseContent = (rc: unknown): boolean => { if (rc == null) return false; if (typeof rc === 'string') return rc.length > 0; try { return JSON.stringify(rc).length > 0; } catch { return true; } }; return ( {t('APILogs.Title')} {agentInstanceId && ( Agent ID: {agentInstanceId} )} {loading ? {t('Loading')} : logs.length === 0 ? ( {t('APILogs.NoLogs')} ) : ( {t('APILogs.Description')} {agentInstanceId && ( {t('APILogs.CurrentAgent', { agentId: agentInstanceId })} )} {logs.map((log, index) => ( }> {log.requestMetadata.provider} / {log.requestMetadata.model} {formatTime(log.createdAt)} {log.responseMetadata?.duration && ( )} {/* Request Details */} {t('APILogs.RequestDetails')} {JSON.stringify( { metadata: log.requestMetadata, payload: log.requestPayload, }, null, 2, )} {/* Response Content: always show block; display placeholder when missing */} {t('APILogs.ResponseContent')} {hasResponseContent(log.responseContent) ? log.responseContent : t('APILogs.NoResponse')} {/* Response Metadata */} {log.responseMetadata && ( {t('APILogs.ResponseMetadata')} {JSON.stringify(log.responseMetadata, null, 2)} )} {/* Error Details */} {log.errorDetail && ( {t('APILogs.ErrorDetails')} {JSON.stringify(log.errorDetail, null, 2)} )} ))} )} ); };