local-operator-ui 0.4.0 → 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.
package/README.md CHANGED
@@ -13,7 +13,9 @@
13
13
 
14
14
  <br />
15
15
 
16
- <video src="https://github.com/user-attachments/assets/a7a97781-40a0-46ce-8f53-09ff6fb9ae86" alt="Local Operator Dashboard Example" autoplay loop muted playsinline></video>
16
+ <div style="display: flex; justify-content: center; border-radius: 8px; overflow: hidden;">
17
+ <img src="./resources/preview-example.gif" alt="Local Operator UI Dashboard Example" style="width: 100%; max-width: 800px;">
18
+ </div>
17
19
 
18
20
  <br />
19
21
 
Binary file
Binary file
@@ -29848,12 +29848,10 @@ class WebSocketClient extends EventEmitter {
29848
29848
  const error = new Error(
29849
29849
  `WebSocket connection failed after ${this.options.maxReconnectAttempts} attempts. In cooldown period.`
29850
29850
  );
29851
- console.error(error.message);
29852
29851
  return Promise.reject(error);
29853
29852
  }
29854
29853
  if (this.isReconnecting) {
29855
29854
  const error = new Error("WebSocket reconnection already in progress");
29856
- console.error(error.message);
29857
29855
  return Promise.reject(error);
29858
29856
  }
29859
29857
  const now = Date.now();
