local-operator-ui 0.1.4 → 0.2.0

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.
@@ -1,4 +1,4 @@
1
- import { c as createStyled, r as resolveProps, u as useTheme, a as reactExports, b as clsx, d as useForkRef, j as jsxRuntimeExports, e as capitalize, f as composeClasses, g as createTheme, h as generateUtilityClass, i as generateUtilityClasses, k as useDefaultProps, s as styled$1, m as memoTheme, l as getDefaultExportFromCjs, n as requireReactDom, _ as _inheritsLoose, o as _objectWithoutPropertiesLoose$1, R as React, T as TransitionGroupContext, p as duration, q as useTheme$1, t as useTimeout, v as useId, B as ButtonBase, w as alpha, x as createSimplePaletteValueFilter, C as CircularProgress, P as Paper, y as darken, z as lighten, A as useEventCallback, D as setRef, E as useEnhancedEffect, F as useRtl, G as globalCss, H as formatMuiErrorMessage, I as rootShouldForwardProp, J as Typography, K as deepmerge, L as extendSxProp, M as resolveBreakpointValues, N as handleBreakpoints, O as getPath, Q as isFocusVisible, S as typographyClasses, U as slotShouldForwardProp, V as clamp, W as emphasize, X as Timeout, Y as React$1, Z as Box, $ as FontAwesomeIcon, a0 as faRobot, a1 as faSliders, a2 as Button, a3 as faExclamationTriangle, a4 as faCheck, a5 as faTimes, a6 as faEraser, a7 as faPen, a8 as faInfoCircle, a9 as faGear, aa as faServer, ab as faStar, ac as faTrash, ad as faCommentDots, ae as faCode, af as faHome, ag as faDownload, ah as faFileAlt, ai as faDesktop, aj as faImage, ak as faMusic, al as faVideo, am as faLaptop, an as faUsers, ao as faDatabase, ap as faBoxOpen, aq as faBook, ar as faHdd, as as faBox, at as faArchive, au as faNetworkWired, av as faFolder, aw as faFolderOpen, ax as faClock, ay as faChevronDown, az as faTools, aA as faArrowDown, aB as faPaperclip, aC as faStop, aD as faPaperPlane, aE as faQuestion, aF as faLightbulb, aG as faChevronRight, aH as faFile, aI as faUser, aJ as faEllipsisVertical, aK as faComment, aL as faChevronLeft, aM as faPlus, aN as faSearch, aO as faCommentSlash, aP as faArrowRight, aQ as faComments, aR as faTag, aS as faIdCard, aT as faCalendarAlt, aU as faCodeBranch, aV as faShieldAlt, aW as faArrowLeft, aX as requireReact, aY as LinearProgress, aZ as keyframes, a_ as faShield, a$ as faSignOut, b0 as faMagicWandSparkles, b1 as faBrain, b2 as faWandMagicSparkles, b3 as faExternalLinkAlt, b4 as faKey, b5 as faGlobe, b6 as faLock, b7 as faEdit, b8 as faSave, b9 as faEnvelope, ba as faCloudUploadAlt, bb as faHistory, bc as faListAlt, bd as library$1, be as icons$1, bf as CssBaseline, bg as ReactDOM$1, bh as ThemeProvider, bi as theme, bj as ErrorBoundary } from "./theme-DWJi6s4t.js";
1
+ import { c as createStyled, r as resolveProps, u as useTheme, a as reactExports, b as clsx, d as useForkRef, j as jsxRuntimeExports, e as capitalize, f as composeClasses, g as createTheme, h as generateUtilityClass, i as generateUtilityClasses, k as useDefaultProps, s as styled$1, m as memoTheme, l as getDefaultExportFromCjs, n as requireReactDom, _ as _inheritsLoose, o as _objectWithoutPropertiesLoose$1, R as React, T as TransitionGroupContext, p as duration, q as useTheme$1, t as useTimeout, v as useId, B as ButtonBase, w as alpha, x as createSimplePaletteValueFilter, C as CircularProgress, P as Paper, y as darken, z as lighten, A as useEventCallback, D as setRef, E as useEnhancedEffect, F as useRtl, G as globalCss, H as formatMuiErrorMessage, I as rootShouldForwardProp, J as Typography, K as deepmerge, L as extendSxProp, M as resolveBreakpointValues, N as handleBreakpoints, O as getPath, Q as isFocusVisible, S as typographyClasses, U as slotShouldForwardProp, V as clamp, W as emphasize, X as Timeout, Y as React$1, Z as Box, $ as FontAwesomeIcon, a0 as faRobot, a1 as faSliders, a2 as Button, a3 as faExclamationTriangle, a4 as faCheck, a5 as faTimes, a6 as faEraser, a7 as faPen, a8 as faInfoCircle, a9 as faGear, aa as faServer, ab as faStar, ac as faTrash, ad as faCommentDots, ae as faCode, af as faHome, ag as faDownload, ah as faFileAlt, ai as faDesktop, aj as faImage, ak as faMusic, al as faVideo, am as faLaptop, an as faUsers, ao as faDatabase, ap as faBoxOpen, aq as faBook, ar as faHdd, as as faBox, at as faArchive, au as faNetworkWired, av as faFolder, aw as faFolderOpen, ax as faClock, ay as faChevronDown, az as faTools, aA as faArrowDown, aB as faPaperclip, aC as faStop, aD as faPaperPlane, aE as keyframes, aF as faChevronUp, aG as faQuestion, aH as faLightbulb, aI as faChevronRight, aJ as faFile, aK as faUser, aL as faEllipsisVertical, aM as faComment, aN as faFileExport, aO as faChevronLeft, aP as faFileImport, aQ as faUpload, aR as faPlus, aS as faSearch, aT as faCommentSlash, aU as faArrowRight, aV as faComments, aW as faTag, aX as faIdCard, aY as faCalendarAlt, aZ as faCodeBranch, a_ as faShieldAlt, a$ as faArrowLeft, b0 as requireReact, b1 as LinearProgress, b2 as faShield, b3 as faSignOut, b4 as faMagicWandSparkles, b5 as faBrain, b6 as faWandMagicSparkles, b7 as faExternalLinkAlt, b8 as faKey, b9 as faGlobe, ba as faLock, bb as faEdit, bc as faSave, bd as faEnvelope, be as faCloudUploadAlt, bf as faHistory, bg as faListAlt, bh as library$1, bi as icons$1, bj as CssBaseline, bk as ReactDOM$1, bl as ThemeProvider, bm as theme, bn as ErrorBoundary } from "./theme-CuzpzMRz.js";
2
2
  const styled = createStyled();
3
3
  function getThemeProps(params) {
4
4
  const {
@@ -25409,6 +25409,104 @@ const AgentsApi = {
25409
25409
  );
25410
25410
  }
25411
25411
  return response.json();
25412
+ },
25413
+ /**
25414
+ * Get agent system prompt
25415
+ * Retrieve the system prompt for a specific agent.
25416
+ *
25417
+ * @param baseUrl - The base URL of the Local Operator API
25418
+ * @param agentId - ID of the agent to get system prompt for
25419
+ * @returns Promise resolving to the agent system prompt response
25420
+ * @throws Error if the request fails
25421
+ */
25422
+ async getAgentSystemPrompt(baseUrl, agentId) {
25423
+ const response = await fetch(
25424
+ `${baseUrl}/v1/agents/${agentId}/system-prompt`,
25425
+ {
25426
+ method: "GET",
25427
+ headers: {
25428
+ Accept: "application/json"
25429
+ }
25430
+ }
25431
+ );
25432
+ if (!response.ok) {
25433
+ throw new Error(
25434
+ `Get agent system prompt request failed: ${response.status} ${response.statusText}`
25435
+ );
25436
+ }
25437
+ return response.json();
25438
+ },
25439
+ /**
25440
+ * Update agent system prompt
25441
+ * Update the system prompt for a specific agent.
25442
+ *
25443
+ * @param baseUrl - The base URL of the Local Operator API
25444
+ * @param agentId - ID of the agent to update system prompt for
25445
+ * @param systemPrompt - The new system prompt text
25446
+ * @returns Promise resolving to the update response
25447
+ * @throws Error if the request fails
25448
+ */
25449
+ async updateAgentSystemPrompt(baseUrl, agentId, systemPrompt) {
25450
+ const response = await fetch(
25451
+ `${baseUrl}/v1/agents/${agentId}/system-prompt`,
25452
+ {
25453
+ method: "PUT",
25454
+ headers: {
25455
+ "Content-Type": "application/json",
25456
+ Accept: "application/json"
25457
+ },
25458
+ body: JSON.stringify({ system_prompt: systemPrompt })
25459
+ }
25460
+ );
25461
+ if (!response.ok) {
25462
+ throw new Error(
25463
+ `Update agent system prompt request failed: ${response.status} ${response.statusText}`
25464
+ );
25465
+ }
25466
+ return response.json();
25467
+ },
25468
+ /**
25469
+ * Import an agent from a ZIP file
25470
+ * Import an agent from a ZIP file containing agent state files with an agent.yml file.
25471
+ *
25472
+ * @param baseUrl - The base URL of the Local Operator API
25473
+ * @param file - The ZIP file containing agent state files
25474
+ * @returns Promise resolving to the imported agent response
25475
+ * @throws Error if the request fails
25476
+ */
25477
+ async importAgent(baseUrl, file) {
25478
+ const formData = new FormData();
25479
+ formData.append("file", file);
25480
+ const response = await fetch(`${baseUrl}/v1/agents/import`, {
25481
+ method: "POST",
25482
+ body: formData
25483
+ });
25484
+ if (!response.ok) {
25485
+ throw new Error(
25486
+ `Import agent request failed: ${response.status} ${response.statusText}`
25487
+ );
25488
+ }
25489
+ return response.json();
25490
+ },
25491
+ /**
25492
+ * Export an agent as a ZIP file
25493
+ * Export an agent's state files as a ZIP file.
25494
+ *
25495
+ * @param baseUrl - The base URL of the Local Operator API
25496
+ * @param agentId - ID of the agent to export
25497
+ * @returns Promise resolving to a Blob containing the ZIP file
25498
+ * @throws Error if the request fails
25499
+ */
25500
+ async exportAgent(baseUrl, agentId) {
25501
+ const response = await fetch(`${baseUrl}/v1/agents/${agentId}/export`, {
25502
+ method: "GET"
25503
+ });
25504
+ if (!response.ok) {
25505
+ throw new Error(
25506
+ `Export agent request failed: ${response.status} ${response.statusText}`
25507
+ );
25508
+ }
25509
+ return response.blob();
25412
25510
  }
25413
25511
  };
25414
25512
  const ChatApi = {
@@ -25844,8 +25942,18 @@ const getImageUrl = (baseUrl, imagePath) => {
25844
25942
  const encodedPath = encodeURIComponent(normalizedPath);
25845
25943
  return `${normalizedBaseUrl}/v1/static/images?path=${encodedPath}`;
25846
25944
  };
25945
+ const getVideoUrl = (baseUrl, videoPath) => {
25946
+ const normalizedBaseUrl = baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
25947
+ let normalizedPath = videoPath;
25948
+ if (normalizedPath.startsWith("file://")) {
25949
+ normalizedPath = normalizedPath.substring(7);
25950
+ }
25951
+ const encodedPath = encodeURIComponent(normalizedPath);
25952
+ return `${normalizedBaseUrl}/v1/static/videos?path=${encodedPath}`;
25953
+ };
25847
25954
  const StaticApi = {
25848
- getImageUrl
25955
+ getImageUrl,
25956
+ getVideoUrl
25849
25957
  };
25850
25958
  class LocalOperatorClient {
25851
25959
  baseUrl;
@@ -30116,8 +30224,7 @@ const useServerHealth = (refetchInterval = 5e3) => {
30116
30224
  },
30117
30225
  // Refetch at specified interval
30118
30226
  refetchInterval,
30119
- // Enable background refetching
30120
- refetchIntervalInBackground: true,
30227
+ refetchIntervalInBackground: false,
30121
30228
  // Don't retry on failure as this is expected when server is down
30122
30229
  retry: false,
30123
30230
  // Always refetch on window focus to get latest status
@@ -30149,8 +30256,7 @@ const useInternetConnectivity = (refetchInterval = 5e3) => {
30149
30256
  },
30150
30257
  // Refetch at specified interval
30151
30258
  refetchInterval,
30152
- // Enable background refetching
30153
- refetchIntervalInBackground: true,
30259
+ refetchIntervalInBackground: false,
30154
30260
  // Don't retry on failure as this is expected when internet is down
30155
30261
  retry: false,
30156
30262
  // Always refetch on window focus to get latest status
@@ -30311,11 +30417,9 @@ const useAgents = (page = 1, perPage = 50, refetchInterval = 0, name2) => {
30311
30417
  }
30312
30418
  },
30313
30419
  // Prevent automatic refetches on window focus
30314
- refetchOnWindowFocus: false,
30420
+ refetchOnWindowFocus: true,
30315
30421
  // Set refetch interval if provided
30316
30422
  refetchInterval,
30317
- // Enable background refetching if interval is set
30318
- refetchIntervalInBackground: refetchInterval > 0,
30319
30423
  // Prevent stale time to avoid unnecessary refetches
30320
30424
  staleTime: 5e3
30321
30425
  });
@@ -30738,8 +30842,15 @@ const useJobPolling = ({
30738
30842
  conversationId,
30739
30843
  addMessage
30740
30844
  }) => {
30741
- const [currentJobId, setCurrentJobId] = reactExports.useState(null);
30845
+ const [currentJobId, setCurrentJobIdInternal] = reactExports.useState(null);
30742
30846
  const [isLoading, setIsLoading] = reactExports.useState(false);
30847
+ const [currentExecution, setCurrentExecution] = reactExports.useState(null);
30848
+ const setCurrentJobId = reactExports.useCallback((jobId) => {
30849
+ setCurrentJobIdInternal(jobId);
30850
+ if (jobId === null) {
30851
+ setCurrentExecution(null);
30852
+ }
30853
+ }, []);
30743
30854
  const queryClient2 = useQueryClient();
30744
30855
  const { getMessages, setMessages } = useChatStore();
30745
30856
  const lastProcessedJobDataRef = reactExports.useRef(null);
@@ -30786,7 +30897,13 @@ const useJobPolling = ({
30786
30897
  return false;
30787
30898
  }
30788
30899
  },
30789
- [client.jobs, currentJobId, shouldEnableQuery, getConnectivityError]
30900
+ [
30901
+ client.jobs,
30902
+ currentJobId,
30903
+ shouldEnableQuery,
30904
+ getConnectivityError,
30905
+ setCurrentJobId
30906
+ ]
30790
30907
  );
