feat: Add evaluation hooks, skill adaptation and team pipeline config

- Add EvaluationHook for post-execution agent evaluation
- Add SkillAdaptationHook for dynamic skill adaptation
- Add team/ directory with team coordination logic
- Add TEAM_PIPELINE.yaml for smoke_fullstack pipeline config
- Update RuntimeView, TraderView and RuntimeSettingsPanel UI
- Add runtimeApi and websocket services
- Add runtime_state.json to smoke_fullstack state

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-19 18:52:12 +08:00
parent f4a2b7f3af
commit 4b5ac86b83
87 changed files with 5042 additions and 744 deletions

View File

@@ -41,6 +41,7 @@ export default function AgentCard({ agent, onClose, isClosing }) {
const rankMedal = agent.rank ? getRankMedal(agent.rank) : null;
const isPortfolioManager = agent.id === 'portfolio_manager';
const isRiskManager = agent.id === 'risk_manager';
const isValuationAnalyst = agent.id === 'valuation_analyst';
const displayName = isPortfolioManager ? '团队' : agent.name;
// Get model icon configuration
@@ -483,6 +484,78 @@ export default function AgentCard({ agent, onClose, isClosing }) {
</div>
</div>
)}
{/* Valuation Results Card - Only show for valuation_analyst */}
{isValuationAnalyst && agent.signals && agent.signals.length > 0 && (
<div style={{
display: 'flex',
gap: 6,
padding: '8px 12px',
background: '#f5f5f5',
border: '2px solid #7B1FA2'
}}>
<div style={{
fontSize: 10,
fontWeight: 700,
color: '#7B1FA2',
minWidth: 80,
textAlign: 'center'
}}>
估值分析
</div>
{agent.signals
.filter(signal => signal && signal.intrinsic_value != null)
.slice(0, 5)
.map((signal, idx) => {
const fairValue = signal.fair_value_range;
const hasValuation = signal.intrinsic_value || fairValue;
if (!hasValuation) return null;
return (
<div key={idx} style={{
fontSize: 9,
fontFamily: '"Courier New", monospace',
padding: '6px 8px',
background: '#ffffff',
border: '1px solid #7B1FA2',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: 2,
minWidth: 90
}}>
<div style={{ fontWeight: 700, color: '#333' }}>
{signal.ticker}
</div>
{signal.intrinsic_value && (
<div style={{ color: '#00C853', fontSize: 10 }}>
内在 ${signal.intrinsic_value.toFixed(2)}
</div>
)}
{signal.value_gap_pct != null && (
<div style={{
color: signal.value_gap_pct > 0 ? '#00C853' : '#FF1744',
fontSize: 9
}}>
{signal.value_gap_pct > 0 ? '+' : ''}{signal.value_gap_pct.toFixed(1)}%
</div>
)}
{fairValue && (
<div style={{ fontSize: 8, color: '#666' }}>
区间 ${fairValue.bear?.toFixed(0) || '?'}-
${fairValue.bull?.toFixed(0) || '?'}
</div>
)}
{signal.valuation_methods && signal.valuation_methods.length > 0 && (
<div style={{ fontSize: 7, color: '#999' }}>
{signal.valuation_methods[0]}
</div>
)}
</div>
);
})}
</div>
)}
</div>
</div>