@bytexbyte/nxtlinq-ai-agent-ui-react-development 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"AgentAssistantContext.d.ts","sourceRoot":"","sources":["../../src/context/AgentAssistantContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8CAA8C,CAAC;AAChF,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAK1F,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/C,MAAM,MAAM,0BAA0B,GAAG,qBAAqB,GAC5D,qBAAqB,GAAG;IACxB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,YAAY,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD,CAAC;AAIF,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,EAAE,EAAE,IAAI,CACN,qBAAqB,EACnB,OAAO,GACP,aAAa,GACb,gBAAgB,GAChB,aAAa,GACb,kBAAkB,GAClB,OAAO,GACP,mBAAmB,GACnB,wBAAwB,CAC3B,CAAC;CACH,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,EAAE,GACH,EAAE,2BAA2B,GAAG,KAAK,CAAC,YAAY,CA4LlD;AAED,wBAAgB,iBAAiB,IAAI,0BAA0B,CAQ9D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAU5D"}
1
+ {"version":3,"file":"AgentAssistantContext.d.ts","sourceRoot":"","sources":["../../src/context/AgentAssistantContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,WAAW,EAAE,MAAM,8CAA8C,CAAC;AACzF,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AACrD,OAAO,KAAK,EAAE,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAK1F,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/C,MAAM,MAAM,0BAA0B,GAAG,qBAAqB,GAC5D,qBAAqB,GAAG;IACxB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,YAAY,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD,CAAC;AAIF,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,EAAE,EAAE,IAAI,CACN,qBAAqB,EACnB,OAAO,GACP,aAAa,GACb,gBAAgB,GAChB,aAAa,GACb,kBAAkB,GAClB,OAAO,GACP,mBAAmB,GACnB,wBAAwB,CAC3B,CAAC;CACH,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,EAAE,GACH,EAAE,2BAA2B,GAAG,KAAK,CAAC,YAAY,CA8MlD;AAED,wBAAgB,iBAAiB,IAAI,0BAA0B,CAQ9D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAU5D"}
@@ -24,7 +24,9 @@ export function AgentAssistantProvider({ children, ui, }) {
24
24
  });
25
25
  const voiceTranscriptApi = useMemo(() => ({
26
26
  getMessages: () => agent.agent.getSnapshot().messages,
27
- setMessages: agent.setMessages,
27
+ updateMessages: (updater) => {
28
+ agent.setMessages(updater(agent.agent.getSnapshot().messages));
29
+ },
28
30
  syncVoiceTurnHistory: agent.syncVoiceTurnHistory,
29
31
  }), [agent.agent, agent.setMessages, agent.syncVoiceTurnHistory]);
30
32
  const { handleTranscript, handleDone, clearVoiceStream } = useVoiceTranscriptMessages(voiceTranscriptApi, interactionMode, voice.voiceSessionId);
@@ -64,6 +66,24 @@ export function AgentAssistantProvider({ children, ui, }) {
64
66
  setInteractionMode,
65
67
  ]);
66
68
  const { wrappedStartVoice, wrappedStopVoice, wrappedInterrupt, isVoiceChannelReady, } = useVoiceConnectOrchestration(agent, voice, interactionMode, micStartsMuted, orchestrationCallbacks);