30791
30908
  reactExports.useEffect(() => {
30792
30909
  if (conversationId !== previousConversationIdRef.current) {
@@ -30833,7 +30950,13 @@ const useJobPolling = ({
30833
30950
  }
30834
30951
  }
30835
30952
  previousConversationIdRef.current = conversationId;
30836
- }, [conversationId, client.jobs, shouldEnableQuery, getConnectivityError]);
30953
+ }, [
30954
+ conversationId,
30955
+ client.jobs,
30956
+ shouldEnableQuery,
30957
+ getConnectivityError,
30958
+ setCurrentJobId
30959
+ ]);
30837
30960
  const updateConversationMessages = reactExports.useCallback(
30838
30961
  async (agentId) => {
30839
30962
  if (!agentId) return;
@@ -30922,7 +31045,7 @@ const useJobPolling = ({
30922
31045
  setCurrentJobId(null);
30923
31046
  setIsLoading(false);
30924
31047
  },
30925
- [conversationId, addMessage, updateConversationMessages]
31048
+ [conversationId, addMessage, updateConversationMessages, setCurrentJobId]
30926
31049
  );
30927
31050
  const {
30928
31051
  data: jobData,
@@ -30940,10 +31063,8 @@ const useJobPolling = ({
30940
31063
  enabled: shouldEnableQuery({ bypassInternetCheck: true }) && !!currentJobId,
30941
31064
  // Poll every 1 second while job is active
30942
31065
  refetchInterval: currentJobId ? 1e3 : false,
30943
- // Force refetch on interval regardless of window focus
30944
- refetchIntervalInBackground: true,
30945
- // Don't refetch on window focus while polling
30946
- refetchOnWindowFocus: false,
31066
+ refetchIntervalInBackground: false,
31067
+ refetchOnWindowFocus: true,
30947
31068
  // Don't cache the result
30948
31069
  gcTime: 0,
30949
31070
  staleTime: 0,
@@ -30956,6 +31077,9 @@ const useJobPolling = ({
30956
31077
  const jobDataSignature = `${jobData.id}-${jobData.status}-${dataUpdatedAt}`;
30957
31078
  if (jobDataSignature !== lastProcessedJobDataRef.current) {
30958
31079
  lastProcessedJobDataRef.current = jobDataSignature;
31080
+ if (jobData.current_execution) {
31081
+ setCurrentExecution(jobData.current_execution);
31082
+ }
30959
31083
  if (jobData.status === "processing") {
30960
31084
  const debounceTimeout = setTimeout(() => {
30961
31085
  updateConversationMessages(conversationId);
@@ -30964,6 +31088,7 @@ const useJobPolling = ({
30964
31088
  }
30965
31089
  if (jobData.status === "completed" || jobData.status === "failed") {
30966
31090
  handleJobCompletion(jobData);
31091
+ setCurrentExecution(null);
30967
31092
  }
30968
31093
  }
30969
31094
  return void 0;
@@ -30972,7 +31097,9 @@ const useJobPolling = ({
30972
31097
  dataUpdatedAt,
30973
31098
  handleJobCompletion,
30974
31099
  conversationId,
30975
- updateConversationMessages
31100
+ updateConversationMessages,
31101
+ setCurrentExecution,
31102
+ setCurrentJobId
30976
31103
  ]);
30977
31104
  reactExports.useEffect(() => {
30978
31105
  if (error) {
@@ -30988,7 +31115,8 @@ const useJobPolling = ({
30988
31115
  jobStatus: jobData?.status || null,
30989
31116
  isLoading,
30990
31117
  setIsLoading,
30991
- checkForActiveJobs
31118
+ checkForActiveJobs,
31119
+ currentExecution
30992
31120
  };
30993
31121
  };
30994
31122
  const useScrollToBottom = (dependencies = [], threshold = 300, buttonThreshold = 50) => {
@@ -31090,7 +31218,7 @@ const SidebarContainer$6 = styled$1(Box)({
31090
31218
  width: 280,
31091
31219
  height: "100%"
31092
31220
  });
31093
- const ContentContainer$3 = styled$1(Box)({
31221
+ const ContentContainer$4 = styled$1(Box)({
31094
31222
  flexGrow: 1,
31095
31223
  height: "100%",
31096
31224
  overflow: "hidden"
@@ -31101,7 +31229,7 @@ const StyledDivider = styled$1(Divider)({
31101
31229
  const ChatLayout = ({ sidebar, content: content2 }) => {
31102
31230
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(Container$1, { children: [
31103
31231
  /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarContainer$6, { children: sidebar }),
31104
- /* @__PURE__ */ jsxRuntimeExports.jsx(ContentContainer$3, { children: content2 })
31232
+ /* @__PURE__ */ jsxRuntimeExports.jsx(ContentContainer$4, { children: content2 })
31105
31233
  ] });
31106
31234
  };
31107
31235
  const useAgentRouteParam = () => {
@@ -31528,6 +31656,9 @@ const useClearAgentConversation = () => {
31528
31656
  queryClient2.invalidateQueries({
31529
31657
  queryKey: ["agent", variables.agentId, "conversation"]
31530
31658
  });
31659
+ queryClient2.invalidateQueries({
31660
+ queryKey: ["conversation-messages", variables.agentId]
31661
+ });
31531
31662
  clearChatMessages(variables.agentId);
31532
31663
  clearMessageHistory(variables.agentId);
31533
31664
  y$1.success("Conversation cleared successfully");
@@ -31786,7 +31917,7 @@ const SidebarContent = styled$1(Box)({
31786
31917
  borderRadius: "4px"
31787
31918
  }
31788
31919
  });
31789
- const SectionTitle$6 = styled$1(Typography)(({ theme: theme2 }) => ({
31920
+ const SectionTitle$7 = styled$1(Typography)(({ theme: theme2 }) => ({
31790
31921
  fontWeight: 600,
31791
31922
  marginBottom: theme2.spacing(2),
31792
31923
  marginTop: theme2.spacing(3),
@@ -31794,11 +31925,11 @@ const SectionTitle$6 = styled$1(Typography)(({ theme: theme2 }) => ({
31794
31925
  alignItems: "center",
31795
31926
  color: theme2.palette.text.primary
31796
31927
  }));
31797
- const TitleIcon$3 = styled$1(FontAwesomeIcon)({
31928
+ const TitleIcon$4 = styled$1(FontAwesomeIcon)({
31798
31929
  marginRight: 10,
31799
31930
  color: "#f2f2f3"
31800
31931
  });
31801
- const InfoButton$2 = styled$1(IconButton)(({ theme: theme2 }) => ({
31932
+ const InfoButton$3 = styled$1(IconButton)(({ theme: theme2 }) => ({
31802
31933
  marginLeft: theme2.spacing(1),
31803
31934
  color: theme2.palette.primary.main,
31804
31935
  "&:hover": {
@@ -32430,8 +32561,8 @@ const GenerationSettingsSection = ({
32430
32561
  updateAgentMutation
32431
32562
  }) => {
32432
32563
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
32433
- /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$6, { variant: "subtitle1", children: [
32434
- /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon$3, { icon: faSliders }),
32564
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$7, { variant: "subtitle1", children: [
32565
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon$4, { icon: faSliders }),
32435
32566
  "Generation Settings",
32436
32567
  /* @__PURE__ */ jsxRuntimeExports.jsx(
32437
32568
  Tooltip,
@@ -32439,7 +32570,7 @@ const GenerationSettingsSection = ({
32439
32570
  title: "Settings that control how the agent generates responses",
32440
32571
  arrow: true,
32441
32572
  placement: "top",
32442
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoButton$2, { size: "small", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faInfoCircle, size: "xs" }) })
32573
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoButton$3, { size: "small", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faInfoCircle, size: "xs" }) })
32443
32574
  }
32444
32575
  )
32445
32576
  ] }),
@@ -33009,10 +33140,19 @@ const HostingSelect = ({
33009
33140
  const [inputValue, setInputValue] = reactExports.useState("");
33010
33141
  const [isSubmitting, setIsSubmitting] = reactExports.useState(false);
33011
33142
  const showAllOptions = reactExports.useRef(false);
33143
+ const credentialFetchAttemptsRef = reactExports.useRef(0);
33144
+ const MAX_CREDENTIAL_FETCH_ATTEMPTS = 3;
33012
33145
  const availableHostingProviders = reactExports.useMemo(() => {
33013
33146
  if (!filterByCredentials) {
33014
33147
  return getHostingProviders();
33015
33148
  }
33149
+ if (credentialFetchAttemptsRef.current >= MAX_CREDENTIAL_FETCH_ATTEMPTS) {
33150
+ console.warn(
33151
+ `Exceeded maximum credential fetch attempts (${MAX_CREDENTIAL_FETCH_ATTEMPTS})`
33152
+ );
33153
+ return getHostingProviders();
33154
+ }
33155
+ credentialFetchAttemptsRef.current += 1;
33016
33156
  return getAvailableHostingProviders(userCredentials);
33017
33157
  }, [userCredentials, filterByCredentials]);
33018
33158
  const hostingOptions = reactExports.useMemo(() => {
@@ -33074,6 +33214,9 @@ const HostingSelect = ({
33074
33214
  provider: void 0
33075
33215
  };
33076
33216
  }, [value, hostingOptions]);
33217
+ reactExports.useEffect(() => {
33218
+ credentialFetchAttemptsRef.current = 0;
33219
+ }, []);
33077
33220
  reactExports.useEffect(() => {
33078
33221
  if (selectedOption) {
33079
33222
  setInputValue(selectedOption.name);
@@ -33086,6 +33229,7 @@ const HostingSelect = ({
33086
33229
  try {
33087
33230
  setIsSubmitting(true);
33088
33231
  const option = newValue;
33232
+ credentialFetchAttemptsRef.current = 0;
33089
33233
  await onSave(option.id);
33090
33234
  setIsUserTyping(false);
33091
33235
  setInputValue(option.name);
@@ -42973,18 +43117,35 @@ const ModelSelect = ({
42973
43117
  const models = getModelsForHostingProvider(hostingId);
42974
43118
  return models;
42975
43119
  }, [hostingId]);
42976
- const { refreshModels } = useModels();
43120
+ const { refreshModels, isLoading: isModelsLoading } = useModels();
42977
43121
  const previousHostingIdRef = reactExports.useRef(null);
43122
+ const refreshTimeRef = reactExports.useRef(null);
43123
+ const refreshAttemptCountRef = reactExports.useRef(0);
43124
+ const MAX_REFRESH_ATTEMPTS = 3;
42978
43125
  reactExports.useEffect(() => {
42979
43126
  if (hostingId && previousHostingIdRef.current !== hostingId) {
42980
43127
  previousHostingIdRef.current = hostingId;
43128
+ refreshAttemptCountRef.current = 0;
42981
43129
  const timeoutId = setTimeout(() => {
42982
- refreshModels();
42983
- }, 0);
43130
+ const now = Date.now();
43131
+ const lastRefreshTime = refreshTimeRef.current;
43132
+ const THROTTLE_DURATION = 2e3;
43133
+ if (refreshAttemptCountRef.current >= MAX_REFRESH_ATTEMPTS) {
43134
+ console.warn(
43135
+ `Exceeded maximum model refresh attempts (${MAX_REFRESH_ATTEMPTS}) for hosting provider ${hostingId}`
43136
+ );
43137
+ return;
43138
+ }
43139
+ if ((!lastRefreshTime || now - lastRefreshTime > THROTTLE_DURATION) && !isModelsLoading) {
43140
+ refreshAttemptCountRef.current += 1;
43141
+ refreshModels();
43142
+ refreshTimeRef.current = now;
43143
+ }
43144
+ }, 100);
42984
43145
  return () => clearTimeout(timeoutId);
42985
43146
  }
42986
43147
  return void 0;
42987
- }, [hostingId, refreshModels]);
43148
+ }, [hostingId, refreshModels, isModelsLoading]);
42988
43149
  const modelOptions = reactExports.useMemo(() => {
42989
43150
  const options = [
42990
43151
  {
@@ -43223,8 +43384,8 @@ const ModelHostingSection = ({
43223
43384
  updateAgentMutation
43224
43385
  }) => {
43225
43386
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
43226
- /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$6, { variant: "subtitle1", children: [
43227
- /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon$3, { icon: faServer }),
43387
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$7, { variant: "subtitle1", children: [
43388
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon$4, { icon: faServer }),
43228
43389
  "Model & Hosting",
43229
43390
  /* @__PURE__ */ jsxRuntimeExports.jsx(
43230
43391
  Tooltip,
@@ -43232,7 +43393,7 @@ const ModelHostingSection = ({
43232
43393
  title: "Configure which model and hosting provider to use",
43233
43394
  arrow: true,
43234
43395
  placement: "top",
43235
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoButton$2, { size: "small", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faInfoCircle, size: "xs" }) })
43396
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoButton$3, { size: "small", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faInfoCircle, size: "xs" }) })
43236
43397
  }
43237
43398
  )
43238
43399
  ] }),
@@ -44500,366 +44661,6 @@ const MessageInput = ({
44500
44661
  )
44501
44662
  ] });
44502
44663
  };
44503
- const LoadingIndicator = ({ status, agentName = "Agent" }) => {
44504
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
44505
- Box,
44506
- {
44507
- sx: {
44508
- display: "flex",
44509
- alignItems: "center",
44510
- gap: 2
44511
- },
44512
- children: [
44513
- /* @__PURE__ */ jsxRuntimeExports.jsx(
44514
- Avatar,
44515
- {
44516
- sx: {
44517
- bgcolor: "rgba(56, 201, 106, 0.2)",
44518
- color: "primary.main"
44519
- },
44520
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faRobot, size: "sm" })
44521
- }
44522
- ),
44523
- /* @__PURE__ */ jsxRuntimeExports.jsxs(
44524
- Box,
44525
- {
44526
- sx: {
44527
- bgcolor: "background.paper",
44528
- p: 2,
44529
- borderRadius: 2,
44530
- border: "1px solid rgba(255, 255, 255, 0.1)",
44531
- display: "flex",
44532
- alignItems: "center",
44533
- gap: 1
44534
- },
44535
- children: [
44536
- /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, { size: 16, color: "primary" }),
44537
- /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", children: status ? `${agentName} is ${getStatusText(status)}...` : `${agentName} is thinking...` })
44538
- ]
44539
- }
44540
- )
44541
- ]
44542
- }
44543
- );
44544
- };
44545
- const getStatusText = (status) => {
44546
- switch (status) {
44547
- case "pending":
44548
- return "waiting to start";
44549
- case "processing":
44550
- return "thinking";
44551
- case "completed":
44552
- return "finishing up";
44553
- case "failed":
44554
- return "having trouble";
44555
- case "cancelled":
44556
- return "was cancelled";
44557
- default:
44558
- return "thinking";
44559
- }
44560
- };
44561
- const HighlightContainer$1 = styled$1(Box, {
44562
- shouldForwardProp: (prop) => prop !== "action" && prop !== "isUser"
44563
- })(({ action }) => ({
44564
- position: "relative",
44565
- padding: "16px",
44566
- borderRadius: "8px",
44567
- marginBottom: "16px",
44568
- boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
44569
- width: "100%",
44570
- border: `1px solid ${action === "DONE" ? "rgba(76, 175, 80, 0.5)" : "rgba(33, 150, 243, 0.5)"}`,
44571
- backgroundColor: action === "DONE" ? "rgba(76, 175, 80, 0.1)" : "rgba(33, 150, 243, 0.1)",
44572
- transition: "all 0.2s ease",
44573
- "&:hover": {
44574
- boxShadow: "0 6px 16px rgba(0, 0, 0, 0.2)"
44575
- }
44576
- }));
44577
- const ActionBadge = styled$1(Box, {
44578
- shouldForwardProp: (prop) => prop !== "action"
44579
- })(({ theme: theme2, action }) => ({
44580
- position: "absolute",
44581
- top: "-10px",
44582
- right: "16px",
44583
- padding: "4px 8px",
44584
- borderRadius: "12px",
44585
- fontSize: "0.7rem",
44586
- fontWeight: "bold",
44587
- backgroundColor: action === "DONE" ? theme2.palette.success.main : theme2.palette.info.main,
44588
- color: "#fff",
44589
- display: "flex",
44590
- alignItems: "center",
44591
- gap: "4px",
44592
- boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
44593
- }));
44594
- const ActionHighlight = ({
44595
- children,
44596
- action,
44597
- isUser,
44598
- taskClassification,
44599
- executionType
44600
- }) => {
44601
- const shouldHighlight = (action === "DONE" || action === "ASK") && taskClassification !== "conversation" || executionType === "response" && taskClassification !== "conversation";
44602
- if (!shouldHighlight) {
44603
- return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children });
44604
- }
44605
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(HighlightContainer$1, { action, isUser, children: [
44606
- /* @__PURE__ */ jsxRuntimeExports.jsxs(ActionBadge, { action, children: [
44607
- /* @__PURE__ */ jsxRuntimeExports.jsx(
44608
- FontAwesomeIcon,
44609
- {
44610
- icon: action === "DONE" ? faCheck : faQuestion,
44611
- size: "xs"
44612
- }
44613
- ),
44614
- action === "DONE" ? "COMPLETE" : "QUESTION"
44615
- ] }),
44616
- children
44617
- ] });
44618
- };
44619
- const MarkdownContent = styled$1(Box, {
44620
- shouldForwardProp: (prop) => ![
44621
- "fontSize",
44622
- "lineHeight",
44623
- "paragraphSpacing",
44624
- "headingScale",
44625
- "codeSize"
44626
- ].includes(prop)
44627
- })(
44628
- ({
44629
- fontSize = "1.05rem",
44630
- lineHeight = 1.6,
44631
- paragraphSpacing = "8px",
44632
- headingScale = 1,
44633
- codeSize = "0.85em"
44634
- }) => ({
44635
- wordBreak: "break-word",
44636
- overflowWrap: "break-word",
44637
- lineHeight,
44638
- fontSize,
44639
- "& code": {
44640
- fontFamily: '"Roboto Mono", monospace',
44641
- backgroundColor: "rgba(0, 0, 0, 0.3)",
44642
- padding: "3px 6px",
44643
- borderRadius: "4px",
44644
- fontSize: codeSize,
44645
- whiteSpace: "pre-wrap",
44646
- wordBreak: "break-word",
44647
- color: "#e6e6e6"
44648
- },
44649
- "& pre": {
44650
- backgroundColor: "rgba(0, 0, 0, 0.3)",
44651
- padding: "16px",
44652
- borderRadius: "8px",
44653
- overflowX: "auto",
44654
- fontFamily: '"Roboto Mono", monospace',
44655
- fontSize: codeSize,
44656
- margin: "12px 0",
44657
- maxWidth: "100%",
44658
- border: "1px solid rgba(255, 255, 255, 0.1)"
44659
- },
44660
- "& pre code": {
44661
- whiteSpace: "pre-wrap",
44662
- wordBreak: "break-word",
44663
- backgroundColor: "transparent",
44664
- padding: 0,
44665
- borderRadius: 0
44666
- },
44667
- "& h1": {
44668
- fontSize: `calc(1.5rem * ${headingScale})`,
44669
- fontWeight: 600,
44670
- margin: "20px 0 12px 0",
44671
- borderBottom: "1px solid rgba(255, 255, 255, 0.1)",
44672
- paddingBottom: "8px"
44673
- },
44674
- "& h2": {
44675
- fontSize: `calc(1.3rem * ${headingScale})`,
44676
- fontWeight: 600,
44677
- margin: "18px 0 10px 0"
44678
- },
44679
- "& h3": {
44680
- fontSize: `calc(1.1rem * ${headingScale})`,
44681
- fontWeight: 600,
44682
- margin: "16px 0 8px 0"
44683
- },
44684
- "& ul": {
44685
- paddingLeft: "24px",
44686
- margin: "10px 0"
44687
- },
44688
- "& li": {
44689
- margin: "4px 0"
44690
- },
44691
- "& a": {
44692
- color: "#90caf9",
44693
- textDecoration: "none",
44694
- borderBottom: "1px dotted rgba(144, 202, 249, 0.5)",
44695
- transition: "all 0.2s ease",
44696
- "&:hover": {
44697
- textDecoration: "none",
44698
- borderBottom: "1px solid #90caf9",
44699
- color: "#bbdefb"
44700
- }
44701
- },
44702
- "& strong": {
44703
- fontWeight: 600,
44704
- color: "#e6e6e6"
44705
- },
44706
- "& em": {
44707
- fontStyle: "italic",
44708
- color: "#e0e0e0"
44709
- },
44710
- "& br": {
44711
- display: "block",
44712
- content: '""',
44713
- marginTop: "8px"
44714
- },
44715
- "& p:first-of-type": {
44716
- marginTop: "2px"
44717
- },
44718
- "& p": {
44719
- margin: `${paragraphSpacing} 0`
44720
- }
44721
- })
44722
- );
44723
- const convertUrlsToMarkdownLinks = (text2) => {
44724
- const urlRegex = /(?<!\]\()(https?:\/\/\S+?)([,.;:!?"'\)\]]+)?(?=\s|$)/g;
44725
- return text2.replace(
44726
- urlRegex,
44727
- (_match, url, punctuation) => `[${url}](${url})${punctuation || ""}`
44728
- );
44729
- };
44730
- const MarkdownRenderer = reactExports.memo(
44731
- ({ content: content2, styleProps }) => {
44732
- const processedContent = reactExports.useMemo(() => {
44733
- return convertUrlsToMarkdownLinks(content2.trim());
44734
- }, [content2]);
44735
- return /* @__PURE__ */ jsxRuntimeExports.jsx(MarkdownContent, { ...styleProps, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
44736
- Markdown,
44737
- {
44738
- components: {
44739
- a: ({ href, children }) => /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children })
44740
- },
44741
- children: processedContent
44742
- }
44743
- ) });
44744
- }
44745
- );
44746
- const BlockContainer = styled$1(Box)(() => ({
44747
- width: "95%",
44748
- cursor: "pointer",
44749
- transition: "all 0.2s ease",
44750
- marginLeft: 56,
44751
- "&:hover": {
44752
- opacity: 0.9
44753
- }
44754
- }));
44755
- const BlockHeader = styled$1(Box, {
44756
- shouldForwardProp: (prop) => prop !== "executionType" && prop !== "isUser"
44757
- })(
44758
- ({ theme: theme2, executionType }) => ({
44759
- display: "flex",
44760
- alignItems: "center",
44761
- padding: "8px 12px",
44762
- backgroundColor: "rgba(0, 0, 0, 0.2)",
44763
- borderLeft: `3px solid ${executionType === "plan" ? theme2.palette.grey[600] : theme2.palette.grey[600]}`
44764
- })
44765
- );
44766
- const BlockIcon = styled$1(Box)(({ theme: theme2 }) => ({
44767
- marginRight: 8,
44768
- display: "flex",
44769
- alignItems: "center",
44770
- justifyContent: "flex-start",
44771
- color: theme2.palette.grey[500]
44772
- }));
44773
- const BlockTitle = styled$1(Typography)(({ theme: theme2 }) => ({
44774
- fontWeight: 500,
44775
- fontSize: "0.85rem",
44776
- color: theme2.palette.grey[500]
44777
- }));
44778
- const BlockContent = styled$1(Typography)(({ theme: theme2 }) => ({
44779
- fontSize: "0.85rem",
44780
- color: theme2.palette.grey[400],
44781
- overflow: "hidden",
44782
- textOverflow: "ellipsis",
44783
- marginTop: 2
44784
- }));
44785
- const ExpandedContent = styled$1(Box)(({ theme: theme2 }) => ({
44786
- padding: "12px 16px",
44787
- backgroundColor: "rgba(0, 0, 0, 0.2)",
44788
- borderBottomLeftRadius: 4,
44789
- borderBottomRightRadius: 4,
44790
- fontSize: "0.85rem",
44791
- color: theme2.palette.grey[300],
44792
- borderLeft: `3px solid ${theme2.palette.grey[600]}`,
44793
- marginLeft: 0
44794
- }));
44795
- const BackgroundBlock = ({
44796
- content: content2,
44797
- action,
44798
- executionType,
44799
- isUser
44800
- }) => {
44801
- const [isExpanded, setIsExpanded] = reactExports.useState(false);
44802
- const toggleExpand = () => {
44803
- setIsExpanded(!isExpanded);
44804
- };
44805
- const getTitle = () => {
44806
- switch (action) {
44807
- case "DONE":
44808
- return "Task Complete";
44809
- case "ASK":
44810
- return "Asking a Question";
44811
- default:
44812
- return executionType === "plan" ? "Planning" : "Reflection";
44813
- }
44814
- };
44815
- const getIcon = () => {
44816
- switch (action) {
44817
- case "DONE":
44818
- return faCheck;
44819
- case "ASK":
44820
- return faQuestion;
44821
- default:
44822
- return executionType === "plan" ? faLightbulb : faCommentDots;
44823
- }
44824
- };
44825
- const getTruncatedContent = (content22, maxLength = 140) => {
44826
- return content22.length > maxLength ? `${content22.slice(0, maxLength)}...` : content22;
44827
- };
44828
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(BlockContainer, { onClick: toggleExpand, children: [
44829
- /* @__PURE__ */ jsxRuntimeExports.jsxs(BlockHeader, { executionType, isUser, children: [
44830
- /* @__PURE__ */ jsxRuntimeExports.jsx(BlockIcon, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: getIcon(), size: "sm" }) }),
44831
- /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { flexGrow: 1 }, children: [
44832
- /* @__PURE__ */ jsxRuntimeExports.jsx(BlockTitle, { variant: "subtitle2", children: getTitle() }),
44833
- !isExpanded && /* @__PURE__ */ jsxRuntimeExports.jsx(BlockContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
44834
- MarkdownRenderer,
44835
- {
44836
- content: getTruncatedContent(content2),
44837
- styleProps: {
44838
- fontSize: "0.85rem",
44839
- lineHeight: 1.5,
44840
- paragraphSpacing: "4px",
44841
- headingScale: 0.9,
44842
- codeSize: "0.85em"
44843
- }
44844
- }
44845
- ) })
44846
- ] })
44847
- ] }),
44848
- /* @__PURE__ */ jsxRuntimeExports.jsx(Collapse, { in: isExpanded, timeout: "auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExpandedContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
44849
- MarkdownRenderer,
44850
- {
44851
- content: content2,
44852
- styleProps: {
44853
- fontSize: "0.85rem",
44854
- lineHeight: 1.5,
44855
- paragraphSpacing: "4px",
44856
- headingScale: 0.9,
44857
- codeSize: "0.85em"
44858
- }
44859
- }
44860
- ) }) })
44861
- ] });
44862
- };
44863
44664
  function _objectWithoutPropertiesLoose(r, e) {
44864
44665
  if (null == r) return {};
44865
44666
  var t = {};
@@ -82181,6 +81982,578 @@ function ft(n2) {
82181
81982
  }
82182
81983
  return React.memo(l2);
82183
81984
  }
81985
+ const SyntaxHighlighterStyles$1 = ft`
81986
+ .loading-syntax-highlighter * {
81987
+ font-family: 'Roboto Mono', monospace !important;
81988
+ }
81989
+ `;
81990
+ const dotAnimation = keyframes`
81991
+ 0%, 100% { opacity: 0.3; }
81992
+ 50% { opacity: 1; }
81993
+ `;
81994
+ const textStrobeAnimation = keyframes`
81995
+ 0% { opacity: 0.6; }
81996
+ 50% { opacity: 1; }
81997
+ 100% { opacity: 0.6; }
81998
+ `;
81999
+ const LoadingContainer$5 = styled$1(Box)(() => ({
82000
+ display: "flex",
82001
+ alignItems: "center",
82002
+ gap: 0
82003
+ }));
82004
+ const AgentAvatar$2 = styled$1(Avatar)(({ theme: theme2 }) => ({
82005
+ backgroundColor: "rgba(56, 201, 106, 0.2)",
82006
+ color: theme2.palette.primary.main
82007
+ }));
82008
+ const ContentContainer$3 = styled$1(Box)(() => ({
82009
+ display: "flex",
82010
+ flexDirection: "column",
82011
+ gap: 8,
82012
+ maxWidth: "calc(100% - 60px)"
82013
+ }));
82014
+ const StatusContainer = styled$1(Box)(() => ({
82015
+ display: "flex",
82016
+ alignItems: "center",
82017
+ gap: 8
82018
+ }));
82019
+ const StatusText = styled$1(Typography)(({ theme: theme2 }) => ({
82020
+ color: theme2.palette.text.secondary,
82021
+ display: "flex",
82022
+ marginLeft: 16,
82023
+ position: "relative",
82024
+ animation: `${textStrobeAnimation} 3s ease-in-out infinite`
82025
+ }));
82026
+ const StatusTextContent = styled$1("span")(() => ({
82027
+ wordBreak: "break-word",
82028
+ display: "inline"
82029
+ }));
82030
+ const StatusControls = styled$1("span")(() => ({
82031
+ display: "inline-flex",
82032
+ alignItems: "center",
82033
+ marginLeft: 4,
82034
+ whiteSpace: "nowrap"
82035
+ }));
82036
+ const DotContainer = styled$1("span")(() => ({
82037
+ display: "inline-flex",
82038
+ alignItems: "center",
82039
+ position: "relative",
82040
+ zIndex: 2,
82041
+ marginLeft: 4
82042
+ }));
82043
+ const Dot = styled$1("span")(({ theme: theme2, delay }) => ({
82044
+ width: 4,
82045
+ height: 4,
82046
+ borderRadius: "50%",
82047
+ backgroundColor: theme2.palette.text.secondary,
82048
+ margin: "0 1px",
82049
+ animation: `${dotAnimation} 1.4s infinite ease-in-out`,
82050
+ animationDelay: `${delay}s`
82051
+ }));
82052
+ const CodeToggleButton = styled$1(Button)(({ theme: theme2 }) => ({
82053
+ color: theme2.palette.text.secondary,
82054
+ padding: "0 4px",
82055
+ minWidth: "auto",
82056
+ textTransform: "none",
82057
+ marginLeft: 8,
82058
+ height: "auto",
82059
+ fontSize: "0.75rem",
82060
+ lineHeight: 1,
82061
+ opacity: 0.7,
82062
+ borderRadius: "12px",
82063
+ transition: "all 0.2s ease",
82064
+ position: "relative",
82065
+ zIndex: 2,
82066
+ "&:hover": {
82067
+ backgroundColor: "transparent",
82068
+ opacity: 1,
82069
+ color: theme2.palette.primary.light
82070
+ },
82071
+ "& .MuiButton-startIcon": {
82072
+ marginRight: 2,
82073
+ marginLeft: 0
82074
+ }
82075
+ }));
82076
+ const CodeContainer$4 = styled$1(Box)(() => ({
82077
+ maxWidth: "100%",
82078
+ marginLeft: 16,
82079
+ marginTop: 8
82080
+ }));
82081
+ const LoadingCodeBlock = ({ code: code2 }) => {
82082
+ if (!code2) return null;
82083
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
82084
+ Box,
82085
+ {
82086
+ sx: {
82087
+ width: "100%",
82088
+ maxHeight: "300px",
82089
+ overflow: "auto",
82090
+ "&::-webkit-scrollbar": {
82091
+ width: "6px",
82092
+ height: "6px"
82093
+ },
82094
+ "&::-webkit-scrollbar-thumb": {
82095
+ backgroundColor: "rgba(255, 255, 255, 0.1)",
82096
+ borderRadius: "3px"
82097
+ },
82098
+ "&::-webkit-scrollbar-corner": {
82099
+ backgroundColor: "rgba(0, 0, 0, 0.3)"
82100
+ },
82101
+ borderRadius: "8px"
82102
+ },
82103
+ children: [
82104
+ /* @__PURE__ */ jsxRuntimeExports.jsx(SyntaxHighlighterStyles$1, {}),
82105
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
82106
+ highlighter,
82107
+ {
82108
+ language: "python",
82109
+ style: atomOneDark,
82110
+ customStyle: {
82111
+ fontSize: "0.85rem",
82112
+ width: "100%",
82113
+ boxShadow: "0 2px 6px rgba(0, 0, 0, 0.2)",
82114
+ padding: "0.75rem",
82115
+ margin: 0
82116
+ // Remove margin to make it more compact
82117
+ },
82118
+ codeTagProps: {
82119
+ style: {
82120
+ fontFamily: '"Roboto Mono", monospace !important'
82121
+ }
82122
+ },
82123
+ className: "loading-syntax-highlighter",
82124
+ wrapLines: true,
82125
+ wrapLongLines: true,
82126
+ children: code2
82127
+ }
82128
+ )
82129
+ ]
82130
+ }
82131
+ );
82132
+ };
82133
+ const getStatusText = (status) => {
82134
+ switch (status) {
82135
+ case "pending":
82136
+ return "Waiting to start";
82137
+ case "processing":
82138
+ return "Thinking";
82139
+ case "completed":
82140
+ return "Finishing up";
82141
+ case "failed":
82142
+ return "Had trouble";
82143
+ case "cancelled":
82144
+ return "Had to stop";
82145
+ default:
82146
+ return "Thinking";
82147
+ }
82148
+ };
82149
+ const getDetailedStatusText = (status, execution) => {
82150
+ if (execution.action) {
82151
+ switch (execution.action) {
82152
+ case "CODE":
82153
+ return "Executing code";
82154
+ case "WRITE":
82155
+ return "Writing content";
82156
+ case "EDIT":
82157
+ return "Editing content";
82158
+ case "READ":
82159
+ return "Reading content";
82160
+ case "ASK":
82161
+ return "Formulating a question";
82162
+ case "DONE":
82163
+ return "Completing the task";
82164
+ case "BYE":
82165
+ return "Ending the conversation";
82166
+ }
82167
+ }
82168
+ if (execution.execution_type) {
82169
+ switch (execution.execution_type) {
82170
+ case "plan":
82171
+ return "Planning my approach";
82172
+ case "action":
82173
+ return "Thinking";
82174
+ case "reflection":
82175
+ return "Reflecting on next steps";
82176
+ case "response":
82177
+ return "Writing a response";
82178
+ case "security_check":
82179
+ return "Performing security checks";
82180
+ case "classification":
82181
+ return "Thinking about my response";
82182
+ case "system":
82183
+ return "Processing system tasks";
82184
+ case "user_input":
82185
+ return "Processing your input";
82186
+ }
82187
+ }
82188
+ return status ? getStatusText(status) : "thinking";
82189
+ };
82190
+ const LoadingIndicator = ({ status, currentExecution, scrollToBottom }) => {
82191
+ const statusText = currentExecution ? getDetailedStatusText(status, currentExecution) : status ? getStatusText(status) : "Thinking";
82192
+ const codeSnippet = currentExecution?.code || null;
82193
+ const message2 = currentExecution?.message || null;
82194
+ const [isCodeExpanded, setIsCodeExpanded] = reactExports.useState(false);
82195
+ const { ref, scrollToBottom: scrollToBottomHook } = useScrollToBottom(
82196
+ [status, currentExecution, message2],
82197
+ 300,
82198
+ // Default threshold
82199
+ 50
82200
+ // Default button threshold
82201
+ );
82202
+ reactExports.useEffect(() => {
82203
+ if (codeSnippet && isCodeExpanded) {
82204
+ requestAnimationFrame(() => {
82205
+ if (scrollToBottomHook) {
82206
+ scrollToBottomHook();
82207
+ } else if (scrollToBottom) {
82208
+ scrollToBottom();
82209
+ }
82210
+ });
82211
+ }
82212
+ }, [codeSnippet, isCodeExpanded, scrollToBottom, scrollToBottomHook]);
82213
+ const toggleCodeExpansion = () => {
82214
+ setIsCodeExpanded((prev2) => !prev2);
82215
+ };
82216
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(LoadingContainer$5, { children: [
82217
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref, style: { height: 0, width: 0 } }),
82218
+ /* @__PURE__ */ jsxRuntimeExports.jsx(AgentAvatar$2, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faRobot, size: "sm" }) }),
82219
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(ContentContainer$3, { children: [
82220
+ /* @__PURE__ */ jsxRuntimeExports.jsx(StatusContainer, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(StatusText, { variant: "body2", children: [
82221
+ /* @__PURE__ */ jsxRuntimeExports.jsx(StatusTextContent, { children: message2 ? message2 : `${statusText}` }),
82222
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(StatusControls, { children: [
82223
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(DotContainer, { children: [
82224
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Dot, { delay: 0 }),
82225
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Dot, { delay: 0.2 }),
82226
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Dot, { delay: 0.4 })
82227
+ ] }),
82228
+ codeSnippet && /* @__PURE__ */ jsxRuntimeExports.jsx(
82229
+ CodeToggleButton,
82230
+ {
82231
+ onClick: toggleCodeExpansion,
82232
+ size: "small",
82233
+ variant: "text",
82234
+ startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(
82235
+ FontAwesomeIcon,
82236
+ {
82237
+ icon: isCodeExpanded ? faChevronUp : faChevronDown,
82238
+ size: "xs",
82239
+ style: { fontSize: "0.75rem" }
82240
+ }
82241
+ ),
82242
+ children: isCodeExpanded ? "(Hide code)" : "(Show code)"
82243
+ }
82244
+ )
82245
+ ] })
82246
+ ] }) }),
82247
+ codeSnippet && isCodeExpanded && /* @__PURE__ */ jsxRuntimeExports.jsx(CodeContainer$4, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(LoadingCodeBlock, { code: codeSnippet }) })
82248
+ ] })
82249
+ ] });
82250
+ };
82251
+ const HighlightContainer$1 = styled$1(Box, {
82252
+ shouldForwardProp: (prop) => prop !== "action" && prop !== "isUser"
82253
+ })(({ action }) => ({
82254
+ position: "relative",
82255
+ padding: "16px",
82256
+ borderRadius: "8px",
82257
+ marginBottom: "16px",
82258
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
82259
+ width: "100%",
82260
+ border: `1px solid ${action === "DONE" ? "rgba(76, 175, 80, 0.5)" : "rgba(33, 150, 243, 0.5)"}`,
82261
+ backgroundColor: action === "DONE" ? "rgba(76, 175, 80, 0.1)" : "rgba(33, 150, 243, 0.1)",
82262
+ transition: "all 0.2s ease",
82263
+ "&:hover": {
82264
+ boxShadow: "0 6px 16px rgba(0, 0, 0, 0.2)"
82265
+ }
82266
+ }));
82267
+ const ActionBadge = styled$1(Box, {
82268
+ shouldForwardProp: (prop) => prop !== "action"
82269
+ })(({ theme: theme2, action }) => ({
82270
+ position: "absolute",
82271
+ top: "-10px",
82272
+ right: "16px",
82273
+ padding: "4px 8px",
82274
+ borderRadius: "12px",
82275
+ fontSize: "0.7rem",
82276
+ fontWeight: "bold",
82277
+ backgroundColor: action === "DONE" ? theme2.palette.success.main : theme2.palette.info.main,
82278
+ color: "#fff",
82279
+ display: "flex",
82280
+ alignItems: "center",
82281
+ gap: "4px",
82282
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.2)"
82283
+ }));
82284
+ const ActionHighlight = ({
82285
+ children,
82286
+ action,
82287
+ isUser,
82288
+ taskClassification,
82289
+ executionType
82290
+ }) => {
82291
+ const shouldHighlight = (action === "DONE" || action === "ASK") && taskClassification !== "conversation" || executionType === "response" && taskClassification !== "conversation";
82292
+ if (!shouldHighlight) {
82293
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, { children });
82294
+ }
82295
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(HighlightContainer$1, { action, isUser, children: [
82296
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(ActionBadge, { action, children: [
82297
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
82298
+ FontAwesomeIcon,
82299
+ {
82300
+ icon: action === "DONE" ? faCheck : faQuestion,
82301
+ size: "xs"
82302
+ }
82303
+ ),
82304
+ action === "DONE" ? "COMPLETE" : "QUESTION"
82305
+ ] }),
82306
+ children
82307
+ ] });
82308
+ };
82309
+ const MarkdownContent = styled$1(Box, {
82310
+ shouldForwardProp: (prop) => ![
82311
+ "fontSize",
82312
+ "lineHeight",
82313
+ "paragraphSpacing",
82314
+ "headingScale",
82315
+ "codeSize"
82316
+ ].includes(prop)
82317
+ })(
82318
+ ({
82319
+ fontSize = "1.05rem",
82320
+ lineHeight = 1.6,
82321
+ paragraphSpacing = "8px",
82322
+ headingScale = 1,
82323
+ codeSize = "0.85em"
82324
+ }) => ({
82325
+ wordBreak: "break-word",
82326
+ overflowWrap: "break-word",
82327
+ lineHeight,
82328
+ fontSize,
82329
+ "& code": {
82330
+ fontFamily: '"Roboto Mono", monospace',
82331
+ backgroundColor: "rgba(0, 0, 0, 0.3)",
82332
+ padding: "3px 6px",
82333
+ borderRadius: "4px",
82334
+ fontSize: codeSize,
82335
+ whiteSpace: "pre-wrap",
82336
+ wordBreak: "break-word",
82337
+ color: "#e6e6e6"
82338
+ },
82339
+ "& pre": {
82340
+ backgroundColor: "rgba(0, 0, 0, 0.3)",
82341
+ padding: "16px",
82342
+ borderRadius: "8px",
82343
+ overflowX: "auto",
82344
+ fontFamily: '"Roboto Mono", monospace',
82345
+ fontSize: codeSize,
82346
+ margin: "12px 0",
82347
+ maxWidth: "100%",
82348
+ border: "1px solid rgba(255, 255, 255, 0.1)"
82349
+ },
82350
+ "& pre code": {
82351
+ whiteSpace: "pre-wrap",
82352
+ wordBreak: "break-word",
82353
+ backgroundColor: "transparent",
82354
+ padding: 0,
82355
+ borderRadius: 0
82356
+ },
82357
+ "& h1": {
82358
+ fontSize: `calc(1.5rem * ${headingScale})`,
82359
+ fontWeight: 600,
82360
+ margin: "20px 0 12px 0",
82361
+ borderBottom: "1px solid rgba(255, 255, 255, 0.1)",
82362
+ paddingBottom: "8px"
82363
+ },
82364
+ "& h2": {
82365
+ fontSize: `calc(1.3rem * ${headingScale})`,
82366
+ fontWeight: 600,
82367
+ margin: "18px 0 10px 0"
82368
+ },
82369
+ "& h3": {
82370
+ fontSize: `calc(1.1rem * ${headingScale})`,
82371
+ fontWeight: 600,
82372
+ margin: "16px 0 8px 0"
82373
+ },
82374
+ "& ul": {
82375
+ paddingLeft: "24px",
82376
+ margin: "10px 0"
82377
+ },
82378
+ "& li": {
82379
+ margin: "4px 0"
82380
+ },
82381
+ "& a": {
82382
+ color: "#90caf9",
82383
+ textDecoration: "none",
82384
+ borderBottom: "1px dotted rgba(144, 202, 249, 0.5)",
82385
+ transition: "all 0.2s ease",
82386
+ "&:hover": {
82387
+ textDecoration: "none",
82388
+ borderBottom: "1px solid #90caf9",
82389
+ color: "#bbdefb"
82390
+ }
82391
+ },
82392
+ "& strong": {
82393
+ fontWeight: 600,
82394
+ color: "#e6e6e6"
82395
+ },
82396
+ "& em": {
82397
+ fontStyle: "italic",
82398
+ color: "#e0e0e0"
82399
+ },
82400
+ "& br": {
82401
+ display: "block",
82402
+ content: '""',
82403
+ marginTop: "8px"
82404
+ },
82405
+ "& p:first-of-type": {
82406
+ marginTop: "2px"
82407
+ },
82408
+ "& p": {
82409
+ margin: `${paragraphSpacing} 0`
82410
+ }
82411
+ })
82412
+ );
82413
+ const convertUrlsToMarkdownLinks = (text2) => {
82414
+ const markdownLinkRegex = /(?<!\]\()(https?:\/\/\S+?)([,.;:!?"'\)\]]+)?(?=\s|$)/g;
82415
+ if (markdownLinkRegex.test(text2)) {
82416
+ return text2;
82417
+ }
82418
+ const urlRegex = /(?<!\]\()(https?:\/\/\S+?)([,.;:!?"'\)\]]+)?(?=\s|$)/g;
82419
+ return text2.replace(
82420
+ urlRegex,
82421
+ (_match, url, punctuation) => `[${url}](${url})${punctuation || ""}`
82422
+ );
82423
+ };
82424
+ const MarkdownRenderer = reactExports.memo(
82425
+ ({ content: content2, styleProps }) => {
82426
+ const processedContent = reactExports.useMemo(() => {
82427
+ return convertUrlsToMarkdownLinks(content2.trim());
82428
+ }, [content2]);
82429
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(MarkdownContent, { ...styleProps, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
82430
+ Markdown,
82431
+ {
82432
+ components: {
82433
+ a: ({ href, children }) => /* @__PURE__ */ jsxRuntimeExports.jsx("a", { href, target: "_blank", rel: "noopener noreferrer", children })
82434
+ },
82435
+ children: processedContent
82436
+ }
82437
+ ) });
82438
+ }
82439
+ );
82440
+ const BlockContainer = styled$1(Box)(() => ({
82441
+ width: "95%",
82442
+ cursor: "pointer",
82443
+ transition: "all 0.2s ease",
82444
+ marginLeft: 56,
82445
+ "&:hover": {
82446
+ opacity: 0.9
82447
+ }
82448
+ }));
82449
+ const BlockHeader = styled$1(Box, {
82450
+ shouldForwardProp: (prop) => prop !== "executionType" && prop !== "isUser"
82451
+ })(
82452
+ ({ theme: theme2, executionType }) => ({
82453
+ display: "flex",
82454
+ alignItems: "center",
82455
+ padding: "8px 12px",
82456
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
82457
+ borderLeft: `3px solid ${executionType === "plan" ? theme2.palette.grey[600] : theme2.palette.grey[600]}`
82458
+ })
82459
+ );
82460
+ const BlockIcon = styled$1(Box)(({ theme: theme2 }) => ({
82461
+ marginRight: 8,
82462
+ display: "flex",
82463
+ alignItems: "center",
82464
+ justifyContent: "flex-start",
82465
+ color: theme2.palette.grey[500]
82466
+ }));
82467
+ const BlockTitle = styled$1(Typography)(({ theme: theme2 }) => ({
82468
+ fontWeight: 500,
82469
+ fontSize: "0.85rem",
82470
+ color: theme2.palette.grey[500]
82471
+ }));
82472
+ const BlockContent = styled$1(Typography)(({ theme: theme2 }) => ({
82473
+ fontSize: "0.85rem",
82474
+ color: theme2.palette.grey[400],
82475
+ overflow: "hidden",
82476
+ textOverflow: "ellipsis",
82477
+ marginTop: 2
82478
+ }));
82479
+ const ExpandedContent = styled$1(Box)(({ theme: theme2 }) => ({
82480
+ padding: "12px 16px",
82481
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
82482
+ borderBottomLeftRadius: 4,
82483
+ borderBottomRightRadius: 4,
82484
+ fontSize: "0.85rem",
82485
+ color: theme2.palette.grey[300],
82486
+ borderLeft: `3px solid ${theme2.palette.grey[600]}`,
82487
+ marginLeft: 0
82488
+ }));
82489
+ const BackgroundBlock = ({
82490
+ content: content2,
82491
+ action,
82492
+ executionType,
82493
+ isUser
82494
+ }) => {
82495
+ const [isExpanded, setIsExpanded] = reactExports.useState(false);
82496
+ const toggleExpand = () => {
82497
+ setIsExpanded(!isExpanded);
82498
+ };
82499
+ const getTitle = () => {
82500
+ switch (action) {
82501
+ case "DONE":
82502
+ return "Task Complete";
82503
+ case "ASK":
82504
+ return "Asking a Question";
82505
+ default:
82506
+ return executionType === "plan" ? "Planning" : "Reflection";
82507
+ }
82508
+ };
82509
+ const getIcon = () => {
82510
+ switch (action) {
82511
+ case "DONE":
82512
+ return faCheck;
82513
+ case "ASK":
82514
+ return faQuestion;
82515
+ default:
82516
+ return executionType === "plan" ? faLightbulb : faCommentDots;
82517
+ }
82518
+ };
82519
+ const getTruncatedContent = (content22, maxLength = 140) => {
82520
+ return content22.length > maxLength ? `${content22.slice(0, maxLength)}...` : content22;
82521
+ };
82522
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(BlockContainer, { onClick: toggleExpand, children: [
82523
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(BlockHeader, { executionType, isUser, children: [
82524
+ /* @__PURE__ */ jsxRuntimeExports.jsx(BlockIcon, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: getIcon(), size: "sm" }) }),
82525
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { flexGrow: 1 }, children: [
82526
+ /* @__PURE__ */ jsxRuntimeExports.jsx(BlockTitle, { variant: "subtitle2", children: getTitle() }),
82527
+ !isExpanded && /* @__PURE__ */ jsxRuntimeExports.jsx(BlockContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
82528
+ MarkdownRenderer,
82529
+ {
82530
+ content: getTruncatedContent(content2),
82531
+ styleProps: {
82532
+ fontSize: "0.85rem",
82533
+ lineHeight: 1.5,
82534
+ paragraphSpacing: "4px",
82535
+ headingScale: 0.9,
82536
+ codeSize: "0.85em"
82537
+ }
82538
+ }
82539
+ ) })
82540
+ ] })
82541
+ ] }),
82542
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Collapse, { in: isExpanded, timeout: "auto", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ExpandedContent, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(
82543
+ MarkdownRenderer,
82544
+ {
82545
+ content: content2,
82546
+ styleProps: {
82547
+ fontSize: "0.85rem",
82548
+ lineHeight: 1.5,
82549
+ paragraphSpacing: "4px",
82550
+ headingScale: 0.9,
82551
+ codeSize: "0.85em"
82552
+ }
82553
+ }
82554
+ ) }) })
82555
+ ] });
82556
+ };
82184
82557
  const CodeContainer$3 = styled$1(Box)({
82185
82558
  marginBottom: 16,
82186
82559
  width: "100%"
@@ -82348,7 +82721,7 @@ const FileName = styled$1(Typography)({
82348
82721
  textDecoration: "underline"
82349
82722
  }
82350
82723
  });
82351
- const getFileName$1 = (path) => {
82724
+ const getFileName$2 = (path) => {
82352
82725
  const parts = path.split(/[/\\]/);
82353
82726
  return parts[parts.length - 1];
82354
82727
  };
@@ -82360,10 +82733,10 @@ const FileAttachment = ({ file, onClick }) => {
82360
82733
  FileAttachmentContainer,
82361
82734
  {
82362
82735
  onClick: handleClick,
82363
- title: `Click to open ${getFileName$1(file)}`,
82736
+ title: `Click to open ${getFileName$2(file)}`,
82364
82737
  children: [
82365
82738
  /* @__PURE__ */ jsxRuntimeExports.jsx(FileIcon, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faFile, size: "sm" }) }),
82366
- /* @__PURE__ */ jsxRuntimeExports.jsx(FileName, { variant: "body2", children: getFileName$1(file) })
82739
+ /* @__PURE__ */ jsxRuntimeExports.jsx(FileName, { variant: "body2", children: getFileName$2(file) })
82367
82740
  ]
82368
82741
  }
