@hef2024/llmasaservice-ui 0.16.9 → 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 +10 -1
- package/dist/index.d.ts +10 -1
- package/dist/index.js +77 -70
- package/dist/index.mjs +77 -70
- package/package.json +4 -4
- package/src/AIAgentPanel.tsx +84 -14
- package/src/AIChatPanel.tsx +43 -81
- package/src/components/ui/Button.tsx +2 -0
- package/src/components/ui/Dialog.tsx +2 -0
- package/src/components/ui/Input.tsx +2 -0
- package/src/components/ui/Select.tsx +2 -0
- package/src/components/ui/Tooltip.tsx +2 -0
- package/src/components/ui/index.ts +2 -0
- package/DEPLOYMENT.md +0 -193
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.
|
|
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.
|
|
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 (
|
|
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
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4133
|
+
if (initialPrompt && initialPrompt !== "" && !initialPromptSentRef.current) {
|
|
4134
|
+
initialPromptSentRef.current = true;
|
|
4135
|
+
continueChat(initialPrompt);
|
|
4134
4136
|
}
|
|
4135
|
-
|
|
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
|
-
});
|
|
4173
|
-
}
|
|
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 || "");
|
|
@@ -4226,7 +4189,13 @@ ${followOnPrompt}`;
|
|
|
4226
4189
|
variant: "default",
|
|
4227
4190
|
size: "sm",
|
|
4228
4191
|
className: "ai-chat-agent-suggestion__button",
|
|
4229
|
-
onClick: () =>
|
|
4192
|
+
onClick: () => {
|
|
4193
|
+
onAgentChange(agentId);
|
|
4194
|
+
setTimeout(() => {
|
|
4195
|
+
var _a;
|
|
4196
|
+
(_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "auto" });
|
|
4197
|
+
}, 50);
|
|
4198
|
+
}
|
|
4230
4199
|
},
|
|
4231
4200
|
"Switch"
|
|
4232
4201
|
));
|
|
@@ -4682,6 +4651,9 @@ var ChatPanelWrapper = ({
|
|
|
4682
4651
|
effectiveCustomer,
|
|
4683
4652
|
showPoweredBy,
|
|
4684
4653
|
actions,
|
|
4654
|
+
initialPrompt,
|
|
4655
|
+
initialMessage,
|
|
4656
|
+
hideInitialPrompt,
|
|
4685
4657
|
followOnQuestions,
|
|
4686
4658
|
followOnPrompt,
|
|
4687
4659
|
agentOptions,
|
|
@@ -4692,7 +4664,8 @@ var ChatPanelWrapper = ({
|
|
|
4692
4664
|
totalContextTokens,
|
|
4693
4665
|
maxContextTokens,
|
|
4694
4666
|
enableContextDetailView,
|
|
4695
|
-
onConversationCreated
|
|
4667
|
+
onConversationCreated,
|
|
4668
|
+
conversationInitialPrompt
|
|
4696
4669
|
}) => {
|
|
4697
4670
|
var _a, _b;
|
|
4698
4671
|
const convAgentProfile = getAgent(activeConv.agentId);
|
|
@@ -4728,6 +4701,7 @@ var ChatPanelWrapper = ({
|
|
|
4728
4701
|
const mcpServers = (0, import_react13.useMemo)(() => {
|
|
4729
4702
|
return (convAgentProfile == null ? void 0 : convAgentProfile.mcpServers) || EMPTY_ARRAY;
|
|
4730
4703
|
}, [convAgentProfile == null ? void 0 : convAgentProfile.mcpServers]);
|
|
4704
|
+
const effectiveInitialPrompt = conversationInitialPrompt || initialPrompt;
|
|
4731
4705
|
if (!convAgentMetadata) return null;
|
|
4732
4706
|
return /* @__PURE__ */ import_react13.default.createElement(
|
|
4733
4707
|
"div",
|
|
@@ -4744,10 +4718,10 @@ var ChatPanelWrapper = ({
|
|
|
4744
4718
|
title: "",
|
|
4745
4719
|
theme,
|
|
4746
4720
|
promptTemplate: convAgentMetadata.displayPromptTemplate || "{{prompt}}",
|
|
4747
|
-
initialMessage: convAgentMetadata.displayStartMessageOrPrompt === "message" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0,
|
|
4748
|
-
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),
|
|
4749
4723
|
placeholder: convAgentMetadata.displayPlaceholder || "Type a message...",
|
|
4750
|
-
hideInitialPrompt: (_a = convAgentMetadata.displayHideInitialPrompt) != null ? _a : true,
|
|
4724
|
+
hideInitialPrompt: (_a = hideInitialPrompt != null ? hideInitialPrompt : convAgentMetadata.displayHideInitialPrompt) != null ? _a : true,
|
|
4751
4725
|
data: chatPanelData,
|
|
4752
4726
|
agent: activeConv.agentId,
|
|
4753
4727
|
conversation: activeConv.conversationId.startsWith("new-") ? void 0 : activeConv.conversationId,
|
|
@@ -4781,7 +4755,7 @@ var ChatPanelWrapper = ({
|
|
|
4781
4755
|
);
|
|
4782
4756
|
};
|
|
4783
4757
|
ChatPanelWrapper.displayName = "ChatPanelWrapper";
|
|
4784
|
-
var AIAgentPanel = ({
|
|
4758
|
+
var AIAgentPanel = import_react13.default.forwardRef(({
|
|
4785
4759
|
agents,
|
|
4786
4760
|
defaultAgent,
|
|
4787
4761
|
customerId,
|
|
@@ -4813,11 +4787,14 @@ var AIAgentPanel = ({
|
|
|
4813
4787
|
showPoweredBy = true,
|
|
4814
4788
|
conversation,
|
|
4815
4789
|
actions = [],
|
|
4790
|
+
initialPrompt,
|
|
4791
|
+
initialMessage,
|
|
4792
|
+
hideInitialPrompt,
|
|
4816
4793
|
followOnQuestions = [],
|
|
4817
4794
|
followOnPrompt = "",
|
|
4818
4795
|
historyListLimit = 50,
|
|
4819
4796
|
showConversationHistory = true
|
|
4820
|
-
}) => {
|
|
4797
|
+
}, ref) => {
|
|
4821
4798
|
var _a, _b, _c, _d;
|
|
4822
4799
|
const [isCollapsed, setIsCollapsed] = (0, import_react13.useState)(defaultCollapsed);
|
|
4823
4800
|
const [isHistoryCollapsed, setIsHistoryCollapsed] = (0, import_react13.useState)(() => {
|
|
@@ -4899,6 +4876,29 @@ var AIAgentPanel = ({
|
|
|
4899
4876
|
activeConversationsRef.current = activeConversations;
|
|
4900
4877
|
const currentConversationIdRef = (0, import_react13.useRef)(currentConversationId);
|
|
4901
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]);
|
|
4902
4902
|
const [showContextNotification, setShowContextNotification] = (0, import_react13.useState)(false);
|
|
4903
4903
|
const prevContextRef = (0, import_react13.useRef)(null);
|
|
4904
4904
|
const contextNotificationTimeoutRef = (0, import_react13.useRef)(null);
|
|
@@ -5242,15 +5242,17 @@ var AIAgentPanel = ({
|
|
|
5242
5242
|
let filtered = apiConversations;
|
|
5243
5243
|
if (searchQuery) {
|
|
5244
5244
|
const query = searchQuery.toLowerCase();
|
|
5245
|
-
filtered = filtered.filter(
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
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
|
+
});
|
|
5251
5253
|
}
|
|
5252
5254
|
return groupConversationsByTime(filtered, true);
|
|
5253
|
-
}, [apiConversations, searchQuery]);
|
|
5255
|
+
}, [apiConversations, searchQuery, conversationFirstPrompts]);
|
|
5254
5256
|
const effectiveCustomer = (0, import_react13.useMemo)(() => {
|
|
5255
5257
|
return __spreadProps(__spreadValues({}, customer), {
|
|
5256
5258
|
customer_id: customerId
|
|
@@ -5859,6 +5861,9 @@ var AIAgentPanel = ({
|
|
|
5859
5861
|
effectiveCustomer,
|
|
5860
5862
|
showPoweredBy,
|
|
5861
5863
|
actions,
|
|
5864
|
+
initialPrompt,
|
|
5865
|
+
initialMessage,
|
|
5866
|
+
hideInitialPrompt,
|
|
5862
5867
|
followOnQuestions,
|
|
5863
5868
|
followOnPrompt,
|
|
5864
5869
|
agentOptions,
|
|
@@ -5869,7 +5874,8 @@ var AIAgentPanel = ({
|
|
|
5869
5874
|
totalContextTokens: mergedContext.totalTokens || 0,
|
|
5870
5875
|
maxContextTokens,
|
|
5871
5876
|
enableContextDetailView,
|
|
5872
|
-
onConversationCreated: handleConversationCreated
|
|
5877
|
+
onConversationCreated: handleConversationCreated,
|
|
5878
|
+
conversationInitialPrompt: activeConv.conversationInitialPrompt
|
|
5873
5879
|
}
|
|
5874
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..."))),
|
|
5875
5881
|
/* @__PURE__ */ import_react13.default.createElement(
|
|
@@ -5883,7 +5889,8 @@ var AIAgentPanel = ({
|
|
|
5883
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"))
|
|
5884
5890
|
)
|
|
5885
5891
|
);
|
|
5886
|
-
};
|
|
5892
|
+
});
|
|
5893
|
+
AIAgentPanel.displayName = "AIAgentPanel";
|
|
5887
5894
|
var AIAgentPanel_default = AIAgentPanel;
|
|
5888
5895
|
|
|
5889
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 (
|
|
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
|
-
|
|
4099
|
-
|
|
4100
|
-
|
|
4100
|
+
if (initialPrompt && initialPrompt !== "" && !initialPromptSentRef.current) {
|
|
4101
|
+
initialPromptSentRef.current = true;
|
|
4102
|
+
continueChat(initialPrompt);
|
|
4101
4103
|
}
|
|
4102
|
-
|
|
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
|
-
});
|
|
4140
|
-
}
|
|
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 || "");
|
|
@@ -4193,7 +4156,13 @@ ${followOnPrompt}`;
|
|
|
4193
4156
|
variant: "default",
|
|
4194
4157
|
size: "sm",
|
|
4195
4158
|
className: "ai-chat-agent-suggestion__button",
|
|
4196
|
-
onClick: () =>
|
|
4159
|
+
onClick: () => {
|
|
4160
|
+
onAgentChange(agentId);
|
|
4161
|
+
setTimeout(() => {
|
|
4162
|
+
var _a;
|
|
4163
|
+
(_a = bottomRef.current) == null ? void 0 : _a.scrollIntoView({ behavior: "auto" });
|
|
4164
|
+
}, 50);
|
|
4165
|
+
}
|
|
4197
4166
|
},
|
|
4198
4167
|
"Switch"
|
|
4199
4168
|
));
|
|
@@ -4649,6 +4618,9 @@ var ChatPanelWrapper = ({
|
|
|
4649
4618
|
effectiveCustomer,
|
|
4650
4619
|
showPoweredBy,
|
|
4651
4620
|
actions,
|
|
4621
|
+
initialPrompt,
|
|
4622
|
+
initialMessage,
|
|
4623
|
+
hideInitialPrompt,
|
|
4652
4624
|
followOnQuestions,
|
|
4653
4625
|
followOnPrompt,
|
|
4654
4626
|
agentOptions,
|
|
@@ -4659,7 +4631,8 @@ var ChatPanelWrapper = ({
|
|
|
4659
4631
|
totalContextTokens,
|
|
4660
4632
|
maxContextTokens,
|
|
4661
4633
|
enableContextDetailView,
|
|
4662
|
-
onConversationCreated
|
|
4634
|
+
onConversationCreated,
|
|
4635
|
+
conversationInitialPrompt
|
|
4663
4636
|
}) => {
|
|
4664
4637
|
var _a, _b;
|
|
4665
4638
|
const convAgentProfile = getAgent(activeConv.agentId);
|
|
@@ -4695,6 +4668,7 @@ var ChatPanelWrapper = ({
|
|
|
4695
4668
|
const mcpServers = useMemo4(() => {
|
|
4696
4669
|
return (convAgentProfile == null ? void 0 : convAgentProfile.mcpServers) || EMPTY_ARRAY;
|
|
4697
4670
|
}, [convAgentProfile == null ? void 0 : convAgentProfile.mcpServers]);
|
|
4671
|
+
const effectiveInitialPrompt = conversationInitialPrompt || initialPrompt;
|
|
4698
4672
|
if (!convAgentMetadata) return null;
|
|
4699
4673
|
return /* @__PURE__ */ React12.createElement(
|
|
4700
4674
|
"div",
|
|
@@ -4711,10 +4685,10 @@ var ChatPanelWrapper = ({
|
|
|
4711
4685
|
title: "",
|
|
4712
4686
|
theme,
|
|
4713
4687
|
promptTemplate: convAgentMetadata.displayPromptTemplate || "{{prompt}}",
|
|
4714
|
-
initialMessage: convAgentMetadata.displayStartMessageOrPrompt === "message" ? convAgentMetadata.displayInitialMessageOrPrompt : void 0,
|
|
4715
|
-
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),
|
|
4716
4690
|
placeholder: convAgentMetadata.displayPlaceholder || "Type a message...",
|
|
4717
|
-
hideInitialPrompt: (_a = convAgentMetadata.displayHideInitialPrompt) != null ? _a : true,
|
|
4691
|
+
hideInitialPrompt: (_a = hideInitialPrompt != null ? hideInitialPrompt : convAgentMetadata.displayHideInitialPrompt) != null ? _a : true,
|
|
4718
4692
|
data: chatPanelData,
|
|
4719
4693
|
agent: activeConv.agentId,
|
|
4720
4694
|
conversation: activeConv.conversationId.startsWith("new-") ? void 0 : activeConv.conversationId,
|
|
@@ -4748,7 +4722,7 @@ var ChatPanelWrapper = ({
|
|
|
4748
4722
|
);
|
|
4749
4723
|
};
|
|
4750
4724
|
ChatPanelWrapper.displayName = "ChatPanelWrapper";
|
|
4751
|
-
var AIAgentPanel = ({
|
|
4725
|
+
var AIAgentPanel = React12.forwardRef(({
|
|
4752
4726
|
agents,
|
|
4753
4727
|
defaultAgent,
|
|
4754
4728
|
customerId,
|
|
@@ -4780,11 +4754,14 @@ var AIAgentPanel = ({
|
|
|
4780
4754
|
showPoweredBy = true,
|
|
4781
4755
|
conversation,
|
|
4782
4756
|
actions = [],
|
|
4757
|
+
initialPrompt,
|
|
4758
|
+
initialMessage,
|
|
4759
|
+
hideInitialPrompt,
|
|
4783
4760
|
followOnQuestions = [],
|
|
4784
4761
|
followOnPrompt = "",
|
|
4785
4762
|
historyListLimit = 50,
|
|
4786
4763
|
showConversationHistory = true
|
|
4787
|
-
}) => {
|
|
4764
|
+
}, ref) => {
|
|
4788
4765
|
var _a, _b, _c, _d;
|
|
4789
4766
|
const [isCollapsed, setIsCollapsed] = useState8(defaultCollapsed);
|
|
4790
4767
|
const [isHistoryCollapsed, setIsHistoryCollapsed] = useState8(() => {
|
|
@@ -4866,6 +4843,29 @@ var AIAgentPanel = ({
|
|
|
4866
4843
|
activeConversationsRef.current = activeConversations;
|
|
4867
4844
|
const currentConversationIdRef = useRef6(currentConversationId);
|
|
4868
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]);
|
|
4869
4869
|
const [showContextNotification, setShowContextNotification] = useState8(false);
|
|
4870
4870
|
const prevContextRef = useRef6(null);
|
|
4871
4871
|
const contextNotificationTimeoutRef = useRef6(null);
|
|
@@ -5209,15 +5209,17 @@ var AIAgentPanel = ({
|
|
|
5209
5209
|
let filtered = apiConversations;
|
|
5210
5210
|
if (searchQuery) {
|
|
5211
5211
|
const query = searchQuery.toLowerCase();
|
|
5212
|
-
filtered = filtered.filter(
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
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
|
+
});
|
|
5218
5220
|
}
|
|
5219
5221
|
return groupConversationsByTime(filtered, true);
|
|
5220
|
-
}, [apiConversations, searchQuery]);
|
|
5222
|
+
}, [apiConversations, searchQuery, conversationFirstPrompts]);
|
|
5221
5223
|
const effectiveCustomer = useMemo4(() => {
|
|
5222
5224
|
return __spreadProps(__spreadValues({}, customer), {
|
|
5223
5225
|
customer_id: customerId
|
|
@@ -5826,6 +5828,9 @@ var AIAgentPanel = ({
|
|
|
5826
5828
|
effectiveCustomer,
|
|
5827
5829
|
showPoweredBy,
|
|
5828
5830
|
actions,
|
|
5831
|
+
initialPrompt,
|
|
5832
|
+
initialMessage,
|
|
5833
|
+
hideInitialPrompt,
|
|
5829
5834
|
followOnQuestions,
|
|
5830
5835
|
followOnPrompt,
|
|
5831
5836
|
agentOptions,
|
|
@@ -5836,7 +5841,8 @@ var AIAgentPanel = ({
|
|
|
5836
5841
|
totalContextTokens: mergedContext.totalTokens || 0,
|
|
5837
5842
|
maxContextTokens,
|
|
5838
5843
|
enableContextDetailView,
|
|
5839
|
-
onConversationCreated: handleConversationCreated
|
|
5844
|
+
onConversationCreated: handleConversationCreated,
|
|
5845
|
+
conversationInitialPrompt: activeConv.conversationInitialPrompt
|
|
5840
5846
|
}
|
|
5841
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..."))),
|
|
5842
5848
|
/* @__PURE__ */ React12.createElement(
|
|
@@ -5850,7 +5856,8 @@ var AIAgentPanel = ({
|
|
|
5850
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"))
|
|
5851
5857
|
)
|
|
5852
5858
|
);
|
|
5853
|
-
};
|
|
5859
|
+
});
|
|
5860
|
+
AIAgentPanel.displayName = "AIAgentPanel";
|
|
5854
5861
|
var AIAgentPanel_default = AIAgentPanel;
|
|
5855
5862
|
|
|
5856
5863
|
// src/hooks/useConversationStore.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hef2024/llmasaservice-ui",
|
|
3
|
-
"version": "0.
|
|
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",
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"build": "tsup index.ts --format cjs,esm --dts",
|
|
10
10
|
"lint": "tsc",
|
|
11
11
|
"storybook": "storybook dev -p 6006",
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
"build-storybook": "storybook build",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"test:watch": "vitest"
|
|
15
15
|
},
|
|
16
16
|
"homepage": "https://llmasaservice.io",
|
|
17
17
|
"repository": {
|
package/src/AIAgentPanel.tsx
CHANGED
|
@@ -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
|
-
//
|
|
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
|
-
|
|
482
|
+
initialMessage ||
|
|
483
|
+
(convAgentMetadata.displayStartMessageOrPrompt === 'message'
|
|
460
484
|
? convAgentMetadata.displayInitialMessageOrPrompt
|
|
461
|
-
: undefined
|
|
485
|
+
: undefined)
|
|
462
486
|
}
|
|
463
487
|
initialPrompt={
|
|
464
|
-
|
|
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
|
|
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
|
-
|
|
1143
|
-
conv.
|
|
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
|
|
package/src/AIChatPanel.tsx
CHANGED
|
@@ -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 (
|
|
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
|
|
1380
|
-
//
|
|
1390
|
+
// Auto-send initialPrompt exactly once when component mounts
|
|
1391
|
+
// Simple behavior matching original ChatPanel - just send the prompt
|
|
1381
1392
|
useEffect(() => {
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
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,
|
|
1397
|
+
}, [initialPrompt, continueChat]);
|
|
1442
1398
|
|
|
1443
1399
|
// ============================================================================
|
|
1444
1400
|
// Render Helpers
|
|
@@ -1581,7 +1537,13 @@ const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
|
|
1581
1537
|
variant="default"
|
|
1582
1538
|
size="sm"
|
|
1583
1539
|
className="ai-chat-agent-suggestion__button"
|
|
1584
|
-
onClick={() =>
|
|
1540
|
+
onClick={() => {
|
|
1541
|
+
onAgentChange(agentId);
|
|
1542
|
+
// Scroll to bottom after a brief delay to let React re-render
|
|
1543
|
+
setTimeout(() => {
|
|
1544
|
+
bottomRef.current?.scrollIntoView({ behavior: 'auto' });
|
|
1545
|
+
}, 50);
|
|
1546
|
+
}}
|
|
1585
1547
|
>
|
|
1586
1548
|
Switch
|
|
1587
1549
|
</Button>
|
package/DEPLOYMENT.md
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
# 📦 Deployment Guide
|
|
2
|
-
|
|
3
|
-
## Current Status
|
|
4
|
-
- ✅ Build successful (version 0.16.8)
|
|
5
|
-
- ✅ Tests passing (17 tests passed)
|
|
6
|
-
- ✅ Ready to publish
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## Step 1: Login to npm
|
|
11
|
-
|
|
12
|
-
**Important:** You need to be logged in as the owner of the `@hef2024` scope.
|
|
13
|
-
|
|
14
|
-
```bash
|
|
15
|
-
npm login
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
You'll be prompted for:
|
|
19
|
-
- Username (must be the owner of @hef2024 scope)
|
|
20
|
-
- Password
|
|
21
|
-
- Email
|
|
22
|
-
- OTP (if 2FA is enabled)
|
|
23
|
-
|
|
24
|
-
Verify you're logged in:
|
|
25
|
-
```bash
|
|
26
|
-
npm whoami
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
**Note:** If this is the first time publishing this package, make sure you have access to the `@hef2024` scope on npm. If you don't own this scope, you'll need to either:
|
|
30
|
-
1. Create the scope on npm (if available)
|
|
31
|
-
2. Change the package name in `package.json` to a scope you own
|
|
32
|
-
3. Publish without a scope (remove `@hef2024/` prefix)
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Step 2: Publish the Package
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
# Make sure you're in the llmasaservice-ui-1 directory
|
|
40
|
-
cd /Users/indomitablehef/llmasaservice-ui-1
|
|
41
|
-
|
|
42
|
-
# Build the package (already done, but good to verify)
|
|
43
|
-
npm run build
|
|
44
|
-
|
|
45
|
-
# Run tests (already done, but good to verify)
|
|
46
|
-
npm test
|
|
47
|
-
|
|
48
|
-
# Publish to npm
|
|
49
|
-
npm publish --access public
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
**Note:** The package name is `@hef2024/llmasaservice-ui` and it's scoped, so `--access public` is required.
|
|
53
|
-
|
|
54
|
-
**If you get a 404 error:**
|
|
55
|
-
- This might be the first publish of this package
|
|
56
|
-
- Make sure you're logged in as the owner of the `@hef2024` scope
|
|
57
|
-
- If the scope doesn't exist or you don't have access, you'll need to either create it on npm or change the package name
|
|
58
|
-
|
|
59
|
-
---
|
|
60
|
-
|
|
61
|
-
## Step 3: Unlink in FocusedFit
|
|
62
|
-
|
|
63
|
-
Navigate to your FocusedFit project directory and run:
|
|
64
|
-
|
|
65
|
-
```bash
|
|
66
|
-
# Unlink the local development version
|
|
67
|
-
npm unlink @hef2024/llmasaservice-ui
|
|
68
|
-
|
|
69
|
-
# Or if it was linked as 'llmasaservice-ui':
|
|
70
|
-
npm unlink llmasaservice-ui
|
|
71
|
-
|
|
72
|
-
# Restore to published version
|
|
73
|
-
npm install
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**Alternative:** If the unlink doesn't work, you can manually remove the link:
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
# Check if it's linked
|
|
80
|
-
npm ls @hef2024/llmasaservice-ui
|
|
81
|
-
|
|
82
|
-
# Remove node_modules and package-lock.json
|
|
83
|
-
rm -rf node_modules package-lock.json
|
|
84
|
-
|
|
85
|
-
# Reinstall
|
|
86
|
-
npm install
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
## Step 4: Install Published Version in FocusedFit
|
|
92
|
-
|
|
93
|
-
In your FocusedFit project:
|
|
94
|
-
|
|
95
|
-
```bash
|
|
96
|
-
# Install the published version
|
|
97
|
-
npm install @hef2024/llmasaservice-ui@latest
|
|
98
|
-
|
|
99
|
-
# Or install a specific version
|
|
100
|
-
npm install @hef2024/llmasaservice-ui@0.16.8
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Step 5: Verify Installation
|
|
106
|
-
|
|
107
|
-
In your FocusedFit project:
|
|
108
|
-
|
|
109
|
-
```bash
|
|
110
|
-
# Check installed version
|
|
111
|
-
npm ls @hef2024/llmasaservice-ui
|
|
112
|
-
|
|
113
|
-
# Should show something like:
|
|
114
|
-
# @hef2024/llmasaservice-ui@0.16.8
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## Troubleshooting
|
|
120
|
-
|
|
121
|
-
### If unlink fails:
|
|
122
|
-
```bash
|
|
123
|
-
# Remove the symlink manually
|
|
124
|
-
rm -rf node_modules/@hef2024/llmasaservice-ui
|
|
125
|
-
rm -rf node_modules/llmasaservice-ui
|
|
126
|
-
|
|
127
|
-
# Clear npm cache
|
|
128
|
-
npm cache clean --force
|
|
129
|
-
|
|
130
|
-
# Reinstall
|
|
131
|
-
npm install
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
### If you see "local" or "file:" in npm ls:
|
|
135
|
-
The package is still linked. Make sure you:
|
|
136
|
-
1. Ran `npm unlink` in FocusedFit
|
|
137
|
-
2. Removed `node_modules` and `package-lock.json`
|
|
138
|
-
3. Ran `npm install` again
|
|
139
|
-
|
|
140
|
-
### To verify the link is removed:
|
|
141
|
-
```bash
|
|
142
|
-
# In FocusedFit directory
|
|
143
|
-
cat node_modules/@hef2024/llmasaservice-ui/package.json
|
|
144
|
-
# Should NOT show a "link" field or point to a local path
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Quick Reference
|
|
150
|
-
|
|
151
|
-
### In llmasaservice-ui-1 (this package):
|
|
152
|
-
```bash
|
|
153
|
-
npm run build # Build the package
|
|
154
|
-
npm test # Run tests
|
|
155
|
-
npm publish --access public # Publish to npm
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### In FocusedFit (consuming app):
|
|
159
|
-
```bash
|
|
160
|
-
npm unlink @hef2024/llmasaservice-ui # Unlink local version
|
|
161
|
-
npm install # Restore dependencies
|
|
162
|
-
npm install @hef2024/llmasaservice-ui@latest # Install published version
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
---
|
|
166
|
-
|
|
167
|
-
## Version Bumping (for future releases)
|
|
168
|
-
|
|
169
|
-
When you need to publish a new version:
|
|
170
|
-
|
|
171
|
-
1. Update version in `package.json`:
|
|
172
|
-
```json
|
|
173
|
-
"version": "0.16.9"
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
2. Build and test:
|
|
177
|
-
```bash
|
|
178
|
-
npm run build
|
|
179
|
-
npm test
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
3. Commit and tag:
|
|
183
|
-
```bash
|
|
184
|
-
git add package.json
|
|
185
|
-
git commit -m "Bump version to 0.16.9"
|
|
186
|
-
git tag v0.16.9
|
|
187
|
-
git push origin main --tags
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
4. Publish:
|
|
191
|
-
```bash
|
|
192
|
-
npm publish --access public
|
|
193
|
-
```
|