import type { ReActRound, ReActStep } from '../types'
const NODE_STYLE: Record<string, { icon: string; label: string; cn: string }> = {
thought: { icon: '💭', label: 'Thought 思考', cn: 'chain-node-thought' },
action: { icon: '⚡', label: 'Action 行动', cn: 'chain-node-action' },
observation: { icon: '👁', label: 'Observation 观察', cn: 'chain-node-observation' },
}
function ChainNode({ step }: { step: ReActStep }) {
const cfg = NODE_STYLE[step.type]
if (!cfg) return null
return (
<div className={`chain-node ${cfg.cn}`}>
<div className="chain-node-head">
<span className="chain-node-icon">{cfg.icon}</span>
<span className="chain-node-label">{cfg.label}</span>
</div>
<pre className="chain-node-body">{step.content}</pre>
{step.meta?.arguments && (
<pre className="chain-node-meta">参数:{step.meta.arguments}</pre>
)}
</div>
)
}
function RoundArrow() {
return <div className="chain-arrow">↓</div>
}
interface Props {
rounds: ReActRound[]
inputStep?: ReActStep
answerStep?: ReActStep
loading?: boolean
}
export function ReActChain({ rounds, inputStep, answerStep, loading }: Props) {
if (!rounds.length && !inputStep && !loading) {
return (
<div className="chain-empty">
<p>运行演示后,这里将按轮次展示完整的</p>
<p className="chain-empty-formula">Thought → Action → Observation → Answer</p>
</div>
)
}
return (
<div className="react-chain">
{inputStep && (
<>
<div className="chain-node chain-node-input">
<div className="chain-node-head">
<span className="chain-node-icon">❓</span>
<span className="chain-node-label">用户提问</span>
</div>
<pre className="chain-node-body">{inputStep.content}</pre>
</div>
<RoundArrow />
</>
)}
{rounds.map((r, idx) => (
<div key={r.round} className="chain-round">
<div className="chain-round-badge">第 {r.round} 轮推理</div>
<div className="chain-round-body">
{r.thought && <ChainNode step={r.thought} />}
{r.thought && r.action && <div className="chain-mini-arrow">→</div>}
{r.action && <ChainNode step={r.action} />}
{r.action && !r.observation && loading && (
<>
<div className="chain-mini-arrow">→</div>
<div className="chain-node chain-node-pending">
<div className="chain-node-head">
<span className="chain-node-icon pulse">⏳</span>
<span className="chain-node-label">Observation 观察 · 工具执行中</span>
</div>
</div>
</>
)}
{r.action && r.observation && <div className="chain-mini-arrow">→</div>}
{r.observation && <ChainNode step={r.observation} />}
</div>
{(idx < rounds.length - 1 || answerStep || loading) && <RoundArrow />}
</div>
))}
{answerStep && (
<div className="chain-node chain-node-answer">
<div className="chain-node-head">
<span className="chain-node-icon">✅</span>
<span className="chain-node-label">Answer 最终回答</span>
</div>
<pre className="chain-node-body">{answerStep.content}</pre>
</div>
)}
{loading && !answerStep && (
<div className="chain-loading">
<span className="pulse">⏳</span> 模型推理中,等待下一轮…
</div>
)}
</div>
)
}