@@ -30202,11 +30200,7 @@ class WebSocketClient extends EventEmitter {
30202
30200
  if (this.status === "disconnected" || this.status === "reconnecting") {
30203
30201
  this.reconnectAttempts++;
30204
30202
  this.reconnectTimeoutId = null;
30205
- this.connect().catch((error) => {
30206
- console.error(
30207
- `Reconnection attempt ${this.reconnectAttempts} failed for ${this.messageId}:`,
30208
- error
30209
- );
30203
+ this.connect().catch(() => {
30210
30204
  if (this.reconnectAttempts >= (this.options.maxReconnectAttempts || 0)) {
30211
30205
  this.enterCooldown();
30212
30206
  } else if (this.status !== "failed") {
@@ -35040,13 +35034,21 @@ const useScrollToBottom = (dependencies = [], threshold = 100, buttonThreshold =
35040
35034
  while (parent) {
35041
35035
  const { overflow, overflowY } = window.getComputedStyle(parent);
35042
35036
  if (overflow === "auto" || overflow === "scroll" || overflowY === "auto" || overflowY === "scroll") {
35043
- containerRef.current = parent;
35044
- checkScrollPosition();
35037
+ if (containerRef.current !== parent) {
35038
+ containerRef.current = parent;
35039
+ checkScrollPosition();
35040
+ parent.addEventListener("scroll", handleScroll, { passive: true });
35041
+ }
35045
35042
  break;
35046
35043
  }
35047
35044
  parent = parent.parentElement;
35048
35045
  }
35049
- }, [checkScrollPosition]);
35046
+ return () => {
35047
+ if (containerRef.current) {
35048
+ containerRef.current.removeEventListener("scroll", handleScroll);
35049
+ }
35050
+ };
35051
+ }, [checkScrollPosition, handleScroll]);
35050
35052
  return {
35051
35053
  ref,
35052
35054
  containerRef,
@@ -35072,7 +35074,7 @@ const ContentContainer$4 = styled$1(Box)({
35072
35074
  height: "100%",
35073
35075
  overflow: "hidden"
35074
35076
  });
35075
- const StyledDivider = styled$1(Divider)(({ theme }) => ({
35077
+ styled$1(Divider)(({ theme }) => ({
35076
35078
  opacity: theme.palette.mode === "dark" ? 0.1 : 0.2,
35077
35079
  backgroundColor: theme.palette.divider
35078
35080
  }));
@@ -35515,7 +35517,7 @@ const DangerButton = styled$1(DialogButton)(({ theme }) => ({
35515
35517
  },
35516
35518
  transition: "all 0.2s ease-in-out"
35517
35519
  }));
35518
- const FormContainer$2 = styled$1(Box)({
35520
+ const FormContainer$1 = styled$1(Box)({
35519
35521
  display: "flex",
35520
35522
  flexDirection: "column",
35521
35523
  gap: 20
@@ -46908,29 +46910,33 @@ const ModelSelect = ({
46908
46910
  getOptionLabel: (option) => option.name,
46909
46911
  isOptionEqualToValue: (option, value2) => option.id === value2.id,
46910
46912
  groupBy: (option) => getProviderFromId(option.id),
46911
- renderOption: (props, option) => /* @__PURE__ */ jsxRuntimeExports.jsx("li", { ...props, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(OptionContainer, { children: [
46912
- /* @__PURE__ */ jsxRuntimeExports.jsxs(OptionLabelContainer, { children: [
46913
- /* @__PURE__ */ jsxRuntimeExports.jsx(OptionLabel, { children: option.name }),
46914
- option.recommended && /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Recommended based on community usage and feedback", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RecommendedStar, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faStar, size: "xs" }) }) })
46915
- ] }),
46916
- option.description && /* @__PURE__ */ jsxRuntimeExports.jsx(OptionDescription, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
46917
- Markdown,
46918
- {
46919
- components: {
46920
- a: ({ href, children }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
46921
- "a",
46922
- {
46923
- href,
46924
- target: "_blank",
46925
- rel: "noopener noreferrer",
46926
- children
46927
- }
46928
- )
46929
- },
46930
- children: option.description
46931
- }
46932
- ) })
46933
- ] }) }),
46913
+ renderOption: (props, option) => {
46914
+ const { key, ...rest } = props;
46915
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("li", { ...rest, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(OptionContainer, { children: [
46916
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(OptionLabelContainer, { children: [
46917
+ /* @__PURE__ */ jsxRuntimeExports.jsx(OptionLabel, { children: option.name }),
46918
+ option.recommended && // @ts-ignore
46919
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Recommended based on community usage and feedback", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RecommendedStar, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faStar, size: "xs" }) }) })
46920
+ ] }),
46921
+ option.description && /* @__PURE__ */ jsxRuntimeExports.jsx(OptionDescription, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
46922
+ Markdown,
46923
+ {
46924
+ components: {
46925
+ a: ({ href, children }) => /* @__PURE__ */ jsxRuntimeExports.jsx(
46926
+ "a",
46927
+ {
46928
+ href,
46929
+ target: "_blank",
46930
+ rel: "noopener noreferrer",
46931
+ children
46932
+ }
46933
+ )
46934
+ },
46935
+ children: option.description
46936
+ }
46937
+ ) })
46938
+ ] }) }, key);
46939
+ },
46934
46940
  freeSolo: allowCustom,
46935
46941
  renderInput: (params) => /* @__PURE__ */ jsxRuntimeExports.jsx(
46936
46942
  TextField,
@@ -47664,9 +47670,7 @@ const AttachmentsContainer = styled$1(Box)(({ theme }) => ({
47664
47670
  display: "flex",
47665
47671
  flexWrap: "wrap",
47666
47672
  gap: theme.spacing(1.5),
47667
- padding: theme.spacing(2),
47668
- borderTop: `1px solid ${alpha(theme.palette.divider, 0.1)}`,
47669
- backgroundColor: alpha(theme.palette.background.paper, 0.4)
47673
+ padding: theme.spacing(1)
47670
47674
  }));
47671
47675
  const AttachmentItem = styled$1(Paper)(({ theme }) => ({
47672
47676
  position: "relative",
@@ -48061,98 +48065,204 @@ const useMessageInput = ({
48061
48065
  textareaRef
48062
48066
  };
48063
48067
  };
48064
- const FormContainer$1 = styled$1("form")(({ theme }) => ({
48065
- padding: theme.spacing(3),
48068
+ const InputOuterContainer = styled$1(Box)(({ theme }) => ({
48069
+ width: "100%",
48070
+ flexGrow: 1,
48071
+ flexShrink: 0,
48072
+ minHeight: 0,
48066
48073
  display: "flex",
48074
+ flexDirection: "column",
48067
48075
  alignItems: "center",
48068
- gap: theme.spacing(2),
48069
- borderTop: `1px solid ${alpha(theme.palette.divider, theme.palette.mode === "light" ? 0.2 : 0.1)}`,
48070
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.background.paper, 0.7) : alpha(theme.palette.background.paper, 0.4),
48071
- minHeight: 100,
48072
- position: "relative"
48073
- // 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
48074
48080
  }));
48075
- const AttachmentButton = styled$1(IconButton)(({ theme }) => ({
48076
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.primary.main, 0.8) : alpha(theme.palette.primary.main, 0.15),
48077
- color: theme.palette.mode === "light" ? theme.palette.common.white : theme.palette.primary.light,
48078
- width: 52,
48079
- height: 52,
48080
- borderRadius: theme.shape.borderRadius * 1.5,
48081
- marginRight: theme.spacing(1),
48082
- transition: "all 0.2s ease-in-out",
48081
+ const InputInnerContainer = styled$1(Box)(({ theme }) => ({
48082
+ width: "900px",
48083
+ maxWidth: "900px",
48084
+ margin: "0 auto",
48083
48085
  display: "flex",
48084
- alignItems: "center",
48085
- justifyContent: "center",
48086
- "&:hover": {
48087
- backgroundColor: theme.palette.mode === "light" ? theme.palette.primary.main : alpha(theme.palette.primary.main, 0.25),
48088
- transform: "translateY(-2px)",
48089
- 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%"
48090
48098
  },
48091
- "&:active": {
48092
- transform: "translateY(0px)",
48093
- boxShadow: "none"
48099
+ [theme.breakpoints.between("sm", "md")]: {
48100
+ maxWidth: "90%",
48101
+ width: "90%"
48094
48102
  },
48095
- "&.Mui-disabled": {
48096
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.action.disabled, 0.3) : alpha(theme.palette.action.disabled, 0.1),
48097
- 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
+ }
48098
48151
  }
48099
48152
  }));
48100
48153
  const StyledTextField$2 = styled$1(TextField)(({ theme }) => ({
48101
48154
  flex: 1,
48102
48155
  "& .MuiOutlinedInput-root": {
48103
- borderRadius: theme.shape.borderRadius * 1.5,
48104
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.common.white, 0.9) : alpha(theme.palette.background.paper, 0.6),
48105
- border: `1px solid ${alpha(
48106
- theme.palette.mode === "light" ? theme.palette.grey[300] : theme.palette.divider,
48107
- theme.palette.mode === "light" ? 0.5 : 0.1
48108
- )}`,
48109
- 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
+ },
48110
48170
  "&.Mui-focused": {
48111
- backgroundColor: theme.palette.mode === "light" ? theme.palette.common.white : alpha(theme.palette.background.paper, 0.8),
48112
- boxShadow: `0 0 0 3px ${alpha(theme.palette.primary.main, theme.palette.mode === "light" ? 0.2 : 0.15)}`,
48113
- borderColor: alpha(theme.palette.primary.main, 0.5)
48171
+ backgroundColor: "transparent",
48172
+ boxShadow: "none"
48114
48173
  },
48115
48174
  "&:hover": {
48116
- backgroundColor: theme.palette.mode === "light" ? theme.palette.common.white : alpha(theme.palette.background.paper, 0.7),
48117
- borderColor: theme.palette.mode === "light" ? alpha(theme.palette.primary.main, 0.3) : alpha(theme.palette.primary.main, 0.2)
48118
- },
48119
- padding: "14px 18px",
48120
- fontSize: "1rem",
48121
- minHeight: 48,
48122
- display: "flex",
48123
- alignItems: "center"
48175
+ backgroundColor: "transparent"
48176
+ }
48124
48177
  },
48125
48178
  "& .MuiInputBase-input": {
48126
- 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
+ }
48127
48198
  },
48128
48199
  "& .MuiInputBase-input::placeholder": {
48129
48200
  color: theme.palette.mode === "light" ? alpha(theme.palette.text.secondary, 0.7) : alpha(theme.palette.text.secondary, 0.5),
48130
48201
  opacity: 1
48131
48202
  }
48132
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
+ }));
48133
48229
  const SendButton = styled$1(Button)(({ theme }) => ({
48134
- borderRadius: theme.shape.borderRadius * 1.5,
48135
- minWidth: "auto",
48136
- width: 48,
48137
- height: 48,
48230
+ minWidth: 40,
48231
+ height: 40,
48232
+ borderRadius: "100%",
48138
48233
  padding: 0,
48139
- marginLeft: theme.spacing(1),
48140
- boxShadow: theme.palette.mode === "light" ? theme.shadows[3] : theme.shadows[2],
48141
- transition: "all 0.2s ease-in-out",
48142
48234
  display: "flex",
48143
48235
  alignItems: "center",
48144
48236
  justifyContent: "center",
48145
- "&:not(:disabled):hover": {
48146
- transform: "translateY(-2px)",
48147
- 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)"
48148
48240
  },
48149
- "&:not(:disabled):active": {
48150
- transform: "translateY(0px)",
48151
- boxShadow: theme.shadows[1]
48241
+ "&:active": {
48242
+ transform: "scale(1)"
48152
48243
  },
48153
48244
  "&.Mui-disabled": {
48154
- backgroundColor: theme.palette.mode === "light" ? alpha(theme.palette.action.disabled, 0.3) : alpha(theme.palette.action.disabled, 0.2),
48155
- 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)
48156
48266
  }
48157
48267
  }));
48158
48268
  const MessageInput = ({
@@ -48164,10 +48274,20 @@ const MessageInput = ({
48164
48274
  onCancelJob,
48165
48275
  isFarFromBottom = false,
48166
48276
  scrollToBottom = () => {
48167
- }
48277
+ },
48278
+ initialSuggestions
48168
48279
  }) => {
48169
48280
  const [attachments, setAttachments] = reactExports.useState([]);
48170
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]);
48171
48291
  const {
48172
48292
  inputValue: newMessage,
48173
48293
  setInputValue: setNewMessage,
@@ -48183,7 +48303,6 @@ const MessageInput = ({
48183
48303
  },
48184
48304
  scrollToBottom,
48185
48305
  forceScrollToBottom: scrollToBottom
48186
- // Use the scrollToBottom function for both regular and forced scrolling
48187
48306
  });
48188
48307
  const handleSubmit = (e) => {
48189
48308
  e.preventDefault();
@@ -48219,42 +48338,27 @@ const MessageInput = ({
48219
48338
  fileInputRef.current?.click();
48220
48339
  };
48221
48340
  const isInputDisabled = Boolean(isLoading && currentJobId);
48222
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
48223
- /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$1, { onSubmit: handleSubmit, children: [
48224
- /* @__PURE__ */ jsxRuntimeExports.jsx(
48225
- ScrollToBottomButton,
48226
- {
48227
- visible: isFarFromBottom,
48228
- onClick: scrollToBottom
48229
- }
48230
- ),
48231
- /* @__PURE__ */ jsxRuntimeExports.jsx(
48232
- "input",
48233
- {
48234
- type: "file",
48235
- ref: fileInputRef,
48236
- onChange: handleFileSelect,
48237
- style: { display: "none" },
48238
- disabled: isInputDisabled,
48239
- 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
48240
48355
  }
48241
48356
  ),
48242
- /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Attach file", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48243
- AttachmentButton,
48244
- {
48245
- onClick: triggerFileInput,
48246
- color: "primary",
48247
- size: "medium",
48248
- "aria-label": "Attach file",
48249
- disabled: isInputDisabled,
48250
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPaperclip })
48251
- }
48252
- ) }) }),
48253
48357
  /* @__PURE__ */ jsxRuntimeExports.jsx(
48254
48358
  StyledTextField$2,
48255
48359
  {
48256
48360
  fullWidth: true,
48257
- 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",
48258
48362
  value: newMessage,
48259
48363
  onChange: (e) => setNewMessage(e.target.value),
48260
48364
  onKeyDown: handleKeyDown,
@@ -48265,34 +48369,94 @@ const MessageInput = ({
48265
48369
  disabled: isInputDisabled
48266
48370
  }
48267
48371
  ),
48268
- isLoading && currentJobId ? /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Stop agent", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48269
- SendButton,
48270
- {
48271
- type: "button",
48272
- variant: "contained",
48273
- color: "error",
48274
- onClick: () => onCancelJob?.(currentJobId),
48275
- "aria-label": "Stop agent",
48276
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faStop })
48277
- }
48278
- ) }) }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Send message", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48279
- SendButton,
48280
- {
48281
- type: "submit",
48282
- variant: "contained",
48283
- color: "primary",
48284
- disabled: isLoading || !newMessage.trim() && attachments.length === 0,
48285
- "aria-label": "Send message",
48286
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPaperPlane })
48287
- }
48288
- ) }) })
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
+ ] })
48289
48425
  ] }),
