Skip to content

Commit f37a2fb

Browse files
committed
Allow collapse/expand of step output
1 parent 4aac4dc commit f37a2fb

File tree

2 files changed

+80
-48
lines changed

2 files changed

+80
-48
lines changed

llmstack/client/src/components/apps/renderer/LayoutRenderer.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
}
7373

7474
.layout-chat_message_type_step_header {
75-
display: inline-block;
75+
display: flex;
7676
background-color: #f3f3f3;
7777
color: #559;
7878
font-size: 12px;
@@ -81,6 +81,7 @@
8181
padding: 8px;
8282
margin: 8px 0;
8383
border-radius: 6px;
84+
align-items: center;
8485
}
8586

8687
.error {

llmstack/client/src/components/apps/renderer/LayoutRenderer.jsx

Lines changed: 78 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
2-
import { ContentCopyOutlined } from "@mui/icons-material";
2+
import {
3+
ContentCopyOutlined,
4+
KeyboardArrowDownOutlined,
5+
KeyboardArrowRightOutlined,
6+
} from "@mui/icons-material";
37
import { CircularProgress } from "@mui/material";
48
import { Liquid } from "liquidjs";
59
import {
@@ -8,6 +12,7 @@ import {
812
Box,
913
Button,
1014
Chip,
15+
Collapse,
1116
Container,
1217
Grid,
1318
Paper,
@@ -127,12 +132,13 @@ const AppTypingIndicator = memo(
127132
);
128133

129134
const AppAvatar = memo(
130-
({ assistantImage }) => {
135+
({ assistantImage, sx = {} }) => {
131136
return assistantImage ? (
132137
<Avatar
133138
src={assistantImage}
134139
alt="Assistant"
135140
style={{ margin: "10px 8px" }}
141+
sx={sx}
136142
/>
137143
) : null;
138144
},
@@ -274,32 +280,44 @@ const AgentMessage = memo(
274280
},
275281
);
276282

277-
const AgentStepToolHeader = memo(({ processor, isRunning = true }) => {
278-
const icon = (
279-
<ProviderIcon
280-
provider_slug={processor?.provider_slug}
281-
style={{ width: "15px", height: "15px" }}
282-
/>
283-
);
283+
const AgentStepToolHeader = memo(
284+
({ processor, isExpanded, onClick, isRunning = true }) => {
285+
const icon = (
286+
<ProviderIcon
287+
provider_slug={processor?.provider_slug}
288+
style={{ width: "12px", height: "12px" }}
289+
/>
290+
);
284291

285-
return (
286-
<Box className={"layout-chat_message_type_step_header"}>
287-
Using&nbsp;&nbsp;{icon}&nbsp;
288-
<i>{processor?.name || processor?.processor_slug}</i>
289-
{isRunning && (
290-
<div className="layout-chat_message_from_app step-runner-indicator">
291-
<span></span>
292-
<span></span>
293-
<span></span>
294-
</div>
295-
)}
296-
</Box>
297-
);
298-
});
292+
return (
293+
<Box className={"layout-chat_message_type_step_header"} onClick={onClick}>
294+
Using&nbsp;&nbsp;{icon}&nbsp;
295+
<i>{processor?.name || processor?.processor_slug}</i>
296+
{isRunning && (
297+
<div className="layout-chat_message_from_app step-runner-indicator">
298+
<span></span>
299+
<span></span>
300+
<span></span>
301+
</div>
302+
)}
303+
{isExpanded ? (
304+
<KeyboardArrowDownOutlined
305+
sx={{ color: "#999", cursor: "pointer", fontSize: "1.2rem" }}
306+
/>
307+
) : (
308+
<KeyboardArrowRightOutlined
309+
sx={{ color: "#999", cursor: "pointer", fontSize: "1.2rem" }}
310+
/>
311+
)}
312+
</Box>
313+
);
314+
},
315+
);
299316

300317
const AgentStepMessage = memo(
301318
(props) => {
302-
const { message, processors } = props;
319+
const { message, processors, assistantImage } = props;
320+
const [expanded, setExpanded] = useState(true);
303321

304322
// A util function to format incomplete JSON strings
305323
const formatJSON = useCallback((jsonString) => {
@@ -311,38 +329,50 @@ const AgentStepMessage = memo(
311329
}, []);
312330

313331
return (
314-
<Box className="layout-chat_message_type_step">
332+
<Box
333+
className="layout-chat_message_type_step"
334+
style={assistantImage ? { marginLeft: "56px" } : {}}
335+
>
315336
{message.content.name && (
316337
<AgentStepToolHeader
317338
processor={processors.find(
318339
(processor) => processor.id === message.content.name,
319340
)}
320341
isRunning={message.isRunning}
342+
onClick={() => setExpanded(!expanded)}
343+
isExpanded={expanded}
321344
/>
322345
)}
323-
{message.content.arguments && (
324-
<AceEditor
325-
mode="json"
326-
theme="dracula"
327-
value={formatJSON(
328-
message.content.arguments.replaceAll("\\n", "\n"),
346+
<Collapse in={expanded}>
347+
<Box>
348+
{message.content.arguments && (
349+
<AceEditor
350+
mode="json"
351+
theme="dracula"
352+
value={formatJSON(
353+
message.content.arguments.replaceAll("\\n", "\n"),
354+
)}
355+
editorProps={{
356+
$blockScrolling: true,
357+
$onChangeWrapLimit: 80,
358+
}}
359+
setOptions={{
360+
useWorker: false,
361+
showGutter: false,
362+
maxLines: Infinity,
363+
wrap: true,
364+
}}
365+
style={{
366+
marginBottom: 10,
367+
borderRadius: "5px",
368+
wordWrap: "break-word",
369+
maxWidth: "75%",
370+
}}
371+
/>
329372
)}
330-
editorProps={{ $blockScrolling: true, $onChangeWrapLimit: 80 }}
331-
setOptions={{
332-
useWorker: false,
333-
showGutter: false,
334-
maxLines: Infinity,
335-
wrap: true,
336-
}}
337-
style={{
338-
marginBottom: 10,
339-
borderRadius: "5px",
340-
wordWrap: "break-word",
341-
maxWidth: "75%",
342-
}}
343-
/>
344-
)}
345-
<LayoutRenderer>{message.content.output || ""}</LayoutRenderer>
373+
<LayoutRenderer>{message.content.output || ""}</LayoutRenderer>
374+
</Box>
375+
</Collapse>
346376
</Box>
347377
);
348378
},
@@ -469,6 +499,7 @@ const PromptlyAppChatOutput = memo(
469499
message={message}
470500
key={message.id}
471501
processors={appRunData?.processors}
502+
assistantImage={assistantImage}
472503
/>
473504
);
474505
} else if (message.subType === "agent-step-error") {

0 commit comments

Comments
 (0)