@docsearch/react 4.6.3 → 5.0.0-beta.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/README.md +0 -2
- package/dist/esm/AskAiScreenState-D0IZsCMJ.d.ts +106 -0
- package/dist/esm/DocSearch-Dq5Utfyb.d.ts +295 -0
- package/dist/esm/DocSearchAskAiModal-BwbMrrHv.d.ts +48 -0
- package/dist/esm/DocSearchAskAiModal-CCrk6YLb.js +954 -0
- package/dist/esm/DocSearchAskAiModal-CCrk6YLb.js.map +1 -0
- package/dist/esm/DocSearchButton-CRlNPf5k.d.ts +18 -0
- package/dist/esm/DocSearchButton-CaxxOzQU.js +71 -0
- package/dist/esm/DocSearchButton-CaxxOzQU.js.map +1 -0
- package/dist/esm/DocSearchModal-CpvDjo1O.js +250 -0
- package/dist/esm/DocSearchModal-CpvDjo1O.js.map +1 -0
- package/dist/esm/DocSearchTheme-DvL4mf0D.d.ts +5 -0
- package/dist/esm/askaiModal.d.ts +2 -0
- package/dist/esm/askaiModal.js +3 -0
- package/dist/esm/button.d.ts +2 -0
- package/dist/esm/button.js +3 -0
- package/dist/esm/docsearchAi.d.ts +220 -0
- package/dist/esm/docsearchAi.js +34 -0
- package/dist/esm/docsearchAi.js.map +1 -0
- package/dist/esm/index-Dl8FMlR5.d.ts +223 -0
- package/dist/esm/index.d.ts +9 -655
- package/dist/esm/index.js +35 -3
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/keyboard-BkSdCzTU.js +9 -0
- package/dist/esm/keyboard-BkSdCzTU.js.map +1 -0
- package/dist/esm/keyboardShortcuts-C-lx6Xt7.js +25 -0
- package/dist/esm/keyboardShortcuts-C-lx6Xt7.js.map +1 -0
- package/dist/esm/modal.d.ts +2 -0
- package/dist/esm/modal.js +3 -0
- package/dist/esm/normalizeDocSearchIndexes-DAzlMybx.js +1240 -0
- package/dist/esm/normalizeDocSearchIndexes-DAzlMybx.js.map +1 -0
- package/dist/esm/objectSpread2-BNmiQYyW.js +67 -0
- package/dist/esm/objectWithoutProperties-phqYxDS0.js +53 -0
- package/dist/esm/objectWithoutProperties-phqYxDS0.js.map +1 -0
- package/dist/esm/sidepanel.d.ts +395 -0
- package/dist/esm/sidepanel.js +773 -0
- package/dist/esm/sidepanel.js.map +1 -0
- package/dist/esm/useDocSearchKeyboardEvents-68G8dw6c.d.ts +43 -0
- package/dist/esm/useDocSearchKeyboardEvents.d.ts +2 -41
- package/dist/esm/useDocSearchKeyboardEvents.js +43 -1
- package/dist/esm/useDocSearchKeyboardEvents.js.map +1 -0
- package/dist/esm/useSearchClient-mIHVB6ga.js +433 -0
- package/dist/esm/useSearchClient-mIHVB6ga.js.map +1 -0
- package/dist/esm/useSuggestedQuestions-D2TGVPsI.js +1112 -0
- package/dist/esm/useSuggestedQuestions-D2TGVPsI.js.map +1 -0
- package/dist/esm/useTheme.d.ts +7 -6
- package/dist/esm/useTheme.js +21 -1
- package/dist/esm/useTheme.js.map +1 -0
- package/dist/esm/version.d.ts +4 -2
- package/dist/esm/version.js +6 -1
- package/dist/esm/version.js.map +1 -0
- package/dist/umd/index.js +175 -5
- package/dist/umd/index.js.map +1 -1
- package/package.json +31 -34
- package/style/askai.js +1 -0
- package/button.js +0 -1
- package/dist/esm/DocSearchButton.d.ts +0 -18
- package/dist/esm/DocSearchButton.js +0 -1
- package/dist/esm/DocSearchModal.d.ts +0 -444
- package/dist/esm/DocSearchModal.js +0 -3
- package/dist/esm/Sidepanel.d.ts +0 -371
- package/dist/esm/Sidepanel.js +0 -3
- package/dist/umd/DocSearchModal.js +0 -5
- package/dist/umd/DocSearchModal.js.map +0 -1
- package/dist/umd/DocsearchButton.js +0 -3
- package/dist/umd/DocsearchButton.js.map +0 -1
- package/dist/umd/Sidepanel.js +0 -5
- package/dist/umd/Sidepanel.js.map +0 -1
- package/dist/umd/useDocSearchKeyboardEvents.js +0 -3
- package/dist/umd/useDocSearchKeyboardEvents.js.map +0 -1
- package/dist/umd/useTheme.js +0 -3
- package/dist/umd/useTheme.js.map +0 -1
- package/dist/umd/version.js +0 -3
- package/dist/umd/version.js.map +0 -1
- package/modal.js +0 -1
- package/sidepanel.js +0 -1
- package/useDocSearchKeyboardEvents.js +0 -1
- package/useTheme.js +0 -1
- package/version.js +0 -1
|
@@ -0,0 +1,1112 @@
|
|
|
1
|
+
import { t as _objectSpread2 } from "./objectSpread2-BNmiQYyW.js";
|
|
2
|
+
import { n as SearchIcon, t as _objectWithoutProperties } from "./objectWithoutProperties-phqYxDS0.js";
|
|
3
|
+
import { d as _objectDestructuringEmpty, l as CloseIcon, m as LoadingIcon, n as createStoredConversations, o as SUGGESTED_QUETIONS_INDEX_NAME, s as ContentIcon, u as _extends } from "./useSearchClient-mIHVB6ga.js";
|
|
4
|
+
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { Popover } from "@base-ui/react/popover";
|
|
6
|
+
import { marked } from "marked";
|
|
7
|
+
import { Chat, useChat } from "@ai-sdk/react";
|
|
8
|
+
import { DefaultChatTransport, generateId, lastAssistantMessageIsCompleteWithToolCalls } from "ai";
|
|
9
|
+
|
|
10
|
+
//#region src/icons/AlertIcon.tsx
|
|
11
|
+
function AlertIcon(props) {
|
|
12
|
+
return /* @__PURE__ */ React.createElement("svg", _objectSpread2({
|
|
13
|
+
width: "16",
|
|
14
|
+
height: "16",
|
|
15
|
+
viewBox: "0 0 24 24",
|
|
16
|
+
fill: "none",
|
|
17
|
+
fillRule: "evenodd",
|
|
18
|
+
stroke: "currentColor",
|
|
19
|
+
strokeLinecap: "round",
|
|
20
|
+
strokeLinejoin: "round",
|
|
21
|
+
strokeWidth: "2"
|
|
22
|
+
}, props), /* @__PURE__ */ React.createElement("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }), /* @__PURE__ */ React.createElement("path", { d: "M12 9v4" }), /* @__PURE__ */ React.createElement("path", { d: "M12 17h.01" }));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
//#region src/icons/StopIcon.tsx
|
|
27
|
+
function StopIcon() {
|
|
28
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
29
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
30
|
+
width: 18,
|
|
31
|
+
height: 18,
|
|
32
|
+
viewBox: "0 0 18 18",
|
|
33
|
+
fill: "none"
|
|
34
|
+
}, /* @__PURE__ */ React.createElement("path", {
|
|
35
|
+
fillRule: "evenodd",
|
|
36
|
+
clipRule: "evenodd",
|
|
37
|
+
d: "M8.99984 1.29102C4.74264 1.29102 1.2915 4.74215 1.2915 8.99935C1.2915 13.2565 4.74264 16.7077 8.99984 16.7077C13.257 16.7077 16.7082 13.2565 16.7082 8.99935C16.7082 4.74215 13.257 1.29102 8.99984 1.29102ZM0.0415039 8.99935C0.0415039 4.0518 4.05229 0.0410156 8.99984 0.0410156C13.9474 0.0410156 17.9582 4.0518 17.9582 8.99935C17.9582 13.9469 13.9474 17.9577 8.99984 17.9577C4.05229 17.9577 0.0415039 13.9469 0.0415039 8.99935ZM5.87484 6.49935C5.87484 6.15417 6.15466 5.87435 6.49984 5.87435H11.4998C11.845 5.87435 12.1248 6.15417 12.1248 6.49935V11.4993C12.1248 11.8445 11.845 12.1243 11.4998 12.1243H6.49984C6.15466 12.1243 5.87484 11.8445 5.87484 11.4993V6.49935ZM7.12484 7.12435V10.8743H10.8748V7.12435H7.12484Z",
|
|
38
|
+
fill: "currentcolor"
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/icons/MoreVerticalIcon.tsx
|
|
44
|
+
function MoreVerticalIcon() {
|
|
45
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
46
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
47
|
+
width: 4,
|
|
48
|
+
height: 16,
|
|
49
|
+
viewBox: "0 0 4 16",
|
|
50
|
+
fill: "none"
|
|
51
|
+
}, /* @__PURE__ */ React.createElement("path", {
|
|
52
|
+
fillRule: "evenodd",
|
|
53
|
+
clipRule: "evenodd",
|
|
54
|
+
d: "M1.99984 1.95898C1.88478 1.95898 1.7915 2.05226 1.7915 2.16732C1.7915 2.28238 1.88478 2.37565 1.99984 2.37565C2.1149 2.37565 2.20817 2.28238 2.20817 2.16732C2.20817 2.05226 2.1149 1.95898 1.99984 1.95898ZM0.541504 2.16732C0.541504 1.3619 1.19442 0.708984 1.99984 0.708984C2.80525 0.708984 3.45817 1.3619 3.45817 2.16732C3.45817 2.97273 2.80525 3.62565 1.99984 3.62565C1.19442 3.62565 0.541504 2.97273 0.541504 2.16732ZM1.99984 7.79232C1.88478 7.79232 1.7915 7.88559 1.7915 8.00065C1.7915 8.11571 1.88478 8.20898 1.99984 8.20898C2.1149 8.20898 2.20817 8.11571 2.20817 8.00065C2.20817 7.88559 2.1149 7.79232 1.99984 7.79232ZM0.541504 8.00065C0.541504 7.19524 1.19442 6.54232 1.99984 6.54232C2.80525 6.54232 3.45817 7.19524 3.45817 8.00065C3.45817 8.80607 2.80525 9.45898 1.99984 9.45898C1.19442 9.45898 0.541504 8.80607 0.541504 8.00065ZM1.99984 13.6257C1.88478 13.6257 1.7915 13.7189 1.7915 13.834C1.7915 13.949 1.88478 14.0423 1.99984 14.0423C2.1149 14.0423 2.20817 13.949 2.20817 13.834C2.20817 13.7189 2.1149 13.6257 1.99984 13.6257ZM0.541504 13.834C0.541504 13.0286 1.19442 12.3757 1.99984 12.3757C2.80525 12.3757 3.45817 13.0286 3.45817 13.834C3.45817 14.6394 2.80525 15.2923 1.99984 15.2923C1.19442 15.2923 0.541504 14.6394 0.541504 13.834Z",
|
|
55
|
+
fill: "currentcolor"
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
//#endregion
|
|
60
|
+
//#region src/icons/ConversationHistoryIcon.tsx
|
|
61
|
+
function ConversationHistoryIcon() {
|
|
62
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
63
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
64
|
+
width: "18",
|
|
65
|
+
height: "18",
|
|
66
|
+
viewBox: "0 0 18 18",
|
|
67
|
+
fill: "none"
|
|
68
|
+
}, /* @__PURE__ */ React.createElement("path", {
|
|
69
|
+
d: "M9 0.875C10.6068 0.875 12.1776 1.35149 13.5137 2.24414C14.8498 3.13693 15.8919 4.40598 16.5068 5.89062C17.1218 7.37522 17.2822 9.00892 16.9688 10.585C16.6552 12.1611 15.8814 13.6088 14.7451 14.7451C13.6088 15.8814 12.1611 16.6552 10.585 16.9688C9.00892 17.2822 7.37523 17.1218 5.89062 16.5068C4.40598 15.8919 3.13693 14.8498 2.24414 13.5137C1.35149 12.1776 0.875 10.6068 0.875 9C0.875 8.65482 1.15482 8.375 1.5 8.375C1.84518 8.375 2.125 8.65482 2.125 9C2.125 10.3596 2.52792 11.6888 3.2832 12.8193C4.03864 13.9499 5.1129 14.8312 6.36914 15.3516C7.62523 15.8718 9.00736 16.0083 10.3408 15.7432C11.6744 15.4779 12.8998 14.8228 13.8613 13.8613C14.8228 12.8998 15.4779 11.6744 15.7432 10.3408C16.0083 9.00736 15.8718 7.62523 15.3516 6.36914C14.8312 5.1129 13.9499 4.03864 12.8193 3.2832C11.6888 2.52792 10.3596 2.125 9 2.125C7.06829 2.125 5.21604 2.89096 3.82129 4.22949L3.00879 5.04199H5.66699C6.01202 5.04217 6.29199 5.32192 6.29199 5.66699C6.29182 6.01191 6.01191 6.29182 5.66699 6.29199H1.5C1.45939 6.29199 1.41889 6.28716 1.37891 6.2793C1.36148 6.27587 1.345 6.26949 1.32812 6.26465C1.267 6.24714 1.20782 6.22205 1.15332 6.18555C1.08536 6.14005 1.02604 6.08256 0.980469 6.01465C0.970244 5.99942 0.962841 5.98268 0.954102 5.9668C0.904937 5.87756 0.875056 5.77606 0.875 5.66699V1.5C0.875 1.15482 1.15482 0.875002 1.5 0.875C1.84518 0.875 2.125 1.15482 2.125 1.5V4.15723L2.94141 3.3418L2.9502 3.33301C4.57158 1.77433 6.73388 0.875 9 0.875ZM9.33301 4.20801C9.67808 4.20801 9.95783 4.48798 9.95801 4.83301V9.44727L12.9463 10.9414C13.2548 11.0958 13.3798 11.4707 13.2256 11.7793C13.0712 12.088 12.6955 12.213 12.3867 12.0586L9.05371 10.3926C8.84198 10.2867 8.70801 10.0697 8.70801 9.83301V4.83301C8.70818 4.48809 8.98809 4.20819 9.33301 4.20801Z",
|
|
70
|
+
fill: "currentcolor"
|
|
71
|
+
}));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/icons/NewConversationIcon.tsx
|
|
76
|
+
function NewConversationIcon() {
|
|
77
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
78
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
79
|
+
width: "19",
|
|
80
|
+
height: "19",
|
|
81
|
+
viewBox: "0 0 19 19",
|
|
82
|
+
fill: "none"
|
|
83
|
+
}, /* @__PURE__ */ React.createElement("path", {
|
|
84
|
+
fillRule: "evenodd",
|
|
85
|
+
clipRule: "evenodd",
|
|
86
|
+
d: "M0.712717 3.38039C1.14249 2.95062 1.72538 2.70917 2.33317 2.70917H8.1665C8.51168 2.70917 8.7915 2.989 8.7915 3.33417C8.7915 3.67935 8.51168 3.95917 8.1665 3.95917H2.33317C2.0569 3.95917 1.79195 4.06892 1.5966 4.26427C1.40125 4.45962 1.2915 4.72457 1.2915 5.00084V16.6675C1.2915 16.9438 1.40125 17.2087 1.5966 17.4041C1.79195 17.5994 2.0569 17.7092 2.33317 17.7092H13.9998C14.2761 17.7092 14.5411 17.5994 14.7364 17.4041C14.9318 17.2087 15.0415 16.9438 15.0415 16.6675V10.8342C15.0415 10.489 15.3213 10.2092 15.6665 10.2092C16.0117 10.2092 16.2915 10.489 16.2915 10.8342V16.6675C16.2915 17.2753 16.0501 17.8582 15.6203 18.288C15.1905 18.7177 14.6076 18.9592 13.9998 18.9592H2.33317C1.72538 18.9592 1.14249 18.7177 0.712717 18.288C0.282947 17.8582 0.0415039 17.2753 0.0415039 16.6675V5.00084C0.0415039 4.39305 0.282947 3.81016 0.712717 3.38039Z",
|
|
87
|
+
fill: "currentcolor"
|
|
88
|
+
}), /* @__PURE__ */ React.createElement("path", {
|
|
89
|
+
fillRule: "evenodd",
|
|
90
|
+
clipRule: "evenodd",
|
|
91
|
+
d: "M15.6665 2.19141C15.3634 2.19141 15.0728 2.3118 14.8584 2.52611L7.06419 10.3204L6.52548 12.4752L8.68031 11.9365L16.4746 4.14223C16.6889 3.92792 16.8093 3.63725 16.8093 3.33417C16.8093 3.03109 16.6889 2.74043 16.4746 2.52611C16.2603 2.3118 15.9696 2.19141 15.6665 2.19141ZM13.9746 1.64223C14.4233 1.1935 15.0319 0.941406 15.6665 0.941406C16.3011 0.941406 16.9097 1.1935 17.3584 1.64223C17.8072 2.09096 18.0593 2.69957 18.0593 3.33417C18.0593 3.96877 17.8072 4.57738 17.3584 5.02611L9.44178 12.9428C9.36168 13.0229 9.26132 13.0797 9.15142 13.1072L5.81809 13.9405C5.6051 13.9938 5.3798 13.9314 5.22456 13.7761C5.06932 13.6209 5.00692 13.3956 5.06016 13.1826L5.8935 9.84925C5.92097 9.73936 5.9778 9.639 6.0579 9.5589L13.9746 1.64223Z",
|
|
92
|
+
fill: "currentcolor"
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/icons/ToolIcon.tsx
|
|
98
|
+
function ToolIcon({ size = 20 }) {
|
|
99
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
100
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
101
|
+
width: size,
|
|
102
|
+
height: size,
|
|
103
|
+
viewBox: "0 0 24 24",
|
|
104
|
+
fill: "none",
|
|
105
|
+
stroke: "currentColor",
|
|
106
|
+
strokeWidth: "2",
|
|
107
|
+
strokeLinecap: "round",
|
|
108
|
+
strokeLinejoin: "round",
|
|
109
|
+
className: "DocSearch-Search-Icon"
|
|
110
|
+
}, /* @__PURE__ */ React.createElement("path", { d: "M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" }));
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/icons/MemoryIcon.tsx
|
|
115
|
+
function MemoryIcon() {
|
|
116
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
117
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
118
|
+
width: "24",
|
|
119
|
+
height: "24",
|
|
120
|
+
viewBox: "0 0 24 24",
|
|
121
|
+
fill: "none",
|
|
122
|
+
stroke: "currentColor",
|
|
123
|
+
strokeWidth: "2",
|
|
124
|
+
strokeLinecap: "round",
|
|
125
|
+
strokeLinejoin: "round"
|
|
126
|
+
}, /* @__PURE__ */ React.createElement("path", { d: "M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z" }), /* @__PURE__ */ React.createElement("path", { d: "M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z" }));
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
//#endregion
|
|
130
|
+
//#region src/icons/BackIcon.tsx
|
|
131
|
+
function BackIcon({ size = 20, color = "currentColor" }) {
|
|
132
|
+
return /* @__PURE__ */ React.createElement("svg", {
|
|
133
|
+
width: size,
|
|
134
|
+
height: size,
|
|
135
|
+
className: "DocSearch-Back-Icon",
|
|
136
|
+
viewBox: "0 0 24 24",
|
|
137
|
+
fill: "none",
|
|
138
|
+
stroke: color,
|
|
139
|
+
strokeWidth: "1.6",
|
|
140
|
+
strokeLinecap: "round",
|
|
141
|
+
strokeLinejoin: "round",
|
|
142
|
+
"aria-hidden": "true"
|
|
143
|
+
}, /* @__PURE__ */ React.createElement("path", { d: "m12 19-7-7 7-7" }), /* @__PURE__ */ React.createElement("path", { d: "M19 12H5" }));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/components/ConversationPromptSuggestions.tsx
|
|
148
|
+
const ConversationPromptSuggestions = React.memo(function ConversationPromptSuggestions({ title, suggestions, onSelectPromptSuggestion }) {
|
|
149
|
+
const titleId = React.useId();
|
|
150
|
+
const handleSelectPromptSuggestion = React.useCallback((e) => {
|
|
151
|
+
onSelectPromptSuggestion(e.currentTarget.value);
|
|
152
|
+
}, [onSelectPromptSuggestion]);
|
|
153
|
+
return /* @__PURE__ */ React.createElement("section", {
|
|
154
|
+
className: "DocSearch-PromptSuggestions",
|
|
155
|
+
"aria-labelledby": titleId
|
|
156
|
+
}, /* @__PURE__ */ React.createElement("h3", {
|
|
157
|
+
className: "DocSearch-PromptSuggestions-Title",
|
|
158
|
+
id: titleId
|
|
159
|
+
}, title), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-PromptSuggestions-Content" }, suggestions.map((suggestion) => /* @__PURE__ */ React.createElement("button", {
|
|
160
|
+
key: suggestion,
|
|
161
|
+
type: "button",
|
|
162
|
+
className: "DocSearch-PromptSuggestions-Action",
|
|
163
|
+
value: suggestion,
|
|
164
|
+
onClick: handleSelectPromptSuggestion
|
|
165
|
+
}, suggestion))));
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
//#endregion
|
|
169
|
+
//#region src/components/FeedbackActions.tsx
|
|
170
|
+
const FEEDBACK_REASONS = [
|
|
171
|
+
{
|
|
172
|
+
value: "incorrect",
|
|
173
|
+
translationKey: "feedbackTagIncorrect",
|
|
174
|
+
defaultLabel: "Incorrect or incomplete"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
value: "not_what_i_asked",
|
|
178
|
+
translationKey: "feedbackTagNotWhatIAsked",
|
|
179
|
+
defaultLabel: "Not what I asked for"
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
value: "slow_or_buggy",
|
|
183
|
+
translationKey: "feedbackTagSlowOrBuggy",
|
|
184
|
+
defaultLabel: "Slow or buggy"
|
|
185
|
+
},
|
|
186
|
+
{
|
|
187
|
+
value: "style_or_tone",
|
|
188
|
+
translationKey: "feedbackTagStyleOrTone",
|
|
189
|
+
defaultLabel: "Style or tone"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
value: "safety_or_legal",
|
|
193
|
+
translationKey: "feedbackTagSafetyOrLegal",
|
|
194
|
+
defaultLabel: "Safety or legal concern"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
value: "other",
|
|
198
|
+
translationKey: "feedbackTagOther",
|
|
199
|
+
defaultLabel: "Other"
|
|
200
|
+
}
|
|
201
|
+
];
|
|
202
|
+
const MAX_NOTES_LENGTH = 1e3;
|
|
203
|
+
function FeedbackActions({ id, showActions, latestAssistantMessageContent, translations, conversations, onFeedback, isSidepanel = false }) {
|
|
204
|
+
const [view, setView] = useState(() => {
|
|
205
|
+
var _conversations$getOne;
|
|
206
|
+
const message = (_conversations$getOne = conversations.getOne) === null || _conversations$getOne === void 0 ? void 0 : _conversations$getOne.call(conversations, id);
|
|
207
|
+
return (message === null || message === void 0 ? void 0 : message.feedback) ? "thanks" : "actions";
|
|
208
|
+
});
|
|
209
|
+
const [tags, setTags] = useState([]);
|
|
210
|
+
const [notes, setNotes] = useState("");
|
|
211
|
+
const [saving, setSaving] = useState(false);
|
|
212
|
+
const [savingError, setSavingError] = useState(null);
|
|
213
|
+
const { likeButtonTitle = "Like", dislikeButtonTitle = "Dislike", thanksForFeedbackText = "Thanks for your feedback!" } = translations;
|
|
214
|
+
const handleLike = async () => {
|
|
215
|
+
if (saving) return;
|
|
216
|
+
setSavingError(null);
|
|
217
|
+
setSaving(true);
|
|
218
|
+
try {
|
|
219
|
+
await (onFeedback === null || onFeedback === void 0 ? void 0 : onFeedback(id, { thumbs: 1 }));
|
|
220
|
+
setView("thanks");
|
|
221
|
+
} catch (error) {
|
|
222
|
+
setSavingError(error);
|
|
223
|
+
} finally {
|
|
224
|
+
setSaving(false);
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
const handleDislike = () => {
|
|
228
|
+
setSavingError(null);
|
|
229
|
+
setView("note");
|
|
230
|
+
};
|
|
231
|
+
const handleToggleTag = (value) => {
|
|
232
|
+
setTags((prev) => prev.includes(value) ? prev.filter((tag) => tag !== value) : [...prev, value]);
|
|
233
|
+
};
|
|
234
|
+
const handleSubmitNote = async () => {
|
|
235
|
+
if (saving) return;
|
|
236
|
+
setSavingError(null);
|
|
237
|
+
setSaving(true);
|
|
238
|
+
try {
|
|
239
|
+
await (onFeedback === null || onFeedback === void 0 ? void 0 : onFeedback(id, {
|
|
240
|
+
thumbs: 0,
|
|
241
|
+
tags: tags.length > 0 ? tags : void 0,
|
|
242
|
+
notes: notes.trim() || void 0
|
|
243
|
+
}));
|
|
244
|
+
setView("thanks");
|
|
245
|
+
} catch (error) {
|
|
246
|
+
setSavingError(error);
|
|
247
|
+
} finally {
|
|
248
|
+
setSaving(false);
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const handleCloseNote = () => {
|
|
252
|
+
setTags([]);
|
|
253
|
+
setNotes("");
|
|
254
|
+
setSavingError(null);
|
|
255
|
+
setView("actions");
|
|
256
|
+
};
|
|
257
|
+
if (!showActions || !latestAssistantMessageContent) return null;
|
|
258
|
+
const copyButton = /* @__PURE__ */ React.createElement(CopyButton, {
|
|
259
|
+
translations,
|
|
260
|
+
onClick: () => navigator.clipboard.writeText(latestAssistantMessageContent)
|
|
261
|
+
});
|
|
262
|
+
return /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Actions" }, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-AskAiScreen-Actions-Controls" }, isSidepanel ? copyButton : null, view === "thanks" ? /* @__PURE__ */ React.createElement("p", { className: "DocSearch-AskAiScreen-FeedbackText DocSearch-AskAiScreen-FeedbackText--visible" }, thanksForFeedbackText) : /* @__PURE__ */ React.createElement(React.Fragment, null, saving && view === "actions" ? /* @__PURE__ */ React.createElement(LoadingIcon, { className: "DocSearch-AskAiScreen-SmallerLoadingIcon" }) : /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(LikeButton, {
|
|
263
|
+
title: likeButtonTitle,
|
|
264
|
+
onClick: handleLike
|
|
265
|
+
}), /* @__PURE__ */ React.createElement(DislikeButton, {
|
|
266
|
+
title: dislikeButtonTitle,
|
|
267
|
+
onClick: handleDislike
|
|
268
|
+
})), savingError && view === "actions" ? /* @__PURE__ */ React.createElement("p", { className: "DocSearch-AskAiScreen-FeedbackText" }, savingError.message || "An error occured") : null), isSidepanel ? null : copyButton), view === "note" ? /* @__PURE__ */ React.createElement(NegativeFeedbackPanel, {
|
|
269
|
+
translations,
|
|
270
|
+
tags,
|
|
271
|
+
notes,
|
|
272
|
+
saving,
|
|
273
|
+
savingError,
|
|
274
|
+
onToggleTag: handleToggleTag,
|
|
275
|
+
onNotesChange: setNotes,
|
|
276
|
+
onSubmit: handleSubmitNote,
|
|
277
|
+
onClose: handleCloseNote
|
|
278
|
+
}) : null);
|
|
279
|
+
}
|
|
280
|
+
function NegativeFeedbackPanel({ translations, tags, notes, saving, savingError, onToggleTag, onNotesChange, onSubmit, onClose }) {
|
|
281
|
+
const { feedbackPanelTitle = "What went wrong? (optional)", feedbackDetailsPlaceholder = "Share some details...", feedbackSubmitButtonText = "Submit", feedbackCancelButtonText = "Cancel" } = translations;
|
|
282
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
283
|
+
className: "DocSearch-Feedback-Panel",
|
|
284
|
+
role: "group",
|
|
285
|
+
"aria-label": feedbackPanelTitle
|
|
286
|
+
}, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Feedback-Panel-Header" }, /* @__PURE__ */ React.createElement("p", { className: "DocSearch-Feedback-Panel-Title" }, feedbackPanelTitle)), /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Feedback-Panel-Reasons" }, FEEDBACK_REASONS.map((reason) => {
|
|
287
|
+
var _translations$reason$;
|
|
288
|
+
const isSelected = tags.includes(reason.value);
|
|
289
|
+
return /* @__PURE__ */ React.createElement("button", {
|
|
290
|
+
key: reason.value,
|
|
291
|
+
type: "button",
|
|
292
|
+
className: `DocSearch-Feedback-Panel-Reason${isSelected ? " DocSearch-Feedback-Panel-Reason--selected" : ""}`,
|
|
293
|
+
"aria-pressed": isSelected,
|
|
294
|
+
onClick: () => onToggleTag(reason.value)
|
|
295
|
+
}, /* @__PURE__ */ React.createElement("span", null, (_translations$reason$ = translations[reason.translationKey]) !== null && _translations$reason$ !== void 0 ? _translations$reason$ : reason.defaultLabel));
|
|
296
|
+
})), /* @__PURE__ */ React.createElement("textarea", {
|
|
297
|
+
className: "DocSearch-Feedback-Panel-Textarea",
|
|
298
|
+
placeholder: feedbackDetailsPlaceholder,
|
|
299
|
+
value: notes,
|
|
300
|
+
rows: 3,
|
|
301
|
+
maxLength: MAX_NOTES_LENGTH,
|
|
302
|
+
onChange: (event) => onNotesChange(event.target.value.slice(0, MAX_NOTES_LENGTH))
|
|
303
|
+
}), /* @__PURE__ */ React.createElement("p", {
|
|
304
|
+
className: "DocSearch-Feedback-Panel-CharCount",
|
|
305
|
+
"aria-live": "polite"
|
|
306
|
+
}, notes.length, "/", MAX_NOTES_LENGTH), savingError ? /* @__PURE__ */ React.createElement("p", { className: "DocSearch-Feedback-Panel-Error" }, savingError.message || "An error occured") : null, /* @__PURE__ */ React.createElement("div", { className: "DocSearch-Feedback-Panel-Actions" }, /* @__PURE__ */ React.createElement("button", {
|
|
307
|
+
type: "button",
|
|
308
|
+
className: "DocSearch-Feedback-Panel-Cancel",
|
|
309
|
+
onClick: onClose
|
|
310
|
+
}, feedbackCancelButtonText), /* @__PURE__ */ React.createElement("button", {
|
|
311
|
+
type: "button",
|
|
312
|
+
className: "DocSearch-Feedback-Panel-Submit",
|
|
313
|
+
disabled: saving,
|
|
314
|
+
onClick: onSubmit
|
|
315
|
+
}, saving ? /* @__PURE__ */ React.createElement(LoadingIcon, { className: "DocSearch-AskAiScreen-SmallerLoadingIcon" }) : feedbackSubmitButtonText)));
|
|
316
|
+
}
|
|
317
|
+
function CopyButton({ onClick, translations }) {
|
|
318
|
+
const { copyButtonTitle = "Copy", copyButtonCopiedText = "Copied!" } = translations;
|
|
319
|
+
const [isCopied, setIsCopied] = useState(false);
|
|
320
|
+
useEffect(() => {
|
|
321
|
+
if (isCopied) {
|
|
322
|
+
const timer = setTimeout(() => {
|
|
323
|
+
setIsCopied(false);
|
|
324
|
+
}, 1500);
|
|
325
|
+
return () => clearTimeout(timer);
|
|
326
|
+
}
|
|
327
|
+
}, [isCopied]);
|
|
328
|
+
const handleClick = () => {
|
|
329
|
+
onClick();
|
|
330
|
+
setIsCopied(true);
|
|
331
|
+
};
|
|
332
|
+
return /* @__PURE__ */ React.createElement("button", {
|
|
333
|
+
type: "button",
|
|
334
|
+
className: `DocSearch-AskAiScreen-ActionButton DocSearch-AskAiScreen-CopyButton ${isCopied ? "DocSearch-AskAiScreen-CopyButton--copied" : ""}`,
|
|
335
|
+
disabled: isCopied,
|
|
336
|
+
title: isCopied ? copyButtonCopiedText : copyButtonTitle,
|
|
337
|
+
onClick: handleClick
|
|
338
|
+
}, isCopied ? /* @__PURE__ */ React.createElement("svg", {
|
|
339
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
340
|
+
width: "24",
|
|
341
|
+
height: "24",
|
|
342
|
+
viewBox: "0 0 24 24",
|
|
343
|
+
fill: "none",
|
|
344
|
+
stroke: "currentColor",
|
|
345
|
+
strokeWidth: "1.5",
|
|
346
|
+
strokeLinecap: "round",
|
|
347
|
+
strokeLinejoin: "round"
|
|
348
|
+
}, /* @__PURE__ */ React.createElement("path", { d: "M20 6 9 17l-5-5" })) : /* @__PURE__ */ React.createElement("svg", {
|
|
349
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
350
|
+
width: "24",
|
|
351
|
+
height: "24",
|
|
352
|
+
viewBox: "0 0 24 24",
|
|
353
|
+
fill: "none",
|
|
354
|
+
stroke: "currentColor",
|
|
355
|
+
strokeWidth: "1.5",
|
|
356
|
+
strokeLinecap: "round",
|
|
357
|
+
strokeLinejoin: "round"
|
|
358
|
+
}, /* @__PURE__ */ React.createElement("rect", {
|
|
359
|
+
width: "14",
|
|
360
|
+
height: "14",
|
|
361
|
+
x: "8",
|
|
362
|
+
y: "8",
|
|
363
|
+
rx: "2",
|
|
364
|
+
ry: "2"
|
|
365
|
+
}), /* @__PURE__ */ React.createElement("path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" })));
|
|
366
|
+
}
|
|
367
|
+
function LikeButton({ title, onClick }) {
|
|
368
|
+
return /* @__PURE__ */ React.createElement("button", {
|
|
369
|
+
type: "button",
|
|
370
|
+
className: "DocSearch-AskAiScreen-ActionButton DocSearch-AskAiScreen-LikeButton",
|
|
371
|
+
title,
|
|
372
|
+
onClick
|
|
373
|
+
}, /* @__PURE__ */ React.createElement("svg", {
|
|
374
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
375
|
+
width: "24",
|
|
376
|
+
height: "24",
|
|
377
|
+
viewBox: "0 0 24 24",
|
|
378
|
+
fill: "none",
|
|
379
|
+
stroke: "currentColor",
|
|
380
|
+
strokeWidth: "1.5",
|
|
381
|
+
strokeLinecap: "round",
|
|
382
|
+
strokeLinejoin: "round"
|
|
383
|
+
}, /* @__PURE__ */ React.createElement("path", { d: "M7 10v12" }), /* @__PURE__ */ React.createElement("path", { d: "M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z" })));
|
|
384
|
+
}
|
|
385
|
+
function DislikeButton({ title, onClick }) {
|
|
386
|
+
return /* @__PURE__ */ React.createElement("button", {
|
|
387
|
+
type: "button",
|
|
388
|
+
className: "DocSearch-AskAiScreen-ActionButton DocSearch-AskAiScreen-DislikeButton",
|
|
389
|
+
title,
|
|
390
|
+
onClick
|
|
391
|
+
}, /* @__PURE__ */ React.createElement("svg", {
|
|
392
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
393
|
+
width: "24",
|
|
394
|
+
height: "24",
|
|
395
|
+
viewBox: "0 0 24 24",
|
|
396
|
+
fill: "none",
|
|
397
|
+
stroke: "currentColor",
|
|
398
|
+
strokeWidth: "1.5",
|
|
399
|
+
strokeLinecap: "round",
|
|
400
|
+
strokeLinejoin: "round"
|
|
401
|
+
}, /* @__PURE__ */ React.createElement("path", { d: "M17 14V2" }), /* @__PURE__ */ React.createElement("path", { d: "M9 18.12 10 14H4.17a2 2 0 0 1-1.92-2.56l2.33-8A2 2 0 0 1 6.5 2H20a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-2.76a2 2 0 0 0-1.79 1.11L12 22a3.13 3.13 0 0 1-3-3.88Z" })));
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
//#endregion
|
|
405
|
+
//#region src/components/ui/Popover.tsx
|
|
406
|
+
const _excluded$2 = ["className"];
|
|
407
|
+
const _excluded2 = [
|
|
408
|
+
"align",
|
|
409
|
+
"alignOffset",
|
|
410
|
+
"side",
|
|
411
|
+
"sideOffset",
|
|
412
|
+
"collisionBoundary",
|
|
413
|
+
"container",
|
|
414
|
+
"children"
|
|
415
|
+
];
|
|
416
|
+
function Popover$1(_ref) {
|
|
417
|
+
let props = _extends({}, (_objectDestructuringEmpty(_ref), _ref));
|
|
418
|
+
return /* @__PURE__ */ React.createElement(Popover.Root, props);
|
|
419
|
+
}
|
|
420
|
+
function PopoverTrigger(_ref2) {
|
|
421
|
+
let { className } = _ref2, props = _objectWithoutProperties(_ref2, _excluded$2);
|
|
422
|
+
const cn = `DocSearch-Popover-Trigger${className ? ` ${className}` : ""}`;
|
|
423
|
+
return /* @__PURE__ */ React.createElement(Popover.Trigger, _objectSpread2({ className: cn }, props));
|
|
424
|
+
}
|
|
425
|
+
Popover$1.Trigger = PopoverTrigger;
|
|
426
|
+
function PopoverPopup(_ref3) {
|
|
427
|
+
let { align = "center", alignOffset = 0, side = "bottom", sideOffset = 4, collisionBoundary = "clipping-ancestors", container, children } = _ref3, props = _objectWithoutProperties(_ref3, _excluded2);
|
|
428
|
+
return /* @__PURE__ */ React.createElement(Popover.Portal, { container }, /* @__PURE__ */ React.createElement(Popover.Positioner, {
|
|
429
|
+
className: "DocSearch-Popover-Positioner",
|
|
430
|
+
align,
|
|
431
|
+
alignOffset,
|
|
432
|
+
side,
|
|
433
|
+
sideOffset,
|
|
434
|
+
collisionBoundary
|
|
435
|
+
}, /* @__PURE__ */ React.createElement(Popover.Popup, _objectSpread2({ className: "DocSearch-Popover-Popup" }, props), /* @__PURE__ */ React.createElement(Popover.Arrow, { className: "DocSearch-Popover-Arrow" }), /* @__PURE__ */ React.createElement(Popover.Close, { className: "DocSearch-Popover-Close" }, /* @__PURE__ */ React.createElement(CloseIcon, null)), children)));
|
|
436
|
+
}
|
|
437
|
+
Popover$1.Popup = PopoverPopup;
|
|
438
|
+
function PopoverTitle(_ref4) {
|
|
439
|
+
let props = _extends({}, (_objectDestructuringEmpty(_ref4), _ref4));
|
|
440
|
+
return /* @__PURE__ */ React.createElement(Popover.Title, _objectSpread2({ className: "DocSearch-Popover-Title" }, props));
|
|
441
|
+
}
|
|
442
|
+
Popover$1.Title = PopoverTitle;
|
|
443
|
+
|
|
444
|
+
//#endregion
|
|
445
|
+
//#region src/components/SourcesPanel.tsx
|
|
446
|
+
function SourcesPanel({ links, titleText = "Sources" }) {
|
|
447
|
+
const [open, setOpen] = React.useState(false);
|
|
448
|
+
const triggerRef = React.useRef(null);
|
|
449
|
+
const [boundary, setBoundary] = React.useState(null);
|
|
450
|
+
useEffect(() => {
|
|
451
|
+
var _ref, _trigger$closest;
|
|
452
|
+
if (!open) return;
|
|
453
|
+
const trigger = triggerRef.current;
|
|
454
|
+
const scrollContainer = (_ref = (_trigger$closest = trigger === null || trigger === void 0 ? void 0 : trigger.closest(".DocSearch-Sidepanel-Content")) !== null && _trigger$closest !== void 0 ? _trigger$closest : trigger === null || trigger === void 0 ? void 0 : trigger.closest(".DocSearch-Dropdown")) !== null && _ref !== void 0 ? _ref : null;
|
|
455
|
+
setBoundary(scrollContainer);
|
|
456
|
+
if (!scrollContainer) return;
|
|
457
|
+
const handleScroll = () => {
|
|
458
|
+
if (!triggerRef.current) return;
|
|
459
|
+
const triggerRect = triggerRef.current.getBoundingClientRect();
|
|
460
|
+
const containerRect = scrollContainer.getBoundingClientRect();
|
|
461
|
+
if (triggerRect.bottom <= containerRect.top || triggerRect.top >= containerRect.bottom) setOpen(false);
|
|
462
|
+
};
|
|
463
|
+
scrollContainer.addEventListener("scroll", handleScroll, { passive: true });
|
|
464
|
+
return () => {
|
|
465
|
+
scrollContainer.removeEventListener("scroll", handleScroll);
|
|
466
|
+
};
|
|
467
|
+
}, [open]);
|
|
468
|
+
if (links.length === 0) return null;
|
|
469
|
+
return /* @__PURE__ */ React.createElement(Popover$1, {
|
|
470
|
+
open,
|
|
471
|
+
modal: "trap-focus",
|
|
472
|
+
onOpenChange: setOpen
|
|
473
|
+
}, /* @__PURE__ */ React.createElement(Popover$1.Trigger, {
|
|
474
|
+
ref: triggerRef,
|
|
475
|
+
className: "DocSearch-AskAiScreen-Sources-Action"
|
|
476
|
+
}, /* @__PURE__ */ React.createElement("span", { className: "DocSearch-AskAiScreen-Sources-Action-icon" }, /* @__PURE__ */ React.createElement(ContentIcon, null)), /* @__PURE__ */ React.createElement("span", { className: "DocSearch-AskAiScreen-Sources-Action-text" }, links.length, " sources")), /* @__PURE__ */ React.createElement(Popover$1.Popup, {
|
|
477
|
+
container: boundary,
|
|
478
|
+
sideOffset: 10,
|
|
479
|
+
align: "start",
|
|
480
|
+
alignOffset: -16,
|
|
481
|
+
collisionBoundary: boundary !== null && boundary !== void 0 ? boundary : "clipping-ancestors"
|
|
482
|
+
}, /* @__PURE__ */ React.createElement(Popover$1.Title, null, titleText), /* @__PURE__ */ React.createElement("ul", { className: "DocSearch-AskAiScreen-Sources" }, links.map((l) => /* @__PURE__ */ React.createElement("li", {
|
|
483
|
+
key: l.url,
|
|
484
|
+
className: "DocSearch-AskAiScreen-Sources-source"
|
|
485
|
+
}, /* @__PURE__ */ React.createElement("a", {
|
|
486
|
+
href: l.url,
|
|
487
|
+
target: "_blank",
|
|
488
|
+
rel: "noopener noreferrer"
|
|
489
|
+
}, /* @__PURE__ */ React.createElement(ContentIcon, null), /* @__PURE__ */ React.createElement("span", { className: "DocSearch-AskAiScreen-Sources-source-title" }, l.title || l.url)))))));
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
//#endregion
|
|
493
|
+
//#region src/utils/sanitize.ts
|
|
494
|
+
/**
|
|
495
|
+
* Escapes HTML special characters to prevent XSS attacks. This should be used
|
|
496
|
+
* for any user-provided content that will be displayed.
|
|
497
|
+
*/
|
|
498
|
+
function escapeHtml$1(unsafe) {
|
|
499
|
+
return unsafe.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Sanitizes user input to prevent XSS attacks. Removes any HTML tags and
|
|
503
|
+
* escapes special characters.
|
|
504
|
+
*/
|
|
505
|
+
function sanitizeUserInput(input) {
|
|
506
|
+
return escapeHtml$1(input.replace(/<[^>]*>/g, ""));
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
//#endregion
|
|
510
|
+
//#region src/utils/ai.ts
|
|
511
|
+
function extractLinksFromMessage(message) {
|
|
512
|
+
const links = [];
|
|
513
|
+
const seen = /* @__PURE__ */ new Set();
|
|
514
|
+
if (!message) return [];
|
|
515
|
+
message.parts.forEach((part) => {
|
|
516
|
+
if (part.type !== "text") return;
|
|
517
|
+
if (part.text.length === 0) return;
|
|
518
|
+
const markdownLinkRegex = /\[([^\]]*)\]\(([^)]+)\)/g;
|
|
519
|
+
const plainLinkRegex = /* @__PURE__ */ new RegExp("(?<!\\]\\()https?:\\/\\/[^\\s<>\"{}|\\\\^`[\\]]+", "g");
|
|
520
|
+
const cleanText = part.text.replace(/```[\s\S]*?```/g, "").replace(/`[^`]*`/g, "");
|
|
521
|
+
const markdownMatches = cleanText.matchAll(markdownLinkRegex);
|
|
522
|
+
for (const match of markdownMatches) {
|
|
523
|
+
const title = match[1].trim();
|
|
524
|
+
const url = match[2];
|
|
525
|
+
if (!seen.has(url)) {
|
|
526
|
+
seen.add(url);
|
|
527
|
+
links.push({
|
|
528
|
+
url,
|
|
529
|
+
title: title || void 0
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
const plainUrls = cleanText.matchAll(plainLinkRegex);
|
|
534
|
+
for (const match of plainUrls) {
|
|
535
|
+
const cleanUrl = match[0].replace(/[.,;:!?]+$/, "");
|
|
536
|
+
if (!seen.has(cleanUrl)) {
|
|
537
|
+
seen.add(cleanUrl);
|
|
538
|
+
links.push({ url: cleanUrl });
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
return links;
|
|
543
|
+
}
|
|
544
|
+
const buildDummyAskAiHit = (query, messages, chatId) => {
|
|
545
|
+
const textPart = messages[0].parts.find((part) => part.type === "text");
|
|
546
|
+
const sanitizedText = (textPart === null || textPart === void 0 ? void 0 : textPart.text) ? sanitizeUserInput(textPart.text) : "";
|
|
547
|
+
return {
|
|
548
|
+
query,
|
|
549
|
+
objectID: sanitizedText,
|
|
550
|
+
chatId,
|
|
551
|
+
messages,
|
|
552
|
+
type: "askAI",
|
|
553
|
+
anchor: "stored",
|
|
554
|
+
content: null,
|
|
555
|
+
hierarchy: {
|
|
556
|
+
lvl0: "askAI",
|
|
557
|
+
lvl1: sanitizedText,
|
|
558
|
+
lvl2: (/* @__PURE__ */ new Date()).toISOString(),
|
|
559
|
+
lvl3: null,
|
|
560
|
+
lvl4: null,
|
|
561
|
+
lvl5: null,
|
|
562
|
+
lvl6: null
|
|
563
|
+
},
|
|
564
|
+
url: "",
|
|
565
|
+
url_without_anchor: ""
|
|
566
|
+
};
|
|
567
|
+
};
|
|
568
|
+
const getMessageContent = (message) => message === null || message === void 0 ? void 0 : message.parts.find((part) => part.type === "text");
|
|
569
|
+
/** Helper function to check if error is a thread depth error (AI-217). */
|
|
570
|
+
function isThreadDepthError(error) {
|
|
571
|
+
var _error$message;
|
|
572
|
+
if (!error) return false;
|
|
573
|
+
return ((_error$message = error.message) === null || _error$message === void 0 ? void 0 : _error$message.includes("AI-217")) || false;
|
|
574
|
+
}
|
|
575
|
+
const EMPTY_TOOLS = Object.freeze({});
|
|
576
|
+
function isAIToolPart(part) {
|
|
577
|
+
return part.type.startsWith("tool-");
|
|
578
|
+
}
|
|
579
|
+
function isSearchToolPart(part) {
|
|
580
|
+
return part.type === "tool-searchIndex" || part.type === "tool-algolia_search_index" || part.type.startsWith("tool-algolia_search_index_");
|
|
581
|
+
}
|
|
582
|
+
function isSearchIndexOutputPart(part) {
|
|
583
|
+
return part.type === "tool-searchIndex" && part.state === "output-available";
|
|
584
|
+
}
|
|
585
|
+
function isSearchOutputPart(part) {
|
|
586
|
+
return isAIToolPart(part) && isSearchToolPart(part) && part.state === "output-available";
|
|
587
|
+
}
|
|
588
|
+
function sanitizeMessagesForRequest(messages) {
|
|
589
|
+
var _sanitizedMessages;
|
|
590
|
+
let sanitizedMessages;
|
|
591
|
+
messages.forEach((message, index) => {
|
|
592
|
+
const parts = message.parts.filter((part) => !part.type.startsWith("data-"));
|
|
593
|
+
if (parts.length === message.parts.length) {
|
|
594
|
+
sanitizedMessages === null || sanitizedMessages === void 0 || sanitizedMessages.push(message);
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
if (!sanitizedMessages) sanitizedMessages = messages.slice(0, index);
|
|
598
|
+
sanitizedMessages.push(_objectSpread2(_objectSpread2({}, message), {}, { parts }));
|
|
599
|
+
});
|
|
600
|
+
return (_sanitizedMessages = sanitizedMessages) !== null && _sanitizedMessages !== void 0 ? _sanitizedMessages : messages;
|
|
601
|
+
}
|
|
602
|
+
function getAgentPromptSuggestions(parts) {
|
|
603
|
+
const suggestionsPart = parts.find((part) => part.type === "data-suggestions");
|
|
604
|
+
if (!suggestionsPart) return [];
|
|
605
|
+
return suggestionsPart.data.suggestions;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
//#endregion
|
|
609
|
+
//#region src/components/ui/ToolState.tsx
|
|
610
|
+
function ToolState({ icon, shimmer = false, children, variant }) {
|
|
611
|
+
const className = `DocSearch-AskAiScreen-MessageContent-Tool Tool--${variant}${shimmer ? " shimmer" : ""}`;
|
|
612
|
+
return /* @__PURE__ */ React.createElement("div", { className }, icon, children);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
//#endregion
|
|
616
|
+
//#region src/components/ToolCall.tsx
|
|
617
|
+
function SearchTool({ part, translations, onSearchQueryClick }) {
|
|
618
|
+
const { searchingText, preToolCallText, toolCallResultText } = translations;
|
|
619
|
+
switch (part.state) {
|
|
620
|
+
case "input-streaming": return /* @__PURE__ */ React.createElement(ToolState, {
|
|
621
|
+
shimmer: true,
|
|
622
|
+
icon: /* @__PURE__ */ React.createElement(LoadingIcon, { className: "DocSearch-AskAiScreen-SmallerLoadingIcon" }),
|
|
623
|
+
variant: "PartialCall"
|
|
624
|
+
}, /* @__PURE__ */ React.createElement("span", null, searchingText));
|
|
625
|
+
case "input-available": return /* @__PURE__ */ React.createElement(ToolState, {
|
|
626
|
+
shimmer: true,
|
|
627
|
+
icon: /* @__PURE__ */ React.createElement(LoadingIcon, { className: "DocSearch-AskAiScreen-SmallerLoadingIcon" }),
|
|
628
|
+
variant: "Call"
|
|
629
|
+
}, /* @__PURE__ */ React.createElement("span", null, preToolCallText, " ", `"${part.input.query || ""}" ...`));
|
|
630
|
+
case "output-available": {
|
|
631
|
+
const query = part.type === "tool-searchIndex" ? part.output.query : part.input.query;
|
|
632
|
+
return /* @__PURE__ */ React.createElement(ToolState, {
|
|
633
|
+
icon: /* @__PURE__ */ React.createElement(SearchIcon, null),
|
|
634
|
+
variant: "Result"
|
|
635
|
+
}, /* @__PURE__ */ React.createElement("span", null, toolCallResultText, " ", onSearchQueryClick ? /* @__PURE__ */ React.createElement("span", {
|
|
636
|
+
role: "button",
|
|
637
|
+
tabIndex: 0,
|
|
638
|
+
className: "DocSearch-AskAiScreen-MessageContent-Tool-Query",
|
|
639
|
+
onKeyDown: (e) => {
|
|
640
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
641
|
+
e.preventDefault();
|
|
642
|
+
onSearchQueryClick(query || "");
|
|
643
|
+
}
|
|
644
|
+
},
|
|
645
|
+
onClick: () => onSearchQueryClick(query || "")
|
|
646
|
+
}, " ", "\"", query || "", "\"") : /* @__PURE__ */ React.createElement("span", { className: "DocSearch-AskAiScreen-MessageContent-Tool-Query" }, " ", "\"", query || "", "\"")));
|
|
647
|
+
}
|
|
648
|
+
default: return null;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
function CustomTool({ tool, part }) {
|
|
652
|
+
const toolOutput = useMemo(() => {
|
|
653
|
+
if (part.state !== "output-available") return null;
|
|
654
|
+
return tool.render({ message: {
|
|
655
|
+
input: part.input,
|
|
656
|
+
output: part.output
|
|
657
|
+
} });
|
|
658
|
+
}, [
|
|
659
|
+
part.input,
|
|
660
|
+
part.output,
|
|
661
|
+
tool,
|
|
662
|
+
part.state
|
|
663
|
+
]);
|
|
664
|
+
if (part.state === "output-error") return null;
|
|
665
|
+
if (part.state !== "output-available") {
|
|
666
|
+
const { callingToolText = "Loading tool" } = tool.translations || {};
|
|
667
|
+
return /* @__PURE__ */ React.createElement(ToolState, {
|
|
668
|
+
shimmer: true,
|
|
669
|
+
variant: "PartialCall",
|
|
670
|
+
icon: /* @__PURE__ */ React.createElement(ToolIcon, null)
|
|
671
|
+
}, /* @__PURE__ */ React.createElement("span", null, callingToolText));
|
|
672
|
+
}
|
|
673
|
+
if (!toolOutput) return null;
|
|
674
|
+
return /* @__PURE__ */ React.createElement(ToolState, {
|
|
675
|
+
icon: /* @__PURE__ */ React.createElement(ToolIcon, null),
|
|
676
|
+
variant: "Result"
|
|
677
|
+
}, /* @__PURE__ */ React.createElement("span", null, toolOutput));
|
|
678
|
+
}
|
|
679
|
+
function MemoryTool({ part, translations }) {
|
|
680
|
+
const { savedMemoryToolResultText, memoryToolResultText } = translations;
|
|
681
|
+
if (part.state === "output-error") return null;
|
|
682
|
+
if (part.type === "tool-algolia_memorize") return /* @__PURE__ */ React.createElement(ToolState, {
|
|
683
|
+
variant: "Result",
|
|
684
|
+
icon: /* @__PURE__ */ React.createElement(MemoryIcon, null)
|
|
685
|
+
}, savedMemoryToolResultText);
|
|
686
|
+
return /* @__PURE__ */ React.createElement(ToolState, {
|
|
687
|
+
variant: "Result",
|
|
688
|
+
icon: /* @__PURE__ */ React.createElement(MemoryIcon, null)
|
|
689
|
+
}, memoryToolResultText);
|
|
690
|
+
}
|
|
691
|
+
function isMemoryToolPart(part) {
|
|
692
|
+
return part.type === "tool-algolia_ponder" || part.type === "tool-algolia_memorize" || part.type === "tool-algolia_memory_search";
|
|
693
|
+
}
|
|
694
|
+
function ToolCall({ part, translations, tools, onSearchQueryClick, memoryEnabled = false }) {
|
|
695
|
+
const customTool = tools[part.type.replace("tool-", "")];
|
|
696
|
+
if (customTool) return /* @__PURE__ */ React.createElement(CustomTool, {
|
|
697
|
+
tool: customTool,
|
|
698
|
+
part
|
|
699
|
+
});
|
|
700
|
+
if (memoryEnabled && isMemoryToolPart(part)) return /* @__PURE__ */ React.createElement(MemoryTool, {
|
|
701
|
+
part,
|
|
702
|
+
translations
|
|
703
|
+
});
|
|
704
|
+
if (isSearchToolPart(part)) return /* @__PURE__ */ React.createElement(SearchTool, {
|
|
705
|
+
part,
|
|
706
|
+
translations,
|
|
707
|
+
onSearchQueryClick
|
|
708
|
+
});
|
|
709
|
+
return null;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
//#endregion
|
|
713
|
+
//#region src/MemoizedMarkdown.tsx
|
|
714
|
+
function escapeHtml(html) {
|
|
715
|
+
return html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
716
|
+
}
|
|
717
|
+
const renderer = new marked.Renderer();
|
|
718
|
+
renderer.code = ({ text, lang = "", escaped }) => {
|
|
719
|
+
const languageClass = lang ? `language-${lang}` : "";
|
|
720
|
+
const safeCode = escaped ? text : escapeHtml(text);
|
|
721
|
+
return `
|
|
722
|
+
<div class="DocSearch-CodeSnippet">
|
|
723
|
+
<button class="DocSearch-CodeSnippet-CopyButton" data-code="${encodeURIComponent(text)}" aria-label="copy code"><svg class="DocSearch-CodeSnippet-CopyIcon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect width="14" height="14" x="8" y="8" rx="2" ry="2" /><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" /></svg><svg class="DocSearch-CodeSnippet-CheckIcon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></svg><span class="DocSearch-CodeSnippet-CopyButton-Label"></span></button>
|
|
724
|
+
<pre><code class="${languageClass}">${safeCode}</code></pre>
|
|
725
|
+
</div>
|
|
726
|
+
`;
|
|
727
|
+
};
|
|
728
|
+
renderer.link = ({ href, title, text }) => {
|
|
729
|
+
const titleAttr = title ? ` title="${escapeHtml(title)}"` : "";
|
|
730
|
+
return `<a href="${href ? escapeHtml(href) : ""}"${titleAttr} target="_blank" rel="noopener noreferrer">${escapeHtml(text)}</a>`;
|
|
731
|
+
};
|
|
732
|
+
const MemoizedMarkdown = memo(({ content, copyButtonText, copyButtonCopiedText, isStreaming }) => {
|
|
733
|
+
const html = useMemo(() => marked.parse(content, {
|
|
734
|
+
gfm: true,
|
|
735
|
+
breaks: true,
|
|
736
|
+
renderer
|
|
737
|
+
}), [content]);
|
|
738
|
+
const containerRef = useRef(null);
|
|
739
|
+
useEffect(() => {
|
|
740
|
+
const container = containerRef.current;
|
|
741
|
+
if (!container) return;
|
|
742
|
+
Array.from(container.querySelectorAll(".DocSearch-CodeSnippet-CopyButton")).forEach((btn) => {
|
|
743
|
+
const label = btn.querySelector(".DocSearch-CodeSnippet-CopyButton-Label");
|
|
744
|
+
if (label) label.textContent = copyButtonText;
|
|
745
|
+
btn.classList.remove("DocSearch-CodeSnippet-CopyButton--copied");
|
|
746
|
+
});
|
|
747
|
+
function handleClick(event) {
|
|
748
|
+
var _btn$getAttribute;
|
|
749
|
+
const btn = event.target.closest(".DocSearch-CodeSnippet-CopyButton");
|
|
750
|
+
if (!btn) return;
|
|
751
|
+
const encoded = (_btn$getAttribute = btn.getAttribute("data-code")) !== null && _btn$getAttribute !== void 0 ? _btn$getAttribute : "";
|
|
752
|
+
navigator.clipboard.writeText(decodeURIComponent(encoded)).catch(() => {});
|
|
753
|
+
const label = btn.querySelector(".DocSearch-CodeSnippet-CopyButton-Label");
|
|
754
|
+
if (!label) return;
|
|
755
|
+
btn.classList.add("DocSearch-CodeSnippet-CopyButton--copied");
|
|
756
|
+
const original = copyButtonText;
|
|
757
|
+
label.textContent = copyButtonCopiedText;
|
|
758
|
+
setTimeout(() => {
|
|
759
|
+
btn.classList.remove("DocSearch-CodeSnippet-CopyButton--copied");
|
|
760
|
+
label.textContent = original;
|
|
761
|
+
}, 1500);
|
|
762
|
+
}
|
|
763
|
+
container.addEventListener("click", handleClick);
|
|
764
|
+
return () => {
|
|
765
|
+
container.removeEventListener("click", handleClick);
|
|
766
|
+
};
|
|
767
|
+
}, [
|
|
768
|
+
html,
|
|
769
|
+
copyButtonText,
|
|
770
|
+
copyButtonCopiedText
|
|
771
|
+
]);
|
|
772
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
773
|
+
ref: containerRef,
|
|
774
|
+
className: `DocSearch-Markdown-Content ${isStreaming ? "DocSearch-Markdown-Content--streaming" : ""}`,
|
|
775
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
776
|
+
});
|
|
777
|
+
});
|
|
778
|
+
MemoizedMarkdown.displayName = "MemoizedMarkdown";
|
|
779
|
+
|
|
780
|
+
//#endregion
|
|
781
|
+
//#region src/utils/groupConsecutiveToolResults.ts
|
|
782
|
+
/**
|
|
783
|
+
* Extracts the search query from a search tool result part. `searchIndex`
|
|
784
|
+
* exposes the query on its output, while the Algolia MCP search tools expose it
|
|
785
|
+
* on their input.
|
|
786
|
+
*/
|
|
787
|
+
function getSearchQuery(part) {
|
|
788
|
+
var _part$output, _part$input;
|
|
789
|
+
const query = isSearchIndexOutputPart(part) ? (_part$output = part.output) === null || _part$output === void 0 ? void 0 : _part$output.query : (_part$input = part.input) === null || _part$input === void 0 ? void 0 : _part$input.query;
|
|
790
|
+
return (query !== null && query !== void 0 ? query : "").trim();
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* Groups consecutive search tool invocation result parts together. Both the
|
|
794
|
+
* `searchIndex` tool and the Algolia MCP search tools (`algolia_search_index`
|
|
795
|
+
* and `algolia_search_index_*`) are aggregated. Empty or falsy queries are
|
|
796
|
+
* ignored.
|
|
797
|
+
*/
|
|
798
|
+
function groupConsecutiveToolResults(parts) {
|
|
799
|
+
const aggregatedParts = [];
|
|
800
|
+
for (let i = 0; i < parts.length; i++) {
|
|
801
|
+
const part = parts[i];
|
|
802
|
+
if (isSearchOutputPart(part)) {
|
|
803
|
+
const queries = [];
|
|
804
|
+
let singleQueryPart;
|
|
805
|
+
let j = i;
|
|
806
|
+
while (j < parts.length) {
|
|
807
|
+
const candidate = parts[j];
|
|
808
|
+
if (isSearchOutputPart(candidate)) {
|
|
809
|
+
const q = getSearchQuery(candidate);
|
|
810
|
+
if (q && q.length > 0) {
|
|
811
|
+
queries.push(q);
|
|
812
|
+
singleQueryPart = candidate;
|
|
813
|
+
}
|
|
814
|
+
j++;
|
|
815
|
+
} else break;
|
|
816
|
+
}
|
|
817
|
+
if (queries.length > 1) aggregatedParts.push({
|
|
818
|
+
type: "aggregated-tool-call",
|
|
819
|
+
queries
|
|
820
|
+
});
|
|
821
|
+
else if (queries.length === 1 && singleQueryPart) aggregatedParts.push(singleQueryPart);
|
|
822
|
+
i = j - 1;
|
|
823
|
+
} else aggregatedParts.push(part);
|
|
824
|
+
}
|
|
825
|
+
return aggregatedParts;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
//#endregion
|
|
829
|
+
//#region src/Menu.tsx
|
|
830
|
+
const _excluded$1 = [
|
|
831
|
+
"children",
|
|
832
|
+
"className",
|
|
833
|
+
"onClick"
|
|
834
|
+
];
|
|
835
|
+
const MenuContext = React.createContext({
|
|
836
|
+
open: false,
|
|
837
|
+
setOpen: (_open) => {}
|
|
838
|
+
});
|
|
839
|
+
function Menu({ children }) {
|
|
840
|
+
const [open, setOpen] = React.useState(false);
|
|
841
|
+
const menuRef = React.useRef(null);
|
|
842
|
+
React.useEffect(() => {
|
|
843
|
+
function close(e) {
|
|
844
|
+
var _menuRef$current;
|
|
845
|
+
if (!((_menuRef$current = menuRef.current) === null || _menuRef$current === void 0 ? void 0 : _menuRef$current.contains(e.target))) setOpen(false);
|
|
846
|
+
}
|
|
847
|
+
if (open) window.addEventListener("click", close);
|
|
848
|
+
return function removeListener() {
|
|
849
|
+
window.removeEventListener("click", close);
|
|
850
|
+
};
|
|
851
|
+
}, [open]);
|
|
852
|
+
return /* @__PURE__ */ React.createElement(MenuContext.Provider, { value: {
|
|
853
|
+
open,
|
|
854
|
+
setOpen
|
|
855
|
+
} }, /* @__PURE__ */ React.createElement("div", {
|
|
856
|
+
ref: menuRef,
|
|
857
|
+
className: "DocSearch-Menu"
|
|
858
|
+
}, children));
|
|
859
|
+
}
|
|
860
|
+
function MenuTrigger({ children, className = "", disabled }) {
|
|
861
|
+
const { open, setOpen } = React.useContext(MenuContext);
|
|
862
|
+
function toggleOpen() {
|
|
863
|
+
if (disabled) return;
|
|
864
|
+
setOpen(!open);
|
|
865
|
+
}
|
|
866
|
+
return /* @__PURE__ */ React.createElement("button", {
|
|
867
|
+
type: "button",
|
|
868
|
+
className: `DocSearch-Menu-trigger ${className}${disabled ? " disabled" : ""}`,
|
|
869
|
+
"aria-disabled": disabled,
|
|
870
|
+
onClick: () => toggleOpen()
|
|
871
|
+
}, children);
|
|
872
|
+
}
|
|
873
|
+
Menu.Trigger = MenuTrigger;
|
|
874
|
+
function MenuContent({ children }) {
|
|
875
|
+
const { open } = React.useContext(MenuContext);
|
|
876
|
+
return /* @__PURE__ */ React.createElement("div", { className: `DocSearch-Menu-content${open ? " open" : ""}` }, children);
|
|
877
|
+
}
|
|
878
|
+
Menu.Content = MenuContent;
|
|
879
|
+
function MenuItem(_ref) {
|
|
880
|
+
let { children, className = "", onClick } = _ref, props = _objectWithoutProperties(_ref, _excluded$1);
|
|
881
|
+
const { setOpen } = React.useContext(MenuContext);
|
|
882
|
+
const handleClick = (e) => {
|
|
883
|
+
if (onClick) {
|
|
884
|
+
onClick(e);
|
|
885
|
+
setOpen(false);
|
|
886
|
+
}
|
|
887
|
+
};
|
|
888
|
+
return /* @__PURE__ */ React.createElement("button", _objectSpread2({
|
|
889
|
+
type: "button",
|
|
890
|
+
className: `DocSearch-Menu-item ${className}`,
|
|
891
|
+
onClick: handleClick
|
|
892
|
+
}, props), children);
|
|
893
|
+
}
|
|
894
|
+
Menu.Item = MenuItem;
|
|
895
|
+
|
|
896
|
+
//#endregion
|
|
897
|
+
//#region src/askai.ts
|
|
898
|
+
const agentStudioBaseUrl = (appId) => `https://${appId}.algolia.net/agent-studio/1`;
|
|
899
|
+
const getAgentStudioErrorMessage = (error) => {
|
|
900
|
+
let errorMessage = error.message;
|
|
901
|
+
try {
|
|
902
|
+
const parsedError = JSON.parse(error.message);
|
|
903
|
+
if (parsedError.name === "ValidationError") {
|
|
904
|
+
const validationError = parsedError;
|
|
905
|
+
if (validationError.detail && validationError.detail.length > 0) {
|
|
906
|
+
const { msg, loc } = validationError.detail[0];
|
|
907
|
+
errorMessage = `${msg}: ${loc.at(-1)}`;
|
|
908
|
+
}
|
|
909
|
+
} else errorMessage = parsedError.message;
|
|
910
|
+
} catch (_unused) {}
|
|
911
|
+
return new Error(errorMessage);
|
|
912
|
+
};
|
|
913
|
+
const postAgentStudioFeedback = ({ agentId, vote, messageId, appId, apiKey, abortSignal, notes, tags }) => {
|
|
914
|
+
const headers = new Headers();
|
|
915
|
+
headers.set("x-algolia-application-id", appId);
|
|
916
|
+
headers.set("x-algolia-api-key", apiKey);
|
|
917
|
+
headers.set("content-type", "application/json");
|
|
918
|
+
const baseUrl = `${agentStudioBaseUrl(appId)}/feedback`;
|
|
919
|
+
return fetch(baseUrl, {
|
|
920
|
+
method: "POST",
|
|
921
|
+
body: JSON.stringify(_objectSpread2(_objectSpread2({
|
|
922
|
+
messageId,
|
|
923
|
+
agentId,
|
|
924
|
+
vote
|
|
925
|
+
}, notes ? { notes } : {}), tags && tags.length > 0 ? { tags } : {})),
|
|
926
|
+
headers,
|
|
927
|
+
signal: abortSignal
|
|
928
|
+
});
|
|
929
|
+
};
|
|
930
|
+
|
|
931
|
+
//#endregion
|
|
932
|
+
//#region src/useAskAi.ts
|
|
933
|
+
const _excluded = [
|
|
934
|
+
"id",
|
|
935
|
+
"messages",
|
|
936
|
+
"body"
|
|
937
|
+
];
|
|
938
|
+
const getAgentStudioTransport = ({ appId, apiKey, assistantId, searchParameters, userToken, indices }) => {
|
|
939
|
+
const algoliaParams = {};
|
|
940
|
+
if (searchParameters) algoliaParams.searchParameters = searchParameters;
|
|
941
|
+
if (indices && indices.length > 0) algoliaParams.indices = indices;
|
|
942
|
+
return new DefaultChatTransport({
|
|
943
|
+
api: `${agentStudioBaseUrl(appId)}/agents/${assistantId}/completions?stream=true&compatibilityMode=ai-sdk-5`,
|
|
944
|
+
headers: _objectSpread2({
|
|
945
|
+
"x-algolia-application-id": appId,
|
|
946
|
+
"x-algolia-api-key": apiKey
|
|
947
|
+
}, userToken ? { "x-algolia-secure-user-token": userToken } : {}),
|
|
948
|
+
body: { algolia: algoliaParams },
|
|
949
|
+
prepareSendMessagesRequest(_ref) {
|
|
950
|
+
let { id, messages, body } = _ref, rest = _objectWithoutProperties(_ref, _excluded);
|
|
951
|
+
const sanitizedMessages = sanitizeMessagesForRequest(messages);
|
|
952
|
+
return _objectSpread2(_objectSpread2({}, rest), {}, { body: _objectSpread2({
|
|
953
|
+
id,
|
|
954
|
+
messages: sanitizedMessages
|
|
955
|
+
}, body) });
|
|
956
|
+
}
|
|
957
|
+
});
|
|
958
|
+
};
|
|
959
|
+
const useAskAi = ({ assistantId, apiKey, appId, indexName, tools = EMPTY_TOOLS, searchParameters, memory, indices }) => {
|
|
960
|
+
const abortControllerRef = useRef(new AbortController());
|
|
961
|
+
const askAiTransport = useMemo(() => getAgentStudioTransport({
|
|
962
|
+
apiKey,
|
|
963
|
+
appId,
|
|
964
|
+
assistantId,
|
|
965
|
+
searchParameters,
|
|
966
|
+
userToken: memory === null || memory === void 0 ? void 0 : memory.userToken,
|
|
967
|
+
indices
|
|
968
|
+
}), [
|
|
969
|
+
apiKey,
|
|
970
|
+
appId,
|
|
971
|
+
assistantId,
|
|
972
|
+
searchParameters,
|
|
973
|
+
memory === null || memory === void 0 ? void 0 : memory.userToken,
|
|
974
|
+
indices
|
|
975
|
+
]);
|
|
976
|
+
const askAiTransportRef = useRef(askAiTransport);
|
|
977
|
+
askAiTransportRef.current = askAiTransport;
|
|
978
|
+
const toolsRef = useRef(tools);
|
|
979
|
+
toolsRef.current = tools;
|
|
980
|
+
const addToolOutputRef = useRef(null);
|
|
981
|
+
const handleToolCall = useCallback(({ toolCall }) => {
|
|
982
|
+
const tool = toolsRef.current[toolCall.toolName];
|
|
983
|
+
if (!(tool === null || tool === void 0 ? void 0 : tool.onToolCall)) return;
|
|
984
|
+
tool.onToolCall(_objectSpread2(_objectSpread2({}, toolCall), {}, { addToolOutput: async ({ output }) => {
|
|
985
|
+
if (!addToolOutputRef.current) return;
|
|
986
|
+
await addToolOutputRef.current({
|
|
987
|
+
output,
|
|
988
|
+
tool: toolCall.toolName,
|
|
989
|
+
toolCallId: toolCall.toolCallId
|
|
990
|
+
});
|
|
991
|
+
} }));
|
|
992
|
+
}, []);
|
|
993
|
+
const createChatInstance = useCallback((messages, id = generateId()) => new Chat({
|
|
994
|
+
id,
|
|
995
|
+
messages,
|
|
996
|
+
sendAutomaticallyWhen: lastAssistantMessageIsCompleteWithToolCalls,
|
|
997
|
+
transport: askAiTransportRef.current,
|
|
998
|
+
onToolCall: handleToolCall
|
|
999
|
+
}), [handleToolCall]);
|
|
1000
|
+
const [chatInstance, setChatInstance] = useState(() => createChatInstance());
|
|
1001
|
+
const chatInstanceRef = useRef(chatInstance);
|
|
1002
|
+
chatInstanceRef.current = chatInstance;
|
|
1003
|
+
const { messages, status, setMessages, error, stop, addToolOutput } = useChat({ chat: chatInstance });
|
|
1004
|
+
useEffect(() => {
|
|
1005
|
+
addToolOutputRef.current = addToolOutput;
|
|
1006
|
+
}, [addToolOutput]);
|
|
1007
|
+
const conversations = useRef(createStoredConversations({
|
|
1008
|
+
key: `__DOCSEARCH_ASKAI_CONVERSATIONS__${indexName}`,
|
|
1009
|
+
limit: 10
|
|
1010
|
+
})).current;
|
|
1011
|
+
const sendFeedback = useCallback(async (messageId, { thumbs, tags, notes }) => {
|
|
1012
|
+
var _conversations$addFee;
|
|
1013
|
+
if (!assistantId) return;
|
|
1014
|
+
if ((await postAgentStudioFeedback({
|
|
1015
|
+
agentId: assistantId,
|
|
1016
|
+
vote: thumbs,
|
|
1017
|
+
messageId,
|
|
1018
|
+
appId,
|
|
1019
|
+
apiKey,
|
|
1020
|
+
abortSignal: abortControllerRef.current.signal,
|
|
1021
|
+
notes,
|
|
1022
|
+
tags
|
|
1023
|
+
})).status >= 300) throw new Error("Failed, try again later.");
|
|
1024
|
+
(_conversations$addFee = conversations.addFeedback) === null || _conversations$addFee === void 0 || _conversations$addFee.call(conversations, messageId, thumbs === 1 ? "like" : "dislike", {
|
|
1025
|
+
tags,
|
|
1026
|
+
notes
|
|
1027
|
+
});
|
|
1028
|
+
}, [
|
|
1029
|
+
assistantId,
|
|
1030
|
+
appId,
|
|
1031
|
+
apiKey,
|
|
1032
|
+
conversations
|
|
1033
|
+
]);
|
|
1034
|
+
const onStopStreaming = useCallback(async () => {
|
|
1035
|
+
abortControllerRef.current.abort();
|
|
1036
|
+
await stop();
|
|
1037
|
+
}, [stop]);
|
|
1038
|
+
const exchanges = useMemo(() => {
|
|
1039
|
+
const grouped = [];
|
|
1040
|
+
for (let i = 0; i < messages.length; i++) if (messages[i].role === "user") {
|
|
1041
|
+
var _messages;
|
|
1042
|
+
const userMessage = messages[i];
|
|
1043
|
+
const assistantMessage = ((_messages = messages[i + 1]) === null || _messages === void 0 ? void 0 : _messages.role) === "assistant" ? messages[i + 1] : null;
|
|
1044
|
+
grouped.push({
|
|
1045
|
+
id: userMessage.id,
|
|
1046
|
+
userMessage,
|
|
1047
|
+
assistantMessage
|
|
1048
|
+
});
|
|
1049
|
+
if (assistantMessage) i++;
|
|
1050
|
+
}
|
|
1051
|
+
return grouped;
|
|
1052
|
+
}, [messages]);
|
|
1053
|
+
const isStreaming = status === "streaming" || status === "submitted";
|
|
1054
|
+
const askAiError = useMemo(() => {
|
|
1055
|
+
if (!error) return void 0;
|
|
1056
|
+
return getAgentStudioErrorMessage(error);
|
|
1057
|
+
}, [error]);
|
|
1058
|
+
const updateChatInstance = useCallback((restored, existingConversationId) => {
|
|
1059
|
+
const newChatInstance = createChatInstance(restored, existingConversationId);
|
|
1060
|
+
chatInstanceRef.current = newChatInstance;
|
|
1061
|
+
setChatInstance(newChatInstance);
|
|
1062
|
+
}, [createChatInstance]);
|
|
1063
|
+
const startNewConversation = useCallback(() => {
|
|
1064
|
+
updateChatInstance();
|
|
1065
|
+
}, [updateChatInstance]);
|
|
1066
|
+
const restoreConversation = useCallback((restored, existingConversationId) => {
|
|
1067
|
+
updateChatInstance(restored, existingConversationId);
|
|
1068
|
+
}, [updateChatInstance]);
|
|
1069
|
+
const sendMessageSafe = useCallback((...args) => chatInstanceRef.current.sendMessage(...args), []);
|
|
1070
|
+
return {
|
|
1071
|
+
chatId: chatInstance.id,
|
|
1072
|
+
messages,
|
|
1073
|
+
sendMessage: sendMessageSafe,
|
|
1074
|
+
status,
|
|
1075
|
+
setMessages,
|
|
1076
|
+
askAiError,
|
|
1077
|
+
stopAskAiStreaming: onStopStreaming,
|
|
1078
|
+
isStreaming,
|
|
1079
|
+
exchanges,
|
|
1080
|
+
conversations,
|
|
1081
|
+
sendFeedback,
|
|
1082
|
+
startNewConversation,
|
|
1083
|
+
restoreConversation
|
|
1084
|
+
};
|
|
1085
|
+
};
|
|
1086
|
+
|
|
1087
|
+
//#endregion
|
|
1088
|
+
//#region src/useSuggestedQuestions.ts
|
|
1089
|
+
const useSuggestedQuestions = ({ assistantId, searchClient, suggestedQuestionsEnabled = false }) => {
|
|
1090
|
+
const [suggestedQuestions, setSuggestedQuestions] = useState([]);
|
|
1091
|
+
useEffect(() => {
|
|
1092
|
+
const getSuggestedQuestions = async () => {
|
|
1093
|
+
const { results } = await searchClient.search({ requests: [{
|
|
1094
|
+
indexName: SUGGESTED_QUETIONS_INDEX_NAME,
|
|
1095
|
+
filters: `state:published AND assistantId:${assistantId}`,
|
|
1096
|
+
hitsPerPage: 3
|
|
1097
|
+
}] });
|
|
1098
|
+
const result = results[0];
|
|
1099
|
+
setSuggestedQuestions(result.hits);
|
|
1100
|
+
};
|
|
1101
|
+
if (suggestedQuestionsEnabled && assistantId && assistantId !== "") getSuggestedQuestions();
|
|
1102
|
+
}, [
|
|
1103
|
+
suggestedQuestionsEnabled,
|
|
1104
|
+
assistantId,
|
|
1105
|
+
searchClient
|
|
1106
|
+
]);
|
|
1107
|
+
return suggestedQuestions;
|
|
1108
|
+
};
|
|
1109
|
+
|
|
1110
|
+
//#endregion
|
|
1111
|
+
export { AlertIcon as S, BackIcon as _, MemoizedMarkdown as a, MoreVerticalIcon as b, buildDummyAskAiHit as c, getMessageContent as d, isAIToolPart as f, ConversationPromptSuggestions as g, FeedbackActions as h, groupConsecutiveToolResults as i, extractLinksFromMessage as l, SourcesPanel as m, useAskAi as n, ToolCall as o, isThreadDepthError as p, Menu as r, EMPTY_TOOLS as s, useSuggestedQuestions as t, getAgentPromptSuggestions as u, NewConversationIcon as v, StopIcon as x, ConversationHistoryIcon as y };
|
|
1112
|
+
//# sourceMappingURL=useSuggestedQuestions-D2TGVPsI.js.map
|