82369
82742
  );
@@ -82381,7 +82754,7 @@ const AttachmentImage = styled$1("img")({
82381
82754
  boxShadow: "0 4px 12px rgba(0, 0, 0, 0.25)"
82382
82755
  }
82383
82756
  });
82384
- const getFileName = (path) => {
82757
+ const getFileName$1 = (path) => {
82385
82758
  const parts = path.split(/[/\\]/);
82386
82759
  return parts[parts.length - 1];
82387
82760
  };
@@ -82397,9 +82770,9 @@ const ImageAttachment = ({
82397
82770
  AttachmentImage,
82398
82771
  {
82399
82772
  src,
82400
- alt: getFileName(file),
82773
+ alt: getFileName$1(file),
82401
82774
  onClick: handleClick,
82402
- title: `Click to open ${getFileName(file)}`
82775
+ title: `Click to open ${getFileName$1(file)}`
82403
82776
  }
82404
82777
  );
82405
82778
  };
@@ -82631,6 +83004,42 @@ const StatusIndicator = ({ status }) => {
82631
83004
  if (!status) return null;
82632
83005
  return /* @__PURE__ */ jsxRuntimeExports.jsx(StyledStatusIndicator, { status, children: status });
82633
83006
  };
83007
+ const AttachmentVideo = styled$1("video")({
83008
+ maxWidth: "100%",
83009
+ maxHeight: 300,
83010
+ borderRadius: 8,
83011
+ marginBottom: 8,
83012
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)",
83013
+ cursor: "pointer",
83014
+ transition: "transform 0.2s ease, box-shadow 0.2s ease",
83015
+ "&:hover": {
83016
+ transform: "scale(1.02)",
83017
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.25)"
83018
+ }
83019
+ });
83020
+ const getFileName = (path) => {
83021
+ const parts = path.split(/[/\\]/);
83022
+ return parts[parts.length - 1];
83023
+ };
83024
+ const VideoAttachment = ({
83025
+ file,
83026
+ src,
83027
+ onClick
83028
+ }) => {
83029
+ const handleClick = () => {
83030
+ onClick(file);
83031
+ };
83032
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
83033
+ AttachmentVideo,
83034
+ {
83035
+ src,
83036
+ controls: true,
83037
+ preload: "metadata",
83038
+ onClick: handleClick,
83039
+ title: `Click to open ${getFileName(file)}`
83040
+ }
83041
+ );
83042
+ };
82634
83043
  const isWebUrl = (path) => {
82635
83044
  return path.startsWith("http://") || path.startsWith("https://");
82636
83045
  };
