Spaces:
Running
Running
File size: 1,937 Bytes
d660fa9 f4542ce | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | /**
* ChatPanel — read-only live transcript of one agent-to-agent conversation.
*
* Reveals messages one by one to mirror the backend's staged generation,
* and auto-scrolls to the newest message.
*
* Architecture: rendered inside AgentWindow; fed the conversation object
* and the revealed-count from the simulation snapshot.
*
* Design: observation-only — there is deliberately no input to talk to
* agents from the UI.
*/
import { useEffect, useRef } from "react";
import ChatBubble from "./ChatBubble";
export default function ChatPanel({ conversation, selfId, color, revealedCount }) {
const bottomRef = useRef(null);
const messages = conversation?.messages || [];
const visible = revealedCount != null ? messages.slice(0, revealedCount) : messages;
useEffect(() => {
bottomRef.current?.scrollIntoView({ behavior: "smooth" });
}, [visible.length]);
if (!messages.length) return null;
return (
<div style={{
marginTop: 8,
borderTop: "1px solid rgba(212,160,74,0.08)",
paddingTop: 8,
maxHeight: 180,
overflowY: "auto",
}}>
<div style={{
fontSize: 8,
color: "#6b6b78",
marginBottom: 6,
textTransform: "uppercase",
letterSpacing: 1.2,
fontFamily: "'Space Mono', monospace",
}}>
Chat with {conversation.partner_name}
</div>
{visible.map((msg, i) => (
<ChatBubble
key={i}
text={msg.text}
isSelf={msg.speaker === selfId}
color={color}
/>
))}
{revealedCount != null && visible.length < messages.length && (
<div style={{
fontSize: 9,
color: "#6b6b78",
textAlign: "center",
marginTop: 4,
fontStyle: "italic",
fontFamily: "'Space Mono', monospace",
}}>
···
</div>
)}
<div ref={bottomRef} />
</div>
);
}
|