local-operator-ui 0.4.2 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Binary file
Binary file
@@ -35074,7 +35074,7 @@ const ContentContainer$4 = styled$1(Box)({
35074
35074
  height: "100%",
35075
35075
  overflow: "hidden"
35076
35076
  });
35077
- const StyledDivider = styled$1(Divider)(({ theme }) => ({
35077
+ styled$1(Divider)(({ theme }) => ({
35078
35078
  opacity: theme.palette.mode === "dark" ? 0.1 : 0.2,
35079
35079
  backgroundColor: theme.palette.divider
35080
35080
  }));
@@ -35517,7 +35517,7 @@ const DangerButton = styled$1(DialogButton)(({ theme }) => ({
35517
35517
  },
35518
35518
  transition: "all 0.2s ease-in-out"
35519
35519
  }));
35520
- const FormContainer$2 = styled$1(Box)({
35520
+ const FormContainer$1 = styled$1(Box)({
35521
35521
  display: "flex",
35522
35522
  flexDirection: "column",
35523
35523
  gap: 20
@@ -47670,9 +47670,7 @@ const AttachmentsContainer = styled$1(Box)(({ theme }) => ({
47670
47670
  display: "flex",
47671
47671
  flexWrap: "wrap",
47672
47672
  gap: theme.spacing(1.5),
47673
- padding: theme.spacing(2),
47674
- borderTop: `1px solid ${alpha(theme.palette.divider, 0.1)}`,
47675
- backgroundColor: alpha(theme.palette.background.paper, 0.4)
47673
+ padding: theme.spacing(1)
47676
47674
  }));
47677
47675
  const AttachmentItem = styled$1(Paper)(({ theme }) => ({
47678
47676
  position: "relative",
@@ -48067,98 +48065,204 @@ const useMessageInput = ({
48067
48065
  textareaRef
48068
48066
  };
48069
48067
  };
48070
- const FormContainer$1 = styled$1("form")(({ theme }) => ({
48071
- padding: theme.spacing(3),
48068
+ const InputOuterContainer = styled$1(Box)(({ theme }) => ({
48069
+ width: "100%",
48070
+ flexGrow: 1,
48071
+ flexShrink: 0,
48072
+ minHeight: 0,
48072
48073
  display: "flex",
48074
+ flexDirection: "column",
48073
48075
  alignItems: "center",
48074
- gap: theme.spacing(2),
48075
- borderTop: `1px solid ${alpha(theme.palette.divider, theme.palette.mode === "light" ? 0.2 : 0.1)}`,
48076
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.background.paper, 0.7) : alpha(theme.palette.background.paper, 0.4),
48077
- minHeight: 100,
48078
- position: "relative"
48079
- // Add position relative for the scroll button
48076
+ justifyContent: "center",
48077
+ padding: theme.spacing(1),
48078
+ paddingBottom: theme.spacing(2),
48079
+ backgroundColor: theme.palette.messagesView.background
48080
48080
  }));
48081
- const AttachmentButton = styled$1(IconButton)(({ theme }) => ({
48082
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.primary.main, 0.8) : alpha(theme.palette.primary.main, 0.15),
48083
- color: theme.palette.mode === "light" ? theme.palette.common.white : theme.palette.primary.light,
48084
- width: 52,
48085
- height: 52,
48086
- borderRadius: theme.shape.borderRadius * 1.5,
48087
- marginRight: theme.spacing(1),
48088
- transition: "all 0.2s ease-in-out",
48081
+ const InputInnerContainer = styled$1(Box)(({ theme }) => ({
48082
+ width: "900px",
48083
+ maxWidth: "900px",
48084
+ margin: "0 auto",
48089
48085
  display: "flex",
48090
- alignItems: "center",
48091
- justifyContent: "center",
48092
- "&:hover": {
48093
- backgroundColor: theme.palette.mode === "light" ? theme.palette.primary.main : alpha(theme.palette.primary.main, 0.25),
48094
- transform: "translateY(-2px)",
48095
- boxShadow: theme.palette.mode === "light" ? `0 4px 8px ${alpha(theme.palette.primary.main, 0.4)}` : `0 4px 8px ${alpha(theme.palette.primary.main, 0.2)}`
48086
+ flexDirection: "column",
48087
+ gap: theme.spacing(1.5),
48088
+ outline: "none",
48089
+ borderRadius: theme.shape.borderRadius * 4,
48090
+ border: `1px solid ${alpha(theme.palette.divider, theme.palette.mode === "light" ? 0.3 : 0.1)}`,
48091
+ backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.background.paper, 0.9) : alpha(theme.palette.background.paper, 0.6),
48092
+ padding: theme.spacing(2),
48093
+ transition: "box-shadow 0.2s ease-in-out, outline 0.2s ease-in-out",
48094
+ boxSizing: "border-box",
48095
+ [theme.breakpoints.down("sm")]: {
48096
+ maxWidth: "100%",
48097
+ width: "100%"
48096
48098
  },
48097
- "&:active": {
48098
- transform: "translateY(0px)",
48099
- boxShadow: "none"
48099
+ [theme.breakpoints.between("sm", "md")]: {
48100
+ maxWidth: "90%",
48101
+ width: "90%"
48100
48102
  },
48101
- "&.Mui-disabled": {
48102
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.action.disabled, 0.3) : alpha(theme.palette.action.disabled, 0.1),
48103
- color: theme.palette.action.disabled
48103
+ [theme.breakpoints.up("md")]: {
48104
+ maxWidth: "900px",
48105
+ width: "900px"
48106
+ },
48107
+ // When the input inside is focused, add an outline instead of increasing border thickness
48108
+ "&:has(.MuiOutlinedInput-root.Mui-focused)": {
48109
+ outline: `2px solid ${theme.palette.primary.main}`,
48110
+ outlineOffset: "0px",
48111
+ boxShadow: `0 0 0 2px ${alpha(theme.palette.primary.main, 0.2)}`
48112
+ }
48113
+ }));
48114
+ const SuggestionsContainer = styled$1(Box)(({ theme }) => ({
48115
+ width: "100%",
48116
+ maxWidth: "900px",
48117
+ margin: "0 auto",
48118
+ marginTop: theme.spacing(4),
48119
+ [theme.breakpoints.down("sm")]: {
48120
+ maxWidth: "100%",
48121
+ width: "100%"
48122
+ },
48123
+ [theme.breakpoints.between("sm", "md")]: {
48124
+ maxWidth: "90%",
48125
+ width: "90%"
48126
+ },
48127
+ [theme.breakpoints.up("md")]: {
48128
+ maxWidth: "900px",
48129
+ width: "900px"
48130
+ }
48131
+ }));
48132
+ const SuggestionChip = styled$1(Button)(({ theme }) => ({
48133
+ borderRadius: 999,
48134
+ textTransform: "none",
48135
+ fontSize: "0.85rem",
48136
+ paddingLeft: theme.spacing(1.5),
48137
+ paddingRight: theme.spacing(1.5),
48138
+ paddingTop: theme.spacing(0.5),
48139
+ paddingBottom: theme.spacing(0.5),
48140
+ whiteSpace: "nowrap",
48141
+ variant: "outlined",
48142
+ size: "small",
48143
+ ...theme.palette.mode === "light" && {
48144
+ backgroundColor: alpha(theme.palette.primary.main, 0.15),
48145
+ color: darken(theme.palette.primary.main, 0.4),
48146
+ borderColor: alpha(theme.palette.primary.main, 0.5),
48147
+ "&:hover": {
48148
+ backgroundColor: alpha(theme.palette.primary.main, 0.25),
48149
+ borderColor: alpha(theme.palette.primary.main, 0.7)
48150
+ }
48104
48151
  }
48105
48152
  }));
48106
48153
  const StyledTextField$2 = styled$1(TextField)(({ theme }) => ({
48107
48154
  flex: 1,
48108
48155
  "& .MuiOutlinedInput-root": {
48109
- borderRadius: theme.shape.borderRadius * 1.5,
48110
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.common.white, 0.9) : alpha(theme.palette.background.paper, 0.6),
48111
- border: `1px solid ${alpha(
48112
- theme.palette.mode === "light" ? theme.palette.grey[300] : theme.palette.divider,
48113
- theme.palette.mode === "light" ? 0.5 : 0.1
48114
- )}`,
48115
- transition: "all 0.2s ease-in-out",
48156
+ backgroundColor: "transparent",
48157
+ padding: "6px 8px",
48158
+ fontSize: "1rem",
48159
+ display: "flex",
48160
+ alignItems: "center",
48161
+ "& fieldset": {
48162
+ border: "none"
48163
+ },
48164
+ "&:hover fieldset": {
48165
+ border: "none"
48166
+ },
48167
+ "&.Mui-focused fieldset": {
48168
+ border: "none"
48169
+ },
48116
48170
  "&.Mui-focused": {
48117
- backgroundColor: theme.palette.mode === "light" ? theme.palette.common.white : alpha(theme.palette.background.paper, 0.8),
48118
- boxShadow: `0 0 0 3px ${alpha(theme.palette.primary.main, theme.palette.mode === "light" ? 0.2 : 0.15)}`,
48119
- borderColor: alpha(theme.palette.primary.main, 0.5)
48171
+ backgroundColor: "transparent",
48172
+ boxShadow: "none"
48120
48173
  },
48121
48174
  "&:hover": {
48122
- backgroundColor: theme.palette.mode === "light" ? theme.palette.common.white : alpha(theme.palette.background.paper, 0.7),
48123
- borderColor: theme.palette.mode === "light" ? alpha(theme.palette.primary.main, 0.3) : alpha(theme.palette.primary.main, 0.2)
48124
- },
48125
- padding: "14px 18px",
48126
- fontSize: "1rem",
48127
- minHeight: 48,
48128
- display: "flex",
48129
- alignItems: "center"
48175
+ backgroundColor: "transparent"
48176
+ }
48130
48177
  },
48131
48178
  "& .MuiInputBase-input": {
48132
- color: theme.palette.text.primary
48179
+ color: theme.palette.text.primary,
48180
+ overflowY: "auto",
48181
+ scrollbarWidth: "thin",
48182
+ scrollbarColor: `${alpha(theme.palette.text.primary, 0.5)} transparent`,
48183
+ /* Firefox */
48184
+ "&::-webkit-scrollbar": {
48185
+ width: "8px",
48186
+ height: "8px"
48187
+ },
48188
+ "&::-webkit-scrollbar-track": {
48189
+ background: "transparent"
48190
+ },
48191
+ "&::-webkit-scrollbar-thumb": {
48192
+ backgroundColor: alpha(theme.palette.text.primary, 0.5),
48193
+ borderRadius: "4px"
48194
+ },
48195
+ "&::-webkit-scrollbar-thumb:hover": {
48196
+ backgroundColor: alpha(theme.palette.text.primary, 0.7)
48197
+ }
48133
48198
  },
48134
48199
  "& .MuiInputBase-input::placeholder": {
48135
48200
  color: theme.palette.mode === "light" ? alpha(theme.palette.text.secondary, 0.7) : alpha(theme.palette.text.secondary, 0.5),
48136
48201
  opacity: 1
48137
48202
  }
48138
48203
  }));
48204
+ const ButtonsRow = styled$1(Box)(({ theme }) => ({
48205
+ display: "flex",
48206
+ alignItems: "center",
48207
+ justifyContent: "space-between",
48208
+ gap: theme.spacing(1)
48209
+ }));
48210
+ const AttachmentButton = styled$1(IconButton)(({ theme }) => ({
48211
+ backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.primary.main, 0.1) : alpha(theme.palette.primary.main, 0.15),
48212
+ color: theme.palette.primary.main,
48213
+ width: 40,
48214
+ height: 40,
48215
+ borderRadius: "100%",
48216
+ transition: "all 0.2s ease-in-out",
48217
+ "&:hover": {
48218
+ backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.primary.main, 0.2) : alpha(theme.palette.primary.main, 0.25),
48219
+ transform: "scale(1.1)"
48220
+ },
48221
+ "&:active": {
48222
+ transform: "scale(1)"
48223
+ },
48224
+ "&.Mui-disabled": {
48225
+ backgroundColor: alpha(theme.palette.action.disabled, 0.1),
48226
+ color: theme.palette.action.disabled
48227
+ }
48228
+ }));
48139
48229
  const SendButton = styled$1(Button)(({ theme }) => ({
48140
- borderRadius: theme.shape.borderRadius * 1.5,
48141
- minWidth: "auto",
48142
- width: 48,
48143
- height: 48,
48230
+ minWidth: 40,
48231
+ height: 40,
48232
+ borderRadius: "100%",
48144
48233
  padding: 0,
48145
- marginLeft: theme.spacing(1),
48146
- boxShadow: theme.palette.mode === "light" ? theme.shadows[3] : theme.shadows[2],
48147
- transition: "all 0.2s ease-in-out",
48148
48234
  display: "flex",
48149
48235
  alignItems: "center",
48150
48236
  justifyContent: "center",
48151
- "&:not(:disabled):hover": {
48152
- transform: "translateY(-2px)",
48153
- boxShadow: theme.palette.mode === "light" ? theme.shadows[5] : theme.shadows[4]
48237
+ transition: "all 0.2s ease-in-out",
48238
+ "&:hover": {
48239
+ transform: "scale(1.1)"
48154
48240
  },
48155
- "&:not(:disabled):active": {
48156
- transform: "translateY(0px)",
48157
- boxShadow: theme.shadows[1]
48241
+ "&:active": {
48242
+ transform: "scale(1)"
48158
48243
  },
48159
48244
  "&.Mui-disabled": {
48160
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.action.disabled, 0.3) : alpha(theme.palette.action.disabled, 0.2),
48161
- color: theme.palette.mode === "light" ? alpha(theme.palette.common.white, 0.7) : alpha(theme.palette.common.white, 0.5)
48245
+ backgroundColor: alpha(theme.palette.action.disabled, 0.1),
48246
+ color: alpha(theme.palette.common.white, 0.5)
48247
+ }
48248
+ }));
48249
+ const EmptyStateContainer$4 = styled$1(Box)(({ theme }) => ({
48250
+ display: "flex",
48251
+ flexDirection: "column",
48252
+ alignItems: "center",
48253
+ justifyContent: "center",
48254
+ padding: theme.spacing(4),
48255
+ gap: theme.spacing(2)
48256
+ }));
48257
+ const EmptyStateTitle = styled$1(Typography)(({ theme }) => ({
48258
+ fontSize: "1.25rem",
48259
+ fontWeight: 500,
48260
+ color: theme.palette.text.secondary,
48261
+ textAlign: "center",
48262
+ marginBottom: theme.spacing(1),
48263
+ [theme.breakpoints.up("sm")]: {
48264
+ fontSize: "1.5rem",
48265
+ marginBottom: theme.spacing(2)
48162
48266
  }
48163
48267
  }));
48164
48268
  const MessageInput = ({
@@ -48170,10 +48274,20 @@ const MessageInput = ({
48170
48274
  onCancelJob,
48171
48275
  isFarFromBottom = false,
48172
48276
  scrollToBottom = () => {
48173
- }
48277
+ },
48278
+ initialSuggestions
48174
48279
  }) => {
48175
48280
  const [attachments, setAttachments] = reactExports.useState([]);
48176
48281
  const fileInputRef = reactExports.useRef(null);
48282
+ const MAX_SUGGESTIONS = 7;
48283
+ const suggestions = reactExports.useMemo(() => {
48284
+ if (!initialSuggestions || initialSuggestions.length === 0) return [];
48285
+ if (initialSuggestions.length <= MAX_SUGGESTIONS) {
48286
+ return initialSuggestions;
48287
+ }
48288
+ const shuffled = [...initialSuggestions].sort(() => Math.random() - 0.5);
48289
+ return shuffled.slice(0, MAX_SUGGESTIONS);
48290
+ }, [initialSuggestions]);
48177
48291
  const {
48178
48292
  inputValue: newMessage,
48179
48293
  setInputValue: setNewMessage,
@@ -48189,7 +48303,6 @@ const MessageInput = ({
48189
48303
  },
48190
48304
  scrollToBottom,
48191
48305
  forceScrollToBottom: scrollToBottom
48192
- // Use the scrollToBottom function for both regular and forced scrolling
48193
48306
  });
48194
48307
  const handleSubmit = (e) => {
48195
48308
  e.preventDefault();
@@ -48225,42 +48338,27 @@ const MessageInput = ({
48225
48338
  fileInputRef.current?.click();
48226
48339
  };
48227
48340
  const isInputDisabled = Boolean(isLoading && currentJobId);
48228
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
48229
- /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$1, { onSubmit: handleSubmit, children: [
48230
- /* @__PURE__ */ jsxRuntimeExports.jsx(
48231
- ScrollToBottomButton,
48232
- {
48233
- visible: isFarFromBottom,
48234
- onClick: scrollToBottom
48235
- }
48236
- ),
48237
- /* @__PURE__ */ jsxRuntimeExports.jsx(
48238
- "input",
48239
- {
48240
- type: "file",
48241
- ref: fileInputRef,
48242
- onChange: handleFileSelect,
48243
- style: { display: "none" },
48244
- disabled: isInputDisabled,
48245
- multiple: true
48341
+ const handleSuggestionClick = (suggestion) => {
48342
+ if (isInputDisabled) return;
48343
+ onSendMessage(suggestion, attachments);
48344
+ setAttachments([]);
48345
+ setNewMessage("");
48346
+ };
48347
+ const inputContent = /* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit: handleSubmit, style: { width: "100%" }, children: [
48348
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(InputInnerContainer, { children: [
48349
+ attachments.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
48350
+ AttachmentsPreview,
48351
+ {
48352
+ attachments,
48353
+ onRemoveAttachment: handleRemoveAttachment,
48354
+ disabled: isInputDisabled
48246
48355
  }
48247
48356
  ),
48248
- /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Attach file", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48249
- AttachmentButton,
48250
- {
48251
- onClick: triggerFileInput,
48252
- color: "primary",
48253
- size: "medium",
48254
- "aria-label": "Attach file",
48255
- disabled: isInputDisabled,
48256
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPaperclip })
48257
- }
48258
- ) }) }),
48259
48357
  /* @__PURE__ */ jsxRuntimeExports.jsx(
48260
48358
  StyledTextField$2,
48261
48359
  {
48262
48360
  fullWidth: true,
48263
- placeholder: isInputDisabled ? "⌛ Agent is busy..." : " Type to Chat! Press ↵ to send, Shift+↵ for new line 📝",
48361
+ placeholder: isInputDisabled ? "⌛ Agent is busy" : "Ask me for help",
48264
48362
  value: newMessage,
48265
48363
  onChange: (e) => setNewMessage(e.target.value),
48266
48364
  onKeyDown: handleKeyDown,
@@ -48271,34 +48369,94 @@ const MessageInput = ({
48271
48369
  disabled: isInputDisabled
48272
48370
  }
48273
48371
  ),
48274
- isLoading && currentJobId ? /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Stop agent", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48275
- SendButton,
48276
- {
48277
- type: "button",
48278
- variant: "contained",
48279
- color: "error",
48280
- onClick: () => onCancelJob?.(currentJobId),
48281
- "aria-label": "Stop agent",
48282
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faStop })
48283
- }
48284
- ) }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Send message", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48285
- SendButton,
48286
- {
48287
- type: "submit",
48288
- variant: "contained",
48289
- color: "primary",
48290
- disabled: isLoading || !newMessage.trim() && attachments.length === 0,
48291
- "aria-label": "Send message",
48292
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPaperPlane })
48293
- }
48294
- ) }) })
48372
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(ButtonsRow, { children: [
48373
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { display: "flex", alignItems: "center", gap: 1, children: [
48374
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
48375
+ "input",
48376
+ {
48377
+ type: "file",
48378
+ ref: fileInputRef,
48379
+ onChange: handleFileSelect,
48380
+ style: { display: "none" },
48381
+ disabled: isInputDisabled,
48382
+ multiple: true
48383
+ }
48384
+ ),
48385
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Attach file", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48386
+ AttachmentButton,
48387
+ {
48388
+ onClick: triggerFileInput,
48389
+ color: "primary",
48390
+ size: "small",
48391
+ "aria-label": "Attach file",
48392
+ disabled: isInputDisabled,
48393
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPaperclip })
48394
+ }
48395
+ ) }) })
48396
+ ] }),
48397
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { display: "flex", alignItems: "center", gap: 1, children: isLoading && currentJobId ? (
48398
+ // @ts-ignore Tooltip type issue
48399
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Stop agent", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48400
+ SendButton,
48401
+ {
48402
+ type: "button",
48403
+ variant: "contained",
48404
+ color: "error",
48405
+ onClick: () => onCancelJob?.(currentJobId),
48406
+ "aria-label": "Stop agent",
48407
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faStop })
48408
+ }
48409
+ ) }) })
48410
+ ) : (
48411
+ // @ts-ignore Tooltip type issue
48412
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Send message", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48413
+ SendButton,
48414
+ {
48415
+ type: "submit",
48416
+ variant: "contained",
48417
+ color: "primary",
48418
+ disabled: isLoading || !newMessage.trim() && attachments.length === 0,
48419
+ "aria-label": "Send message",
48420
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPaperPlane })
48421
+ }
48422
+ ) }) })
48423
+ ) })
48424
+ ] })
48295
48425
  ] }),
