Threads
Overview
To navigate the list of threads and view them, you must pass the required props: threads
and thread
.
threads
– an array of objects. You can find the object structure on the API – Threads page.
thread
– one of the objects from the threads array.
If your thread structure doesn’t match CUI Kit, you can use an Adapter with ready-made solutions for popular models.
Example thread structure
{
"id": "test-thread",
"title": "Second thread",
"date": "2025-01-18T12:00:00.000Z",
"messages": [
{
"role": "user",
"content": {
"type": "text",
"text": "Hello!"
}
},
{
"role": "assistant",
"content": "Hello there! How can I assist you today?"
}
]
}
Message content
The structure of message content differs depending on the role
value.
For role='user'
:
type UserContent = string | ({
type: "image_url",
image_url: { url: string }
} | {
type: "text",
text: string
})[];
For role='assistant'
:
type AssistantContent = string | ({
type: "text",
text: string
})[];
Thread actions
You can manage threads using the API reference, or pass your own callback functions that will be called after the user interacts with a thread.
For the latest list of callback functions, see the API – Threads page.
This example demonstrates how callback functions operate during thread interactions:
<ChatPage
initialThread={threads[0]}
threads={threads}
handleStopMessageStreaming={handleStopMessageStreaming}
onUserMessageSent={onUserMessageSent}
onFirstMessageSent={onFirstMessageSent}
onThreadDeleted={onThreadDeleted}
onChangeCurrentThread={onChangeCurrentThread}
handleCreateNewThread={handleCreateNewThread}
/>
import * as React from "react";
import {
ChatPage,
useAssistantAnswerMock,
Thread,
} from "@plteam/chat-ui";
import Box from "@mui/material/Box";
import Snackbar, { SnackbarCloseReason } from "@mui/material/Snackbar";
import IconButton from "@mui/material/IconButton";
import CloseIcon from "@mui/icons-material/Close";
let counter = 0;
const App: React.FC = () => {
const [open, setOpen] = React.useState(false);
const [text, setText] = React.useState('');
const openSnackbar = (text: string) => {
setText(text);
setOpen(true);
};
const handleClose = (_event: React.SyntheticEvent | Event, reason?: SnackbarCloseReason) => {
if (reason === 'clickaway') {
return;
}
setOpen(false);
};
const [threads] = React.useState<Thread[]>([
{
id: "test-thread",
title: "Second thread",
date: (new Date('2025-01-18T12:00:00.000Z')).toISOString(),
messages: [
{
role: "user",
content: {
type: "text",
text: "Hello!",
},
},
{
role: "assistant",
content: "Hello there! How can I assist you today?",
},
],
},
{
id: "test-thread2",
title: "First thread",
date: (new Date('2024-12-12T12:00:00.000Z')).toISOString(),
messages: [
{
role: "user",
content: "Hello, how are you today?",
},
{
role: "assistant",
content: "Hi there! I'm doing great, thanks for asking. What can I help you with this morning?",
},
],
},
]);
const onFirstMessageSent = ({ thread }: { thread: Thread }) => {
openSnackbar(`The first message in thread "${thread.title}" has been sent`);
}
const onThreadDeleted = ({ thread }: { thread: Thread }) => {
openSnackbar(`Thread deleted: ${thread.title}`);
}
const onChangeCurrentThread = ({ thread }: { thread: Thread }) => {
openSnackbar(`Current thread changed: ${thread.title}`);
}
const handleCreateNewThread = (): Thread => {
openSnackbar('Opened a new thread with our data');
counter++;
return ({
id: `thread${counter}`,
title: `Thread #${counter}`,
messages: [],
date: new Date().toISOString(),
});
}
const snackBarActions = React.useMemo(() => (
<IconButton
size="small"
aria-label="close"
color="inherit"
onClick={handleClose}
>
<CloseIcon fontSize="small" />
</IconButton>
), [handleClose]);
const { onUserMessageSent, handleStopMessageStreaming } =
useAssistantAnswerMock();
return (
<>
<Box height={"100dvh"} width={"100dvw"}>
<ChatPage
initialThread={threads[0]}
threads={threads}
handleStopMessageStreaming={handleStopMessageStreaming}
onUserMessageSent={onUserMessageSent}
onFirstMessageSent={onFirstMessageSent}
onThreadDeleted={onThreadDeleted}
onChangeCurrentThread={onChangeCurrentThread}
handleCreateNewThread={handleCreateNewThread}
/>
</Box>
<Snackbar
open={open}
onClose={handleClose}
message={text}
action={snackBarActions}
/>
</>
);
}
export default App;