@hef2024/llmasaservice-ui 0.20.2 → 0.21.0
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.js +77 -32
- package/dist/index.mjs +77 -32
- package/package.json +1 -1
- package/src/AIAgentPanel.tsx +118 -49
package/dist/index.js
CHANGED
|
@@ -5698,9 +5698,13 @@ var AIAgentPanel = import_react14.default.forwardRef(({
|
|
|
5698
5698
|
const [currentAgentId, setCurrentAgentId] = (0, import_react14.useState)(
|
|
5699
5699
|
defaultAgent || agentIds[0] || ""
|
|
5700
5700
|
);
|
|
5701
|
+
const [pendingFollowOnPrompt, setPendingFollowOnPrompt] = (0, import_react14.useState)(null);
|
|
5702
|
+
const [agentSwitchSettled, setAgentSwitchSettled] = (0, import_react14.useState)(true);
|
|
5703
|
+
const lastProcessedFollowOnRef = (0, import_react14.useRef)("");
|
|
5701
5704
|
(0, import_react14.useEffect)(() => {
|
|
5702
5705
|
if (selectedAgent && selectedAgent !== currentAgentId) {
|
|
5703
5706
|
const oldAgentId = currentAgentId;
|
|
5707
|
+
setAgentSwitchSettled(false);
|
|
5704
5708
|
setCurrentAgentId(selectedAgent);
|
|
5705
5709
|
if (onAgentSwitch) {
|
|
5706
5710
|
onAgentSwitch(oldAgentId, selectedAgent);
|
|
@@ -5720,6 +5724,37 @@ var AIAgentPanel = import_react14.default.forwardRef(({
|
|
|
5720
5724
|
}
|
|
5721
5725
|
}
|
|
5722
5726
|
}, [selectedAgent]);
|
|
5727
|
+
(0, import_react14.useEffect)(() => {
|
|
5728
|
+
if (!agentSwitchSettled && followOnPrompt && followOnPrompt !== "" && followOnPrompt !== lastProcessedFollowOnRef.current) {
|
|
5729
|
+
setPendingFollowOnPrompt(followOnPrompt);
|
|
5730
|
+
lastProcessedFollowOnRef.current = followOnPrompt;
|
|
5731
|
+
}
|
|
5732
|
+
}, [followOnPrompt, agentSwitchSettled]);
|
|
5733
|
+
(0, import_react14.useEffect)(() => {
|
|
5734
|
+
if (!agentSwitchSettled) {
|
|
5735
|
+
const timer = setTimeout(() => {
|
|
5736
|
+
setAgentSwitchSettled(true);
|
|
5737
|
+
}, 100);
|
|
5738
|
+
return () => clearTimeout(timer);
|
|
5739
|
+
}
|
|
5740
|
+
}, [agentSwitchSettled]);
|
|
5741
|
+
const effectiveFollowOnPrompt = (0, import_react14.useMemo)(() => {
|
|
5742
|
+
if (!agentSwitchSettled) {
|
|
5743
|
+
return "";
|
|
5744
|
+
}
|
|
5745
|
+
if (pendingFollowOnPrompt) {
|
|
5746
|
+
return pendingFollowOnPrompt;
|
|
5747
|
+
}
|
|
5748
|
+
return followOnPrompt;
|
|
5749
|
+
}, [followOnPrompt, pendingFollowOnPrompt, agentSwitchSettled]);
|
|
5750
|
+
(0, import_react14.useEffect)(() => {
|
|
5751
|
+
if (agentSwitchSettled && pendingFollowOnPrompt) {
|
|
5752
|
+
const timer = setTimeout(() => {
|
|
5753
|
+
setPendingFollowOnPrompt(null);
|
|
5754
|
+
}, 100);
|
|
5755
|
+
return () => clearTimeout(timer);
|
|
5756
|
+
}
|
|
5757
|
+
}, [agentSwitchSettled, pendingFollowOnPrompt]);
|
|
5723
5758
|
const [apiConversations, setApiConversations] = (0, import_react14.useState)([]);
|
|
5724
5759
|
const [conversationsLoading, setConversationsLoading] = (0, import_react14.useState)(false);
|
|
5725
5760
|
const [conversationsError, setConversationsError] = (0, import_react14.useState)(null);
|
|
@@ -5917,22 +5952,6 @@ var AIAgentPanel = import_react14.default.forwardRef(({
|
|
|
5917
5952
|
}
|
|
5918
5953
|
}
|
|
5919
5954
|
}), [apiKey, customerId, getAgent, fetchFirstPrompt]);
|
|
5920
|
-
const stripContextFromPrompt = (0, import_react14.useCallback)((prompt) => {
|
|
5921
|
-
let cleanPrompt = prompt;
|
|
5922
|
-
const contextIndex = cleanPrompt.indexOf("---context---");
|
|
5923
|
-
if (contextIndex !== -1) {
|
|
5924
|
-
cleanPrompt = cleanPrompt.substring(0, contextIndex).trim();
|
|
5925
|
-
}
|
|
5926
|
-
const isoTimestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z:/;
|
|
5927
|
-
if (isoTimestampRegex.test(cleanPrompt)) {
|
|
5928
|
-
const colonIndex = cleanPrompt.indexOf(":", 19);
|
|
5929
|
-
cleanPrompt = cleanPrompt.substring(colonIndex + 1);
|
|
5930
|
-
} else if (/^\d+:/.test(cleanPrompt)) {
|
|
5931
|
-
const colonIndex = cleanPrompt.indexOf(":");
|
|
5932
|
-
cleanPrompt = cleanPrompt.substring(colonIndex + 1);
|
|
5933
|
-
}
|
|
5934
|
-
return cleanPrompt.trim();
|
|
5935
|
-
}, []);
|
|
5936
5955
|
const loadConversationTranscript = (0, import_react14.useCallback)((conversationId, agentIdForConversation, title) => __async(void 0, null, function* () {
|
|
5937
5956
|
var _a2;
|
|
5938
5957
|
const existingActive = activeConversationsRef.current.get(conversationId);
|
|
@@ -5969,23 +5988,49 @@ var AIAgentPanel = import_react14.default.forwardRef(({
|
|
|
5969
5988
|
const history = {};
|
|
5970
5989
|
let firstPrompt = null;
|
|
5971
5990
|
if (Array.isArray(payload) && payload.length > 0) {
|
|
5972
|
-
payload.
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5991
|
+
const lastCall = payload[payload.length - 1];
|
|
5992
|
+
const callId = lastCall.id || "";
|
|
5993
|
+
const timestamp = lastCall.createdAt || lastCall.created_at || (/* @__PURE__ */ new Date()).toISOString();
|
|
5994
|
+
if (lastCall.messages) {
|
|
5995
|
+
try {
|
|
5996
|
+
const messages2 = JSON.parse(lastCall.messages);
|
|
5997
|
+
console.log("loadConversationTranscript - parsed messages:", messages2);
|
|
5998
|
+
const relevantMessages = messages2.filter(
|
|
5999
|
+
(msg) => msg.role !== "system" && !(msg.role === "user" && msg.content.startsWith("__system__:"))
|
|
6000
|
+
);
|
|
6001
|
+
console.log("loadConversationTranscript - filtered messages:", relevantMessages);
|
|
6002
|
+
for (let i = 0; i < relevantMessages.length; i++) {
|
|
6003
|
+
const msg = relevantMessages[i];
|
|
6004
|
+
if (!msg) continue;
|
|
6005
|
+
if (msg.role === "user") {
|
|
6006
|
+
if (!firstPrompt) {
|
|
6007
|
+
firstPrompt = msg.content.length > 60 ? msg.content.slice(0, 57) + "..." : msg.content;
|
|
6008
|
+
}
|
|
6009
|
+
const nextMsg = relevantMessages[i + 1];
|
|
6010
|
+
if (nextMsg && nextMsg.role === "assistant") {
|
|
6011
|
+
const historyKey = `${timestamp}:${msg.content}`;
|
|
6012
|
+
history[historyKey] = {
|
|
6013
|
+
content: nextMsg.content,
|
|
6014
|
+
callId
|
|
6015
|
+
};
|
|
6016
|
+
i++;
|
|
6017
|
+
} else {
|
|
6018
|
+
if (lastCall.response) {
|
|
6019
|
+
const historyKey = `${timestamp}:${msg.content}`;
|
|
6020
|
+
history[historyKey] = {
|
|
6021
|
+
content: lastCall.response,
|
|
6022
|
+
callId
|
|
6023
|
+
};
|
|
6024
|
+
}
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
5979
6027
|
}
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
history[historyKey] = {
|
|
5983
|
-
content: call.response,
|
|
5984
|
-
callId: call.id || ""
|
|
5985
|
-
};
|
|
6028
|
+
} catch (err) {
|
|
6029
|
+
console.error("loadConversationTranscript - failed to parse messages property:", err);
|
|
5986
6030
|
}
|
|
5987
|
-
}
|
|
6031
|
+
}
|
|
5988
6032
|
}
|
|
6033
|
+
console.log("loadConversationTranscript - created", Object.keys(history).length, "history entries");
|
|
5989
6034
|
console.log("loadConversationTranscript - parsed history:", history);
|
|
5990
6035
|
if (firstPrompt) {
|
|
5991
6036
|
setConversationFirstPrompts((prev) => __spreadProps(__spreadValues({}, prev), {
|
|
@@ -6016,7 +6061,7 @@ var AIAgentPanel = import_react14.default.forwardRef(({
|
|
|
6016
6061
|
setConversationsError(error.message || "Failed to load conversation");
|
|
6017
6062
|
setLoadingConversationId(null);
|
|
6018
6063
|
}
|
|
6019
|
-
}), [apiKey, currentAgentId, getAgent, onConversationChange
|
|
6064
|
+
}), [apiKey, currentAgentId, getAgent, onConversationChange]);
|
|
6020
6065
|
const handleRefreshConversations = (0, import_react14.useCallback)(() => {
|
|
6021
6066
|
fetchConversations(currentAgentId);
|
|
6022
6067
|
}, [currentAgentId, fetchConversations]);
|
|
@@ -6766,7 +6811,7 @@ var AIAgentPanel = import_react14.default.forwardRef(({
|
|
|
6766
6811
|
initialMessage,
|
|
6767
6812
|
hideInitialPrompt,
|
|
6768
6813
|
followOnQuestions,
|
|
6769
|
-
followOnPrompt,
|
|
6814
|
+
followOnPrompt: effectiveFollowOnPrompt,
|
|
6770
6815
|
agentOptions,
|
|
6771
6816
|
currentAgentId,
|
|
6772
6817
|
handleAgentSwitch,
|
package/dist/index.mjs
CHANGED
|
@@ -5665,9 +5665,13 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
5665
5665
|
const [currentAgentId, setCurrentAgentId] = useState8(
|
|
5666
5666
|
defaultAgent || agentIds[0] || ""
|
|
5667
5667
|
);
|
|
5668
|
+
const [pendingFollowOnPrompt, setPendingFollowOnPrompt] = useState8(null);
|
|
5669
|
+
const [agentSwitchSettled, setAgentSwitchSettled] = useState8(true);
|
|
5670
|
+
const lastProcessedFollowOnRef = useRef6("");
|
|
5668
5671
|
useEffect9(() => {
|
|
5669
5672
|
if (selectedAgent && selectedAgent !== currentAgentId) {
|
|
5670
5673
|
const oldAgentId = currentAgentId;
|
|
5674
|
+
setAgentSwitchSettled(false);
|
|
5671
5675
|
setCurrentAgentId(selectedAgent);
|
|
5672
5676
|
if (onAgentSwitch) {
|
|
5673
5677
|
onAgentSwitch(oldAgentId, selectedAgent);
|
|
@@ -5687,6 +5691,37 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
5687
5691
|
}
|
|
5688
5692
|
}
|
|
5689
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]);
|
|
5690
5725
|
const [apiConversations, setApiConversations] = useState8([]);
|
|
5691
5726
|
const [conversationsLoading, setConversationsLoading] = useState8(false);
|
|
5692
5727
|
const [conversationsError, setConversationsError] = useState8(null);
|
|
@@ -5884,22 +5919,6 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
5884
5919
|
}
|
|
5885
5920
|
}
|
|
5886
5921
|
}), [apiKey, customerId, getAgent, fetchFirstPrompt]);
|
|
5887
|
-
const stripContextFromPrompt = useCallback4((prompt) => {
|
|
5888
|
-
let cleanPrompt = prompt;
|
|
5889
|
-
const contextIndex = cleanPrompt.indexOf("---context---");
|
|
5890
|
-
if (contextIndex !== -1) {
|
|
5891
|
-
cleanPrompt = cleanPrompt.substring(0, contextIndex).trim();
|
|
5892
|
-
}
|
|
5893
|
-
const isoTimestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z:/;
|
|
5894
|
-
if (isoTimestampRegex.test(cleanPrompt)) {
|
|
5895
|
-
const colonIndex = cleanPrompt.indexOf(":", 19);
|
|
5896
|
-
cleanPrompt = cleanPrompt.substring(colonIndex + 1);
|
|
5897
|
-
} else if (/^\d+:/.test(cleanPrompt)) {
|
|
5898
|
-
const colonIndex = cleanPrompt.indexOf(":");
|
|
5899
|
-
cleanPrompt = cleanPrompt.substring(colonIndex + 1);
|
|
5900
|
-
}
|
|
5901
|
-
return cleanPrompt.trim();
|
|
5902
|
-
}, []);
|
|
5903
5922
|
const loadConversationTranscript = useCallback4((conversationId, agentIdForConversation, title) => __async(void 0, null, function* () {
|
|
5904
5923
|
var _a2;
|
|
5905
5924
|
const existingActive = activeConversationsRef.current.get(conversationId);
|
|
@@ -5936,23 +5955,49 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
5936
5955
|
const history = {};
|
|
5937
5956
|
let firstPrompt = null;
|
|
5938
5957
|
if (Array.isArray(payload) && payload.length > 0) {
|
|
5939
|
-
payload.
|
|
5940
|
-
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
5944
|
-
|
|
5945
|
-
|
|
5958
|
+
const lastCall = payload[payload.length - 1];
|
|
5959
|
+
const callId = lastCall.id || "";
|
|
5960
|
+
const timestamp = lastCall.createdAt || lastCall.created_at || (/* @__PURE__ */ new Date()).toISOString();
|
|
5961
|
+
if (lastCall.messages) {
|
|
5962
|
+
try {
|
|
5963
|
+
const messages2 = JSON.parse(lastCall.messages);
|
|
5964
|
+
console.log("loadConversationTranscript - parsed messages:", messages2);
|
|
5965
|
+
const relevantMessages = messages2.filter(
|
|
5966
|
+
(msg) => msg.role !== "system" && !(msg.role === "user" && msg.content.startsWith("__system__:"))
|
|
5967
|
+
);
|
|
5968
|
+
console.log("loadConversationTranscript - filtered messages:", relevantMessages);
|
|
5969
|
+
for (let i = 0; i < relevantMessages.length; i++) {
|
|
5970
|
+
const msg = relevantMessages[i];
|
|
5971
|
+
if (!msg) continue;
|
|
5972
|
+
if (msg.role === "user") {
|
|
5973
|
+
if (!firstPrompt) {
|
|
5974
|
+
firstPrompt = msg.content.length > 60 ? msg.content.slice(0, 57) + "..." : msg.content;
|
|
5975
|
+
}
|
|
5976
|
+
const nextMsg = relevantMessages[i + 1];
|
|
5977
|
+
if (nextMsg && nextMsg.role === "assistant") {
|
|
5978
|
+
const historyKey = `${timestamp}:${msg.content}`;
|
|
5979
|
+
history[historyKey] = {
|
|
5980
|
+
content: nextMsg.content,
|
|
5981
|
+
callId
|
|
5982
|
+
};
|
|
5983
|
+
i++;
|
|
5984
|
+
} else {
|
|
5985
|
+
if (lastCall.response) {
|
|
5986
|
+
const historyKey = `${timestamp}:${msg.content}`;
|
|
5987
|
+
history[historyKey] = {
|
|
5988
|
+
content: lastCall.response,
|
|
5989
|
+
callId
|
|
5990
|
+
};
|
|
5991
|
+
}
|
|
5992
|
+
}
|
|
5993
|
+
}
|
|
5946
5994
|
}
|
|
5947
|
-
|
|
5948
|
-
|
|
5949
|
-
history[historyKey] = {
|
|
5950
|
-
content: call.response,
|
|
5951
|
-
callId: call.id || ""
|
|
5952
|
-
};
|
|
5995
|
+
} catch (err) {
|
|
5996
|
+
console.error("loadConversationTranscript - failed to parse messages property:", err);
|
|
5953
5997
|
}
|
|
5954
|
-
}
|
|
5998
|
+
}
|
|
5955
5999
|
}
|
|
6000
|
+
console.log("loadConversationTranscript - created", Object.keys(history).length, "history entries");
|
|
5956
6001
|
console.log("loadConversationTranscript - parsed history:", history);
|
|
5957
6002
|
if (firstPrompt) {
|
|
5958
6003
|
setConversationFirstPrompts((prev) => __spreadProps(__spreadValues({}, prev), {
|
|
@@ -5983,7 +6028,7 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
5983
6028
|
setConversationsError(error.message || "Failed to load conversation");
|
|
5984
6029
|
setLoadingConversationId(null);
|
|
5985
6030
|
}
|
|
5986
|
-
}), [apiKey, currentAgentId, getAgent, onConversationChange
|
|
6031
|
+
}), [apiKey, currentAgentId, getAgent, onConversationChange]);
|
|
5987
6032
|
const handleRefreshConversations = useCallback4(() => {
|
|
5988
6033
|
fetchConversations(currentAgentId);
|
|
5989
6034
|
}, [currentAgentId, fetchConversations]);
|
|
@@ -6733,7 +6778,7 @@ var AIAgentPanel = React13.forwardRef(({
|
|
|
6733
6778
|
initialMessage,
|
|
6734
6779
|
hideInitialPrompt,
|
|
6735
6780
|
followOnQuestions,
|
|
6736
|
-
followOnPrompt,
|
|
6781
|
+
followOnPrompt: effectiveFollowOnPrompt,
|
|
6737
6782
|
agentOptions,
|
|
6738
6783
|
currentAgentId,
|
|
6739
6784
|
handleAgentSwitch,
|
package/package.json
CHANGED
package/src/AIAgentPanel.tsx
CHANGED
|
@@ -716,11 +716,20 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
716
716
|
defaultAgent || agentIds[0] || ''
|
|
717
717
|
);
|
|
718
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
|
+
|
|
719
724
|
// Sync with controlled selectedAgent prop when it changes
|
|
720
725
|
useEffect(() => {
|
|
721
726
|
// Only sync if selectedAgent is provided (controlled mode) and differs from current
|
|
722
727
|
if (selectedAgent && selectedAgent !== currentAgentId) {
|
|
723
728
|
const oldAgentId = currentAgentId;
|
|
729
|
+
|
|
730
|
+
// Mark that an agent switch is in progress (not yet settled)
|
|
731
|
+
setAgentSwitchSettled(false);
|
|
732
|
+
|
|
724
733
|
setCurrentAgentId(selectedAgent);
|
|
725
734
|
|
|
726
735
|
// Fire onAgentSwitch callback for programmatic changes too
|
|
@@ -744,7 +753,54 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
744
753
|
});
|
|
745
754
|
}
|
|
746
755
|
}
|
|
747
|
-
}, [selectedAgent]); // Note: intentionally excluding
|
|
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]);
|
|
748
804
|
|
|
749
805
|
// API-based conversation state
|
|
750
806
|
const [apiConversations, setApiConversations] = useState<APIConversationSummary[]>([]);
|
|
@@ -1036,28 +1092,6 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
1036
1092
|
}, [apiKey, customerId, getAgent, fetchFirstPrompt]);
|
|
1037
1093
|
|
|
1038
1094
|
// Helper to strip context/template data from a prompt - keeps only the user's actual message
|
|
1039
|
-
const stripContextFromPrompt = useCallback((prompt: string): string => {
|
|
1040
|
-
let cleanPrompt = prompt;
|
|
1041
|
-
|
|
1042
|
-
// Strip ---context--- block and everything after it
|
|
1043
|
-
const contextIndex = cleanPrompt.indexOf('---context---');
|
|
1044
|
-
if (contextIndex !== -1) {
|
|
1045
|
-
cleanPrompt = cleanPrompt.substring(0, contextIndex).trim();
|
|
1046
|
-
}
|
|
1047
|
-
|
|
1048
|
-
// Strip timestamp prefix (ISO format: 2024-01-01T00:00:00.000Z:)
|
|
1049
|
-
const isoTimestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z:/;
|
|
1050
|
-
if (isoTimestampRegex.test(cleanPrompt)) {
|
|
1051
|
-
const colonIndex = cleanPrompt.indexOf(':', 19);
|
|
1052
|
-
cleanPrompt = cleanPrompt.substring(colonIndex + 1);
|
|
1053
|
-
} else if (/^\d+:/.test(cleanPrompt)) {
|
|
1054
|
-
const colonIndex = cleanPrompt.indexOf(':');
|
|
1055
|
-
cleanPrompt = cleanPrompt.substring(colonIndex + 1);
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
return cleanPrompt.trim();
|
|
1059
|
-
}, []);
|
|
1060
|
-
|
|
1061
1095
|
// Load a specific conversation's transcript (or switch to it if already active)
|
|
1062
1096
|
const loadConversationTranscript = useCallback(async (conversationId: string, agentIdForConversation?: string, title?: string) => {
|
|
1063
1097
|
// Check if conversation is already in activeConversations (use ref to avoid dependency)
|
|
@@ -1104,40 +1138,75 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
1104
1138
|
console.log('loadConversationTranscript - API response:', payload);
|
|
1105
1139
|
|
|
1106
1140
|
// The /calls endpoint returns an array of calls
|
|
1107
|
-
//
|
|
1108
|
-
// IMPORTANT: Strip context/template data from prompts to prevent token bloat
|
|
1141
|
+
// Use the messages property from the LAST call, which contains the full conversation history
|
|
1109
1142
|
const history: Record<string, { content: string; callId: string }> = {};
|
|
1110
1143
|
let firstPrompt: string | null = null;
|
|
1111
1144
|
|
|
1112
1145
|
if (Array.isArray(payload) && payload.length > 0) {
|
|
1113
|
-
//
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1146
|
+
// Get the last call - it contains the full conversation history in the messages property
|
|
1147
|
+
const lastCall = payload[payload.length - 1];
|
|
1148
|
+
const callId = lastCall.id || '';
|
|
1149
|
+
const timestamp = lastCall.createdAt || lastCall.created_at || new Date().toISOString();
|
|
1150
|
+
|
|
1151
|
+
if (lastCall.messages) {
|
|
1152
|
+
try {
|
|
1153
|
+
// Parse the messages JSON string
|
|
1154
|
+
const messages = JSON.parse(lastCall.messages) as { role: string; content: string }[];
|
|
1155
|
+
console.log('loadConversationTranscript - parsed messages:', messages);
|
|
1120
1156
|
|
|
1121
|
-
//
|
|
1122
|
-
const
|
|
1157
|
+
// Filter out system messages and special __system__: user messages
|
|
1158
|
+
const relevantMessages = messages.filter(msg =>
|
|
1159
|
+
msg.role !== 'system' &&
|
|
1160
|
+
!(msg.role === 'user' && msg.content.startsWith('__system__:'))
|
|
1161
|
+
);
|
|
1162
|
+
console.log('loadConversationTranscript - filtered messages:', relevantMessages);
|
|
1123
1163
|
|
|
1124
|
-
//
|
|
1125
|
-
|
|
1126
|
-
|
|
1164
|
+
// Pair user/assistant messages to build history
|
|
1165
|
+
// Note: The messages array contains the INPUT to the LLM (history + new prompt)
|
|
1166
|
+
// The LAST user message needs to be paired with the call's response field
|
|
1167
|
+
for (let i = 0; i < relevantMessages.length; i++) {
|
|
1168
|
+
const msg = relevantMessages[i];
|
|
1169
|
+
|
|
1170
|
+
if (!msg) continue;
|
|
1171
|
+
|
|
1172
|
+
if (msg.role === 'user') {
|
|
1173
|
+
// Extract first prompt for conversation title
|
|
1174
|
+
if (!firstPrompt) {
|
|
1175
|
+
firstPrompt = msg.content.length > 60 ? msg.content.slice(0, 57) + '...' : msg.content;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// Look for the next assistant message in the array
|
|
1179
|
+
const nextMsg = relevantMessages[i + 1];
|
|
1180
|
+
|
|
1181
|
+
if (nextMsg && nextMsg.role === 'assistant') {
|
|
1182
|
+
// This is a historical turn - pair the user message with the assistant message from the array
|
|
1183
|
+
const historyKey = `${timestamp}:${msg.content}`;
|
|
1184
|
+
history[historyKey] = {
|
|
1185
|
+
content: nextMsg.content,
|
|
1186
|
+
callId: callId,
|
|
1187
|
+
};
|
|
1188
|
+
|
|
1189
|
+
// Skip the assistant message we just processed
|
|
1190
|
+
i++;
|
|
1191
|
+
} else {
|
|
1192
|
+
// This is the LAST user message - pair it with the response field
|
|
1193
|
+
if (lastCall.response) {
|
|
1194
|
+
const historyKey = `${timestamp}:${msg.content}`;
|
|
1195
|
+
history[historyKey] = {
|
|
1196
|
+
content: lastCall.response,
|
|
1197
|
+
callId: callId,
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1127
1202
|
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
const timestamp = call.createdAt || call.created_at || new Date().toISOString();
|
|
1131
|
-
const historyKey = `${timestamp}:${cleanedPrompt}`;
|
|
1132
|
-
|
|
1133
|
-
history[historyKey] = {
|
|
1134
|
-
content: call.response,
|
|
1135
|
-
callId: call.id || '',
|
|
1136
|
-
};
|
|
1203
|
+
} catch (err) {
|
|
1204
|
+
console.error('loadConversationTranscript - failed to parse messages property:', err);
|
|
1137
1205
|
}
|
|
1138
|
-
}
|
|
1206
|
+
}
|
|
1139
1207
|
}
|
|
1140
1208
|
|
|
1209
|
+
console.log('loadConversationTranscript - created', Object.keys(history).length, 'history entries');
|
|
1141
1210
|
console.log('loadConversationTranscript - parsed history:', history);
|
|
1142
1211
|
|
|
1143
1212
|
// Update first prompt in state if we found one
|
|
@@ -1178,7 +1247,7 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
1178
1247
|
// Clear loading state on error
|
|
1179
1248
|
setLoadingConversationId(null);
|
|
1180
1249
|
}
|
|
1181
|
-
}, [apiKey, currentAgentId, getAgent, onConversationChange
|
|
1250
|
+
}, [apiKey, currentAgentId, getAgent, onConversationChange]);
|
|
1182
1251
|
|
|
1183
1252
|
|
|
1184
1253
|
// Refresh conversations callback
|
|
@@ -2267,7 +2336,7 @@ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
|
|
|
2267
2336
|
initialMessage={initialMessage}
|
|
2268
2337
|
hideInitialPrompt={hideInitialPrompt}
|
|
2269
2338
|
followOnQuestions={followOnQuestions}
|
|
2270
|
-
followOnPrompt={
|
|
2339
|
+
followOnPrompt={effectiveFollowOnPrompt}
|
|
2271
2340
|
agentOptions={agentOptions}
|
|
2272
2341
|
currentAgentId={currentAgentId}
|
|
2273
2342
|
handleAgentSwitch={handleAgentSwitch}
|