MCPcopy
hub / github.com/stephengpope/thepopebot / PreviewMessage

Function PreviewMessage

lib/chat/components/message.jsx:250–534  ·  view source on GitHub ↗
({ message, isLoading, onRetry, onEdit })

Source from the content-addressed store, hash-verified

248}
249
250export function PreviewMessage({ message, isLoading, onRetry, onEdit }) {
251 const isUser = message.role === 'user';
252 const isSystem = message.role === 'system';
253 const [copied, setCopied] = useState(false);
254 const [editing, setEditing] = useState(false);
255 const [editText, setEditText] = useState('');
256 const textareaRef = useRef(null);
257 const [showWorking, setShowWorking] = useState(false);
258
259 // Extract text from parts (AI SDK v5+) or fall back to content
260 const text =
261 message.parts
262 ?.filter((p) => p.type === 'text')
263 .map((p) => p.text)
264 .join('\n') ||
265 message.content ||
266 '';
267
268 const partsLength = message.parts?.length || 0;
269 const textLength = text.length;
270 let lastToolPart;
271 for (let i = (message.parts?.length || 0) - 1; i >= 0; i--) {
272 if (message.parts[i].type?.startsWith('tool-')) { lastToolPart = message.parts[i]; break; }
273 }
274 const hasRunningTool = (lastToolPart?.state === 'input-streaming' || lastToolPart?.state === 'input-available') || false;
275
276 useEffect(() => {
277 if (!isLoading || hasRunningTool) {
278 setShowWorking(false);
279 return;
280 }
281 setShowWorking(false);
282 const timer = setTimeout(() => setShowWorking(true), 500);
283 return () => clearTimeout(timer);
284 }, [isLoading, partsLength, textLength, hasRunningTool]);
285
286 // Extract file parts
287 const fileParts = message.parts?.filter((p) => p.type === 'file') || [];
288 const imageParts = fileParts.filter((p) => p.mediaType?.startsWith('image/'));
289 const otherFileParts = fileParts.filter((p) => !p.mediaType?.startsWith('image/'));
290 const hasToolParts = message.parts?.some((p) => p.type?.startsWith('tool-')) || false;
291
292 // System messages render as a subtle info banner
293 if (isSystem) {
294 return (
295 <div className="w-full px-4 py-2 rounded-md bg-muted/50 border border-border/50">
296 <p className="text-xs text-muted-foreground whitespace-pre-wrap">{text}</p>
297 </div>
298 );
299 }
300
301 const handleCopy = async () => {
302 try {
303 await navigator.clipboard.writeText(text);
304 setCopied(true);
305 setTimeout(() => setCopied(false), 2000);
306 } catch {}
307 };

Callers

nothing calls this directly

Calls 3

cnFunction · 0.90
handleEditSubmitFunction · 0.85
handleEditCancelFunction · 0.85

Tested by

no test coverage detected