@hef2024/llmasaservice-ui 0.16.10 → 0.17.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.d.mts CHANGED
@@ -170,6 +170,12 @@ interface AgentConfig {
170
170
  localName?: string;
171
171
  avatarUrl?: string;
172
172
  }
173
+ /**
174
+ * Imperative handle for programmatic control of AIAgentPanel
175
+ */
176
+ interface AIAgentPanelHandle {
177
+ startNewConversation: (prompt: string, agent?: string) => void;
178
+ }
173
179
  /**
174
180
  * Props for AIAgentPanel
175
181
  */
@@ -218,12 +224,15 @@ interface AIAgentPanelProps {
218
224
  clickCode?: string;
219
225
  style?: string;
220
226
  }[];
227
+ initialPrompt?: string;
228
+ initialMessage?: string;
229
+ hideInitialPrompt?: boolean;
221
230
  followOnQuestions?: string[];
222
231
  followOnPrompt?: string;
223
232
  historyListLimit?: number;
224
233
  showConversationHistory?: boolean;
225
234
  }
226
- declare const AIAgentPanel: React__default.FC<AIAgentPanelProps>;
235
+ declare const AIAgentPanel: React__default.ForwardRefExoticComponent<AIAgentPanelProps & React__default.RefAttributes<AIAgentPanelHandle>>;
227
236
 
228
237
  /**
229
238
  * AIChatPanel - A modern chat interface using shadcn-style components
package/dist/index.d.ts CHANGED
@@ -170,6 +170,12 @@ interface AgentConfig {
170
170
  localName?: string;
171
171
  avatarUrl?: string;
172
172
  }
173
+ /**
174
+ * Imperative handle for programmatic control of AIAgentPanel
175
+ */
176
+ interface AIAgentPanelHandle {
177
+ startNewConversation: (prompt: string, agent?: string) => void;
178
+ }
173
179
  /**
174
180
  * Props for AIAgentPanel
175
181
  */
@@ -218,12 +224,15 @@ interface AIAgentPanelProps {
218
224
  clickCode?: string;
219
225
  style?: string;
220
226
  }[];
227
+ initialPrompt?: string;
228
+ initialMessage?: string;
229
+ hideInitialPrompt?: boolean;
221
230
  followOnQuestions?: string[];
222
231
  followOnPrompt?: string;
223
232
  historyListLimit?: number;
224
233
  showConversationHistory?: boolean;
225
234
  }
226
- declare const AIAgentPanel: React__default.FC<AIAgentPanelProps>;
235
+ declare const AIAgentPanel: React__default.ForwardRefExoticComponent<AIAgentPanelProps & React__default.RefAttributes<AIAgentPanelHandle>>;
227
236
 
