@hef2024/llmasaservice-ui 0.16.8 → 0.16.9
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/DEPLOYMENT.md +193 -0
- package/dist/index.css +1951 -1886
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +326 -104
- package/dist/index.mjs +327 -105
- package/package.json +1 -1
- package/src/AIAgentPanel.css +79 -1
- package/src/AIAgentPanel.tsx +236 -23
- package/src/AIChatPanel.tsx +252 -108
- package/src/AgentPanel.tsx +1 -3
- package/src/ChatPanel.tsx +1 -7
- package/src/components/ui/Button.tsx +2 -0
- package/src/components/ui/Dialog.tsx +2 -0
- package/src/components/ui/Input.tsx +2 -0
- package/src/components/ui/Select.tsx +2 -0
- package/src/components/ui/Tooltip.tsx +2 -0
- package/src/components/ui/index.ts +2 -0
- package/src/hooks/useAgentRegistry.ts +1 -4
package/src/AIChatPanel.tsx
CHANGED
|
@@ -86,6 +86,9 @@ export interface AIChatPanelProps {
|
|
|
86
86
|
totalContextTokens?: number;
|
|
87
87
|
maxContextTokens?: number;
|
|
88
88
|
enableContextDetailView?: boolean;
|
|
89
|
+
|
|
90
|
+
// Callback when a new conversation is created via API
|
|
91
|
+
onConversationCreated?: (conversationId: string) => void;
|
|
89
92
|
}
|
|
90
93
|
|
|
91
94
|
/**
|
|
@@ -658,7 +661,14 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
658
661
|
totalContextTokens = 0,
|
|
659
662
|
maxContextTokens = 8000,
|
|
660
663
|
enableContextDetailView = false,
|
|
664
|
+
onConversationCreated,
|
|
661
665
|
}) => {
|
|
666
|
+
// ============================================================================
|
|
667
|
+
// API URL
|
|
668
|
+
// ============================================================================
|
|
669
|
+
// Public API URL for dev and production (matches ChatPanel)
|
|
670
|
+
const publicAPIUrl = 'https://api.llmasaservice.io';
|
|
671
|
+
|
|
662
672
|
// ============================================================================
|
|
663
673
|
// State
|
|
664
674
|
// ============================================================================
|
|
@@ -694,6 +704,33 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
694
704
|
// Store the latest processed history for callbacks (doesn't trigger re-renders)
|
|
695
705
|
const latestHistoryRef = useRef<Record<string, HistoryEntry>>(initialHistory);
|
|
696
706
|
|
|
707
|
+
// Sync new entries from initialHistory into local history state
|
|
708
|
+
// This allows parent components to inject messages (e.g., page-based agent suggestions)
|
|
709
|
+
useEffect(() => {
|
|
710
|
+
if (!initialHistory) return;
|
|
711
|
+
|
|
712
|
+
// Use functional update to access current history without adding it to deps
|
|
713
|
+
setHistory(prev => {
|
|
714
|
+
const currentKeys = Object.keys(prev);
|
|
715
|
+
const newEntries: Record<string, HistoryEntry> = {};
|
|
716
|
+
let hasNewEntries = false;
|
|
717
|
+
|
|
718
|
+
for (const [key, value] of Object.entries(initialHistory)) {
|
|
719
|
+
if (!currentKeys.includes(key)) {
|
|
720
|
+
newEntries[key] = value as HistoryEntry;
|
|
721
|
+
hasNewEntries = true;
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Merge new entries if any were found
|
|
726
|
+
if (hasNewEntries) {
|
|
727
|
+
return { ...prev, ...newEntries };
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
return prev; // No changes
|
|
731
|
+
});
|
|
732
|
+
}, [initialHistory]);
|
|
733
|
+
|
|
697
734
|
// ============================================================================
|
|
698
735
|
// useLLM Hook
|
|
699
736
|
// ============================================================================
|
|
@@ -754,6 +791,74 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
754
791
|
};
|
|
755
792
|
}, []);
|
|
756
793
|
|
|
794
|
+
// Ensure a conversation exists before sending the first message
|
|
795
|
+
// This creates a conversation on the server and returns the conversation ID
|
|
796
|
+
const ensureConversation = useCallback(() => {
|
|
797
|
+
console.log('ensureConversation - called with:', {
|
|
798
|
+
currentConversation,
|
|
799
|
+
createConversationOnFirstChat,
|
|
800
|
+
project_id,
|
|
801
|
+
publicAPIUrl,
|
|
802
|
+
});
|
|
803
|
+
if (
|
|
804
|
+
(!currentConversation || currentConversation === '') &&
|
|
805
|
+
createConversationOnFirstChat
|
|
806
|
+
) {
|
|
807
|
+
// Guard: Don't create conversation without a project_id
|
|
808
|
+
if (!project_id) {
|
|
809
|
+
console.error('ensureConversation - Cannot create conversation without project_id');
|
|
810
|
+
return Promise.resolve('');
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
const requestBody = {
|
|
814
|
+
project_id: project_id,
|
|
815
|
+
agentId: agent,
|
|
816
|
+
customerId: customer?.customer_id ?? null,
|
|
817
|
+
customerEmail: customer?.customer_user_email ?? null,
|
|
818
|
+
timezone: browserInfo?.userTimezone,
|
|
819
|
+
language: browserInfo?.userLanguage,
|
|
820
|
+
};
|
|
821
|
+
console.log('ensureConversation - Creating conversation with:', requestBody);
|
|
822
|
+
console.log('ensureConversation - API URL:', `${publicAPIUrl}/conversations`);
|
|
823
|
+
|
|
824
|
+
return fetch(`${publicAPIUrl}/conversations`, {
|
|
825
|
+
method: 'POST',
|
|
826
|
+
headers: {
|
|
827
|
+
'Content-Type': 'application/json',
|
|
828
|
+
},
|
|
829
|
+
body: JSON.stringify(requestBody),
|
|
830
|
+
})
|
|
831
|
+
.then(async (res) => {
|
|
832
|
+
if (!res.ok) {
|
|
833
|
+
const errorText = await res.text();
|
|
834
|
+
throw new Error(
|
|
835
|
+
`HTTP error! status: ${res.status}, message: ${errorText}`
|
|
836
|
+
);
|
|
837
|
+
}
|
|
838
|
+
return res.json();
|
|
839
|
+
})
|
|
840
|
+
.then((newConvo) => {
|
|
841
|
+
console.log('ensureConversation - API response:', newConvo);
|
|
842
|
+
if (newConvo?.id) {
|
|
843
|
+
console.log('ensureConversation - New conversation ID:', newConvo.id);
|
|
844
|
+
setCurrentConversation(newConvo.id);
|
|
845
|
+
// NOTE: Don't call onConversationCreated here - it causes a re-render
|
|
846
|
+
// before send() is called. The caller should notify after send() starts.
|
|
847
|
+
return newConvo.id;
|
|
848
|
+
}
|
|
849
|
+
console.warn('ensureConversation - No ID in response');
|
|
850
|
+
return '';
|
|
851
|
+
})
|
|
852
|
+
.catch((error) => {
|
|
853
|
+
console.error('Error creating new conversation', error);
|
|
854
|
+
return '';
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
// If a currentConversation exists, return it in a resolved Promise.
|
|
858
|
+
console.log('ensureConversation - using existing conversation:', currentConversation);
|
|
859
|
+
return Promise.resolve(currentConversation);
|
|
860
|
+
}, [currentConversation, createConversationOnFirstChat, publicAPIUrl, project_id, agent, customer, browserInfo]);
|
|
861
|
+
|
|
757
862
|
// Data with extras (matches ChatPanel's dataWithExtras)
|
|
758
863
|
const dataWithExtras = useCallback(() => {
|
|
759
864
|
return [
|
|
@@ -927,6 +1032,7 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
927
1032
|
// Continue chat (send message) - matches ChatPanel behavior exactly
|
|
928
1033
|
// promptText is now required - comes from the isolated ChatInput component
|
|
929
1034
|
const continueChat = useCallback((promptText: string) => {
|
|
1035
|
+
console.log('AIChatPanel.continueChat called with:', promptText);
|
|
930
1036
|
// Clear thinking blocks for new response
|
|
931
1037
|
setThinkingBlocks([]);
|
|
932
1038
|
setCurrentThinkingIndex(0);
|
|
@@ -957,73 +1063,88 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
957
1063
|
|
|
958
1064
|
setIsLoading(true);
|
|
959
1065
|
|
|
960
|
-
//
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
const
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
promptForHistory = historyPrompt
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1066
|
+
// Ensure conversation exists before sending (matches ChatPanel)
|
|
1067
|
+
console.log('AIChatPanel.continueChat - about to call ensureConversation');
|
|
1068
|
+
ensureConversation().then((convId) => {
|
|
1069
|
+
console.log('AIChatPanel.continueChat - ensureConversation resolved with:', convId);
|
|
1070
|
+
// Build messagesAndHistory from history (matches ChatPanel)
|
|
1071
|
+
const messagesAndHistory: { role: string; content: string }[] = [];
|
|
1072
|
+
Object.entries(history).forEach(([historyPrompt, historyEntry]) => {
|
|
1073
|
+
// Strip timestamp prefix from prompt before using it (matches ChatPanel)
|
|
1074
|
+
let promptForHistory = historyPrompt;
|
|
1075
|
+
const isoTimestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z:/;
|
|
1076
|
+
if (isoTimestampRegex.test(historyPrompt)) {
|
|
1077
|
+
const colonIndex = historyPrompt.indexOf(':', 19);
|
|
1078
|
+
promptForHistory = historyPrompt.substring(colonIndex + 1);
|
|
1079
|
+
} else if (/^\d+:/.test(historyPrompt)) {
|
|
1080
|
+
const colonIndex = historyPrompt.indexOf(':');
|
|
1081
|
+
promptForHistory = historyPrompt.substring(colonIndex + 1);
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
messagesAndHistory.push({ role: 'user', content: promptForHistory });
|
|
1085
|
+
messagesAndHistory.push({ role: 'assistant', content: historyEntry.content });
|
|
1086
|
+
});
|
|
1087
|
+
|
|
1088
|
+
// Generate unique key using ISO timestamp prefix + prompt (matches ChatPanel)
|
|
1089
|
+
const timestamp = new Date().toISOString();
|
|
1090
|
+
const promptKey = `${timestamp}:${promptToSend.trim()}`;
|
|
1091
|
+
|
|
1092
|
+
// Set history entry before sending (matches ChatPanel)
|
|
1093
|
+
setHistory((prevHistory) => ({
|
|
1094
|
+
...prevHistory,
|
|
1095
|
+
[promptKey]: { content: '', callId: '' },
|
|
1096
|
+
}));
|
|
1097
|
+
|
|
1098
|
+
// Build the full prompt - only apply template for first message (matches ChatPanel)
|
|
1099
|
+
let fullPromptToSend = promptToSend.trim();
|
|
1100
|
+
if (Object.keys(history).length === 0 && promptTemplate) {
|
|
1101
|
+
fullPromptToSend = promptTemplate.replace('{{prompt}}', fullPromptToSend);
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// Add follow-on prompt
|
|
1105
|
+
if (followOnPrompt) {
|
|
1106
|
+
fullPromptToSend += `\n\n${followOnPrompt}`;
|
|
972
1107
|
}
|
|
973
1108
|
|
|
974
|
-
|
|
975
|
-
|
|
1109
|
+
const newController = new AbortController();
|
|
1110
|
+
setLastController(newController);
|
|
1111
|
+
|
|
1112
|
+
// Pass data array to send() for template replacement (e.g., {{Context}})
|
|
1113
|
+
// Pass service (group_id) and customer data just like ChatPanel does
|
|
1114
|
+
// Use convId from ensureConversation (matches ChatPanel)
|
|
1115
|
+
send(
|
|
1116
|
+
fullPromptToSend,
|
|
1117
|
+
messagesAndHistory,
|
|
1118
|
+
[
|
|
1119
|
+
...dataWithExtras(),
|
|
1120
|
+
{ key: '--messages', data: messagesAndHistory.length.toString() },
|
|
1121
|
+
],
|
|
1122
|
+
true, // stream
|
|
1123
|
+
true, // includeHistory
|
|
1124
|
+
service, // group_id from agent config
|
|
1125
|
+
convId, // Use the conversation ID from ensureConversation
|
|
1126
|
+
newController
|
|
1127
|
+
);
|
|
1128
|
+
|
|
1129
|
+
setLastPrompt(promptToSend.trim());
|
|
1130
|
+
setLastMessages(messagesAndHistory);
|
|
1131
|
+
setLastKey(promptKey);
|
|
1132
|
+
|
|
1133
|
+
// Notify parent of new conversation ID AFTER send() has started
|
|
1134
|
+
// This prevents the component from being remounted before send() runs
|
|
1135
|
+
if (convId && onConversationCreated) {
|
|
1136
|
+
// Use setTimeout to ensure send() has fully started before triggering re-render
|
|
1137
|
+
setTimeout(() => {
|
|
1138
|
+
onConversationCreated(convId);
|
|
1139
|
+
}, 100);
|
|
1140
|
+
}
|
|
1141
|
+
|
|
1142
|
+
// Scroll to bottom after adding the new prompt to show it immediately
|
|
1143
|
+
// Use setTimeout to ensure the DOM has updated with the new history entry
|
|
1144
|
+
setTimeout(() => {
|
|
1145
|
+
scrollToBottom();
|
|
1146
|
+
}, 0);
|
|
976
1147
|
});
|
|
977
|
-
|
|
978
|
-
// Generate unique key using ISO timestamp prefix + prompt (matches ChatPanel)
|
|
979
|
-
const timestamp = new Date().toISOString();
|
|
980
|
-
const promptKey = `${timestamp}:${promptToSend.trim()}`;
|
|
981
|
-
|
|
982
|
-
// Set history entry before sending (matches ChatPanel)
|
|
983
|
-
setHistory((prevHistory) => ({
|
|
984
|
-
...prevHistory,
|
|
985
|
-
[promptKey]: { content: '', callId: '' },
|
|
986
|
-
}));
|
|
987
|
-
|
|
988
|
-
// Build the full prompt - only apply template for first message (matches ChatPanel)
|
|
989
|
-
let fullPromptToSend = promptToSend.trim();
|
|
990
|
-
if (Object.keys(history).length === 0 && promptTemplate) {
|
|
991
|
-
fullPromptToSend = promptTemplate.replace('{{prompt}}', fullPromptToSend);
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
// Add follow-on prompt
|
|
995
|
-
if (followOnPrompt) {
|
|
996
|
-
fullPromptToSend += `\n\n${followOnPrompt}`;
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
const newController = new AbortController();
|
|
1000
|
-
setLastController(newController);
|
|
1001
|
-
|
|
1002
|
-
// Pass data array to send() for template replacement (e.g., {{Context}})
|
|
1003
|
-
// Pass service (group_id) and customer data just like ChatPanel does
|
|
1004
|
-
send(
|
|
1005
|
-
fullPromptToSend,
|
|
1006
|
-
messagesAndHistory,
|
|
1007
|
-
[
|
|
1008
|
-
...dataWithExtras(),
|
|
1009
|
-
{ key: '--messages', data: messagesAndHistory.length.toString() },
|
|
1010
|
-
],
|
|
1011
|
-
true, // stream
|
|
1012
|
-
true, // includeHistory
|
|
1013
|
-
service, // group_id from agent config
|
|
1014
|
-
currentConversation,
|
|
1015
|
-
newController
|
|
1016
|
-
);
|
|
1017
|
-
|
|
1018
|
-
setLastPrompt(promptToSend.trim());
|
|
1019
|
-
setLastMessages(messagesAndHistory);
|
|
1020
|
-
setLastKey(promptKey);
|
|
1021
|
-
|
|
1022
|
-
// Scroll to bottom after adding the new prompt to show it immediately
|
|
1023
|
-
// Use setTimeout to ensure the DOM has updated with the new history entry
|
|
1024
|
-
setTimeout(() => {
|
|
1025
|
-
scrollToBottom();
|
|
1026
|
-
}, 0);
|
|
1027
1148
|
}, [
|
|
1028
1149
|
idle,
|
|
1029
1150
|
stop,
|
|
@@ -1038,9 +1159,10 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1038
1159
|
followOnPrompt,
|
|
1039
1160
|
send,
|
|
1040
1161
|
service,
|
|
1041
|
-
|
|
1162
|
+
ensureConversation,
|
|
1042
1163
|
dataWithExtras,
|
|
1043
1164
|
scrollToBottom,
|
|
1165
|
+
onConversationCreated,
|
|
1044
1166
|
]);
|
|
1045
1167
|
|
|
1046
1168
|
// Handle suggestion click - directly sends like ChatPanel does
|
|
@@ -1095,27 +1217,29 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1095
1217
|
|
|
1096
1218
|
// Effect 1: Process response for DISPLAY ONLY (no callbacks here)
|
|
1097
1219
|
// Updates state for rendering, stores in ref for later callback use
|
|
1220
|
+
// NOTE: We store RAW content (without action processing) in history state.
|
|
1221
|
+
// Actions are applied at RENDER time so that switching agents with different
|
|
1222
|
+
// actions will re-process the history correctly.
|
|
1098
1223
|
useEffect(() => {
|
|
1099
1224
|
if (!response || !lastKey || justReset) return;
|
|
1100
1225
|
|
|
1101
1226
|
const { cleanedText, blocks } = processThinkingTags(response);
|
|
1102
|
-
const processedContent = processActions(cleanedText);
|
|
1103
1227
|
|
|
1104
1228
|
// Update display state
|
|
1105
1229
|
setThinkingBlocks(blocks);
|
|
1106
1230
|
|
|
1107
|
-
// Update history state
|
|
1231
|
+
// Update history state with RAW content (actions applied at render time)
|
|
1108
1232
|
setHistory((prev) => {
|
|
1109
1233
|
const newHistory = { ...prev };
|
|
1110
1234
|
newHistory[lastKey] = {
|
|
1111
|
-
content:
|
|
1235
|
+
content: cleanedText, // Store raw content, not processed
|
|
1112
1236
|
callId: lastCallId || '',
|
|
1113
1237
|
};
|
|
1114
1238
|
// Keep ref in sync for callbacks (this doesn't trigger re-renders)
|
|
1115
1239
|
latestHistoryRef.current = newHistory;
|
|
1116
1240
|
return newHistory;
|
|
1117
1241
|
});
|
|
1118
|
-
}, [response, lastKey, lastCallId, processThinkingTags,
|
|
1242
|
+
}, [response, lastKey, lastCallId, processThinkingTags, justReset]);
|
|
1119
1243
|
|
|
1120
1244
|
// Effect 2: Handle response completion - SINGLE POINT for all completion logic
|
|
1121
1245
|
// Triggers ONLY when idle transitions from false → true
|
|
@@ -1259,47 +1383,62 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1259
1383
|
// This prevents unwanted LLM calls when switching to loaded conversations
|
|
1260
1384
|
const hasLoadedHistory = initialHistory && Object.keys(initialHistory).length > 0;
|
|
1261
1385
|
|
|
1386
|
+
// Don't proceed if project_id is not yet available
|
|
1387
|
+
if (!project_id) {
|
|
1388
|
+
return;
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1262
1391
|
if (initialPrompt && initialPrompt !== '' && initialPrompt !== lastPrompt && !hasLoadedHistory) {
|
|
1263
1392
|
setIsLoading(true);
|
|
1264
1393
|
setThinkingBlocks([]);
|
|
1265
1394
|
setCurrentThinkingIndex(0);
|
|
1266
1395
|
setUserHasScrolled(false); // Enable auto-scroll for new prompt
|
|
1267
1396
|
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
fullPrompt =
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1397
|
+
// Ensure conversation exists before sending (matches ChatPanel)
|
|
1398
|
+
ensureConversation().then((convId) => {
|
|
1399
|
+
const controller = new AbortController();
|
|
1400
|
+
setLastController(controller);
|
|
1401
|
+
|
|
1402
|
+
// Generate timestamp-prefixed key (matches ChatPanel)
|
|
1403
|
+
const timestamp = new Date().toISOString();
|
|
1404
|
+
const promptKey = `${timestamp}:${initialPrompt}`;
|
|
1405
|
+
|
|
1406
|
+
// Set history entry before sending (matches ChatPanel)
|
|
1407
|
+
setHistory({ [promptKey]: { content: '', callId: '' } });
|
|
1408
|
+
|
|
1409
|
+
// Build prompt with template
|
|
1410
|
+
let fullPrompt = initialPrompt;
|
|
1411
|
+
if (promptTemplate) {
|
|
1412
|
+
fullPrompt = promptTemplate.replace('{{prompt}}', initialPrompt);
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1415
|
+
send(
|
|
1416
|
+
fullPrompt,
|
|
1417
|
+
[],
|
|
1418
|
+
[
|
|
1419
|
+
...dataWithExtras(),
|
|
1420
|
+
{ key: '--messages', data: '0' },
|
|
1421
|
+
],
|
|
1422
|
+
true,
|
|
1423
|
+
true,
|
|
1424
|
+
service,
|
|
1425
|
+
convId, // Use conversation ID from ensureConversation
|
|
1426
|
+
controller
|
|
1427
|
+
);
|
|
1428
|
+
|
|
1429
|
+
setLastPrompt(initialPrompt);
|
|
1430
|
+
setLastMessages([]);
|
|
1431
|
+
setLastKey(promptKey);
|
|
1432
|
+
|
|
1433
|
+
// Notify parent of new conversation ID AFTER send() has started
|
|
1434
|
+
if (convId && onConversationCreated) {
|
|
1435
|
+
setTimeout(() => {
|
|
1436
|
+
onConversationCreated(convId);
|
|
1437
|
+
}, 100);
|
|
1438
|
+
}
|
|
1439
|
+
});
|
|
1301
1440
|
}
|
|
1302
|
-
}, [initialPrompt, initialHistory]);
|
|
1441
|
+
}, [initialPrompt, initialHistory, ensureConversation, promptTemplate, send, dataWithExtras, service, lastPrompt, project_id, onConversationCreated]);
|
|
1303
1442
|
|
|
1304
1443
|
// ============================================================================
|
|
1305
1444
|
// Render Helpers
|
|
@@ -1536,12 +1675,17 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1536
1675
|
{/* History */}
|
|
1537
1676
|
{Object.entries(history).map(([prompt, entry], index) => {
|
|
1538
1677
|
const isLastEntry = index === Object.keys(history).length - 1;
|
|
1678
|
+
// Check if this is a system message (injected by page context, etc.)
|
|
1679
|
+
const isSystemMessage = prompt.startsWith('__system__:');
|
|
1680
|
+
// Process thinking tags first, then apply actions at render time
|
|
1681
|
+
// This ensures actions are always applied with current props (e.g., after agent switch)
|
|
1539
1682
|
const { cleanedText } = processThinkingTags(entry.content);
|
|
1683
|
+
const processedContent = processActions(cleanedText);
|
|
1540
1684
|
|
|
1541
1685
|
return (
|
|
1542
1686
|
<div key={index} className="ai-chat-entry">
|
|
1543
|
-
{/* User Message */}
|
|
1544
|
-
{!(hideInitialPrompt && index === 0) && (
|
|
1687
|
+
{/* User Message - hidden for initial prompt or system messages */}
|
|
1688
|
+
{!(hideInitialPrompt && index === 0) && !isSystemMessage && (
|
|
1545
1689
|
<div className="ai-chat-message ai-chat-message--user">
|
|
1546
1690
|
<div className="ai-chat-message__content">
|
|
1547
1691
|
{formatPromptForDisplay(prompt)}
|
|
@@ -1557,13 +1701,13 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1557
1701
|
<div className="ai-chat-streaming">
|
|
1558
1702
|
{thinkingBlocks.length > 0 && renderThinkingBlocks()}
|
|
1559
1703
|
|
|
1560
|
-
{
|
|
1704
|
+
{processedContent ? (
|
|
1561
1705
|
<ReactMarkdown
|
|
1562
1706
|
remarkPlugins={[remarkGfm]}
|
|
1563
1707
|
rehypePlugins={[rehypeRaw]}
|
|
1564
1708
|
components={markdownComponents}
|
|
1565
1709
|
>
|
|
1566
|
-
{
|
|
1710
|
+
{processedContent}
|
|
1567
1711
|
</ReactMarkdown>
|
|
1568
1712
|
) : (
|
|
1569
1713
|
<div className="ai-chat-loading">
|
|
@@ -1584,7 +1728,7 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1584
1728
|
rehypePlugins={[rehypeRaw]}
|
|
1585
1729
|
components={markdownComponents}
|
|
1586
1730
|
>
|
|
1587
|
-
{
|
|
1731
|
+
{processedContent}
|
|
1588
1732
|
</ReactMarkdown>
|
|
1589
1733
|
</>
|
|
1590
1734
|
)}
|
package/src/AgentPanel.tsx
CHANGED
|
@@ -159,9 +159,7 @@ const AgentPanel: React.FC<AgentPanelProps & ExtraProps> = ({
|
|
|
159
159
|
useEffect(() => {
|
|
160
160
|
const fetchAgentData = async () => {
|
|
161
161
|
try {
|
|
162
|
-
const fetchUrl =
|
|
163
|
-
? `https://8ftw8droff.execute-api.us-east-1.amazonaws.com/dev/agents/${agent}`
|
|
164
|
-
: `https://api.llmasaservice.io/agents/${agent}`;
|
|
162
|
+
const fetchUrl = `https://api.llmasaservice.io/agents/${agent}`;
|
|
165
163
|
|
|
166
164
|
const response = await fetch(fetchUrl, {
|
|
167
165
|
method: "GET",
|
package/src/ChatPanel.tsx
CHANGED
|
@@ -597,13 +597,7 @@ const ChatPanel: React.FC<ChatPanelProps & ExtraProps> = ({
|
|
|
597
597
|
};
|
|
598
598
|
|
|
599
599
|
// public api url for dev and production
|
|
600
|
-
|
|
601
|
-
if (
|
|
602
|
-
window.location.hostname === "localhost" ||
|
|
603
|
-
window.location.hostname === "dev.llmasaservice.io"
|
|
604
|
-
) {
|
|
605
|
-
publicAPIUrl = "https://8ftw8droff.execute-api.us-east-1.amazonaws.com/dev";
|
|
606
|
-
}
|
|
600
|
+
const publicAPIUrl = "https://api.llmasaservice.io";
|
|
607
601
|
|
|
608
602
|
const [toolList, setToolList] = useState<any[]>([]);
|
|
609
603
|
const [toolsLoading, setToolsLoading] = useState(false);
|
|
@@ -69,10 +69,7 @@ interface UseAgentRegistryOptions {
|
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
const resolveApiEndpoint = (baseUrl: string, agentId: string): string => {
|
|
72
|
-
|
|
73
|
-
? 'https://8ftw8droff.execute-api.us-east-1.amazonaws.com/dev'
|
|
74
|
-
: 'https://api.llmasaservice.io';
|
|
75
|
-
return `${apiRoot}/agents/${agentId}`;
|
|
72
|
+
return `https://api.llmasaservice.io/agents/${agentId}`;
|
|
76
73
|
};
|
|
77
74
|
|
|
78
75
|
/**
|