* 思考过程区块 — 推理模型(DeepSeek deepseek-v4 等)的 reasoning_content。 * 默认展开(思考时让用户看到「在想」),可手动折叠;与正文 text 分开渲染。
({ text, live }: { text: string; live: boolean })
| 57 | * 默认展开(思考时让用户看到「在想」),可手动折叠;与正文 text 分开渲染。 |
| 58 | */ |
| 59 | function ReasoningBlock({ text, live }: { text: string; live: boolean }) { |
| 60 | const t = useT(); |
| 61 | const [open, setOpen] = useState(true); |
| 62 | return ( |
| 63 | <div className="mb-3 max-w-[68ch] border-l-2 border-[var(--line)] pl-3"> |
| 64 | <button |
| 65 | onClick={() => setOpen((v) => !v)} |
| 66 | className="flex items-center gap-2 text-[10.5px] uppercase tracking-[0.16em] text-[var(--paper-mute)] transition-colors hover:text-[var(--paper-dim)]" |
| 67 | > |
| 68 | {live ? ( |
| 69 | <span className="k-thinking"> |
| 70 | <span /> |
| 71 | <span /> |
| 72 | <span /> |
| 73 | </span> |
| 74 | ) : ( |
| 75 | <span className="text-[var(--amber)]">💭</span> |
| 76 | )} |
| 77 | <span>{live ? t("msg.reasoning_live") : t("msg.reasoning_title")}</span> |
| 78 | <span className="font-mono">{open ? "[−]" : "[+]"}</span> |
| 79 | </button> |
| 80 | {open && ( |
| 81 | <div className="mt-2 whitespace-pre-wrap text-[12px] italic leading-relaxed text-[var(--paper-mute)]"> |
| 82 | {text} |
| 83 | </div> |
| 84 | )} |
| 85 | </div> |
| 86 | ); |
| 87 | } |
| 88 | |
| 89 | export function MessageBubble({ |
| 90 | msg, |