228
237
  /**
229
238
  * AIChatPanel - A modern chat interface using shadcn-style components
package/dist/index.js CHANGED
@@ -3669,6 +3669,7 @@ var AIChatPanel = ({
3669
3669
  const prevIdleRef = (0, import_react11.useRef)(true);
3670
3670
  const hasNotifiedCompletionRef = (0, import_react11.useRef)(true);
3671
3671
  const latestHistoryRef = (0, import_react11.useRef)(initialHistory);
3672
+ const initialPromptSentRef = (0, import_react11.useRef)(false);
3672
3673
  (0, import_react11.useEffect)(() => {
3673
3674
  if (!initialHistory) return;
3674
3675
  setHistory((prev) => {
@@ -3913,11 +3914,22 @@ var AIChatPanel = ({
3913
3914
  const promptToSend = promptText;
3914
3915
  if (!promptToSend || !promptToSend.trim()) return;
3915
3916
  setIsLoading(true);
3917
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3918
+ const promptKey = `${timestamp}:${promptToSend.trim()}`;
3919
+ setHistory((prevHistory) => __spreadProps(__spreadValues({}, prevHistory), {
3920
+ [promptKey]: { content: "", callId: "" }
3921
+ }));
3922
+ setLastPrompt(promptToSend.trim());
3923
+ setLastKey(promptKey);
3924
+ setTimeout(() => {
3925
+ scrollToBottom();
3926
+ }, 0);
3916
3927
  console.log("AIChatPanel.continueChat - about to call ensureConversation");
3917
3928
  ensureConversation().then((convId) => {
3918
3929
  console.log("AIChatPanel.continueChat - ensureConversation resolved with:", convId);
3919
3930
  const messagesAndHistory = [];
3920
3931
  Object.entries(history).forEach(([historyPrompt, historyEntry]) => {
3932
+ if (historyPrompt === promptKey) return;
3921
3933
  let promptForHistory = historyPrompt;
3922
3934
  const isoTimestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z:/;
3923
3935
  if (isoTimestampRegex.test(historyPrompt)) {
@@ -3930,13 +3942,8 @@ var AIChatPanel = ({
3930
3942
  messagesAndHistory.push({ role: "user", content: promptForHistory });
3931
3943
  messagesAndHistory.push({ role: "assistant", content: historyEntry.content });
3932
3944
  });
3933
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3934
- const promptKey = `${timestamp}:${promptToSend.trim()}`;
3935
- setHistory((prevHistory) => __spreadProps(__spreadValues({}, prevHistory), {
3936
- [promptKey]: { content: "", callId: "" }
3937
- }));
3938
3945
  let fullPromptToSend = promptToSend.trim();
3939
- if (Object.keys(history).length === 0 && promptTemplate) {
3946
+ if (messagesAndHistory.length === 0 && promptTemplate) {
3940
3947
  fullPromptToSend = promptTemplate.replace("{{prompt}}", fullPromptToSend);
3941
3948
  }
3942
3949
  if (followOnPrompt) {
@@ -3963,17 +3970,12 @@ ${followOnPrompt}`;
3963
3970
  // Use the conversation ID from ensureConversation
3964
3971
  newController
3965
3972
  );
3966
- setLastPrompt(promptToSend.trim());
3967
3973
  setLastMessages(messagesAndHistory);
3968
- setLastKey(promptKey);
3969
3974
  if (convId && onConversationCreated) {
3970
3975
  setTimeout(() => {
3971
3976
  onConversationCreated(convId);
3972
3977
  }, 100);
3973
3978
  }
3974
- setTimeout(() => {
3975
- scrollToBottom();
3976
- }, 0);
3977
3979
  });
3978
3980
  }, [
3979
3981
  idle,
@@ -4128,50 +4130,11 @@ ${followOnPrompt}`;
4128
4130
  };
4129
4131
  }, []);
4130
4132
  (0, import_react11.useEffect)(() => {
4131
- const hasLoadedHistory = initialHistory && Object.keys(initialHistory).length > 0;
4132
- if (!project_id) {
4133
- return;
4134
- }
4135
- if (initialPrompt && initialPrompt !== "" && initialPrompt !== lastPrompt && !hasLoadedHistory) {
4136
- setIsLoading(true);
4137
- setThinkingBlocks([]);
4138
- setCurrentThinkingIndex(0);
4139
- setUserHasScrolled(false);
4140
- ensureConversation().then((convId) => {
4141
- const controller = new AbortController();
4142
- setLastController(controller);
4143
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
4144
- const promptKey = `${timestamp}:${initialPrompt}`;
4145
- setHistory({ [promptKey]: { content: "", callId: "" } });
4146
- let fullPrompt = initialPrompt;
4147
- if (promptTemplate) {
4148
- fullPrompt = promptTemplate.replace("{{prompt}}", initialPrompt);
4149
- }
4150
- send(
4151
- fullPrompt,
4152
- [],
4153
- [
4154
- ...dataWithExtras(),
4155
- { key: "--messages", data: "0" }
4156
- ],
4157
- true,
4158
- true,
4159
- service,
4160
- convId,
4161
- // Use conversation ID from ensureConversation
4162
- controller
4163
- );
4164
- setLastPrompt(initialPrompt);
4165
- setLastMessages([]);
4166
- setLastKey(promptKey);
4167
- if (convId && onConversationCreated) {
4168
- setTimeout(() => {
4169
- onConversationCreated(convId);
4170
- }, 100);
4171
- }
4172
- });
4133
+ if (initialPrompt && initialPrompt !== "" && !initialPromptSentRef.current) {
4134
+ initialPromptSentRef.current = true;
4135
+ continueChat(initialPrompt);
4173
4136
  }
4174
- }, [initialPrompt, initialHistory, ensureConversation, promptTemplate, send, dataWithExtras, service, lastPrompt, project_id, onConversationCreated]);
4137
+ }, [initialPrompt, continueChat]);
4175
4138
  const CodeBlock = (0, import_react11.useCallback)((_a) => {
4176
4139
  var _b = _a, { node, inline, className, children } = _b, props = __objRest(_b, ["node", "inline", "className", "children"]);
4177
4140
  const match = /language-(\w+)/.exec(className || "");
@@ -4688,6 +4651,9 @@ var ChatPanelWrapper = ({
4688
4651
  effectiveCustomer,
4689
4652
  showPoweredBy,
4690
4653
  actions,
4654
+ initialPrompt,
4655
+ initialMessage,
4656
+ hideInitialPrompt,
4691
4657
  followOnQuestions,
4692
4658
  followOnPrompt,
4693
4659
  agentOptions,
@@ -4698,7 +4664,8 @@ var ChatPanelWrapper = ({
4698
4664
  totalContextTokens,
4699
4665
  maxContextTokens,
4700
4666
  enableContextDetailView,
4701
- onConversationCreated
4667
+ onConversationCreated,
4668
+ conversationInitialPrompt
4702
4669
  }) => {
4703
4670
  var _a, _b;
4704
4671
  const convAgentProfile = getAgent(activeConv.agentId);
@@ -4734,6 +4701,7 @@ var ChatPanelWrapper = ({
4734
4701
  const mcpServers = (0, import_react13.useMemo)(() => {
4735
4702
  return (convAgentProfile == null ? void 0 : convAgentProfile.mcpServers) || EMPTY_ARRAY;
4736
4703
  }, [convAgentProfile == null ? void 0 : convAgentProfile.mcpServers]);
4704
+ const effectiveInitialPrompt = conversationInitialPrompt || initialPrompt;
4737
4705
  if (!convAgentMetadata) return null;
4738
4706
  return /* @__PURE__ */ import_react13.default.createElement(
4739
4707
  "div",
@@ -4750,10 +4718,10 @@ var ChatPanelWrapper = ({
4750
4718
  title: "",
4751
4719
  theme,
4752
4720
  promptTemplate: convAgentMetadata.displayPromptTemplate || "{{prompt}}",
4753
- initialMessage: convAgentMetadata.displayStartMessageOrPrompt === "message" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0,
4754
- initialPrompt: convAgentMetadata.displayStartMessageOrPrompt === "prompt" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0,
4721
+ initialMessage: initialMessage || (convAgentMetadata.displayStartMessageOrPrompt === "message" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0),
4722
+ initialPrompt: effectiveInitialPrompt || (convAgentMetadata.displayStartMessageOrPrompt === "prompt" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0),
4755
4723
  placeholder: convAgentMetadata.displayPlaceholder || "Type a message...",
4756
- hideInitialPrompt: (_a = convAgentMetadata.displayHideInitialPrompt) != null ? _a : true,
4724
+ hideInitialPrompt: (_a = hideInitialPrompt != null ? hideInitialPrompt : convAgentMetadata.displayHideInitialPrompt) != null ? _a : true,
4757
4725
  data: chatPanelData,
4758
4726
  agent: activeConv.agentId,
4759
4727
  conversation: activeConv.conversationId.startsWith("new-") ? void 0 : activeConv.conversationId,
@@ -4787,7 +4755,7 @@ var ChatPanelWrapper = ({
4787
4755
  );
4788
4756
  };
4789
4757
  ChatPanelWrapper.displayName = "ChatPanelWrapper";
4790
- var AIAgentPanel = ({
4758
+ var AIAgentPanel = import_react13.default.forwardRef(({
4791
4759
  agents,
4792
4760
  defaultAgent,
4793
4761
  customerId,
@@ -4819,11 +4787,14 @@ var AIAgentPanel = ({
4819
4787
  showPoweredBy = true,
4820
4788
  conversation,
4821
4789
  actions = [],
4790
+ initialPrompt,
4791
+ initialMessage,
4792
+ hideInitialPrompt,
4822
4793
  followOnQuestions = [],
4823
4794
  followOnPrompt = "",
4824
4795
  historyListLimit = 50,
4825
4796
  showConversationHistory = true
4826
- }) => {
4797
+ }, ref) => {
4827
4798
  var _a, _b, _c, _d;
4828
4799
  const [isCollapsed, setIsCollapsed] = (0, import_react13.useState)(defaultCollapsed);
4829
4800
  const [isHistoryCollapsed, setIsHistoryCollapsed] = (0, import_react13.useState)(() => {
@@ -4905,6 +4876,29 @@ var AIAgentPanel = ({
4905
4876
  activeConversationsRef.current = activeConversations;
4906
4877
  const currentConversationIdRef = (0, import_react13.useRef)(currentConversationId);
4907
4878
  currentConversationIdRef.current = currentConversationId;
4879
+ import_react13.default.useImperativeHandle(ref, () => ({
4880
+ startNewConversation: (prompt, agent) => {
4881
+ const targetAgent = agent || currentAgentId;
4882
+ const tempId = `new-${Date.now()}`;
4883
+ setActiveConversations((prev) => {
4884
+ const next = new Map(prev);
4885
+ next.set(tempId, {
4886
+ conversationId: tempId,
4887
+ stableKey: tempId,
4888
+ agentId: targetAgent,
4889
+ history: {},
4890
+ isLoading: false,
4891
+ title: "New conversation",
4892
+ conversationInitialPrompt: prompt
4893
+ });
4894
+ return next;
4895
+ });
4896
+ setCurrentConversationId(tempId);
4897
+ if (onConversationChange) {
4898
+ onConversationChange(tempId);
4899
+ }
4900
+ }
4901
+ }), [currentAgentId, onConversationChange]);
4908
4902
  const [showContextNotification, setShowContextNotification] = (0, import_react13.useState)(false);
4909
4903
  const prevContextRef = (0, import_react13.useRef)(null);
4910
4904
  const contextNotificationTimeoutRef = (0, import_react13.useRef)(null);
@@ -5248,15 +5242,17 @@ var AIAgentPanel = ({
5248
5242
  let filtered = apiConversations;
5249
5243
  if (searchQuery) {
5250
5244
  const query = searchQuery.toLowerCase();
5251
- filtered = filtered.filter(
5252
- (conv) => {
5253
- var _a2, _b2;
5254
- return ((_a2 = conv.title) == null ? void 0 : _a2.toLowerCase().includes(query)) || ((_b2 = conv.summary) == null ? void 0 : _b2.toLowerCase().includes(query));
5255
- }
5256
- );
5245
+ filtered = filtered.filter((conv) => {
5246
+ var _a2, _b2;
5247
+ if ((_a2 = conv.title) == null ? void 0 : _a2.toLowerCase().includes(query)) return true;
5248
+ if ((_b2 = conv.summary) == null ? void 0 : _b2.toLowerCase().includes(query)) return true;
5249
+ const firstPrompt = conversationFirstPrompts[conv.conversationId];
5250
+ if (firstPrompt == null ? void 0 : firstPrompt.toLowerCase().includes(query)) return true;
5251
+ return false;
5252
+ });
5257
5253
  }
5258
5254
  return groupConversationsByTime(filtered, true);
5259
- }, [apiConversations, searchQuery]);
5255
+ }, [apiConversations, searchQuery, conversationFirstPrompts]);
5260
5256
  const effectiveCustomer = (0, import_react13.useMemo)(() => {
5261
5257
  return __spreadProps(__spreadValues({}, customer), {
5262
5258
  customer_id: customerId
@@ -5865,6 +5861,9 @@ var AIAgentPanel = ({
5865
5861
  effectiveCustomer,
5866
5862
  showPoweredBy,
5867
5863
  actions,
5864
+ initialPrompt,
5865
+ initialMessage,
5866
+ hideInitialPrompt,
5868
5867
  followOnQuestions,
5869
5868
  followOnPrompt,
5870
5869
  agentOptions,
@@ -5875,7 +5874,8 @@ var AIAgentPanel = ({
5875
5874
  totalContextTokens: mergedContext.totalTokens || 0,
5876
5875
  maxContextTokens,
5877
5876
  enableContextDetailView,
5878
- onConversationCreated: handleConversationCreated
5877
+ onConversationCreated: handleConversationCreated,
5878
+ conversationInitialPrompt: activeConv.conversationInitialPrompt
5879
5879
  }
5880
5880
  )), loadingConversationId && /* @__PURE__ */ import_react13.default.createElement("div", { className: "ai-agent-panel__conversation-loading-overlay" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "ai-agent-panel__loading-spinner" }), /* @__PURE__ */ import_react13.default.createElement("p", null, "Loading conversation...")), currentAgentMetadata && activeConversationsList.length === 0 && !loadingConversationId && /* @__PURE__ */ import_react13.default.createElement("div", { className: "ai-agent-panel__empty-chat" }, /* @__PURE__ */ import_react13.default.createElement(MessageIcon, null), /* @__PURE__ */ import_react13.default.createElement("p", null, "Select a conversation or start a new one"), /* @__PURE__ */ import_react13.default.createElement(Button, { variant: "default", size: "sm", onClick: handleNewConversation }, "New Conversation")), agentsLoading && !currentAgentMetadata && /* @__PURE__ */ import_react13.default.createElement("div", { className: "ai-agent-panel__loading" }, /* @__PURE__ */ import_react13.default.createElement("div", { className: "ai-agent-panel__loading-spinner" }), /* @__PURE__ */ import_react13.default.createElement("p", null, "Loading agent..."))),
5881
5881
  /* @__PURE__ */ import_react13.default.createElement(
@@ -5889,7 +5889,8 @@ var AIAgentPanel = ({
5889
5889
  /* @__PURE__ */ import_react13.default.createElement(DialogFooter, null, /* @__PURE__ */ import_react13.default.createElement(Button, { variant: "outline", onClick: handleHandoffCancel }, "Stay with current agent"), /* @__PURE__ */ import_react13.default.createElement(Button, { onClick: handleHandoffConfirm }, "Switch agent"))
5890
5890
  )
5891
5891
  );
5892
- };
5892
+ });
5893
+ AIAgentPanel.displayName = "AIAgentPanel";
5893
5894
  var AIAgentPanel_default = AIAgentPanel;
5894
5895
 
5895
5896
  // src/hooks/useConversationStore.ts
package/dist/index.mjs CHANGED
@@ -3636,6 +3636,7 @@ var AIChatPanel = ({
3636
3636
  const prevIdleRef = useRef5(true);
3637
3637
  const hasNotifiedCompletionRef = useRef5(true);
3638
3638
  const latestHistoryRef = useRef5(initialHistory);
3639
+ const initialPromptSentRef = useRef5(false);
3639
3640
  useEffect7(() => {
3640
3641
  if (!initialHistory) return;
3641
3642
  setHistory((prev) => {
@@ -3880,11 +3881,22 @@ var AIChatPanel = ({
3880
3881
  const promptToSend = promptText;
3881
3882
  if (!promptToSend || !promptToSend.trim()) return;
3882
3883
  setIsLoading(true);
3884
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3885
+ const promptKey = `${timestamp}:${promptToSend.trim()}`;
3886
+ setHistory((prevHistory) => __spreadProps(__spreadValues({}, prevHistory), {
3887
+ [promptKey]: { content: "", callId: "" }
3888
+ }));
3889
+ setLastPrompt(promptToSend.trim());
3890
+ setLastKey(promptKey);
3891
+ setTimeout(() => {
3892
+ scrollToBottom();
3893
+ }, 0);
3883
3894
  console.log("AIChatPanel.continueChat - about to call ensureConversation");
3884
3895
  ensureConversation().then((convId) => {
3885
3896
  console.log("AIChatPanel.continueChat - ensureConversation resolved with:", convId);
3886
3897
  const messagesAndHistory = [];
3887
3898
  Object.entries(history).forEach(([historyPrompt, historyEntry]) => {
3899
+ if (historyPrompt === promptKey) return;
3888
3900
  let promptForHistory = historyPrompt;
3889
3901
  const isoTimestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z:/;
3890
3902
  if (isoTimestampRegex.test(historyPrompt)) {
@@ -3897,13 +3909,8 @@ var AIChatPanel = ({
3897
3909
  messagesAndHistory.push({ role: "user", content: promptForHistory });
3898
3910
  messagesAndHistory.push({ role: "assistant", content: historyEntry.content });
3899
3911
  });
3900
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3901
- const promptKey = `${timestamp}:${promptToSend.trim()}`;
3902
- setHistory((prevHistory) => __spreadProps(__spreadValues({}, prevHistory), {
3903
- [promptKey]: { content: "", callId: "" }
3904
- }));
3905
3912
  let fullPromptToSend = promptToSend.trim();
3906
- if (Object.keys(history).length === 0 && promptTemplate) {
3913
+ if (messagesAndHistory.length === 0 && promptTemplate) {
3907
3914
  fullPromptToSend = promptTemplate.replace("{{prompt}}", fullPromptToSend);
3908
3915
  }
3909
3916
  if (followOnPrompt) {
@@ -3930,17 +3937,12 @@ ${followOnPrompt}`;
3930
3937
  // Use the conversation ID from ensureConversation
3931
3938
  newController
3932
3939
  );
3933
- setLastPrompt(promptToSend.trim());
3934
3940
  setLastMessages(messagesAndHistory);
3935
- setLastKey(promptKey);
3936
3941
  if (convId && onConversationCreated) {
3937
3942
  setTimeout(() => {
3938
3943
  onConversationCreated(convId);
3939
3944
  }, 100);
3940
3945
  }
3941
- setTimeout(() => {
3942
- scrollToBottom();
3943
- }, 0);
3944
3946
  });
3945
3947
  }, [
3946
3948
  idle,
@@ -4095,50 +4097,11 @@ ${followOnPrompt}`;
4095
4097
  };
4096
4098
  }, []);
4097
4099
  useEffect7(() => {
4098
- const hasLoadedHistory = initialHistory && Object.keys(initialHistory).length > 0;
4099
- if (!project_id) {
4100
- return;
4101
- }
4102
- if (initialPrompt && initialPrompt !== "" && initialPrompt !== lastPrompt && !hasLoadedHistory) {
4103
- setIsLoading(true);
4104
- setThinkingBlocks([]);
4105
- setCurrentThinkingIndex(0);
4106
- setUserHasScrolled(false);
4107
- ensureConversation().then((convId) => {
4108
- const controller = new AbortController();
4109
- setLastController(controller);
4110
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
4111
- const promptKey = `${timestamp}:${initialPrompt}`;
4112
- setHistory({ [promptKey]: { content: "", callId: "" } });
4113
- let fullPrompt = initialPrompt;
4114
- if (promptTemplate) {
4115
- fullPrompt = promptTemplate.replace("{{prompt}}", initialPrompt);
4116
- }
4117
- send(
4118
- fullPrompt,
4119
- [],
4120
- [
4121
- ...dataWithExtras(),
4122
- { key: "--messages", data: "0" }
4123
- ],
4124
- true,
4125
- true,
4126
- service,
4127
- convId,
4128
- // Use conversation ID from ensureConversation
4129
- controller
4130
- );
4131
- setLastPrompt(initialPrompt);
4132
- setLastMessages([]);
4133
- setLastKey(promptKey);
4134
- if (convId && onConversationCreated) {
4135
- setTimeout(() => {
4136
- onConversationCreated(convId);
4137
- }, 100);
4138
- }
4139
- });
4100
+ if (initialPrompt && initialPrompt !== "" && !initialPromptSentRef.current) {
4101
+ initialPromptSentRef.current = true;
4102
+ continueChat(initialPrompt);
4140
4103
  }
4141
- }, [initialPrompt, initialHistory, ensureConversation, promptTemplate, send, dataWithExtras, service, lastPrompt, project_id, onConversationCreated]);
4104
+ }, [initialPrompt, continueChat]);
4142
4105
  const CodeBlock = useCallback2((_a) => {
4143
4106
  var _b = _a, { node, inline, className, children } = _b, props = __objRest(_b, ["node", "inline", "className", "children"]);
4144
4107
  const match = /language-(\w+)/.exec(className || "");
@@ -4655,6 +4618,9 @@ var ChatPanelWrapper = ({
4655
4618
  effectiveCustomer,
4656
4619
  showPoweredBy,
4657
4620
  actions,
4621
+ initialPrompt,
4622
+ initialMessage,
4623
+ hideInitialPrompt,
4658
4624
  followOnQuestions,
4659
4625
  followOnPrompt,
4660
4626
  agentOptions,
@@ -4665,7 +4631,8 @@ var ChatPanelWrapper = ({
4665
4631
  totalContextTokens,
4666
4632
  maxContextTokens,
4667
4633
  enableContextDetailView,
4668
- onConversationCreated
4634
+ onConversationCreated,
4635
+ conversationInitialPrompt
4669
4636
  }) => {
4670
4637
  var _a, _b;
4671
4638
  const convAgentProfile = getAgent(activeConv.agentId);
@@ -4701,6 +4668,7 @@ var ChatPanelWrapper = ({
4701
4668
  const mcpServers = useMemo4(() => {
4702
4669
  return (convAgentProfile == null ? void 0 : convAgentProfile.mcpServers) || EMPTY_ARRAY;
4703
4670
  }, [convAgentProfile == null ? void 0 : convAgentProfile.mcpServers]);
4671
+ const effectiveInitialPrompt = conversationInitialPrompt || initialPrompt;
4704
4672
  if (!convAgentMetadata) return null;
4705
4673
  return /* @__PURE__ */ React12.createElement(
4706
4674
  "div",
@@ -4717,10 +4685,10 @@ var ChatPanelWrapper = ({
4717
4685
  title: "",
4718
4686
  theme,
4719
4687
  promptTemplate: convAgentMetadata.displayPromptTemplate || "{{prompt}}",
4720
- initialMessage: convAgentMetadata.displayStartMessageOrPrompt === "message" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0,
4721
- initialPrompt: convAgentMetadata.displayStartMessageOrPrompt === "prompt" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0,
4688
+ initialMessage: initialMessage || (convAgentMetadata.displayStartMessageOrPrompt === "message" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0),
4689
+ initialPrompt: effectiveInitialPrompt || (convAgentMetadata.displayStartMessageOrPrompt === "prompt" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0),
4722
4690
  placeholder: convAgentMetadata.displayPlaceholder || "Type a message...",
4723
- hideInitialPrompt: (_a = convAgentMetadata.displayHideInitialPrompt) != null ? _a : true,
4691
+ hideInitialPrompt: (_a = hideInitialPrompt != null ? hideInitialPrompt : convAgentMetadata.displayHideInitialPrompt) != null ? _a : true,
4724
4692
  data: chatPanelData,
4725
4693
  agent: activeConv.agentId,
4726
4694
  conversation: activeConv.conversationId.startsWith("new-") ? void 0 : activeConv.conversationId,
@@ -4754,7 +4722,7 @@ var ChatPanelWrapper = ({
4754
4722
  );
4755
4723
  };
4756
4724
  ChatPanelWrapper.displayName = "ChatPanelWrapper";
4757
- var AIAgentPanel = ({
4725
+ var AIAgentPanel = React12.forwardRef(({
4758
4726
  agents,
4759
4727
  defaultAgent,
4760
4728
  customerId,
@@ -4786,11 +4754,14 @@ var AIAgentPanel = ({
4786
4754
  showPoweredBy = true,
4787
4755
  conversation,
4788
4756
  actions = [],
4757
+ initialPrompt,
4758
+ initialMessage,
4759
+ hideInitialPrompt,
4789
4760
  followOnQuestions = [],
4790
4761
  followOnPrompt = "",
4791
4762
  historyListLimit = 50,
4792
4763
  showConversationHistory = true
4793
- }) => {
4764
+ }, ref) => {
4794
4765
  var _a, _b, _c, _d;
4795
4766
  const [isCollapsed, setIsCollapsed] = useState8(defaultCollapsed);
4796
4767
  const [isHistoryCollapsed, setIsHistoryCollapsed] = useState8(() => {
@@ -4872,6 +4843,29 @@ var AIAgentPanel = ({
4872
4843
  activeConversationsRef.current = activeConversations;
4873
4844
  const currentConversationIdRef = useRef6(currentConversationId);
4874
4845
  currentConversationIdRef.current = currentConversationId;
4846
+ React12.useImperativeHandle(ref, () => ({
4847
+ startNewConversation: (prompt, agent) => {
4848
+ const targetAgent = agent || currentAgentId;
4849
+ const tempId = `new-${Date.now()}`;
4850
+ setActiveConversations((prev) => {
4851
+ const next = new Map(prev);
4852
+ next.set(tempId, {
4853
+ conversationId: tempId,
4854
+ stableKey: tempId,
4855
+ agentId: targetAgent,
4856
+ history: {},
4857
+ isLoading: false,
4858
+ title: "New conversation",
4859
+ conversationInitialPrompt: prompt
4860
+ });
4861
+ return next;
4862
+ });
4863
+ setCurrentConversationId(tempId);
4864
+ if (onConversationChange) {
4865
+ onConversationChange(tempId);
4866
+ }
4867
+ }
4868
+ }), [currentAgentId, onConversationChange]);
4875
4869
  const [showContextNotification, setShowContextNotification] = useState8(false);
4876
4870
  const prevContextRef = useRef6(null);
4877
4871
  const contextNotificationTimeoutRef = useRef6(null);
@@ -5215,15 +5209,17 @@ var AIAgentPanel = ({
5215
5209
  let filtered = apiConversations;
5216
5210
  if (searchQuery) {
5217
5211
  const query = searchQuery.toLowerCase();
5218
- filtered = filtered.filter(
5219
- (conv) => {
5220
- var _a2, _b2;
5221
- return ((_a2 = conv.title) == null ? void 0 : _a2.toLowerCase().includes(query)) || ((_b2 = conv.summary) == null ? void 0 : _b2.toLowerCase().includes(query));
5222
- }
5223
- );
5212
+ filtered = filtered.filter((conv) => {
5213
+ var _a2, _b2;
5214
+ if ((_a2 = conv.title) == null ? void 0 : _a2.toLowerCase().includes(query)) return true;
5215
+ if ((_b2 = conv.summary) == null ? void 0 : _b2.toLowerCase().includes(query)) return true;
5216
+ const firstPrompt = conversationFirstPrompts[conv.conversationId];
5217
+ if (firstPrompt == null ? void 0 : firstPrompt.toLowerCase().includes(query)) return true;
5218
+ return false;
5219
+ });
5224
5220
  }
5225
5221
  return groupConversationsByTime(filtered, true);
5226
- }, [apiConversations, searchQuery]);
5222
+ }, [apiConversations, searchQuery, conversationFirstPrompts]);
5227
5223
  const effectiveCustomer = useMemo4(() => {
5228
5224
  return __spreadProps(__spreadValues({}, customer), {
5229
5225
  customer_id: customerId
@@ -5832,6 +5828,9 @@ var AIAgentPanel = ({
5832
5828
  effectiveCustomer,
5833
5829
  showPoweredBy,
5834
5830
  actions,
5831
+ initialPrompt,
5832
+ initialMessage,
5833
+ hideInitialPrompt,
5835
5834
  followOnQuestions,
5836
5835
  followOnPrompt,
5837
5836
  agentOptions,
@@ -5842,7 +5841,8 @@ var AIAgentPanel = ({
5842
5841
  totalContextTokens: mergedContext.totalTokens || 0,
5843
5842
  maxContextTokens,
5844
5843
  enableContextDetailView,
5845
- onConversationCreated: handleConversationCreated
5844
+ onConversationCreated: handleConversationCreated,
5845
+ conversationInitialPrompt: activeConv.conversationInitialPrompt
5846
5846
  }
5847
5847
  )), loadingConversationId && /* @__PURE__ */ React12.createElement("div", { className: "ai-agent-panel__conversation-loading-overlay" }, /* @__PURE__ */ React12.createElement("div", { className: "ai-agent-panel__loading-spinner" }), /* @__PURE__ */ React12.createElement("p", null, "Loading conversation...")), currentAgentMetadata && activeConversationsList.length === 0 && !loadingConversationId && /* @__PURE__ */ React12.createElement("div", { className: "ai-agent-panel__empty-chat" }, /* @__PURE__ */ React12.createElement(MessageIcon, null), /* @__PURE__ */ React12.createElement("p", null, "Select a conversation or start a new one"), /* @__PURE__ */ React12.createElement(Button, { variant: "default", size: "sm", onClick: handleNewConversation }, "New Conversation")), agentsLoading && !currentAgentMetadata && /* @__PURE__ */ React12.createElement("div", { className: "ai-agent-panel__loading" }, /* @__PURE__ */ React12.createElement("div", { className: "ai-agent-panel__loading-spinner" }), /* @__PURE__ */ React12.createElement("p", null, "Loading agent..."))),
5848
5848
  /* @__PURE__ */ React12.createElement(
@@ -5856,7 +5856,8 @@ var AIAgentPanel = ({
5856
5856
  /* @__PURE__ */ React12.createElement(DialogFooter, null, /* @__PURE__ */ React12.createElement(Button, { variant: "outline", onClick: handleHandoffCancel }, "Stay with current agent"), /* @__PURE__ */ React12.createElement(Button, { onClick: handleHandoffConfirm }, "Switch agent"))
5857
5857
  )
5858
5858
  );
5859
- };
5859
+ });
5860
+ AIAgentPanel.displayName = "AIAgentPanel";
5860
5861
  var AIAgentPanel_default = AIAgentPanel;
5861
5862
 
5862
5863
  // src/hooks/useConversationStore.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hef2024/llmasaservice-ui",
3
- "version": "0.16.10",
3
+ "version": "0.17.0",
4
4
  "description": "Prebuilt UI components for LLMAsAService.io",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -47,6 +47,7 @@ export interface ActiveConversation {
47
47
  history: Record<string, { content: string; callId: string }>;
48
48
  isLoading: boolean;
49
49
  title: string;
50
+ conversationInitialPrompt?: string; // Per-conversation initial prompt for programmatic start
50
51
  }
51
52
 
52
53
  /**
@@ -58,6 +59,13 @@ export interface AgentConfig {
58
59
  avatarUrl?: string;
59
60
  }
60
61
 
62
+ /**
63
+ * Imperative handle for programmatic control of AIAgentPanel
64
+ */
65
+ export interface AIAgentPanelHandle {
66
+ startNewConversation: (prompt: string, agent?: string) => void;
67
+ }
68
+
61
69
  /**
62
70
  * Props for AIAgentPanel
63
71
  */
@@ -120,7 +128,10 @@ export interface AIAgentPanelProps {
120
128
  style?: string;
121
129
  }[];
122
130
 
123
- // Follow-on
131
+ // Initial prompt and follow-on
132
+ initialPrompt?: string;
133
+ initialMessage?: string;
134
+ hideInitialPrompt?: boolean;
124
135
  followOnQuestions?: string[];
125
136
  followOnPrompt?: string;
126
137
 
@@ -351,6 +362,9 @@ interface ChatPanelWrapperProps {
351
362
  effectiveCustomer: any;
352
363
  showPoweredBy: boolean;
353
364
  actions: any[];
365
+ initialPrompt?: string;
366
+ initialMessage?: string;
367
+ hideInitialPrompt?: boolean;
354
368
  followOnQuestions: string[];
355
369
  followOnPrompt: string;
356
370
  agentOptions: any[];
@@ -364,6 +378,8 @@ interface ChatPanelWrapperProps {
364
378
  enableContextDetailView: boolean;
365
379
  // Conversation creation callback
366
380
  onConversationCreated: (tempId: string, realId: string) => void;
381
+ // Per-conversation initial prompt
382
+ conversationInitialPrompt?: string;
367
383
  }
368
384
 
369
385
  // Remove React.memo temporarily to debug - ChatPanelWrapper needs to re-render when agentId changes
@@ -382,6 +398,9 @@ const ChatPanelWrapper = (({
382
398
  effectiveCustomer,
383
399
  showPoweredBy,
384
400
  actions,
401
+ initialPrompt,
402
+ initialMessage,
403
+ hideInitialPrompt,
385
404
  followOnQuestions,
386
405
  followOnPrompt,
387
406
  agentOptions,
@@ -393,6 +412,7 @@ const ChatPanelWrapper = (({
393
412
  maxContextTokens,
394
413
  enableContextDetailView,
395
414
  onConversationCreated,
415
+ conversationInitialPrompt,
396
416
  }) => {
397
417
  const convAgentProfile = getAgent(activeConv.agentId);
398
418
  const convAgentMetadata = convAgentProfile?.metadata;
@@ -441,6 +461,9 @@ const ChatPanelWrapper = (({
441
461
  return convAgentProfile?.mcpServers || EMPTY_ARRAY;
442
462
  }, [convAgentProfile?.mcpServers]);
443
463
 
464
+ // Determine which initialPrompt to use - conversation-specific OR prop-based
465
+ const effectiveInitialPrompt = conversationInitialPrompt || initialPrompt;
466
+
444
467
  if (!convAgentMetadata) return null;
445
468
 
446
469
  return (
@@ -456,17 +479,19 @@ const ChatPanelWrapper = (({
456
479
  theme={theme}
457
480
  promptTemplate={convAgentMetadata.displayPromptTemplate || '{{prompt}}'}
458
481
  initialMessage={
459
- convAgentMetadata.displayStartMessageOrPrompt === 'message'
482
+ initialMessage ||
483
+ (convAgentMetadata.displayStartMessageOrPrompt === 'message'
460
484
  ? convAgentMetadata.displayInitialMessageOrPrompt
461
- : undefined
485
+ : undefined)
462
486
  }
463
487
  initialPrompt={
464
- convAgentMetadata.displayStartMessageOrPrompt === 'prompt'
488
+ effectiveInitialPrompt ||
489
+ (convAgentMetadata.displayStartMessageOrPrompt === 'prompt'
465
490
  ? convAgentMetadata.displayInitialMessageOrPrompt
466
- : undefined
491
+ : undefined)
467
492
  }
468
493
  placeholder={convAgentMetadata.displayPlaceholder || 'Type a message...'}
469
- hideInitialPrompt={convAgentMetadata.displayHideInitialPrompt ?? true}
494
+ hideInitialPrompt={hideInitialPrompt ?? convAgentMetadata.displayHideInitialPrompt ?? true}
470
495
  data={chatPanelData}
471
496
  agent={activeConv.agentId}
472
497
  conversation={activeConv.conversationId.startsWith('new-') ? undefined : activeConv.conversationId}
@@ -502,7 +527,7 @@ const ChatPanelWrapper = (({
502
527
 
503
528
  ChatPanelWrapper.displayName = 'ChatPanelWrapper';
504
529
 
505
- const AIAgentPanel: React.FC<AIAgentPanelProps> = ({
530
+ const AIAgentPanel = React.forwardRef<AIAgentPanelHandle, AIAgentPanelProps>(({
506
531
  agents,
507
532
  defaultAgent,
508
533
  customerId,
@@ -534,11 +559,14 @@ const AIAgentPanel: React.FC<AIAgentPanelProps> = ({
534
559
  showPoweredBy = true,
535
560
  conversation,
536
561
  actions = [],
562
+ initialPrompt,
563
+ initialMessage,
564
+ hideInitialPrompt,
537
565
  followOnQuestions = [],
538
566
  followOnPrompt = '',
539
567
  historyListLimit = 50,
540
568
  showConversationHistory = true,
541
- }) => {
569
+ }, ref) => {
542
570
  // Panel state
543
571
  const [isCollapsed, setIsCollapsed] = useState(defaultCollapsed);
544
572
  const [isHistoryCollapsed, setIsHistoryCollapsed] = useState(() => {
@@ -653,6 +681,33 @@ const AIAgentPanel: React.FC<AIAgentPanelProps> = ({
653
681
  const currentConversationIdRef = useRef<string | null>(currentConversationId);
654
682
  currentConversationIdRef.current = currentConversationId;
655
683
 
684
+ // Imperative handle for programmatic control
685
+ React.useImperativeHandle(ref, () => ({
686
+ startNewConversation: (prompt: string, agent?: string) => {
687
+ const targetAgent = agent || currentAgentId;
688
+ const tempId = `new-${Date.now()}`;
689
+
690
+ setActiveConversations(prev => {
691
+ const next = new Map(prev);
692
+ next.set(tempId, {
693
+ conversationId: tempId,
694
+ stableKey: tempId,
695
+ agentId: targetAgent,
696
+ history: {},
697
+ isLoading: false,
698
+ title: 'New conversation',
699
+ conversationInitialPrompt: prompt,
700
+ });
701
+ return next;
702
+ });
703
+
704
+ setCurrentConversationId(tempId);
705
+ if (onConversationChange) {
706
+ onConversationChange(tempId);
707
+ }
708
+ }
709
+ }), [currentAgentId, onConversationChange]);
710
+
656
711
  // Context change notification state
657
712
  const [showContextNotification, setShowContextNotification] = useState(false);
658
713
  const prevContextRef = useRef<string | null>(null);
@@ -1138,15 +1193,24 @@ console.log("apiKey", apiKey);
1138
1193
  // Filter by search query
1139
1194
  if (searchQuery) {
1140
1195
  const query = searchQuery.toLowerCase();
1141
- filtered = filtered.filter(conv =>
1142
- conv.title?.toLowerCase().includes(query) ||
1143
- conv.summary?.toLowerCase().includes(query)
1144
- );
1196
+ filtered = filtered.filter(conv => {
1197
+ // Check title from API
1198
+ if (conv.title?.toLowerCase().includes(query)) return true;
1199
+
1200
+ // Check summary from API
1201
+ if (conv.summary?.toLowerCase().includes(query)) return true;
1202
+
1203
+ // Check the first prompt (what's actually displayed in the UI)
1204
+ const firstPrompt = conversationFirstPrompts[conv.conversationId];
1205
+ if (firstPrompt?.toLowerCase().includes(query)) return true;
1206
+
1207
+ return false;
1208
+ });
1145
1209
  }
1146
1210
 
1147
1211
  // Group all conversations, show all groups even if empty
1148
1212
  return groupConversationsByTime(filtered, true);
1149
- }, [apiConversations, searchQuery]);
1213
+ }, [apiConversations, searchQuery, conversationFirstPrompts]);
1150
1214
 
1151
1215
  // Build effective customer object with required customerId
1152
1216
  const effectiveCustomer = useMemo(() => {
@@ -2022,6 +2086,9 @@ console.log("apiKey", apiKey);
2022
2086
  effectiveCustomer={effectiveCustomer}
2023
2087
  showPoweredBy={showPoweredBy}
2024
2088
  actions={actions}
2089
+ initialPrompt={initialPrompt}
2090
+ initialMessage={initialMessage}
2091
+ hideInitialPrompt={hideInitialPrompt}
2025
2092
  followOnQuestions={followOnQuestions}
2026
2093
  followOnPrompt={followOnPrompt}
2027
2094
  agentOptions={agentOptions}
@@ -2033,6 +2100,7 @@ console.log("apiKey", apiKey);
2033
2100
  maxContextTokens={maxContextTokens}
2034
2101
  enableContextDetailView={enableContextDetailView}
2035
2102
  onConversationCreated={handleConversationCreated}
2103
+ conversationInitialPrompt={activeConv.conversationInitialPrompt}
2036
2104
  />
2037
2105
  ))}
2038
2106
 
@@ -2090,7 +2158,9 @@ console.log("apiKey", apiKey);
2090
2158
  </Dialog>
2091
2159
  </div>
2092
2160
  );
2093
- };
2161
+ });
2162
+
2163
+ AIAgentPanel.displayName = 'AIAgentPanel';
2094
2164
 
2095
2165
  export default AIAgentPanel;
2096
2166
 
@@ -703,6 +703,8 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
703
703
  const hasNotifiedCompletionRef = useRef<boolean>(true);
704
704
  // Store the latest processed history for callbacks (doesn't trigger re-renders)
705
705
  const latestHistoryRef = useRef<Record<string, HistoryEntry>>(initialHistory);
706
+ // Track if we've sent the initial prompt (prevents loops)
707
+ const initialPromptSentRef = useRef<boolean>(false);
706
708
 
707
709
  // Sync new entries from initialHistory into local history state
708
710
  // This allows parent components to inject messages (e.g., page-based agent suggestions)
@@ -1063,13 +1065,39 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
1063
1065
 
1064
1066
  setIsLoading(true);
1065
1067
 
1068
+ // === OPTIMISTIC UPDATE: Show prompt immediately in UI ===
1069
+ // Generate unique key using ISO timestamp prefix + prompt
1070
+ const timestamp = new Date().toISOString();
1071
+ const promptKey = `${timestamp}:${promptToSend.trim()}`;
1072
+
1073
+ // Add prompt to history IMMEDIATELY - this makes it appear in the UI right away
1074
+ setHistory((prevHistory) => ({
1075
+ ...prevHistory,
1076
+ [promptKey]: { content: '', callId: '' },
1077
+ }));
1078
+
1079
+ // Store the key for later use
1080
+ setLastPrompt(promptToSend.trim());
1081
+ setLastKey(promptKey);
1082
+
1083
+ // Scroll to bottom immediately to show the new prompt
1084
+ // Use setTimeout to ensure the DOM has updated
1085
+ setTimeout(() => {
1086
+ scrollToBottom();
1087
+ }, 0);
1088
+
1089
+ // Now proceed with API calls in the background (conversation creation + LLM call)
1066
1090
  // Ensure conversation exists before sending (matches ChatPanel)
1067
1091
  console.log('AIChatPanel.continueChat - about to call ensureConversation');
1068
1092
  ensureConversation().then((convId) => {
1069
1093
  console.log('AIChatPanel.continueChat - ensureConversation resolved with:', convId);
1070
1094
  // Build messagesAndHistory from history (matches ChatPanel)
1095
+ // IMPORTANT: Exclude the current prompt (promptKey) since it's new and we're sending it now
1071
1096
  const messagesAndHistory: { role: string; content: string }[] = [];
1072
1097
  Object.entries(history).forEach(([historyPrompt, historyEntry]) => {
1098
+ // Skip the current prompt we just added optimistically
1099
+ if (historyPrompt === promptKey) return;
1100
+
1073
1101
  // Strip timestamp prefix from prompt before using it (matches ChatPanel)
1074
1102
  let promptForHistory = historyPrompt;
1075
1103
  const isoTimestampRegex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z:/;
@@ -1085,19 +1113,10 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
1085
1113
  messagesAndHistory.push({ role: 'assistant', content: historyEntry.content });
1086
1114
  });
1087
1115
 
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
1116
  // Build the full prompt - only apply template for first message (matches ChatPanel)
1117
+ // Check if this is the first message by seeing if messagesAndHistory is empty
1099
1118
  let fullPromptToSend = promptToSend.trim();
1100
- if (Object.keys(history).length === 0 && promptTemplate) {
1119
+ if (messagesAndHistory.length === 0 && promptTemplate) {
1101
1120
  fullPromptToSend = promptTemplate.replace('{{prompt}}', fullPromptToSend);
1102
1121
  }
1103
1122
 
@@ -1126,9 +1145,7 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
1126
1145
  newController
1127
1146
  );
1128
1147
 
1129
- setLastPrompt(promptToSend.trim());
1130
1148
  setLastMessages(messagesAndHistory);
1131
- setLastKey(promptKey);
1132
1149
 
1133
1150
  // Notify parent of new conversation ID AFTER send() has started
1134
1151
  // This prevents the component from being remounted before send() runs
@@ -1138,12 +1155,6 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
1138
1155
  onConversationCreated(convId);
1139
1156
  }, 100);
1140
1157
  }
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);
1147
1158
  });
1148
1159
  }, [
1149
1160
  idle,
@@ -1376,69 +1387,14 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
1376
1387
  };
1377
1388
  }, []); // Empty deps - only run cleanup on unmount
1378
1389
 
1379
- // Auto-send initialPrompt when it changes (matches ChatPanel behavior)
1380
- // IMPORTANT: Skip if we have initialHistory - that means we're loading an existing conversation
1390
+ // Auto-send initialPrompt exactly once when component mounts
1391
+ // Simple behavior matching original ChatPanel - just send the prompt
1381
1392
  useEffect(() => {
1382
- // Don't auto-send initialPrompt if we loaded existing history
1383
- // This prevents unwanted LLM calls when switching to loaded conversations
1384
- const hasLoadedHistory = initialHistory && Object.keys(initialHistory).length > 0;
1385
-
1386
- // Don't proceed if project_id is not yet available
1387
- if (!project_id) {
1388
- return;
1389
- }
1390
-
1391
- if (initialPrompt && initialPrompt !== '' && initialPrompt !== lastPrompt && !hasLoadedHistory) {
1392
- setIsLoading(true);
1393
- setThinkingBlocks([]);
1394
- setCurrentThinkingIndex(0);
1395
- setUserHasScrolled(false); // Enable auto-scroll for new prompt
1396
-
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
- });
1393
+ if (initialPrompt && initialPrompt !== '' && !initialPromptSentRef.current) {
1394
+ initialPromptSentRef.current = true;
1395
+ continueChat(initialPrompt);
1440
1396
  }
1441
- }, [initialPrompt, initialHistory, ensureConversation, promptTemplate, send, dataWithExtras, service, lastPrompt, project_id, onConversationCreated]);
1397
+ }, [initialPrompt, continueChat]);
1442
1398
 
1443
1399
  // ============================================================================
1444
1400
  // Render Helpers
@@ -57,3 +57,5 @@ export default Button;
57
57
 
58
58
 
59
59
 
60
+
61
+
@@ -153,3 +153,5 @@ export default Dialog;
153
153
 
154
154
 
155
155
 
156
+
157
+
@@ -33,3 +33,5 @@ export default Input;
33
33
 
34
34
 
35
35
 
36
+
37
+
@@ -156,3 +156,5 @@ export default Select;
156
156
 
157
157
 
158
158
 
159
+
160
+
@@ -73,3 +73,5 @@ export default Tooltip;
73
73
 
74
74
 
75
75
 
76
+
77
+
@@ -20,3 +20,5 @@ export type { DialogProps, DialogFooterProps } from './Dialog';
20
20
 
21
21
 
22
22
 
23
+
24
+