142 lines
5.4 KiB
TypeScript
142 lines
5.4 KiB
TypeScript
import './ProgressSidebar.css';
|
|
|
|
type MemoryListProps = {
|
|
items?: any[];
|
|
emptyText: string;
|
|
};
|
|
|
|
type Props = {
|
|
phase?: string;
|
|
status?: string;
|
|
currentRound?: number;
|
|
divergeRounds?: number;
|
|
reportSchema?: Record<string, any>;
|
|
sharedMemory?: Record<string, any>;
|
|
finalReportPartial?: Record<string, string>;
|
|
currentFinalField?: string;
|
|
};
|
|
|
|
function MemoryList({ items, emptyText }: MemoryListProps): JSX.Element {
|
|
if (!items || items.length === 0) {
|
|
return <div className="empty-hint">{emptyText}</div>;
|
|
}
|
|
return (
|
|
<div className="memory-list">
|
|
{items.map((item, index) => (
|
|
<div key={`${index}-${String(item).slice(0, 20)}`} className="memory-item">{item}</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default function ProgressSidebar({
|
|
phase,
|
|
status,
|
|
currentRound,
|
|
divergeRounds,
|
|
reportSchema,
|
|
sharedMemory,
|
|
finalReportPartial,
|
|
currentFinalField,
|
|
}: Props): JSX.Element {
|
|
const fields = Object.keys(reportSchema || {});
|
|
const finalFilled = fields.filter(field => (finalReportPartial?.[field] || '').trim()).length;
|
|
const progressPercent = fields.length > 0 ? Math.round((finalFilled / fields.length) * 100) : 0;
|
|
const fieldMemoryEntries = Object.entries(sharedMemory?.field_memory || {});
|
|
const agentMemoryEntries = Object.entries(sharedMemory?.agent_memory || {});
|
|
const displayStatus = status || '等待中';
|
|
|
|
return (
|
|
<div className="progress-sidebar">
|
|
<div className="progress-card">
|
|
<div className="progress-title">方案进度</div>
|
|
<div className="progress-meta">
|
|
<span className={`progress-phase phase-${phase || 'starting'}`}>{phase || 'starting'}</span>
|
|
<span className="progress-status">{displayStatus}</span>
|
|
</div>
|
|
<div className="progress-line">
|
|
<div className="progress-line-fill" style={{ width: `${progressPercent}%` }} />
|
|
</div>
|
|
<div className="progress-text">第 {currentRound || 0} 轮 / 发散 {divergeRounds || 0} 轮</div>
|
|
<div className="progress-text">最终报告已生成字段 {finalFilled}/{fields.length || 0}</div>
|
|
{currentFinalField && <div className="field-current">当前字段:{currentFinalField}</div>}
|
|
</div>
|
|
|
|
<div className="progress-card">
|
|
<div className="progress-title">稳定判断</div>
|
|
<MemoryList items={sharedMemory?.stable_claims || []} emptyText="尚未形成稳定判断" />
|
|
</div>
|
|
|
|
<div className="progress-card">
|
|
<div className="progress-title">关键依据</div>
|
|
<MemoryList items={sharedMemory?.key_evidence || []} emptyText="尚未沉淀关键依据" />
|
|
</div>
|
|
|
|
<div className="progress-card">
|
|
<div className="progress-title">冲突与待核</div>
|
|
<MemoryList items={sharedMemory?.conflicts || []} emptyText="当前没有显式冲突" />
|
|
<div className="memory-subtitle">待核问题</div>
|
|
<MemoryList items={sharedMemory?.open_questions || []} emptyText="当前没有待核问题" />
|
|
</div>
|
|
|
|
<div className="progress-card">
|
|
<div className="progress-title">字段记忆</div>
|
|
{fieldMemoryEntries.length === 0 ? (
|
|
<div className="empty-hint">尚未形成字段记忆</div>
|
|
) : (
|
|
<div className="field-memory-list">
|
|
{fieldMemoryEntries.map(([field, item]: [string, any]) => (
|
|
<div key={field} className={`field-memory-card status-${item.status || 'partial'}`}>
|
|
<div className="field-memory-head">
|
|
<span className="field-memory-title">{item.title || field}</span>
|
|
<span className="field-memory-status">{item.status || 'partial'}</span>
|
|
</div>
|
|
{item.current_takeaways?.length > 0 && (
|
|
<>
|
|
<div className="memory-subtitle">当前判断</div>
|
|
<MemoryList items={item.current_takeaways} emptyText="" />
|
|
</>
|
|
)}
|
|
{item.missing_points?.length > 0 && (
|
|
<>
|
|
<div className="memory-subtitle">待补内容</div>
|
|
<MemoryList items={item.missing_points} emptyText="" />
|
|
</>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="progress-card">
|
|
<div className="progress-title">角色记忆</div>
|
|
{agentMemoryEntries.length === 0 ? (
|
|
<div className="empty-hint">尚未形成角色记忆</div>
|
|
) : (
|
|
<div className="agent-memory-list">
|
|
{agentMemoryEntries.map(([agentId, item]: [string, any]) => (
|
|
<div key={agentId} className="agent-memory-card">
|
|
<div className="agent-memory-name">{item.name || agentId}</div>
|
|
{item.latest_position && <div className="agent-memory-position">{item.latest_position}</div>}
|
|
{item.useful_findings?.length > 0 && (
|
|
<>
|
|
<div className="memory-subtitle">有效发现</div>
|
|
<MemoryList items={item.useful_findings} emptyText="" />
|
|
</>
|
|
)}
|
|
{item.open_issues?.length > 0 && (
|
|
<>
|
|
<div className="memory-subtitle">待继续澄清</div>
|
|
<MemoryList items={item.open_issues} emptyText="" />
|
|
</>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|