48290
- attachments.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(
48291
- AttachmentsPreview,
48426
+ messages.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(SuggestionsContainer, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
48427
+ Box,
48292
48428
  {
48293
- attachments,
48294
- onRemoveAttachment: handleRemoveAttachment,
48295
- disabled: isInputDisabled
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,
48457
+ {
48458
+ visible: isFarFromBottom,
48459
+ onClick: scrollToBottom
48296
48460
  }
48297
48461
  )
48298
48462
  ] });
@@ -107462,12 +107626,11 @@ const useWebSocketMessage = (options) => {
107462
107626
  reactExports.useEffect(() => {
107463
107627
  if (autoConnect && messageId && baseUrl && connectRef.current && !clientRef.current && !globalClientsRef.current[messageId]) {
107464
107628
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().substring(11, 23);
107465
- console.log(`[${timestamp}] Auto-connecting WebSocket for ${messageId}`);
107466
107629
  globalClientsRef.current[messageId] = true;
107467
107630
  setTimeout(() => {
107468
107631
  if (connectRef.current) {
107469
107632
  connectRef.current().catch((err) => {
107470
- console.error(
107633
+ console.warn(
107471
107634
  `[${timestamp}] Error auto-connecting WebSocket for ${messageId}:`,
107472
107635
  err
107473
107636
  );
@@ -108705,16 +108868,18 @@ const MessageItem = reactExports.memo(
108705
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;
108706
108869
  }
108707
108870
  );
108708
- const MessagesContainer = styled$1(Box)(({ theme }) => ({
108709
- flexGrow: 1,
108710
- overflow: "auto",
108711
- 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,
108712
108878
  display: "flex",
108713
108879
  flexDirection: "column",
108714
108880
  gap: 16,
108715
108881
  backgroundColor: theme.palette.messagesView.background,
108716
108882
  position: "relative",
108717
- // Add position relative for absolute positioning of children
108718
108883
  "&::-webkit-scrollbar": {
108719
108884
  width: "8px"
108720
108885
  },
@@ -108722,7 +108887,6 @@ const MessagesContainer = styled$1(Box)(({ theme }) => ({
108722
108887
  backgroundColor: theme.palette.mode === "dark" ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.2)",
108723
108888
  borderRadius: "4px"
108724
108889
  },
108725
- // Improve GPU acceleration for smoother scrolling
108726
108890
  transform: "translateZ(0)",
108727
108891
  willChange: "scroll-position"
108728
108892
  }));
@@ -108755,22 +108919,14 @@ const LoadingBox = styled$1(Box)({
108755
108919
  justifyContent: "center",
108756
108920
  padding: 32
108757
108921
  });
108758
- const EmptyMessagesBox = styled$1(Box)(({ theme }) => ({
108759
- textAlign: "center",
108760
- color: theme.palette.text.secondary,
108761
- padding: 32,
108762
- fontSize: "0.9rem",
108922
+ const FullScreenCenteredContainer = styled$1(Box)({
108763
108923
  display: "flex",
108764
- flexDirection: "column",
108924
+ justifyContent: "center",
108765
108925
  alignItems: "center",
108766
- justifyContent: "center"
108767
- }));
108768
- const EmptyMessagesIcon = styled$1(FontAwesomeIcon)(({ theme }) => ({
108769
- fontSize: "2rem",
108770
- opacity: 0.5,
108771
- marginBottom: "1rem",
108772
- color: theme.palette.text.secondary
108773
- }));
108926
+ flexGrow: 1,
108927
+ height: "100%",
108928
+ width: "100%"
108929
+ });
108774
108930
  const MessagesView = ({
108775
108931
  messages,
108776
108932
  isLoading,
@@ -108785,7 +108941,8 @@ const MessagesView = ({
108785
108941
  refetch,
108786
108942
  conversationId
108787
108943
  }) => {
108788
- 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: [
108789
108946
  isFetchingMore && /* @__PURE__ */ jsxRuntimeExports.jsxs(LoadingMoreIndicator, { children: [
108790
108947
  /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, { size: 20, sx: { mr: 1 } }),
108791
108948
  "Loading more messages..."
@@ -108821,22 +108978,16 @@ const MessagesView = ({
108821
108978
  }
108822
108979
  )
108823
108980
  ] })
108824
- ) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
108825
- /* @__PURE__ */ jsxRuntimeExports.jsxs(EmptyMessagesBox, { children: [
108826
- /* @__PURE__ */ jsxRuntimeExports.jsx(EmptyMessagesIcon, { icon: faCommentDots }),
108827
- /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body1", children: "No messages yet. Start a conversation!" })
108828
- ] }),
108829
- isLoading && /* @__PURE__ */ jsxRuntimeExports.jsx(CenteredMessagesContainer, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
108830
- LoadingIndicator,
108831
- {
108832
- status: jobStatus,
108833
- agentName,
108834
- currentExecution,
108835
- scrollToBottom,
108836
- conversationId
108837
- }
108838
- ) })
108839
- ] }),
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
+ ) }) }),
108840
108991
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: messagesEndRef })
108841
108992
  ] })
