@hef2024/llmasaservice-ui 0.20.1 → 0.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.css +66 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +177 -16
- package/dist/index.mjs +177 -16
- package/package.json +1 -1
- package/src/AIAgentPanel.tsx +146 -9
- package/src/AIChatPanel.css +82 -0
- package/src/AIChatPanel.tsx +82 -6
- package/src/components/ui/ToolInfoModal.tsx +3 -0
- package/src/hooks/useAgentRegistry.ts +0 -1
package/dist/index.mjs
CHANGED
|
@@ -3467,12 +3467,15 @@ var ChatInput = React12.memo(({
|
|
|
3467
3467
|
contextSections = [],
|
|
3468
3468
|
totalContextTokens = 0,
|
|
3469
3469
|
maxContextTokens = 8e3,
|
|
3470
|
-
enableContextDetailView = false
|
|
3470
|
+
enableContextDetailView = false,
|
|
3471
|
+
disabledSectionIds = /* @__PURE__ */ new Set(),
|
|
3472
|
+
onToggleSection
|
|
3471
3473
|
}) => {
|
|
3472
3474
|
const [inputValue, setInputValue] = useState6("");
|
|
3473
3475
|
const [dropdownOpen, setDropdownOpen] = useState6(false);
|
|
3474
3476
|
const [contextViewerOpen, setContextViewerOpen] = useState6(false);
|
|
3475
3477
|
const [contextViewMode, setContextViewMode] = useState6("summary");
|
|
3478
|
+
const [expandedSectionId, setExpandedSectionId] = useState6(null);
|
|
3476
3479
|
const textareaRef = useRef5(null);
|
|
3477
3480
|
const containerRef = useRef5(null);
|
|
3478
3481
|
const contextPopoverRef = useRef5(null);
|
|
@@ -3509,6 +3512,7 @@ var ChatInput = React12.memo(({
|
|
|
3509
3512
|
if (contextPopoverRef.current && !contextPopoverRef.current.contains(event.target)) {
|
|
3510
3513
|
setContextViewerOpen(false);
|
|
3511
3514
|
setContextViewMode("summary");
|
|
3515
|
+
setExpandedSectionId(null);
|
|
3512
3516
|
}
|
|
3513
3517
|
};
|
|
3514
3518
|
if (contextViewerOpen) {
|
|
@@ -3590,6 +3594,9 @@ var ChatInput = React12.memo(({
|
|
|
3590
3594
|
setContextViewerOpen(!contextViewerOpen);
|
|
3591
3595
|
if (!contextViewerOpen) {
|
|
3592
3596
|
setContextViewMode("summary");
|
|
3597
|
+
setExpandedSectionId(null);
|
|
3598
|
+
} else {
|
|
3599
|
+
setExpandedSectionId(null);
|
|
3593
3600
|
}
|
|
3594
3601
|
},
|
|
3595
3602
|
type: "button",
|
|
@@ -3607,7 +3614,10 @@ var ChatInput = React12.memo(({
|
|
|
3607
3614
|
"button",
|
|
3608
3615
|
{
|
|
3609
3616
|
className: "ai-chat-context-popover__close",
|
|
3610
|
-
onClick: () =>
|
|
3617
|
+
onClick: () => {
|
|
3618
|
+
setContextViewerOpen(false);
|
|
3619
|
+
setExpandedSectionId(null);
|
|
3620
|
+
},
|
|
3611
3621
|
type: "button"
|
|
3612
3622
|
},
|
|
3613
3623
|
"\xD7"
|
|
@@ -3624,6 +3634,7 @@ var ChatInput = React12.memo(({
|
|
|
3624
3634
|
className: `ai-chat-context-popover__section-item ${enableContextDetailView ? "ai-chat-context-popover__section-item--clickable" : ""}`,
|
|
3625
3635
|
onClick: () => {
|
|
3626
3636
|
if (enableContextDetailView) {
|
|
3637
|
+
setExpandedSectionId(section.id);
|
|
3627
3638
|
setContextViewMode("detail");
|
|
3628
3639
|
}
|
|
3629
3640
|
}
|
|
@@ -3635,7 +3646,10 @@ var ChatInput = React12.memo(({
|
|
|
3635
3646
|
"button",
|
|
3636
3647
|
{
|
|
3637
3648
|
className: "ai-chat-context-popover__expand-btn",
|
|
3638
|
-
onClick: () =>
|
|
3649
|
+
onClick: () => {
|
|
3650
|
+
setExpandedSectionId(null);
|
|
3651
|
+
setContextViewMode("detail");
|
|
3652
|
+
},
|
|
3639
3653
|
type: "button"
|
|
3640
3654
|
},
|
|
3641
3655
|
"View details \u2192"
|
|
@@ -3644,7 +3658,10 @@ var ChatInput = React12.memo(({
|
|
|
3644
3658
|
"button",
|
|
3645
3659
|
{
|
|
3646
3660
|
className: "ai-chat-context-popover__back",
|
|
3647
|
-
onClick: () =>
|
|
3661
|
+
onClick: () => {
|
|
3662
|
+
setContextViewMode("summary");
|
|
3663
|
+
setExpandedSectionId(null);
|
|
3664
|
+
},
|
|
3648
3665
|
type: "button"
|
|
3649
3666
|
},
|
|
3650
3667
|
"\u2190 Back"
|
|
@@ -3652,7 +3669,10 @@ var ChatInput = React12.memo(({
|
|
|
3652
3669
|
"button",
|
|
3653
3670
|
{
|
|
3654
3671
|
className: "ai-chat-context-popover__close",
|
|
3655
|
-
onClick: () =>
|
|
3672
|
+
onClick: () => {
|
|
3673
|
+
setContextViewerOpen(false);
|
|
3674
|
+
setExpandedSectionId(null);
|
|
3675
|
+
},
|
|
3656
3676
|
type: "button"
|
|
3657
3677
|
},
|
|
3658
3678
|
"\xD7"
|
|
@@ -3664,7 +3684,39 @@ var ChatInput = React12.memo(({
|
|
|
3664
3684
|
}
|
|
3665
3685
|
))), /* @__PURE__ */ React12.createElement("div", { className: "ai-chat-context-popover__detail-sections" }, contextSections.map((section) => {
|
|
3666
3686
|
const format = detectFormat(section.data);
|
|
3667
|
-
|
|
3687
|
+
const isEnabled = !disabledSectionIds.has(section.id);
|
|
3688
|
+
return /* @__PURE__ */ React12.createElement(
|
|
3689
|
+
"details",
|
|
3690
|
+
{
|
|
3691
|
+
key: section.id,
|
|
3692
|
+
className: `ai-chat-context-popover__detail-section ${!isEnabled ? "ai-chat-context-popover__detail-section--disabled" : ""}`,
|
|
3693
|
+
open: expandedSectionId === section.id
|
|
3694
|
+
},
|
|
3695
|
+
/* @__PURE__ */ React12.createElement("summary", { className: "ai-chat-context-popover__detail-section-header" }, /* @__PURE__ */ React12.createElement("div", { className: "ai-chat-context-popover__detail-section-title-row" }, /* @__PURE__ */ React12.createElement("span", { className: "ai-chat-context-popover__detail-section-title" }, section.title), /* @__PURE__ */ React12.createElement(
|
|
3696
|
+
"label",
|
|
3697
|
+
{
|
|
3698
|
+
className: "ai-chat-context-toggle",
|
|
3699
|
+
onClick: (e) => e.stopPropagation(),
|
|
3700
|
+
title: isEnabled ? "Disable this context section" : "Enable this context section"
|
|
3701
|
+
},
|
|
3702
|
+
/* @__PURE__ */ React12.createElement(
|
|
3703
|
+
"input",
|
|
3704
|
+
{
|
|
3705
|
+
type: "checkbox",
|
|
3706
|
+
checked: isEnabled,
|
|
3707
|
+
onChange: (e) => {
|
|
3708
|
+
e.stopPropagation();
|
|
3709
|
+
if (onToggleSection) {
|
|
3710
|
+
onToggleSection(section.id, !isEnabled);
|
|
3711
|
+
}
|
|
3712
|
+
},
|
|
3713
|
+
className: "ai-chat-context-toggle__input"
|
|
3714
|
+
}
|
|
3715
|
+
),
|
|
3716
|
+
/* @__PURE__ */ React12.createElement("span", { className: "ai-chat-context-toggle__slider" })
|
|
3717
|
+
)), /* @__PURE__ */ React12.createElement("span", { className: "ai-chat-context-popover__detail-section-meta" }, /* @__PURE__ */ React12.createElement("code", null, `{{${section.id}}}`), /* @__PURE__ */ React12.createElement("span", null, "~", section.tokens || Math.ceil(JSON.stringify(section.data).length / 4)))),
|
|
3718
|
+
/* @__PURE__ */ React12.createElement("pre", { className: "ai-chat-context-popover__detail-content" }, /* @__PURE__ */ React12.createElement("code", null, formatContent(section.data, format)))
|
|
3719
|
+
);
|
|
3668
3720
|
})))
|
|
3669
3721
|
)), /* @__PURE__ */ React12.createElement(
|
|
3670
3722
|
"button",
|
|
@@ -3740,6 +3792,8 @@ var AIChatPanel = ({
|
|
|
3740
3792
|
totalContextTokens = 0,
|
|
3741
3793
|
maxContextTokens = 8e3,
|
|
3742
3794
|
enableContextDetailView = false,
|
|
3795
|
+
disabledSectionIds: propDisabledSectionIds,
|
|
3796
|
+
onToggleSection: propOnToggleSection,
|
|
3743
3797
|
onConversationCreated,
|
|
3744
3798
|
// UI Customization Props
|
|
3745
3799
|
cssUrl,
|
|
@@ -3791,6 +3845,8 @@ var AIChatPanel = ({
|
|
|
3791
3845
|
const [pendingToolRequests, setPendingToolRequests] = useState6([]);
|
|
3792
3846
|
const [sessionApprovedTools, setSessionApprovedTools] = useState6([]);
|
|
3793
3847
|
const [alwaysApprovedTools, setAlwaysApprovedTools] = useState6([]);
|
|
3848
|
+
const [internalDisabledSectionIds, setInternalDisabledSectionIds] = useState6(/* @__PURE__ */ new Set());
|
|
3849
|
+
const disabledSectionIds = propDisabledSectionIds != null ? propDisabledSectionIds : internalDisabledSectionIds;
|
|
3794
3850
|
useEffect7(() => {
|
|
3795
3851
|
setShowEmailPanel(customerEmailCaptureMode !== "HIDE");
|
|
3796
3852
|
if (customerEmailCaptureMode === "REQUIRED") {
|
|
@@ -3868,6 +3924,21 @@ var AIChatPanel = ({
|
|
|
3868
3924
|
userLanguage: navigator.language
|
|
3869
3925
|
};
|
|
3870
3926
|
}, []);
|
|
3927
|
+
const handleToggleSection = useCallback2((sectionId, enabled) => {
|
|
3928
|
+
if (propOnToggleSection) {
|
|
3929
|
+
propOnToggleSection(sectionId, enabled);
|
|
3930
|
+
} else {
|
|
3931
|
+
setInternalDisabledSectionIds((prev) => {
|
|
3932
|
+
const next = new Set(prev);
|
|
3933
|
+
if (enabled) {
|
|
3934
|
+
next.delete(sectionId);
|
|
3935
|
+
} else {
|
|
3936
|
+
next.add(sectionId);
|
|
3937
|
+
}
|
|
3938
|
+
return next;
|
|
3939
|
+
});
|
|
3940
|
+
}
|
|
3941
|
+
}, [propOnToggleSection]);
|
|
3871
3942
|
const ensureConversation = useCallback2(() => {
|
|
3872
3943
|
var _a2, _b;
|
|
3873
3944
|
console.log("ensureConversation - called with:", {
|
|
@@ -5008,7 +5079,9 @@ var AIChatPanel = ({
|
|
|
5008
5079
|
contextSections,
|
|
5009
5080
|
totalContextTokens,
|
|
5010
5081
|
maxContextTokens,
|
|
5011
|
-
enableContextDetailView
|
|
5082
|
+
enableContextDetailView,
|
|
5083
|
+
disabledSectionIds,
|
|
5084
|
+
onToggleSection: handleToggleSection
|
|
5012
5085
|
}
|
|
5013
5086
|
),
|
|
5014
5087
|
showPoweredBy && /* @__PURE__ */ React12.createElement("div", { className: "ai-chat-panel__footer" }, mcpServers && mcpServers.length > 0 && /* @__PURE__ */ React12.createElement("div", { className: "ai-chat-tools-status" }, /* @__PURE__ */ React12.createElement(
|
|
@@ -5359,6 +5432,8 @@ var ChatPanelWrapper = ({
|
|
|
5359
5432
|
totalContextTokens,
|
|
5360
5433
|
maxContextTokens,
|
|
5361
5434
|
enableContextDetailView,
|
|
5435
|
+
disabledSectionIds,
|
|
5436
|
+
onToggleSection,
|
|
5362
5437
|
onConversationCreated,
|
|
5363
5438
|
conversationInitialPrompt,
|
|
5364
5439
|
// New props from ChatPanel port
|
|
@@ -5460,6 +5535,8 @@ var ChatPanelWrapper = ({
|
|
|
5460
5535
|
totalContextTokens,
|
|
5461
5536
|
maxContextTokens,
|
|
5462
5537
|
enableContextDetailView,
|
|
5538
|
+
disabledSectionIds,
|
|
5539
|
+
onToggleSection,
|
|
5463
5540
|
onConversationCreated: conversationCreatedCallback,
|
|
5464
5541
|
cssUrl,
|
|
5465
5542
|
markdownClass,
|
|
@@ -5484,6 +5561,7 @@ ChatPanelWrapper.displayName = "ChatPanelWrapper";
|
|
|
5484
5561
|
var AIAgentPanel = React13.forwardRef(({
|
|
5485
5562
|
agents,
|
|
5486
5563
|
defaultAgent,
|
|
5564
|
+
selectedAgent,
|
|
5487
5565
|
customerId,
|
|
5488
5566
|
apiKey,
|
|
5489
5567
|
context,
|
|
@@ -5587,6 +5665,63 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
5587
5665
|
const [currentAgentId, setCurrentAgentId] = useState8(
|
|
5588
5666
|
defaultAgent || agentIds[0] || ""
|
|
5589
5667
|
);
|
|
5668
|
+
const [pendingFollowOnPrompt, setPendingFollowOnPrompt] = useState8(null);
|
|
5669
|
+
const [agentSwitchSettled, setAgentSwitchSettled] = useState8(true);
|
|
5670
|
+
const lastProcessedFollowOnRef = useRef6("");
|
|
5671
|
+
useEffect9(() => {
|
|
5672
|
+
if (selectedAgent && selectedAgent !== currentAgentId) {
|
|
5673
|
+
const oldAgentId = currentAgentId;
|
|
5674
|
+
setAgentSwitchSettled(false);
|
|
5675
|
+
setCurrentAgentId(selectedAgent);
|
|
5676
|
+
if (onAgentSwitch) {
|
|
5677
|
+
onAgentSwitch(oldAgentId, selectedAgent);
|
|
5678
|
+
}
|
|
5679
|
+
if (currentConversationIdRef.current) {
|
|
5680
|
+
setActiveConversations((prev) => {
|
|
5681
|
+
const existing = prev.get(currentConversationIdRef.current);
|
|
5682
|
+
if (existing) {
|
|
5683
|
+
const next = new Map(prev);
|
|
5684
|
+
next.set(currentConversationIdRef.current, __spreadProps(__spreadValues({}, existing), {
|
|
5685
|
+
agentId: selectedAgent
|
|
5686
|
+
}));
|
|
5687
|
+
return next;
|
|
5688
|
+
}
|
|
5689
|
+
return prev;
|
|
5690
|
+
});
|
|
5691
|
+
}
|
|
5692
|
+
}
|
|
5693
|
+
}, [selectedAgent]);
|
|
5694
|
+
useEffect9(() => {
|
|
5695
|
+
if (!agentSwitchSettled && followOnPrompt && followOnPrompt !== "" && followOnPrompt !== lastProcessedFollowOnRef.current) {
|
|
5696
|
+
setPendingFollowOnPrompt(followOnPrompt);
|
|
5697
|
+
lastProcessedFollowOnRef.current = followOnPrompt;
|
|
5698
|
+
}
|
|
5699
|
+
}, [followOnPrompt, agentSwitchSettled]);
|
|
5700
|
+
useEffect9(() => {
|
|
5701
|
+
if (!agentSwitchSettled) {
|
|
5702
|
+
const timer = setTimeout(() => {
|
|
5703
|
+
setAgentSwitchSettled(true);
|
|
5704
|
+
}, 100);
|
|
5705
|
+
return () => clearTimeout(timer);
|
|
5706
|
+
}
|
|
5707
|
+
}, [agentSwitchSettled]);
|
|
5708
|
+
const effectiveFollowOnPrompt = useMemo4(() => {
|
|
5709
|
+
if (!agentSwitchSettled) {
|
|
5710
|
+
return "";
|
|
5711
|
+
}
|
|
5712
|
+
if (pendingFollowOnPrompt) {
|
|
5713
|
+
return pendingFollowOnPrompt;
|
|
5714
|
+
}
|
|
5715
|
+
return followOnPrompt;
|
|
5716
|
+
}, [followOnPrompt, pendingFollowOnPrompt, agentSwitchSettled]);
|
|
5717
|
+
useEffect9(() => {
|
|
5718
|
+
if (agentSwitchSettled && pendingFollowOnPrompt) {
|
|
5719
|
+
const timer = setTimeout(() => {
|
|
5720
|
+
setPendingFollowOnPrompt(null);
|
|
5721
|
+
}, 100);
|
|
5722
|
+
return () => clearTimeout(timer);
|
|
5723
|
+
}
|
|
5724
|
+
}, [agentSwitchSettled, pendingFollowOnPrompt]);
|
|
5590
5725
|
const [apiConversations, setApiConversations] = useState8([]);
|
|
5591
5726
|
const [conversationsLoading, setConversationsLoading] = useState8(false);
|
|
5592
5727
|
const [conversationsError, setConversationsError] = useState8(null);
|
|
@@ -5603,6 +5738,7 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
5603
5738
|
"This Month": false,
|
|
5604
5739
|
"Older": false
|
|
5605
5740
|
});
|
|
5741
|
+
const [disabledContextSections, setDisabledContextSections] = useState8(/* @__PURE__ */ new Map());
|
|
5606
5742
|
const {
|
|
5607
5743
|
agents: agentProfiles,
|
|
5608
5744
|
isLoading: agentsLoading,
|
|
@@ -5746,13 +5882,8 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
5746
5882
|
fetchInProgressRef.current = true;
|
|
5747
5883
|
setConversationsLoading(true);
|
|
5748
5884
|
setConversationsError(null);
|
|
5749
|
-
console.log("projectId", projectId);
|
|
5750
|
-
console.log("customerId", customerId);
|
|
5751
|
-
console.log("apiKey", apiKey);
|
|
5752
5885
|
try {
|
|
5753
|
-
console.log("fetchConversations - customerId:", customerId);
|
|
5754
5886
|
const url2 = `https://api.llmasaservice.io/conversations?customer_id=${customerId}`;
|
|
5755
|
-
console.log("fetchConversations - URL:", url2);
|
|
5756
5887
|
const response = yield fetch(url2, {
|
|
5757
5888
|
signal,
|
|
5758
5889
|
headers: {
|
|
@@ -6136,8 +6267,21 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
6136
6267
|
});
|
|
6137
6268
|
}
|
|
6138
6269
|
}, [pageContextSections, currentAgentId, agentIds, getAgent, localOverrides]);
|
|
6270
|
+
const currentDisabledSections = useMemo4(() => {
|
|
6271
|
+
return currentConversationId ? disabledContextSections.get(currentConversationId) || /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set();
|
|
6272
|
+
}, [currentConversationId, disabledContextSections]);
|
|
6273
|
+
const filteredContext = useMemo4(() => {
|
|
6274
|
+
const enabledSections = mergedContext.sections.filter(
|
|
6275
|
+
(section) => !currentDisabledSections.has(section.id)
|
|
6276
|
+
);
|
|
6277
|
+
const totalTokens = enabledSections.reduce((sum, s) => sum + (s.tokens || 0), 0);
|
|
6278
|
+
return {
|
|
6279
|
+
sections: enabledSections,
|
|
6280
|
+
totalTokens
|
|
6281
|
+
};
|
|
6282
|
+
}, [mergedContext.sections, currentDisabledSections]);
|
|
6139
6283
|
const chatPanelData = useMemo4(() => {
|
|
6140
|
-
const contextData =
|
|
6284
|
+
const contextData = filteredContext.sections.map((section) => ({
|
|
6141
6285
|
key: section.id,
|
|
6142
6286
|
data: JSON.stringify(section.data)
|
|
6143
6287
|
}));
|
|
@@ -6151,7 +6295,7 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
6151
6295
|
}
|
|
6152
6296
|
}
|
|
6153
6297
|
return [...data, ...contextData];
|
|
6154
|
-
}, [data,
|
|
6298
|
+
}, [data, filteredContext.sections, buildAgentAwarenessInstructions, currentAgentId, enableAgentSuggestions]);
|
|
6155
6299
|
const handleAgentSwitch = useCallback4(
|
|
6156
6300
|
(newAgentId) => {
|
|
6157
6301
|
const oldAgentId = currentAgentId;
|
|
@@ -6282,6 +6426,21 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
6282
6426
|
setSuggestedAgent(null);
|
|
6283
6427
|
setHandoffSource("agent");
|
|
6284
6428
|
}, []);
|
|
6429
|
+
const handleContextSectionToggle = useCallback4((sectionId, enabled) => {
|
|
6430
|
+
if (!currentConversationId) return;
|
|
6431
|
+
setDisabledContextSections((prev) => {
|
|
6432
|
+
const next = new Map(prev);
|
|
6433
|
+
const conversationDisabled = next.get(currentConversationId) || /* @__PURE__ */ new Set();
|
|
6434
|
+
const nextDisabled = new Set(conversationDisabled);
|
|
6435
|
+
if (enabled) {
|
|
6436
|
+
nextDisabled.delete(sectionId);
|
|
6437
|
+
} else {
|
|
6438
|
+
nextDisabled.add(sectionId);
|
|
6439
|
+
}
|
|
6440
|
+
next.set(currentConversationId, nextDisabled);
|
|
6441
|
+
return next;
|
|
6442
|
+
});
|
|
6443
|
+
}, [currentConversationId]);
|
|
6285
6444
|
const handleConversationCreated = useCallback4((tempId, realId) => {
|
|
6286
6445
|
console.log("Conversation created:", tempId, "->", realId);
|
|
6287
6446
|
setActiveConversations((prev) => {
|
|
@@ -6609,15 +6768,17 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
6609
6768
|
initialMessage,
|
|
6610
6769
|
hideInitialPrompt,
|
|
6611
6770
|
followOnQuestions,
|
|
6612
|
-
followOnPrompt,
|
|
6771
|
+
followOnPrompt: effectiveFollowOnPrompt,
|
|
6613
6772
|
agentOptions,
|
|
6614
6773
|
currentAgentId,
|
|
6615
6774
|
handleAgentSwitch,
|
|
6616
6775
|
agentsLoading,
|
|
6617
6776
|
contextSections: mergedContext.sections,
|
|
6618
|
-
totalContextTokens:
|
|
6777
|
+
totalContextTokens: filteredContext.totalTokens,
|
|
6619
6778
|
maxContextTokens,
|
|
6620
6779
|
enableContextDetailView,
|
|
6780
|
+
disabledSectionIds: currentDisabledSections,
|
|
6781
|
+
onToggleSection: handleContextSectionToggle,
|
|
6621
6782
|
onConversationCreated: handleConversationCreated,
|
|
6622
6783
|
conversationInitialPrompt: activeConv.conversationInitialPrompt,
|
|
6623
6784
|
cssUrl,
|
package/package.json
CHANGED
package/src/AIAgentPanel.tsx
CHANGED
|
@@ -73,6 +73,9 @@ export interface AIAgentPanelProps {
|
|
|
73
73
|
// Agent Configuration - can be string IDs or full config objects
|
|
74
74
|
agents: (string | AgentConfig)[];
|
|
75
75
|
defaultAgent?: string;
|
|
76
|
+
|
|
77
|
+
// Controlled selection - when provided, external state drives which agent is active
|
|
78
|
+
selectedAgent?: string;
|
|
76
79
|
|
|
77
80
|
// Customer ID - REQUIRED for conversation history
|
|
78
81
|
customerId: string;
|
|
@@ -394,6 +397,8 @@ interface ChatPanelWrapperProps {
|
|
|
394
397
|
totalContextTokens: number;
|
|
395
398
|
maxContextTokens: number;
|
|
396
399
|
enableContextDetailView: boolean;
|
|
400
|
+
disabledSectionIds: Set<string>;
|
|
401
|
+
onToggleSection: (sectionId: string, enabled: boolean) => void;
|
|
397
402
|
// Conversation creation callback
|
|
398
403
|
onConversationCreated: (tempId: string, realId: string) => void;
|
|
399
404
|
// Per-conversation initial prompt
|
|
@@ -445,6 +450,8 @@ const ChatPanelWrapper = (({
|
|
|
445
450
|
totalContextTokens,
|
|
446
451
|
maxContextTokens,
|
|
447
452
|
enableContextDetailView,
|
|
453
|
+
disabledSectionIds,
|
|
454
|
+
onToggleSection,
|
|
448
455
|
onConversationCreated,
|
|
449
456
|
conversationInitialPrompt,
|
|
450
457
|
// New props from ChatPanel port
|
|
@@ -570,6 +577,8 @@ const ChatPanelWrapper = (({
|
|
|
570
577
|
totalContextTokens={totalContextTokens}
|
|
571
578
|
maxContextTokens={maxContextTokens}
|
|
572
579
|
enableContextDetailView={enableContextDetailView}
|
|
580
|
+
disabledSectionIds={disabledSectionIds}
|
|
581
|
+
onToggleSection={onToggleSection}
|
|
573
582
|
onConversationCreated={conversationCreatedCallback}
|
|
574
583
|
cssUrl={cssUrl}
|
|
575
584
|
markdownClass={markdownClass}
|
|
@@ -596,6 +605,7 @@ ChatPanelWrapper.displayName = 'ChatPanelWrapper';
|
|
|
596
605
|
const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
597
606
|
agents,
|
|
598
607
|
defaultAgent,
|
|
608
|
+
selectedAgent,
|
|
599
609
|
customerId,
|
|
600
610
|
apiKey,
|
|
601
611
|
context,
|
|
@@ -706,6 +716,92 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
706
716
|
defaultAgent || agentIds[0] || ''
|
|
707
717
|
);
|
|
708
718
|
|
|
719
|
+
// Track pending follow-on prompt after agent switch (to handle timing issues)
|
|
720
|
+
const [pendingFollowOnPrompt, setPendingFollowOnPrompt] = useState<string | null>(null);
|
|
721
|
+
const [agentSwitchSettled, setAgentSwitchSettled] = useState(true);
|
|
722
|
+
const lastProcessedFollowOnRef = useRef<string>('');
|
|
723
|
+
|
|
724
|
+
// Sync with controlled selectedAgent prop when it changes
|
|
725
|
+
useEffect(() => {
|
|
726
|
+
// Only sync if selectedAgent is provided (controlled mode) and differs from current
|
|
727
|
+
if (selectedAgent && selectedAgent !== currentAgentId) {
|
|
728
|
+
const oldAgentId = currentAgentId;
|
|
729
|
+
|
|
730
|
+
// Mark that an agent switch is in progress (not yet settled)
|
|
731
|
+
setAgentSwitchSettled(false);
|
|
732
|
+
|
|
733
|
+
setCurrentAgentId(selectedAgent);
|
|
734
|
+
|
|
735
|
+
// Fire onAgentSwitch callback for programmatic changes too
|
|
736
|
+
if (onAgentSwitch) {
|
|
737
|
+
onAgentSwitch(oldAgentId, selectedAgent);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// Update the current conversation's agent ID to match
|
|
741
|
+
if (currentConversationIdRef.current) {
|
|
742
|
+
setActiveConversations(prev => {
|
|
743
|
+
const existing = prev.get(currentConversationIdRef.current!);
|
|
744
|
+
if (existing) {
|
|
745
|
+
const next = new Map(prev);
|
|
746
|
+
next.set(currentConversationIdRef.current!, {
|
|
747
|
+
...existing,
|
|
748
|
+
agentId: selectedAgent,
|
|
749
|
+
});
|
|
750
|
+
return next;
|
|
751
|
+
}
|
|
752
|
+
return prev;
|
|
753
|
+
});
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}, [selectedAgent]); // Note: intentionally excluding other deps to only trigger on prop change
|
|
757
|
+
|
|
758
|
+
// Queue followOnPrompt if it arrives during an agent switch
|
|
759
|
+
useEffect(() => {
|
|
760
|
+
if (!agentSwitchSettled && followOnPrompt && followOnPrompt !== '' && followOnPrompt !== lastProcessedFollowOnRef.current) {
|
|
761
|
+
// Agent switch in progress - queue the prompt
|
|
762
|
+
setPendingFollowOnPrompt(followOnPrompt);
|
|
763
|
+
lastProcessedFollowOnRef.current = followOnPrompt;
|
|
764
|
+
}
|
|
765
|
+
}, [followOnPrompt, agentSwitchSettled]);
|
|
766
|
+
|
|
767
|
+
// Mark agent switch as settled after a short delay (allows ChatPanelWrapper to re-render)
|
|
768
|
+
useEffect(() => {
|
|
769
|
+
if (!agentSwitchSettled) {
|
|
770
|
+
const timer = setTimeout(() => {
|
|
771
|
+
setAgentSwitchSettled(true);
|
|
772
|
+
}, 100); // Small delay to ensure ChatPanelWrapper has re-rendered with new agent
|
|
773
|
+
|
|
774
|
+
return () => clearTimeout(timer);
|
|
775
|
+
}
|
|
776
|
+
}, [agentSwitchSettled]);
|
|
777
|
+
|
|
778
|
+
// Compute effective follow-on prompt (handles timing with agent switch)
|
|
779
|
+
const effectiveFollowOnPrompt = useMemo(() => {
|
|
780
|
+
// If agent switch hasn't settled yet, don't send any prompt
|
|
781
|
+
if (!agentSwitchSettled) {
|
|
782
|
+
return '';
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// If there's a pending prompt from agent switch, use it
|
|
786
|
+
if (pendingFollowOnPrompt) {
|
|
787
|
+
return pendingFollowOnPrompt;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// Otherwise use the prop directly
|
|
791
|
+
return followOnPrompt;
|
|
792
|
+
}, [followOnPrompt, pendingFollowOnPrompt, agentSwitchSettled]);
|
|
793
|
+
|
|
794
|
+
// Clear pending prompt after it's been passed down
|
|
795
|
+
useEffect(() => {
|
|
796
|
+
if (agentSwitchSettled && pendingFollowOnPrompt) {
|
|
797
|
+
// Clear after a tick to ensure it was processed
|
|
798
|
+
const timer = setTimeout(() => {
|
|
799
|
+
setPendingFollowOnPrompt(null);
|
|
800
|
+
}, 100);
|
|
801
|
+
return () => clearTimeout(timer);
|
|
802
|
+
}
|
|
803
|
+
}, [agentSwitchSettled, pendingFollowOnPrompt]);
|
|
804
|
+
|
|
709
805
|
// API-based conversation state
|
|
710
806
|
const [apiConversations, setApiConversations] = useState<APIConversationSummary[]>([]);
|
|
711
807
|
const [conversationsLoading, setConversationsLoading] = useState(false);
|
|
@@ -732,6 +828,9 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
732
828
|
'Older': false,
|
|
733
829
|
});
|
|
734
830
|
|
|
831
|
+
// Context section toggle state (per-conversation disabled sections)
|
|
832
|
+
const [disabledContextSections, setDisabledContextSections] = useState<Map<string, Set<string>>>(new Map());
|
|
833
|
+
|
|
735
834
|
// Agent registry hook
|
|
736
835
|
const {
|
|
737
836
|
agents: agentProfiles,
|
|
@@ -945,14 +1044,9 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
945
1044
|
|
|
946
1045
|
setConversationsLoading(true);
|
|
947
1046
|
setConversationsError(null);
|
|
948
|
-
console.log("projectId", projectId);
|
|
949
|
-
console.log("customerId", customerId);
|
|
950
|
-
console.log("apiKey", apiKey);
|
|
951
1047
|
|
|
952
1048
|
try {
|
|
953
|
-
console.log('fetchConversations - customerId:', customerId);
|
|
954
1049
|
const url = `https://api.llmasaservice.io/conversations?customer_id=${customerId}`;
|
|
955
|
-
console.log('fetchConversations - URL:', url);
|
|
956
1050
|
|
|
957
1051
|
const response = await fetch(url, {
|
|
958
1052
|
signal,
|
|
@@ -1509,9 +1603,30 @@ console.log("apiKey", apiKey);
|
|
|
1509
1603
|
}
|
|
1510
1604
|
}, [pageContextSections, currentAgentId, agentIds, getAgent, localOverrides]);
|
|
1511
1605
|
|
|
1606
|
+
// Get disabled sections for current conversation
|
|
1607
|
+
const currentDisabledSections = useMemo((): Set<string> => {
|
|
1608
|
+
return currentConversationId
|
|
1609
|
+
? disabledContextSections.get(currentConversationId) || new Set<string>()
|
|
1610
|
+
: new Set<string>();
|
|
1611
|
+
}, [currentConversationId, disabledContextSections]);
|
|
1612
|
+
|
|
1613
|
+
// Filtered context (only enabled sections)
|
|
1614
|
+
const filteredContext = useMemo(() => {
|
|
1615
|
+
const enabledSections = mergedContext.sections.filter(
|
|
1616
|
+
section => !currentDisabledSections.has(section.id)
|
|
1617
|
+
);
|
|
1618
|
+
const totalTokens = enabledSections.reduce((sum, s) => sum + (s.tokens || 0), 0);
|
|
1619
|
+
|
|
1620
|
+
return {
|
|
1621
|
+
sections: enabledSections,
|
|
1622
|
+
totalTokens,
|
|
1623
|
+
};
|
|
1624
|
+
}, [mergedContext.sections, currentDisabledSections]);
|
|
1625
|
+
|
|
1512
1626
|
// Build data array for ChatPanel
|
|
1513
1627
|
const chatPanelData = useMemo(() => {
|
|
1514
|
-
|
|
1628
|
+
// Use filtered sections (disabled sections are excluded)
|
|
1629
|
+
const contextData = filteredContext.sections.map((section) => ({
|
|
1515
1630
|
key: section.id,
|
|
1516
1631
|
data: JSON.stringify(section.data),
|
|
1517
1632
|
}));
|
|
@@ -1528,7 +1643,7 @@ console.log("apiKey", apiKey);
|
|
|
1528
1643
|
}
|
|
1529
1644
|
|
|
1530
1645
|
return [...data, ...contextData];
|
|
1531
|
-
}, [data,
|
|
1646
|
+
}, [data, filteredContext.sections, buildAgentAwarenessInstructions, currentAgentId, enableAgentSuggestions]);
|
|
1532
1647
|
|
|
1533
1648
|
// Handle agent switch - updates the agent for the current conversation without starting a new one
|
|
1534
1649
|
const handleAgentSwitch = useCallback(
|
|
@@ -1697,6 +1812,26 @@ console.log("apiKey", apiKey);
|
|
|
1697
1812
|
setHandoffSource('agent');
|
|
1698
1813
|
}, []);
|
|
1699
1814
|
|
|
1815
|
+
// Handle context section toggle for current conversation
|
|
1816
|
+
const handleContextSectionToggle = useCallback((sectionId: string, enabled: boolean) => {
|
|
1817
|
+
if (!currentConversationId) return;
|
|
1818
|
+
|
|
1819
|
+
setDisabledContextSections(prev => {
|
|
1820
|
+
const next = new Map(prev);
|
|
1821
|
+
const conversationDisabled = next.get(currentConversationId) || new Set();
|
|
1822
|
+
const nextDisabled = new Set(conversationDisabled);
|
|
1823
|
+
|
|
1824
|
+
if (enabled) {
|
|
1825
|
+
nextDisabled.delete(sectionId);
|
|
1826
|
+
} else {
|
|
1827
|
+
nextDisabled.add(sectionId);
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
next.set(currentConversationId, nextDisabled);
|
|
1831
|
+
return next;
|
|
1832
|
+
});
|
|
1833
|
+
}, [currentConversationId]);
|
|
1834
|
+
|
|
1700
1835
|
// Handle conversation created - update temp ID to real ID from API
|
|
1701
1836
|
const handleConversationCreated = useCallback((tempId: string, realId: string) => {
|
|
1702
1837
|
console.log('Conversation created:', tempId, '->', realId);
|
|
@@ -2188,15 +2323,17 @@ console.log("apiKey", apiKey);
|
|
|
2188
2323
|
initialMessage={initialMessage}
|
|
2189
2324
|
hideInitialPrompt={hideInitialPrompt}
|
|
2190
2325
|
followOnQuestions={followOnQuestions}
|
|
2191
|
-
followOnPrompt={
|
|
2326
|
+
followOnPrompt={effectiveFollowOnPrompt}
|
|
2192
2327
|
agentOptions={agentOptions}
|
|
2193
2328
|
currentAgentId={currentAgentId}
|
|
2194
2329
|
handleAgentSwitch={handleAgentSwitch}
|
|
2195
2330
|
agentsLoading={agentsLoading}
|
|
2196
2331
|
contextSections={mergedContext.sections}
|
|
2197
|
-
totalContextTokens={
|
|
2332
|
+
totalContextTokens={filteredContext.totalTokens}
|
|
2198
2333
|
maxContextTokens={maxContextTokens}
|
|
2199
2334
|
enableContextDetailView={enableContextDetailView}
|
|
2335
|
+
disabledSectionIds={currentDisabledSections}
|
|
2336
|
+
onToggleSection={handleContextSectionToggle}
|
|
2200
2337
|
onConversationCreated={handleConversationCreated}
|
|
2201
2338
|
conversationInitialPrompt={activeConv.conversationInitialPrompt}
|
|
2202
2339
|
cssUrl={cssUrl}
|