@hef2024/llmasaservice-ui 0.20.0 → 0.20.2
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/AICHATPANEL-PORT-INVENTORY.md +1 -0
- package/DEBUG-ERROR-HANDLING.md +1 -0
- package/FIX-APPLIED.md +1 -0
- package/IMPLEMENTATION-COMPLETE.md +1 -0
- package/dist/index.css +511 -0
- package/dist/index.d.mts +39 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.js +1181 -451
- package/dist/index.mjs +1012 -282
- package/docs/CHANGELOG-ERROR-HANDLING.md +1 -0
- package/docs/CONVERSATION-HISTORY.md +1 -0
- package/docs/ERROR-HANDLING-413.md +1 -0
- package/docs/ERROR-HANDLING-SUMMARY.md +1 -0
- package/package.json +2 -2
- package/src/AIAgentPanel.tsx +186 -9
- package/src/AIChatPanel.css +618 -0
- package/src/AIChatPanel.tsx +723 -38
- package/src/AgentPanel.tsx +3 -1
- package/src/ChatPanel.tsx +69 -29
- package/src/components/ui/Button.tsx +1 -0
- package/src/components/ui/Dialog.tsx +1 -0
- package/src/components/ui/Input.tsx +1 -0
- package/src/components/ui/Select.tsx +1 -0
- package/src/components/ui/ToolInfoModal.tsx +69 -0
- package/src/components/ui/Tooltip.tsx +1 -0
- package/src/components/ui/index.ts +1 -0
|
@@ -251,3 +251,4 @@ Potential improvements for future iterations:
|
|
|
251
251
|
- Errors are detected by monitoring the `error` property from `useLLM` hook
|
|
252
252
|
- The implementation is consistent across both modern (AIChatPanel) and legacy (ChatPanel) components
|
|
253
253
|
- Error state is properly synchronized with loading state to prevent UI inconsistencies
|
|
254
|
+
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hef2024/llmasaservice-ui",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.2",
|
|
4
4
|
"description": "Prebuilt UI components for LLMAsAService.io",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"dotenv": "^16.4.7",
|
|
58
58
|
"llmasaservice-client": "^0.10.4",
|
|
59
59
|
"process": "^0.11.10",
|
|
60
|
-
"react-markdown": "^
|
|
60
|
+
"react-markdown": "^10.1.0",
|
|
61
61
|
"react-syntax-highlighter": "^15.5.0",
|
|
62
62
|
"rehype-raw": "^7.0.0",
|
|
63
63
|
"remark-gfm": "^4.0.0",
|
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;
|
|
@@ -141,6 +144,23 @@ export interface AIAgentPanelProps {
|
|
|
141
144
|
|
|
142
145
|
// Enable/disable conversation history panel
|
|
143
146
|
showConversationHistory?: boolean;
|
|
147
|
+
|
|
148
|
+
// New props from ChatPanel port
|
|
149
|
+
cssUrl?: string;
|
|
150
|
+
markdownClass?: string;
|
|
151
|
+
width?: string;
|
|
152
|
+
height?: string;
|
|
153
|
+
scrollToEnd?: boolean;
|
|
154
|
+
prismStyle?: any;
|
|
155
|
+
showSaveButton?: boolean;
|
|
156
|
+
showEmailButton?: boolean;
|
|
157
|
+
messages?: { role: "user" | "assistant"; content: string }[];
|
|
158
|
+
showCallToAction?: boolean;
|
|
159
|
+
callToActionButtonText?: string;
|
|
160
|
+
callToActionEmailAddress?: string;
|
|
161
|
+
callToActionEmailSubject?: string;
|
|
162
|
+
customerEmailCaptureMode?: "HIDE" | "OPTIONAL" | "REQUIRED";
|
|
163
|
+
customerEmailCapturePlaceholder?: string;
|
|
144
164
|
}
|
|
145
165
|
|
|
146
166
|
// Icons
|
|
@@ -377,10 +397,28 @@ interface ChatPanelWrapperProps {
|
|
|
377
397
|
totalContextTokens: number;
|
|
378
398
|
maxContextTokens: number;
|
|
379
399
|
enableContextDetailView: boolean;
|
|
400
|
+
disabledSectionIds: Set<string>;
|
|
401
|
+
onToggleSection: (sectionId: string, enabled: boolean) => void;
|
|
380
402
|
// Conversation creation callback
|
|
381
403
|
onConversationCreated: (tempId: string, realId: string) => void;
|
|
382
404
|
// Per-conversation initial prompt
|
|
383
405
|
conversationInitialPrompt?: string;
|
|
406
|
+
// New props from ChatPanel port
|
|
407
|
+
cssUrl?: string;
|
|
408
|
+
markdownClass?: string;
|
|
409
|
+
width?: string;
|
|
410
|
+
height?: string;
|
|
411
|
+
scrollToEnd?: boolean;
|
|
412
|
+
prismStyle?: any;
|
|
413
|
+
showSaveButton?: boolean;
|
|
414
|
+
showEmailButton?: boolean;
|
|
415
|
+
messages?: { role: "user" | "assistant"; content: string }[];
|
|
416
|
+
showCallToAction?: boolean;
|
|
417
|
+
callToActionButtonText?: string;
|
|
418
|
+
callToActionEmailAddress?: string;
|
|
419
|
+
callToActionEmailSubject?: string;
|
|
420
|
+
customerEmailCaptureMode?: "HIDE" | "OPTIONAL" | "REQUIRED";
|
|
421
|
+
customerEmailCapturePlaceholder?: string;
|
|
384
422
|
}
|
|
385
423
|
|
|
386
424
|
// Remove React.memo temporarily to debug - ChatPanelWrapper needs to re-render when agentId changes
|
|
@@ -412,13 +450,32 @@ const ChatPanelWrapper = (({
|
|
|
412
450
|
totalContextTokens,
|
|
413
451
|
maxContextTokens,
|
|
414
452
|
enableContextDetailView,
|
|
453
|
+
disabledSectionIds,
|
|
454
|
+
onToggleSection,
|
|
415
455
|
onConversationCreated,
|
|
416
456
|
conversationInitialPrompt,
|
|
457
|
+
// New props from ChatPanel port
|
|
458
|
+
cssUrl,
|
|
459
|
+
markdownClass,
|
|
460
|
+
width,
|
|
461
|
+
height,
|
|
462
|
+
scrollToEnd,
|
|
463
|
+
prismStyle,
|
|
464
|
+
showSaveButton,
|
|
465
|
+
showEmailButton,
|
|
466
|
+
messages,
|
|
467
|
+
showCallToAction,
|
|
468
|
+
callToActionButtonText,
|
|
469
|
+
callToActionEmailAddress,
|
|
470
|
+
callToActionEmailSubject,
|
|
471
|
+
customerEmailCaptureMode,
|
|
472
|
+
customerEmailCapturePlaceholder,
|
|
417
473
|
}) => {
|
|
418
474
|
const convAgentProfile = getAgent(activeConv.agentId);
|
|
419
475
|
const convAgentMetadata = convAgentProfile?.metadata;
|
|
420
476
|
const isVisible = currentConversationId === activeConv.conversationId;
|
|
421
477
|
|
|
478
|
+
|
|
422
479
|
// Memoize callbacks to prevent recreating on every render
|
|
423
480
|
const historyCallback = useCallback(
|
|
424
481
|
(history: Record<string, { content: string; callId: string }>) => {
|
|
@@ -505,7 +562,7 @@ const ChatPanelWrapper = (({
|
|
|
505
562
|
customer={effectiveCustomer}
|
|
506
563
|
showPoweredBy={showPoweredBy}
|
|
507
564
|
showNewConversationButton={false}
|
|
508
|
-
createConversationOnFirstChat={
|
|
565
|
+
createConversationOnFirstChat={convAgentProfile?.createConversationOnFirstChat ?? true}
|
|
509
566
|
mcpServers={mcpServers}
|
|
510
567
|
actions={actions}
|
|
511
568
|
followOnQuestions={effectiveFollowOnQuestions}
|
|
@@ -520,7 +577,24 @@ const ChatPanelWrapper = (({
|
|
|
520
577
|
totalContextTokens={totalContextTokens}
|
|
521
578
|
maxContextTokens={maxContextTokens}
|
|
522
579
|
enableContextDetailView={enableContextDetailView}
|
|
580
|
+
disabledSectionIds={disabledSectionIds}
|
|
581
|
+
onToggleSection={onToggleSection}
|
|
523
582
|
onConversationCreated={conversationCreatedCallback}
|
|
583
|
+
cssUrl={cssUrl}
|
|
584
|
+
markdownClass={markdownClass}
|
|
585
|
+
width={width}
|
|
586
|
+
height={height}
|
|
587
|
+
scrollToEnd={scrollToEnd ?? convAgentMetadata.displayAutoScroll}
|
|
588
|
+
prismStyle={prismStyle}
|
|
589
|
+
showSaveButton={showSaveButton ?? convAgentMetadata.displayShowSaveButton ?? true}
|
|
590
|
+
showEmailButton={showEmailButton ?? convAgentMetadata.displayShowEmailButton ?? true}
|
|
591
|
+
messages={messages}
|
|
592
|
+
showCallToAction={showCallToAction ?? convAgentMetadata.displayShowCallToAction ?? false}
|
|
593
|
+
callToActionButtonText={callToActionButtonText ?? convAgentMetadata.displayCallToActionButtonText ?? 'Submit'}
|
|
594
|
+
callToActionEmailAddress={callToActionEmailAddress ?? convAgentMetadata.displayCallToActionEmailAddress ?? ''}
|
|
595
|
+
callToActionEmailSubject={callToActionEmailSubject ?? convAgentMetadata.displayCallToActionEmailSubject ?? 'Agent CTA submitted'}
|
|
596
|
+
customerEmailCaptureMode={customerEmailCaptureMode ?? convAgentMetadata?.customerEmailCaptureMode ?? 'HIDE'}
|
|
597
|
+
customerEmailCapturePlaceholder={customerEmailCapturePlaceholder ?? convAgentMetadata?.customerEmailCapturePlaceholder ?? 'Please enter your email...'}
|
|
524
598
|
/>
|
|
525
599
|
</div>
|
|
526
600
|
);
|
|
@@ -531,6 +605,7 @@ ChatPanelWrapper.displayName = 'ChatPanelWrapper';
|
|
|
531
605
|
const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
532
606
|
agents,
|
|
533
607
|
defaultAgent,
|
|
608
|
+
selectedAgent,
|
|
534
609
|
customerId,
|
|
535
610
|
apiKey,
|
|
536
611
|
context,
|
|
@@ -568,6 +643,22 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
568
643
|
followOnPrompt = '',
|
|
569
644
|
historyListLimit = 50,
|
|
570
645
|
showConversationHistory = true,
|
|
646
|
+
// New props from ChatPanel port
|
|
647
|
+
cssUrl,
|
|
648
|
+
markdownClass,
|
|
649
|
+
width,
|
|
650
|
+
height,
|
|
651
|
+
scrollToEnd,
|
|
652
|
+
prismStyle,
|
|
653
|
+
showSaveButton,
|
|
654
|
+
showEmailButton,
|
|
655
|
+
messages,
|
|
656
|
+
showCallToAction,
|
|
657
|
+
callToActionButtonText,
|
|
658
|
+
callToActionEmailAddress,
|
|
659
|
+
callToActionEmailSubject,
|
|
660
|
+
customerEmailCaptureMode,
|
|
661
|
+
customerEmailCapturePlaceholder,
|
|
571
662
|
}, ref) => {
|
|
572
663
|
// Panel state - only start collapsed if collapsible is true
|
|
573
664
|
const [isCollapsed, setIsCollapsed] = useState(collapsible && defaultCollapsed);
|
|
@@ -625,6 +716,36 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
625
716
|
defaultAgent || agentIds[0] || ''
|
|
626
717
|
);
|
|
627
718
|
|
|
719
|
+
// Sync with controlled selectedAgent prop when it changes
|
|
720
|
+
useEffect(() => {
|
|
721
|
+
// Only sync if selectedAgent is provided (controlled mode) and differs from current
|
|
722
|
+
if (selectedAgent && selectedAgent !== currentAgentId) {
|
|
723
|
+
const oldAgentId = currentAgentId;
|
|
724
|
+
setCurrentAgentId(selectedAgent);
|
|
725
|
+
|
|
726
|
+
// Fire onAgentSwitch callback for programmatic changes too
|
|
727
|
+
if (onAgentSwitch) {
|
|
728
|
+
onAgentSwitch(oldAgentId, selectedAgent);
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Update the current conversation's agent ID to match
|
|
732
|
+
if (currentConversationIdRef.current) {
|
|
733
|
+
setActiveConversations(prev => {
|
|
734
|
+
const existing = prev.get(currentConversationIdRef.current!);
|
|
735
|
+
if (existing) {
|
|
736
|
+
const next = new Map(prev);
|
|
737
|
+
next.set(currentConversationIdRef.current!, {
|
|
738
|
+
...existing,
|
|
739
|
+
agentId: selectedAgent,
|
|
740
|
+
});
|
|
741
|
+
return next;
|
|
742
|
+
}
|
|
743
|
+
return prev;
|
|
744
|
+
});
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
}, [selectedAgent]); // Note: intentionally excluding currentAgentId and onAgentSwitch to only trigger on prop change
|
|
748
|
+
|
|
628
749
|
// API-based conversation state
|
|
629
750
|
const [apiConversations, setApiConversations] = useState<APIConversationSummary[]>([]);
|
|
630
751
|
const [conversationsLoading, setConversationsLoading] = useState(false);
|
|
@@ -651,6 +772,9 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
651
772
|
'Older': false,
|
|
652
773
|
});
|
|
653
774
|
|
|
775
|
+
// Context section toggle state (per-conversation disabled sections)
|
|
776
|
+
const [disabledContextSections, setDisabledContextSections] = useState<Map<string, Set<string>>>(new Map());
|
|
777
|
+
|
|
654
778
|
// Agent registry hook
|
|
655
779
|
const {
|
|
656
780
|
agents: agentProfiles,
|
|
@@ -864,14 +988,9 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
864
988
|
|
|
865
989
|
setConversationsLoading(true);
|
|
866
990
|
setConversationsError(null);
|
|
867
|
-
console.log("projectId", projectId);
|
|
868
|
-
console.log("customerId", customerId);
|
|
869
|
-
console.log("apiKey", apiKey);
|
|
870
991
|
|
|
871
992
|
try {
|
|
872
|
-
console.log('fetchConversations - customerId:', customerId);
|
|
873
993
|
const url = `https://api.llmasaservice.io/conversations?customer_id=${customerId}`;
|
|
874
|
-
console.log('fetchConversations - URL:', url);
|
|
875
994
|
|
|
876
995
|
const response = await fetch(url, {
|
|
877
996
|
signal,
|
|
@@ -1428,9 +1547,30 @@ console.log("apiKey", apiKey);
|
|
|
1428
1547
|
}
|
|
1429
1548
|
}, [pageContextSections, currentAgentId, agentIds, getAgent, localOverrides]);
|
|
1430
1549
|
|
|
1550
|
+
// Get disabled sections for current conversation
|
|
1551
|
+
const currentDisabledSections = useMemo((): Set<string> => {
|
|
1552
|
+
return currentConversationId
|
|
1553
|
+
? disabledContextSections.get(currentConversationId) || new Set<string>()
|
|
1554
|
+
: new Set<string>();
|
|
1555
|
+
}, [currentConversationId, disabledContextSections]);
|
|
1556
|
+
|
|
1557
|
+
// Filtered context (only enabled sections)
|
|
1558
|
+
const filteredContext = useMemo(() => {
|
|
1559
|
+
const enabledSections = mergedContext.sections.filter(
|
|
1560
|
+
section => !currentDisabledSections.has(section.id)
|
|
1561
|
+
);
|
|
1562
|
+
const totalTokens = enabledSections.reduce((sum, s) => sum + (s.tokens || 0), 0);
|
|
1563
|
+
|
|
1564
|
+
return {
|
|
1565
|
+
sections: enabledSections,
|
|
1566
|
+
totalTokens,
|
|
1567
|
+
};
|
|
1568
|
+
}, [mergedContext.sections, currentDisabledSections]);
|
|
1569
|
+
|
|
1431
1570
|
// Build data array for ChatPanel
|
|
1432
1571
|
const chatPanelData = useMemo(() => {
|
|
1433
|
-
|
|
1572
|
+
// Use filtered sections (disabled sections are excluded)
|
|
1573
|
+
const contextData = filteredContext.sections.map((section) => ({
|
|
1434
1574
|
key: section.id,
|
|
1435
1575
|
data: JSON.stringify(section.data),
|
|
1436
1576
|
}));
|
|
@@ -1447,7 +1587,7 @@ console.log("apiKey", apiKey);
|
|
|
1447
1587
|
}
|
|
1448
1588
|
|
|
1449
1589
|
return [...data, ...contextData];
|
|
1450
|
-
}, [data,
|
|
1590
|
+
}, [data, filteredContext.sections, buildAgentAwarenessInstructions, currentAgentId, enableAgentSuggestions]);
|
|
1451
1591
|
|
|
1452
1592
|
// Handle agent switch - updates the agent for the current conversation without starting a new one
|
|
1453
1593
|
const handleAgentSwitch = useCallback(
|
|
@@ -1616,6 +1756,26 @@ console.log("apiKey", apiKey);
|
|
|
1616
1756
|
setHandoffSource('agent');
|
|
1617
1757
|
}, []);
|
|
1618
1758
|
|
|
1759
|
+
// Handle context section toggle for current conversation
|
|
1760
|
+
const handleContextSectionToggle = useCallback((sectionId: string, enabled: boolean) => {
|
|
1761
|
+
if (!currentConversationId) return;
|
|
1762
|
+
|
|
1763
|
+
setDisabledContextSections(prev => {
|
|
1764
|
+
const next = new Map(prev);
|
|
1765
|
+
const conversationDisabled = next.get(currentConversationId) || new Set();
|
|
1766
|
+
const nextDisabled = new Set(conversationDisabled);
|
|
1767
|
+
|
|
1768
|
+
if (enabled) {
|
|
1769
|
+
nextDisabled.delete(sectionId);
|
|
1770
|
+
} else {
|
|
1771
|
+
nextDisabled.add(sectionId);
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
next.set(currentConversationId, nextDisabled);
|
|
1775
|
+
return next;
|
|
1776
|
+
});
|
|
1777
|
+
}, [currentConversationId]);
|
|
1778
|
+
|
|
1619
1779
|
// Handle conversation created - update temp ID to real ID from API
|
|
1620
1780
|
const handleConversationCreated = useCallback((tempId: string, realId: string) => {
|
|
1621
1781
|
console.log('Conversation created:', tempId, '->', realId);
|
|
@@ -2113,11 +2273,28 @@ console.log("apiKey", apiKey);
|
|
|
2113
2273
|
handleAgentSwitch={handleAgentSwitch}
|
|
2114
2274
|
agentsLoading={agentsLoading}
|
|
2115
2275
|
contextSections={mergedContext.sections}
|
|
2116
|
-
totalContextTokens={
|
|
2276
|
+
totalContextTokens={filteredContext.totalTokens}
|
|
2117
2277
|
maxContextTokens={maxContextTokens}
|
|
2118
2278
|
enableContextDetailView={enableContextDetailView}
|
|
2279
|
+
disabledSectionIds={currentDisabledSections}
|
|
2280
|
+
onToggleSection={handleContextSectionToggle}
|
|
2119
2281
|
onConversationCreated={handleConversationCreated}
|
|
2120
2282
|
conversationInitialPrompt={activeConv.conversationInitialPrompt}
|
|
2283
|
+
cssUrl={cssUrl}
|
|
2284
|
+
markdownClass={markdownClass}
|
|
2285
|
+
width={width}
|
|
2286
|
+
height={height}
|
|
2287
|
+
scrollToEnd={scrollToEnd}
|
|
2288
|
+
prismStyle={prismStyle}
|
|
2289
|
+
showSaveButton={showSaveButton}
|
|
2290
|
+
showEmailButton={showEmailButton}
|
|
2291
|
+
messages={messages}
|
|
2292
|
+
showCallToAction={showCallToAction}
|
|
2293
|
+
callToActionButtonText={callToActionButtonText}
|
|
2294
|
+
callToActionEmailAddress={callToActionEmailAddress}
|
|
2295
|
+
callToActionEmailSubject={callToActionEmailSubject}
|
|
2296
|
+
customerEmailCaptureMode={customerEmailCaptureMode}
|
|
2297
|
+
customerEmailCapturePlaceholder={customerEmailCapturePlaceholder}
|
|
2121
2298
|
/>
|
|
2122
2299
|
))}
|
|
2123
2300
|
|