1
This commit is contained in:
parent
754bb02c12
commit
d885dffb53
@ -70,7 +70,7 @@ class CryptoAgent:
|
||||
)
|
||||
monitor.update_config("crypto_agent", {
|
||||
"symbols": self.symbols,
|
||||
"paper_trading_enabled": self.paper_trading_enabled,
|
||||
"auto_trading_enabled": self.paper_trading_enabled, # 改名为自动交易
|
||||
"analysis_interval": "每5分钟整点"
|
||||
})
|
||||
|
||||
|
||||
@ -15,6 +15,7 @@ from app.services.telegram_service import get_telegram_service
|
||||
from app.services.signal_database_service import get_signal_db_service
|
||||
from app.services.fundamental_service import get_fundamental_service
|
||||
from app.crypto_agent.llm_signal_analyzer import LLMSignalAnalyzer
|
||||
from app.utils.system_status import get_system_monitor, AgentStatus
|
||||
|
||||
|
||||
# 股票名称映射表
|
||||
@ -104,7 +105,28 @@ class StockAgent:
|
||||
self._event_loop = None
|
||||
self._task = None
|
||||
|
||||
logger.info(f"股票智能体初始化完成 - 美股: {len(us_symbols)}只, 港股: {len(hk_symbols)}只, 总计: {len(self.symbols)}只")
|
||||
# 注册到系统监控
|
||||
monitor = get_system_monitor()
|
||||
self._monitor_info = monitor.register_agent(
|
||||
agent_id="stock_agent",
|
||||
name="股票智能体",
|
||||
agent_type="stock"
|
||||
)
|
||||
|
||||
# 分类美股和港股数量
|
||||
us_count = len([s for s in self.symbols if not s.endswith('.HK')])
|
||||
hk_count = len([s for s in self.symbols if s.endswith('.HK')])
|
||||
|
||||
monitor.update_config("stock_agent", {
|
||||
"us_symbols": us_symbols,
|
||||
"hk_symbols": hk_symbols,
|
||||
"total_symbols": len(self.symbols),
|
||||
"us_count": us_count,
|
||||
"hk_count": hk_count,
|
||||
"analysis_interval": f"{self.settings.stock_analysis_interval}秒"
|
||||
})
|
||||
|
||||
logger.info(f"股票智能体初始化完成 - 美股: {us_count}只, 港股: {hk_count}只, 总计: {len(self.symbols)}只")
|
||||
|
||||
@staticmethod
|
||||
def get_stock_name(symbol: str) -> str:
|
||||
@ -120,14 +142,26 @@ class StockAgent:
|
||||
self.running = True
|
||||
self._event_loop = asyncio.get_event_loop()
|
||||
|
||||
# 更新状态为启动中
|
||||
monitor = get_system_monitor()
|
||||
monitor.update_status("stock_agent", AgentStatus.STARTING)
|
||||
|
||||
logger.info("美股智能体已启动")
|
||||
|
||||
# 启动分析任务
|
||||
self._task = asyncio.create_task(self._analysis_loop())
|
||||
|
||||
# 更新状态为运行中
|
||||
monitor.update_status("stock_agent", AgentStatus.RUNNING)
|
||||
|
||||
async def stop(self):
|
||||
"""停止智能体"""
|
||||
self.running = False
|
||||
|
||||
# 更新状态为已停止
|
||||
monitor = get_system_monitor()
|
||||
monitor.update_status("stock_agent", AgentStatus.STOPPED)
|
||||
|
||||
if self._task:
|
||||
self._task.cancel()
|
||||
try:
|
||||
|
||||
@ -2,181 +2,222 @@
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>系统状态监控 - Stock Agent</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<title>系统状态 - Stock Agent</title>
|
||||
<link rel="stylesheet" href="/static/css/style.css">
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
/* 防止横向滚动 */
|
||||
html, body {
|
||||
overflow-x: hidden;
|
||||
max-width: 100vw;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
/* 覆盖全局 #app 样式 */
|
||||
#app {
|
||||
height: auto;
|
||||
display: block;
|
||||
align-items: initial;
|
||||
justify-content: initial;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.status-page {
|
||||
min-height: 100vh;
|
||||
background: var(--bg-primary);
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
.status-container {
|
||||
max-width: 1400px;
|
||||
min-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.header {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
/* 固定顶部区域 */
|
||||
.sticky-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 100;
|
||||
background: var(--bg-primary);
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
||||
.status-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||
padding: 10px 0 20px 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: var(--bg-primary);
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
font-size: 32px;
|
||||
color: #333;
|
||||
margin-bottom: 10px;
|
||||
.status-title {
|
||||
font-size: 24px;
|
||||
font-weight: 300;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.header .subtitle {
|
||||
color: #666;
|
||||
.status-title span {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
padding: 8px 16px;
|
||||
background: transparent;
|
||||
border: 1px solid var(--accent);
|
||||
color: var(--accent);
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.system-overview {
|
||||
.refresh-btn:hover {
|
||||
background: var(--accent);
|
||||
color: var(--bg-primary);
|
||||
}
|
||||
|
||||
.last-update {
|
||||
text-align: right;
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* 统计卡片 */
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 25px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||
transition: transform 0.3s ease;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.stat-card:hover {
|
||||
transform: translateY(-5px);
|
||||
.stat-label {
|
||||
font-size: 12px;
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.stat-card .label {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.stat-card .value {
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.stat-card.running .value {
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.stat-card.error .value {
|
||||
color: #ef4444;
|
||||
}
|
||||
|
||||
.agents-section {
|
||||
background: white;
|
||||
border-radius: 16px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.agents-section h2 {
|
||||
.stat-value {
|
||||
font-size: 24px;
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 300;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.agent-grid {
|
||||
.stat-value.running {
|
||||
color: #00ff41;
|
||||
}
|
||||
|
||||
.stat-value.error {
|
||||
color: #ff4444;
|
||||
}
|
||||
|
||||
/* Agent 部分 */
|
||||
.agents-section {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 18px;
|
||||
font-weight: 300;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.agents-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
||||
gap: 20px;
|
||||
grid-template-columns: repeat(auto-fill, minmax(400px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.agent-card {
|
||||
border: 2px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
background: var(--bg-secondary);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 4px;
|
||||
padding: 20px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.agent-card:hover {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
|
||||
border-color: var(--accent);
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.agent-card.status-running {
|
||||
border-left: 4px solid #10b981;
|
||||
border-left: 3px solid #00ff41;
|
||||
}
|
||||
|
||||
.agent-card.status-error {
|
||||
border-left: 4px solid #ef4444;
|
||||
border-left: 3px solid #ff4444;
|
||||
}
|
||||
|
||||
.agent-card.status-stopped {
|
||||
border-left: 4px solid #f59e0b;
|
||||
border-left: 3px solid #ffaa00;
|
||||
}
|
||||
|
||||
.agent-card.status-starting {
|
||||
border-left: 4px solid #3b82f6;
|
||||
border-left: 3px solid var(--accent);
|
||||
}
|
||||
|
||||
.agent-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.agent-name {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.agent-status {
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
padding: 4px 12px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.agent-status.running {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
background: rgba(0, 255, 65, 0.1);
|
||||
color: #00ff41;
|
||||
}
|
||||
|
||||
.agent-status.error {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
background: rgba(255, 68, 68, 0.1);
|
||||
color: #ff4444;
|
||||
}
|
||||
|
||||
.agent-status.stopped {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
background: rgba(255, 170, 0, 0.1);
|
||||
color: #ffaa00;
|
||||
}
|
||||
|
||||
.agent-status.starting {
|
||||
background: #dbeafe;
|
||||
color: #1e40af;
|
||||
background: rgba(0, 122, 255, 0.1);
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.agent-info {
|
||||
margin-top: 15px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.agent-info-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #f3f4f6;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.agent-info-row:last-child {
|
||||
@ -184,50 +225,44 @@
|
||||
}
|
||||
|
||||
.agent-info-label {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.agent-info-value {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
color: var(--text-primary);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.agent-info-value.error {
|
||||
color: #ff4444;
|
||||
}
|
||||
|
||||
.loading {
|
||||
text-align: center;
|
||||
padding: 40px;
|
||||
color: #666;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.error-message {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 20px;
|
||||
background: rgba(255, 68, 68, 0.1);
|
||||
color: #ff4444;
|
||||
padding: 12px 16px;
|
||||
border-radius: 4px;
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid #ff4444;
|
||||
}
|
||||
|
||||
.refresh-button {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
transition: background 0.3s ease;
|
||||
/* 响应式 */
|
||||
@media (max-width: 1200px) {
|
||||
.status-container {
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.refresh-button:hover {
|
||||
background: #5568d3;
|
||||
.agents-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.last-update {
|
||||
text-align: right;
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
@ -238,47 +273,65 @@
|
||||
.pulse {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
/* 符号列表样式 */
|
||||
.symbols-list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.symbol-tag {
|
||||
background: var(--bg-primary);
|
||||
padding: 2px 8px;
|
||||
border-radius: 3px;
|
||||
font-size: 11px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>🚀 系统状态监控</h1>
|
||||
<p class="subtitle">实时监控所有 Agent 的运行状态</p>
|
||||
<div style="margin-top: 20px;">
|
||||
<button class="refresh-button" onclick="loadStatus()">🔄 刷新状态</button>
|
||||
<span class="last-update" id="lastUpdate">加载中...</span>
|
||||
<div id="app">
|
||||
<div class="status-page">
|
||||
<div class="status-container">
|
||||
<div class="sticky-header">
|
||||
<div class="status-header">
|
||||
<h1 class="status-title">系统状态 <span>监控</span></h1>
|
||||
<button class="refresh-btn" onclick="loadStatus()">🔄 刷新</button>
|
||||
</div>
|
||||
<div class="last-update" id="lastUpdate">加载中...</div>
|
||||
</div>
|
||||
|
||||
<div id="errorContainer"></div>
|
||||
|
||||
<div class="system-overview">
|
||||
<div class="stats-grid">
|
||||
<div class="stat-card">
|
||||
<div class="label">运行时长</div>
|
||||
<div class="value" id="uptime">-</div>
|
||||
<div class="stat-label">运行时长</div>
|
||||
<div class="stat-value" id="uptime">-</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="label">Agent 总数</div>
|
||||
<div class="value" id="totalAgents">-</div>
|
||||
<div class="stat-label">Agent 总数</div>
|
||||
<div class="stat-value" id="totalAgents">-</div>
|
||||
</div>
|
||||
<div class="stat-card running">
|
||||
<div class="label">运行中</div>
|
||||
<div class="value" id="runningAgents">-</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">运行中</div>
|
||||
<div class="stat-value running" id="runningAgents">-</div>
|
||||
</div>
|
||||
<div class="stat-card error">
|
||||
<div class="label">错误</div>
|
||||
<div class="value" id="errorAgents">-</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-label">错误</div>
|
||||
<div class="stat-value error" id="errorAgents">-</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="agents-section">
|
||||
<h2>🤖 Agent 详情</h2>
|
||||
<h2 class="section-title">🤖 Agent 详情</h2>
|
||||
<div id="agentsContainer">
|
||||
<div class="loading">加载中...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let refreshInterval;
|
||||
@ -291,7 +344,7 @@
|
||||
} else if (seconds < 86400) {
|
||||
const hours = Math.floor(seconds / 3600);
|
||||
const minutes = Math.floor((seconds % 3600) / 60);
|
||||
return `${hours} 小时 ${minutes} 分钟`;
|
||||
return `${hours}小时 ${minutes}分`;
|
||||
} else {
|
||||
const days = Math.floor(seconds / 86400);
|
||||
const hours = Math.floor((seconds % 86400) / 3600);
|
||||
@ -322,10 +375,70 @@
|
||||
}
|
||||
|
||||
function formatSymbols(symbols) {
|
||||
if (!symbols) return '-';
|
||||
if (Array.isArray(symbols)) {
|
||||
return symbols.join(', ');
|
||||
return '<div class="symbols-list">' +
|
||||
symbols.map(s => `<span class="symbol-tag">${s}</span>`).join('') +
|
||||
'</div>';
|
||||
}
|
||||
return symbols || '-';
|
||||
if (typeof symbols === 'string') {
|
||||
return symbols;
|
||||
}
|
||||
return '-';
|
||||
}
|
||||
|
||||
function isCryptoAgent(type) {
|
||||
return type === 'crypto';
|
||||
}
|
||||
|
||||
function formatStockAgentConfig(config) {
|
||||
if (!config) return '';
|
||||
|
||||
let html = '';
|
||||
|
||||
// 显示美股和港股数量
|
||||
if (config.us_count !== undefined || config.hk_count !== undefined) {
|
||||
const usCount = config.us_count || 0;
|
||||
const hkCount = config.hk_count || 0;
|
||||
html += `
|
||||
<div class="agent-info-row">
|
||||
<span class="agent-info-label">股票分布</span>
|
||||
<span class="agent-info-value">🇺🇸 美股 ${usCount}只 | 🇭🇰 港股 ${hkCount}只</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// 显示美股列表
|
||||
if (config.us_symbols && config.us_symbols.length > 0) {
|
||||
html += `
|
||||
<div class="agent-info-row">
|
||||
<span class="agent-info-label">美股列表</span>
|
||||
<span class="agent-info-value">${formatSymbols(config.us_symbols)}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// 显示港股列表
|
||||
if (config.hk_symbols && config.hk_symbols.length > 0) {
|
||||
html += `
|
||||
<div class="agent-info-row">
|
||||
<span class="agent-info-label">港股列表</span>
|
||||
<span class="agent-info-value">${formatSymbols(config.hk_symbols)}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// 显示分析间隔
|
||||
if (config.analysis_interval) {
|
||||
html += `
|
||||
<div class="agent-info-row">
|
||||
<span class="agent-info-label">分析间隔</span>
|
||||
<span class="agent-info-value">${config.analysis_interval}</span>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
async function loadStatus() {
|
||||
@ -366,9 +479,12 @@
|
||||
return;
|
||||
}
|
||||
|
||||
container.innerHTML = '<div class="agent-grid">' + agents.map(([id, agent]) => {
|
||||
container.innerHTML = '<div class="agents-grid">' + agents.map(([id, agent]) => {
|
||||
const statusClass = getStatusClass(agent.status);
|
||||
const symbols = agent.config?.symbols || [];
|
||||
|
||||
// 判断 Agent 类型
|
||||
const isStockAgent = agent.type === 'stock';
|
||||
const isCryptoAgent = agent.type === 'crypto';
|
||||
|
||||
return `
|
||||
<div class="agent-card status-${statusClass}">
|
||||
@ -389,22 +505,30 @@
|
||||
<span class="agent-info-label">最后活动</span>
|
||||
<span class="agent-info-value">${agent.last_activity || '-'}</span>
|
||||
</div>
|
||||
${symbols.length > 0 ? `
|
||||
${isStockAgent ? formatStockAgentConfig(agent.config) : `
|
||||
${agent.config?.symbols && agent.config.symbols.length > 0 ? `
|
||||
<div class="agent-info-row">
|
||||
<span class="agent-info-label">监控标的</span>
|
||||
<span class="agent-info-value">${formatSymbols(symbols)}</span>
|
||||
<span class="agent-info-value">${formatSymbols(agent.config.symbols)}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${agent.config?.paper_trading_enabled !== undefined ? `
|
||||
${isCryptoAgent && agent.config?.auto_trading_enabled !== undefined ? `
|
||||
<div class="agent-info-row">
|
||||
<span class="agent-info-label">模拟交易</span>
|
||||
<span class="agent-info-value">${agent.config.paper_trading_enabled ? '✅ 已启用' : '❌ 未启用'}</span>
|
||||
<span class="agent-info-label">自动交易</span>
|
||||
<span class="agent-info-value">${agent.config.auto_trading_enabled ? '✅ 已启用' : '❌ 未启用'}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
${agent.config?.analysis_interval ? `
|
||||
<div class="agent-info-row">
|
||||
<span class="agent-info-label">分析间隔</span>
|
||||
<span class="agent-info-value">${agent.config.analysis_interval}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
`}
|
||||
${agent.error_message ? `
|
||||
<div class="agent-info-row">
|
||||
<span class="agent-info-label">错误信息</span>
|
||||
<span class="agent-info-value" style="color: #ef4444;">${agent.error_message}</span>
|
||||
<span class="agent-info-value error">${agent.error_message}</span>
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user