48296
- attachments.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
48297
- AttachmentsPreview,
48426
+ messages.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(SuggestionsContainer, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48427
+ Box,
48428
+ {
48429
+ sx: {
48430
+ display: "flex",
48431
+ flexWrap: "wrap",
48432
+ gap: 1,
48433
+ marginTop: 1.5,
48434
+ justifyContent: "center"
48435
+ },
48436
+ children: suggestions.map((suggestion) => /* @__PURE__ */ jsxRuntimeExports.jsx(
48437
+ SuggestionChip,
48438
+ {
48439
+ variant: "outlined",
48440
+ size: "small",
48441
+ onClick: () => handleSuggestionClick(suggestion),
48442
+ disabled: isInputDisabled,
48443
+ children: suggestion
48444
+ },
48445
+ suggestion
48446
+ ))
48447
+ }
48448
+ ) })
48449
+ ] });
48450
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
48451
+ /* @__PURE__ */ jsxRuntimeExports.jsx(InputOuterContainer, { children: messages.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs(EmptyStateContainer$4, { children: [
48452
+ /* @__PURE__ */ jsxRuntimeExports.jsx(EmptyStateTitle, { variant: "h6", children: "What can I help you with today?" }),
48453
+ inputContent
48454
+ ] }) : inputContent }),
48455
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
48456
+ ScrollToBottomButton,
48298
48457
  {
48299
- attachments,
48300
- onRemoveAttachment: handleRemoveAttachment,
48301
- disabled: isInputDisabled
48458
+ visible: isFarFromBottom,
48459
+ onClick: scrollToBottom
48302
48460
  }