@@ -82656,11 +83065,34 @@ const isImage = (path) => {
82656
83065
  const lowerPath = path.toLowerCase();
82657
83066
  return imageExtensions.some((ext) => lowerPath.endsWith(ext));
82658
83067
  };
83068
+ const isVideo = (path) => {
83069
+ const videoExtensions = [
83070
+ ".mp4",
83071
+ ".webm",
83072
+ ".ogg",
83073
+ ".mov",
83074
+ ".avi",
83075
+ ".wmv",
83076
+ ".flv",
83077
+ ".mkv",
83078
+ ".m4v",
83079
+ ".3gp",
83080
+ ".3g2"
83081
+ ];
83082
+ const lowerPath = path.toLowerCase();
83083
+ return videoExtensions.some((ext) => lowerPath.endsWith(ext));
83084
+ };
82659
83085
  const getAttachmentUrl = (client, path) => {
82660
- if (isImage(path) && !path.startsWith("http")) {
82661
- const normalizedPath = path.startsWith("file://") ? path : `file://${path}`;
83086
+ if (path.startsWith("http")) {
83087
+ return path;
83088
+ }
83089
+ const normalizedPath = path.startsWith("file://") ? path : `file://${path}`;
83090
+ if (isImage(path)) {
82662
83091
  return client.static.getImageUrl(normalizedPath);
82663
83092
  }
83093
+ if (isVideo(path)) {
83094
+ return client.static.getVideoUrl(normalizedPath);
83095
+ }
82664
83096
  return path;
82665
83097
  };
82666
83098
  const MessageItem = reactExports.memo(
@@ -82716,6 +83148,15 @@ const MessageItem = reactExports.memo(
82716
83148
  },
82717
83149
  `${message2.id}-${file}`
82718
83150
  )) }),
