Skip to content

Commit 52cdf15

Browse files
authored
flambeau: share sessions with public url (#6886)
- allow users to share their chat session - the session history is copied over to a s3 prefix: BUCKET/shared/* - uuid is generated, that url is returned to the user - view only mode, accessible to non-authenticated users (no interaction possible) - refactor of processMessage to not have it twice in both views Example public url: https://torchci-git-wdvr-flambeau-share-fbopensource.vercel.app/flambeau/s/7933f1e8-5300-44fd-be2a-9efe799693f4
1 parent e124c82 commit 52cdf15

File tree

8 files changed

+777
-79
lines changed

8 files changed

+777
-79
lines changed

torchci/components/TorchAgentPage.tsx

Lines changed: 123 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,8 @@ import {
3838
} from "./TorchAgentPage/styles";
3939
import { TodoList } from "./TorchAgentPage/TodoList";
4040
import { ToolUse } from "./TorchAgentPage/ToolUse";
41-
import { ParsedContent } from "./TorchAgentPage/types";
41+
import { useMessageProcessor } from "./TorchAgentPage/useMessageProcessor";
4242
import {
43-
extractGrafanaLinks,
4443
formatElapsedTime,
4544
formatTokenCount,
4645
renderMarkdownWithLinks,
@@ -54,7 +53,13 @@ interface ChatSession {
5453
filename: string;
5554
key: string;
5655
title?: string;
56+
displayedTitle?: string;
5757
status?: string;
58+
shared?: {
59+
uuid: string;
60+
sharedAt: string;
61+
shareUrl: string;
62+
};
5863
}
5964

6065
// Helper function to check for special auth cookie (presence only)
@@ -69,7 +74,17 @@ const hasAuthCookie = () => {
6974
return !!authCookie;
7075
};
7176

72-
export const TorchAgentPage = () => {
77+
interface TorchAgentPageProps {
78+
initialChatData?: any;
79+
isSharedView?: boolean;
80+
shareId?: string;
81+
}
82+
83+
export const TorchAgentPage = ({
84+
initialChatData,
85+
isSharedView = false,
86+
shareId,
87+
}: TorchAgentPageProps = {}) => {
7388
const session = useSession();
7489
const theme = useTheme();
7590
const isMobile = useMediaQuery(theme.breakpoints.down("lg")); // Below 1200px
@@ -91,8 +106,16 @@ export const TorchAgentPage = () => {
91106

92107
const [query, setQuery] = useState("");
93108
const [isLoading, setIsLoading] = useState(false);
94-
const [response, setResponse] = useState("");
95-
const [parsedResponses, setParsedResponses] = useState<ParsedContent[]>([]);
109+
110+
// Use message processor hook for handling chat data
111+
const messageProcessor = useMessageProcessor();
112+
const {
113+
parsedResponses,
114+
response,
115+
setParsedResponses,
116+
setResponse,
117+
processSessionData,
118+
} = messageProcessor;
96119
const [expandedTools, setExpandedTools] = useState<Record<number, boolean>>(
97120
{}
98121
);
@@ -116,6 +139,11 @@ export const TorchAgentPage = () => {
116139
const [isSessionLoading, setIsSessionLoading] = useState(false);
117140
const [drawerOpen, setDrawerOpen] = useState(true);
118141
const [headerHeight, setHeaderHeight] = useState(80); // Default fallback
142+
const [currentSessionSharedInfo, setCurrentSessionSharedInfo] = useState<{
143+
uuid: string;
144+
sharedAt: string;
145+
shareUrl: string;
146+
} | null>(null);
119147

120148
const contentRef = useRef<HTMLDivElement>(null);
121149

@@ -263,59 +291,11 @@ export const TorchAgentPage = () => {
263291
if (response.ok) {
264292
const sessionData = await response.json();
265293

266-
if (sessionData.messages && Array.isArray(sessionData.messages)) {
267-
setParsedResponses([]);
268-
269-
let fullResponse = "";
270-
sessionData.messages.forEach((msg: any) => {
271-
if (msg.content) {
272-
fullResponse += msg.content + "\n";
273-
}
274-
});
275-
setResponse(fullResponse);
276-
277-
// Process all messages in chronological order
278-
sessionData.messages.forEach((msg: any) => {
279-
if (msg.type === "user_message" || msg.type === "user") {
280-
// Process user message
281-
const textContent = msg.content;
282-
const grafanaLinks = extractGrafanaLinks(textContent);
283-
284-
setParsedResponses((prev) => [
285-
...prev,
286-
{
287-
type: "user_message",
288-
content: textContent,
289-
displayedContent: textContent,
290-
isAnimating: false,
291-
timestamp: Date.now(),
292-
grafanaLinks:
293-
grafanaLinks.length > 0 ? grafanaLinks : undefined,
294-
},
295-
]);
296-
} else if (msg.content) {
297-
// Process assistant message content line by line
298-
const lines = msg.content
299-
.split("\n")
300-
.filter((line: string) => line.trim());
301-
lines.forEach((line: string) => {
302-
processMessageLine(
303-
line,
304-
setParsedResponses,
305-
false,
306-
undefined,
307-
(sessionId: string) => {
308-
console.log(
309-
"Setting session ID from loadChatSession:",
310-
sessionId
311-
);
312-
setCurrentSessionId(sessionId);
313-
}
314-
);
315-
});
316-
}
317-
});
318-
}
294+
// Update shared info for current session
295+
setCurrentSessionSharedInfo(sessionData.shared || null);
296+
297+
// Process session data using the message processor
298+
processSessionData(sessionData, setCurrentSessionId);
319299

320300
setSelectedSession(sessionId);
321301
setCurrentSessionId(sessionId);
@@ -345,6 +325,7 @@ export const TorchAgentPage = () => {
345325
setParsedResponses([]);
346326
setSelectedSession(null);
347327
setCurrentSessionId(null);
328+
setCurrentSessionSharedInfo(null);
348329
setError("");
349330
setTotalTokens(0);
350331
setCompletedTokens(0);
@@ -729,7 +710,20 @@ export const TorchAgentPage = () => {
729710

730711
const hasCookieAuth = hasAuthCookie();
731712

732-
if (session.status === "loading" || permissionState === "checking") {
713+
// Initialize shared view data if provided
714+
useEffect(() => {
715+
if (isSharedView && initialChatData) {
716+
console.log("Loading shared chat data:", initialChatData);
717+
processSessionData(initialChatData, setCurrentSessionId);
718+
setSelectedSession(shareId || "shared");
719+
setCurrentSessionId(shareId || "shared");
720+
}
721+
}, [isSharedView, initialChatData, shareId, processSessionData]);
722+
723+
if (
724+
!isSharedView &&
725+
(session.status === "loading" || permissionState === "checking")
726+
) {
733727
return (
734728
<TorchAgentPageContainer>
735729
<QuerySection sx={{ padding: "20px", textAlign: "center" }}>
@@ -745,6 +739,7 @@ export const TorchAgentPage = () => {
745739
}
746740

747741
if (
742+
!isSharedView &&
748743
!hasCookieAuth &&
749744
(session.status === "unauthenticated" ||
750745
!session.data?.user ||
@@ -804,6 +799,7 @@ export const TorchAgentPage = () => {
804799

805800
// Check if user is authenticated but has insufficient permissions
806801
if (
802+
!isSharedView &&
807803
session.data?.user &&
808804
!hasAuthCookie() &&
809805
permissionState === "insufficient"
@@ -1000,7 +996,7 @@ export const TorchAgentPage = () => {
1000996
return (
1001997
<Box sx={{ display: "flex", height: "100vh" }}>
1002998
{/* Hamburger button for collapsed sidebar */}
1003-
{!drawerOpen && (
999+
{!isSharedView && !drawerOpen && (
10041000
<Box
10051001
sx={{
10061002
position: "fixed",
@@ -1024,22 +1020,25 @@ export const TorchAgentPage = () => {
10241020
</Box>
10251021
)}
10261022

1027-
<ChatHistorySidebar
1028-
drawerOpen={drawerOpen}
1029-
sidebarWidth={sidebarWidth}
1030-
chatHistory={chatHistory}
1031-
selectedSession={selectedSession}
1032-
isHistoryLoading={isHistoryLoading}
1033-
isMobile={isMobile}
1034-
headerHeight={headerHeight}
1035-
onStartNewChat={startNewChat}
1036-
onLoadChatSession={loadChatSession}
1037-
onToggleSidebar={toggleSidebar}
1038-
/>
1023+
{!isSharedView && (
1024+
<ChatHistorySidebar
1025+
drawerOpen={drawerOpen}
1026+
sidebarWidth={sidebarWidth}
1027+
chatHistory={chatHistory}
1028+
selectedSession={selectedSession}
1029+
isHistoryLoading={isHistoryLoading}
1030+
isMobile={isMobile}
1031+
headerHeight={headerHeight}
1032+
onStartNewChat={startNewChat}
1033+
onLoadChatSession={loadChatSession}
1034+
onToggleSidebar={toggleSidebar}
1035+
/>
1036+
)}
10391037

10401038
<ChatMain
10411039
sx={{
1042-
marginLeft: drawerOpen && !isMobile ? `${sidebarWidth}px` : 0,
1040+
marginLeft:
1041+
!isSharedView && drawerOpen && !isMobile ? `${sidebarWidth}px` : 0,
10431042
transition: "margin-left 0.3s ease",
10441043
}}
10451044
>
@@ -1053,14 +1052,28 @@ export const TorchAgentPage = () => {
10531052
) : (
10541053
<TorchAgentPageContainer
10551054
ref={contentRef}
1056-
drawerOpen={drawerOpen && !isMobile}
1055+
drawerOpen={!isSharedView && drawerOpen && !isMobile}
10571056
sidebarWidth={sidebarWidth}
10581057
>
10591058
<HeaderSection
10601059
showScrollButton={showScrollButton}
10611060
onScrollToBottom={scrollToBottomAndEnable}
10621061
featureRequestUrl={featureRequestUrl}
10631062
bugReportUrl={bugReportUrl}
1063+
currentSessionId={currentSessionId}
1064+
chatTitle={
1065+
selectedSession
1066+
? chatHistory.find(
1067+
(session) => session.sessionId === selectedSession
1068+
)?.displayedTitle ||
1069+
chatHistory.find(
1070+
(session) => session.sessionId === selectedSession
1071+
)?.title ||
1072+
"Current Chat"
1073+
: "Current Chat"
1074+
}
1075+
isSharedView={isSharedView}
1076+
sharedInfo={currentSessionSharedInfo}
10641077
/>
10651078

10661079
<ChatMessages ref={chatContainerRef}>
@@ -1156,7 +1169,7 @@ export const TorchAgentPage = () => {
11561169
</ChatMessages>
11571170

11581171
{/* Show welcome message for completely new chats */}
1159-
{!selectedSession && (
1172+
{!isSharedView && !selectedSession && (
11601173
<WelcomeSection
11611174
query={query}
11621175
isLoading={isLoading}
@@ -1169,7 +1182,7 @@ export const TorchAgentPage = () => {
11691182
)}
11701183

11711184
{/* Show query input for active chats (read-only for history) */}
1172-
{selectedSession && (
1185+
{!isSharedView && selectedSession && (
11731186
<QueryInputSection
11741187
query={query}
11751188
isLoading={isLoading}
@@ -1181,6 +1194,40 @@ export const TorchAgentPage = () => {
11811194
currentSessionId={currentSessionId}
11821195
/>
11831196
)}
1197+
1198+
{/* Show shared view banner */}
1199+
{isSharedView && (
1200+
<Box
1201+
sx={{
1202+
p: 2,
1203+
bgcolor: "primary.main",
1204+
color: "primary.contrastText",
1205+
textAlign: "center",
1206+
borderRadius: 1,
1207+
mb: 2,
1208+
}}
1209+
>
1210+
<Typography variant="body2">
1211+
This is a shared read-only chat. You can view the conversation
1212+
but cannot interact with it.{" "}
1213+
<Typography
1214+
component="a"
1215+
href="/flambeau"
1216+
sx={{
1217+
color: "primary.contrastText",
1218+
textDecoration: "underline",
1219+
fontWeight: "bold",
1220+
"&:hover": {
1221+
textDecoration: "none",
1222+
},
1223+
}}
1224+
>
1225+
Click here to start a new chat
1226+
</Typography>
1227+
.
1228+
</Typography>
1229+
</Box>
1230+
)}
11841231
</TorchAgentPageContainer>
11851232
)}
11861233
</ChatMain>

0 commit comments

Comments
 (0)