48303
48461
  )
48304
48462
  ] });
@@ -108710,16 +108868,18 @@ const MessageItem = reactExports.memo(
108710
108868
  return prevProps.message.id === nextProps.message.id && prevProps.message.message === nextProps.message.message && prevProps.message.status === nextProps.message.status && prevProps.message.is_complete === nextProps.message.is_complete && prevProps.message.is_streamable === nextProps.message.is_streamable;
108711
108869
  }
108712
108870
  );
108713
- const MessagesContainer = styled$1(Box)(({ theme }) => ({
108714
- flexGrow: 1,
108715
- overflow: "auto",
108716
- padding: 16,
108871
+ const MessagesContainer = styled$1(Box, {
108872
+ shouldForwardProp: (prop) => prop !== "collapsed"
108873
+ })(({ theme, collapsed }) => ({
108874
+ flexGrow: collapsed ? 0 : 1,
108875
+ height: collapsed ? 0 : "100%",
108876
+ overflow: collapsed ? "hidden" : "auto",
108877
+ padding: collapsed ? 0 : 16,
108717
108878
  display: "flex",
108718
108879
  flexDirection: "column",
108719
108880
  gap: 16,
108720
108881
  backgroundColor: theme.palette.messagesView.background,
108721
108882
  position: "relative",
108722
- // Add position relative for absolute positioning of children
108723
108883
  "&::-webkit-scrollbar": {
108724
108884
  width: "8px"
108725
108885
  },
@@ -108727,7 +108887,6 @@ const MessagesContainer = styled$1(Box)(({ theme }) => ({
108727
108887
  backgroundColor: theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.2)",
108728
108888
  borderRadius: "4px"
108729
108889
  },
108730
- // Improve GPU acceleration for smoother scrolling
108731
108890
  transform: "translateZ(0)",
108732
108891
  willChange: "scroll-position"
108733
108892
  }));
@@ -108760,22 +108919,14 @@ const LoadingBox = styled$1(Box)({
108760
108919
  justifyContent: "center",
108761
108920
  padding: 32
108762
108921
  });
108763
- const EmptyMessagesBox = styled$1(Box)(({ theme }) => ({
108764
- textAlign: "center",
108765
- color: theme.palette.text.secondary,
108766
- padding: 32,
108767
- fontSize: "0.9rem",
108922
+ const FullScreenCenteredContainer = styled$1(Box)({
108768
108923
  display: "flex",
108769
- flexDirection: "column",
108924
+ justifyContent: "center",
108770
108925
  alignItems: "center",
108771
- justifyContent: "center"
108772
- }));
108773
- const EmptyMessagesIcon = styled$1(FontAwesomeIcon)(({ theme }) => ({
108774
- fontSize: "2rem",
108775
- opacity: 0.5,
108776
- marginBottom: "1rem",
108777
- color: theme.palette.text.secondary
108778
- }));
108926
+ flexGrow: 1,
108927
+ height: "100%",
108928
+ width: "100%"
108929
+ });
108779
108930
  const MessagesView = ({
108780
108931
  messages,
108781
108932
  isLoading,
@@ -108790,7 +108941,8 @@ const MessagesView = ({
108790
108941
  refetch,
108791
108942
  conversationId
108792
108943
  }) => {
108793
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(MessagesContainer, { ref: messagesContainerRef, children: [
108944
+ const collapsed = messages.length === 0 && !isLoadingMessages && !isFetchingMore;
108945
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(MessagesContainer, { ref: messagesContainerRef, collapsed, children: [
108794
108946
  isFetchingMore && /* @__PURE__ */ jsxRuntimeExports.jsxs(LoadingMoreIndicator, { children: [
108795
108947
  /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, { size: 20, sx: { mr: 1 } }),
108796
108948
  "Loading more messages..."
@@ -108826,22 +108978,16 @@ const MessagesView = ({
108826
108978
  }
108827
108979
  )
108828
108980
  ] })
108829
- ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
108830
- /* @__PURE__ */ jsxRuntimeExports.jsxs(EmptyMessagesBox, { children: [
108831
- /* @__PURE__ */ jsxRuntimeExports.jsx(EmptyMessagesIcon, { icon: faCommentDots }),
108832
- /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body1", children: "No messages yet. Start a conversation!" })
108833
- ] }),
108834
- isLoading && /* @__PURE__ */ jsxRuntimeExports.jsx(CenteredMessagesContainer, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
108835
- LoadingIndicator,
108836
- {
108837
- status: jobStatus,
108838
- agentName,
108839
- currentExecution,
108840
- scrollToBottom,
108841
- conversationId
108842
- }
108843
- ) })
108844
- ] }),
108981
+ ) : /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children: isLoadingMessages && /* @__PURE__ */ jsxRuntimeExports.jsx(FullScreenCenteredContainer, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
108982
+ LoadingIndicator,
108983
+ {
108984
+ status: jobStatus,
108985
+ agentName,
108986
+ currentExecution,
108987
+ scrollToBottom,
108988
+ conversationId
108989
+ }
108990
+ ) }) }),
108845
108991
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: messagesEndRef })
108846
108992
  ] })