83151
+ message2.files && message2.files.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { mb: 2 }, children: message2.files.filter((file) => isVideo(file)).map((file) => /* @__PURE__ */ jsxRuntimeExports.jsx(
83152
+ VideoAttachment,
83153
+ {
83154
+ file,
83155
+ src: getUrl(file),
83156
+ onClick: handleFileClick
83157
+ },
83158
+ `${message2.id}-${file}`
83159
+ )) }),
82719
83160
  message2.message && /* @__PURE__ */ jsxRuntimeExports.jsx(MessageContent, { content: message2.message, isUser }),
82720
83161
  (() => {
82721
83162
  const hasCollapsibleContent = isSecurityCheck && (message2.code || message2.stdout || message2.stderr || message2.logging);
@@ -82738,7 +83179,7 @@ const MessageItem = reactExports.memo(
82738
83179
  return contentBlocks;
82739
83180
  })(),
82740
83181
  message2.status && /* @__PURE__ */ jsxRuntimeExports.jsx(StatusIndicator, { status: message2.status }),
82741
- message2.files && message2.files.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { mt: 2 }, children: message2.files.filter((file) => !isImage(file)).map((file) => /* @__PURE__ */ jsxRuntimeExports.jsx(
83182
+ message2.files && message2.files.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { mt: 2 }, children: message2.files.filter((file) => !isImage(file) && !isVideo(file)).map((file) => /* @__PURE__ */ jsxRuntimeExports.jsx(
82742
83183
  FileAttachment,
82743
83184
  {
82744
83185
  file,
@@ -82764,6 +83205,15 @@ const MessageItem = reactExports.memo(
82764
83205
  },
82765
83206
  `${message2.id}-${file}`
82766
83207
  )) }),
83208
+ message2.files && message2.files.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { mb: 2 }, children: message2.files.filter((file) => isVideo(file)).map((file) => /* @__PURE__ */ jsxRuntimeExports.jsx(
83209
+ VideoAttachment,
83210
+ {
83211
+ file,
83212
+ src: getUrl(file),
83213
+ onClick: handleFileClick
83214
+ },
83215
+ `${message2.id}-${file}`
83216
+ )) }),
82767
83217
  message2.message && /* @__PURE__ */ jsxRuntimeExports.jsx(MessageContent, { content: message2.message, isUser }),
82768
83218
  (() => {
82769
83219
  const hasCollapsibleContent = isAction && (message2.code || message2.stdout || message2.stderr || message2.logging);
@@ -82786,7 +83236,7 @@ const MessageItem = reactExports.memo(
82786
83236
  return contentBlocks;
82787
83237
  })(),
82788
83238
  message2.status && /* @__PURE__ */ jsxRuntimeExports.jsx(StatusIndicator, { status: message2.status }),
82789
- message2.files && message2.files.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { mt: 2 }, children: message2.files.filter((file) => !isImage(file)).map((file) => /* @__PURE__ */ jsxRuntimeExports.jsx(
83239
+ message2.files && message2.files.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { mt: 2 }, children: message2.files.filter((file) => !isImage(file) && !isVideo(file)).map((file) => /* @__PURE__ */ jsxRuntimeExports.jsx(
82790
83240
  FileAttachment,
82791
83241
  {
82792
83242
  file,
@@ -82850,8 +83300,10 @@ const MessagesView = ({
82850
83300
  isFetchingMore,
82851
83301
  jobStatus,
82852
83302
  agentName,
83303
+ currentExecution,
82853
83304
  messagesContainerRef,
82854
- messagesEndRef
83305
+ messagesEndRef,
83306
+ scrollToBottom
82855
83307
  }) => {
82856
83308
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(MessagesContainer, { ref: messagesContainerRef, children: [
82857
83309
  isFetchingMore && /* @__PURE__ */ jsxRuntimeExports.jsxs(LoadingMoreIndicator, { children: [
@@ -82876,7 +83328,15 @@ const MessagesView = ({
82876
83328
  ),
82877
83329
  /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body1", children: "No messages yet. Start a conversation!" })
82878
83330
  ] }),
82879
- isLoading && /* @__PURE__ */ jsxRuntimeExports.jsx(LoadingIndicator, { status: jobStatus, agentName }),
83331
+ isLoading && /* @__PURE__ */ jsxRuntimeExports.jsx(
83332
+ LoadingIndicator,
83333
+ {
83334
+ status: jobStatus,
83335
+ agentName,
83336
+ currentExecution,
83337
+ scrollToBottom
83338
+ }
83339
+ ),
82880
83340
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { ref: messagesEndRef })
82881
83341
  ] })
82882
83342
  ] });
@@ -82930,6 +83390,7 @@ const ChatContent = ({
82930
83390
  isFetchingMore,
82931
83391
  isFarFromBottom,
82932
83392
  jobStatus,
83393
+ currentExecution,
82933
83394
  messagesContainerRef,
82934
83395
  messagesEndRef,
82935
83396
  scrollToBottom,
@@ -82968,8 +83429,10 @@ const ChatContent = ({
82968
83429
  isFetchingMore,
82969
83430
  jobStatus,
82970
83431
  agentName,
83432
+ currentExecution,
82971
83433
  messagesContainerRef,
82972
- messagesEndRef
83434
+ messagesEndRef,
83435
+ scrollToBottom
82973
83436
  }
82974
83437
  )
82975
83438
  ) : (
@@ -83051,6 +83514,53 @@ const useDeleteAgent = () => {
83051
83514
  }
83052
83515
  });
83053
83516
  };
83517
+ const useImportAgent = () => {
83518
+ const queryClient2 = useQueryClient();
83519
+ const client = createLocalOperatorClient(apiConfig.baseUrl);
83520
+ return useMutation({
83521
+ mutationFn: async (file) => {
83522
+ try {
83523
+ const response = await client.agents.importAgent(file);
83524
+ if (response.status >= 400) {
83525
+ throw new Error(response.message || "Failed to import agent");
83526
+ }
83527
+ return response.result;
83528
+ } catch (error) {
83529
+ const errorMessage = error instanceof Error ? error.message : "An unknown error occurred while importing the agent";
83530
+ y$1.error(errorMessage);
83531
+ throw error;
83532
+ }
83533
+ },
83534
+ onSuccess: (data) => {
83535
+ queryClient2.invalidateQueries({ queryKey: agentsQueryKey });
83536
+ y$1.success("Agent imported successfully");
83537
+ return data;
83538
+ },
83539
+ onError: (error) => {
83540
+ console.error("Error importing agent:", error);
83541
+ }
83542
+ });
83543
+ };
83544
+ const useExportAgent = () => {
83545
+ const client = createLocalOperatorClient(apiConfig.baseUrl);
83546
+ return useMutation({
83547
+ mutationFn: async (agentId) => {
83548
+ try {
83549
+ return await client.agents.exportAgent(agentId);
83550
+ } catch (error) {
83551
+ const errorMessage = error instanceof Error ? error.message : `An unknown error occurred while exporting agent ${agentId}`;
83552
+ y$1.error(errorMessage);
83553
+ throw error;
83554
+ }
83555
+ },
83556
+ onSuccess: () => {
83557
+ y$1.success("Agent exported successfully");
83558
+ },
83559
+ onError: (error) => {
83560
+ console.error("Error exporting agent:", error);
83561
+ }
83562
+ });
83563
+ };
83054
83564
  const OptionsIconButton = styled$1(IconButton)({
83055
83565
  opacity: 0,
83056
83566
  transition: "opacity 0.2s",
@@ -83090,7 +83600,8 @@ const AgentOptionsMenu = ({
83090
83600
  buttonSx = {},
83091
83601
  isAgentsPage = false,
83092
83602
  onViewAgentSettings,
83093
- onChatWithAgent
83603
+ onChatWithAgent,
83604
+ onExportAgent
83094
83605
  }) => {
83095
83606
  const [menuAnchorEl, setMenuAnchorEl] = reactExports.useState(null);
83096
83607
  const [isDeleteModalOpen, setIsDeleteModalOpen] = reactExports.useState(false);
@@ -83177,6 +83688,19 @@ const AgentOptionsMenu = ({
83177
83688
  ]
83178
83689
  }
83179
83690
  ),
83691
+ onExportAgent && /* @__PURE__ */ jsxRuntimeExports.jsxs(
83692
+ StyledMenuItem,
83693
+ {
83694
+ onClick: () => {
83695
+ onExportAgent();
83696
+ handleCloseMenu();
83697
+ },
83698
+ children: [
83699
+ /* @__PURE__ */ jsxRuntimeExports.jsx(MenuItemIcon, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faFileExport, size: "sm" }) }),
83700
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", children: "Export Agent" })
83701
+ ]
83702
+ }
83703
+ ),
83180
83704
  /* @__PURE__ */ jsxRuntimeExports.jsxs(DeleteMenuItem, { onClick: handleOpenDeleteConfirmation, children: [
83181
83705
  /* @__PURE__ */ jsxRuntimeExports.jsx(MenuItemIcon, { color: "error", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faTrash, size: "sm" }) }),
83182
83706
  /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", children: "Delete Agent" })
@@ -83287,7 +83811,7 @@ const CompactPagination = ({
83287
83811
  )
83288
83812
  ] });
83289
83813
  };
