@spteck/react-controls-v2 2.0.14 → 2.0.16

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.
Files changed (38) hide show
  1. package/dist/components/ContentRenderer/ContentRenderer.d.ts +45 -0
  2. package/dist/components/ContentRenderer/ContentRenderer.d.ts.map +1 -0
  3. package/dist/components/ContentRenderer/index.d.ts +3 -0
  4. package/dist/components/ContentRenderer/index.d.ts.map +1 -0
  5. package/dist/components/MarkdownRenderer/MarkdownRenderer.d.ts +11 -0
  6. package/dist/components/MarkdownRenderer/MarkdownRenderer.d.ts.map +1 -0
  7. package/dist/components/MarkdownRenderer/index.d.ts +2 -0
  8. package/dist/components/MarkdownRenderer/index.d.ts.map +1 -0
  9. package/dist/components/aiAssistant/AIAssistant.d.ts +1 -1
  10. package/dist/components/aiAssistant/AIAssistant.d.ts.map +1 -1
  11. package/dist/components/aiAssistant/ChatList.d.ts +9 -0
  12. package/dist/components/aiAssistant/ChatList.d.ts.map +1 -0
  13. package/dist/components/aiAssistant/IAIAssistantProps.d.ts +1 -0
  14. package/dist/components/aiAssistant/IAIAssistantProps.d.ts.map +1 -1
  15. package/dist/components/aiAssistant/index.d.ts +1 -0
  16. package/dist/components/aiAssistant/index.d.ts.map +1 -1
  17. package/dist/components/aiAssistant/useAIAssistantStyles.d.ts +2 -0
  18. package/dist/components/aiAssistant/useAIAssistantStyles.d.ts.map +1 -1
  19. package/dist/components/aiAssistant/useStreamRequest.d.ts.map +1 -1
  20. package/dist/components/index.d.ts +2 -0
  21. package/dist/components/index.d.ts.map +1 -1
  22. package/dist/hooks/index.d.ts +2 -0
  23. package/dist/hooks/index.d.ts.map +1 -1
  24. package/dist/hooks/useAIAssistant.d.ts +50 -0
  25. package/dist/hooks/useAIAssistant.d.ts.map +1 -0
  26. package/dist/hooks/useAIAssistantParser.d.ts +45 -0
  27. package/dist/hooks/useAIAssistantParser.d.ts.map +1 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +19 -19
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +868 -268
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/utils/contentDetector.d.ts +28 -0
  35. package/dist/utils/contentDetector.d.ts.map +1 -0
  36. package/dist/utils/index.d.ts +1 -0
  37. package/dist/utils/index.d.ts.map +1 -1
  38. package/package.json +8 -6
package/dist/index.mjs CHANGED
@@ -28,13 +28,14 @@ import * as AC from "adaptivecards";
28
28
  import { HostConfig as HostConfig$1, AdaptiveCard as AdaptiveCard$1, generateUniqueId as generateUniqueId$1, Input as Input$1, StringProperty as StringProperty$1, Versions as Versions$1, SerializableObjectCollectionProperty as SerializableObjectCollectionProperty$1, Choice as Choice$1, ValueSetProperty as ValueSetProperty$1, BoolProperty as BoolProperty$1, ValidationEvent, Strings as Strings$1, property as property$1, NumProperty as NumProperty$1, EnumProperty as EnumProperty$1, InputTextStyle, ActionProperty as ActionProperty$1, TimeProperty as TimeProperty$1, SerializationContext as SerializationContext$1, ExecuteAction as ExecuteAction$1, SubmitAction as SubmitAction$1, OpenUrlAction as OpenUrlAction$1, CardObjectRegistry as CardObjectRegistry$1, GlobalRegistry as GlobalRegistry$1 } from "adaptivecards";
29
29
  import { create } from "nano-css";
30
30
  import * as markdown from "markdown-it";
31
+ import markdown__default from "markdown-it";
31
32
  import { DatePicker } from "@fluentui/react-datepicker-compat";
32
33
  import { formatDateToTimeString, TimePicker as TimePicker$1 } from "@fluentui/react-timepicker-compat";
33
34
  import { initializeIcons } from "@fluentui/react/lib/Icons";
34
35
  import { Expression } from "adaptive-expressions";
35
36
  import { Template } from "adaptivecards-templating";
36
- import { Chat, ChatMyMessage, ChatMessage } from "@fluentui-contrib/react-chat";
37
37
  import getCaretCoordinates from "textarea-caret";
38
+ import { Chat, ChatMyMessage, ChatMessage } from "@fluentui-contrib/react-chat";
38
39
  import { Fade } from "@fluentui/react-motion-components-preview";