69
+ // iOS 切換 App 或相機後返回時,若 WebRTC App Channel 已斷開則自動停止語音 session,
70
+ // 避免麥克風圖示顯示活躍但狀態卡在 Idle 的問題。
71
+ useEffect(() => {
72
+ if (typeof document === 'undefined')
73
+ return;
74
+ const handleVisibilityChange = () => {
75
+ if (document.visibilityState !== 'visible')
76
+ return;
77
+ if (voice.voiceSessionId == null)
78
+ return;
79
+ const session = agent.agent.getVoiceSession();
80
+ if (!session?.isAppChannelOpen()) {
81
+ void wrappedStopVoice();
82
+ }
83
+ };
84
+ document.addEventListener('visibilitychange', handleVisibilityChange);
85
+ return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
86
+ }, [voice.voiceSessionId, agent.agent, wrappedStopVoice]);
67
87
  const theme = useMemo(() => ({
68
88
  ...defaultAgentAssistantTheme,
69
89
  ...ui.theme,
@@ -0,0 +1,15 @@
1
+ import * as React from 'react';
2
+ export type ChatBotHeaderProps = {
3
+ mobileLayout: boolean;
4
+ isDragging: boolean;
5
+ onDragStart: (event: React.PointerEvent<HTMLDivElement>) => void;
6
+ isVoiceMode: boolean;
7
+ isVoiceConnecting: boolean;
8
+ onVoiceToggle: () => void;
9
+ piiDisplayMode: 'plain' | 'redacted';
10
+ isAITLoading: boolean;
11
+ onSettingsClick: () => void;
12
+ onClose: () => void;
13
+ };
14
+ export declare const ChatBotHeader: React.FC<ChatBotHeaderProps>;
15
+ //# sourceMappingURL=ChatBotHeader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChatBotHeader.d.ts","sourceRoot":"","sources":["../../../../src/legacy/chatbot/ui/ChatBotHeader.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAU/B,MAAM,MAAM,kBAAkB,GAAG;IAC/B,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,CAAC;IACpB,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,CAAC,cAAc,CAAC,KAAK,IAAI,CAAC;IACjE,WAAW,EAAE,OAAO,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,OAAO,GAAG,UAAU,CAAC;IACrC,YAAY,EAAE,OAAO,CAAC;IACtB,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAqHtD,CAAC"}
@@ -0,0 +1,62 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
+ /** @jsxImportSource @emotion/react */
3
+ import { css } from '@emotion/react';
4
+ import { ModelSelector } from './ModelSelector';
5
+ import { DRAG_CORNER_EXCLUSION_PX, HeaderActions, HeaderLoadingIndicator, PiiBadge, } from './chatBotHeaderParts';
6
+ import { chatHeader, headerTitle } from './styles/isolatedStyles';
7
+ export const ChatBotHeader = ({ mobileLayout, isDragging, onDragStart, isVoiceMode, isVoiceConnecting, onVoiceToggle, piiDisplayMode, isAITLoading, onSettingsClick, onClose, }) => {
8
+ const actions = (_jsx(HeaderActions, { isVoiceMode: isVoiceMode, isVoiceConnecting: isVoiceConnecting, onVoiceToggle: onVoiceToggle, onSettingsClick: onSettingsClick, onClose: onClose }));
9
+ const metaChips = !isVoiceMode ? (_jsxs(_Fragment, { children: [_jsx("div", { css: css `position: relative !important; pointer-events: auto !important;`, children: _jsx(ModelSelector, {}) }), piiDisplayMode === 'redacted' && _jsx(PiiBadge, {}), isAITLoading && _jsx(HeaderLoadingIndicator, {})] })) : null;
10
+ const dragOverlay = (_jsx("div", { css: css `
11
+ position: absolute !important;
12
+ left: ${DRAG_CORNER_EXCLUSION_PX}px !important;
13
+ right: ${DRAG_CORNER_EXCLUSION_PX}px !important;
14
+ top: 0 !important;
15
+ bottom: 0 !important;
16
+ z-index: 1 !important;
17
+ cursor: ${isDragging ? 'grabbing' : 'grab'} !important;
18
+ user-select: none !important;
19
+ `, onPointerDown: onDragStart, title: "Drag to move", "aria-hidden": true }));
20
+ return (_jsxs("div", { css: [chatHeader, css `
21
+ position: relative !important;
22
+ ${mobileLayout ? css `
23
+ padding: 10px 12px !important;
24
+ flex-direction: column !important;
25
+ align-items: stretch !important;
26
+ gap: 8px !important;
27
+ ` : ''}
28
+ `], children: [dragOverlay, mobileLayout ? (_jsxs("div", { css: css `
29
+ position: relative !important;
30
+ z-index: 2 !important;
31
+ display: flex !important;
32
+ flex-direction: column !important;
33
+ gap: 8px !important;
34
+ width: 100% !important;
35
+ `, children: [_jsxs("div", { css: css `
36
+ display: flex !important;
37
+ justify-content: space-between !important;
38
+ align-items: center !important;
39
+ gap: 8px !important;
40
+ pointer-events: none !important;
41
+ `, children: [_jsx("h3", { css: [headerTitle, css `pointer-events: none !important;`], children: "AI Agent" }), actions] }), metaChips && (_jsx("div", { css: css `
42
+ display: flex !important;
43
+ align-items: center !important;
44
+ flex-wrap: wrap !important;
45
+ gap: 8px !important;
46
+ pointer-events: none !important;
47
+ `, children: metaChips }))] })) : (_jsxs("div", { css: css `
48
+ position: relative !important;
49
+ z-index: 2 !important;
50
+ display: flex !important;
51
+ justify-content: space-between !important;
52
+ align-items: center !important;
53
+ width: 100% !important;
54
+ pointer-events: none !important;
55
+ `, children: [_jsxs("div", { css: css `
56
+ display: flex !important;
57
+ align-items: center !important;
58
+ gap: 10px !important;
59
+ min-width: 0 !important;
60
+ pointer-events: none !important;
61
+ `, children: [_jsx("h3", { css: headerTitle, children: "AI Agent" }), metaChips] }), actions] }))] }));
62
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"ChatBotUI.d.ts","sourceRoot":"","sources":["../../../../src/legacy/chatbot/ui/ChatBotUI.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAuG/B,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EA20B7B,CAAC"}
1
+ {"version":3,"file":"ChatBotUI.d.ts","sourceRoot":"","sources":["../../../../src/legacy/chatbot/ui/ChatBotUI.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AA+F/B,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,EAgtB7B,CAAC"}
@@ -4,16 +4,13 @@ import { css } from '@emotion/react';
4
4
  import * as React from 'react';
5
5
  import { useDraggable, useLocalStorage, useResizable, walletTextUtils } from '@bytexbyte/nxtlinq-ai-agent-web-development';
6
6
  import { useChatBot } from '../context/ChatBotContext';
7
- import GraphicEqIcon from '@mui/icons-material/GraphicEq';
7
+ import { ChatBotHeader } from './ChatBotHeader';
8
8
  import { MessageInput } from './MessageInput';
9
9
  import { MessageList } from './MessageList';
10
- import { ModelSelector } from './ModelSelector';
11
10
  import { PermissionForm } from './PermissionForm';
12
11
  import { PresetMessages } from './PresetMessages';
13
12
  import { VoiceModePanel } from './VoiceModePanel';
14
- import { chatHeader, chatWindow, closeButton, errorToast, floatingButton, headerButton, headerTitle, idvBanner, idvBannerText, idvBannerTitle, idvDismissButton, idvVerifyButton, infoToast, loadingSpinner, modalOverlay, resizeHandleNE, resizeHandleNW, resizeHandleSE, resizeHandleSW, sdkContainer, successToast, toastCloseButton, warningToast } from './styles/isolatedStyles';
15
- /** Header drag band inset so it does not overlap corner resize hit areas */
16
- const DRAG_CORNER_EXCLUSION_PX = 20;
13
+ import { chatWindow, errorToast, floatingButton, idvBanner, idvBannerText, idvBannerTitle, idvDismissButton, idvVerifyButton, infoToast, modalOverlay, resizeHandleNE, resizeHandleNW, resizeHandleSE, resizeHandleSW, sdkContainer, successToast, toastCloseButton, warningToast } from './styles/isolatedStyles';
17
14
  const MOBILE_BREAKPOINT = 768;
18
15
  const MOBILE_EDGE_MARGIN = 12;
19
16
  const MOBILE_FAB_POSITION = { right: MOBILE_EDGE_MARGIN, bottom: MOBILE_EDGE_MARGIN };
@@ -526,72 +523,7 @@ export const ChatBotUI = () => {
526
523
  left: ${MOBILE_EDGE_MARGIN}px !important;
527
524
  top: ${MOBILE_EDGE_MARGIN}px !important;
528
525
  ` : ''}
529
- `], children: [!mobileLayout && (_jsxs(_Fragment, { children: [_jsx("div", { css: resizeHandleNW, onPointerDown: handleResizeStart('nw'), title: "Resize", "aria-label": "Resize chat window from top-left" }), _jsx("div", { css: resizeHandleNE, onPointerDown: handleResizeStart('ne'), title: "Resize", "aria-label": "Resize chat window from top-right" }), _jsx("div", { css: resizeHandleSW, onPointerDown: handleResizeStart('sw'), title: "Resize", "aria-label": "Resize chat window from bottom-left" }), _jsx("div", { css: resizeHandleSE, onPointerDown: handleResizeStart('se'), title: "Resize", "aria-label": "Resize chat window from bottom-right" })] })), _jsxs("div", { css: [chatHeader, css `
530
- position: relative !important;
531
- `], children: [_jsx("div", { css: css `
532
- position: absolute !important;
533
- left: ${DRAG_CORNER_EXCLUSION_PX}px !important;
534
- right: ${DRAG_CORNER_EXCLUSION_PX}px !important;
535
- top: 0 !important;
536
- bottom: 0 !important;
537
- z-index: 1 !important;
538
- cursor: ${isDragging ? 'grabbing' : 'grab'} !important;
539
- user-select: none !important;
540
- `, onPointerDown: handleDragStart, title: "Drag to move", "aria-hidden": true }), _jsxs("div", { css: css `
541
- position: relative !important;
542
- z-index: 2 !important;
543
- display: flex !important;
544
- justify-content: space-between !important;
545
- align-items: center !important;
546
- width: 100% !important;
547
- pointer-events: none !important;
548
- `, children: [_jsxs("div", { css: css `
549
- display: flex !important;
550
- align-items: center !important;
551
- gap: 10px !important;
552
- pointer-events: none !important;
553
- `, children: [_jsx("h3", { css: headerTitle, children: "AI Agent" }), !isVoiceMode && (_jsx("div", { css: css `
554
- position: relative !important;
555
- pointer-events: auto !important;
556
- `, children: _jsx(ModelSelector, {}) })), !isVoiceMode && piiDisplayMode === 'redacted' && (_jsxs("div", { css: css `
557
- display: inline-flex !important;
558
- align-items: center !important;
559
- gap: 4px !important;
560
- padding: 2px 8px !important;
561
- background-color: rgba(255, 255, 255, 0.2) !important;
562
- border: 1px solid rgba(255, 255, 255, 0.4) !important;
563
- border-radius: 10px !important;
564
- font-size: 10px !important;
565
- font-weight: 600 !important;
566
- color: #ffffff !important;
567
- white-space: nowrap !important;
568
- line-height: 1.4 !important;
569
- user-select: none !important;
570
- `, title: "PII Protection is active \u2014 sensitive data is automatically anonymized before sending to AI", children: [_jsx("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "#ffffff", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm-2 16l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z" }) }), "PII Protected"] })), isAITLoading && (_jsxs("div", { css: css `
571
- display: flex !important;
572
- align-items: center !important;
573
- gap: 5px !important;
574
- font-size: 12px !important;
575
- opacity: 0.8 !important;
576
- `, children: [_jsx("div", { css: loadingSpinner }), "Loading..."] }))] }), _jsxs("div", { css: css `
577
- display: flex !important;
578
- align-items: center !important;
579
- gap: 10px !important;
580
- pointer-events: auto !important;
581
- `, children: [_jsxs("button", { onClick: () => void ((isVoiceMode || isVoiceConnecting) ? exitVoiceMode() : enterVoiceMode()), css: [headerButton, css `
582
- width: auto !important;
583
- min-width: 82px !important;
584
- padding: 0 10px !important;
585
- gap: 6px !important;
586
- font-size: 12px !important;
587
- font-weight: 600 !important;
588
- line-height: 1 !important;
589
- white-space: nowrap !important;
590
- `], title: isVoiceConnecting
591
- ? 'Cancel voice connection and return to text mode'
592
- : isVoiceMode
593
- ? 'Switch to text mode'
594
- : 'Switch to voice mode', onPointerDown: (e) => e.stopPropagation(), children: [_jsx(GraphicEqIcon, { css: css `font-size: 16px !important; color: #fff !important;` }), (isVoiceMode || isVoiceConnecting) ? 'Text Mode' : 'Voice Mode'] }), _jsx("button", { onClick: handleSettingsClick, css: headerButton, title: "AIT Settings", onPointerDown: (e) => e.stopPropagation(), children: "\u2699\uFE0F" }), _jsx("button", { onClick: handleClose, css: closeButton, onPointerDown: (e) => e.stopPropagation(), title: "Minimize", children: "\u2212" })] })] })] }), showIDVSuggestion && hitAddress && !props.requireWalletIDVVerification && !hasBerifymeToken && !isWalletVerifiedWithBerifyme && (_jsxs("div", { "data-idv-banner": true, css: idvBanner, children: [_jsx("div", { css: css `
526
+ `], children: [!mobileLayout && (_jsxs(_Fragment, { children: [_jsx("div", { css: resizeHandleNW, onPointerDown: handleResizeStart('nw'), title: "Resize", "aria-label": "Resize chat window from top-left" }), _jsx("div", { css: resizeHandleNE, onPointerDown: handleResizeStart('ne'), title: "Resize", "aria-label": "Resize chat window from top-right" }), _jsx("div", { css: resizeHandleSW, onPointerDown: handleResizeStart('sw'), title: "Resize", "aria-label": "Resize chat window from bottom-left" }), _jsx("div", { css: resizeHandleSE, onPointerDown: handleResizeStart('se'), title: "Resize", "aria-label": "Resize chat window from bottom-right" })] })), _jsx(ChatBotHeader, { mobileLayout: mobileLayout, isDragging: isDragging, onDragStart: handleDragStart, isVoiceMode: isVoiceMode, isVoiceConnecting: isVoiceConnecting, onVoiceToggle: () => void ((isVoiceMode || isVoiceConnecting) ? exitVoiceMode() : enterVoiceMode()), piiDisplayMode: piiDisplayMode, isAITLoading: isAITLoading, onSettingsClick: handleSettingsClick, onClose: handleClose }), showIDVSuggestion && hitAddress && !props.requireWalletIDVVerification && !hasBerifymeToken && !isWalletVerifiedWithBerifyme && (_jsxs("div", { "data-idv-banner": true, css: idvBanner, children: [_jsx("div", { css: css `
595
527
  font-size: 20px !important;
596
528
  color: #f39c12 !important;
597
529
  `, children: "\uD83D\uDCA1" }), _jsxs("div", { css: css `flex: 1 !important;`, children: [_jsx("h5", { css: idvBannerTitle, children: walletTextUtils.getWalletText('Recommended: Verify Your Wallet', serviceId) }), _jsx("p", { css: idvBannerText, children: walletTextUtils.getWalletText('While not required, verifying your wallet with Berify.me provides additional security and trust for your AI agent interactions.', serviceId) }), _jsx("button", { onClick: () => onVerifyWallet('berifyme'), css: idvVerifyButton, children: walletTextUtils.getWalletText('Verify Wallet', serviceId) })] }), _jsx("button", { onClick: handleDismissIDV, css: idvDismissButton, title: `Hide for ${Math.floor((props.idvBannerDismissSeconds || 86400) / 3600)} hours`, children: "\u00D7" })] })), !showIDVSuggestion && dismissUntil && timeRemaining && (_jsxs("div", { css: css `
@@ -0,0 +1,15 @@
1
+ import * as React from 'react';
2
+ export declare const DRAG_CORNER_EXCLUSION_PX = 20;
3
+ export declare const piiBadgeStyles: import("@emotion/utils").SerializedStyles;
4
+ export declare const PiiBadge: React.FC;
5
+ type HeaderActionsProps = {
6
+ isVoiceMode: boolean;
7
+ isVoiceConnecting: boolean;
8
+ onVoiceToggle: () => void;
9
+ onSettingsClick: () => void;
10
+ onClose: () => void;
11
+ };
12
+ export declare const HeaderActions: React.FC<HeaderActionsProps>;
13
+ export declare const HeaderLoadingIndicator: React.FC;
14
+ export {};
15
+ //# sourceMappingURL=chatBotHeaderParts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chatBotHeaderParts.d.ts","sourceRoot":"","sources":["../../../../src/legacy/chatbot/ui/chatBotHeaderParts.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAa3C,eAAO,MAAM,cAAc,2CAc1B,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAU5B,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA8CtD,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAW1C,CAAC"}
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
+ /** @jsxImportSource @emotion/react */
3
+ import { css } from '@emotion/react';
4
+ import GraphicEqIcon from '@mui/icons-material/GraphicEq';
5
+ import { closeButton, headerButton, loadingSpinner } from './styles/isolatedStyles';
6
+ export const DRAG_CORNER_EXCLUSION_PX = 20;
7
+ const voiceButtonStyles = css `
8
+ width: auto !important;
9
+ min-width: 82px !important;
10
+ padding: 0 10px !important;
11
+ gap: 6px !important;
12
+ font-size: 12px !important;
13
+ font-weight: 600 !important;
14
+ line-height: 1 !important;
15
+ white-space: nowrap !important;
16
+ `;
17
+ export const piiBadgeStyles = css `
18
+ display: inline-flex !important;
19
+ align-items: center !important;
20
+ gap: 4px !important;
21
+ padding: 2px 8px !important;
22
+ background-color: rgba(255, 255, 255, 0.2) !important;
23
+ border: 1px solid rgba(255, 255, 255, 0.4) !important;
24
+ border-radius: 10px !important;
25
+ font-size: 10px !important;
26
+ font-weight: 600 !important;
27
+ color: #ffffff !important;
28
+ white-space: nowrap !important;
29
+ line-height: 1.4 !important;
30
+ user-select: none !important;
31
+ `;
32
+ export const PiiBadge = () => (_jsxs("div", { css: piiBadgeStyles, title: "PII Protection is active \u2014 sensitive data is automatically anonymized before sending to AI", children: [_jsx("svg", { width: "10", height: "10", viewBox: "0 0 24 24", fill: "#ffffff", xmlns: "http://www.w3.org/2000/svg", children: _jsx("path", { d: "M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4zm-2 16l-4-4 1.41-1.41L10 14.17l6.59-6.59L18 9l-8 8z" }) }), "PII Protected"] }));
33
+ export const HeaderActions = ({ isVoiceMode, isVoiceConnecting, onVoiceToggle, onSettingsClick, onClose, }) => (_jsxs("div", { css: css `
34
+ display: flex !important;
35
+ align-items: center !important;
36
+ gap: 10px !important;
37
+ flex-shrink: 0 !important;
38
+ pointer-events: auto !important;
39
+ `, children: [_jsxs("button", { onClick: onVoiceToggle, css: [headerButton, voiceButtonStyles], title: isVoiceConnecting
40
+ ? 'Cancel voice connection and return to text mode'
41
+ : isVoiceMode
42
+ ? 'Switch to text mode'
43
+ : 'Switch to voice mode', onPointerDown: (e) => e.stopPropagation(), children: [_jsx(GraphicEqIcon, { css: css `font-size: 16px !important; color: #fff !important;` }), (isVoiceMode || isVoiceConnecting) ? 'Text Mode' : 'Voice Mode'] }), _jsx("button", { onClick: onSettingsClick, css: headerButton, title: "AIT Settings", onPointerDown: (e) => e.stopPropagation(), children: "\u2699\uFE0F" }), _jsx("button", { onClick: onClose, css: closeButton, onPointerDown: (e) => e.stopPropagation(), title: "Minimize", children: "\u2212" })] }));
44
+ export const HeaderLoadingIndicator = () => (_jsxs("div", { css: css `
45
+ display: flex !important;
46
+ align-items: center !important;
47
+ gap: 5px !important;
48
+ font-size: 12px !important;
49
+ opacity: 0.8 !important;
50
+ `, children: [_jsx("div", { css: loadingSpinner }), "Loading..."] }));
@@ -1,15 +1,17 @@
1
1
  import type { Message, VoiceDoneEvent, VoiceTranscriptEvent } from '@bytexbyte/nxtlinq-ai-agent-core-development';
2
- import type { InteractionMode } from '../context/AgentAssistantContext';
3
- type VoiceTranscriptAgentApi = {
2
+ type InteractionMode = 'text' | 'voice';
3
+ export type VoiceTranscriptAgentApi = {
4
4
  getMessages: () => Message[];
5
- setMessages: (messages: Message[]) => void;
5
+ updateMessages: (updater: (prev: Message[]) => Message[]) => void;
6
6
  syncVoiceTurnHistory: (options?: {
7
7
  last?: number;
8
8
  }) => Promise<void>;
9
9
  };
10
- export declare function useVoiceTranscriptMessages(api: VoiceTranscriptAgentApi, interactionMode: InteractionMode, voiceSessionId: string | null): {
10
+ export declare function useVoiceTranscriptMessages(api: VoiceTranscriptAgentApi, interactionMode: InteractionMode, voiceSessionId: string | null, getPendingUserText?: () => string): {
11
11
  handleTranscript: (event: VoiceTranscriptEvent) => void;
12
- handleDone: (event: VoiceDoneEvent) => void;
12
+ handleDone: (event: VoiceDoneEvent, options?: {
13
+ pendingUserText?: string;
14
+ }) => void;
13
15
  clearVoiceStream: () => void;
14
16
  };
15
17
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"useVoiceTranscriptMessages.d.ts","sourceRoot":"","sources":["../../src/voice/useVoiceTranscriptMessages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,oBAAoB,EACrB,MAAM,8CAA8C,CAAC;AAGtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,KAAK,uBAAuB,GAAG;IAC7B,WAAW,EAAE,MAAM,OAAO,EAAE,CAAC;IAC7B,WAAW,EAAE,CAAC,QAAQ,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;IAC3C,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE,CAAC;AAWF,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,uBAAuB,EAC5B,eAAe,EAAE,eAAe,EAChC,cAAc,EAAE,MAAM,GAAG,IAAI;8BA6FnB,oBAAoB;wBA4BpB,cAAc;;EAwBzB"}
1
+ {"version":3,"file":"useVoiceTranscriptMessages.d.ts","sourceRoot":"","sources":["../../src/voice/useVoiceTranscriptMessages.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,oBAAoB,EACrB,MAAM,8CAA8C,CAAC;AAKtD,KAAK,eAAe,GAAG,MAAM,GAAG,OAAO,CAAC;AAExC,MAAM,MAAM,uBAAuB,GAAG;IACpC,WAAW,EAAE,MAAM,OAAO,EAAE,CAAC;IAC7B,cAAc,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,IAAI,CAAC;IAClE,oBAAoB,EAAE,CAAC,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE,CAAC;AAWF,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,uBAAuB,EAC5B,eAAe,EAAE,eAAe,EAChC,cAAc,EAAE,MAAM,GAAG,IAAI,EAC7B,kBAAkB,CAAC,EAAE,MAAM,MAAM;8BAiGvB,oBAAoB;wBA4BpB,cAAc,YAAY;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE;;EAgCjE"}
@@ -1,5 +1,6 @@
1
1
  import { mergeStreamingTranscript } from '@bytexbyte/nxtlinq-ai-agent-core-development';
2
2
  import { useCallback, useRef } from 'react';
3
+ import { ensureUserBubbleForVoiceTurn } from './voiceUserBubble';
3
4
  const STREAM_PREFIX = 'voice-stream-';
4
5
  function voiceMeta(sessionId) {
5
6
  return {
@@ -7,104 +8,105 @@ function voiceMeta(sessionId) {
7
8
  voiceSessionId: sessionId ?? undefined,
8
9
  };
9
10
  }
10
- export function useVoiceTranscriptMessages(api, interactionMode, voiceSessionId) {
11
+ export function useVoiceTranscriptMessages(api, interactionMode, voiceSessionId, getPendingUserText) {
11
12
  const streamIdRef = useRef(null);
12
13
  const sessionIdRef = useRef(voiceSessionId);
13
14
  sessionIdRef.current = voiceSessionId;
14
15
  const isVoiceUiActive = useCallback(() => interactionMode === 'voice' && sessionIdRef.current != null, [interactionMode]);
15
16
  const upsertStreaming = useCallback((text) => {
16
- const messages = api.getMessages();
17
- let streamId = streamIdRef.current;
18
- if (!streamId) {
19
- streamId = `${STREAM_PREFIX}${Date.now()}`;
20
- streamIdRef.current = streamId;
21
- }
22
- const idx = messages.findIndex((m) => m.id === streamId);
23
- const partialContent = idx >= 0
24
- ? mergeStreamingTranscript(messages[idx]?.partialContent ?? '', text)
25
- : text;
26
- const meta = voiceMeta(sessionIdRef.current);
27
- if (idx >= 0) {
28
- api.setMessages(messages.map((m, i) => i === idx
29
- ? { ...m, partialContent, isStreaming: true, metadata: { ...m.metadata, ...meta } }
30
- : m));
31
- return;
32
- }
33
- api.setMessages([
34
- ...messages,
35
- {
36
- id: streamId,
37
- role: 'assistant',
38
- content: '',
39
- partialContent,
40
- isStreaming: true,
41
- timestamp: new Date().toISOString(),
42
- metadata: meta,
43
- },
44
- ]);
45
- }, [api]);
17
+ api.updateMessages((prev) => {
18
+ let streamId = streamIdRef.current;
19
+ if (!streamId) {
20
+ streamId = `${STREAM_PREFIX}${Date.now()}`;
21
+ streamIdRef.current = streamId;
22
+ }
23
+ const idx = prev.findIndex((m) => m.id === streamId);
24
+ const partialContent = idx >= 0
25
+ ? mergeStreamingTranscript(prev[idx]?.partialContent ?? '', text)
26
+ : text;
27
+ const meta = voiceMeta(sessionIdRef.current);
28
+ if (idx >= 0) {
29
+ return prev.map((m, i) => i === idx
30
+ ? { ...m, partialContent, isStreaming: true, metadata: { ...m.metadata, ...meta } }
31
+ : m);
32
+ }
33
+ const withUser = ensureUserBubbleForVoiceTurn(prev, getPendingUserText?.() ?? '', undefined, meta);
34
+ return [
35
+ ...withUser,
36
+ {
37
+ id: streamId,
38
+ role: 'assistant',
39
+ content: '',
40
+ partialContent,
41
+ isStreaming: true,
42
+ timestamp: new Date().toISOString(),
43
+ metadata: meta,
44
+ },
45
+ ];
46
+ });
47
+ }, [api, getPendingUserText]);
46
48
  const finalizeAssistant = useCallback((text, messageId) => {
47
49
  const trimmed = text.trim();
48
50
  streamIdRef.current = null;
49
51
  if (!trimmed)
50
52
  return;
51
- const messages = api.getMessages();
52
- const streamIdx = messages.findIndex((m) => m.isStreaming && m.role === 'assistant');
53
- if (streamIdx >= 0) {
54
- api.setMessages(messages.map((m, i) => i === streamIdx
55
- ? {
56
- ...m,
57
- id: messageId ?? m.id,
53
+ api.updateMessages((prev) => {
54
+ const streamIdx = prev.findIndex((m) => m.isStreaming && m.role === 'assistant');
55
+ if (streamIdx >= 0) {
56
+ return prev.map((m, i) => i === streamIdx
57
+ ? {
58
+ ...m,
59
+ id: messageId ?? m.id,
60
+ content: trimmed,
61
+ partialContent: undefined,
62
+ isStreaming: false,
63
+ metadata: { ...m.metadata, ...voiceMeta(sessionIdRef.current) },
64
+ }
65
+ : m);
66
+ }
67
+ const last = prev[prev.length - 1];
68
+ if (last?.role === 'assistant' && last.content === trimmed)
69
+ return prev;
70
+ return [
71
+ ...prev,
72
+ {
73
+ id: messageId ?? `voice-asst-${Date.now()}`,
74
+ role: 'assistant',
58
75
  content: trimmed,
59
- partialContent: undefined,
60
- isStreaming: false,
61
- metadata: { ...m.metadata, ...voiceMeta(sessionIdRef.current) },
62
- }
63
- : m));
64
- return;
65
- }
66
- const last = messages[messages.length - 1];
67
- if (last?.role === 'assistant' && last.content === trimmed)
68
- return;
69
- api.setMessages([
70
- ...messages,
71
- {
72
- id: messageId ?? `voice-asst-${Date.now()}`,
73
- role: 'assistant',
74
- content: trimmed,
75
- timestamp: new Date().toISOString(),
76
- metadata: voiceMeta(sessionIdRef.current),
77
- },
78
- ]);
76
+ timestamp: new Date().toISOString(),
77
+ metadata: voiceMeta(sessionIdRef.current),
78
+ },
79
+ ];
80
+ });
79
81
  }, [api]);
80
82
  const handleTranscript = useCallback((event) => {
81
83
  if (!isVoiceUiActive())
82
84
  return;
83
85
  const text = event.text?.trim() ?? '';
84
86
  if (event.role === 'assistant') {
85
- // Keep one streaming bubble for the whole turn; finalize only in handleDone.
86
87
  if (text)
87
88
  upsertStreaming(text);
88
89
  return;
89
90
  }
90
91
  if (event.role === 'user' && !event.interim && text) {
91
- const messages = api.getMessages();
92
- const last = messages[messages.length - 1];
93
- if (last?.role === 'user' && last.content === text)
94
- return;
95
- api.setMessages([
96
- ...messages,
97
- {
98
- id: `voice-user-${Date.now()}`,
99
- role: 'user',
100
- content: text,
101
- timestamp: new Date().toISOString(),
102
- metadata: voiceMeta(sessionIdRef.current),
103
- },
104
- ]);
92
+ api.updateMessages((prev) => {
93
+ const last = prev[prev.length - 1];
94
+ if (last?.role === 'user' && last.content === text)
95
+ return prev;
96
+ return [
97
+ ...prev,
98
+ {
99
+ id: `voice-user-${Date.now()}`,
100
+ role: 'user',
101
+ content: text,
102
+ timestamp: new Date().toISOString(),
103
+ metadata: voiceMeta(sessionIdRef.current),
104
+ },
105
+ ];
106
+ });
105
107
  }
106
- }, [api, finalizeAssistant, isVoiceUiActive, upsertStreaming]);
107
- const handleDone = useCallback((event) => {
108
+ }, [api, isVoiceUiActive, upsertStreaming]);
109
+ const handleDone = useCallback((event, options) => {
108
110
  if (!isVoiceUiActive())
109
111
  return;
110
112
  if (event.guardrailsBlocked || event.billingBlocked || event.error) {
@@ -113,6 +115,7 @@ export function useVoiceTranscriptMessages(api, interactionMode, voiceSessionId)
113
115
  }
114
116
  const reply = event.replyText?.trim() ?? '';
115
117
  if (reply) {
118
+ api.updateMessages((prev) => ensureUserBubbleForVoiceTurn(prev, options?.pendingUserText ?? getPendingUserText?.() ?? '', event.userMessageId, voiceMeta(sessionIdRef.current)));
116
119
  finalizeAssistant(reply, event.assistantMessageId ?? undefined);
117
120
  }
118
121
  else {
@@ -121,7 +124,7 @@ export function useVoiceTranscriptMessages(api, interactionMode, voiceSessionId)
121
124
  void api.syncVoiceTurnHistory({ last: 20 }).catch((err) => {
122
125
  console.warn('[nxtlinq] syncVoiceTurnHistory after voice turn failed', err);
123
126
  });
124
- }, [api, finalizeAssistant, isVoiceUiActive]);
127
+ }, [api, finalizeAssistant, getPendingUserText, isVoiceUiActive]);
125
128
  const clearVoiceStream = useCallback(() => {
126
129
  streamIdRef.current = null;
127
130
  }, []);
@@ -0,0 +1,10 @@
1
+ import type { Message } from '@bytexbyte/nxtlinq-ai-agent-core-development';
2
+ export declare const VOICE_USER_INPUT_PLACEHOLDER = "(Voice input)";
3
+ type VoiceMeta = {
4
+ voiceRealtime: true;
5
+ voiceSessionId?: string;
6
+ };
7
+ /** Ensure a user bubble exists before the in-flight assistant reply for this turn. */
8
+ export declare function ensureUserBubbleForVoiceTurn(messages: Message[], userText: string, userMessageId: string | null | undefined, metaForPlaceholder: VoiceMeta | undefined): Message[];
9
+ export {};
10
+ //# sourceMappingURL=voiceUserBubble.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voiceUserBubble.d.ts","sourceRoot":"","sources":["../../src/voice/voiceUserBubble.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,8CAA8C,CAAC;AAE5E,eAAO,MAAM,4BAA4B,kBAAkB,CAAC;AAE5D,KAAK,SAAS,GAAG;IACf,aAAa,EAAE,IAAI,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,sFAAsF;AACtF,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,OAAO,EAAE,EACnB,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACxC,kBAAkB,EAAE,SAAS,GAAG,SAAS,GACxC,OAAO,EAAE,CAuDX"}
@@ -0,0 +1,52 @@
1
+ export const VOICE_USER_INPUT_PLACEHOLDER = '(Voice input)';
2
+ /** Ensure a user bubble exists before the in-flight assistant reply for this turn. */
3
+ export function ensureUserBubbleForVoiceTurn(messages, userText, userMessageId, metaForPlaceholder) {
4
+ const streamIdx = messages.findIndex((m) => m.isStreaming && m.role === 'assistant');
5
+ const insertAt = streamIdx >= 0 ? streamIdx : messages.length;
6
+ const before = messages.slice(0, insertAt);
7
+ const lastAsstIdx = (() => {
8
+ for (let i = before.length - 1; i >= 0; i -= 1) {
9
+ const m = before[i];
10
+ if (m.role === 'assistant' && !m.isStreaming && Boolean(m.content?.trim()))
11
+ return i;
12
+ }
13
+ return -1;
14
+ })();
15
+ const lastUserIdx = (() => {
16
+ for (let i = before.length - 1; i >= 0; i -= 1) {
17
+ if (before[i].role === 'user')
18
+ return i;
19
+ }
20
+ return -1;
21
+ })();
22
+ const hasUserForTurn = lastUserIdx >= 0 && lastUserIdx > lastAsstIdx;
23
+ const trimmed = userText.trim();
24
+ const displayText = trimmed || VOICE_USER_INPUT_PLACEHOLDER;
25
+ if (hasUserForTurn) {
26
+ const existing = before[lastUserIdx];
27
+ const shouldUpgrade = trimmed &&
28
+ existing.content !== trimmed &&
29
+ (existing.content === VOICE_USER_INPUT_PLACEHOLDER || !existing.content.trim());
30
+ if (!shouldUpgrade)
31
+ return messages;
32
+ const upgraded = before.map((m, i) => i === lastUserIdx
33
+ ? {
34
+ ...m,
35
+ content: trimmed,
36
+ id: userMessageId ?? m.id,
37
+ metadata: userMessageId ? undefined : m.metadata,
38
+ }
39
+ : m);
40
+ return [...upgraded, ...messages.slice(insertAt)];
41
+ }
42
+ const userMsg = {
43
+ id: userMessageId ?? `voice-user-${Date.now()}`,
44
+ role: 'user',
45
+ content: displayText,
46
+ timestamp: new Date().toISOString(),
47
+ metadata: userMessageId ? undefined : metaForPlaceholder,
48
+ };
49
+ const next = [...messages];
50
+ next.splice(insertAt, 0, userMsg);
51
+ return next;
52
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytexbyte/nxtlinq-ai-agent-ui-react-development",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Official React Web UI for nxtlinq AI Agent — drop-in chat widget",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -38,8 +38,8 @@
38
38
  "react-dom": ">=18.0.0"
39
39
  },
40
40
  "dependencies": {
41
- "@bytexbyte/nxtlinq-ai-agent-core-development": "0.3.8",
42
- "@bytexbyte/nxtlinq-ai-agent-web-development": "0.1.1",
41
+ "@bytexbyte/nxtlinq-ai-agent-core-development": "0.3.9",
42
+ "@bytexbyte/nxtlinq-ai-agent-web-development": "0.1.2",
43
43
  "@emotion/react": "^11.14.0",
44
44
  "@emotion/styled": "^11.14.1",
45
45
  "@mui/icons-material": "^7.2.0",