83290
- const StyledIcon = styled$1(FontAwesomeIcon)(({ theme: theme2 }) => ({
83814
+ const StyledIcon$1 = styled$1(FontAwesomeIcon)(({ theme: theme2 }) => ({
83291
83815
  color: theme2.palette.primary.main,
83292
83816
  fontSize: "1.2rem"
83293
83817
  }));
@@ -83321,7 +83845,7 @@ const NameField = styled$1(StyledTextField$1)({
83321
83845
  transform: "translate(14px, -9px) scale(0.75)"
83322
83846
  }
83323
83847
  });
83324
- const Subtitle = styled$1(Typography)(({ theme: theme2 }) => ({
83848
+ const Subtitle$1 = styled$1(Typography)(({ theme: theme2 }) => ({
83325
83849
  color: theme2.palette.text.secondary,
83326
83850
  fontSize: "0.875rem",
83327
83851
  marginTop: 4,
@@ -83359,7 +83883,7 @@ const CreateAgentDialog = ({
83359
83883
  const isLoading = createAgentMutation.isPending;
83360
83884
  const isSubmitDisabled = isLoading || !name2.trim();
83361
83885
  const dialogTitle = /* @__PURE__ */ jsxRuntimeExports.jsxs(TitleContainer, { children: [
83362
- /* @__PURE__ */ jsxRuntimeExports.jsx(StyledIcon, { icon: faRobot }),
83886
+ /* @__PURE__ */ jsxRuntimeExports.jsx(StyledIcon$1, { icon: faRobot }),
83363
83887
  "Create New Agent"
83364
83888
  ] });
83365
83889
  const dialogActions = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
@@ -83392,7 +83916,7 @@ const CreateAgentDialog = ({
83392
83916
  actions: dialogActions,
83393
83917
  maxWidth: "sm",
83394
83918
  children: [
83395
- /* @__PURE__ */ jsxRuntimeExports.jsx(Subtitle, { children: "Configure your new AI assistant with a name and optional description" }),
83919
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Subtitle$1, { children: "Configure your new AI assistant with a name and optional description" }),
83396
83920
  /* @__PURE__ */ jsxRuntimeExports.jsx("form", { id: "create-agent-form", onSubmit: handleSubmit, children: /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$2, { children: [
83397
83921
  /* @__PURE__ */ jsxRuntimeExports.jsx(
83398
83922
  NameField,
@@ -83433,6 +83957,199 @@ const CreateAgentDialog = ({
83433
83957
  }
83434
83958
  );
83435
83959
  };
83960
+ const StyledIcon = styled$1(FontAwesomeIcon)(({ theme: theme2 }) => ({
83961
+ color: theme2.palette.primary.main,
83962
+ fontSize: "1.2rem"
83963
+ }));
83964
+ const UploadArea = styled$1(Box)(({ theme: theme2 }) => ({
83965
+ border: `2px dashed ${theme2.palette.divider}`,
83966
+ borderRadius: theme2.shape.borderRadius * 2,
83967
+ padding: theme2.spacing(4),
83968
+ textAlign: "center",
83969
+ cursor: "pointer",
83970
+ transition: "all 0.2s ease-in-out",
83971
+ backgroundColor: alpha(theme2.palette.background.paper, 0.6),
83972
+ "&:hover": {
83973
+ borderColor: theme2.palette.primary.main,
83974
+ backgroundColor: alpha(theme2.palette.action.hover, 0.1)
83975
+ },
83976
+ "&.drag-active": {
83977
+ borderColor: theme2.palette.primary.main,
83978
+ backgroundColor: alpha(theme2.palette.primary.main, 0.05),
83979
+ boxShadow: `0 0 0 3px ${alpha(theme2.palette.primary.main, 0.15)}`
83980
+ }
83981
+ }));
83982
+ const UploadIcon = styled$1(FontAwesomeIcon)(({ theme: theme2 }) => ({
83983
+ fontSize: "2rem",
83984
+ color: theme2.palette.text.secondary,
83985
+ marginBottom: theme2.spacing(2)
83986
+ }));
83987
+ const FileInput = styled$1("input")({
83988
+ display: "none"
83989
+ });
83990
+ const Subtitle = styled$1(Typography)(({ theme: theme2 }) => ({
83991
+ color: theme2.palette.text.secondary,
83992
+ fontSize: "0.875rem",
83993
+ marginTop: 4,
83994
+ marginBottom: 16
83995
+ }));
83996
+ const ErrorMessage = styled$1(Typography)(({ theme: theme2 }) => ({
83997
+ color: theme2.palette.error.main,
83998
+ fontSize: "0.875rem",
83999
+ marginTop: theme2.spacing(2)
84000
+ }));
84001
+ const ImportAgentDialog = ({
84002
+ open,
84003
+ onClose,
84004
+ onAgentImported
84005
+ }) => {
84006
+ const [file, setFile] = reactExports.useState(null);
84007
+ const [isDragActive, setIsDragActive] = reactExports.useState(false);
84008
+ const [error, setError] = reactExports.useState(null);
84009
+ const fileInputRef = reactExports.useRef(null);
84010
+ const importAgentMutation = useImportAgent();
84011
+ const handleDragEnter = reactExports.useCallback((e) => {
84012
+ e.preventDefault();
84013
+ e.stopPropagation();
84014
+ setIsDragActive(true);
84015
+ }, []);
84016
+ const handleDragLeave = reactExports.useCallback((e) => {
84017
+ e.preventDefault();
84018
+ e.stopPropagation();
84019
+ setIsDragActive(false);
84020
+ }, []);
84021
+ const handleDragOver = reactExports.useCallback((e) => {
84022
+ e.preventDefault();
84023
+ e.stopPropagation();
84024
+ }, []);
84025
+ const validateFile = reactExports.useCallback((file2) => {
84026
+ if (!file2.name.toLowerCase().endsWith(".zip")) {
84027
+ setError("Only ZIP files are supported");
84028
+ return false;
84029
+ }
84030
+ setError(null);
84031
+ return true;
84032
+ }, []);
84033
+ const handleDrop = reactExports.useCallback(
84034
+ (e) => {
84035
+ e.preventDefault();
84036
+ e.stopPropagation();
84037
+ setIsDragActive(false);
84038
+ if (e.dataTransfer.files && e.dataTransfer.files.length > 0) {
84039
+ const droppedFile = e.dataTransfer.files[0];
84040
+ if (validateFile(droppedFile)) {
84041
+ setFile(droppedFile);
84042
+ }
84043
+ }
84044
+ },
84045
+ [validateFile]
84046
+ );
84047
+ const handleFileSelect = reactExports.useCallback(
84048
+ (e) => {
84049
+ if (e.target.files && e.target.files.length > 0) {
84050
+ const selectedFile = e.target.files[0];
84051
+ if (validateFile(selectedFile)) {
84052
+ setFile(selectedFile);
84053
+ }
84054
+ }
84055
+ },
84056
+ [validateFile]
84057
+ );
84058
+ const handleClickUpload = reactExports.useCallback(() => {
84059
+ fileInputRef.current?.click();
84060
+ }, []);
84061
+ const handleSubmit = async () => {
84062
+ if (!file) return;
84063
+ try {
84064
+ const result = await importAgentMutation.mutateAsync(file);
84065
+ setFile(null);
84066
+ setError(null);
84067
+ if (onAgentImported && result) {
84068
+ onAgentImported(result.id);
84069
+ }
84070
+ onClose();
84071
+ } catch (error2) {
84072
+ console.error("Failed to import agent:", error2);
84073
+ }
84074
+ };
84075
+ const handleClose = () => {
84076
+ setFile(null);
84077
+ setError(null);
84078
+ onClose();
84079
+ };
84080
+ const isLoading = importAgentMutation.isPending;
84081
+ const isSubmitDisabled = isLoading || !file;
84082
+ const dialogTitle = /* @__PURE__ */ jsxRuntimeExports.jsxs(TitleContainer, { children: [
84083
+ /* @__PURE__ */ jsxRuntimeExports.jsx(StyledIcon, { icon: faFileImport }),
84084
+ "Import Agent"
84085
+ ] });
84086
+ const dialogActions = /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
84087
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
84088
+ SecondaryButton,
84089
+ {
84090
+ onClick: handleClose,
84091
+ variant: "outlined",
84092
+ disabled: isLoading,
84093
+ children: "Cancel"
84094
+ }
84095
+ ),
84096
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
84097
+ PrimaryButton,
84098
+ {
84099
+ onClick: handleSubmit,
84100
+ disabled: isSubmitDisabled,
84101
+ startIcon: isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, { size: 20, color: "inherit" }) : null,
84102
+ children: "Import Agent"
84103
+ }
84104
+ )
84105
+ ] });
84106
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
84107
+ BaseDialog,
84108
+ {
84109
+ open,
84110
+ onClose: handleClose,
84111
+ title: dialogTitle,
84112
+ actions: dialogActions,
84113
+ maxWidth: "sm",
84114
+ children: [
84115
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Subtitle, { children: "Import an agent from a ZIP file exported from Local Operator. The file should contain an agent.yml file." }),
84116
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(FormContainer$2, { children: [
84117
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
84118
+ FileInput,
84119
+ {
84120
+ ref: fileInputRef,
84121
+ type: "file",
84122
+ accept: ".zip",
84123
+ onChange: handleFileSelect,
84124
+ disabled: isLoading
84125
+ }
84126
+ ),
84127
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
84128
+ UploadArea,
84129
+ {
84130
+ onClick: handleClickUpload,
84131
+ onDragEnter: handleDragEnter,
84132
+ onDragLeave: handleDragLeave,
84133
+ onDragOver: handleDragOver,
84134
+ onDrop: handleDrop,
84135
+ className: isDragActive ? "drag-active" : "",
84136
+ children: file ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
84137
+ /* @__PURE__ */ jsxRuntimeExports.jsx(UploadIcon, { icon: faFileImport }),
84138
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body1", gutterBottom: true, children: file.name }),
84139
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", color: "text.secondary", children: "Click or drag to replace" })
84140
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
84141
+ /* @__PURE__ */ jsxRuntimeExports.jsx(UploadIcon, { icon: faUpload }),
84142
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body1", gutterBottom: true, children: "Drag and drop a ZIP file here" }),
84143
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Typography, { variant: "body2", color: "text.secondary", children: "or click to select a file" })
84144
+ ] })
84145
+ }
84146
+ ),
84147
+ error && /* @__PURE__ */ jsxRuntimeExports.jsx(ErrorMessage, { children: error })
84148
+ ] })
84149
+ ]
84150
+ }
84151
+ );
84152
+ };
83436
84153
  const SidebarHeaderContainer = styled$1(Box)(({ theme: theme2 }) => ({
83437
84154
  padding: theme2.spacing(3),
83438
84155
  borderBottom: "1px solid rgba(255,255,255,0.08)"
@@ -83443,25 +84160,28 @@ const HeaderRow = styled$1(Box)({
83443
84160
  alignItems: "center",
83444
84161
  marginBottom: 16
83445
84162
  });
84163
+ const ActionsContainer = styled$1(Box)({
84164
+ display: "flex",
84165
+ gap: 8
84166
+ });
83446
84167
  const SidebarTitle$1 = styled$1(Typography)({
83447
84168
  fontWeight: 600,
83448
84169
  fontSize: "1rem"
83449
84170
  });
83450
- const NewAgentButton = styled$1(Button)(({ theme: theme2 }) => ({
83451
- borderRadius: 8,
83452
- textTransform: "none",
83453
- fontWeight: 600,
83454
- paddingLeft: 16,
83455
- paddingRight: 16,
83456
- paddingTop: 6.4,
83457
- paddingBottom: 6.4,
84171
+ const ActionButton = styled$1(IconButton)(({ theme: theme2 }) => ({
84172
+ borderRadius: 10,
84173
+ padding: 8,
84174
+ backgroundColor: alpha(theme2.palette.primary.main, 0.1),
84175
+ color: theme2.palette.primary.main,
83458
84176
  transition: "all 0.2s ease-in-out",
83459
84177
  "&:hover": {
83460
- boxShadow: `0 2px 8px ${theme2.palette.primary.main}33`,
83461
- transform: "translateY(-1px)"
84178
+ backgroundColor: alpha(theme2.palette.primary.main, 0.2),
84179
+ transform: "translateY(-2px)",
84180
+ boxShadow: `0 4px 8px ${alpha(theme2.palette.primary.main, 0.25)}`
83462
84181
  },
83463
84182
  "&:active": {
83464
- transform: "translateY(0)"
84183
+ transform: "translateY(0)",
84184
+ boxShadow: `0 2px 4px ${alpha(theme2.palette.primary.main, 0.2)}`
83465
84185
  }
83466
84186
  }));
83467
84187
  const SearchField = styled$1(TextField)(({ theme: theme2 }) => ({
@@ -83493,22 +84213,33 @@ const SidebarHeader$1 = ({
83493
84213
  onSearchChange,
83494
84214
  onNewAgentClick,
83495
84215
  searchPlaceholder = "Search agents",
83496
- newAgentTooltip = "Create a new agent"
84216
+ newAgentTooltip = "Create a new agent",
84217
+ onImportAgentClick,
84218
+ importAgentTooltip = "Import an agent from a ZIP file"
83497
84219
  }) => {
83498
84220
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(SidebarHeaderContainer, { children: [
83499
84221
  /* @__PURE__ */ jsxRuntimeExports.jsxs(HeaderRow, { children: [
83500
84222
  /* @__PURE__ */ jsxRuntimeExports.jsx(SidebarTitle$1, { variant: "subtitle1", children: title }),
83501
- /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: newAgentTooltip, arrow: true, placement: "top", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
83502
- NewAgentButton,
83503
- {
83504
- variant: "outlined",
83505
- color: "primary",
83506
- size: "small",
83507
- startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPlus }),
83508
- onClick: onNewAgentClick,
83509
- children: "New Agent"
83510
- }
83511
- ) })
84223
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(ActionsContainer, { children: [
84224
+ onImportAgentClick && /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: importAgentTooltip, arrow: true, placement: "top", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
84225
+ ActionButton,
84226
+ {
84227
+ onClick: onImportAgentClick,
84228
+ size: "small",
84229
+ "aria-label": "Import agent",
84230
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faFileImport })
84231
+ }
84232
+ ) }),
84233
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: newAgentTooltip, arrow: true, placement: "top", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
84234
+ ActionButton,
84235
+ {
84236
+ onClick: onNewAgentClick,
84237
+ size: "small",
84238
+ "aria-label": "New agent",
84239
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faPlus })
84240
+ }
84241
+ ) })
84242
+ ] })
83512
84243
  ] }),
