@mitodl/smoot-design 0.0.0-a2e4e1e → 0.0.0-bafccd3
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 +4 -0
- package/dist/bundles/{remoteTutorDrawer.es.js → aiDrawerManager.es.js} +17612 -17240
- package/dist/bundles/aiDrawerManager.es.js.map +1 -0
- package/dist/bundles/aiDrawerManager.umd.js +245 -0
- package/dist/bundles/aiDrawerManager.umd.js.map +1 -0
- package/dist/cjs/VERSION.d.ts +12 -0
- package/dist/cjs/VERSION.js +15 -0
- package/dist/cjs/ai.d.ts +3 -3
- package/dist/cjs/ai.js +5 -1
- package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.d.ts → AiDrawer/AiDrawer.d.ts} +11 -13
- package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.js → AiDrawer/AiDrawer.js} +27 -41
- package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.stories.d.ts → AiDrawer/AiDrawer.stories.d.ts} +4 -3
- package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.stories.js → AiDrawer/AiDrawer.stories.js} +32 -51
- package/dist/cjs/bundles/AiDrawer/AiDrawerManager.d.ts +12 -0
- package/dist/cjs/bundles/AiDrawer/AiDrawerManager.js +51 -0
- package/dist/cjs/bundles/AiDrawer/AiDrawerManager.stories.d.ts +6 -0
- package/dist/cjs/bundles/AiDrawer/AiDrawerManager.stories.js +267 -0
- package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.test.js → AiDrawer/AiDrawerManager.test.js} +22 -18
- package/dist/cjs/bundles/{RemoteTutorDrawer → AiDrawer}/FlashcardsScreen.js +1 -1
- package/dist/cjs/bundles/aiDrawerManager.d.ts +6 -0
- package/dist/cjs/bundles/aiDrawerManager.js +44 -0
- package/dist/cjs/components/AiChat/AiChat.d.ts +3 -3
- package/dist/cjs/components/AiChat/AiChat.js +65 -53
- package/dist/cjs/components/AiChat/AiChat.stories.d.ts +0 -4
- package/dist/cjs/components/AiChat/AiChat.stories.js +5 -54
- package/dist/cjs/components/AiChat/AiChatContext.d.ts +26 -0
- package/dist/cjs/components/AiChat/AiChatContext.js +106 -0
- package/dist/cjs/components/AiChat/AiChatContext.stories.d.ts +14 -0
- package/dist/cjs/components/AiChat/AiChatContext.stories.js +75 -0
- package/dist/cjs/components/AiChat/AiChatMarkdown.stories.d.ts +15 -0
- package/dist/cjs/components/AiChat/AiChatMarkdown.stories.js +282 -0
- package/dist/cjs/components/AiChat/Markdown.d.ts +7 -0
- package/dist/cjs/components/AiChat/Markdown.js +14 -0
- package/dist/cjs/components/AiChat/test-utils/api.js +40 -1
- package/dist/cjs/components/AiChat/types.d.ts +25 -11
- package/dist/cjs/components/AiChat/types.js +1 -1
- package/dist/cjs/components/AiChat/utils.d.ts +1 -1
- package/dist/cjs/components/AiChat/utils.js +1 -1
- package/dist/cjs/components/LinkAdapter/LinkAdapter.js +1 -1
- package/dist/cjs/components/TabButtons/TabButtonList.js +1 -1
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/utils/retryingFetch.d.ts +19 -0
- package/dist/cjs/utils/retryingFetch.js +98 -0
- package/dist/cjs/utils/retryingFetch.test.js +48 -0
- package/dist/esm/VERSION.d.ts +12 -0
- package/dist/esm/VERSION.js +12 -0
- package/dist/esm/ai.d.ts +3 -3
- package/dist/esm/ai.js +2 -1
- package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.d.ts → AiDrawer/AiDrawer.d.ts} +11 -13
- package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.js → AiDrawer/AiDrawer.js} +26 -40
- package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.stories.d.ts → AiDrawer/AiDrawer.stories.d.ts} +4 -3
- package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.stories.js → AiDrawer/AiDrawer.stories.js} +31 -50
- package/dist/esm/bundles/AiDrawer/AiDrawerManager.d.ts +12 -0
- package/dist/esm/bundles/AiDrawer/AiDrawerManager.js +48 -0
- package/dist/esm/bundles/AiDrawer/AiDrawerManager.stories.d.ts +6 -0
- package/dist/esm/bundles/AiDrawer/AiDrawerManager.stories.js +264 -0
- package/dist/esm/bundles/AiDrawer/AiDrawerManager.test.d.ts +1 -0
- package/dist/esm/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.test.js → AiDrawer/AiDrawerManager.test.js} +22 -18
- package/dist/esm/bundles/{RemoteTutorDrawer → AiDrawer}/FlashcardsScreen.js +1 -1
- package/dist/esm/bundles/aiDrawerManager.d.ts +6 -0
- package/dist/esm/bundles/aiDrawerManager.js +41 -0
- package/dist/esm/components/AiChat/AiChat.d.ts +3 -3
- package/dist/esm/components/AiChat/AiChat.js +65 -54
- package/dist/esm/components/AiChat/AiChat.stories.d.ts +0 -4
- package/dist/esm/components/AiChat/AiChat.stories.js +4 -53
- package/dist/esm/components/AiChat/AiChatContext.d.ts +26 -0
- package/dist/esm/components/AiChat/AiChatContext.js +102 -0
- package/dist/esm/components/AiChat/AiChatContext.stories.d.ts +14 -0
- package/dist/esm/components/AiChat/AiChatContext.stories.js +72 -0
- package/dist/esm/components/AiChat/AiChatMarkdown.stories.d.ts +15 -0
- package/dist/esm/components/AiChat/AiChatMarkdown.stories.js +279 -0
- package/dist/esm/components/AiChat/Markdown.d.ts +7 -0
- package/dist/esm/components/AiChat/Markdown.js +12 -0
- package/dist/esm/components/AiChat/test-utils/api.js +40 -1
- package/dist/esm/components/AiChat/types.d.ts +25 -11
- package/dist/esm/components/AiChat/types.js +1 -1
- package/dist/esm/components/AiChat/utils.d.ts +1 -1
- package/dist/esm/components/AiChat/utils.js +1 -1
- package/dist/esm/components/LinkAdapter/LinkAdapter.js +1 -1
- package/dist/esm/components/TabButtons/TabButtonList.js +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/utils/retryingFetch.d.ts +19 -0
- package/dist/esm/utils/retryingFetch.js +96 -0
- package/dist/esm/utils/retryingFetch.test.d.ts +1 -0
- package/dist/esm/utils/retryingFetch.test.js +46 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -7
- package/dist/bundles/remoteTutorDrawer.umd.js +0 -207
- package/dist/cjs/bundles/remoteTutorDrawer.d.ts +0 -7
- package/dist/cjs/bundles/remoteTutorDrawer.js +0 -40
- package/dist/esm/bundles/remoteTutorDrawer.d.ts +0 -7
- package/dist/esm/bundles/remoteTutorDrawer.js +0 -37
- /package/dist/cjs/bundles/{RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts → AiDrawer/AiDrawerManager.test.d.ts} +0 -0
- /package/dist/cjs/bundles/{RemoteTutorDrawer → AiDrawer}/FlashcardsScreen.d.ts +0 -0
- /package/dist/{esm/bundles/RemoteTutorDrawer/RemoteTutorDrawer.test.d.ts → cjs/utils/retryingFetch.test.d.ts} +0 -0
- /package/dist/esm/bundles/{RemoteTutorDrawer → AiDrawer}/FlashcardsScreen.d.ts +0 -0
|
@@ -11,7 +11,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
11
11
|
return t;
|
|
12
12
|
};
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.AiChat = void 0;
|
|
14
|
+
exports.AiChat = exports.AiChatDisplay = void 0;
|
|
15
15
|
const React = require("react");
|
|
16
16
|
const react_1 = require("react");
|
|
17
17
|
const styled_1 = require("@emotion/styled");
|
|
@@ -20,14 +20,14 @@ const classnames_1 = require("classnames");
|
|
|
20
20
|
const react_2 = require("@remixicon/react");
|
|
21
21
|
const Input_1 = require("../Input/Input");
|
|
22
22
|
const EntryScreen_1 = require("./EntryScreen");
|
|
23
|
-
const react_markdown_1 = require("react-markdown");
|
|
24
23
|
const ScrollSnap_1 = require("../ScrollSnap/ScrollSnap");
|
|
25
24
|
const SrAnnouncer_1 = require("../SrAnnouncer/SrAnnouncer");
|
|
26
25
|
const VisuallyHidden_1 = require("../VisuallyHidden/VisuallyHidden");
|
|
27
26
|
const Alert_1 = require("../Alert/Alert");
|
|
28
27
|
const ChatTitle_1 = require("./ChatTitle");
|
|
29
|
-
const
|
|
28
|
+
const AiChatContext_1 = require("./AiChatContext");
|
|
30
29
|
const useScrollSnap_1 = require("../ScrollSnap/useScrollSnap");
|
|
30
|
+
const Markdown_1 = require("./Markdown");
|
|
31
31
|
const classes = {
|
|
32
32
|
root: "MitAiChat--root",
|
|
33
33
|
title: "MitAiChat--title",
|
|
@@ -65,6 +65,9 @@ const MessagesContainer = (0, styled_1.default)(ScrollSnap_1.ScrollSnap)(({ exte
|
|
|
65
65
|
padding: "14px 0",
|
|
66
66
|
overflow: externalScroll ? "visible" : "auto",
|
|
67
67
|
gap: "16px",
|
|
68
|
+
[`> .${classes.messageRowAssistant}:first-child`]: {
|
|
69
|
+
marginTop: "16px",
|
|
70
|
+
},
|
|
68
71
|
}));
|
|
69
72
|
const MessageRow = styled_1.default.div({
|
|
70
73
|
display: "flex",
|
|
@@ -78,25 +81,45 @@ const MessageRow = styled_1.default.div({
|
|
|
78
81
|
},
|
|
79
82
|
position: "relative",
|
|
80
83
|
});
|
|
81
|
-
const Message = styled_1.default.div(({ theme }) => (Object.assign(Object.assign({ color: theme.custom.colors.darkGray2, backgroundColor: theme.custom.colors.white
|
|
84
|
+
const Message = styled_1.default.div(({ theme }) => (Object.assign(Object.assign({ color: theme.custom.colors.darkGray2, backgroundColor: theme.custom.colors.white }, theme.typography.body2), { "p:first-of-type": {
|
|
82
85
|
marginTop: 0,
|
|
83
86
|
}, "p:last-of-type": {
|
|
84
87
|
marginBottom: 0,
|
|
85
|
-
}, "ol,
|
|
88
|
+
}, "ol,ul": {
|
|
86
89
|
paddingInlineStart: "16px",
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
margin: "12px 0 12px 4px",
|
|
91
|
+
}, "ol > li, ul > li": {
|
|
92
|
+
margin: "12px 0",
|
|
93
|
+
"ol,ul": {
|
|
94
|
+
margin: "12px 0 12px 4px",
|
|
90
95
|
},
|
|
91
96
|
li: {
|
|
92
|
-
margin: "
|
|
97
|
+
margin: "6px 0",
|
|
98
|
+
},
|
|
99
|
+
}, ul: {
|
|
100
|
+
paddingInlineStart: 0,
|
|
101
|
+
"> li": {
|
|
102
|
+
listStyleType: "none",
|
|
103
|
+
position: "relative",
|
|
104
|
+
"&::before": {
|
|
105
|
+
content: '"–"',
|
|
106
|
+
position: "absolute",
|
|
107
|
+
left: 0,
|
|
108
|
+
color: "#888",
|
|
109
|
+
marginRight: "8px",
|
|
110
|
+
},
|
|
111
|
+
paddingLeft: "16px",
|
|
112
|
+
},
|
|
113
|
+
}, "ol + ul": {
|
|
114
|
+
marginLeft: "24px",
|
|
115
|
+
li: {
|
|
116
|
+
margin: "6px 0",
|
|
93
117
|
},
|
|
94
118
|
}, a: {
|
|
95
119
|
color: theme.custom.colors.red,
|
|
96
120
|
fontWeight: "normal",
|
|
97
|
-
}, borderRadius: "12px", [`.${classes.
|
|
98
|
-
padding: "12px 16px
|
|
99
|
-
}, [`.${classes.messageRowUser} &`]: {
|
|
121
|
+
}, borderRadius: "12px", [`.${classes.messageRowUser} &`]: {
|
|
122
|
+
padding: "12px 16px",
|
|
100
123
|
borderRadius: "8px 0px 8px 8px",
|
|
101
124
|
backgroundColor: theme.custom.colors.lightGray1,
|
|
102
125
|
} })));
|
|
@@ -131,47 +154,32 @@ const Disclaimer = (0, styled_1.default)(Typography_1.default)(({ theme }) => ({
|
|
|
131
154
|
marginTop: "16px",
|
|
132
155
|
textAlign: "center",
|
|
133
156
|
}));
|
|
134
|
-
const
|
|
157
|
+
const AiChatDisplay = (_a) => {
|
|
135
158
|
var _b, _c;
|
|
136
|
-
var {
|
|
159
|
+
var { conversationStarters, askTimTitle, entryScreenEnabled = true, entryScreenTitle, srLoadingMessages, placeholder = "", className, scrollElement, ref, useMathJax = false } = _a, others = __rest(_a, ["conversationStarters", "askTimTitle", "entryScreenEnabled", "entryScreenTitle", "srLoadingMessages", "placeholder", "className", "scrollElement", "ref", "useMathJax"]) // Could contain data attributes
|
|
137
160
|
;
|
|
138
161
|
const containerRef = (0, react_1.useRef)(null);
|
|
139
162
|
const messagesContainerRef = (0, react_1.useRef)(null);
|
|
140
|
-
const [showEntryScreen, setShowEntryScreen] = (0, react_1.useState)(entryScreenEnabled);
|
|
141
163
|
const chatScreenRef = (0, react_1.useRef)(null);
|
|
142
|
-
const [initialMessages, setInitialMessages] = (0, react_1.useState)();
|
|
143
164
|
const promptInputRef = (0, react_1.useRef)(null);
|
|
144
|
-
const { messages
|
|
145
|
-
initialMessages,
|
|
146
|
-
id: chatId,
|
|
147
|
-
});
|
|
165
|
+
const { messages, input, handleInputChange, handleSubmit, append, isLoading, stop, error, initialMessages, status, } = (0, AiChatContext_1.useAiChat)();
|
|
148
166
|
(0, useScrollSnap_1.useScrollSnap)({
|
|
149
167
|
scrollElement: scrollElement || messagesContainerRef.current,
|
|
150
168
|
contentElement: scrollElement ? messagesContainerRef.current : null,
|
|
151
169
|
threshold: 200,
|
|
152
170
|
});
|
|
153
|
-
(0, react_1.
|
|
154
|
-
if (_initialMessages) {
|
|
155
|
-
const prefix = Math.random().toString().slice(2);
|
|
156
|
-
setInitialMessages(_initialMessages.map((m, i) => (Object.assign(Object.assign({}, m), { id: `initial-${prefix}-${i}` }))));
|
|
157
|
-
}
|
|
158
|
-
}, [_initialMessages]);
|
|
171
|
+
const [showEntryScreen, setShowEntryScreen] = (0, react_1.useState)(entryScreenEnabled);
|
|
159
172
|
(0, react_1.useEffect)(() => {
|
|
160
173
|
var _a, _b;
|
|
161
174
|
if (!showEntryScreen) {
|
|
162
175
|
(_b = (_a = promptInputRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("input")) === null || _b === void 0 ? void 0 : _b.focus();
|
|
163
176
|
}
|
|
164
177
|
}, [showEntryScreen]);
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
return Object.assign(Object.assign({}, m), { content });
|
|
171
|
-
}
|
|
172
|
-
return m;
|
|
173
|
-
});
|
|
174
|
-
}, [parseContent, unparsed, initialMessages]);
|
|
178
|
+
(0, react_1.useEffect)(() => {
|
|
179
|
+
if (messages.some((m) => m.role === "user" || ["submitted", "streaming"].includes(status))) {
|
|
180
|
+
setShowEntryScreen(false);
|
|
181
|
+
}
|
|
182
|
+
}, [messages, status]);
|
|
175
183
|
const showStarters = messages.length === ((initialMessages === null || initialMessages === void 0 ? void 0 : initialMessages.length) || 0);
|
|
176
184
|
const waiting = !showStarters && !error && ((_b = messages[messages.length - 1]) === null || _b === void 0 ? void 0 : _b.role) === "user";
|
|
177
185
|
const stoppable = isLoading && ((_c = messages[messages.length - 1]) === null || _c === void 0 ? void 0 : _c.role) !== "user";
|
|
@@ -184,16 +192,7 @@ const AiChat = (_a) => {
|
|
|
184
192
|
};
|
|
185
193
|
const lastMsg = messages[messages.length - 1];
|
|
186
194
|
const externalScroll = !!scrollElement;
|
|
187
|
-
return (React.createElement(Container, { className: className, ref: containerRef,
|
|
188
|
-
/**
|
|
189
|
-
* Changing the `useChat` chatId seems to persist some state between
|
|
190
|
-
* hook calls. This can cause strange effects like loading API responses
|
|
191
|
-
* for previous chatId into new chatId.
|
|
192
|
-
*
|
|
193
|
-
* To avoid this, let's change the key, this will force React to make a new component
|
|
194
|
-
* not sharing any of the old state.
|
|
195
|
-
*/
|
|
196
|
-
key: chatId }, showEntryScreen ? (React.createElement(EntryScreen_1.EntryScreen, { className: classes.entryScreenContainer, title: entryScreenTitle, conversationStarters: conversationStarters, onPromptSubmit: (prompt) => {
|
|
195
|
+
return (React.createElement(Container, { className: className, ref: containerRef }, showEntryScreen ? (React.createElement(EntryScreen_1.EntryScreen, { className: classes.entryScreenContainer, title: entryScreenTitle, conversationStarters: conversationStarters, onPromptSubmit: (prompt) => {
|
|
197
196
|
if (prompt.trim() === "") {
|
|
198
197
|
return;
|
|
199
198
|
}
|
|
@@ -203,13 +202,20 @@ const AiChat = (_a) => {
|
|
|
203
202
|
React.createElement(ChatContainer, Object.assign({ className: (0, classnames_1.default)(className, classes.root), externalScroll: externalScroll }, others),
|
|
204
203
|
React.createElement(ChatTitle_1.ChatTitle, { askTimTitle: askTimTitle, externalScroll: externalScroll, className: (0, classnames_1.default)(className, classes.title) }),
|
|
205
204
|
React.createElement(MessagesContainer, { className: classes.messagesContainer, externalScroll: externalScroll, ref: messagesContainerRef },
|
|
206
|
-
messages.map((m) =>
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
205
|
+
messages.map((m, i) => {
|
|
206
|
+
// Our Markdown+Mathjax has issues when rendering streaming display math
|
|
207
|
+
// Force a re-render of the last (streaming) message when it's done loading.
|
|
208
|
+
const key = i === messages.length - 1 && isLoading
|
|
209
|
+
? `isLoading-${m.id}`
|
|
210
|
+
: m.id;
|
|
211
|
+
return (React.createElement(MessageRow, { key: key, "data-chat-role": m.role, className: (0, classnames_1.default)(classes.messageRow, {
|
|
212
|
+
[classes.messageRowUser]: m.role === "user",
|
|
213
|
+
[classes.messageRowAssistant]: m.role === "assistant",
|
|
214
|
+
}) },
|
|
215
|
+
React.createElement(Message, { className: classes.message },
|
|
216
|
+
React.createElement(VisuallyHidden_1.VisuallyHidden, { as: m.role === "user" ? "h5" : "h6" }, m.role === "user" ? "You said: " : "Assistant said: "),
|
|
217
|
+
React.createElement(Markdown_1.default, { enableMathjax: useMathJax }, m.content))));
|
|
218
|
+
}),
|
|
213
219
|
showStarters ? (React.createElement(StarterContainer, null, conversationStarters === null || conversationStarters === void 0 ? void 0 : conversationStarters.map((m) => (React.createElement(Starter, { className: classes.conversationStarter, key: m.content, onClick: () => {
|
|
214
220
|
scrollToBottom();
|
|
215
221
|
append({ role: "user", content: m.content });
|
|
@@ -244,4 +250,10 @@ const AiChat = (_a) => {
|
|
|
244
250
|
React.createElement(Disclaimer, { variant: "body3" }, "AI-generated content may be incorrect.")),
|
|
245
251
|
React.createElement(SrAnnouncer_1.SrAnnouncer, { isLoading: isLoading, loadingMessages: srLoadingMessages, message: (lastMsg === null || lastMsg === void 0 ? void 0 : lastMsg.role) === "assistant" ? lastMsg === null || lastMsg === void 0 ? void 0 : lastMsg.content : "" }))))));
|
|
246
252
|
};
|
|
253
|
+
exports.AiChatDisplay = AiChatDisplay;
|
|
254
|
+
const AiChat = (_a) => {
|
|
255
|
+
var { requestOpts, initialMessages, chatId, parseContent } = _a, displayProps = __rest(_a, ["requestOpts", "initialMessages", "chatId", "parseContent"]);
|
|
256
|
+
return (React.createElement(AiChatContext_1.AiChatProvider, { requestOpts: requestOpts, chatId: chatId, initialMessages: initialMessages, parseContent: parseContent },
|
|
257
|
+
React.createElement(AiChatDisplay, Object.assign({}, displayProps))));
|
|
258
|
+
};
|
|
247
259
|
exports.AiChat = AiChat;
|
|
@@ -9,10 +9,6 @@ export declare const StreamingResponses: Story;
|
|
|
9
9
|
* to text via `parseContent`.
|
|
10
10
|
*/
|
|
11
11
|
export declare const JsonResponses: Story;
|
|
12
|
-
/**
|
|
13
|
-
* This story shows the component's builtin markdown styling.
|
|
14
|
-
*/
|
|
15
|
-
export declare const MarkdownStyling: Story;
|
|
16
12
|
/**
|
|
17
13
|
* Where a scrollable container exists in the including component, it can be passed in
|
|
18
14
|
* for the AiChat component to use in place of its own height constrained message container
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ScrollContainer = exports.
|
|
3
|
+
exports.ScrollContainer = exports.JsonResponses = exports.StreamingResponses = void 0;
|
|
4
4
|
const React = require("react");
|
|
5
5
|
const AiChat_1 = require("./AiChat");
|
|
6
6
|
const styled_1 = require("@emotion/styled");
|
|
7
7
|
const api_1 = require("./test-utils/api");
|
|
8
8
|
const react_1 = require("react");
|
|
9
|
+
const better_react_mathjax_1 = require("better-react-mathjax");
|
|
9
10
|
const TEST_API_STREAMING = "http://localhost:4567/streaming";
|
|
10
11
|
const TEST_API_JSON = "http://localhost:4567/json";
|
|
11
12
|
const INITIAL_MESSAGES = [
|
|
@@ -39,8 +40,9 @@ const meta = {
|
|
|
39
40
|
},
|
|
40
41
|
render: (args) => React.createElement(AiChat_1.AiChat, Object.assign({}, args)),
|
|
41
42
|
decorators: (Story, context) => {
|
|
42
|
-
return (React.createElement(
|
|
43
|
-
React.createElement(
|
|
43
|
+
return (React.createElement(better_react_mathjax_1.MathJaxContext, null,
|
|
44
|
+
React.createElement(Container, null,
|
|
45
|
+
React.createElement(Story, { key: String(context.args.entryScreenEnabled) }))));
|
|
44
46
|
},
|
|
45
47
|
args: {
|
|
46
48
|
entryScreenTitle: "What do you want to learn from MIT?",
|
|
@@ -77,57 +79,6 @@ exports.JsonResponses = {
|
|
|
77
79
|
},
|
|
78
80
|
},
|
|
79
81
|
};
|
|
80
|
-
const DEMO_MARKDOWN = `This shows default markdown styling. Here's are some lists:
|
|
81
|
-
- Item 1
|
|
82
|
-
- Item 2 - an unordered list (bullets)
|
|
83
|
-
- Point A
|
|
84
|
-
- Point B
|
|
85
|
-
- Item 3 - an ordered list (numbers)
|
|
86
|
-
1. Item 3.1
|
|
87
|
-
2. Item 3.2
|
|
88
|
-
3. Item 3.3
|
|
89
|
-
|
|
90
|
-
Sometimes, unordered lists are nested within ordered lists:
|
|
91
|
-
1. Item 1
|
|
92
|
-
- Item 1.1
|
|
93
|
-
- Item 1.2
|
|
94
|
-
2. Item 2
|
|
95
|
-
- Item 2.1
|
|
96
|
-
- Item 2.2
|
|
97
|
-
|
|
98
|
-
Sometimes, ordered lists are nested within unordered lists:
|
|
99
|
-
- Item 1
|
|
100
|
-
1. Item 1.1
|
|
101
|
-
2. Item 1.2
|
|
102
|
-
- Item 2
|
|
103
|
-
1. Item 2.1
|
|
104
|
-
2. Item 2.2
|
|
105
|
-
|
|
106
|
-
Here is a longer paragraph and **bold text** and *italic text*. Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
|
107
|
-
sed do eiusmod tempor [incididunt](https://mit.edu) ut labore et dolore magna aliqua. Ut enim ad minim veniam.
|
|
108
|
-
|
|
109
|
-
And some inline code, \`\`<inline></inline>\`\` and code block:
|
|
110
|
-
\`\`\`
|
|
111
|
-
def f(x):
|
|
112
|
-
print(x)
|
|
113
|
-
\`\`\`
|
|
114
|
-
`;
|
|
115
|
-
/**
|
|
116
|
-
* This story shows the component's builtin markdown styling.
|
|
117
|
-
*/
|
|
118
|
-
exports.MarkdownStyling = {
|
|
119
|
-
args: {
|
|
120
|
-
requestOpts: { apiUrl: TEST_API_STREAMING },
|
|
121
|
-
entryScreenEnabled: false,
|
|
122
|
-
conversationStarters: [],
|
|
123
|
-
initialMessages: [
|
|
124
|
-
{
|
|
125
|
-
role: "assistant",
|
|
126
|
-
content: DEMO_MARKDOWN,
|
|
127
|
-
},
|
|
128
|
-
],
|
|
129
|
-
},
|
|
130
|
-
};
|
|
131
82
|
const ScrollComponent = (args) => {
|
|
132
83
|
const ref = (0, react_1.useRef)(null);
|
|
133
84
|
const [scrollElement, setScrollElement] = (0, react_1.useState)(null);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { UseChatHelpers } from "@ai-sdk/react";
|
|
3
|
+
import type { AiChatMessage, AiChatContextProps } from "./types";
|
|
4
|
+
/**
|
|
5
|
+
* All of `@ai-sdk/react`'s [`useChat`](https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat)
|
|
6
|
+
* results, plus the initial messages.
|
|
7
|
+
*/
|
|
8
|
+
type AiChatContextResult = UseChatHelpers & {
|
|
9
|
+
initialMessages: AiChatMessage[] | null;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Provides AiChatContext to its children. Within this provider, you can consume
|
|
13
|
+
* the AiChatContext using the `useAiChat` hook.
|
|
14
|
+
*/
|
|
15
|
+
declare const AiChatProvider: React.FC<AiChatContextProps>;
|
|
16
|
+
/**
|
|
17
|
+
* Returns the AiChatContext, which includes all results from `@ai-sdk/react`'s
|
|
18
|
+
* [`useChat`](https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat) hook as
|
|
19
|
+
* well as the initial messages.
|
|
20
|
+
*
|
|
21
|
+
* In addition to customizing the fetcher, using a context allows us to avoid
|
|
22
|
+
* this issue https://github.com/vercel/ai/issues/3266 since the caller no
|
|
23
|
+
* longer needs to provide the initial messages.
|
|
24
|
+
*/
|
|
25
|
+
declare const useAiChat: () => AiChatContextResult;
|
|
26
|
+
export { useAiChat, AiChatProvider };
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
+
var t = {};
|
|
13
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
+
t[p] = s[p];
|
|
15
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
+
t[p[i]] = s[p[i]];
|
|
19
|
+
}
|
|
20
|
+
return t;
|
|
21
|
+
};
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.AiChatProvider = exports.useAiChat = void 0;
|
|
24
|
+
const React = require("react");
|
|
25
|
+
const react_1 = require("@ai-sdk/react");
|
|
26
|
+
const react_2 = require("react");
|
|
27
|
+
const retryingFetch_1 = require("../../utils/retryingFetch");
|
|
28
|
+
const identity = (x) => x;
|
|
29
|
+
const getFetcher = (requestOpts) => (url, opts) => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
+
var _a, _b;
|
|
31
|
+
if (typeof (opts === null || opts === void 0 ? void 0 : opts.body) !== "string") {
|
|
32
|
+
console.error("Unexpected body type.");
|
|
33
|
+
return (0, retryingFetch_1.default)(url, opts);
|
|
34
|
+
}
|
|
35
|
+
const messages = JSON.parse(opts === null || opts === void 0 ? void 0 : opts.body).messages;
|
|
36
|
+
const transformBody = (_a = requestOpts.transformBody) !== null && _a !== void 0 ? _a : identity;
|
|
37
|
+
const options = Object.assign(Object.assign(Object.assign(Object.assign({}, opts), { body: JSON.stringify(transformBody(messages)) }), requestOpts.fetchOpts), { headers: Object.assign(Object.assign(Object.assign({}, opts === null || opts === void 0 ? void 0 : opts.headers), { "Content-Type": "application/json" }), (_b = requestOpts.fetchOpts) === null || _b === void 0 ? void 0 : _b.headers) });
|
|
38
|
+
return (0, retryingFetch_1.default)(url, options);
|
|
39
|
+
});
|
|
40
|
+
const AiChatContext = (0, react_2.createContext)(null);
|
|
41
|
+
/**
|
|
42
|
+
* Provides AiChatContext to its children. Within this provider, you can consume
|
|
43
|
+
* the AiChatContext using the `useAiChat` hook.
|
|
44
|
+
*/
|
|
45
|
+
const AiChatProvider = ({ initialMessages: _initialMessages, requestOpts, chatId, parseContent, children, }) => {
|
|
46
|
+
const initialMessages = (0, react_2.useMemo)(() => {
|
|
47
|
+
var _a;
|
|
48
|
+
return ((_a = _initialMessages === null || _initialMessages === void 0 ? void 0 : _initialMessages.map((message, i) => (Object.assign(Object.assign({}, message), { id: `initial-${i}` })))) !== null && _a !== void 0 ? _a : []);
|
|
49
|
+
}, [_initialMessages]);
|
|
50
|
+
const fetcher = (0, react_2.useMemo)(() => getFetcher(requestOpts), [requestOpts]);
|
|
51
|
+
const _a = (0, react_1.useChat)({
|
|
52
|
+
api: requestOpts.apiUrl,
|
|
53
|
+
streamProtocol: "text",
|
|
54
|
+
fetch: fetcher,
|
|
55
|
+
onFinish: (message) => {
|
|
56
|
+
var _a;
|
|
57
|
+
if (!requestOpts.onFinish)
|
|
58
|
+
return;
|
|
59
|
+
if (message.role === "assistant" || message.role === "user") {
|
|
60
|
+
(_a = requestOpts.onFinish) === null || _a === void 0 ? void 0 : _a.call(requestOpts, message);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
console.info("Unexpected message role.", message);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
initialMessages,
|
|
67
|
+
id: chatId,
|
|
68
|
+
}), { messages: unparsed } = _a, others = __rest(_a, ["messages"]);
|
|
69
|
+
const messages = (0, react_2.useMemo)(() => {
|
|
70
|
+
const initial = initialMessages === null || initialMessages === void 0 ? void 0 : initialMessages.map((m) => m.id);
|
|
71
|
+
return unparsed.map((m) => {
|
|
72
|
+
if (m.role === "assistant" && !(initial === null || initial === void 0 ? void 0 : initial.includes(m.id))) {
|
|
73
|
+
const content = parseContent ? parseContent(m.content) : m.content;
|
|
74
|
+
return Object.assign(Object.assign({}, m), { content });
|
|
75
|
+
}
|
|
76
|
+
return m;
|
|
77
|
+
});
|
|
78
|
+
}, [parseContent, unparsed, initialMessages]);
|
|
79
|
+
return (React.createElement(AiChatContext.Provider
|
|
80
|
+
/**
|
|
81
|
+
* Ensure that child state is reset when chatId changes.
|
|
82
|
+
*/
|
|
83
|
+
, {
|
|
84
|
+
/**
|
|
85
|
+
* Ensure that child state is reset when chatId changes.
|
|
86
|
+
*/
|
|
87
|
+
key: chatId, value: Object.assign({ initialMessages, messages }, others) }, children));
|
|
88
|
+
};
|
|
89
|
+
exports.AiChatProvider = AiChatProvider;
|
|
90
|
+
/**
|
|
91
|
+
* Returns the AiChatContext, which includes all results from `@ai-sdk/react`'s
|
|
92
|
+
* [`useChat`](https://ai-sdk.dev/docs/reference/ai-sdk-ui/use-chat) hook as
|
|
93
|
+
* well as the initial messages.
|
|
94
|
+
*
|
|
95
|
+
* In addition to customizing the fetcher, using a context allows us to avoid
|
|
96
|
+
* this issue https://github.com/vercel/ai/issues/3266 since the caller no
|
|
97
|
+
* longer needs to provide the initial messages.
|
|
98
|
+
*/
|
|
99
|
+
const useAiChat = () => {
|
|
100
|
+
const context = React.useContext(AiChatContext);
|
|
101
|
+
if (!context) {
|
|
102
|
+
throw new Error("useAiChatContext must be used within an AiChatProvider");
|
|
103
|
+
}
|
|
104
|
+
return context;
|
|
105
|
+
};
|
|
106
|
+
exports.useAiChat = useAiChat;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { AiChatProvider } from "./AiChatContext";
|
|
3
|
+
/**
|
|
4
|
+
* AiChatProvider provides state and functions for managing chat. The higher-level
|
|
5
|
+
* `AiChat` component is a wrapper around this provider and the `AiChatDisplay`,
|
|
6
|
+
* roughly.
|
|
7
|
+
*
|
|
8
|
+
* If you need to access chat state outside of the chat display, you can use
|
|
9
|
+
* `AiChatProvider` directly.
|
|
10
|
+
*/
|
|
11
|
+
declare const meta: Meta<typeof AiChatProvider>;
|
|
12
|
+
export default meta;
|
|
13
|
+
type Story = StoryObj<typeof AiChatProvider>;
|
|
14
|
+
export declare const StreamingResponses: Story;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamingResponses = void 0;
|
|
4
|
+
const React = require("react");
|
|
5
|
+
const AiChat_1 = require("./AiChat");
|
|
6
|
+
const AiChatContext_1 = require("./AiChatContext");
|
|
7
|
+
const styled_1 = require("@emotion/styled");
|
|
8
|
+
const api_1 = require("./test-utils/api");
|
|
9
|
+
const Typography_1 = require("@mui/material/Typography");
|
|
10
|
+
const TEST_API_STREAMING = "http://localhost:4567/streaming";
|
|
11
|
+
const INITIAL_MESSAGES = [
|
|
12
|
+
{
|
|
13
|
+
content: "Hi! What are you interested in learning about?",
|
|
14
|
+
role: "assistant",
|
|
15
|
+
},
|
|
16
|
+
];
|
|
17
|
+
const STARTERS = [
|
|
18
|
+
{ content: "I'm interested in quantum computing" },
|
|
19
|
+
{ content: "I want to understand global warming. " },
|
|
20
|
+
{ content: "I am curious about AI applications for business" },
|
|
21
|
+
];
|
|
22
|
+
const Container = styled_1.default.div({
|
|
23
|
+
width: "100%",
|
|
24
|
+
height: "400px",
|
|
25
|
+
position: "relative",
|
|
26
|
+
});
|
|
27
|
+
const MessageCounter = () => {
|
|
28
|
+
const { messages } = (0, AiChatContext_1.useAiChat)();
|
|
29
|
+
return (React.createElement(Typography_1.default, { variant: "subtitle1" },
|
|
30
|
+
"Message count: ",
|
|
31
|
+
messages.length,
|
|
32
|
+
" (Provided by ",
|
|
33
|
+
React.createElement("code", null, "AiChatContext"),
|
|
34
|
+
")"));
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* AiChatProvider provides state and functions for managing chat. The higher-level
|
|
38
|
+
* `AiChat` component is a wrapper around this provider and the `AiChatDisplay`,
|
|
39
|
+
* roughly.
|
|
40
|
+
*
|
|
41
|
+
* If you need to access chat state outside of the chat display, you can use
|
|
42
|
+
* `AiChatProvider` directly.
|
|
43
|
+
*/
|
|
44
|
+
const meta = {
|
|
45
|
+
title: "smoot-design/AI/AiChatContext",
|
|
46
|
+
component: AiChatContext_1.AiChatProvider,
|
|
47
|
+
parameters: {
|
|
48
|
+
msw: { handlers: api_1.handlers },
|
|
49
|
+
},
|
|
50
|
+
render: (args) => {
|
|
51
|
+
return (React.createElement(AiChatContext_1.AiChatProvider, Object.assign({}, args),
|
|
52
|
+
React.createElement(MessageCounter, null),
|
|
53
|
+
React.createElement(Container, null,
|
|
54
|
+
React.createElement(AiChat_1.AiChatDisplay, { entryScreenEnabled: false, conversationStarters: STARTERS, placeholder: "Type your message here", askTimTitle: "Ask TIM" }))));
|
|
55
|
+
},
|
|
56
|
+
decorators: (Story) => {
|
|
57
|
+
return (React.createElement(Container, null,
|
|
58
|
+
React.createElement(Story, null)));
|
|
59
|
+
},
|
|
60
|
+
args: {
|
|
61
|
+
requestOpts: { apiUrl: TEST_API_STREAMING },
|
|
62
|
+
initialMessages: INITIAL_MESSAGES,
|
|
63
|
+
},
|
|
64
|
+
argTypes: {
|
|
65
|
+
initialMessages: {
|
|
66
|
+
control: { type: "object", disable: true },
|
|
67
|
+
},
|
|
68
|
+
requestOpts: {
|
|
69
|
+
control: { type: "object", disable: true },
|
|
70
|
+
table: { readonly: true }, // See above
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
};
|
|
74
|
+
exports.default = meta;
|
|
75
|
+
exports.StreamingResponses = {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/react";
|
|
2
|
+
import { AiChat } from "./AiChat";
|
|
3
|
+
declare const meta: Meta<typeof AiChat>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof AiChat>;
|
|
6
|
+
export declare const Typical: Story;
|
|
7
|
+
export declare const Textual: Story;
|
|
8
|
+
export declare const Math: Story;
|
|
9
|
+
export declare const SimpleOrderedList: Story;
|
|
10
|
+
export declare const SimpleUnorderedList: Story;
|
|
11
|
+
export declare const NestedOrderedList: Story;
|
|
12
|
+
export declare const NestedUnorderedList: Story;
|
|
13
|
+
export declare const NestedOrderedUnorderedList: Story;
|
|
14
|
+
export declare const NestedUnorderedOrderedList: Story;
|
|
15
|
+
export declare const UnexpectedList: Story;
|