@axiom-lattice/react-sdk 2.1.12 → 2.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -136,7 +136,7 @@ function useChat(threadId, options = {}) {
136
136
  stopStreamingRef.current = null;
137
137
  }
138
138
  const { input, command, streaming = true } = data;
139
- const { message: message4, files, ...rest } = input || {};
139
+ const { message: message5, files, ...rest } = input || {};
140
140
  setState((prev) => ({
141
141
  ...prev,
142
142
  isLoading: true,
@@ -145,7 +145,7 @@ function useChat(threadId, options = {}) {
145
145
  }));
146
146
  const userMessage = {
147
147
  id: Date.now().toString(),
148
- content: message4 || command?.resume?.message || "",
148
+ content: message5 || command?.resume?.message || "",
149
149
  files,
150
150
  role: "human"
151
151
  };
@@ -483,7 +483,7 @@ function AgentThreadProvider({
483
483
  stopStreamingRef.current = null;
484
484
  }
485
485
  const { input, command, streaming = true } = data;
486
- const { message: message4, files, ...rest } = input || {};
486
+ const { message: message5, files, ...rest } = input || {};
487
487
  setState((prev) => ({
488
488
  ...prev,
489
489
  isLoading: true,
@@ -491,7 +491,7 @@ function AgentThreadProvider({
491
491
  }));
492
492
  const userMessage = {
493
493
  id: Date.now().toString(),
494
- content: message4 || command?.resume?.message || "",
494
+ content: message5 || command?.resume?.message || "",
495
495
  files,
496
496
  role: "human"
497
497
  };
@@ -1562,11 +1562,11 @@ var ConfirmFeedback = ({
1562
1562
  data,
1563
1563
  interactive = true
1564
1564
  }) => {
1565
- const { message: message4, type, config, feedback, options } = data ?? {};
1565
+ const { message: message5, type, config, feedback, options } = data ?? {};
1566
1566
  const { sendMessage } = useAgentChat();
1567
1567
  const [clicked, setClicked] = useState8(false);
1568
1568
  return /* @__PURE__ */ jsxs2(Space, { direction: "vertical", style: { width: "100%" }, children: [
1569
- /* @__PURE__ */ jsx7(MDResponse, { content: message4 }),
1569
+ /* @__PURE__ */ jsx7(MDResponse, { content: message5 }),
1570
1570
  options ? /* @__PURE__ */ jsx7(Space, { style: { justifyContent: "flex-end", width: "100%" }, children: options?.map((option) => /* @__PURE__ */ jsx7(
1571
1571
  Button,
1572
1572
  {
@@ -1648,7 +1648,7 @@ import { DownloadOutlined, ExpandAltOutlined } from "@ant-design/icons";
1648
1648
  import { jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
1649
1649
  var { Text: Text2 } = Typography2;
1650
1650
  var GenericDataTable = ({ data, interactive = true, default_open_in_side_app = true }) => {
1651
- const { dataSource, message: message4 } = data ?? {};
1651
+ const { dataSource, message: message5 } = data ?? {};
1652
1652
  const [expandedRowKeys, setExpandedRowKeys] = useState9([]);
1653
1653
  const { openSideApp } = useChatUIContext();
1654
1654
  const processedData = dataSource?.map((item, index) => ({
@@ -1732,7 +1732,7 @@ var GenericDataTable = ({ data, interactive = true, default_open_in_side_app = t
1732
1732
  {
1733
1733
  size: "small",
1734
1734
  title: () => /* @__PURE__ */ jsxs3(Flex, { justify: "space-between", align: "center", children: [
1735
- /* @__PURE__ */ jsx8(Space2, { children: /* @__PURE__ */ jsx8(Text2, { strong: true, style: { fontSize: 16 }, children: message4 || "" }) }),
1735
+ /* @__PURE__ */ jsx8(Space2, { children: /* @__PURE__ */ jsx8(Text2, { strong: true, style: { fontSize: 16 }, children: message5 || "" }) }),
1736
1736
  /* @__PURE__ */ jsxs3(Space2, { children: [
1737
1737
  /* @__PURE__ */ jsx8(
1738
1738
  Button2,
@@ -1753,8 +1753,8 @@ var GenericDataTable = ({ data, interactive = true, default_open_in_side_app = t
1753
1753
  onClick: () => {
1754
1754
  openSideApp({
1755
1755
  component_key: "generic_data_table",
1756
- message: message4 || "",
1757
- data: { dataSource, message: message4 }
1756
+ message: message5 || "",
1757
+ data: { dataSource, message: message5 }
1758
1758
  });
1759
1759
  },
1760
1760
  children: [
@@ -2689,7 +2689,7 @@ var AttachmentsCard = ({
2689
2689
  columns = 1,
2690
2690
  showDownloadButton = false
2691
2691
  }) => {
2692
- const { Text: Text11 } = Typography7;
2692
+ const { Text: Text12 } = Typography7;
2693
2693
  const [showAll, setShowAll] = useState11(false);
2694
2694
  const { openSideApp } = useChatUIContext();
2695
2695
  const getStyles = () => {
@@ -2764,7 +2764,7 @@ var AttachmentsCard = ({
2764
2764
  );
2765
2765
  };
2766
2766
  const renderFileDescription = (item) => /* @__PURE__ */ jsx16(Space7, { direction: "vertical", size: size === "small" ? 2 : 4, children: /* @__PURE__ */ jsx16(Space7, { children: /* @__PURE__ */ jsx16(
2767
- Text11,
2767
+ Text12,
2768
2768
  {
2769
2769
  type: "secondary",
2770
2770
  style: {
@@ -2836,7 +2836,7 @@ var AttachmentsCard = ({
2836
2836
  }
2837
2837
  ),
2838
2838
  item.files && /* @__PURE__ */ jsxs9("div", { style: { paddingLeft: "12px" }, children: [
2839
- /* @__PURE__ */ jsxs9(Text11, { type: "secondary", style: { fontSize: "12px" }, children: [
2839
+ /* @__PURE__ */ jsxs9(Text12, { type: "secondary", style: { fontSize: "12px" }, children: [
2840
2840
  "\u5305\u542B\u6587\u4EF6(",
2841
2841
  item.files.length,
2842
2842
  ")"
@@ -3508,7 +3508,7 @@ import {
3508
3508
  } from "react";
3509
3509
  import { jsx as jsx23 } from "react/jsx-runtime";
3510
3510
  var LazyBubble = ({
3511
- message: message4,
3511
+ message: message5,
3512
3512
  renderContent,
3513
3513
  autoLoadRightPanel
3514
3514
  }) => {
@@ -3539,10 +3539,10 @@ var LazyBubble = ({
3539
3539
  autoLoadRightPanel?.();
3540
3540
  }, []);
3541
3541
  const getPlaceholder = () => {
3542
- const estimatedHeight = message4.content ? Math.min(100, message4.content.length / 5) : 100;
3542
+ const estimatedHeight = message5.content ? Math.min(100, message5.content.length / 5) : 100;
3543
3543
  return /* @__PURE__ */ jsx23("div", { style: { height: `${estimatedHeight}px`, minHeight: "50px" } });
3544
3544
  };
3545
- return /* @__PURE__ */ jsx23(ErrorBoundary, { children: /* @__PURE__ */ jsx23("div", { ref, style: { width: "100%" }, children: isVisible || wasEverVisible ? renderContent(message4) : getPlaceholder() }) });
3545
+ return /* @__PURE__ */ jsx23(ErrorBoundary, { children: /* @__PURE__ */ jsx23("div", { ref, style: { width: "100%" }, children: isVisible || wasEverVisible ? renderContent(message5) : getPlaceholder() }) });
3546
3546
  };
3547
3547
  var MemoizedBubbleList = memo(
3548
3548
  ({
@@ -3573,8 +3573,8 @@ var MessageList = ({
3573
3573
  messageLengthRef.current = messages?.length;
3574
3574
  }
3575
3575
  }, [messages?.length]);
3576
- const renderContent = useCallback7((message4) => {
3577
- const { content } = message4;
3576
+ const renderContent = useCallback7((message5) => {
3577
+ const { content } = message5;
3578
3578
  try {
3579
3579
  const json = JSON.parse(content);
3580
3580
  if (json.action && json.message) {
@@ -3582,7 +3582,7 @@ var MessageList = ({
3582
3582
  }
3583
3583
  } catch (error) {
3584
3584
  }
3585
- const tool_calls_md = message4.tool_calls?.map((tool_call) => {
3585
+ const tool_calls_md = message5.tool_calls?.map((tool_call) => {
3586
3586
  return `\`\`\`tool_call
3587
3587
  ${JSON.stringify(tool_call)}
3588
3588
  \`\`\``;
@@ -3591,17 +3591,17 @@ ${JSON.stringify(tool_call)}
3591
3591
  return /* @__PURE__ */ jsx23(Space10, { direction: "vertical", style: { width: "100%" }, children: /* @__PURE__ */ jsx23(MDResponse, { content: content_md }) });
3592
3592
  }, []);
3593
3593
  const items = useMemo4(
3594
- () => messages.map((message4, index) => ({
3595
- key: message4.id,
3596
- role: message4.role,
3594
+ () => messages.map((message5, index) => ({
3595
+ key: message5.id,
3596
+ role: message5.role,
3597
3597
  typing: false,
3598
3598
  content: /* @__PURE__ */ jsx23(
3599
3599
  LazyBubble,
3600
3600
  {
3601
- message: message4,
3601
+ message: message5,
3602
3602
  renderContent,
3603
3603
  autoLoadRightPanel: () => {
3604
- const { content, role: role2 } = message4;
3604
+ const { content, role: role2 } = message5;
3605
3605
  const isNewAddedMessage = messageLengthRef.current > 1 && messageLengthRef.current + 1 === messages.length;
3606
3606
  if (index === messages.length - 1 && isNewAddedMessage && role2 === "ai") {
3607
3607
  try {
@@ -4449,6 +4449,9 @@ var LatticeChatShellContext = createContext4({
4449
4449
  updateConfigValue: () => {
4450
4450
  },
4451
4451
  resetConfig: () => {
4452
+ },
4453
+ settingsModalOpen: false,
4454
+ setSettingsModalOpen: () => {
4452
4455
  }
4453
4456
  });
4454
4457
  var LatticeChatShellContextProvider = ({
@@ -4472,6 +4475,7 @@ var LatticeChatShellContextProvider = ({
4472
4475
  return { ...DEFAULT_CONFIG, ...initialConfig };
4473
4476
  }, [persistToLocalStorage, localStorageKey, initialConfig]);
4474
4477
  const [config, setConfig] = useState17(loadInitialConfig);
4478
+ const [settingsModalOpen, setSettingsModalOpen] = useState17(false);
4475
4479
  const saveToLocalStorage = useCallback8(
4476
4480
  (newConfig) => {
4477
4481
  if (persistToLocalStorage && typeof window !== "undefined") {
@@ -4516,7 +4520,9 @@ var LatticeChatShellContextProvider = ({
4516
4520
  config,
4517
4521
  updateConfig,
4518
4522
  updateConfigValue,
4519
- resetConfig
4523
+ resetConfig,
4524
+ settingsModalOpen,
4525
+ setSettingsModalOpen
4520
4526
  },
4521
4527
  children
4522
4528
  }
@@ -4741,22 +4747,30 @@ var AssistantContextProvider = ({
4741
4747
  }
4742
4748
  }, [autoLoad, listAssistants]);
4743
4749
  useEffect12(() => {
4744
- if (state.assistants.length > 0 && !state.currentAssistant) {
4745
- if (initialAssistantId) {
4746
- const assistant = state.assistants.find(
4747
- (a) => a.id === initialAssistantId
4748
- );
4749
- if (assistant) {
4750
+ if (state.assistants.length > 0) {
4751
+ const isCurrentAssistantValid = state.currentAssistant && state.assistants.some((a) => a.id === state.currentAssistant?.id);
4752
+ if (!isCurrentAssistantValid) {
4753
+ if (initialAssistantId) {
4754
+ const assistant = state.assistants.find(
4755
+ (a) => a.id === initialAssistantId
4756
+ );
4757
+ if (assistant) {
4758
+ setState((prev) => ({
4759
+ ...prev,
4760
+ currentAssistant: assistant
4761
+ }));
4762
+ } else {
4763
+ setState((prev) => ({
4764
+ ...prev,
4765
+ currentAssistant: prev.assistants[0]
4766
+ }));
4767
+ }
4768
+ } else {
4750
4769
  setState((prev) => ({
4751
4770
  ...prev,
4752
- currentAssistant: assistant
4771
+ currentAssistant: prev.assistants[0]
4753
4772
  }));
4754
4773
  }
4755
- } else {
4756
- setState((prev) => ({
4757
- ...prev,
4758
- currentAssistant: prev.assistants[0]
4759
- }));
4760
4774
  }
4761
4775
  }
4762
4776
  }, [initialAssistantId, state.assistants, state.currentAssistant]);
@@ -5188,7 +5202,7 @@ var AssistantList = () => {
5188
5202
 
5189
5203
  // src/components/Chat/ChatSidebar.tsx
5190
5204
  import { createStyles as createStyles10 } from "antd-style";
5191
- import { jsx as jsx37, jsxs as jsxs19 } from "react/jsx-runtime";
5205
+ import { Fragment as Fragment5, jsx as jsx37, jsxs as jsxs19 } from "react/jsx-runtime";
5192
5206
  var useStyles3 = createStyles10(({ token, css }) => ({
5193
5207
  sidebar: css`
5194
5208
  display: flex;
@@ -5307,13 +5321,15 @@ var ChatSidebar = ({
5307
5321
  }) => {
5308
5322
  const { styles } = useStyles3();
5309
5323
  const { setMenuCollapsed, menuCollapsed } = useChatUIContext();
5324
+ const { setSettingsModalOpen } = useLatticeChatShellContext();
5310
5325
  const handleToggleCollapse = () => {
5311
5326
  setMenuCollapsed(!menuCollapsed);
5312
5327
  };
5313
5328
  const handleSettingsClick = () => {
5329
+ setSettingsModalOpen(true);
5314
5330
  onSettingsClick?.();
5315
5331
  };
5316
- return /* @__PURE__ */ jsxs19("div", { className: styles.sidebar, children: [
5332
+ return /* @__PURE__ */ jsx37(Fragment5, { children: /* @__PURE__ */ jsxs19("div", { className: styles.sidebar, children: [
5317
5333
  !menuCollapsed && /* @__PURE__ */ jsxs19("div", { className: styles.content, children: [
5318
5334
  /* @__PURE__ */ jsxs19("div", { className: styles.section, children: [
5319
5335
  /* @__PURE__ */ jsx37("div", { className: styles.sectionTitle, children: "Assistants" }),
@@ -5347,7 +5363,7 @@ var ChatSidebar = ({
5347
5363
  }
5348
5364
  )
5349
5365
  ] })
5350
- ] });
5366
+ ] }) });
5351
5367
  };
5352
5368
 
5353
5369
  // src/components/Chat/LatticeChatView.tsx
@@ -5381,10 +5397,1370 @@ var LatticeChatView = (props) => {
5381
5397
  ) : null;
5382
5398
  };
5383
5399
 
5384
- // src/components/Chat/LatticeChatShell.tsx
5385
- import { jsx as jsx39 } from "react/jsx-runtime";
5386
- var LatticeChatShell = (props) => {
5387
- return /* @__PURE__ */ jsx39(LatticeChatShellContextProvider, { ...props, children: /* @__PURE__ */ jsx39(AssistantContextProvider, { autoLoad: true, children: /* @__PURE__ */ jsx39(ConversationContextProvider, { children: /* @__PURE__ */ jsx39(LatticeChatView, {}) }) }) });
5400
+ // src/components/Chat/SettingsModal.tsx
5401
+ import { useState as useState20, useEffect as useEffect14, useRef as useRef11 } from "react";
5402
+ import {
5403
+ Modal,
5404
+ Input,
5405
+ Button as Button12,
5406
+ message as message4,
5407
+ Typography as Typography13,
5408
+ Alert as Alert3,
5409
+ Select,
5410
+ Switch,
5411
+ Space as Space13,
5412
+ Tabs as Tabs2,
5413
+ Drawer
5414
+ } from "antd";
5415
+ import {
5416
+ SaveOutlined,
5417
+ EnvironmentOutlined,
5418
+ ReloadOutlined as ReloadOutlined2,
5419
+ CheckCircleOutlined as CheckCircleOutlined4,
5420
+ ApiOutlined,
5421
+ LinkOutlined,
5422
+ CheckCircleFilled,
5423
+ CloseCircleFilled,
5424
+ PlusOutlined,
5425
+ CloudServerOutlined
5426
+ } from "@ant-design/icons";
5427
+ import { createStyles as createStyles11 } from "antd-style";
5428
+ import { Fragment as Fragment6, jsx as jsx39, jsxs as jsxs20 } from "react/jsx-runtime";
5429
+ var { Text: Text11, Title: Title2 } = Typography13;
5430
+ var { TextArea } = Input;
5431
+ var useStyles4 = createStyles11(({ token, css }) => ({
5432
+ // settingsModal: css`
5433
+ // .ant-modal {
5434
+ // max-width: 100vw !important;
5435
+ // width: 100vw !important;
5436
+ // margin: 0 !important;
5437
+ // top: 0 !important;
5438
+ // padding-bottom: 0 !important;
5439
+ // }
5440
+ // .ant-modal-content {
5441
+ // padding: 0;
5442
+ // height: 100vh;
5443
+ // max-height: 100vh;
5444
+ // border-radius: 0;
5445
+ // overflow: hidden;
5446
+ // width: 100%;
5447
+ // }
5448
+ // .ant-modal-body {
5449
+ // padding: 0;
5450
+ // height: 100%;
5451
+ // display: flex;
5452
+ // overflow: hidden;
5453
+ // width: 100%;
5454
+ // }
5455
+ // `,
5456
+ tabsContainer: css`
5457
+ height: 100vh;
5458
+ display: flex;
5459
+ flex-direction: column;
5460
+ overflow: hidden;
5461
+
5462
+ .ant-tabs {
5463
+ height: 100%;
5464
+ display: flex;
5465
+ flex-direction: column;
5466
+ }
5467
+
5468
+ .ant-tabs-content-holder {
5469
+ flex: 1;
5470
+ overflow: hidden;
5471
+ }
5472
+
5473
+ .ant-tabs-content {
5474
+ height: 100%;
5475
+ }
5476
+
5477
+ .ant-tabs-tabpane {
5478
+ height: 100%;
5479
+ overflow: hidden;
5480
+ }
5481
+
5482
+ .ant-tabs-nav {
5483
+ margin: 0;
5484
+ padding: 0 ${token.paddingLG}px;
5485
+ background: ${token.colorBgContainer};
5486
+ border-bottom: 1px solid ${token.colorBorder};
5487
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
5488
+ }
5489
+
5490
+ .ant-tabs-tab {
5491
+ padding: ${token.paddingMD}px ${token.paddingLG}px;
5492
+ margin: ${token.paddingSM}px ${token.marginXS}px 0 0;
5493
+ border-radius: ${token.borderRadius}px ${token.borderRadius}px 0 0;
5494
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
5495
+
5496
+ &:hover {
5497
+ background: ${token.colorFillTertiary};
5498
+ }
5499
+
5500
+ &.ant-tabs-tab-active {
5501
+ background: ${token.colorBgContainer};
5502
+ border-bottom-color: ${token.colorBgContainer};
5503
+ }
5504
+ }
5505
+ `,
5506
+ tabContent: css`
5507
+ height: 100%;
5508
+ display: flex;
5509
+ flex-direction: column;
5510
+ overflow: hidden;
5511
+ background: linear-gradient(
5512
+ 135deg,
5513
+ ${token.colorBgLayout} 0%,
5514
+ ${token.colorFillQuaternary} 100%
5515
+ );
5516
+ `,
5517
+ sidebar: css`
5518
+ width: 280px;
5519
+ background: linear-gradient(
5520
+ 180deg,
5521
+ ${token.colorBgContainer} 0%,
5522
+ ${token.colorFillQuaternary} 100%
5523
+ );
5524
+ border-right: 1px solid ${token.colorBorder};
5525
+ display: flex;
5526
+ flex-direction: column;
5527
+ overflow-y: auto;
5528
+ flex-shrink: 0;
5529
+ box-shadow: 2px 0 8px rgba(0, 0, 0, 0.04);
5530
+
5531
+ /* Custom scrollbar */
5532
+ &::-webkit-scrollbar {
5533
+ width: 8px;
5534
+ }
5535
+
5536
+ &::-webkit-scrollbar-track {
5537
+ background: transparent;
5538
+ }
5539
+
5540
+ &::-webkit-scrollbar-thumb {
5541
+ background: ${token.colorBorder};
5542
+ border-radius: 4px;
5543
+ transition: background 0.2s;
5544
+
5545
+ &:hover {
5546
+ background: ${token.colorBorderSecondary};
5547
+ }
5548
+ }
5549
+ `,
5550
+ sidebarHeader: css`
5551
+ padding: ${token.paddingXL}px ${token.paddingLG}px;
5552
+ border-bottom: 1px solid ${token.colorBorder};
5553
+ background: linear-gradient(
5554
+ 135deg,
5555
+ ${token.colorPrimaryBg} 0%,
5556
+ ${token.colorBgContainer} 100%
5557
+ );
5558
+ position: sticky;
5559
+ top: 0;
5560
+ z-index: 10;
5561
+ backdrop-filter: blur(10px);
5562
+ `,
5563
+ sidebarTitle: css`
5564
+ font-size: ${token.fontSizeXL}px;
5565
+ font-weight: 700;
5566
+ background: linear-gradient(
5567
+ 135deg,
5568
+ ${token.colorPrimary} 0%,
5569
+ ${token.colorPrimaryHover} 100%
5570
+ );
5571
+ -webkit-background-clip: text;
5572
+ -webkit-text-fill-color: transparent;
5573
+ background-clip: text;
5574
+ margin: 0;
5575
+ letter-spacing: -0.5px;
5576
+ `,
5577
+ menuItem: css`
5578
+ padding: ${token.paddingMD}px ${token.paddingLG}px;
5579
+ margin: ${token.marginXS}px ${token.paddingSM}px;
5580
+ cursor: pointer;
5581
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
5582
+ border-radius: ${token.borderRadiusLG}px;
5583
+ display: flex;
5584
+ align-items: center;
5585
+ gap: ${token.marginMD}px;
5586
+ position: relative;
5587
+ overflow: hidden;
5588
+
5589
+ &::before {
5590
+ content: "";
5591
+ position: absolute;
5592
+ left: 0;
5593
+ top: 0;
5594
+ bottom: 0;
5595
+ width: 3px;
5596
+ background: ${token.colorPrimary};
5597
+ transform: scaleY(0);
5598
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
5599
+ border-radius: 0 2px 2px 0;
5600
+ }
5601
+
5602
+ &:hover {
5603
+ background: ${token.colorFillTertiary};
5604
+ transform: translateX(4px);
5605
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
5606
+ }
5607
+
5608
+ &.active {
5609
+ background: linear-gradient(
5610
+ 135deg,
5611
+ ${token.colorPrimaryBg} 0%,
5612
+ ${token.colorFillTertiary} 100%
5613
+ );
5614
+ color: ${token.colorPrimary};
5615
+ box-shadow: 0 4px 12px rgba(24, 144, 255, 0.15);
5616
+ transform: translateX(4px);
5617
+
5618
+ &::before {
5619
+ transform: scaleY(1);
5620
+ }
5621
+
5622
+ .menuItemIcon {
5623
+ transform: scale(1.1);
5624
+ }
5625
+ }
5626
+ `,
5627
+ menuItemIcon: css`
5628
+ font-size: 18px;
5629
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
5630
+ display: flex;
5631
+ align-items: center;
5632
+ justify-content: center;
5633
+ width: 24px;
5634
+ height: 24px;
5635
+ `,
5636
+ menuItemText: css`
5637
+ font-size: ${token.fontSize}px;
5638
+ font-weight: 600;
5639
+ letter-spacing: 0.2px;
5640
+ `,
5641
+ content: css`
5642
+ flex: 1;
5643
+ display: flex;
5644
+ flex-direction: column;
5645
+ overflow: hidden;
5646
+ width: 100%;
5647
+ min-width: 0;
5648
+ `,
5649
+ contentHeader: css`
5650
+ padding: ${token.paddingLG}px ${token.paddingXL * 2}px;
5651
+ background: ${token.colorBgContainer};
5652
+ border-bottom: 1px solid ${token.colorBorder};
5653
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
5654
+ position: sticky;
5655
+ top: 0;
5656
+ z-index: 5;
5657
+ backdrop-filter: blur(10px);
5658
+ display: flex;
5659
+ justify-content: space-between;
5660
+ align-items: center;
5661
+ gap: ${token.marginLG}px;
5662
+ `,
5663
+ contentHeaderLeft: css`
5664
+ flex: 1;
5665
+ `,
5666
+ contentHeaderRight: css`
5667
+ display: flex;
5668
+ gap: ${token.marginMD}px;
5669
+ flex-shrink: 0;
5670
+ `,
5671
+ contentTitle: css`
5672
+ font-size: ${token.fontSizeHeading3}px;
5673
+ font-weight: 700;
5674
+ color: ${token.colorTextHeading};
5675
+ margin: 0 0 ${token.marginSM}px 0;
5676
+ letter-spacing: -0.5px;
5677
+ `,
5678
+ contentDescription: css`
5679
+ color: ${token.colorTextSecondary};
5680
+ font-size: ${token.fontSize}px;
5681
+ margin: 0;
5682
+ line-height: 1.6;
5683
+ `,
5684
+ contentBody: css`
5685
+ flex: 1;
5686
+ overflow-y: auto;
5687
+ padding: ${token.paddingXL * 2}px ${token.paddingXL * 2}px;
5688
+ background: transparent;
5689
+
5690
+ /* Custom scrollbar */
5691
+ &::-webkit-scrollbar {
5692
+ width: 8px;
5693
+ }
5694
+
5695
+ &::-webkit-scrollbar-track {
5696
+ background: transparent;
5697
+ }
5698
+
5699
+ &::-webkit-scrollbar-thumb {
5700
+ background: ${token.colorBorder};
5701
+ border-radius: 4px;
5702
+ transition: background 0.2s;
5703
+
5704
+ &:hover {
5705
+ background: ${token.colorBorderSecondary};
5706
+ }
5707
+ }
5708
+ `,
5709
+ formContainer: css`
5710
+ width: 100%;
5711
+ max-width: 100%;
5712
+ `,
5713
+ formLabel: css`
5714
+ font-weight: 600;
5715
+ color: ${token.colorTextHeading};
5716
+ margin-bottom: ${token.marginMD}px;
5717
+ display: block;
5718
+ font-size: ${token.fontSize}px;
5719
+ `,
5720
+ formDescription: css`
5721
+ color: ${token.colorTextSecondary};
5722
+ font-size: ${token.fontSizeSM}px;
5723
+ margin-top: ${token.marginSM}px;
5724
+ line-height: 1.6;
5725
+ `,
5726
+ card: css`
5727
+ background: ${token.colorBgContainer};
5728
+ border: 1px solid ${token.colorBorder};
5729
+ border-radius: ${token.borderRadiusLG}px;
5730
+ padding: ${token.paddingXL}px;
5731
+ margin-bottom: ${token.marginLG}px;
5732
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
5733
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
5734
+
5735
+ &:hover {
5736
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
5737
+ transform: translateY(-2px);
5738
+ border-color: ${token.colorPrimary};
5739
+ }
5740
+ `,
5741
+ alertCard: css`
5742
+ border-radius: ${token.borderRadiusLG}px;
5743
+ margin-bottom: ${token.marginLG}px;
5744
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
5745
+ border: 1px solid ${token.colorBorder};
5746
+ `,
5747
+ textArea: css`
5748
+ border-radius: ${token.borderRadius}px;
5749
+ border: 1px solid ${token.colorBorder};
5750
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
5751
+
5752
+ &:hover {
5753
+ border-color: ${token.colorPrimaryHover};
5754
+ }
5755
+
5756
+ &:focus {
5757
+ border-color: ${token.colorPrimary};
5758
+ box-shadow: 0 0 0 2px ${token.colorPrimaryBg};
5759
+ }
5760
+ `,
5761
+ connectionStatus: css`
5762
+ display: flex;
5763
+ align-items: center;
5764
+ gap: ${token.marginXS}px;
5765
+ margin-left: ${token.marginSM}px;
5766
+ `,
5767
+ addServerModal: css`
5768
+ .ant-modal-body {
5769
+ padding: ${token.paddingXL}px;
5770
+ }
5771
+ `
5772
+ }));
5773
+ var SETTINGS_MENU_ITEMS = [
5774
+ {
5775
+ key: "environment",
5776
+ label: "Environment Variables",
5777
+ icon: /* @__PURE__ */ jsx39(EnvironmentOutlined, {})
5778
+ },
5779
+ {
5780
+ key: "models",
5781
+ label: "Model Configuration",
5782
+ icon: /* @__PURE__ */ jsx39(ApiOutlined, {})
5783
+ }
5784
+ ];
5785
+ var SettingsModal = ({
5786
+ open,
5787
+ onClose
5788
+ }) => {
5789
+ const { styles } = useStyles4();
5790
+ const { config: shellConfig, updateConfigValue } = useLatticeChatShellContext();
5791
+ const [connections, setConnections] = useState20(() => {
5792
+ if (typeof window !== "undefined") {
5793
+ try {
5794
+ const stored = localStorage.getItem("lattice_server_connections");
5795
+ if (stored) {
5796
+ const parsed = JSON.parse(stored);
5797
+ return parsed;
5798
+ }
5799
+ } catch (error) {
5800
+ console.warn("Failed to load connections from localStorage:", error);
5801
+ }
5802
+ }
5803
+ if (shellConfig.baseURL) {
5804
+ return [
5805
+ {
5806
+ id: "default",
5807
+ name: "Default",
5808
+ url: shellConfig.baseURL
5809
+ }
5810
+ ];
5811
+ }
5812
+ return [];
5813
+ });
5814
+ const [serverConfigs, setServerConfigs] = useState20({});
5815
+ const connectionsRef = useRef11(connections);
5816
+ useEffect14(() => {
5817
+ connectionsRef.current = connections;
5818
+ }, [connections]);
5819
+ const [activeTabKey, setActiveTabKey] = useState20(
5820
+ connections.length > 0 ? connections[0].id : ""
5821
+ );
5822
+ const [activeMenu, setActiveMenu] = useState20("environment");
5823
+ const [loading, setLoading] = useState20(false);
5824
+ const [showAddServerModal, setShowAddServerModal] = useState20(false);
5825
+ const [newServerUrl, setNewServerUrl] = useState20("");
5826
+ const [newServerName, setNewServerName] = useState20("");
5827
+ const [newServerApiKey, setNewServerApiKey] = useState20("");
5828
+ const [addingServer, setAddingServer] = useState20(false);
5829
+ const saveConnections = (newConnections) => {
5830
+ setConnections(newConnections);
5831
+ if (typeof window !== "undefined") {
5832
+ try {
5833
+ localStorage.setItem(
5834
+ "lattice_server_connections",
5835
+ JSON.stringify(newConnections)
5836
+ );
5837
+ } catch (error) {
5838
+ console.warn("Failed to save connections to localStorage:", error);
5839
+ }
5840
+ }
5841
+ };
5842
+ const initializeServerConfig = (serverId) => {
5843
+ if (!serverConfigs[serverId]) {
5844
+ setServerConfigs((prev) => ({
5845
+ ...prev,
5846
+ [serverId]: {
5847
+ envText: "",
5848
+ models: [
5849
+ {
5850
+ key: "",
5851
+ model: "",
5852
+ provider: "openai",
5853
+ streaming: false,
5854
+ apiKey: "",
5855
+ baseURL: ""
5856
+ }
5857
+ ]
5858
+ }
5859
+ }));
5860
+ }
5861
+ };
5862
+ const checkConnection = async (serverId) => {
5863
+ const connection = connectionsRef.current.find((c) => c.id === serverId);
5864
+ if (!connection) return;
5865
+ const url = connection.url;
5866
+ if (!url) {
5867
+ updateConnectionStatus(serverId, { connected: false });
5868
+ return;
5869
+ }
5870
+ try {
5871
+ updateConnectionStatus(serverId, { connecting: true, error: "" });
5872
+ const controller = new AbortController();
5873
+ const timeoutId = setTimeout(() => controller.abort(), 5e3);
5874
+ const headers = {};
5875
+ if (connection.apiKey) {
5876
+ headers["Authorization"] = `Bearer ${connection.apiKey}`;
5877
+ }
5878
+ const response = await fetch(`${url}/api/config`, {
5879
+ method: "GET",
5880
+ signal: controller.signal,
5881
+ headers
5882
+ });
5883
+ clearTimeout(timeoutId);
5884
+ if (response.ok) {
5885
+ setConnections(
5886
+ (prev) => prev.map(
5887
+ (conn) => conn.id === serverId ? { ...conn, connected: true, connecting: false, error: "" } : { ...conn, connected: false, connecting: false }
5888
+ )
5889
+ );
5890
+ if (url !== shellConfig.baseURL) {
5891
+ updateConfigValue("baseURL", url);
5892
+ }
5893
+ } else {
5894
+ updateConnectionStatus(serverId, {
5895
+ connected: false,
5896
+ connecting: false,
5897
+ error: "Server returned an error"
5898
+ });
5899
+ }
5900
+ } catch (error) {
5901
+ if (error.name === "AbortError") {
5902
+ updateConnectionStatus(serverId, {
5903
+ connected: false,
5904
+ connecting: false,
5905
+ error: "Connection timeout"
5906
+ });
5907
+ } else {
5908
+ updateConnectionStatus(serverId, {
5909
+ connected: false,
5910
+ connecting: false,
5911
+ error: error.message || "Failed to connect to server"
5912
+ });
5913
+ }
5914
+ }
5915
+ };
5916
+ const updateConnectionStatus = (serverId, updates) => {
5917
+ setConnections(
5918
+ (prev) => prev.map(
5919
+ (conn) => conn.id === serverId ? { ...conn, ...updates } : conn
5920
+ )
5921
+ );
5922
+ };
5923
+ const loadCurrentConfig = async (serverId) => {
5924
+ const connection = connectionsRef.current.find((c) => c.id === serverId);
5925
+ if (!connection || !connection.connected) return;
5926
+ const url = connection.url;
5927
+ if (!url) return;
5928
+ try {
5929
+ const headers = {};
5930
+ if (connection.apiKey) {
5931
+ headers["Authorization"] = `Bearer ${connection.apiKey}`;
5932
+ }
5933
+ const response = await fetch(`${url}/api/config`, {
5934
+ headers
5935
+ });
5936
+ if (response.ok) {
5937
+ const data = await response.json();
5938
+ if (data.success && data.data) {
5939
+ const lines = [];
5940
+ const configData = data.data;
5941
+ if (configData.port !== void 0) {
5942
+ lines.push(`PORT=${configData.port}`);
5943
+ }
5944
+ if (configData.queueServiceType) {
5945
+ lines.push(`QUEUE_SERVICE_TYPE=${configData.queueServiceType}`);
5946
+ }
5947
+ if (configData.redisUrl) {
5948
+ lines.push(`REDIS_URL=${configData.redisUrl}`);
5949
+ }
5950
+ if (configData.redisPassword) {
5951
+ lines.push(`REDIS_PASSWORD=`);
5952
+ }
5953
+ if (configData.queueName) {
5954
+ lines.push(`QUEUE_NAME=${configData.queueName}`);
5955
+ }
5956
+ setServerConfigs((prev) => ({
5957
+ ...prev,
5958
+ [serverId]: {
5959
+ ...prev[serverId],
5960
+ envText: lines.join("\n")
5961
+ }
5962
+ }));
5963
+ }
5964
+ }
5965
+ } catch (error) {
5966
+ console.error("Failed to load configuration:", error);
5967
+ message4.error("Failed to load current configuration");
5968
+ }
5969
+ };
5970
+ const loadModelsConfig = async (serverId) => {
5971
+ const connection = connectionsRef.current.find((c) => c.id === serverId);
5972
+ if (!connection || !connection.connected) return;
5973
+ const url = connection.url;
5974
+ if (!url) return;
5975
+ try {
5976
+ const headers = {};
5977
+ if (connection.apiKey) {
5978
+ headers["Authorization"] = `Bearer ${connection.apiKey}`;
5979
+ }
5980
+ const response = await fetch(`${url}/api/models`, {
5981
+ headers
5982
+ });
5983
+ if (response.ok) {
5984
+ const data = await response.json();
5985
+ if (data.success && data.data && Array.isArray(data.data)) {
5986
+ if (data.data.length > 0) {
5987
+ setServerConfigs((prev) => ({
5988
+ ...prev,
5989
+ [serverId]: {
5990
+ ...prev[serverId],
5991
+ models: data.data
5992
+ }
5993
+ }));
5994
+ } else {
5995
+ setServerConfigs((prev) => ({
5996
+ ...prev,
5997
+ [serverId]: {
5998
+ ...prev[serverId],
5999
+ models: [
6000
+ {
6001
+ key: "",
6002
+ model: "",
6003
+ provider: "openai",
6004
+ streaming: false,
6005
+ apiKey: "",
6006
+ baseURL: ""
6007
+ }
6008
+ ]
6009
+ }
6010
+ }));
6011
+ }
6012
+ }
6013
+ }
6014
+ } catch (error) {
6015
+ console.error("Failed to load models configuration:", error);
6016
+ }
6017
+ };
6018
+ useEffect14(() => {
6019
+ if (open && activeTabKey) {
6020
+ initializeServerConfig(activeTabKey);
6021
+ const connection = connections.find((c) => c.id === activeTabKey);
6022
+ if (connection && !connection.connected && !connection.connecting) {
6023
+ checkConnection(activeTabKey);
6024
+ }
6025
+ }
6026
+ }, [open, activeTabKey]);
6027
+ useEffect14(() => {
6028
+ if (open && activeTabKey) {
6029
+ const connection = connections.find((c) => c.id === activeTabKey);
6030
+ if (connection?.connected) {
6031
+ if (activeMenu === "environment") {
6032
+ loadCurrentConfig(activeTabKey);
6033
+ } else if (activeMenu === "models") {
6034
+ loadModelsConfig(activeTabKey);
6035
+ }
6036
+ }
6037
+ }
6038
+ }, [open, activeTabKey, activeMenu]);
6039
+ const handleAddServer = async () => {
6040
+ if (!newServerUrl.trim()) {
6041
+ message4.error("Please enter a server URL");
6042
+ return;
6043
+ }
6044
+ let normalizedUrl = newServerUrl.trim();
6045
+ if (!normalizedUrl.startsWith("http://") && !normalizedUrl.startsWith("https://")) {
6046
+ normalizedUrl = `http://${normalizedUrl}`;
6047
+ }
6048
+ const serverName = newServerName.trim() || normalizedUrl.replace(/^https?:\/\//, "");
6049
+ const newConnection = {
6050
+ id: `conn_${Date.now()}`,
6051
+ name: serverName,
6052
+ url: normalizedUrl,
6053
+ apiKey: newServerApiKey.trim() || void 0,
6054
+ connected: false
6055
+ };
6056
+ setAddingServer(true);
6057
+ const newConnections = [...connections, newConnection];
6058
+ saveConnections(newConnections);
6059
+ setActiveTabKey(newConnection.id);
6060
+ initializeServerConfig(newConnection.id);
6061
+ await checkConnection(newConnection.id);
6062
+ setAddingServer(false);
6063
+ setShowAddServerModal(false);
6064
+ setNewServerUrl("");
6065
+ setNewServerName("");
6066
+ setNewServerApiKey("");
6067
+ message4.success("Server added successfully");
6068
+ };
6069
+ const handleDeleteServer = (serverId) => {
6070
+ const newConnections = connections.filter((c) => c.id !== serverId);
6071
+ saveConnections(newConnections);
6072
+ setServerConfigs((prev) => {
6073
+ const newConfigs = { ...prev };
6074
+ delete newConfigs[serverId];
6075
+ return newConfigs;
6076
+ });
6077
+ if (activeTabKey === serverId) {
6078
+ if (newConnections.length > 0) {
6079
+ setActiveTabKey(newConnections[0].id);
6080
+ } else {
6081
+ setActiveTabKey("");
6082
+ }
6083
+ }
6084
+ message4.success("Server deleted");
6085
+ };
6086
+ const handleTabChange = (newTabKey) => {
6087
+ setConnections(
6088
+ (prev) => prev.map(
6089
+ (conn) => conn.id === newTabKey ? conn : { ...conn, connected: false, connecting: false }
6090
+ // Disconnect others
6091
+ )
6092
+ );
6093
+ setActiveTabKey(newTabKey);
6094
+ };
6095
+ const handleSave = async () => {
6096
+ const connection = connections.find((c) => c.id === activeTabKey);
6097
+ if (!connection || !connection.connected) {
6098
+ message4.error("Please connect to a server first");
6099
+ return;
6100
+ }
6101
+ const url = connection.url;
6102
+ if (!url) {
6103
+ message4.error("Please connect to a server first");
6104
+ return;
6105
+ }
6106
+ try {
6107
+ setLoading(true);
6108
+ const config = serverConfigs[activeTabKey];
6109
+ if (activeMenu === "environment") {
6110
+ const configObj = {};
6111
+ const lines = config.envText.split("\n");
6112
+ for (const line of lines) {
6113
+ const trimmedLine = line.trim();
6114
+ if (!trimmedLine || trimmedLine.startsWith("#")) {
6115
+ continue;
6116
+ }
6117
+ const equalIndex = trimmedLine.indexOf("=");
6118
+ if (equalIndex === -1) {
6119
+ continue;
6120
+ }
6121
+ const key = trimmedLine.substring(0, equalIndex).trim();
6122
+ const value = trimmedLine.substring(equalIndex + 1).trim();
6123
+ if (!key) {
6124
+ continue;
6125
+ }
6126
+ const upperKey = key.toUpperCase();
6127
+ if (upperKey === "PORT") {
6128
+ if (value) {
6129
+ configObj.port = Number(value);
6130
+ }
6131
+ } else if (upperKey === "QUEUE_SERVICE_TYPE") {
6132
+ if (value) {
6133
+ configObj.queueServiceType = value;
6134
+ }
6135
+ } else if (upperKey === "REDIS_URL") {
6136
+ if (value) {
6137
+ configObj.redisUrl = value;
6138
+ }
6139
+ } else if (upperKey === "REDIS_PASSWORD") {
6140
+ if (value) {
6141
+ configObj.redisPassword = value;
6142
+ }
6143
+ } else if (upperKey === "QUEUE_NAME") {
6144
+ if (value) {
6145
+ configObj.queueName = value;
6146
+ }
6147
+ } else {
6148
+ if (value) {
6149
+ configObj[key] = value;
6150
+ }
6151
+ }
6152
+ }
6153
+ const headers = {
6154
+ "Content-Type": "application/json"
6155
+ };
6156
+ if (connection.apiKey) {
6157
+ headers["Authorization"] = `Bearer ${connection.apiKey}`;
6158
+ }
6159
+ const response = await fetch(`${url}/api/config`, {
6160
+ method: "PUT",
6161
+ headers,
6162
+ body: JSON.stringify({ config: configObj })
6163
+ });
6164
+ const data = await response.json();
6165
+ if (response.ok && data.success) {
6166
+ if (data.requiresRestart && data.requiresRestart.length > 0) {
6167
+ message4.warning(
6168
+ `Configuration saved. Please restart the server for ${data.requiresRestart.join(
6169
+ ", "
6170
+ )} to take effect.`,
6171
+ 5
6172
+ );
6173
+ } else {
6174
+ message4.success("Configuration saved and applied successfully");
6175
+ }
6176
+ if (data.warnings && data.warnings.length > 0) {
6177
+ data.warnings.forEach((warning) => {
6178
+ message4.warning(warning, 5);
6179
+ });
6180
+ }
6181
+ onClose();
6182
+ } else {
6183
+ message4.error(data.error || "Failed to save configuration");
6184
+ }
6185
+ } else if (activeMenu === "models") {
6186
+ const validModels = config.models.filter(
6187
+ (m) => m.key && m.model && m.provider
6188
+ );
6189
+ const headers = {
6190
+ "Content-Type": "application/json"
6191
+ };
6192
+ if (connection.apiKey) {
6193
+ headers["Authorization"] = `Bearer ${connection.apiKey}`;
6194
+ }
6195
+ const response = await fetch(`${url}/api/models`, {
6196
+ method: "PUT",
6197
+ headers,
6198
+ body: JSON.stringify({ models: validModels })
6199
+ });
6200
+ const data = await response.json();
6201
+ if (response.ok && data.success) {
6202
+ message4.success(
6203
+ "Model configuration saved and registered successfully"
6204
+ );
6205
+ onClose();
6206
+ } else {
6207
+ message4.error(data.error || "Failed to save model configuration");
6208
+ }
6209
+ }
6210
+ } catch (error) {
6211
+ console.error("Failed to save configuration:", error);
6212
+ message4.error(error.message || "Failed to save configuration");
6213
+ } finally {
6214
+ setLoading(false);
6215
+ }
6216
+ };
6217
+ const renderEnvironmentSettings = (serverId) => {
6218
+ const config = serverConfigs[serverId] || { envText: "", models: [] };
6219
+ const setEnvText = (text) => {
6220
+ setServerConfigs((prev) => ({
6221
+ ...prev,
6222
+ [serverId]: {
6223
+ ...prev[serverId],
6224
+ envText: text
6225
+ }
6226
+ }));
6227
+ };
6228
+ return /* @__PURE__ */ jsxs20("div", { className: styles.formContainer, children: [
6229
+ /* @__PURE__ */ jsx39(
6230
+ Alert3,
6231
+ {
6232
+ message: "Configuration Effect",
6233
+ description: /* @__PURE__ */ jsxs20("div", { children: [
6234
+ /* @__PURE__ */ jsxs20("div", { style: { marginBottom: 8 }, children: [
6235
+ /* @__PURE__ */ jsx39(
6236
+ CheckCircleOutlined4,
6237
+ {
6238
+ style: { color: "#52c41a", marginRight: 8 }
6239
+ }
6240
+ ),
6241
+ /* @__PURE__ */ jsx39("strong", { children: "Immediately effective:" }),
6242
+ " QUEUE_SERVICE_TYPE, REDIS_URL, REDIS_PASSWORD, QUEUE_NAME"
6243
+ ] }),
6244
+ /* @__PURE__ */ jsxs20("div", { children: [
6245
+ /* @__PURE__ */ jsx39(ReloadOutlined2, { style: { color: "#faad14", marginRight: 8 } }),
6246
+ /* @__PURE__ */ jsx39("strong", { children: "Requires restart:" }),
6247
+ " PORT (server must be restarted to change port)"
6248
+ ] })
6249
+ ] }),
6250
+ type: "info",
6251
+ showIcon: true,
6252
+ className: styles.alertCard
6253
+ }
6254
+ ),
6255
+ /* @__PURE__ */ jsx39("div", { style: { marginBottom: 24 }, children: /* @__PURE__ */ jsx39(Text11, { type: "secondary", style: { fontSize: 14, lineHeight: 1.6 }, children: "Configure environment variables in .env format (key=value). One variable per line. Leave password fields empty to keep current values." }) }),
6256
+ /* @__PURE__ */ jsx39(
6257
+ TextArea,
6258
+ {
6259
+ value: config.envText,
6260
+ onChange: (e) => setEnvText(e.target.value),
6261
+ placeholder: `PORT=4001
6262
+ QUEUE_SERVICE_TYPE=redis
6263
+ REDIS_URL=redis://localhost:6379
6264
+ REDIS_PASSWORD=
6265
+ QUEUE_NAME=tasks`,
6266
+ rows: 18,
6267
+ className: styles.textArea,
6268
+ style: {
6269
+ fontFamily: "SF Mono, Monaco, Inconsolata, Roboto Mono, monospace",
6270
+ fontSize: 13,
6271
+ padding: "16px",
6272
+ lineHeight: 1.6
6273
+ }
6274
+ }
6275
+ )
6276
+ ] });
6277
+ };
6278
+ const renderModelSettings = (serverId) => {
6279
+ const config = serverConfigs[serverId] || {
6280
+ envText: "",
6281
+ models: [
6282
+ {
6283
+ key: "",
6284
+ model: "",
6285
+ provider: "openai",
6286
+ streaming: false,
6287
+ apiKey: "",
6288
+ baseURL: ""
6289
+ }
6290
+ ]
6291
+ };
6292
+ const handleModelChange = (index, field, value) => {
6293
+ const newModels = [...config.models];
6294
+ newModels[index] = { ...newModels[index], [field]: value };
6295
+ setServerConfigs((prev) => ({
6296
+ ...prev,
6297
+ [serverId]: {
6298
+ ...prev[serverId],
6299
+ models: newModels
6300
+ }
6301
+ }));
6302
+ };
6303
+ const handleAddModel = () => {
6304
+ setServerConfigs((prev) => ({
6305
+ ...prev,
6306
+ [serverId]: {
6307
+ ...prev[serverId],
6308
+ models: [
6309
+ ...config.models,
6310
+ {
6311
+ key: "",
6312
+ model: "",
6313
+ provider: "openai",
6314
+ streaming: false,
6315
+ apiKey: "",
6316
+ baseURL: ""
6317
+ }
6318
+ ]
6319
+ }
6320
+ }));
6321
+ };
6322
+ const handleRemoveModel = (index) => {
6323
+ if (config.models.length > 1) {
6324
+ setServerConfigs((prev) => ({
6325
+ ...prev,
6326
+ [serverId]: {
6327
+ ...prev[serverId],
6328
+ models: config.models.filter((_, i) => i !== index)
6329
+ }
6330
+ }));
6331
+ }
6332
+ };
6333
+ return /* @__PURE__ */ jsxs20("div", { className: styles.formContainer, children: [
6334
+ /* @__PURE__ */ jsx39("div", { style: { marginBottom: 32 }, children: /* @__PURE__ */ jsx39(Text11, { type: "secondary", style: { fontSize: 14, lineHeight: 1.6 }, children: "Configure model lattices. Each model will be registered with the provided key and can be used by agents." }) }),
6335
+ config.models.map((model, index) => /* @__PURE__ */ jsxs20("div", { className: styles.card, children: [
6336
+ /* @__PURE__ */ jsxs20(
6337
+ "div",
6338
+ {
6339
+ style: {
6340
+ display: "flex",
6341
+ justifyContent: "space-between",
6342
+ alignItems: "center",
6343
+ marginBottom: 24,
6344
+ paddingBottom: 20,
6345
+ borderBottom: "1px solid rgba(0, 0, 0, 0.06)"
6346
+ },
6347
+ children: [
6348
+ /* @__PURE__ */ jsxs20("div", { children: [
6349
+ /* @__PURE__ */ jsxs20(Text11, { strong: true, style: { fontSize: 16 }, children: [
6350
+ "Model ",
6351
+ index + 1
6352
+ ] }),
6353
+ model.key && /* @__PURE__ */ jsxs20(
6354
+ Text11,
6355
+ {
6356
+ type: "secondary",
6357
+ style: { marginLeft: 8, fontSize: 12 },
6358
+ children: [
6359
+ "(",
6360
+ model.key,
6361
+ ")"
6362
+ ]
6363
+ }
6364
+ )
6365
+ ] }),
6366
+ config.models.length > 1 && /* @__PURE__ */ jsx39(
6367
+ Button12,
6368
+ {
6369
+ type: "text",
6370
+ danger: true,
6371
+ size: "small",
6372
+ onClick: () => handleRemoveModel(index),
6373
+ style: {
6374
+ borderRadius: 6,
6375
+ transition: "all 0.2s"
6376
+ },
6377
+ children: "Remove"
6378
+ }
6379
+ )
6380
+ ]
6381
+ }
6382
+ ),
6383
+ /* @__PURE__ */ jsxs20(Space13, { direction: "vertical", style: { width: "100%" }, size: "large", children: [
6384
+ /* @__PURE__ */ jsxs20("div", { children: [
6385
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formLabel, children: "Key *" }),
6386
+ /* @__PURE__ */ jsx39(
6387
+ Input,
6388
+ {
6389
+ placeholder: "e.g., default, gpt-4, claude",
6390
+ value: model.key,
6391
+ onChange: (e) => handleModelChange(index, "key", e.target.value),
6392
+ style: { height: 40 }
6393
+ }
6394
+ ),
6395
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formDescription, children: "Unique identifier for this model" })
6396
+ ] }),
6397
+ /* @__PURE__ */ jsxs20("div", { children: [
6398
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formLabel, children: "Provider *" }),
6399
+ /* @__PURE__ */ jsx39(
6400
+ Select,
6401
+ {
6402
+ style: { width: "100%", height: 40 },
6403
+ value: model.provider,
6404
+ onChange: (value) => handleModelChange(index, "provider", value),
6405
+ options: [
6406
+ { label: "OpenAI", value: "openai" },
6407
+ { label: "Azure", value: "azure" },
6408
+ { label: "DeepSeek", value: "deepseek" },
6409
+ { label: "SiliconCloud", value: "siliconcloud" },
6410
+ { label: "VolcEngine", value: "volcengine" }
6411
+ ]
6412
+ }
6413
+ )
6414
+ ] }),
6415
+ /* @__PURE__ */ jsxs20("div", { children: [
6416
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formLabel, children: "Model Name *" }),
6417
+ /* @__PURE__ */ jsx39(
6418
+ Input,
6419
+ {
6420
+ placeholder: "e.g., gpt-4, claude-3-opus, kimi-k2-250905",
6421
+ value: model.model,
6422
+ onChange: (e) => handleModelChange(index, "model", e.target.value),
6423
+ style: { height: 40 }
6424
+ }
6425
+ )
6426
+ ] }),
6427
+ /* @__PURE__ */ jsxs20("div", { children: [
6428
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formLabel, children: "API Key" }),
6429
+ /* @__PURE__ */ jsx39(
6430
+ Input.Password,
6431
+ {
6432
+ placeholder: "Enter your API key",
6433
+ value: model.apiKey,
6434
+ onChange: (e) => handleModelChange(index, "apiKey", e.target.value),
6435
+ style: { height: 40 }
6436
+ }
6437
+ ),
6438
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formDescription, children: "API key for the model provider. Leave empty to use environment variable." })
6439
+ ] }),
6440
+ /* @__PURE__ */ jsxs20("div", { children: [
6441
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formLabel, children: "Base URL" }),
6442
+ /* @__PURE__ */ jsx39(
6443
+ Input,
6444
+ {
6445
+ placeholder: "e.g., https://api.openai.com/v1",
6446
+ value: model.baseURL,
6447
+ onChange: (e) => handleModelChange(index, "baseURL", e.target.value),
6448
+ style: { height: 40 }
6449
+ }
6450
+ ),
6451
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formDescription, children: "Optional custom base URL for the API" })
6452
+ ] }),
6453
+ /* @__PURE__ */ jsx39("div", { children: /* @__PURE__ */ jsxs20(Space13, { children: [
6454
+ /* @__PURE__ */ jsx39(
6455
+ Switch,
6456
+ {
6457
+ checked: model.streaming,
6458
+ onChange: (checked) => handleModelChange(index, "streaming", checked)
6459
+ }
6460
+ ),
6461
+ /* @__PURE__ */ jsx39(Text11, { children: "Enable Streaming" })
6462
+ ] }) }),
6463
+ /* @__PURE__ */ jsxs20("div", { style: { display: "flex", gap: 20 }, children: [
6464
+ /* @__PURE__ */ jsxs20("div", { style: { flex: 1 }, children: [
6465
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formLabel, children: "Max Tokens" }),
6466
+ /* @__PURE__ */ jsx39(
6467
+ Input,
6468
+ {
6469
+ type: "number",
6470
+ placeholder: "e.g., 4096",
6471
+ value: model.maxTokens,
6472
+ onChange: (e) => handleModelChange(
6473
+ index,
6474
+ "maxTokens",
6475
+ e.target.value ? Number(e.target.value) : void 0
6476
+ ),
6477
+ style: { height: 40 }
6478
+ }
6479
+ )
6480
+ ] }),
6481
+ /* @__PURE__ */ jsxs20("div", { style: { flex: 1 }, children: [
6482
+ /* @__PURE__ */ jsx39(Text11, { className: styles.formLabel, children: "Temperature" }),
6483
+ /* @__PURE__ */ jsx39(
6484
+ Input,
6485
+ {
6486
+ type: "number",
6487
+ step: "0.1",
6488
+ placeholder: "e.g., 0.7",
6489
+ value: model.temperature,
6490
+ onChange: (e) => handleModelChange(
6491
+ index,
6492
+ "temperature",
6493
+ e.target.value ? Number(e.target.value) : void 0
6494
+ ),
6495
+ style: { height: 40 }
6496
+ }
6497
+ )
6498
+ ] })
6499
+ ] })
6500
+ ] })
6501
+ ] }, index)),
6502
+ /* @__PURE__ */ jsx39(
6503
+ Button12,
6504
+ {
6505
+ type: "dashed",
6506
+ onClick: handleAddModel,
6507
+ block: true,
6508
+ size: "large",
6509
+ style: { marginTop: 24, height: 48 },
6510
+ children: "+ Add Model"
6511
+ }
6512
+ )
6513
+ ] });
6514
+ };
6515
+ const renderContent = (serverId) => {
6516
+ switch (activeMenu) {
6517
+ case "environment":
6518
+ return renderEnvironmentSettings(serverId);
6519
+ case "models":
6520
+ return renderModelSettings(serverId);
6521
+ default:
6522
+ return null;
6523
+ }
6524
+ };
6525
+ const activeMenuItem = SETTINGS_MENU_ITEMS.find(
6526
+ (item) => item.key === activeMenu
6527
+ );
6528
+ const currentConnection = connections.find((c) => c.id === activeTabKey);
6529
+ const renderTabLabel = (connection) => {
6530
+ return /* @__PURE__ */ jsxs20("div", { style: { display: "flex", alignItems: "center" }, children: [
6531
+ /* @__PURE__ */ jsx39(
6532
+ CloudServerOutlined,
6533
+ {
6534
+ style: {
6535
+ marginRight: 8,
6536
+ color: connection.connected ? "#52c41a" : connection.connecting ? "#1890ff" : "#d9d9d9"
6537
+ }
6538
+ }
6539
+ ),
6540
+ /* @__PURE__ */ jsx39("span", { children: connection.name }),
6541
+ connection.connected && /* @__PURE__ */ jsx39(
6542
+ CheckCircleFilled,
6543
+ {
6544
+ style: { color: "#52c41a", fontSize: 12, marginLeft: 8 }
6545
+ }
6546
+ ),
6547
+ connection.error && !connection.connecting && /* @__PURE__ */ jsx39(
6548
+ CloseCircleFilled,
6549
+ {
6550
+ style: { color: "#ff4d4f", fontSize: 12, marginLeft: 8 }
6551
+ }
6552
+ )
6553
+ ] });
6554
+ };
6555
+ const tabItems = connections.map((connection) => ({
6556
+ key: connection.id,
6557
+ label: renderTabLabel(connection),
6558
+ children: /* @__PURE__ */ jsx39("div", { className: styles.tabContent, children: connection.connected ? /* @__PURE__ */ jsx39(Fragment6, { children: /* @__PURE__ */ jsxs20("div", { style: { display: "flex", height: "100%" }, children: [
6559
+ /* @__PURE__ */ jsx39("div", { className: styles.sidebar, children: SETTINGS_MENU_ITEMS.map((item) => /* @__PURE__ */ jsxs20(
6560
+ "div",
6561
+ {
6562
+ className: `${styles.menuItem} ${activeMenu === item.key ? "active" : ""}`,
6563
+ onClick: () => setActiveMenu(item.key),
6564
+ children: [
6565
+ /* @__PURE__ */ jsx39("span", { className: styles.menuItemIcon, children: item.icon }),
6566
+ /* @__PURE__ */ jsx39("span", { className: styles.menuItemText, children: item.label })
6567
+ ]
6568
+ },
6569
+ item.key
6570
+ )) }),
6571
+ /* @__PURE__ */ jsxs20("div", { className: styles.content, children: [
6572
+ /* @__PURE__ */ jsxs20("div", { className: styles.contentHeader, children: [
6573
+ /* @__PURE__ */ jsxs20("div", { className: styles.contentHeaderLeft, children: [
6574
+ /* @__PURE__ */ jsx39(Title2, { level: 3, className: styles.contentTitle, children: activeMenuItem?.label }),
6575
+ /* @__PURE__ */ jsxs20(Text11, { className: styles.contentDescription, children: [
6576
+ activeMenu === "environment" && "Manage environment variables for the gateway server",
6577
+ activeMenu === "models" && "Configure and register model lattices for use by agents"
6578
+ ] })
6579
+ ] }),
6580
+ /* @__PURE__ */ jsxs20("div", { className: styles.contentHeaderRight, children: [
6581
+ /* @__PURE__ */ jsx39(Button12, { onClick: onClose, children: "Cancel" }),
6582
+ /* @__PURE__ */ jsx39(
6583
+ Button12,
6584
+ {
6585
+ type: "primary",
6586
+ icon: /* @__PURE__ */ jsx39(SaveOutlined, {}),
6587
+ onClick: handleSave,
6588
+ loading,
6589
+ children: "Save Configuration"
6590
+ }
6591
+ )
6592
+ ] })
6593
+ ] }),
6594
+ /* @__PURE__ */ jsx39("div", { className: styles.contentBody, children: renderContent(connection.id) })
6595
+ ] })
6596
+ ] }) }) : /* @__PURE__ */ jsx39(
6597
+ "div",
6598
+ {
6599
+ style: {
6600
+ flex: 1,
6601
+ display: "flex",
6602
+ alignItems: "center",
6603
+ justifyContent: "center",
6604
+ flexDirection: "column",
6605
+ gap: 16,
6606
+ padding: 48
6607
+ },
6608
+ children: connection.connecting ? /* @__PURE__ */ jsxs20(Fragment6, { children: [
6609
+ /* @__PURE__ */ jsx39(LinkOutlined, { style: { fontSize: 64, color: "#1890ff" }, spin: true }),
6610
+ /* @__PURE__ */ jsx39(Title2, { level: 4, children: "Connecting..." }),
6611
+ /* @__PURE__ */ jsxs20(Text11, { type: "secondary", style: { textAlign: "center" }, children: [
6612
+ "Connecting to ",
6613
+ connection.url
6614
+ ] })
6615
+ ] }) : /* @__PURE__ */ jsxs20(Fragment6, { children: [
6616
+ /* @__PURE__ */ jsx39(LinkOutlined, { style: { fontSize: 64, color: "#d9d9d9" } }),
6617
+ /* @__PURE__ */ jsx39(Title2, { level: 4, type: "secondary", children: connection.error || "Not Connected" }),
6618
+ /* @__PURE__ */ jsx39(
6619
+ Text11,
6620
+ {
6621
+ type: "secondary",
6622
+ style: { textAlign: "center", maxWidth: 400 },
6623
+ children: connection.error ? `Failed to connect to ${connection.url}. Please check the server URL and try again.` : `Click "Reconnect" to connect to ${connection.url}`
6624
+ }
6625
+ ),
6626
+ /* @__PURE__ */ jsx39(
6627
+ Button12,
6628
+ {
6629
+ type: "primary",
6630
+ icon: /* @__PURE__ */ jsx39(LinkOutlined, {}),
6631
+ onClick: () => checkConnection(connection.id),
6632
+ loading: connection.connecting,
6633
+ style: { marginTop: 16 },
6634
+ children: "Reconnect"
6635
+ }
6636
+ )
6637
+ ] })
6638
+ }
6639
+ ) }),
6640
+ closable: connections.length > 1
6641
+ }));
6642
+ return /* @__PURE__ */ jsxs20(Fragment6, { children: [
6643
+ /* @__PURE__ */ jsx39(
6644
+ Drawer,
6645
+ {
6646
+ open,
6647
+ onClose,
6648
+ footer: null,
6649
+ width: "100%",
6650
+ title: "Settings",
6651
+ children: /* @__PURE__ */ jsx39("div", { children: /* @__PURE__ */ jsx39(
6652
+ Tabs2,
6653
+ {
6654
+ activeKey: activeTabKey,
6655
+ onChange: handleTabChange,
6656
+ type: "editable-card",
6657
+ onEdit: (targetKey, action) => {
6658
+ if (action === "add") {
6659
+ setShowAddServerModal(true);
6660
+ } else if (action === "remove") {
6661
+ handleDeleteServer(targetKey);
6662
+ }
6663
+ },
6664
+ items: tabItems,
6665
+ addIcon: /* @__PURE__ */ jsxs20(
6666
+ "div",
6667
+ {
6668
+ style: {
6669
+ display: "flex",
6670
+ alignItems: "center",
6671
+ gap: 4,
6672
+ padding: "4px 8px"
6673
+ },
6674
+ children: [
6675
+ /* @__PURE__ */ jsx39(PlusOutlined, {}),
6676
+ /* @__PURE__ */ jsx39("span", { children: "Add Server" })
6677
+ ]
6678
+ }
6679
+ )
6680
+ }
6681
+ ) })
6682
+ }
6683
+ ),
6684
+ /* @__PURE__ */ jsx39(
6685
+ Modal,
6686
+ {
6687
+ title: "Add New Server",
6688
+ open: showAddServerModal,
6689
+ onOk: handleAddServer,
6690
+ onCancel: () => {
6691
+ setShowAddServerModal(false);
6692
+ setNewServerUrl("");
6693
+ setNewServerName("");
6694
+ setNewServerApiKey("");
6695
+ },
6696
+ confirmLoading: addingServer,
6697
+ className: styles.addServerModal,
6698
+ children: /* @__PURE__ */ jsxs20(Space13, { direction: "vertical", style: { width: "100%" }, size: "large", children: [
6699
+ /* @__PURE__ */ jsxs20("div", { children: [
6700
+ /* @__PURE__ */ jsx39(Text11, { strong: true, style: { display: "block", marginBottom: 8 }, children: "Server Name" }),
6701
+ /* @__PURE__ */ jsx39(
6702
+ Input,
6703
+ {
6704
+ placeholder: "e.g., Production Server",
6705
+ value: newServerName,
6706
+ onChange: (e) => setNewServerName(e.target.value),
6707
+ onPressEnter: handleAddServer
6708
+ }
6709
+ ),
6710
+ /* @__PURE__ */ jsx39(Text11, { type: "secondary", style: { fontSize: 12, marginTop: 4 }, children: "Optional: Leave empty to use URL as name" })
6711
+ ] }),
6712
+ /* @__PURE__ */ jsxs20("div", { children: [
6713
+ /* @__PURE__ */ jsx39(Text11, { strong: true, style: { display: "block", marginBottom: 8 }, children: "Server URL *" }),
6714
+ /* @__PURE__ */ jsx39(
6715
+ Input,
6716
+ {
6717
+ placeholder: "e.g., http://localhost:4001",
6718
+ value: newServerUrl,
6719
+ onChange: (e) => setNewServerUrl(e.target.value),
6720
+ onPressEnter: handleAddServer
6721
+ }
6722
+ ),
6723
+ /* @__PURE__ */ jsx39(Text11, { type: "secondary", style: { fontSize: 12, marginTop: 4 }, children: "Enter the full URL of the gateway server" })
6724
+ ] }),
6725
+ /* @__PURE__ */ jsxs20("div", { children: [
6726
+ /* @__PURE__ */ jsx39(Text11, { strong: true, style: { display: "block", marginBottom: 8 }, children: "API Key" }),
6727
+ /* @__PURE__ */ jsx39(
6728
+ Input.Password,
6729
+ {
6730
+ placeholder: "Optional: Enter API key for authentication",
6731
+ value: newServerApiKey,
6732
+ onChange: (e) => setNewServerApiKey(e.target.value),
6733
+ onPressEnter: handleAddServer
6734
+ }
6735
+ ),
6736
+ /* @__PURE__ */ jsx39(Text11, { type: "secondary", style: { fontSize: 12, marginTop: 4 }, children: "Optional: API key for server authentication" })
6737
+ ] })
6738
+ ] })
6739
+ }
6740
+ )
6741
+ ] });
6742
+ };
6743
+
6744
+ // src/components/Chat/AgentServerSetting.tsx
6745
+ import { jsx as jsx40 } from "react/jsx-runtime";
6746
+ var AgentServerSetting = () => {
6747
+ const { settingsModalOpen, setSettingsModalOpen } = useLatticeChatShellContext();
6748
+ return /* @__PURE__ */ jsx40(
6749
+ SettingsModal,
6750
+ {
6751
+ open: settingsModalOpen,
6752
+ onClose: () => setSettingsModalOpen(false)
6753
+ }
6754
+ );
6755
+ };
6756
+
6757
+ // src/components/Chat/LatticeChatShell.tsx
6758
+ import { jsx as jsx41, jsxs as jsxs21 } from "react/jsx-runtime";
6759
+ var LatticeChatShell = (props) => {
6760
+ return /* @__PURE__ */ jsxs21(LatticeChatShellContextProvider, { ...props, children: [
6761
+ /* @__PURE__ */ jsx41(AssistantContextProvider, { autoLoad: true, children: /* @__PURE__ */ jsx41(ConversationContextProvider, { children: /* @__PURE__ */ jsx41(LatticeChatView, {}) }) }),
6762
+ /* @__PURE__ */ jsx41(AgentServerSetting, {})
6763
+ ] });
5388
6764
  };
5389
6765
  export {
5390
6766
  AgentConversations,