@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 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.forEach((call, index) => {
5973
- var _a3;
5974
- if (call.prompt && call.response) {
5975
- const rawPrompt = typeof call.prompt === "string" ? call.prompt : ((_a3 = call.prompt[0]) == null ? void 0 : _a3.text) || "";
5976
- const cleanedPrompt = stripContextFromPrompt(rawPrompt);
5977
- if (index === 0 && cleanedPrompt) {
5978
- firstPrompt = cleanedPrompt.length > 60 ? cleanedPrompt.slice(0, 57) + "..." : cleanedPrompt;
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
- const timestamp = call.createdAt || call.created_at || (/* @__PURE__ */ new Date()).toISOString();
5981
- const historyKey = `${timestamp}:${cleanedPrompt}`;
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, stripContextFromPrompt]);
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.forEach((call, index) => {
5940
- var _a3;
5941
- if (call.prompt && call.response) {
5942
- const rawPrompt = typeof call.prompt === "string" ? call.prompt : ((_a3 = call.prompt[0]) == null ? void 0 : _a3.text) || "";
5943
- const cleanedPrompt = stripContextFromPrompt(rawPrompt);
5944
- if (index === 0 && cleanedPrompt) {
5945
- firstPrompt = cleanedPrompt.length > 60 ? cleanedPrompt.slice(0, 57) + "..." : cleanedPrompt;
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
- const timestamp = call.createdAt || call.created_at || (/* @__PURE__ */ new Date()).toISOString();
5948
- const historyKey = `${timestamp}:${cleanedPrompt}`;
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, stripContextFromPrompt]);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hef2024/llmasaservice-ui",
3
- "version": "0.20.2",
3
+ "version": "0.21.0",
4
4
  "description": "Prebuilt UI components for LLMAsAService.io",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -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 currentAgentId and onAgentSwitch to only trigger on prop change
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
- // Build history from all calls in chronological order
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
- // Parse all calls in order
1114
- payload.forEach((call: any, index: number) => {
1115
- if (call.prompt && call.response) {
1116
- // Get the raw prompt text
1117
- const rawPrompt = typeof call.prompt === 'string'
1118
- ? call.prompt
1119
- : call.prompt[0]?.text || '';
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
- // Strip context/template data - keep only the user's actual message
1122
- const cleanedPrompt = stripContextFromPrompt(rawPrompt);
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
- // Extract first prompt for display in list
1125
- if (index === 0 && cleanedPrompt) {
1126
- firstPrompt = cleanedPrompt.length > 60 ? cleanedPrompt.slice(0, 57) + '...' : cleanedPrompt;
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
- // Use timestamp-prefixed key to maintain order and uniqueness
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, stripContextFromPrompt]);
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={followOnPrompt}
2339
+ followOnPrompt={effectiveFollowOnPrompt}
2271
2340
  agentOptions={agentOptions}
2272
2341
  currentAgentId={currentAgentId}
2273
2342
  handleAgentSwitch={handleAgentSwitch}