llmasaservice-ui 0.9.12 → 0.10.2

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.
@@ -1,4 +1,5 @@
1
1
  import type { StorybookConfig } from "@storybook/react-webpack5";
2
+ import webpack from 'webpack';
2
3
 
3
4
  const config: StorybookConfig = {
4
5
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
@@ -14,5 +15,34 @@ const config: StorybookConfig = {
14
15
  name: "@storybook/react-webpack5",
15
16
  options: {},
16
17
  },
18
+ webpackFinal: async (config) => {
19
+ // Provide fallbacks for node built-ins
20
+ config.resolve!.fallback = {
21
+ ...config.resolve!.fallback,
22
+ process: require.resolve("process/browser"),
23
+ child_process: false,
24
+ };
25
+
26
+ // Set up aliases
27
+ config.resolve!.alias = {
28
+ ...config.resolve!.alias,
29
+ "node:process": require.resolve("process/browser"),
30
+ };
31
+
32
+ // Add ProvidePlugin to inject process globally
33
+ config.plugins = [
34
+ ...(config.plugins || []),
35
+ new webpack.ProvidePlugin({
36
+ process: "process/browser",
37
+ }),
38
+ // Handle node:process scheme
39
+ new webpack.NormalModuleReplacementPlugin(/node:process/, (resource) => {
40
+ resource.request = "process/browser";
41
+ }),
42
+ ];
43
+
44
+ return config;
45
+ },
17
46
  };
18
- export default config;
47
+
48
+ export default config;
package/dist/index.d.mts CHANGED
@@ -67,6 +67,7 @@ interface ChatPanelProps {
67
67
  createConversationOnFirstChat?: boolean;
68
68
  customerEmailCaptureMode?: "HIDE" | "OPTIONAL" | "REQUIRED";
69
69
  customerEmailCapturePlaceholder?: string;
70
+ mcpServers: [];
70
71
  }
