czty's picture
Add files using upload-large-folder tool
b2c86fd verified
Raw
History Blame Contribute Delete
2.23 kB
/**
* 渲染单条消息
* - user 消息:简单文本
* - assistant 消息:渲染 steps 流(thinking / code / tool_use / result / error)
*/
export default function MessageItem({ message }) {
if (message.role === "user") {
return (
<div className="message user-message">
<div className="message-content">{message.content}</div>
</div>
);
}
// assistant
return (
<div className="message assistant-message">
{message.steps.map((step, i) => (
<StepBlock key={i} step={step} />
))}
{!message.done && message.steps.length === 0 && (
<span className="placeholder">Agent is thinking…</span>
)}
</div>
);
}
function StepBlock({ step }) {
switch (step.type) {
case "thinking":
return (
<div className="step thinking-step">
<div className="result-label">💭 Reasoning</div>
<pre>{step.content}</pre>
</div>
);
case "code":
return (
<div className="step code-step">
<div className="code-header">
<span className="code-lang">{step.lang}</span>
<button onClick={() => navigator.clipboard.writeText(step.content)}>
Copy
</button>
</div>
<pre className="code-block">{step.content}</pre>
</div>
);
case "tool_use":
return (
<div className="step tool-step">
🔧 <strong>{step.tool}</strong>
<span className="tool-detail">{step.content?.slice(0, 80)}…</span>
</div>
);
case "observation":
return (
<details className="step observation-step">
<summary>📊 Observation</summary>
<pre>{step.content}</pre>
</details>
);
case "result":
return (
<div className="step result-step">
<div className="result-label">✅ Result</div>
<div className="result-content">{step.content}</div>
</div>
);
case "error":
return (
<details className="step error-step" open>
<summary>❌ Error</summary>
<pre>{step.content}</pre>
</details>
);
default:
return null;
}
}