39
40
  var EBreakPoints = /* @__PURE__ */ ((EBreakPoints2) => {
40
41
  EBreakPoints2[EBreakPoints2["XXXLarge"] = 1900] = "XXXLarge";
@@ -297,6 +298,311 @@ const useTimeZoneHelper$1 = () => {
297
298
  getUserTimeZone
298
299
  };
299
300
  };
301
+ const useAIAssistantParser = () => {
302
+ const parseSSEResponse = useCallback((rawResponse, options = {}) => {
303
+ const { stripMarkdown = true, debug = false } = options;
304
+ if (!rawResponse || typeof rawResponse !== "string") {
305
+ return {
306
+ data: void 0,
307
+ rawText: "",
308
+ isJson: false,
309
+ error: "Invalid input: rawResponse must be a non-empty string"
310
+ };
311
+ }
312
+ try {
313
+ if (debug) {
314
+ console.log("[useAIAssistantParser] Raw SSE input (full):", rawResponse);
315
+ console.log("[useAIAssistantParser] Raw SSE length:", rawResponse.length);
316
+ }
317
+ const lines = rawResponse.split("\n");
318
+ const dataLines = [];
319
+ let foundData = false;
320
+ let currentDataBlock = "";
321
+ let inDataBlock = false;
322
+ for (let i = 0; i < lines.length; i++) {
323
+ const line2 = lines[i];
324
+ if (debug && i < 20) {
325
+ console.log(`[useAIAssistantParser] Line ${i}:`, JSON.stringify(line2));
326
+ }
327
+ if (line2.startsWith("event: done")) {
328
+ if (currentDataBlock.trim()) {
329
+ dataLines.push(currentDataBlock.trim());
330
+ currentDataBlock = "";
331
+ }
332
+ break;
333
+ }
334
+ if (line2.startsWith("event:") && !line2.startsWith("event: done")) {
335
+ if (currentDataBlock.trim()) {
336
+ dataLines.push(currentDataBlock.trim());
337
+ currentDataBlock = "";
338
+ }
339
+ inDataBlock = false;
340
+ continue;
341
+ }
342
+ if (line2.startsWith("data: ")) {
343
+ const data = line2.substring(6);
344
+ foundData = true;
345
+ if (inDataBlock && currentDataBlock) {
346
+ currentDataBlock += "\n" + data;
347
+ } else {
348
+ currentDataBlock = data;
349
+ inDataBlock = true;
350
+ }
351
+ } else if (line2.trim() === "" && !inDataBlock) {
352
+ continue;
353
+ } else if (inDataBlock && line2.trim() !== "") {
354
+ currentDataBlock += "\n" + line2;
355
+ } else if (line2.trim() === "" && inDataBlock) {
356
+ const nextLineIndex = i + 1;
357
+ if (nextLineIndex < lines.length) {
358
+ const nextLine = lines[nextLineIndex];
359
+ if (nextLine.startsWith("event:") || nextLineIndex === lines.length - 1) {
360
+ if (currentDataBlock.trim()) {
361
+ dataLines.push(currentDataBlock.trim());
362
+ currentDataBlock = "";
363
+ }
364
+ inDataBlock = false;
365
+ } else if (nextLine.trim() !== "") {
366
+ currentDataBlock += "\n";
367
+ } else {
368
+ if (currentDataBlock.trim()) {
369
+ dataLines.push(currentDataBlock.trim());
370
+ currentDataBlock = "";
371
+ }
372
+ inDataBlock = false;
373
+ }
374
+ }
375
+ }
376
+ }
377
+ if (currentDataBlock.trim()) {
378
+ dataLines.push(currentDataBlock.trim());
379
+ }
380
+ if (debug) {
381
+ console.log("[useAIAssistantParser] Found", dataLines.length, "data blocks");
382
+ dataLines.forEach((block, idx) => {
383
+ console.log(`[useAIAssistantParser] Block ${idx} (length: ${block.length}):`, block);
384
+ });
385
+ }
386
+ let lastValidJson = void 0;
387
+ let textBlocks = [];
388
+ for (const dataBlock of dataLines) {
389
+ let cleanContent = dataBlock.trim();
390
+ if (stripMarkdown) {
391
+ cleanContent = cleanContent.replace(/^```json\s*/i, "").replace(/```\s*$/, "");
392
+ cleanContent = cleanContent.trim();
393
+ }
394
+ try {
395
+ const jsonData = JSON.parse(cleanContent);
396
+ if (typeof jsonData === "object" && jsonData !== null) {
397
+ const keys = Object.keys(jsonData);
398
+ const metadataFields = ["status", "requestId", "tokenCount", "durationMs"];
399
+ const isMetadataOnly = keys.length > 0 && keys.every((key) => metadataFields.includes(key));
400
+ if (isMetadataOnly) {
401
+ if (debug) {
402
+ console.log("[useAIAssistantParser] Skipping metadata/status-only JSON block:", cleanContent);
403
+ }
404
+ continue;
405
+ }
406
+ }
407
+ lastValidJson = jsonData;
408
+ if (debug) {
409
+ console.log("[useAIAssistantParser] Successfully parsed data block as JSON");
410
+ }
411
+ } catch (e) {
412
+ if (!cleanContent.match(/^\s*\{\s*["']?status["']?\s*:\s*["']?\w+["']?\s*\}\s*$/)) {
413
+ textBlocks.push(cleanContent);
414
+ if (debug) {
415
+ console.log("[useAIAssistantParser] Data block is text, adding to text blocks");
416
+ }
417
+ } else {
418
+ if (debug) {
419
+ console.log("[useAIAssistantParser] Skipping status-like text block:", cleanContent);
420
+ }
421
+ }
422
+ }
423
+ }
424
+ const lastValidText = textBlocks.filter((block) => block.trim().length > 0).join("\n");
425
+ if (debug) {
426
+ console.log("[useAIAssistantParser] Text blocks collected:", textBlocks.length);
427
+ console.log("[useAIAssistantParser] Filtered text blocks:", textBlocks.filter((block) => block.trim().length > 0).length);
428
+ console.log("[useAIAssistantParser] Final combined text length:", lastValidText.length);
429
+ console.log("[useAIAssistantParser] Final combined text:", lastValidText);
430
+ }
431
+ if (!foundData || dataLines.length === 0) {
432
+ return {
433
+ data: void 0,
434
+ rawText: "",
435
+ isJson: false,
436
+ error: "No data found in SSE response. The server may have returned only status messages without actual data."
437
+ };
438
+ }
439
+ if (lastValidJson !== void 0) {
440
+ if (debug) {
441
+ console.log("[useAIAssistantParser] Returning last valid JSON");
442
+ }
443
+ return {
444
+ data: lastValidJson,
445
+ rawText: lastValidText,
446
+ isJson: true
447
+ };
448
+ }
449
+ if (lastValidText) {
450
+ if (debug) {
451
+ console.log("[useAIAssistantParser] No valid JSON found, returning as text");
452
+ }
453
+ return {
454
+ data: void 0,
455
+ rawText: lastValidText,
456
+ isJson: false
457
+ };
458
+ }
459
+ return {
460
+ data: void 0,
461
+ rawText: dataLines.join("\n"),
462
+ isJson: false,
463
+ error: "Could not parse any data blocks as valid JSON"
464
+ };
465
+ } catch (error) {
466
+ if (debug) {
467
+ console.error("[useAIAssistantParser] SSE parsing error:", error);
468
+ }
469
+ return {
470
+ data: void 0,
471
+ rawText: rawResponse,
472
+ isJson: false,
473
+ error: error instanceof Error ? error.message : "Failed to parse SSE response"
474
+ };
475
+ }
476
+ }, []);
477
+ return {
478
+ parseSSEResponse
479
+ };
480
+ };
481
+ const useAIAssistant = (config) => {
482
+ const [response, setResponse] = useState("");
483
+ const [isLoading, setIsLoading] = useState(false);
484
+ const [error, setError] = useState(null);
485
+ const abortControllerRef = useRef(null);
486
+ const { parseSSEResponse } = useAIAssistantParser();
487
+ const conversationIdRef = useRef(
488
+ config.conversationId || crypto.randomUUID()
489
+ );
490
+ const sendMessage = useCallback(
491
+ async (message, onProgress) => {
492
+ var _a3;
493
+ setResponse("");
494
+ setError(null);
495
+ setIsLoading(true);
496
+ const controller = new AbortController();
497
+ abortControllerRef.current = controller;
498
+ let endpoint = config.endpoint || "http://localhost:7071/api/EventAssistant";
499
+ if (endpoint.endsWith("/")) {
500
+ endpoint = endpoint.slice(0, -1);
501
+ }
502
+ try {
503
+ let fullInput = message.input;
504
+ if (message.history && message.history.length > 0) {
505
+ const historyContext = message.history.join("\n\n");
506
+ fullInput = `${historyContext}
507
+
508
+ ${message.input}`;
509
+ }
510
+ const payload = {
511
+ input: fullInput,
512
+ instructions: message.instructions,
513
+ mode: void 0,
514
+ // future extension
515
+ conversationId: conversationIdRef.current,
516
+ // Use ref value (stays same across renders)
517
+ mcpServers: message.mcpServers || config.mcpServers
518
+ };
519
+ const fetchResponse = await fetch(endpoint, {
520
+ method: "POST",
521
+ headers: {
522
+ "Content-Type": "application/json",
523
+ "Accept": "text/event-stream"
524
+ },
525
+ body: JSON.stringify(payload),
526
+ signal: controller.signal
527
+ });
528
+ if (!fetchResponse.ok) {
529
+ let errorDetails = "";
530
+ try {
531
+ const errorText = await fetchResponse.text();
532
+ if (errorText) {
533
+ errorDetails = ` - ${errorText}`;
534
+ }
535
+ } catch {
536
+ }
537
+ throw new Error(`HTTP error! status: ${fetchResponse.status}${errorDetails}`);
538
+ }
539
+ const reader = (_a3 = fetchResponse.body) == null ? void 0 : _a3.getReader();
540
+ if (!reader) {
541
+ throw new Error("No response body");
542
+ }
543
+ const decoder = new TextDecoder("utf-8");
544
+ let done = false;
545
+ let accumulatedData = "";
546
+ while (!done) {
547
+ const { value, done: doneReading } = await reader.read();
548
+ done = doneReading;
549
+ if (value) {
550
+ const chunk = decoder.decode(value, { stream: true });
551
+ accumulatedData += chunk;
552
+ }
553
+ }
554
+ const parsed = parseSSEResponse(accumulatedData);
555
+ const finalData = parsed.rawText || "";
556
+ setResponse(finalData);
557
+ if (onProgress) {
558
+ onProgress(finalData);
559
+ }
560
+ if (parsed.error) {
561
+ console.warn("[useAIAssistant] Parser warning:", parsed.error);
562
+ }
563
+ return finalData;
564
+ } catch (err) {
565
+ let errorMessage = "Error occurred while processing your request.";
566
+ if (err instanceof Error) {
567
+ if (err.name === "AbortError") {
568
+ errorMessage = "Request was cancelled.";
569
+ } else if (err.message.includes("Rate limit") || err.message.includes("429")) {
570
+ errorMessage = "Rate limit exceeded. Please wait a moment before sending another message.";
571
+ } else if (err.message.includes("quota")) {
572
+ errorMessage = "API quota exceeded. Please try again later.";
573
+ } else {
574
+ errorMessage = err.message;
575
+ }
576
+ }
577
+ setError(errorMessage);
578
+ throw new Error(errorMessage);
579
+ } finally {
580
+ setIsLoading(false);
581
+ }
582
+ },
583
+ [config.endpoint, config.mcpServers, parseSSEResponse]
584
+ );
585
+ const cancelRequest = useCallback(() => {
586
+ if (abortControllerRef.current) {
587
+ abortControllerRef.current.abort();
588
+ }
589
+ }, []);
590
+ const resetConversation = useCallback(() => {
591
+ conversationIdRef.current = crypto.randomUUID();
592
+ setResponse("");
593
+ setError(null);
594
+ }, []);
595
+ return {
596
+ response,
597
+ isLoading,
598
+ error,
599
+ sendMessage,
600
+ cancelRequest,
601
+ resetConversation,
602
+ conversationId: conversationIdRef.current
603
+ // Expose for debugging
604
+ };
605
+ };
300
606
  const useComponentUtils = () => {
301
607
  const getCacheKey = React.useCallback((key, uniqueId) => {
302
608
  return `${key}${uniqueId}`;
@@ -4355,6 +4661,156 @@ function some(array, predicate) {
4355
4661
  function every(array, predicate) {
4356
4662
  return array.every(predicate);
4357
4663
  }
4664
+ var ContentType = /* @__PURE__ */ ((ContentType2) => {
4665
+ ContentType2["HTML"] = "html";
4666
+ ContentType2["MARKDOWN"] = "markdown";
4667
+ ContentType2["ADAPTIVE_CARD"] = "adaptiveCard";
4668
+ ContentType2["PLAIN_TEXT"] = "plainText";
4669
+ return ContentType2;
4670
+ })(ContentType || {});
4671
+ const isValidJSON = (text) => {
4672
+ try {
4673
+ const parsed = JSON.parse(text);
4674
+ return typeof parsed === "object" && parsed !== null;
4675
+ } catch {
4676
+ return false;
4677
+ }
4678
+ };
4679
+ const isAdaptiveCard = (text) => {
4680
+ var _a3;
4681
+ try {
4682
+ const parsed = JSON.parse(text);
4683
+ return parsed && typeof parsed === "object" && (parsed.type === "AdaptiveCard" || ((_a3 = parsed.$schema) == null ? void 0 : _a3.includes("adaptivecards.io")));
4684
+ } catch {
4685
+ return false;
4686
+ }
4687
+ };
4688
+ const isHTML = (text) => {
4689
+ const trimmed = text.trim();
4690
+ const htmlPatterns = [
4691
+ /^<!DOCTYPE\s+html/i,
4692
+ /^<html[\s>]/i,
4693
+ /^<\?xml/i,
4694
+ /<(div|span|p|h[1-6]|table|ul|ol|li|a|img|br|hr|strong|em|b|i)[\s>]/i
4695
+ ];
4696
+ const hasHTMLTags = /<[^>]+>/.test(trimmed);
4697
+ const startsWithTag = /^<[^>]+>/.test(trimmed);
4698
+ const openTags = (trimmed.match(/<(?!\/)[^>]+>/g) || []).length;
4699
+ return htmlPatterns.some((pattern) => pattern.test(trimmed)) || hasHTMLTags && startsWithTag && openTags > 0;
4700
+ };
4701
+ const isMarkdown = (text) => {
4702
+ const trimmed = text.trim();
4703
+ const markdownPatterns = [
4704
+ /^#{1,6}\s+.+$/m,
4705
+ // Headers
4706
+ /\*\*.*?\*\*/,
4707
+ // Bold
4708
+ /\*.*?\*/,
4709
+ // Italic
4710
+ /__.*?__/,
4711
+ // Bold (underscore)
4712
+ /_.*?_/,
4713
+ // Italic (underscore)
4714
+ /\[.*?\]\(.*?\)/,
4715
+ // Links
4716
+ /^\s*[-*+]\s+/m,
4717
+ // Unordered lists
4718
+ /^\s*\d+\.\s+/m,
4719
+ // Ordered lists
4720
+ /`[^`]+`/,
4721
+ // Inline code
4722
+ /^```/m,
4723
+ // Code blocks
4724
+ /^\|.*\|.*\|$/m,
4725
+ // Tables
4726
+ /^>\s+/m,
4727
+ // Blockquotes
4728
+ /^\s*---\s*$/m
4729
+ // Horizontal rules
4730
+ ];
4731
+ const hasMarkdownSyntax = markdownPatterns.some((pattern) => pattern.test(trimmed));
4732
+ const startsWithHTMLTag = /^<[^>]+>/.test(trimmed);
4733
+ return hasMarkdownSyntax && !startsWithHTMLTag;
4734
+ };
4735
+ const calculateConfidence = (text, patterns, isNegativeCheck = false) => {
4736
+ const matches = patterns.filter((pattern) => pattern.test(text)).length;
4737
+ const score = matches / patterns.length;
4738
+ return isNegativeCheck ? 1 - score : score;
4739
+ };
4740
+ const detectContentType = (content) => {
4741
+ var _a3;
4742
+ if (typeof content === "object" && content !== null) {
4743
+ const contentObj = content;
4744
+ if (contentObj.type === "AdaptiveCard" || ((_a3 = contentObj.$schema) == null ? void 0 : _a3.includes("adaptivecards.io"))) {
4745
+ return {
4746
+ type: "adaptiveCard",
4747
+ content,
4748
+ confidence: 1
4749
+ };
4750
+ }
4751
+ content = JSON.stringify(content, null, 2);
4752
+ }
4753
+ const text = content;
4754
+ const trimmed = text.trim();
4755
+ if (!trimmed || trimmed.length < 3) {
4756
+ return {
4757
+ type: "plainText",
4758
+ content: text,
4759
+ confidence: 1
4760
+ };
4761
+ }
4762
+ if (isValidJSON(trimmed) && isAdaptiveCard(trimmed)) {
4763
+ return {
4764
+ type: "adaptiveCard",
4765
+ content: JSON.parse(trimmed),
4766
+ confidence: 1
4767
+ };
4768
+ }
4769
+ if (isHTML(trimmed)) {
4770
+ const htmlPatterns = [
4771
+ /^<!DOCTYPE\s+html/i,
4772
+ /^<html[\s>]/i,
4773
+ /<(div|span|p|h[1-6]|table|ul|ol|li)[\s>]/i
4774
+ ];
4775
+ const confidence = Math.max(
4776
+ 0.7,
4777
+ calculateConfidence(trimmed, htmlPatterns)
4778
+ );
4779
+ return {
4780
+ type: "html",
4781
+ content: text,
4782
+ confidence
4783
+ };
4784
+ }
4785
+ if (isMarkdown(trimmed)) {
4786
+ const markdownPatterns = [
4787
+ /^#{1,6}\s+.+$/m,
4788
+ /\*\*.*?\*\*/,
4789
+ /\[.*?\]\(.*?\)/,
4790
+ /^\s*[-*+]\s+/m,
4791
+ /`[^`]+`/,
4792
+ /^```/m,
4793
+ /^\|.*\|.*\|$/m
4794
+ ];
4795
+ const confidence = Math.max(
4796
+ 0.6,
4797
+ calculateConfidence(trimmed, markdownPatterns)
4798
+ );
4799
+ return {
4800
+ type: "markdown",
4801
+ content: text,
4802
+ confidence
4803
+ };
4804
+ }
4805
+ return {
4806
+ type: "plainText",
4807
+ content: text,
4808
+ confidence: 0.5
4809
+ };
4810
+ };
4811
+ const getContentType = (content) => {
4812
+ return detectContentType(content).type;
4813
+ };
4358
4814
  const useCardStyles = (props) => {
4359
4815
  const { styles: styles2 } = props;
4360
4816
  const { getBaseStyles } = useComponentUtils();
@@ -5136,7 +5592,7 @@ const Carousel = (props) => {
5136
5592
  }
5137
5593
  ) });
5138
5594
  };
5139
- const useStyles$6 = () => {
5595
+ const useStyles$8 = () => {
5140
5596
  return {
5141
5597
  card: css$1({
5142
5598
  position: "absolute",
@@ -5154,7 +5610,7 @@ const Popup = ({
5154
5610
  }) => {
5155
5611
  const popupRef = useRef(null);
5156
5612
  const [position2, setPosition] = useState(anchorPoint);
5157
- const styles2 = useStyles$6();
5613
+ const styles2 = useStyles$8();
5158
5614
  useLayoutEffect(() => {
5159
5615
  if (popupRef.current) {
5160
5616
  const rect = popupRef.current.getBoundingClientRect();
@@ -5311,7 +5767,7 @@ const RenderLabel = (props) => {
5311
5767
  /* @__PURE__ */ jsx$2(Caption1, { style: { color: tokens.colorPaletteRedForeground1 }, children: isRequired ? " *" : "" })
5312
5768
  ] }) });
5313
5769
  };
5314
- const useStyles$5 = makeStyles({
5770
+ const useStyles$7 = makeStyles({
5315
5771
  root: {
5316
5772
  display: "flex",
5317
5773
  justifyContent: "center",
@@ -5326,7 +5782,7 @@ const useStyles$5 = makeStyles({
5326
5782
  });
5327
5783
  const RenderSpinner = (props) => {
5328
5784
  const { size, label, labelPosition, style, className } = props;
5329
- const styles2 = useStyles$5();
5785
+ const styles2 = useStyles$7();
5330
5786
  return /* @__PURE__ */ jsx$2("div", { className: styles2.root, children: /* @__PURE__ */ jsx$2(
5331
5787
  Spinner,
5332
5788
  {
@@ -6016,7 +6472,7 @@ const defaultEventDetailsPopoverStrings = {
6016
6472
  details: "Details"
6017
6473
  };
6018
6474
  const PADDING_LEFT = "32px";
6019
- const useStyles$4 = (_props) => {
6475
+ const useStyles$6 = (_props) => {
6020
6476
  const styles2 = {
6021
6477
  banner: css$1({
6022
6478
  display: "flex",
@@ -6048,7 +6504,7 @@ const RenderProperty = ({ fieldLabel, fieldValue, icon }) => {
6048
6504
  const EventDetailsPopover = (props) => {
6049
6505
  const { event, strings: strings2 = defaultEventDetailsPopoverStrings } = props;
6050
6506
  const { title, start, end, location, category, attendees, weblink } = event;
6051
- const { styles: styles2 } = useStyles$4();
6507
+ const { styles: styles2 } = useStyles$6();
6052
6508
  const { formatDate } = useUtils();
6053
6509
  const formatedStartDate = formatDate(start, "PPp");
6054
6510
  const formatedEndDate = formatDate(end, "PPp");
@@ -8855,7 +9311,7 @@ const DataGridV2 = React.forwardRef((props, ref) => {
8855
9311
  DataGridV2.displayName = "DataGridV2";
8856
9312
  const DEFAULT_MIN_WIDTH = 200;
8857
9313
  const DEFAULT_MIN_HEIGHT = 200;
8858
- const useStyles$3 = makeStyles({
9314
+ const useStyles$5 = makeStyles({
8859
9315
  dialog: {
8860
9316
  width: "100%",
8861
9317
  height: "100%",
@@ -8869,7 +9325,7 @@ const useStyles$3 = makeStyles({
8869
9325
  });
8870
9326
  const RenderDialog = (props) => {
8871
9327
  const { isOpen, dialogTitle, dialogActions, children, maxWidth, className, minHeight, minWidth, maxHeight } = props;
8872
- const styles2 = useStyles$3();
9328
+ const styles2 = useStyles$5();
8873
9329
  if (!isOpen) return /* @__PURE__ */ jsx$2(Fragment, {});
8874
9330
  return /* @__PURE__ */ jsx$2(Dialog, { open: isOpen, modalType: "modal", children: /* @__PURE__ */ jsxs$1(
8875
9331
  DialogSurface,
@@ -9211,7 +9667,7 @@ const ShowMessage = (props) => {
9211
9667
  children
9212
9668
  ] }) });
9213
9669
  };
9214
- const useStyles$2 = () => {
9670
+ const useStyles$4 = () => {
9215
9671
  return {
9216
9672
  container: css$1({
9217
9673
  display: "flex",
@@ -9244,7 +9700,7 @@ const CustomControlBar = ({
9244
9700
  renderControl,
9245
9701
  theme
9246
9702
  }) => {
9247
- const styles2 = useStyles$2();
9703
+ const styles2 = useStyles$4();
9248
9704
  const onItemSelect = React.useCallback(
9249
9705
  (itemId) => {
9250
9706
  if (onSelectedItem) {
@@ -25338,6 +25794,336 @@ const chatReducer = (state, action) => {
25338
25794
  return state;
25339
25795
  }
25340
25796
  };
25797
+ const useStyles$3 = makeStyles({
25798
+ markdown: {
25799
+ fontFamily: tokens.fontFamilyBase,
25800
+ fontSize: tokens.fontSizeBase300,
25801
+ lineHeight: tokens.lineHeightBase300,
25802
+ color: tokens.colorNeutralForeground1,
25803
+ "& p": {
25804
+ marginTop: "0",
25805
+ marginBottom: tokens.spacingVerticalM
25806
+ },
25807
+ "& h1, & h2, & h3, & h4, & h5, & h6": {
25808
+ marginTop: tokens.spacingVerticalL,
25809
+ marginBottom: tokens.spacingVerticalM,
25810
+ fontWeight: tokens.fontWeightSemibold
25811
+ },
25812
+ "& h1": {
25813
+ fontSize: tokens.fontSizeBase500
25814
+ },
25815
+ "& h2": {
25816
+ fontSize: tokens.fontSizeBase400
25817
+ },
25818
+ "& h3": {
25819
+ fontSize: tokens.fontSizeBase300
25820
+ },
25821
+ "& ul, & ol": {
25822
+ marginTop: "0",
25823
+ marginBottom: tokens.spacingVerticalM,
25824
+ paddingLeft: tokens.spacingHorizontalXXL
25825
+ },
25826
+ "& li": {
25827
+ marginBottom: tokens.spacingVerticalXS
25828
+ },
25829
+ "& code": {
25830
+ fontFamily: tokens.fontFamilyMonospace,
25831
+ fontSize: tokens.fontSizeBase200,
25832
+ backgroundColor: tokens.colorNeutralBackground3,
25833
+ padding: "2px 4px",
25834
+ borderRadius: tokens.borderRadiusSmall
25835
+ },
25836
+ "& pre": {
25837
+ backgroundColor: tokens.colorNeutralBackground3,
25838
+ padding: tokens.spacingVerticalM,
25839
+ borderRadius: tokens.borderRadiusMedium,
25840
+ overflowX: "auto",
25841
+ marginBottom: tokens.spacingVerticalM
25842
+ },
25843
+ "& pre code": {
25844
+ backgroundColor: "transparent",
25845
+ padding: "0"
25846
+ },
25847
+ "& table": {
25848
+ borderCollapse: "collapse",
25849
+ width: "100%",
25850
+ marginBottom: tokens.spacingVerticalM,
25851
+ border: `1px solid ${tokens.colorNeutralStroke1}`
25852
+ },
25853
+ "& thead": {
25854
+ backgroundColor: tokens.colorNeutralBackground3
25855
+ },
25856
+ "& th": {
25857
+ padding: tokens.spacingVerticalS + " " + tokens.spacingHorizontalM,
25858
+ textAlign: "left",
25859
+ fontWeight: tokens.fontWeightSemibold,
25860
+ borderBottom: `2px solid ${tokens.colorNeutralStroke1}`,
25861
+ borderRight: `1px solid ${tokens.colorNeutralStroke2}`
25862
+ },
25863
+ "& td": {
25864
+ padding: tokens.spacingVerticalS + " " + tokens.spacingHorizontalM,
25865
+ borderBottom: `1px solid ${tokens.colorNeutralStroke2}`,
25866
+ borderRight: `1px solid ${tokens.colorNeutralStroke2}`
25867
+ },
25868
+ "& tr:last-child td": {
25869
+ borderBottom: "none"
25870
+ },
25871
+ "& th:last-child, & td:last-child": {
25872
+ borderRight: "none"
25873
+ },
25874
+ "& blockquote": {
25875
+ borderLeft: `4px solid ${tokens.colorBrandStroke1}`,
25876
+ paddingLeft: tokens.spacingHorizontalM,
25877
+ marginLeft: "0",
25878
+ marginBottom: tokens.spacingVerticalM,
25879
+ color: tokens.colorNeutralForeground2
25880
+ },
25881
+ "& a": {
25882
+ color: tokens.colorBrandForeground1,
25883
+ textDecoration: "none",
25884
+ ":hover": {
25885
+ textDecoration: "underline"
25886
+ }
25887
+ },
25888
+ "& hr": {
25889
+ border: "none",
25890
+ borderTop: `1px solid ${tokens.colorNeutralStroke2}`,
25891
+ marginTop: tokens.spacingVerticalL,
25892
+ marginBottom: tokens.spacingVerticalL
25893
+ }
25894
+ }
25895
+ });
25896
+ const MarkdownRenderer = ({
25897
+ content,
25898
+ className
25899
+ }) => {
25900
+ const styles2 = useStyles$3();
25901
+ const [html, setHtml] = React.useState("");
25902
+ React.useEffect(() => {
25903
+ const md = new markdown__default({
25904
+ html: false,
25905
+ // Disable HTML tags for security
25906
+ linkify: true,
25907
+ // Auto-convert URLs to links
25908
+ typographer: true,
25909
+ // Enable smartquotes and other typographic replacements
25910
+ breaks: true
25911
+ // Convert line breaks to <br>
25912
+ });
25913
+ const rendered = md.render(content);
25914
+ setHtml(rendered);
25915
+ }, [content]);
25916
+ return /* @__PURE__ */ jsx$2(
25917
+ "div",
25918
+ {
25919
+ className: `${styles2.markdown} ${className || ""}`,
25920
+ dangerouslySetInnerHTML: { __html: html }
25921
+ }
25922
+ );
25923
+ };
25924
+ const useStyles$2 = makeStyles({
25925
+ plainText: {
25926
+ fontFamily: tokens.fontFamilyBase,
25927
+ fontSize: tokens.fontSizeBase300,
25928
+ lineHeight: tokens.lineHeightBase300,
25929
+ color: tokens.colorNeutralForeground1,
25930
+ whiteSpace: "pre-wrap",
25931
+ wordBreak: "break-word"
25932
+ },
25933
+ htmlContent: {
25934
+ fontFamily: tokens.fontFamilyBase,
25935
+ fontSize: tokens.fontSizeBase300,
25936
+ lineHeight: tokens.lineHeightBase300,
25937
+ color: tokens.colorNeutralForeground1,
25938
+ "& p": {
25939
+ marginTop: "0",
25940
+ marginBottom: tokens.spacingVerticalM
25941
+ },
25942
+ "& h1, & h2, & h3, & h4, & h5, & h6": {
25943
+ marginTop: tokens.spacingVerticalL,
25944
+ marginBottom: tokens.spacingVerticalM,
25945
+ fontWeight: tokens.fontWeightSemibold
25946
+ },
25947
+ "& table": {
25948
+ borderCollapse: "collapse",
25949
+ width: "100%",
25950
+ marginBottom: tokens.spacingVerticalM
25951
+ },
25952
+ "& th, & td": {
25953
+ border: `1px solid ${tokens.colorNeutralStroke1}`,
25954
+ padding: tokens.spacingHorizontalS,
25955
+ textAlign: "left"
25956
+ },
25957
+ "& th": {
25958
+ backgroundColor: tokens.colorNeutralBackground3,
25959
+ fontWeight: tokens.fontWeightSemibold
25960
+ }
25961
+ },
25962
+ debugBadge: {
25963
+ display: "inline-block",
25964
+ padding: `${tokens.spacingVerticalXS} ${tokens.spacingHorizontalS}`,
25965
+ marginBottom: tokens.spacingVerticalS,
25966
+ backgroundColor: tokens.colorNeutralBackground3,
25967
+ borderRadius: tokens.borderRadiusSmall,
25968
+ fontSize: tokens.fontSizeBase200,
25969
+ fontFamily: tokens.fontFamilyMonospace,
25970
+ color: tokens.colorNeutralForeground2
25971
+ },
25972
+ adaptiveCardWrapper: {
25973
+ width: "100%"
25974
+ }
25975
+ });
25976
+ const ContentRenderer = ({
25977
+ content,
25978
+ forceType,
25979
+ onTypeDetected,
25980
+ context,
25981
+ theme = AdaptiveCardHostThemeType.SharePoint,
25982
+ onAdaptiveCardAction,
25983
+ className,
25984
+ debug = false
25985
+ }) => {
25986
+ const styles2 = useStyles$2();
25987
+ const [detectionResult, setDetectionResult] = React.useState(null);
25988
+ React.useEffect(() => {
25989
+ if (React.isValidElement(content)) {
25990
+ return;
25991
+ }
25992
+ if (typeof content !== "string" && typeof content !== "object") {
25993
+ return;
25994
+ }
25995
+ const result = detectContentType(content);
25996
+ setDetectionResult(result);
25997
+ if (onTypeDetected) {
25998
+ onTypeDetected(result);
25999
+ }
26000
+ }, [content, onTypeDetected]);
26001
+ if (React.isValidElement(content)) {
26002
+ return /* @__PURE__ */ jsx$2(Fragment, { children: content });
26003
+ }
26004
+ const contentType = forceType || (detectionResult == null ? void 0 : detectionResult.type);
26005
+ const actualContent = (detectionResult == null ? void 0 : detectionResult.content) || content;
26006
+ const renderDebugBadge = () => {
26007
+ if (!debug || !detectionResult) return null;
26008
+ return /* @__PURE__ */ jsxs$1("div", { className: styles2.debugBadge, children: [
26009
+ "Type: ",
26010
+ detectionResult.type,
26011
+ " | Confidence: ",
26012
+ (detectionResult.confidence * 100).toFixed(0),
26013
+ "%"
26014
+ ] });
26015
+ };
26016
+ const renderContent = () => {
26017
+ switch (contentType) {
26018
+ case ContentType.MARKDOWN:
26019
+ return /* @__PURE__ */ jsx$2(
26020
+ MarkdownRenderer,
26021
+ {
26022
+ content: actualContent,
26023
+ className
26024
+ }
26025
+ );
26026
+ case ContentType.HTML:
26027
+ return /* @__PURE__ */ jsx$2(
26028
+ "div",
26029
+ {
26030
+ className: `${styles2.htmlContent} ${className || ""}`,
26031
+ dangerouslySetInnerHTML: { __html: actualContent }
26032
+ }
26033
+ );
26034
+ case ContentType.ADAPTIVE_CARD:
26035
+ return /* @__PURE__ */ jsx$2("div", { className: `${styles2.adaptiveCardWrapper} ${className || ""}`, children: /* @__PURE__ */ jsx$2(
26036
+ AdaptiveCardHost,
26037
+ {
26038
+ card: typeof actualContent === "string" ? JSON.parse(actualContent) : actualContent,
26039
+ context,
26040
+ themeType: theme,
26041
+ onInvokeAction: onAdaptiveCardAction || (() => {
26042
+ }),
26043
+ onError: (error) => console.error("Adaptive Card Error:", error)
26044
+ }
26045
+ ) });
26046
+ case ContentType.PLAIN_TEXT:
26047
+ default:
26048
+ return /* @__PURE__ */ jsx$2("div", { className: `${styles2.plainText} ${className || ""}`, children: actualContent });
26049
+ }
26050
+ };
26051
+ return /* @__PURE__ */ jsxs$1(Fragment, { children: [
26052
+ renderDebugBadge(),
26053
+ renderContent()
26054
+ ] });
26055
+ };
26056
+ const ChatList = React.forwardRef((props, ref) => {
26057
+ const { messages, context } = props;
26058
+ const cleanMessageContent = (content) => {
26059
+ if (React.isValidElement(content)) {
26060
+ return content;
26061
+ }
26062
+ if (typeof content === "string") {
26063
+ let cleaned = content.replace(/\{"status"\s*:\s*"executing"\}/gi, "").replace(/\{'status'\s*:\s*'executing'\}/gi, "").trim();
26064
+ return cleaned;
26065
+ }
26066
+ return content;
26067
+ };
26068
+ const scrollableContainerStyle = css$1({
26069
+ flex: "1 1 0",
26070
+ overflowY: "auto",
26071
+ overflowX: "hidden",
26072
+ padding: "16px",
26073
+ paddingRight: "25px",
26074
+ // Custom scrollbar styles
26075
+ "::-webkit-scrollbar": {
26076
+ width: "6px"
26077
+ },
26078
+ "::-webkit-scrollbar-track": {
26079
+ background: tokens.colorNeutralBackground4,
26080
+ borderRadius: "10px"
26081
+ },
26082
+ "::-webkit-scrollbar-thumb": {
26083
+ background: tokens.colorBrandStroke2Hover,
26084
+ borderRadius: "10px"
26085
+ },
26086
+ "::-webkit-scrollbar-thumb:hover": {
26087
+ background: tokens.colorNeutralStroke2
26088
+ }
26089
+ });
26090
+ const chatContentStyle = css$1({
26091
+ display: "flex",
26092
+ flexDirection: "column",
26093
+ gap: "10px",
26094
+ paddingRight: "30px"
26095
+ // Space for message status indicators
26096
+ });
26097
+ return /* @__PURE__ */ jsx$2("div", { ref, className: scrollableContainerStyle, children: /* @__PURE__ */ jsx$2(Chat, { className: chatContentStyle, children: messages.map(
26098
+ (message, index) => message.senderName === "User" ? /* @__PURE__ */ jsx$2(
26099
+ ChatMyMessage,
26100
+ {
26101
+ status: message.status,
26102
+ author: message.senderName,
26103
+ children: cleanMessageContent(message.message)
26104
+ },
26105
+ index
26106
+ ) : /* @__PURE__ */ jsx$2(
26107
+ ChatMessage,
26108
+ {
26109
+ decoration: message.status === "failed" ? "important" : void 0,
26110
+ avatar: /* @__PURE__ */ jsx$2(
26111
+ Icon,
26112
+ {
26113
+ icon: "carbon:ibm-consulting-advantage-assistant",
26114
+ width: "32",
26115
+ height: "32",
26116
+ style: { color: tokens.colorBrandBackground }
26117
+ }
26118
+ ),
26119
+ author: message.senderName,
26120
+ children: /* @__PURE__ */ jsx$2(ContentRenderer, { content: cleanMessageContent(message.message), context })
26121
+ },
26122
+ index
26123
+ )
26124
+ ) }) });
26125
+ });
26126
+ ChatList.displayName = "ChatList";
25341
26127
  const useAIAssistantStyles = () => {
25342
26128
  return {
25343
26129
  container: css$1({
@@ -25357,10 +26143,7 @@ const useAIAssistantStyles = () => {
25357
26143
  display: "flex",
25358
26144
  flexDirection: "column",
25359
26145
  gap: "10px",
25360
- padding: "10px",
25361
- overflowY: "auto",
25362
- overflowX: "hidden",
25363
- height: "100%",
26146
+ paddingRight: "30px",
25364
26147
  width: "100%",
25365
26148
  // Scrollbar styles
25366
26149
  // Scrollbar styles
@@ -25403,184 +26186,31 @@ const useAIAssistantStyles = () => {
25403
26186
  input: css$1({
25404
26187
  width: "100%",
25405
26188
  fontSize: "14px"
26189
+ }),
26190
+ // AIAssistant main container
26191
+ aiAssistantContainer: css$1({
26192
+ display: "flex",
26193
+ flexDirection: "column",
26194
+ height: "100%",
26195
+ width: "100%",
26196
+ boxSizing: "border-box"
26197
+ }),
26198
+ // AIAssistant input wrapper
26199
+ aiAssistantInputContainer: css$1({
26200
+ flex: "0 0 auto",
26201
+ padding: "16px",
26202
+ paddingBottom: "20px",
26203
+ borderTop: `1px solid ${tokens.colorNeutralStroke2}`,
26204
+ backgroundColor: tokens.colorNeutralBackground1,
26205
+ boxSizing: "border-box"
25406
26206
  })
25407
26207
  };
25408
26208
  };
25409
- function useStreamRequest() {
25410
- const [data, setData] = useState("");
25411
- const [isLoading, setIsLoading] = useState(false);
25412
- const [error, setError] = useState(null);
25413
- const abortControllerRef = useRef(null);
25414
- const sendRequest = useCallback(
25415
- async (endpoint, payload, options, onChunk) => {
25416
- var _a3, _b2, _c2, _d2;
25417
- setData("");
25418
- setError(null);
25419
- setIsLoading(true);
25420
- const controller = new AbortController();
25421
- abortControllerRef.current = controller;
25422
- try {
25423
- const response = await fetch(endpoint, {
25424
- method: "POST",
25425
- headers: { "Content-Type": "application/json" },
25426
- body: JSON.stringify(payload),
25427
- signal: controller.signal,
25428
- ...options
25429
- });
25430
- if (!response.ok) {
25431
- throw new Error(`HTTP error! status: ${response.status}`);
25432
- }
25433
- const reader = (_a3 = response.body) == null ? void 0 : _a3.getReader();
25434
- if (!reader) {
25435
- throw new Error("No response body");
25436
- }
25437
- const decoder = new TextDecoder("utf-8");
25438
- let done = false;
25439
- let accumulatedData = "";
25440
- let buffer = "";
25441
- while (!done) {
25442
- const { value, done: doneReading } = await reader.read();
25443
- done = doneReading;
25444
- if (value) {
25445
- const chunk = decoder.decode(value, { stream: true });
25446
- buffer += chunk;
25447
- const isSSE = buffer.includes("event:") || buffer.includes("data:");
25448
- if (isSSE) {
25449
- const lines = buffer.split("\n");
25450
- buffer = lines.pop() || "";
25451
- let currentEvent = "";
25452
- let currentData = "";
25453
- for (const line2 of lines) {
25454
- if (line2.startsWith("event:")) {
25455
- currentEvent = line2.substring(6).trim();
25456
- } else if (line2.startsWith("data:")) {
25457
- const dataContent = line2.substring(5).trim();
25458
- if (currentData && dataContent) {
25459
- currentData += "\n" + dataContent;
25460
- } else {
25461
- currentData = dataContent;
25462
- }
25463
- } else if (line2 === "") {
25464
- if (!currentData) {
25465
- currentEvent = "";
25466
- currentData = "";
25467
- continue;
25468
- }
25469
- if (currentEvent === "error") {
25470
- try {
25471
- const errorData = JSON.parse(currentData);
25472
- const errorMessage = errorData.message || "An error occurred";
25473
- if (errorMessage.includes("429") || errorMessage.toLowerCase().includes("rate limit")) {
25474
- throw new Error("Rate limit exceeded. Please wait a moment and try again.");
25475
- } else if (errorMessage.includes("quota")) {
25476
- throw new Error("API quota exceeded. Please try again later.");
25477
- } else {
25478
- throw new Error(errorMessage);
25479
- }
25480
- } catch (parseError) {
25481
- if (parseError instanceof Error && parseError.message.includes("Rate limit")) {
25482
- throw parseError;
25483
- }
25484
- throw new Error(currentData || "An error occurred during streaming");
25485
- }
25486
- } else if (currentEvent === "done") {
25487
- done = true;
25488
- } else if (currentEvent === "tool") {
25489
- } else {
25490
- try {
25491
- const parsed = JSON.parse(currentData);
25492
- if (parsed.status && Object.keys(parsed).length === 1) {
25493
- } else if (parsed.content) {
25494
- const contentStr = typeof parsed.content === "string" ? parsed.content : JSON.stringify(parsed.content, null, 2);
25495
- accumulatedData += contentStr;
25496
- setData(accumulatedData);
25497
- if (onChunk) {
25498
- onChunk(contentStr);
25499
- }
25500
- } else {
25501
- const formattedJson = JSON.stringify(parsed, null, 2);
25502
- accumulatedData += formattedJson + "\n";
25503
- setData(accumulatedData);
25504
- if (onChunk) {
25505
- onChunk(formattedJson);
25506
- }
25507
- }
25508
- } catch {
25509
- accumulatedData += currentData + "\n";
25510
- setData(accumulatedData);
25511
- if (onChunk) {
25512
- onChunk(currentData);
25513
- }
25514
- }
25515
- }
25516
- currentEvent = "";
25517
- currentData = "";
25518
- }
25519
- }
25520
- } else {
25521
- const lines = buffer.split("\n");
25522
- buffer = lines.pop() || "";
25523
- for (const line2 of lines) {
25524
- if (line2.trim()) {
25525
- try {
25526
- const parsed = JSON.parse(line2);
25527
- if ((_d2 = (_c2 = (_b2 = parsed.choices) == null ? void 0 : _b2[0]) == null ? void 0 : _c2.delta) == null ? void 0 : _d2.content) {
25528
- const content = parsed.choices[0].delta.content;
25529
- accumulatedData += content;
25530
- setData(accumulatedData);
25531
- if (onChunk) {
25532
- onChunk(content);
25533
- }
25534
- } else if (parsed.content) {
25535
- accumulatedData += parsed.content;
25536
- setData(accumulatedData);
25537
- if (onChunk) {
25538
- onChunk(parsed.content);
25539
- }
25540
- } else if (parsed.done === true || parsed.type === "done") {
25541
- done = true;
25542
- } else if (!parsed.status) {
25543
- accumulatedData += line2;
25544
- setData(accumulatedData);
25545
- if (onChunk) {
25546
- onChunk(line2);
25547
- }
25548
- }
25549
- } catch {
25550
- accumulatedData += line2 + "\n";
25551
- setData(accumulatedData);
25552
- if (onChunk) {
25553
- onChunk(line2 + "\n");
25554
- }
25555
- }
25556
- }
25557
- }
25558
- }
25559
- }
25560
- }
25561
- } catch (err) {
25562
- if (err instanceof Error && err.name === "AbortError") {
25563
- setError("Request aborted");
25564
- throw err;
25565
- } else {
25566
- setError(err instanceof Error ? err.message : "Error occurred");
25567
- throw err;
25568
- }
25569
- } finally {
25570
- setIsLoading(false);
25571
- }
25572
- },
25573
- []
25574
- );
25575
- const cancelRequest = useCallback(() => {
25576
- if (abortControllerRef.current) {
25577
- abortControllerRef.current.abort();
25578
- }
25579
- }, []);
25580
- return { data, isLoading, error, sendRequest, cancelRequest };
25581
- }
25582
26209
  const getTimestamp = (timezone, currentUICultureName) => {
25583
- const { getFormatRelative } = useTimeZoneHelper(timezone, currentUICultureName);
26210
+ const { getFormatRelative } = useTimeZoneHelper(
26211
+ timezone,
26212
+ currentUICultureName
26213
+ );
25584
26214
  return getFormatRelative(/* @__PURE__ */ new Date());
25585
26215
  };
25586
26216
  const AIAssistant = (props) => {
@@ -25603,14 +26233,23 @@ const AIAssistant = (props) => {
25603
26233
  });
25604
26234
  const { messages, inputText, isLoading, error, isRunning } = state;
25605
26235
  const chatHistory = React.useRef([]);
25606
- const styles2 = useAIAssistantStyles();
25607
26236
  const chatListRef = React.useRef(null);
25608
- const { sendRequest, cancelRequest, error: streamError } = useStreamRequest();
26237
+ const styles2 = useAIAssistantStyles();
26238
+ const { sendMessage, cancelRequest } = useAIAssistant({
26239
+ endpoint: openAIConfig == null ? void 0 : openAIConfig.endpoint,
26240
+ mcpServers: openAIConfig == null ? void 0 : openAIConfig.mcpServers
26241
+ });
25609
26242
  const forceScrollToBottom = React.useCallback(() => {
25610
26243
  if (chatListRef.current) {
25611
26244
  chatListRef.current.scrollTop = chatListRef.current.scrollHeight - chatListRef.current.clientHeight;
25612
26245
  }
25613
26246
  }, []);
26247
+ React.useEffect(() => {
26248
+ const timeoutId = setTimeout(() => {
26249
+ forceScrollToBottom();
26250
+ }, 100);
26251
+ return () => clearTimeout(timeoutId);
26252
+ }, [messages, forceScrollToBottom]);
25614
26253
  React.useEffect(() => {
25615
26254
  var _a3, _b2;
25616
26255
  const welcomeMessage = {
@@ -25653,63 +26292,49 @@ const AIAssistant = (props) => {
25653
26292
  type: "ADD_ASSISTANT_MESSAGE",
25654
26293
  message: assistantMessage
25655
26294
  });
25656
- forceScrollToBottom();
25657
- let currentResponse = "";
25658
- const endpoint = (openAIConfig == null ? void 0 : openAIConfig.endpoint) || "http://localhost:7071/api/EventAssistant";
25659
- const payload = {
25660
- instructions: instrutions,
25661
- input: currentInput,
25662
- timezone,
25663
- locale: locale2,
25664
- history: chatHistory.current,
25665
- mcpServers: openAIConfig == null ? void 0 : openAIConfig.mcpServers
25666
- };
25667
26295
  try {
25668
- await sendRequest(endpoint, payload, void 0, (chunk) => {
25669
- currentResponse += chunk;
26296
+ const aiResponse = await sendMessage({
26297
+ instructions: instrutions,
26298
+ input: currentInput,
26299
+ timezone,
26300
+ locale: locale2,
26301
+ history: chatHistory.current,
26302
+ mcpServers: openAIConfig == null ? void 0 : openAIConfig.mcpServers
26303
+ });
26304
+ if (onResponse) {
26305
+ const response = await onResponse(aiResponse);
26306
+ const { message, status } = response;
25670
26307
  dispatch({
25671
26308
  type: "UPDATE_LAST_ASSISTANT_MESSAGE",
25672
26309
  message: {
25673
26310
  ...assistantMessage,
25674
- message: currentResponse,
26311
+ message: message ? message : aiResponse,
26312
+ status: status ? status : "received"
26313
+ }
26314
+ });
26315
+ } else {
26316
+ dispatch({
26317
+ type: "UPDATE_LAST_ASSISTANT_MESSAGE",
26318
+ message: {
26319
+ ...assistantMessage,
26320
+ message: aiResponse,
25675
26321
  status: "received"
25676
26322
  }
25677
26323
  });
25678
- if (onResponse) {
25679
- onResponse(currentResponse).then((response) => {
25680
- const { message, status } = response;
25681
- dispatch({
25682
- type: "UPDATE_LAST_ASSISTANT_MESSAGE",
25683
- message: {
25684
- ...assistantMessage,
25685
- message: message ? message : currentResponse,
25686
- status: status ? status : "received"
25687
- }
25688
- });
25689
- }).catch((err) => {
25690
- console.error("onResponse callback error:", err);
25691
- });
25692
- }
25693
- });
25694
- dispatch({
25695
- type: "UPDATE_LAST_ASSISTANT_MESSAGE",
25696
- message: {
25697
- ...assistantMessage,
25698
- message: currentResponse,
25699
- status: "received"
25700
- }
25701
- });
26324
+ }
25702
26325
  dispatch({
25703
26326
  type: "SET_IS_RUNNING"
25704
26327
  });
26328
+ chatHistory.current.push(currentInput);
26329
+ chatHistory.current.push(aiResponse);
25705
26330
  } catch (err) {
25706
26331
  console.error("Error during streaming:", err);
25707
26332
  let errorMessage = "Error occurred while processing your request.";
25708
26333
  if (err instanceof Error) {
25709
26334
  if (err.message.includes("Rate limit") || err.message.includes("429")) {
25710
- errorMessage = "⚠️ Rate limit exceeded. Please wait a moment before sending another message.";
26335
+ errorMessage = "Rate limit exceeded. Please wait a moment before sending another message.";
25711
26336
  } else if (err.message.includes("quota")) {
25712
- errorMessage = "⚠️ API quota exceeded. Please try again later.";
26337
+ errorMessage = "API quota exceeded. Please try again later.";
25713
26338
  } else if (err.message.includes("abort")) {
25714
26339
  errorMessage = "Request was cancelled.";
25715
26340
  } else {
@@ -25726,9 +26351,6 @@ const AIAssistant = (props) => {
25726
26351
  });
25727
26352
  dispatch({ type: "SET_IS_RUNNING" });
25728
26353
  }
25729
- chatHistory.current.push(currentInput);
25730
- chatHistory.current.push(currentResponse);
25731
- forceScrollToBottom();
25732
26354
  }, [
25733
26355
  inputText,
25734
26356
  instrutions,
@@ -25736,8 +26358,9 @@ const AIAssistant = (props) => {
25736
26358
  onResponse,
25737
26359
  openAIConfig,
25738
26360
  timezone,
25739
- sendRequest,
25740
- streamError
26361
+ sendMessage,
26362
+ forceScrollToBottom,
26363
+ context
25741
26364
  ]);
25742
26365
  const handleInputChange = React.useCallback((value) => {
25743
26366
  dispatch({ type: "SET_INPUT", inputText: value });
@@ -25754,38 +26377,9 @@ const AIAssistant = (props) => {
25754
26377
  }
25755
26378
  );
25756
26379
  }
25757
- return /* @__PURE__ */ jsxs$1("div", { id: "aiAssistant", className: styles2.chatAIAssistantRoot, children: [
25758
- /* @__PURE__ */ jsx$2(Chat, { className: styles2.chatList, ref: chatListRef, children: messages.map(
25759
- (message, index) => message.senderName === "User" ? /* @__PURE__ */ jsx$2(
25760
- ChatMyMessage,
25761
- {
25762
- status: message.status,
25763
- author: message.senderName,
25764
- timestamp: message.timeStamp,
25765
- children: message.message
25766
- },
25767
- index
25768
- ) : /* @__PURE__ */ jsx$2(
25769
- ChatMessage,
25770
- {
25771
- decoration: message.status === "failed" ? "important" : void 0,
25772
- avatar: /* @__PURE__ */ jsx$2(
25773
- Icon,
25774
- {
25775
- icon: "carbon:ibm-consulting-advantage-assistant",
25776
- width: "32",
25777
- height: "32",
25778
- style: { color: tokens.colorBrandBackground }
25779
- }
25780
- ),
25781
- author: message.senderName,
25782
- timestamp: message.timeStamp,
25783
- children: message.message
25784
- },
25785
- index
25786
- )
25787
- ) }),
25788
- /* @__PURE__ */ jsx$2("div", { className: styles2.inputContainer, children: /* @__PURE__ */ jsx$2(
26380
+ return /* @__PURE__ */ jsxs$1("div", { className: styles2.aiAssistantContainer, children: [
26381
+ /* @__PURE__ */ jsx$2(ChatList, { ref: chatListRef, messages, context }),
26382
+ /* @__PURE__ */ jsx$2("div", { className: styles2.aiAssistantInputContainer, children: /* @__PURE__ */ jsx$2(
25789
26383
  ChatInputWithMensions,
25790
26384
  {
25791
26385
  context,
@@ -27288,7 +27882,10 @@ export {
27288
27882
  ChatInput,
27289
27883
  ChatInputWithMensions,
27290
27884
  ChatInputWithMensionsV1,
27885
+ ChatList,
27291
27886
  Container$1 as Container,
27887
+ ContentRenderer,
27888
+ ContentType,
27292
27889
  CustomControlBar,
27293
27890
  DataGrid,
27294
27891
  DataGridV2,
@@ -27304,6 +27901,7 @@ export {
27304
27901
  ListItemActivityMessage,
27305
27902
  LivePersona,
27306
27903
  LogLevel,
27904
+ MarkdownRenderer,
27307
27905
  Mensions,
27308
27906
  MensionsExample,
27309
27907
  Popup,
@@ -27334,9 +27932,11 @@ export {
27334
27932
  defaultCalendarControlStrings,
27335
27933
  defaultCalendarMonthStrings,
27336
27934
  defaultSelectWeekStrings,
27935
+ detectContentType,
27337
27936
  every,
27338
27937
  filter,
27339
27938
  get,
27939
+ getContentType,
27340
27940
  groupBy,
27341
27941
  isEmpty,
27342
27942
  map,