71
72
  interface ExtraProps$1 extends React.HTMLAttributes<HTMLElement> {
72
73
  inline?: boolean;
package/dist/index.d.ts CHANGED
@@ -67,6 +67,7 @@ interface ChatPanelProps {
67
67
  createConversationOnFirstChat?: boolean;
68
68
  customerEmailCaptureMode?: "HIDE" | "OPTIONAL" | "REQUIRED";
69
69
  customerEmailCapturePlaceholder?: string;
70
+ mcpServers: [];
70
71
  }
71
72
  interface ExtraProps$1 extends React.HTMLAttributes<HTMLElement> {
72
73
  inline?: boolean;
package/dist/index.js CHANGED
@@ -127,6 +127,89 @@ var EmailModal = ({ isOpen, onClose, onSend, defaultEmail }) => {
127
127
  };
128
128
  var EmailModal_default = EmailModal;
129
129
 
130
+ // src/mcpClient.ts
131
+ var import_client = require("@modelcontextprotocol/sdk/client/index.js");
132
+ var import_sse = require("@modelcontextprotocol/sdk/client/sse.js");
133
+ var MCPClient = class {
134
+ constructor(name, url, headers = []) {
135
+ this.tools = [];
136
+ this.transport = new import_sse.SSEClientTransport(new URL(url));
137
+ this.client = new import_client.Client(
138
+ {
139
+ name,
140
+ version: "1.0.0"
141
+ },
142
+ { capabilities: { tools: {}, resources: {}, prompts: {} } }
143
+ );
144
+ this.headers = headers;
145
+ }
146
+ connect() {
147
+ return __async(this, null, function* () {
148
+ yield this.client.connect(this.transport);
149
+ });
150
+ }
151
+ disconnect() {
152
+ return __async(this, null, function* () {
153
+ yield this.client.close();
154
+ });
155
+ }
156
+ listTools() {
157
+ return __async(this, null, function* () {
158
+ var _a;
159
+ const result = yield this.client.listTools();
160
+ this.tools = Array.isArray(result) ? result : (_a = result.tools) != null ? _a : [];
161
+ return this.tools;
162
+ });
163
+ }
164
+ getNormalizedTools() {
165
+ const formattedTools = [];
166
+ this.tools.forEach(
167
+ (t) => formattedTools.push({
168
+ name: t.name,
169
+ description: t.description || `Tool: ${t.name}`,
170
+ input_schema: t.inputSchema
171
+ })
172
+ );
173
+ return formattedTools;
174
+ }
175
+ toolExists(name) {
176
+ return this.tools.some((tool) => tool.name === name);
177
+ }
178
+ listPrompts() {
179
+ return __async(this, null, function* () {
180
+ return yield this.client.listPrompts();
181
+ });
182
+ }
183
+ getPrompt(name, args) {
184
+ return __async(this, null, function* () {
185
+ return yield this.client.getPrompt({
186
+ name,
187
+ arguments: args
188
+ });
189
+ });
190
+ }
191
+ listResources() {
192
+ return __async(this, null, function* () {
193
+ return yield this.client.listResources();
194
+ });
195
+ }
196
+ readResource(uri) {
197
+ return __async(this, null, function* () {
198
+ return yield this.client.readResource({
199
+ uri
200
+ });
201
+ });
202
+ }
203
+ callTool(name, args) {
204
+ return __async(this, null, function* () {
205
+ return yield this.client.callTool({
206
+ name,
207
+ arguments: args
208
+ });
209
+ });
210
+ }
211
+ };
212
+
130
213
  // src/ChatPanel.tsx
131
214
  var ChatPanel = ({
132
215
  project_id,
@@ -169,7 +252,8 @@ var ChatPanel = ({
169
252
  hideRagContextInPrompt = true,
170
253
  createConversationOnFirstChat = true,
171
254
  customerEmailCaptureMode = "HIDE",
172
- customerEmailCapturePlaceholder = "Please enter your email..."
255
+ customerEmailCapturePlaceholder = "Please enter your email...",
256
+ mcpServers = []
173
257
  }) => {
174
258
  var _a;
175
259
  const isEmailAddress = (email) => {
@@ -178,6 +262,7 @@ var ChatPanel = ({
178
262
  };
179
263
  const [nextPrompt, setNextPrompt] = (0, import_react2.useState)("");
180
264
  const [lastController, setLastController] = (0, import_react2.useState)(new AbortController());
265
+ const [lastMessages, setLastMessages] = (0, import_react2.useState)([]);
181
266
  const [history, setHistory] = (0, import_react2.useState)(initialHistory);
182
267
  const [isLoading, setIsLoading] = (0, import_react2.useState)(false);
183
268
  const [lastPrompt, setLastPrompt] = (0, import_react2.useState)(null);
@@ -204,23 +289,59 @@ var ChatPanel = ({
204
289
  const [CTAClickedButNoEmail, setCTAClickedButNoEmail] = (0, import_react2.useState)(false);
205
290
  const [emailSent, setEmailSent] = (0, import_react2.useState)(false);
206
291
  const [emailClickedButNoEmail, setEmailClickedButNoEmail] = (0, import_react2.useState)(false);
207
- const handleSendEmail = (to, from) => {
208
- sendConversationsViaEmail(to, `Conversation History from ${title}`, from);
209
- interactionClicked(lastCallId, "email", to);
210
- setEmailSent(true);
211
- };
212
292
  const [currentCustomer, setCurrentCustomer] = (0, import_react2.useState)(customer);
213
- const { send, response, idle, stop, lastCallId } = (0, import_llmasaservice_client.useLLM)({
214
- project_id,
215
- customer: currentCustomer,
216
- url,
217
- agent
218
- });
293
+ const [allActions, setAllActions] = (0, import_react2.useState)([]);
219
294
  const responseAreaRef = (0, import_react2.useRef)(null);
220
295
  let publicAPIUrl = "https://api.llmasaservice.io";
221
296
  if (window.location.hostname === "localhost" || window.location.hostname === "dev.llmasaservice.io") {
222
297
  publicAPIUrl = "https://8ftw8droff.execute-api.us-east-1.amazonaws.com/dev";
223
298
  }
299
+ const [mcpClients, setMcpClients] = (0, import_react2.useState)([]);
300
+ const [convertedTools, setConvertedTools] = (0, import_react2.useState)([]);
301
+ (0, import_react2.useEffect)(() => {
302
+ const list = Array.isArray(mcpServers) ? mcpServers : [];
303
+ const clients = list.map(
304
+ (m) => new MCPClient(m.sseUrl, m.sseUrl, m.sseHeaders)
305
+ );
306
+ setMcpClients(clients);
307
+ return () => {
308
+ clients.forEach((c) => c.disconnect());
309
+ };
310
+ }, [mcpServers]);
311
+ (0, import_react2.useEffect)(() => {
312
+ if (mcpClients.length === 0) return;
313
+ (() => __async(void 0, null, function* () {
314
+ const tools = [];
315
+ yield Promise.all(
316
+ mcpClients.map((client) => __async(void 0, null, function* () {
317
+ var _a2;
318
+ try {
319
+ yield client.connect();
320
+ const list = yield client.listTools();
321
+ console.log("listTools()", list);
322
+ const arr = Array.isArray(list) ? list : (_a2 = list.tools) != null ? _a2 : [];
323
+ arr.forEach(
324
+ (t) => tools.push({
325
+ name: t.name,
326
+ description: t.description || `Tool: ${t.name}`,
327
+ parameters: t.inputSchema
328
+ })
329
+ );
330
+ } catch (e) {
331
+ console.error("listTools() failed", e);
332
+ }
333
+ }))
334
+ );
335
+ setConvertedTools(tools);
336
+ }))();
337
+ }, [mcpClients]);
338
+ const { send, response, idle, stop, lastCallId } = (0, import_llmasaservice_client.useLLM)({
339
+ project_id,
340
+ customer: currentCustomer,
341
+ url,
342
+ agent,
343
+ tools: convertedTools
344
+ });
224
345
  (0, import_react2.useEffect)(() => {
225
346
  setShowEmailPanel(customerEmailCaptureMode !== "HIDE");
226
347
  if (customerEmailCaptureMode === "REQUIRED") {
@@ -292,12 +413,170 @@ var ChatPanel = ({
292
413
  });
293
414
  };
294
415
  }, [cssUrl]);
416
+ const toolUseCallback = (0, import_react2.useCallback)(
417
+ (match, groups) => __async(void 0, null, function* () {
418
+ var _a2, _b, _c, _d, _e, _f;
419
+ for (const client of mcpClients) {
420
+ console.log("tool", groups[1]);
421
+ console.log("input", groups[2]);
422
+ if (client.toolExists(groups[1])) {
423
+ console.log("tool exists", groups[1]);
424
+ setIsLoading(true);
425
+ try {
426
+ let args;
427
+ try {
428
+ args = JSON.parse(groups[2]);
429
+ } catch (e) {
430
+ try {
431
+ args = JSON.parse(groups[2].replace(/\\"/g, '"'));
432
+ } catch (err) {
433
+ console.error("Failed to parse tool arguments:", err);
434
+ console.log("Raw argument string:", groups[2]);
435
+ throw new Error("Could not parse tool arguments");
436
+ }
437
+ }
438
+ const result = yield client.callTool(groups[1], args);
439
+ if (result && result.content && ((_a2 = result.content) == null ? void 0 : _a2.length) > 0) {
440
+ const textResult = (_b = result.content[0]) == null ? void 0 : _b.text;
441
+ const messagesAndHistory = lastMessages;
442
+ messagesAndHistory.push({
443
+ role: "user",
444
+ content: [
445
+ {
446
+ type: "text",
447
+ text: lastPrompt != null ? lastPrompt : ""
448
+ }
449
+ ]
450
+ });
451
+ messagesAndHistory.push({
452
+ role: "assistant",
453
+ content: [],
454
+ tool_calls: [JSON.parse(match)]
455
+ });
456
+ messagesAndHistory.push({
457
+ role: "tool",
458
+ content: [
459
+ {
460
+ type: "text",
461
+ text: textResult
462
+ }
463
+ ],
464
+ tool_call_id: groups[0]
465
+ });
466
+ const browserInfo = getBrowserInfo();
467
+ send(
468
+ "",
469
+ messagesAndHistory,
470
+ [
471
+ ...data,
472
+ {
473
+ key: "--customer_id",
474
+ data: (_c = currentCustomer == null ? void 0 : currentCustomer.customer_id) != null ? _c : ""
475
+ },
476
+ {
477
+ key: "--customer_name",
478
+ data: (_d = currentCustomer == null ? void 0 : currentCustomer.customer_name) != null ? _d : ""
479
+ },
480
+ {
481
+ key: "--customer_user_id",
482
+ data: (_e = currentCustomer == null ? void 0 : currentCustomer.customer_user_id) != null ? _e : ""
483
+ },
484
+ {
485
+ key: "--customer_user_email",
486
+ data: (_f = currentCustomer == null ? void 0 : currentCustomer.customer_user_email) != null ? _f : ""
487
+ },
488
+ { key: "--email", data: emailInput != null ? emailInput : "" },
489
+ { key: "--emailValid", data: emailValid ? "true" : "false" },
490
+ {
491
+ key: "--emailInputSet",
492
+ data: emailInputSet ? "true" : "false"
493
+ },
494
+ {
495
+ key: "--emailPanelShowing",
496
+ data: showEmailPanel ? "true" : "false"
497
+ },
498
+ {
499
+ key: "--callToActionSent",
500
+ data: callToActionSent ? "true" : "false"
501
+ },
502
+ {
503
+ key: "--CTAClickedButNoEmail",
504
+ data: CTAClickedButNoEmail ? "true" : "false"
505
+ },
506
+ { key: "--emailSent", data: emailSent ? "true" : "false" },
507
+ {
508
+ key: "--emailClickedButNoEmail",
509
+ data: emailClickedButNoEmail ? "true" : "false"
510
+ },
511
+ {
512
+ key: "--messages",
513
+ data: messagesAndHistory.length.toString()
514
+ },
515
+ {
516
+ key: "--currentTimeUTC",
517
+ data: browserInfo == null ? void 0 : browserInfo.currentTimeUTC
518
+ },
519
+ { key: "--userTimezone", data: browserInfo == null ? void 0 : browserInfo.userTimezone },
520
+ { key: "--userLanguage", data: browserInfo == null ? void 0 : browserInfo.userLanguage }
521
+ ],
522
+ true,
523
+ true,
524
+ service && service !== "" ? service : groups[3],
525
+ // call the same service that asked for the tool_use
526
+ currentConversation,
527
+ lastController
528
+ );
529
+ } else {
530
+ console.error("No content in result", result);
531
+ }
532
+ } catch (error) {
533
+ console.error("Error calling tool:", error);
534
+ }
535
+ }
536
+ }
537
+ }),
538
+ [
539
+ mcpClients,
540
+ lastPrompt,
541
+ lastMessages,
542
+ lastController,
543
+ data,
544
+ service,
545
+ currentConversation
546
+ ]
547
+ );
548
+ (0, import_react2.useEffect)(() => {
549
+ const anthropic_toolAction = {
550
+ pattern: '\\{"type":"tool_use","id":"([^"]+)","name":"([^"]+)","input":(\\{[^}]+\\}),"service":"([^"]+)"\\}',
551
+ type: "button",
552
+ markdown: "Approve Tool Use: $2",
553
+ callback: toolUseCallback
554
+ };
555
+ const openAI_toolAction = {
556
+ pattern: '\\{"id":"([^"]+)","type":"function","function":\\{"name":"([^"]+)","arguments":"((?:\\\\.|[^"\\\\])*)"\\},"service":"([^"]+)"\\}',
557
+ type: "button",
558
+ markdown: "Approve Tool Use: $2",
559
+ callback: toolUseCallback
560
+ };
561
+ const google_toolAction = {
562
+ pattern: '^\\{\\s*"(functionCall)"\\s*:\\s*\\{\\s*"name"\\s*:\\s*"([^"]+)"\\s*,\\s*"args"\\s*:\\s*(\\{[^}]+\\})\\s*\\}\\s*,\\s*"service"\\s*:\\s*"([^"]+)"\\s*\\}$',
563
+ type: "button",
564
+ markdown: "Approve Tool Use: $2",
565
+ callback: toolUseCallback
566
+ };
567
+ setAllActions([
568
+ ...actions,
569
+ anthropic_toolAction,
570
+ openAI_toolAction,
571
+ google_toolAction
572
+ ]);
573
+ }, [actions, toolUseCallback]);
295
574
  (0, import_react2.useEffect)(() => {
296
575
  if (response && response.length > 0) {
297
576
  setIsLoading(false);
298
577
  let newResponse = response;
299
- if (actions && actions.length > 0) {
300
- actions.forEach((action, index) => {
578
+ if (allActions && allActions.length > 0) {
579
+ allActions.forEach((action, index) => {
301
580
  const regex = new RegExp(action.pattern, "gmi");
302
581
  newResponse = newResponse.replace(regex, (match, ...groups) => {
303
582
  var _a2, _b;
@@ -306,7 +585,7 @@ var ChatPanel = ({
306
585
  const buttonId = `button-${messages.length}-${index}-${matchIndex}`;
307
586
  let html = match;
308
587
  if (action.type === "button" || action.type === "callback") {
309
- html = ` <button id="${buttonId}" ${action.style ? 'class=" ' + action.style + '"' : ""}>${(_a2 = action.markdown) != null ? _a2 : match}</button>`;
588
+ html = `<br /> <button id="${buttonId}" ${action.style ? 'class=" ' + action.style + '"' : ""}>${(_a2 = action.markdown) != null ? _a2 : match}</button>`;
310
589
  } else if (action.type === "markdown" || action.type === "html") {
311
590
  html = (_b = action.markdown) != null ? _b : "";
312
591
  }
@@ -430,6 +709,7 @@ var ChatPanel = ({
430
709
  controller
431
710
  );
432
711
  setLastPrompt(initialPrompt);
712
+ setLastMessages(messages);
433
713
  setLastKey(initialPrompt);
434
714
  setLastController(controller);
435
715
  setHistory({});
@@ -716,6 +996,7 @@ var ChatPanel = ({
716
996
  controller
717
997
  );
718
998
  setLastPrompt(nextPromptToSend);
999
+ setLastMessages(messagesAndHistory);
719
1000
  setLastKey(promptKey);
720
1001
  setLastController(controller);
721
1002
  setNextPrompt("");
@@ -902,6 +1183,11 @@ var ChatPanel = ({
902
1183
  )}&body=${encodeURIComponent(html)}`;
903
1184
  window.location.href = mailtoLink;
904
1185
  };
1186
+ const handleSendEmail = (to, from) => {
1187
+ sendConversationsViaEmail(to, `Conversation History from ${title}`, from);
1188
+ interactionClicked(lastCallId, "email", to);
1189
+ setEmailSent(true);
1190
+ };
905
1191
  const handleSuggestionClick = (suggestion) => {
906
1192
  continueChat(suggestion);
907
1193
  interactionClicked(lastCallId, "suggestion");
@@ -1000,7 +1286,7 @@ var ChatPanel = ({
1000
1286
  rehypePlugins: [import_rehype_raw.default]
1001
1287
  },
1002
1288
  initialMessage
1003
- ))) : null, Object.entries(history).map(([prompt, response2], index) => /* @__PURE__ */ import_react2.default.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ import_react2.default.createElement("div", { className: "prompt" }, formatPromptForDisplay(prompt)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading ? /* @__PURE__ */ import_react2.default.createElement("div", { className: "loading-text" }, "loading...") : null, /* @__PURE__ */ import_react2.default.createElement(
1289
+ ))) : null, Object.entries(history).map(([prompt, response2], index) => /* @__PURE__ */ import_react2.default.createElement("div", { className: "history-entry", key: index }, hideInitialPrompt && index === 0 ? null : /* @__PURE__ */ import_react2.default.createElement("div", { className: "prompt" }, formatPromptForDisplay(prompt)), /* @__PURE__ */ import_react2.default.createElement("div", { className: "response" }, index === Object.keys(history).length - 1 && isLoading ? /* @__PURE__ */ import_react2.default.createElement("div", { className: "loading-text" }, "thinking...") : null, /* @__PURE__ */ import_react2.default.createElement(
1004
1290
  import_react_markdown.default,
1005
1291
  {
1006
1292
  className: markdownClass,
@@ -1486,7 +1772,8 @@ var AgentPanel = ({
1486
1772
  markdownClass = null,
1487
1773
  width,
1488
1774
  height,
1489
- url = "https://chat.llmasaservice.io/",
1775
+ url = "https://chat.llmasaservice.io",
1776
+ //url = "https://chat.llmasaservice.io/dev",
1490
1777
  //scrollToEnd = false,
1491
1778
  //initialMessage = "",
1492
1779
  prismStyle = null,
@@ -1517,21 +1804,31 @@ var AgentPanel = ({
1517
1804
  const customer_id = searchParams.get("customer_id") || "";
1518
1805
  const customer_email = searchParams.get("customer_email") || "";
1519
1806
  const [agentData, setAgentData] = (0, import_react3.useState)(null);
1807
+ const [mcpData, setMCPData] = (0, import_react3.useState)(null);
1520
1808
  (0, import_react3.useEffect)(() => {
1521
1809
  const fetchAgentData = () => __async(void 0, null, function* () {
1522
1810
  try {
1523
- const response = yield fetch(
1524
- url.endsWith("dev") ? `https://8ftw8droff.execute-api.us-east-1.amazonaws.com/dev/agents/${agent}` : `https://api.llmasaservice.io/agents/${agent}`,
1525
- {
1811
+ const fetchUrl = url.endsWith("dev") ? `https://8ftw8droff.execute-api.us-east-1.amazonaws.com/dev/agents/${agent}` : `https://api.llmasaservice.io/agents/${agent}`;
1812
+ const response = yield fetch(fetchUrl, {
1813
+ method: "GET",
1814
+ headers: {
1815
+ "Content-Type": "application/json"
1816
+ }
1817
+ });
1818
+ const data2 = yield response.json();
1819
+ if (data2 && data2.length > 0) {
1820
+ setAgentData(data2[0]);
1821
+ const response2 = yield fetch(fetchUrl + "/mcp", {
1526
1822
  method: "GET",
1527
1823
  headers: {
1528
1824
  "Content-Type": "application/json"
1529
1825
  }
1826
+ });
1827
+ const mcpData2 = yield response2.json();
1828
+ if (mcpData2 && mcpData2.length > 0) {
1829
+ console.log("MCP servers", mcpData2);
1830
+ setMCPData(mcpData2);
1530
1831
  }
1531
- );
1532
- const data2 = yield response.json();
1533
- if (data2 && data2.length > 0) {
1534
- setAgentData(data2[0]);
1535
1832
  }
1536
1833
  } catch (error) {
1537
1834
  console.error("Error fetching agent data:", error);
@@ -1540,7 +1837,7 @@ var AgentPanel = ({
1540
1837
  if (agent && agent !== "") {
1541
1838
  fetchAgentData();
1542
1839
  }
1543
- }, [agent]);
1840
+ }, [agent, url]);
1544
1841
  const getActionsArraySafely = (actionsString) => {
1545
1842
  let actions2 = [];
1546
1843
  if (actionsString && actionsString !== "") {
@@ -1602,7 +1899,8 @@ var AgentPanel = ({
1602
1899
  hideRagContextInPrompt,
1603
1900
  createConversationOnFirstChat: (_s = agentData == null ? void 0 : agentData.createConversationOnFirstChat) != null ? _s : true,
1604
1901
  customerEmailCaptureMode: (_t = agentData == null ? void 0 : agentData.customerEmailCaptureMode) != null ? _t : "HIDE",
1605
- customerEmailCapturePlaceholder: (_u = agentData == null ? void 0 : agentData.customerEmailCapturePlaceholder) != null ? _u : "Please enter your email..."
1902
+ customerEmailCapturePlaceholder: (_u = agentData == null ? void 0 : agentData.customerEmailCapturePlaceholder) != null ? _u : "Please enter your email...",
1903
+ mcpServers: mcpData
1606
1904
  }
1607
1905
  ));
1608
1906
  };