108842
108993
  ] });
@@ -108862,6 +109013,29 @@ styled$1(Box)({
108862
109013
  whiteSpace: "pre-wrap",
108863
109014
  overflow: "auto"
108864
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
+ ];
108865
109039
  const ChatContainer = styled$1(Paper)(({ theme }) => ({
108866
109040
  display: "flex",
108867
109041
  flexDirection: "column",
@@ -108932,11 +109106,11 @@ const ChatContent = ({
108932
109106
  conversationId: agentId
108933
109107
  }
108934
109108
  ),
108935
- /* @__PURE__ */ jsxRuntimeExports.jsx(StyledDivider, {}),
108936
- /* @__PURE__ */ jsxRuntimeExports.jsx(
109109
+ !(isLoadingMessages && messages.length === 0) && /* @__PURE__ */ jsxRuntimeExports.jsx(
108937
109110
  MessageInput,
108938
109111
  {
108939
109112
  onSendMessage,
109113
+ initialSuggestions: DEFAULT_MESSAGE_SUGGESTIONS,
108940
109114
  isLoading,
108941
109115
  conversationId: agentId,
108942
109116
  messages,
@@ -109097,10 +109271,12 @@ const AgentOptionsMenu = ({
109097
109271
  isAgentsPage = false,
109098
109272
  onViewAgentSettings,
109099
109273
  onChatWithAgent,
109100
- onExportAgent
109274
+ onExportAgent,
109275
+ onClearConversation
109101
109276
  }) => {
109102
109277
  const [menuAnchorEl, setMenuAnchorEl] = reactExports.useState(null);
109103
109278
  const [isDeleteModalOpen, setIsDeleteModalOpen] = reactExports.useState(false);
109279
+ const [isClearModalOpen, setIsClearModalOpen] = reactExports.useState(false);
109104
109280
  const isMenuOpen = Boolean(menuAnchorEl);
109105
109281
  const deleteAgentMutation = useDeleteAgent();
109106
109282
  const handleOpenMenu = (e) => {
@@ -109117,6 +109293,13 @@ const AgentOptionsMenu = ({
109117
109293
  const handleCloseDeleteConfirmation = () => {
109118
109294
  setIsDeleteModalOpen(false);
109119
109295
  };
109296
+ const handleOpenClearConfirmation = () => {
109297
+ setIsClearModalOpen(true);
109298
+ handleCloseMenu();
109299
+ };
109300
+ const handleCloseClearConfirmation = () => {
109301
+ setIsClearModalOpen(false);
109302
+ };
109120
109303
  const { clearAgentFromAllPages } = useAgentSelectionStore();
109121
109304
  const handleConfirmDelete = async () => {
109122
109305
  try {
@@ -109197,6 +109380,10 @@ const AgentOptionsMenu = ({
109197
109380
  ]
109198
109381
  }
109199
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
+ ] }),
109200
109387
  /* @__PURE__ */ jsxRuntimeExports.jsxs(DeleteMenuItem, { onClick: handleOpenDeleteConfirmation, children: [
109201
109388
  /* @__PURE__ */ jsxRuntimeExports.jsx(MenuItemIcon, { color: "error", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faTrash, size: "sm" }) }),
109202
109389
  /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", children: "Delete Agent" })
@@ -109223,6 +109410,24 @@ const AgentOptionsMenu = ({
109223
109410
  onConfirm: handleConfirmDelete,
109224
109411
  onCancel: handleCloseDeleteConfirmation
109225
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
+ }
109226
109431
  )
109227
109432
  ] });
109228
109433
  };
@@ -109413,7 +109618,7 @@ const CreateAgentDialog = ({
109413
109618
  maxWidth: "sm",
109414
109619
  children: [
109415
109620
  /* @__PURE__ */ jsxRuntimeExports.jsx(Subtitle$1, { children: "Configure your new AI assistant with a name and optional description" }),
109416
- /* @__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: [
109417
109622
  /* @__PURE__ */ jsxRuntimeExports.jsx(
109418
109623
  NameField,
109419
109624
  {
@@ -109609,7 +109814,7 @@ const ImportAgentDialog = ({
109609
109814
  maxWidth: "sm",
109610
109815
  children: [
109611
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." }),
109612
- /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$2, { children: [
109817
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$1, { children: [
109613
109818
  /* @__PURE__ */ jsxRuntimeExports.jsx(
109614
109819
  FileInput,
109615
109820
  {
@@ -109935,6 +110140,7 @@ const ChatSidebar = ({
109935
110140
  const [isImportDialogOpen, setIsImportDialogOpen] = reactExports.useState(false);
109936
110141
  const perPage = 50;
109937
110142
  const exportAgentMutation = useExportAgent();
110143
+ const clearConversationMutation = useClearAgentConversation();
109938
110144
  const { page, setPage } = usePaginationParams();
109939
110145
  const {
109940
110146
  data: agents = [],
@@ -110092,6 +110298,11 @@ const ChatSidebar = ({
110092
110298
  isAgentsPage: false,
110093
110299
  onViewAgentSettings: onNavigateToAgentSettings ? () => onNavigateToAgentSettings(agent.id) : void 0,
110094
110300
  onExportAgent: () => handleExportAgent(agent.id),
110301
+ onClearConversation: () => {
110302
+ clearConversationMutation.mutate({
110303
+ agentId: agent.id
110304
+ });
110305
+ },
110095
110306
  onAgentDeleted: (deletedAgentId) => {
110096
110307
  if (selectedConversation === deletedAgentId) {
110097
110308
  onSelectConversation("");
@@ -110376,6 +110587,7 @@ const ChatPage = () => {
110376
110587
  },
110377
110588
  [addMessage, conversationId, setCurrentJobId, setIsLoading]
110378
110589
  );
110590
+ const { data: configData } = useConfig();
110379
110591
  const handleSendMessage = reactExports.useCallback(
110380
110592
  async (content2, attachments) => {
110381
110593
  if (!conversationId) return;
@@ -110404,16 +110616,15 @@ const ChatPage = () => {
110404
110616
  ([_2, value]) => value !== void 0 && value !== null
110405
110617
  )
110406
110618
  );
110619
+ const resolvedHosting = !agentData?.hosting || agentData.hosting === "default" || agentData.hosting.trim() === "" ? configData?.values.hosting || "" : agentData.hosting;
110620
+ const resolvedModel = !agentData?.model || agentData.model === "default" || agentData.model.trim() === "" ? configData?.values.model_name || "" : agentData.model;
110407
110621
  const jobDetails = await apiClient.chat.processAgentChatAsync(
110408
110622
  conversationId,
110409
110623
  {
110410
- hosting: agentData?.hosting || "openrouter",
110411
- // Use agent's hosting or default
110412
- model: agentData?.model || "google/gemini-2.0-flash-001",
110413
- // Use agent's model or default
110624
+ hosting: resolvedHosting,
110625
+ model: resolvedModel,
110414
110626
  prompt: content2,
110415
110627
  persist_conversation: true,
110416
- // Persist conversation history
110417
110628
  user_message_id: userMessage.id,
110418
110629
  options: Object.keys(filteredOptions).length > 0 ? filteredOptions : void 0,
110419
110630
  attachments: attachments.length > 0 ? attachments : void 0
@@ -110452,7 +110663,8 @@ ${error2.stack || ""}`;
110452
110663
  setIsLoading,
110453
110664
  agentData,
110454
110665
  apiClient,
110455
- setCurrentJobId
110666
+ setCurrentJobId,
110667
+ configData
110456
110668
  ]
110457
110669
  );
110458
110670
  const rawInfoContent = reactExports.useMemo(() => {
@@ -115333,7 +115545,7 @@ const CredentialDialog = ({
115333
115545
  actions: dialogActions,
115334
115546
  maxWidth: "sm",
115335
115547
  fullWidth: true,
115336
- children: /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$2, { children: [
115548
+ children: /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$1, { children: [
115337
115549
  !initialKey && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
115338
115550
  /* @__PURE__ */ jsxRuntimeExports.jsxs(FormControl, { fullWidth: true, children: [
115339
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-Cu-Ty0jC.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.0",
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",
@@ -167,8 +167,18 @@
167
167
  "gatekeeperAssess": false,
168
168
  "entitlements": "build/entitlements.mac.plist",
169
169
  "entitlementsInherit": "build/entitlements.mac.plist",
170
- "target": ["dmg", "zip"],
171
- "artifactName": "${name}-${version}-${arch}.${ext}"
170
+ "target": [
171
+ {
172
+ "target": "dmg",
173
+ "arch": ["universal"]
174
+ },
175
+ {
176
+ "target": "zip",
177
+ "arch": ["universal"]
178
+ }
179
+ ],
180
+ "artifactName": "${name}-${version}-${arch}.${ext}",
181
+ "x64ArchFiles": "Contents/Resources/python/**/*"
172
182
  },
173
183
  "dmg": {
174
184
  "sign": false,