108847
108993
  ] });
@@ -108867,6 +109013,29 @@ styled$1(Box)({
108867
109013
  whiteSpace: "pre-wrap",
108868
109014
  overflow: "auto"
108869
109015
  });
109016
+ const DEFAULT_MESSAGE_SUGGESTIONS = [
109017
+ "Go to my documents folder",
109018
+ "What's the latest news?",
109019
+ "Make me a research report on the latest trends in AI",
109020
+ "Make me a space invaders game",
109021
+ "Organize my desktop",
109022
+ "Create a presentation outline on climate change",
109023
+ "Train a classifier on the MPG dataset",
109024
+ "Search for quantum computing papers and download interesting ones to read later",
109025
+ "Download some recent papers on fusion energy",
109026
+ "Download some recent papers on cancer research",
109027
+ "Make me a brick breaker game",
109028
+ "Remove downloads that are more than a year old",
109029
+ "Put together a competitive analysis report on the agentic AI space",
109030
+ "Find me a royalty free gif of a cute cat",
109031
+ "Go to my downloads folder",
109032
+ "Organize my documents folder",
109033
+ "Make me a GDPR compliant privacy policy",
109034
+ "Look up trending stocks and put together an investment report",
109035
+ "Fetch the MNIST dataset and train a good classifier",
109036
+ "Look up interest rate trends and make a projection for the next 5 years",
109037
+ "Make a presentation with a dependency graph of genetic factors for Alzheimer's disease"
109038
+ ];
108870
109039
  const ChatContainer = styled$1(Paper)(({ theme }) => ({
108871
109040
  display: "flex",
108872
109041
  flexDirection: "column",
@@ -108937,11 +109106,11 @@ const ChatContent = ({
108937
109106
  conversationId: agentId
108938
109107
  }
108939
109108
  ),
108940
- /* @__PURE__ */ jsxRuntimeExports.jsx(StyledDivider, {}),
108941
- /* @__PURE__ */ jsxRuntimeExports.jsx(
109109
+ !(isLoadingMessages && messages.length === 0) && /* @__PURE__ */ jsxRuntimeExports.jsx(
108942
109110
  MessageInput,
108943
109111
  {
108944
109112
  onSendMessage,
109113
+ initialSuggestions: DEFAULT_MESSAGE_SUGGESTIONS,
108945
109114
  isLoading,
108946
109115
  conversationId: agentId,
108947
109116
  messages,
@@ -109102,10 +109271,12 @@ const AgentOptionsMenu = ({
109102
109271
  isAgentsPage = false,
109103
109272
  onViewAgentSettings,
109104
109273
  onChatWithAgent,
109105
- onExportAgent
109274
+ onExportAgent,
109275
+ onClearConversation
109106
109276
  }) => {
109107
109277
  const [menuAnchorEl, setMenuAnchorEl] = reactExports.useState(null);
109108
109278
  const [isDeleteModalOpen, setIsDeleteModalOpen] = reactExports.useState(false);
109279
+ const [isClearModalOpen, setIsClearModalOpen] = reactExports.useState(false);
109109
109280
  const isMenuOpen = Boolean(menuAnchorEl);
109110
109281
  const deleteAgentMutation = useDeleteAgent();
109111
109282
  const handleOpenMenu = (e) => {
@@ -109122,6 +109293,13 @@ const AgentOptionsMenu = ({
109122
109293
  const handleCloseDeleteConfirmation = () => {
109123
109294
  setIsDeleteModalOpen(false);
109124
109295
  };
109296
+ const handleOpenClearConfirmation = () => {
109297
+ setIsClearModalOpen(true);
109298
+ handleCloseMenu();
109299
+ };
109300
+ const handleCloseClearConfirmation = () => {
109301
+ setIsClearModalOpen(false);
109302
+ };
109125
109303
  const { clearAgentFromAllPages } = useAgentSelectionStore();
109126
109304
  const handleConfirmDelete = async () => {
109127
109305
  try {
@@ -109202,6 +109380,10 @@ const AgentOptionsMenu = ({
109202
109380
  ]
109203
109381
  }
109204
109382
  ),
109383
+ onClearConversation && /* @__PURE__ */ jsxRuntimeExports.jsxs(StyledMenuItem, { onClick: handleOpenClearConfirmation, children: [
109384
+ /* @__PURE__ */ jsxRuntimeExports.jsx(MenuItemIcon, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faTrash, size: "sm" }) }),
109385
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", children: "Clear Conversation" })
109386
+ ] }),
109205
109387
  /* @__PURE__ */ jsxRuntimeExports.jsxs(DeleteMenuItem, { onClick: handleOpenDeleteConfirmation, children: [
109206
109388
  /* @__PURE__ */ jsxRuntimeExports.jsx(MenuItemIcon, { color: "error", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faTrash, size: "sm" }) }),
109207
109389
  /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", children: "Delete Agent" })
@@ -109228,6 +109410,24 @@ const AgentOptionsMenu = ({
109228
109410
  onConfirm: handleConfirmDelete,
109229
109411
  onCancel: handleCloseDeleteConfirmation
109230
109412
  }
109413
+ ),
109414
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
109415
+ ConfirmationModal,
109416
+ {
109417
+ open: isClearModalOpen,
109418
+ title: "Clear Conversation",
109419
+ message: "Are you sure you want to clear this conversation? This action cannot be undone and all messages will be permanently deleted.",
109420
+ confirmText: "Clear",
109421
+ cancelText: "Cancel",
109422
+ isDangerous: true,
109423
+ onConfirm: () => {
109424
+ if (onClearConversation) {
109425
+ onClearConversation();
109426
+ }
109427
+ handleCloseClearConfirmation();
109428
+ },
109429
+ onCancel: handleCloseClearConfirmation
109430
+ }
109231
109431
  )
109232
109432
  ] });
109233
109433
  };
@@ -109418,7 +109618,7 @@ const CreateAgentDialog = ({
109418
109618
  maxWidth: "sm",
109419
109619
  children: [
109420
109620
  /* @__PURE__ */ jsxRuntimeExports.jsx(Subtitle$1, { children: "Configure your new AI assistant with a name and optional description" }),
109421
- /* @__PURE__ */ jsxRuntimeExports.jsx("form", { id: "create-agent-form", onSubmit: handleSubmit, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$2, { children: [
109621
+ /* @__PURE__ */ jsxRuntimeExports.jsx("form", { id: "create-agent-form", onSubmit: handleSubmit, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$1, { children: [
109422
109622
  /* @__PURE__ */ jsxRuntimeExports.jsx(
109423
109623
  NameField,
109424
109624
  {
@@ -109614,7 +109814,7 @@ const ImportAgentDialog = ({
109614
109814
  maxWidth: "sm",
109615
109815
  children: [
109616
109816
  /* @__PURE__ */ jsxRuntimeExports.jsx(Subtitle, { children: "Import an agent from a ZIP file exported from Local Operator. The file should contain an agent.yml file." }),
109617
- /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$2, { children: [
109817
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$1, { children: [
109618
109818
  /* @__PURE__ */ jsxRuntimeExports.jsx(
109619
109819
  FileInput,
109620
109820
  {
@@ -109940,6 +110140,7 @@ const ChatSidebar = ({
109940
110140
  const [isImportDialogOpen, setIsImportDialogOpen] = reactExports.useState(false);
109941
110141
  const perPage = 50;
109942
110142
  const exportAgentMutation = useExportAgent();
110143
+ const clearConversationMutation = useClearAgentConversation();
109943
110144
  const { page, setPage } = usePaginationParams();
109944
110145
  const {
109945
110146
  data: agents = [],
@@ -110097,6 +110298,11 @@ const ChatSidebar = ({
110097
110298
  isAgentsPage: false,
110098
110299
  onViewAgentSettings: onNavigateToAgentSettings ? () => onNavigateToAgentSettings(agent.id) : void 0,
110099
110300
  onExportAgent: () => handleExportAgent(agent.id),
110301
+ onClearConversation: () => {
110302
+ clearConversationMutation.mutate({
110303
+ agentId: agent.id
110304
+ });
110305
+ },
110100
110306
  onAgentDeleted: (deletedAgentId) => {
110101
110307
  if (selectedConversation === deletedAgentId) {
110102
110308
  onSelectConversation("");
@@ -115339,7 +115545,7 @@ const CredentialDialog = ({
115339
115545
  actions: dialogActions,
115340
115546
  maxWidth: "sm",
115341
115547
  fullWidth: true,
115342
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$2, { children: [
115548
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$1, { children: [
115343
115549
  !initialKey && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
115344
115550
  /* @__PURE__ */ jsxRuntimeExports.jsxs(FormControl, { fullWidth: true, children: [
115345
115551
  /* @__PURE__ */ jsxRuntimeExports.jsx(InputLabel, { id: "credential-key-label", children: "Credential Type" }),
@@ -8,7 +8,7 @@
8
8
  <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
9
9
  <meta http-equiv="Content-Security-Policy"
10
10
  content="default-src 'self'; connect-src 'self' http://localhost:1111 http://127.0.0.1:1111 ws://localhost:1111 ws://127.0.0.1:1111; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: http://localhost:1111 http://127.0.0.1:1111; media-src 'self' http://localhost:1111 http://127.0.0.1:1111; font-src 'self'" />
11
- <script type="module" crossorigin src="./assets/index-DHvoVezG.js"></script>
11
+ <script type="module" crossorigin src="./assets/index-BQg1gNa7.js"></script>
12
12
  <link rel="modulepreload" crossorigin href="./assets/error-boundary-HK_94N6W.js">
13
13
  <link rel="stylesheet" crossorigin href="./assets/error-boundary-B9KBGB-g.css">
14
14
  <link rel="stylesheet" crossorigin href="./assets/index-94BTFuhu.css">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "local-operator-ui",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "productName": "Local Operator",
5
5
  "description": "User interface for AI agent assistants that run Python code safely on your device through an intuitive chat interface. Supports local and cloud LLM models with built-in security features.",
6
6
  "main": "./out/main/index.js",