83513
84244
  /* @__PURE__ */ jsxRuntimeExports.jsx(
83514
84245
  SearchField,
@@ -85116,7 +85847,9 @@ const ChatSidebar = ({
85116
85847
  }) => {
85117
85848
  const [searchQuery, setSearchQuery] = reactExports.useState("");
85118
85849
  const [isCreateDialogOpen, setIsCreateDialogOpen] = reactExports.useState(false);
85850
+ const [isImportDialogOpen, setIsImportDialogOpen] = reactExports.useState(false);
85119
85851
  const perPage = 50;
85852
+ const exportAgentMutation = useExportAgent();
85120
85853
  const { page, setPage } = usePaginationParams();
85121
85854
  const {
85122
85855
  data: agents = [],
@@ -85142,6 +85875,32 @@ const ChatSidebar = ({
85142
85875
  const handleCloseCreateDialog = reactExports.useCallback(() => {
85143
85876
  setIsCreateDialogOpen(false);
85144
85877
  }, []);
85878
+ const handleOpenImportDialog = reactExports.useCallback(() => {
85879
+ setIsImportDialogOpen(true);
85880
+ }, []);
85881
+ const handleCloseImportDialog = reactExports.useCallback(() => {
85882
+ setIsImportDialogOpen(false);
85883
+ }, []);
85884
+ const handleExportAgent = reactExports.useCallback(
85885
+ async (agentId) => {
85886
+ try {
85887
+ const blob = await exportAgentMutation.mutateAsync(agentId);
85888
+ const agent = agents.find((a2) => a2.id === agentId);
85889
+ const agentName = agent ? agent.name.replace(/\s+/g, "-").toLowerCase() : agentId;
85890
+ const url = URL.createObjectURL(blob);
85891
+ const a = document.createElement("a");
85892
+ a.href = url;
85893
+ a.download = `${agentName}-export.zip`;
85894
+ document.body.appendChild(a);
85895
+ a.click();
85896
+ URL.revokeObjectURL(url);
85897
+ document.body.removeChild(a);
85898
+ } catch (error) {
85899
+ console.error("Failed to export agent:", error);
85900
+ }
85901
+ },
85902
+ [agents, exportAgentMutation]
85903
+ );
85145
85904
  const handleAgentCreated = reactExports.useCallback(
85146
85905
  (agentId) => {
85147
85906
  const fetchAndSelectAgent = async () => {
@@ -85185,7 +85944,9 @@ const ChatSidebar = ({
85185
85944
  title: "Agents",
85186
85945
  searchQuery,
85187
85946
  onSearchChange: (query) => setSearchQuery(query),
85188
- onNewAgentClick: handleOpenCreateDialog
85947
+ onNewAgentClick: handleOpenCreateDialog,
85948
+ onImportAgentClick: handleOpenImportDialog,
85949
+ importAgentTooltip: "Import an agent from a ZIP file"
85189
85950
  }
85190
85951
  ),
85191
85952
  isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoadingContainer$4, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, { size: 40, thickness: 4 }) }) : isError ? /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -85215,6 +85976,7 @@ const ChatSidebar = ({
85215
85976
  agentName: agent.name,
85216
85977
  isAgentsPage: false,
85217
85978
  onViewAgentSettings: onNavigateToAgentSettings ? () => onNavigateToAgentSettings(agent.id) : void 0,
85979
+ onExportAgent: () => handleExportAgent(agent.id),
85218
85980
  onAgentDeleted: (deletedAgentId) => {
85219
85981
  if (selectedConversation === deletedAgentId) {
85220
85982
  onSelectConversation("");
@@ -85311,6 +86073,14 @@ const ChatSidebar = ({
85311
86073
  onAgentCreated: handleAgentCreated
85312
86074
  }
85313
86075
  ),
86076
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
86077
+ ImportAgentDialog,
86078
+ {
86079
+ open: isImportDialogOpen,
86080
+ onClose: handleCloseImportDialog,
86081
+ onAgentImported: handleAgentCreated
86082
+ }
86083
+ ),
85314
86084
  /* @__PURE__ */ jsxRuntimeExports.jsx(
85315
86085
  CompactPagination,
85316
86086
  {
@@ -85420,7 +86190,8 @@ const ChatPage = () => {
85420
86190
  jobStatus,
85421
86191
  isLoading,
85422
86192
  setIsLoading,
85423
- checkForActiveJobs
86193
+ checkForActiveJobs,
86194
+ currentExecution
85424
86195
  } = useJobPolling({
85425
86196
  conversationId,
85426
86197
  addMessage
@@ -85656,6 +86427,7 @@ Store messages: ${JSON.stringify(getMessages(conversationId || ""), null, 2)}`;
85656
86427
  isFetchingMore,
85657
86428
  isFarFromBottom,
85658
86429
  jobStatus,
86430
+ currentExecution,
85659
86431
  messagesContainerRef,
85660
86432
  messagesEndRef,
85661
86433
  scrollToBottom,
@@ -85743,18 +86515,18 @@ const PageHeader = ({
85743
86515
  children
85744
86516
  ] });
85745
86517
  };
85746
- const SectionTitle$5 = styled$1(Typography)(({ theme: theme2 }) => ({
86518
+ const SectionTitle$6 = styled$1(Typography)(({ theme: theme2 }) => ({
85747
86519
  fontWeight: 600,
85748
86520
  marginBottom: theme2.spacing(2),
85749
86521
  display: "flex",
85750
86522
  alignItems: "center",
85751
86523
  color: theme2.palette.text.primary
85752
86524
  }));
85753
- const TitleIcon$2 = styled$1(FontAwesomeIcon)({
86525
+ const TitleIcon$3 = styled$1(FontAwesomeIcon)({
85754
86526
  marginRight: 10,
85755
86527
  color: "#f2f2f3"
85756
86528
  });
85757
- const InfoButton$1 = styled$1(IconButton)(({ theme: theme2 }) => ({
86529
+ const InfoButton$2 = styled$1(IconButton)(({ theme: theme2 }) => ({
85758
86530
  marginLeft: theme2.spacing(1),
85759
86531
  color: theme2.palette.primary.main,
85760
86532
  "&:hover": {
@@ -85847,8 +86619,8 @@ const ChatSettings = ({
85847
86619
  setLocalAgent(selectedAgent);
85848
86620
  }, [selectedAgent]);
85849
86621
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { mt: 4, mb: 3 }, children: [
85850
- /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$5, { variant: "subtitle1", children: [
85851
- /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon$2, { icon: faComments }),
86622
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$6, { variant: "subtitle1", children: [
86623
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon$3, { icon: faComments }),
85852
86624
  "Chat Settings",
85853
86625
  /* @__PURE__ */ jsxRuntimeExports.jsx(
85854
86626
  Tooltip,
@@ -85856,7 +86628,7 @@ const ChatSettings = ({
85856
86628
  title: "Settings that control how the agent generates responses",
85857
86629
  arrow: true,
85858
86630
  placement: "top",
85859
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoButton$1, { size: "small", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faInfoCircle, size: "xs" }) })
86631
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoButton$2, { size: "small", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faInfoCircle, size: "xs" }) })
85860
86632
  }
85861
86633
  )
85862
86634
  ] }),
@@ -86376,14 +87148,14 @@ const HeaderContainer = styled$1(Box)(({ theme: theme2 }) => ({
86376
87148
  marginBottom: theme2.spacing(2),
86377
87149
  gap: theme2.spacing(2)
86378
87150
  }));
86379
- const SectionTitle$4 = styled$1(Typography)(({ theme: theme2 }) => ({
87151
+ const SectionTitle$5 = styled$1(Typography)(({ theme: theme2 }) => ({
86380
87152
  fontWeight: 600,
86381
87153
  marginBottom: theme2.spacing(2),
86382
87154
  display: "flex",
86383
87155
  alignItems: "center",
86384
87156
  color: theme2.palette.text.primary
86385
87157
  }));
86386
- const TitleIcon$1 = styled$1(FontAwesomeIcon)({
87158
+ const TitleIcon$2 = styled$1(FontAwesomeIcon)({
86387
87159
  marginRight: 10,
86388
87160
  color: "#f2f2f3"
86389
87161
  });
@@ -86516,8 +87288,8 @@ const GeneralSettings = ({
86516
87288
  ] }),
86517
87289
  /* @__PURE__ */ jsxRuntimeExports.jsx(Divider, { sx: { mb: 3 } }),
86518
87290
  /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { mb: 3 }, children: [
86519
- /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$4, { variant: "subtitle1", children: [
86520
- /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon$1, { icon: faInfoCircle }),
87291
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$5, { variant: "subtitle1", children: [
87292
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon$2, { icon: faInfoCircle }),
86521
87293
  "Agent Information"
86522
87294
  ] }),
86523
87295
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -86581,18 +87353,18 @@ const GeneralSettings = ({
86581
87353
  ] })
86582
87354
  ] });
86583
87355
  };
86584
- const SectionTitle$3 = styled$1(Typography)(({ theme: theme2 }) => ({
87356
+ const SectionTitle$4 = styled$1(Typography)(({ theme: theme2 }) => ({
86585
87357
  fontWeight: 600,
86586
87358
  marginBottom: theme2.spacing(2),
86587
87359
  display: "flex",
86588
87360
  alignItems: "center",
86589
87361
  color: theme2.palette.text.primary
86590
87362
  }));
86591
- const TitleIcon = styled$1(FontAwesomeIcon)({
87363
+ const TitleIcon$1 = styled$1(FontAwesomeIcon)({
86592
87364
  marginRight: 10,
86593
87365
  color: "#f2f2f3"
86594
87366
  });
86595
- const InfoButton = styled$1(IconButton)(({ theme: theme2 }) => ({
87367
+ const InfoButton$1 = styled$1(IconButton)(({ theme: theme2 }) => ({
86596
87368
  marginLeft: theme2.spacing(1),
86597
87369
  color: theme2.palette.primary.main,
86598
87370
  "&:hover": {
@@ -86608,8 +87380,8 @@ const SecuritySettings = ({
86608
87380
  initialSelectedAgentId
86609
87381
  }) => {
86610
87382
  return /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { mt: 1 }, children: [
86611
- /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$3, { variant: "subtitle1", children: [
86612
- /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon, { icon: faShieldAlt }),
87383
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$4, { variant: "subtitle1", children: [
87384
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon$1, { icon: faShieldAlt }),
86613
87385
  "Security Prompt",
86614
87386
  /* @__PURE__ */ jsxRuntimeExports.jsx(
86615
87387
  Tooltip,
@@ -86617,7 +87389,7 @@ const SecuritySettings = ({
86617
87389
  title: "Security instructions that guide the agent's behavior and limitations",
86618
87390
  arrow: true,
86619
87391
  placement: "top",
86620
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoButton, { size: "small", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faInfoCircle, size: "xs" }) })
87392
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoButton$1, { size: "small", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faInfoCircle, size: "xs" }) })
86621
87393
  }
86622
87394
  )
86623
87395
  ] }),
@@ -86650,6 +87422,147 @@ const SecuritySettings = ({
86650
87422
  )
86651
87423
  ] });
86652
87424
  };
87425
+ const agentSystemPromptQueryKey = (agentId) => [
87426
+ "agent-system-prompt",
87427
+ agentId
87428
+ ];
87429
+ const useAgentSystemPrompt = (agentId) => {
87430
+ const { shouldEnableQuery } = useConnectivityGate();
87431
+ return useQuery({
87432
+ // Only enable the query if server is online and agent ID is provided
87433
+ enabled: shouldEnableQuery({ bypassInternetCheck: true }) && !!agentId,
87434
+ queryKey: agentSystemPromptQueryKey(agentId),
87435
+ queryFn: async () => {
87436
+ try {
87437
+ const client = createLocalOperatorClient(apiConfig.baseUrl);
87438
+ const response = await client.agents.getAgentSystemPrompt(agentId);
87439
+ if (response.status >= 400) {
87440
+ throw new Error(
87441
+ response.message || "Failed to fetch agent system prompt"
87442
+ );
87443
+ }
87444
+ return response.result?.system_prompt || "";
87445
+ } catch (error) {
87446
+ const errorMessage = error instanceof Error ? error.message : "An unknown error occurred while fetching agent system prompt";
87447
+ showErrorToast(errorMessage);
87448
+ throw error;
87449
+ }
87450
+ },
87451
+ // Prevent automatic refetches on window focus
87452
+ refetchOnWindowFocus: false,
87453
+ // Prevent stale time to avoid unnecessary refetches
87454
+ staleTime: 5e3
87455
+ });
87456
+ };
87457
+ const useUpdateAgentSystemPrompt = (agentId) => {
87458
+ const queryClient2 = useQueryClient();
87459
+ const client = createLocalOperatorClient(apiConfig.baseUrl);
87460
+ return useMutation({
87461
+ mutationFn: async (systemPrompt) => {
87462
+ try {
87463
+ const response = await client.agents.updateAgentSystemPrompt(
87464
+ agentId,
87465
+ systemPrompt
87466
+ );
87467
+ if (response.status >= 400) {
87468
+ throw new Error(
87469
+ response.message || "Failed to update agent system prompt"
87470
+ );
87471
+ }
87472
+ return response;
87473
+ } catch (error) {
87474
+ const errorMessage = error instanceof Error ? error.message : "An unknown error occurred while updating agent system prompt";
87475
+ y$1.error(errorMessage);
87476
+ throw error;
87477
+ }
87478
+ },
87479
+ onSuccess: async () => {
87480
+ await queryClient2.invalidateQueries({
87481
+ queryKey: agentSystemPromptQueryKey(agentId)
87482
+ });
87483
+ y$1.success("Agent system prompt updated successfully");
87484
+ },
87485
+ onError: (error) => {
87486
+ console.error("Error updating agent system prompt:", error);
87487
+ }
87488
+ });
87489
+ };
87490
+ const SectionTitle$3 = styled$1(Typography)(({ theme: theme2 }) => ({
87491
+ fontWeight: 600,
87492
+ marginBottom: theme2.spacing(2),
87493
+ display: "flex",
87494
+ alignItems: "center",
87495
+ color: theme2.palette.text.primary
87496
+ }));
87497
+ const TitleIcon = styled$1(FontAwesomeIcon)({
87498
+ marginRight: 10,
87499
+ color: "#f2f2f3"
87500
+ });
87501
+ const InfoButton = styled$1(IconButton)(({ theme: theme2 }) => ({
87502
+ marginLeft: theme2.spacing(1),
87503
+ color: theme2.palette.primary.main,
87504
+ "&:hover": {
87505
+ backgroundColor: alpha(theme2.palette.primary.main, 0.08)
87506
+ }
87507
+ }));
87508
+ const SystemPromptSettings = ({
87509
+ selectedAgent,
87510
+ savingField,
87511
+ setSavingField,
87512
+ refetchAgent,
87513
+ initialSelectedAgentId
87514
+ }) => {
87515
+ const { data: systemPrompt, isLoading } = useAgentSystemPrompt(
87516
+ selectedAgent.id
87517
+ );
87518
+ const updateSystemPromptMutation = useUpdateAgentSystemPrompt(
87519
+ selectedAgent.id
87520
+ );
87521
+ const [localSystemPrompt, setLocalSystemPrompt] = reactExports.useState("");
87522
+ reactExports.useEffect(() => {
87523
+ if (systemPrompt !== void 0) {
87524
+ setLocalSystemPrompt(systemPrompt);
87525
+ }
87526
+ }, [systemPrompt]);
87527
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(Box, { sx: { mt: 4 }, children: [
87528
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(SectionTitle$3, { variant: "subtitle1", children: [
87529
+ /* @__PURE__ */ jsxRuntimeExports.jsx(TitleIcon, { icon: faRobot }),
87530
+ "System Prompt",
87531
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
87532
+ Tooltip,
87533
+ {
87534
+ title: "System instructions that define the agent's behavior and capabilities",
87535
+ arrow: true,
87536
+ placement: "top",
87537
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(InfoButton, { size: "small", children: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faInfoCircle, size: "xs" }) })
87538
+ }
87539
+ )
87540
+ ] }),
87541
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
87542
+ EditableField,
87543
+ {
87544
+ value: localSystemPrompt,
87545
+ label: "",
87546
+ placeholder: isLoading ? "Loading system prompt..." : "Enter system prompt...",
87547
+ multiline: true,
87548
+ rows: 6,
87549
+ isSaving: savingField === "system_prompt",
87550
+ onSave: async (value) => {
87551
+ setSavingField("system_prompt");
87552
+ try {
87553
+ await updateSystemPromptMutation.mutateAsync(value);
87554
+ if (selectedAgent.id === initialSelectedAgentId && refetchAgent) {
87555
+ await refetchAgent();
87556
+ }
87557
+ } catch (error) {
87558
+ } finally {
87559
+ setSavingField(null);
87560
+ }
87561
+ }
87562
+ }
87563
+ )
87564
+ ] });
87565
+ };
86653
87566
  const DetailsPaper = styled$1(Paper)(({ theme: theme2 }) => ({
86654
87567
  padding: theme2.spacing(4),
86655
87568
  height: "100%",
@@ -86744,6 +87657,16 @@ const AgentSettings = ({
86744
87657
  refetchAgent,
86745
87658
  initialSelectedAgentId
86746
87659
  }
87660
+ ),
87661
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
87662
+ SystemPromptSettings,
87663
+ {
87664
+ selectedAgent,
87665
+ savingField,
87666
+ setSavingField,
87667
+ refetchAgent,
87668
+ initialSelectedAgentId
87669
+ }
86747
87670
  )
86748
87671
  ] }) : /* @__PURE__ */ jsxRuntimeExports.jsxs(EmptyStateContainer$2, { children: [
86749
87672
  /* @__PURE__ */ jsxRuntimeExports.jsx(PlaceholderIcon, { icon: faRobot }),
@@ -86852,7 +87775,9 @@ const AgentsSidebar = ({
86852
87775
  const navigate = useNavigate();
86853
87776
  const [searchQuery, setSearchQuery] = reactExports.useState("");
86854
87777
  const [isCreateDialogOpen, setIsCreateDialogOpen] = reactExports.useState(false);
87778
+ const [isImportDialogOpen, setIsImportDialogOpen] = reactExports.useState(false);
86855
87779
  const perPage = 50;
87780
+ const exportAgentMutation = useExportAgent();
86856
87781
  const { page, setPage } = usePaginationParams();
86857
87782
  const [stableAgents, setStableAgents] = reactExports.useState([]);
86858
87783
  const prevFetchingRef = reactExports.useRef(false);
@@ -86888,6 +87813,32 @@ const AgentsSidebar = ({
86888
87813
  const handleCloseCreateDialog = reactExports.useCallback(() => {
86889
87814
  setIsCreateDialogOpen(false);
86890
87815
  }, []);
87816
+ const handleOpenImportDialog = reactExports.useCallback(() => {
87817
+ setIsImportDialogOpen(true);
87818
+ }, []);
87819
+ const handleCloseImportDialog = reactExports.useCallback(() => {
87820
+ setIsImportDialogOpen(false);
87821
+ }, []);
87822
+ const handleExportAgent = reactExports.useCallback(
87823
+ async (agentId) => {
87824
+ try {
87825
+ const blob = await exportAgentMutation.mutateAsync(agentId);
87826
+ const agent = agents.find((a2) => a2.id === agentId);
87827
+ const agentName = agent ? agent.name.replace(/\s+/g, "-").toLowerCase() : agentId;
87828
+ const url = URL.createObjectURL(blob);
87829
+ const a = document.createElement("a");
87830
+ a.href = url;
87831
+ a.download = `${agentName}-export.zip`;
87832
+ document.body.appendChild(a);
87833
+ a.click();
87834
+ URL.revokeObjectURL(url);
87835
+ document.body.removeChild(a);
87836
+ } catch (error) {
87837
+ console.error("Failed to export agent:", error);
87838
+ }
87839
+ },
87840
+ [agents, exportAgentMutation]
87841
+ );
86891
87842
  const handleAgentCreated = reactExports.useCallback(
86892
87843
  (agentId) => {
86893
87844
  const fetchAndSelectAgent = async () => {
@@ -86929,7 +87880,9 @@ const AgentsSidebar = ({
86929
87880
  title: "Agents",
86930
87881
  searchQuery,
86931
87882
  onSearchChange: (query) => setSearchQuery(query),
86932
- onNewAgentClick: handleOpenCreateDialog
87883
+ onNewAgentClick: handleOpenCreateDialog,
87884
+ onImportAgentClick: handleOpenImportDialog,
87885
+ importAgentTooltip: "Import an agent from a ZIP file"
86933
87886
  }
86934
87887
  ),
86935
87888
  isLoading ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoadingContainer$3, { children: /* @__PURE__ */ jsxRuntimeExports.jsx(CircularProgress, { size: 40, thickness: 4 }) }) : isError ? /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -86962,6 +87915,7 @@ const AgentsSidebar = ({
86962
87915
  refetch();
86963
87916
  },
86964
87917
  onChatWithAgent: () => navigate(`/chat/${agent.id}`),
87918
+ onExportAgent: () => handleExportAgent(agent.id),
86965
87919
  buttonSx: {
86966
87920
  mr: 0.5,
86967
87921
  width: 32,
@@ -87025,6 +87979,14 @@ const AgentsSidebar = ({
87025
87979
  onAgentCreated: handleAgentCreated
87026
87980
  }
87027
87981
  ),
87982
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
87983
+ ImportAgentDialog,
87984
+ {
87985
+ open: isImportDialogOpen,
87986
+ onClose: handleCloseImportDialog,
87987
+ onAgentImported: handleAgentCreated
87988
+ }
87989
+ ),
87028
87990
  /* @__PURE__ */ jsxRuntimeExports.jsx(
87029
87991
  CompactPagination,
87030
87992
  {
@@ -87073,6 +88035,7 @@ const AgentsPage = () => {
87073
88035
  const { agentId, navigateToAgent, clearAgentId } = useAgentRouteParam();
87074
88036
  const navigate = useNavigate();
87075
88037
  const prevAgentIdRef = reactExports.useRef(agentId);
88038
+ const exportAgentMutation = useExportAgent();
87076
88039
  const { setLastAgentsPageAgentId, getLastAgentId, clearLastAgentId } = useAgentSelectionStore();
87077
88040
  const { data: agents = [] } = useAgents();
87078
88041
  const effectiveAgentId = agentId || getLastAgentId("agents");
@@ -87097,6 +88060,22 @@ const AgentsPage = () => {
87097
88060
  setLastAgentsPageAgentId(agentId);
87098
88061
  }
87099
88062
  }, [agentId, setLastAgentsPageAgentId]);
88063
+ const handleExportAgent = async () => {
88064
+ if (!selectedAgent) return;
88065
+ try {
88066
+ const blob = await exportAgentMutation.mutateAsync(selectedAgent.id);
88067
+ const url = URL.createObjectURL(blob);
88068
+ const a = document.createElement("a");
88069
+ a.href = url;
88070
+ a.download = `${selectedAgent.name.replace(/\s+/g, "-").toLowerCase()}-lo-agent.zip`;
88071
+ document.body.appendChild(a);
88072
+ a.click();
88073
+ URL.revokeObjectURL(url);
88074
+ document.body.removeChild(a);
88075
+ } catch (error) {
88076
+ console.error("Failed to export agent:", error);
88077
+ }
88078
+ };
87100
88079
  reactExports.useEffect(() => {
87101
88080
  if (initialAgent) {
87102
88081
  if (agentId !== prevAgentIdRef.current) {
@@ -87133,33 +88112,69 @@ const AgentsPage = () => {
87133
88112
  subtitle: "View, configure and manage your AI agents from a central dashboard"
87134
88113
  }
87135
88114
  ),
87136
- selectedAgent && /* @__PURE__ */ jsxRuntimeExports.jsx(Box, { sx: { position: "absolute", top: 0, right: 0 }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
87137
- Tooltip,
88115
+ selectedAgent && /* @__PURE__ */ jsxRuntimeExports.jsxs(
88116
+ Box,
87138
88117
  {
87139
- title: `Chat with ${selectedAgent?.name || "this Agent"}`,
87140
- children: /* @__PURE__ */ jsxRuntimeExports.jsx(
87141
- Button,
87142
- {
87143
- variant: "outlined",
87144
- color: "primary",
87145
- size: "small",
87146
- startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faComment }),
87147
- onClick: () => navigate(`/chat/${selectedAgent.id}`),
87148
- sx: {
87149
- borderRadius: 2,
87150
- textTransform: "none",
87151
- fontWeight: 500,
87152
- transition: "all 0.2s ease-in-out",
87153
- "&:hover": {
87154
- backgroundColor: alpha("#38C96A", 0.08),
87155
- transform: "translateY(-1px)"
87156
- }
87157
- },
87158
- children: "Chat"
87159
- }
87160
- )
88118
+ sx: {
88119
+ position: "absolute",
88120
+ top: 0,
88121
+ right: 0,
88122
+ display: "flex",
88123
+ gap: 1
88124
+ },
88125
+ children: [
88126
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Tooltip, { title: "Export Agent", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
88127
+ Button,
88128
+ {
88129
+ variant: "outlined",
88130
+ color: "primary",
88131
+ size: "small",
88132
+ startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faFileExport }),
88133
+ onClick: handleExportAgent,
88134
+ disabled: exportAgentMutation.isPending,
88135
+ sx: {
88136
+ borderRadius: 2,
88137
+ textTransform: "none",
88138
+ fontWeight: 500,
88139
+ transition: "all 0.2s ease-in-out",
88140
+ "&:hover": {
88141
+ backgroundColor: alpha("#38C96A", 0.08),
88142
+ transform: "translateY(-1px)"
88143
+ }
88144
+ },
88145
+ children: "Export"
88146
+ }
88147
+ ) }),
88148
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
88149
+ Tooltip,
88150
+ {
88151
+ title: `Chat with ${selectedAgent?.name || "this Agent"}`,
88152
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
88153
+ Button,
88154
+ {
88155
+ variant: "outlined",
88156
+ color: "primary",
88157
+ size: "small",
88158
+ startIcon: /* @__PURE__ */ jsxRuntimeExports.jsx(FontAwesomeIcon, { icon: faComment }),
88159
+ onClick: () => navigate(`/chat/${selectedAgent.id}`),
88160
+ sx: {
88161
+ borderRadius: 2,
88162
+ textTransform: "none",
88163
+ fontWeight: 500,
88164
+ transition: "all 0.2s ease-in-out",
88165
+ "&:hover": {
88166
+ backgroundColor: alpha("#38C96A", 0.08),
88167
+ transform: "translateY(-1px)"
88168
+ }
88169
+ },
88170
+ children: "Chat"
88171
+ }
88172
+ )
88173
+ }
88174
+ )
88175
+ ]
87161
88176
  }
87162
- ) })
88177
+ )
87163
88178
  ] }),
87164
88179
  /* @__PURE__ */ jsxRuntimeExports.jsx(AgentDetailsContainer, { sx: { opacity: selectedAgent ? 1 : 0.7 }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
87165
88180
  AgentSettings,
@@ -90231,6 +91246,26 @@ const UserProfileSidebar = ({
90231
91246
  ) : null
90232
91247
  ] });
90233
91248
  };
91249
+ const useUiPreferencesStore = create$1()(
91250
+ persist(
91251
+ (set) => ({
91252
+ isSidebarCollapsed: false,
91253
+ toggleSidebar: () => {
91254
+ set((state) => ({
91255
+ isSidebarCollapsed: !state.isSidebarCollapsed
91256
+ }));
91257
+ },
91258
+ setSidebarCollapsed: (collapsed) => {
91259
+ set({
91260
+ isSidebarCollapsed: collapsed
91261
+ });
91262
+ }
91263
+ }),
91264
+ {
91265
+ name: "ui-preferences-storage"
91266
+ }
91267
+ )
91268
+ );
90234
91269
  const StyledDrawer = styled$1(Drawer, {
90235
91270
  shouldForwardProp: (prop) => prop !== "width"
90236
91271
  })(({ theme: theme2, width }) => ({
@@ -90346,12 +91381,10 @@ const ToggleButton = styled$1(IconButton)(() => ({
90346
91381
  }
90347
91382
  }));
90348
91383
  const SidebarNavigation = () => {
90349
- const [expanded, setExpanded] = reactExports.useState(true);
90350
91384
  const navigate = useNavigate();
90351
91385
  const currentView = useCurrentView();
90352
- const toggleSidebar = () => {
90353
- setExpanded(!expanded);
90354
- };
91386
+ const { isSidebarCollapsed, toggleSidebar } = useUiPreferencesStore();
91387
+ const expanded = !isSidebarCollapsed;
90355
91388
  const navItems = [
90356
91389
  {
90357
91390
  icon: faCode,
@@ -90426,6 +91459,7 @@ const SidebarNavigation = () => {
90426
91459
  onClick: toggleSidebar,
90427
91460
  size: "small",
90428
91461
  title: expanded ? "Collapse sidebar" : "Expand sidebar",
91462
+ "aria-label": expanded ? "Collapse sidebar" : "Expand sidebar",
90429
91463
  children: /* @__PURE__ */ jsxRuntimeExports.jsx(
90430
91464
  FontAwesomeIcon,
90431
91465
  {