@aws-amplify/ui-react-ai 1.4.1 → 1.5.1
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 +21 -15
- package/dist/esm/components/AIConversation/AIConversation.mjs +7 -12
- package/dist/esm/components/AIConversation/useConversationScrollProps.mjs +31 -0
- package/dist/esm/components/AIConversation/views/default/Form.mjs +14 -1
- package/dist/esm/hooks/contentFromEvents.mjs +7 -7
- package/dist/esm/hooks/useAIConversation.mjs +17 -8
- package/dist/esm/version.mjs +1 -1
- package/dist/index.js +72 -29
- package/dist/types/components/AIConversation/AIConversation.d.ts +1 -1
- package/dist/types/components/AIConversation/AIConversationProvider.d.ts +1 -1
- package/dist/types/components/AIConversation/context/ActionsContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/AttachmentContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/AvatarsContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/ControlsContext.d.ts +3 -3
- package/dist/types/components/AIConversation/context/DisplayTextContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/FallbackComponentContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/MessageRenderContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/MessageVariantContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/MessagesContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/ResponseComponentsContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/SendMessageContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/SuggestedPromptsContext.d.ts +1 -1
- package/dist/types/components/AIConversation/context/index.d.ts +6 -3
- package/dist/types/components/AIConversation/createAIConversation.d.ts +1 -1
- package/dist/types/components/AIConversation/displayText.d.ts +1 -1
- package/dist/types/components/AIConversation/index.d.ts +4 -3
- package/dist/types/components/AIConversation/types.d.ts +7 -7
- package/dist/types/components/AIConversation/useConversationScrollProps.d.ts +6 -0
- package/dist/types/components/AIConversation/utils.d.ts +1 -1
- package/dist/types/components/AIConversation/views/Controls/ActionsBarControl.d.ts +1 -1
- package/dist/types/components/AIConversation/views/Controls/MessagesControl.d.ts +1 -1
- package/dist/types/components/AIConversation/views/default/Attachments.d.ts +1 -1
- package/dist/types/components/AIConversation/views/default/Form.d.ts +1 -1
- package/dist/types/components/AIConversation/views/default/MessageList.d.ts +1 -1
- package/dist/types/components/AIConversation/views/default/PromptList.d.ts +1 -1
- package/dist/types/hooks/contentFromEvents.d.ts +1 -1
- package/dist/types/hooks/createAIHooks.d.ts +3 -3
- package/dist/types/hooks/exhaustivelyListMessages.d.ts +1 -1
- package/dist/types/hooks/shared.d.ts +1 -1
- package/dist/types/hooks/useAIConversation.d.ts +2 -2
- package/dist/types/hooks/useAIGeneration.d.ts +2 -2
- package/dist/types/index.d.ts +3 -2
- package/dist/types/version.d.ts +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,23 +1,29 @@
|
|
|
1
|
-
# Amplify UI
|
|
1
|
+
# Amplify UI React AI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The React AI package provides components and utilities for AI-powered conversations and interactions in Amplify connected applications.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
2. Primitive components that create consistency across Amplify UI and allow you to build complete applications that fit your brand, like Buttons and Badges.
|
|
7
|
-
3. Data-bound components that make it easy to display dynamic data, like DataStoreCollections.
|
|
8
|
-
4. Theming capabilities that allow you to customize the appearance of Amplify UI to match your brand.
|
|
5
|
+
## Contents
|
|
9
6
|
|
|
10
|
-
|
|
7
|
+
### Core Components
|
|
11
8
|
|
|
12
|
-
-
|
|
9
|
+
- `AIConversation` - Component for AI-powered conversations
|
|
10
|
+
- `createAIConversation` - Factory function for creating AI conversation components
|
|
11
|
+
|
|
12
|
+
### Utility Functions
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
- `createAIHooks` - Factory function for creating AI-related hooks
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
- **Endlessly customizable** Every detail of Amplify UI is customizable to match your brand. Style all of Amplify UI with themes, override components with your own, or build your own UI and use Amplify for complex state management.
|
|
18
|
-
- **Accessible** Amplify UI components follow [WCAG](https://www.w3.org/WAI/standards-guidelines/wcag/) and [WAI-ARIA](https://www.w3.org/TR/wai-aria-1.2/) best practices and guidelines such as color contrast, keyboard navigation, accessible labels, and focus management.
|
|
19
|
-
- **Primitive components (React only right now)** Primitive components are used in the connected components, like Authenticator, you can also customize them and use them to build the rest of your UI.
|
|
16
|
+
### Type Definitions
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
- `Avatars` - Type for avatar configurations
|
|
19
|
+
- `CustomAction` - Type for custom actions
|
|
20
|
+
- `ResponseComponent` - Type for response components
|
|
21
|
+
- `SuggestedPrompt` - Type for suggested prompts
|
|
22
|
+
- `ConversationMessage` - Type for conversation messages
|
|
23
|
+
- `ConversationMessageContent` - Type for conversation message content
|
|
24
|
+
- `SendMessage` - Type for send message function
|
|
25
|
+
- `SendMesageParameters` - Type for send message parameters
|
|
22
26
|
|
|
23
|
-
|
|
27
|
+
## React Documentation
|
|
28
|
+
|
|
29
|
+
- https://ui.docs.amplify.aws/react
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Flex, ScrollView } from '@aws-amplify/ui-react';
|
|
3
3
|
import { useIcons, IconUser, IconAssistant } from '@aws-amplify/ui-react/internal';
|
|
4
|
+
import useConversationScrollProps from './useConversationScrollProps.mjs';
|
|
4
5
|
import { MessagesControl } from './views/Controls/MessagesControl.mjs';
|
|
5
6
|
import { FormControl } from './views/Controls/FormControl.mjs';
|
|
6
7
|
import { MessageList } from './views/default/MessageList.mjs';
|
|
@@ -12,7 +13,7 @@ import { useSetUserAgent } from '@aws-amplify/ui-react-core';
|
|
|
12
13
|
import { VERSION } from '../../version.mjs';
|
|
13
14
|
import { DefaultMessageControl } from './views/Controls/DefaultMessageControl.mjs';
|
|
14
15
|
|
|
15
|
-
function AIConversationBase({ avatars, controls, ...rest }) {
|
|
16
|
+
function AIConversationBase({ avatars, controls, messages, ...rest }) {
|
|
16
17
|
useSetUserAgent({
|
|
17
18
|
componentName: 'AIConversation',
|
|
18
19
|
packageName: 'react-ai',
|
|
@@ -31,20 +32,14 @@ function AIConversationBase({ avatars, controls, ...rest }) {
|
|
|
31
32
|
};
|
|
32
33
|
const providerProps = {
|
|
33
34
|
...rest,
|
|
34
|
-
avatars: {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
},
|
|
38
|
-
controls: {
|
|
39
|
-
MessageList,
|
|
40
|
-
PromptList,
|
|
41
|
-
Form,
|
|
42
|
-
...controls,
|
|
43
|
-
},
|
|
35
|
+
avatars: { ...defaultAvatars, ...avatars },
|
|
36
|
+
controls: { MessageList, PromptList, Form, ...controls },
|
|
37
|
+
messages,
|
|
44
38
|
};
|
|
39
|
+
const scrollProps = useConversationScrollProps(messages);
|
|
45
40
|
return (React.createElement(AIConversationProvider, { ...providerProps },
|
|
46
41
|
React.createElement(Flex, { className: ComponentClassName.AIConversation, testId: "ai-conversation" },
|
|
47
|
-
React.createElement(ScrollView, {
|
|
42
|
+
React.createElement(ScrollView, { ...scrollProps, flex: "1" },
|
|
48
43
|
React.createElement(DefaultMessageControl, null),
|
|
49
44
|
React.createElement(MessagesControl, null)),
|
|
50
45
|
React.createElement(FormControl, null))));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useHasValueUpdated } from '@aws-amplify/ui-react-core';
|
|
3
|
+
|
|
4
|
+
function useConversationScrollProps(messages) {
|
|
5
|
+
const [autoScroll, setAutoScroll] = React.useState('smooth');
|
|
6
|
+
const messagesLength = messages.length;
|
|
7
|
+
const hasMessagesLengthChanged = useHasValueUpdated(messagesLength, true);
|
|
8
|
+
const lastScrollTop = React.useRef();
|
|
9
|
+
const onScroll = ({ currentTarget }) => {
|
|
10
|
+
if (autoScroll !== 'smooth')
|
|
11
|
+
return;
|
|
12
|
+
const { scrollTop } = currentTarget;
|
|
13
|
+
// set `autoScroll` and `lastScrollTop` to `undefined` on user scroll up
|
|
14
|
+
if (lastScrollTop.current && scrollTop < lastScrollTop.current) {
|
|
15
|
+
setAutoScroll(undefined);
|
|
16
|
+
lastScrollTop.current = undefined;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
lastScrollTop.current = scrollTop;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
React.useEffect(() => {
|
|
23
|
+
// reset `autoScroll` to 'smooth' on new message
|
|
24
|
+
if (hasMessagesLengthChanged) {
|
|
25
|
+
setAutoScroll('smooth');
|
|
26
|
+
}
|
|
27
|
+
}, [hasMessagesLengthChanged]);
|
|
28
|
+
return { autoScroll, onScroll };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export { useConversationScrollProps as default };
|
|
@@ -46,7 +46,20 @@ const Form = ({ setInput, input, handleSubmit, allowAttachments, onValidate, isL
|
|
|
46
46
|
}
|
|
47
47
|
onValidate(Array.from(e.target.files));
|
|
48
48
|
}, multiple: true, accept: [...validFileTypes].map((type) => `.${type}`).join(','), "data-testid": "hidden-file-input" })))) : null,
|
|
49
|
-
React.createElement(TextAreaField, { className: ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', testId: "text-input", onCompositionStart: () => setComposing(true),
|
|
49
|
+
React.createElement(TextAreaField, { className: ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', testId: "text-input", onCompositionStart: () => setComposing(true), onCompositionUpdate: (e) => {
|
|
50
|
+
const composedText = e?.currentTarget?.value || '';
|
|
51
|
+
setInput?.((prevValue) => ({
|
|
52
|
+
...prevValue,
|
|
53
|
+
text: composedText,
|
|
54
|
+
}));
|
|
55
|
+
}, onCompositionEnd: (e) => {
|
|
56
|
+
setComposing(false);
|
|
57
|
+
const composedText = e?.currentTarget?.value || '';
|
|
58
|
+
setInput?.((prevValue) => ({
|
|
59
|
+
...prevValue,
|
|
60
|
+
text: composedText,
|
|
61
|
+
}));
|
|
62
|
+
}, onKeyDown: (e) => {
|
|
50
63
|
// Submit on enter key if shift is not pressed also
|
|
51
64
|
const shouldSubmit = !e.shiftKey && e.key === 'Enter' && !composing;
|
|
52
65
|
if (shouldSubmit && isHTMLFormElement(e.target)) {
|
|
@@ -2,19 +2,19 @@ const contentFromEvents = (contentBlocks) => {
|
|
|
2
2
|
if (!contentBlocks)
|
|
3
3
|
return [];
|
|
4
4
|
return contentBlocks.map((contentBlock) => {
|
|
5
|
-
|
|
5
|
+
// Filter out sparse array holes from out-of-order direct index assignment
|
|
6
|
+
const events = contentBlock.filter(Boolean);
|
|
7
|
+
const isTextBlock = events.some((event) => event.text);
|
|
6
8
|
if (isTextBlock) {
|
|
7
9
|
return {
|
|
8
|
-
text:
|
|
9
|
-
.map((event) =>
|
|
10
|
-
return event.text;
|
|
11
|
-
})
|
|
10
|
+
text: events
|
|
11
|
+
.map((event) => event.text ?? '')
|
|
12
12
|
.join(''),
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
// tool use is never chunked
|
|
16
|
-
if (
|
|
17
|
-
return { toolUse:
|
|
16
|
+
if (events[0]?.toolUse) {
|
|
17
|
+
return { toolUse: events[0].toolUse };
|
|
18
18
|
}
|
|
19
19
|
});
|
|
20
20
|
};
|
|
@@ -174,11 +174,13 @@ function createUseAIConversation(client) {
|
|
|
174
174
|
contentBlocksRef.current[contentBlockIndex] = [event];
|
|
175
175
|
}
|
|
176
176
|
else {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
event
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
// Direct index assignment: idempotent, handles out-of-order and duplicates
|
|
178
|
+
if (contentBlockDeltaIndex !== undefined) {
|
|
179
|
+
currentBlock[contentBlockDeltaIndex] = event;
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
currentBlock.push(event);
|
|
183
|
+
}
|
|
182
184
|
}
|
|
183
185
|
}
|
|
184
186
|
setClientState((prev) => {
|
|
@@ -190,13 +192,20 @@ function createUseAIConversation(client) {
|
|
|
190
192
|
role: 'assistant',
|
|
191
193
|
isLoading: true,
|
|
192
194
|
};
|
|
195
|
+
// Match by message ID instead of assuming last message
|
|
196
|
+
const existingIndex = prev.data.messages.findIndex((m) => m.id === id);
|
|
197
|
+
const updatedMessages = existingIndex >= 0
|
|
198
|
+
? [
|
|
199
|
+
...prev.data.messages.slice(0, existingIndex),
|
|
200
|
+
message,
|
|
201
|
+
...prev.data.messages.slice(existingIndex + 1),
|
|
202
|
+
]
|
|
203
|
+
: [...prev.data.messages, message];
|
|
193
204
|
return {
|
|
194
205
|
...prev,
|
|
195
206
|
data: {
|
|
196
207
|
...prev.data,
|
|
197
|
-
|
|
198
|
-
// message, but maybe we should match it by message ID?
|
|
199
|
-
messages: [...prev.data.messages.slice(0, -1), message],
|
|
208
|
+
messages: updatedMessages,
|
|
200
209
|
},
|
|
201
210
|
};
|
|
202
211
|
});
|
package/dist/esm/version.mjs
CHANGED
package/dist/index.js
CHANGED
|
@@ -1034,6 +1034,33 @@ function createAIConversation(input = {}) {
|
|
|
1034
1034
|
return { AIConversation };
|
|
1035
1035
|
}
|
|
1036
1036
|
|
|
1037
|
+
function useConversationScrollProps(messages) {
|
|
1038
|
+
const [autoScroll, setAutoScroll] = React__namespace.useState('smooth');
|
|
1039
|
+
const messagesLength = messages.length;
|
|
1040
|
+
const hasMessagesLengthChanged = uiReactCore.useHasValueUpdated(messagesLength, true);
|
|
1041
|
+
const lastScrollTop = React__namespace.useRef();
|
|
1042
|
+
const onScroll = ({ currentTarget }) => {
|
|
1043
|
+
if (autoScroll !== 'smooth')
|
|
1044
|
+
return;
|
|
1045
|
+
const { scrollTop } = currentTarget;
|
|
1046
|
+
// set `autoScroll` and `lastScrollTop` to `undefined` on user scroll up
|
|
1047
|
+
if (lastScrollTop.current && scrollTop < lastScrollTop.current) {
|
|
1048
|
+
setAutoScroll(undefined);
|
|
1049
|
+
lastScrollTop.current = undefined;
|
|
1050
|
+
}
|
|
1051
|
+
else {
|
|
1052
|
+
lastScrollTop.current = scrollTop;
|
|
1053
|
+
}
|
|
1054
|
+
};
|
|
1055
|
+
React__namespace.useEffect(() => {
|
|
1056
|
+
// reset `autoScroll` to 'smooth' on new message
|
|
1057
|
+
if (hasMessagesLengthChanged) {
|
|
1058
|
+
setAutoScroll('smooth');
|
|
1059
|
+
}
|
|
1060
|
+
}, [hasMessagesLengthChanged]);
|
|
1061
|
+
return { autoScroll, onScroll };
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1037
1064
|
const PlaceholderMessage = ({ role }) => {
|
|
1038
1065
|
const variant = React__namespace.useContext(MessageVariantContext);
|
|
1039
1066
|
return (React__namespace.createElement(uiReact.View, { className: ui.classNames(ui.ComponentClassName.AIConversationMessage, ui.classNameModifier(ui.ComponentClassName.AIConversationMessage, variant), ui.classNameModifier(ui.ComponentClassName.AIConversationMessage, role)) },
|
|
@@ -1160,7 +1187,20 @@ const Form = ({ setInput, input, handleSubmit, allowAttachments, onValidate, isL
|
|
|
1160
1187
|
}
|
|
1161
1188
|
onValidate(Array.from(e.target.files));
|
|
1162
1189
|
}, multiple: true, accept: [...validFileTypes].map((type) => `.${type}`).join(','), "data-testid": "hidden-file-input" })))) : null,
|
|
1163
|
-
React__namespace.createElement(uiReact.TextAreaField, { className: ui.ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', testId: "text-input", onCompositionStart: () => setComposing(true),
|
|
1190
|
+
React__namespace.createElement(uiReact.TextAreaField, { className: ui.ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', testId: "text-input", onCompositionStart: () => setComposing(true), onCompositionUpdate: (e) => {
|
|
1191
|
+
const composedText = e?.currentTarget?.value || '';
|
|
1192
|
+
setInput?.((prevValue) => ({
|
|
1193
|
+
...prevValue,
|
|
1194
|
+
text: composedText,
|
|
1195
|
+
}));
|
|
1196
|
+
}, onCompositionEnd: (e) => {
|
|
1197
|
+
setComposing(false);
|
|
1198
|
+
const composedText = e?.currentTarget?.value || '';
|
|
1199
|
+
setInput?.((prevValue) => ({
|
|
1200
|
+
...prevValue,
|
|
1201
|
+
text: composedText,
|
|
1202
|
+
}));
|
|
1203
|
+
}, onKeyDown: (e) => {
|
|
1164
1204
|
// Submit on enter key if shift is not pressed also
|
|
1165
1205
|
const shouldSubmit = !e.shiftKey && e.key === 'Enter' && !composing;
|
|
1166
1206
|
if (shouldSubmit && isHTMLFormElement(e.target)) {
|
|
@@ -1190,9 +1230,9 @@ const PromptList = ({ setInput, suggestedPrompts = [], }) => {
|
|
|
1190
1230
|
})));
|
|
1191
1231
|
};
|
|
1192
1232
|
|
|
1193
|
-
const VERSION = '1.
|
|
1233
|
+
const VERSION = '1.5.1';
|
|
1194
1234
|
|
|
1195
|
-
function AIConversationBase({ avatars, controls, ...rest }) {
|
|
1235
|
+
function AIConversationBase({ avatars, controls, messages, ...rest }) {
|
|
1196
1236
|
uiReactCore.useSetUserAgent({
|
|
1197
1237
|
componentName: 'AIConversation',
|
|
1198
1238
|
packageName: 'react-ai',
|
|
@@ -1211,20 +1251,14 @@ function AIConversationBase({ avatars, controls, ...rest }) {
|
|
|
1211
1251
|
};
|
|
1212
1252
|
const providerProps = {
|
|
1213
1253
|
...rest,
|
|
1214
|
-
avatars: {
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
},
|
|
1218
|
-
controls: {
|
|
1219
|
-
MessageList,
|
|
1220
|
-
PromptList,
|
|
1221
|
-
Form,
|
|
1222
|
-
...controls,
|
|
1223
|
-
},
|
|
1254
|
+
avatars: { ...defaultAvatars, ...avatars },
|
|
1255
|
+
controls: { MessageList, PromptList, Form, ...controls },
|
|
1256
|
+
messages,
|
|
1224
1257
|
};
|
|
1258
|
+
const scrollProps = useConversationScrollProps(messages);
|
|
1225
1259
|
return (React__namespace.createElement(AIConversationProvider, { ...providerProps },
|
|
1226
1260
|
React__namespace.createElement(uiReact.Flex, { className: ui.ComponentClassName.AIConversation, testId: "ai-conversation" },
|
|
1227
|
-
React__namespace.createElement(uiReact.ScrollView, {
|
|
1261
|
+
React__namespace.createElement(uiReact.ScrollView, { ...scrollProps, flex: "1" },
|
|
1228
1262
|
React__namespace.createElement(DefaultMessageControl, null),
|
|
1229
1263
|
React__namespace.createElement(MessagesControl, null)),
|
|
1230
1264
|
React__namespace.createElement(FormControl, null))));
|
|
@@ -1272,19 +1306,19 @@ const contentFromEvents = (contentBlocks) => {
|
|
|
1272
1306
|
if (!contentBlocks)
|
|
1273
1307
|
return [];
|
|
1274
1308
|
return contentBlocks.map((contentBlock) => {
|
|
1275
|
-
|
|
1309
|
+
// Filter out sparse array holes from out-of-order direct index assignment
|
|
1310
|
+
const events = contentBlock.filter(Boolean);
|
|
1311
|
+
const isTextBlock = events.some((event) => event.text);
|
|
1276
1312
|
if (isTextBlock) {
|
|
1277
1313
|
return {
|
|
1278
|
-
text:
|
|
1279
|
-
.map((event) =>
|
|
1280
|
-
return event.text;
|
|
1281
|
-
})
|
|
1314
|
+
text: events
|
|
1315
|
+
.map((event) => event.text ?? '')
|
|
1282
1316
|
.join(''),
|
|
1283
1317
|
};
|
|
1284
1318
|
}
|
|
1285
1319
|
// tool use is never chunked
|
|
1286
|
-
if (
|
|
1287
|
-
return { toolUse:
|
|
1320
|
+
if (events[0]?.toolUse) {
|
|
1321
|
+
return { toolUse: events[0].toolUse };
|
|
1288
1322
|
}
|
|
1289
1323
|
});
|
|
1290
1324
|
};
|
|
@@ -1477,11 +1511,13 @@ function createUseAIConversation(client) {
|
|
|
1477
1511
|
contentBlocksRef.current[contentBlockIndex] = [event];
|
|
1478
1512
|
}
|
|
1479
1513
|
else {
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
event
|
|
1483
|
-
|
|
1484
|
-
|
|
1514
|
+
// Direct index assignment: idempotent, handles out-of-order and duplicates
|
|
1515
|
+
if (contentBlockDeltaIndex !== undefined) {
|
|
1516
|
+
currentBlock[contentBlockDeltaIndex] = event;
|
|
1517
|
+
}
|
|
1518
|
+
else {
|
|
1519
|
+
currentBlock.push(event);
|
|
1520
|
+
}
|
|
1485
1521
|
}
|
|
1486
1522
|
}
|
|
1487
1523
|
setClientState((prev) => {
|
|
@@ -1493,13 +1529,20 @@ function createUseAIConversation(client) {
|
|
|
1493
1529
|
role: 'assistant',
|
|
1494
1530
|
isLoading: true,
|
|
1495
1531
|
};
|
|
1532
|
+
// Match by message ID instead of assuming last message
|
|
1533
|
+
const existingIndex = prev.data.messages.findIndex((m) => m.id === id);
|
|
1534
|
+
const updatedMessages = existingIndex >= 0
|
|
1535
|
+
? [
|
|
1536
|
+
...prev.data.messages.slice(0, existingIndex),
|
|
1537
|
+
message,
|
|
1538
|
+
...prev.data.messages.slice(existingIndex + 1),
|
|
1539
|
+
]
|
|
1540
|
+
: [...prev.data.messages, message];
|
|
1496
1541
|
return {
|
|
1497
1542
|
...prev,
|
|
1498
1543
|
data: {
|
|
1499
1544
|
...prev.data,
|
|
1500
|
-
|
|
1501
|
-
// message, but maybe we should match it by message ID?
|
|
1502
|
-
messages: [...prev.data.messages.slice(0, -1), message],
|
|
1545
|
+
messages: updatedMessages,
|
|
1503
1546
|
},
|
|
1504
1547
|
};
|
|
1505
1548
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AIConversation as AIConversationType, AIConversationInput, AIConversationProps } from './types';
|
|
1
|
+
import type { AIConversation as AIConversationType, AIConversationInput, AIConversationProps } from './types';
|
|
2
2
|
interface AIConversationBaseProps extends AIConversationProps, AIConversationInput {
|
|
3
3
|
}
|
|
4
4
|
export declare const AIConversation: AIConversationType<AIConversationBaseProps>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { AIConversationInput, AIConversationProps } from './types';
|
|
2
|
+
import type { AIConversationInput, AIConversationProps } from './types';
|
|
3
3
|
export interface AIConversationProviderProps extends AIConversationInput, AIConversationProps {
|
|
4
4
|
children?: React.ReactNode;
|
|
5
5
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { CustomAction } from '../types';
|
|
2
|
+
import type { CustomAction } from '../types';
|
|
3
3
|
export declare const ActionsContext: React.Context<CustomAction[] | undefined>;
|
|
4
4
|
export declare const ActionsProvider: ({ children, actions, }: {
|
|
5
5
|
children?: React.ReactNode;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { AIConversationInput } from '../types';
|
|
2
|
+
import type { AIConversationInput } from '../types';
|
|
3
3
|
export interface AttachmentContextProps extends Pick<AIConversationInput, 'allowAttachments' | 'maxAttachments' | 'maxAttachmentSize'> {
|
|
4
4
|
}
|
|
5
5
|
export declare const AttachmentContext: React.Context<Required<AttachmentContextProps>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { Avatars } from '../types';
|
|
2
|
+
import type { Avatars } from '../types';
|
|
3
3
|
export declare const AvatarsContext: React.Context<Avatars | undefined>;
|
|
4
4
|
export declare const AvatarsProvider: ({ children, avatars, }: {
|
|
5
5
|
children?: React.ReactNode;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ConversationInputContextProps } from './ConversationInputContext';
|
|
3
|
-
import { SuggestedPrompt } from '../types';
|
|
4
|
-
import { ConversationMessage } from '../../../types';
|
|
2
|
+
import type { ConversationInputContextProps } from './ConversationInputContext';
|
|
3
|
+
import type { SuggestedPrompt } from '../types';
|
|
4
|
+
import type { ConversationMessage } from '../../../types';
|
|
5
5
|
export interface ControlsContextProps {
|
|
6
6
|
Form?: React.ComponentType<{
|
|
7
7
|
handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ConversationDisplayText } from '../displayText';
|
|
1
|
+
import type { ConversationDisplayText } from '../displayText';
|
|
2
2
|
export declare const ConversationDisplayTextContext: import("react").Context<Required<ConversationDisplayText>>, ConversationDisplayTextProvider: import("react").ComponentType<import("react").PropsWithChildren<Required<ConversationDisplayText>>>, useConversationDisplayText: (params?: {
|
|
3
3
|
errorMessage?: string | undefined;
|
|
4
4
|
} | undefined) => Required<ConversationDisplayText>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { AIConversationInput } from '../types';
|
|
2
|
+
import type { AIConversationInput } from '../types';
|
|
3
3
|
export declare const FallbackComponentContext: React.Context<React.ComponentType<any> | undefined>;
|
|
4
4
|
export declare const FallbackComponentProvider: ({ children, FallbackComponent, }: {
|
|
5
5
|
children?: React.ReactNode;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MessageRenderer } from '../types';
|
|
1
|
+
import type { MessageRenderer } from '../types';
|
|
2
2
|
export declare const MessageRendererContext: import("react").Context<MessageRenderer>, MessageRendererProvider: import("react").ComponentType<import("react").PropsWithChildren<MessageRenderer>>, useMessageRenderer: (params?: {
|
|
3
3
|
errorMessage?: string | undefined;
|
|
4
4
|
} | undefined) => MessageRenderer;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { MessageVariant } from '../types';
|
|
2
|
+
import type { MessageVariant } from '../types';
|
|
3
3
|
export declare const MessageVariantContext: React.Context<MessageVariant | undefined>;
|
|
4
4
|
export declare const MessageVariantProvider: ({ children, variant, }: {
|
|
5
5
|
children?: React.ReactNode;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ConversationMessage } from '../../../types';
|
|
2
|
+
import type { ConversationMessage } from '../../../types';
|
|
3
3
|
type MessagesContextProps = ConversationMessage[] | undefined;
|
|
4
4
|
export declare const MessagesContext: React.Context<MessagesContextProps>;
|
|
5
5
|
export declare const RoleContext: React.Context<"user" | "assistant" | undefined>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ToolConfiguration, ResponseComponents } from '../../../types';
|
|
2
|
+
import type { ToolConfiguration, ResponseComponents } from '../../../types';
|
|
3
3
|
type ResponseComponentsContextProps = ResponseComponents | undefined;
|
|
4
4
|
export declare const RESPONSE_COMPONENT_PREFIX = "AMPLIFY_UI_";
|
|
5
5
|
export declare const ResponseComponentsContext: React.Context<ResponseComponentsContextProps>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { SendMessage } from '../../../types';
|
|
2
|
+
import type { SendMessage } from '../../../types';
|
|
3
3
|
export declare const SendMessageContext: React.Context<SendMessage | undefined>;
|
|
4
4
|
export declare const SendMessageContextProvider: ({ children, handleSendMessage, }: {
|
|
5
5
|
children?: React.ReactNode;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { SuggestedPrompt } from '../types';
|
|
2
|
+
import type { SuggestedPrompt } from '../types';
|
|
3
3
|
type SuggestedPromptsContextProps = SuggestedPrompt[] | undefined;
|
|
4
4
|
export declare const SuggestedPromptsContext: React.Context<SuggestedPromptsContextProps>;
|
|
5
5
|
export declare const SuggestedPromptProvider: ({ children, suggestedPrompts, }: {
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
export { AIContextContext, AIContextProvider } from './AIContextContext';
|
|
2
2
|
export { ActionsContext, ActionsProvider } from './ActionsContext';
|
|
3
3
|
export { AvatarsContext, AvatarsProvider } from './AvatarsContext';
|
|
4
|
-
export { ConversationInputContextProps,
|
|
4
|
+
export type { ConversationInputContextProps, ConversationInput, } from './ConversationInputContext';
|
|
5
|
+
export { ConversationInputContext, ConversationInputContextProvider, } from './ConversationInputContext';
|
|
5
6
|
export { MessagesContext, RoleContext, MessagesProvider, } from './MessagesContext';
|
|
6
7
|
export { SuggestedPromptsContext, SuggestedPromptProvider, } from './SuggestedPromptsContext';
|
|
7
8
|
export { MessageVariantContext, MessageVariantProvider, } from './MessageVariantContext';
|
|
8
9
|
export { ConversationDisplayTextContext, useConversationDisplayText, ConversationDisplayTextProvider, } from './DisplayTextContext';
|
|
9
|
-
export {
|
|
10
|
+
export type { ControlsContextProps } from './ControlsContext';
|
|
11
|
+
export { ControlsContext, ControlsProvider } from './ControlsContext';
|
|
10
12
|
export { LoadingContextProvider } from './LoadingContext';
|
|
11
13
|
export { ResponseComponentsProvider, RESPONSE_COMPONENT_PREFIX, } from './ResponseComponentsContext';
|
|
12
14
|
export { SendMessageContextProvider } from './SendMessageContext';
|
|
13
15
|
export { MessageRendererProvider, MessageRendererContext, useMessageRenderer, } from './MessageRenderContext';
|
|
14
|
-
export {
|
|
16
|
+
export type { AttachmentContextProps } from './AttachmentContext';
|
|
17
|
+
export { AttachmentProvider, AttachmentContext } from './AttachmentContext';
|
|
15
18
|
export { WelcomeMessageContext, WelcomeMessageProvider, } from './WelcomeMessageContext';
|
|
16
19
|
export { FallbackComponentContext, FallbackComponentProvider, } from './FallbackComponentContext';
|
|
17
20
|
export * from './elements';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createAIConversation } from './createAIConversation';
|
|
2
2
|
import { AIConversation } from './AIConversation';
|
|
3
|
-
import { Avatars, CustomAction, SuggestedPrompt } from './types';
|
|
4
|
-
import { ResponseComponent } from '../../types';
|
|
5
|
-
export {
|
|
3
|
+
import type { Avatars, CustomAction, SuggestedPrompt } from './types';
|
|
4
|
+
import type { ResponseComponent } from '../../types';
|
|
5
|
+
export type { Avatars, CustomAction, ResponseComponent, SuggestedPrompt };
|
|
6
|
+
export { createAIConversation, AIConversation };
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { ActionsBarControl, AvatarControl, FormControl, MessagesControl, PromptControl } from './views';
|
|
3
|
-
import { DisplayTextTemplate } from '@aws-amplify/ui';
|
|
4
|
-
import { AIConversationDisplayText } from './displayText';
|
|
5
|
-
import { ConversationMessage, SendMessage, ResponseComponents, TextContentBlock, ImageContentBlock } from '../../types';
|
|
6
|
-
import { ControlsContextProps } from './context/ControlsContext';
|
|
7
|
-
import { AIConversationProviderProps } from './AIConversationProvider';
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { ActionsBarControl, AvatarControl, FormControl, MessagesControl, PromptControl } from './views';
|
|
3
|
+
import type { DisplayTextTemplate } from '@aws-amplify/ui';
|
|
4
|
+
import type { AIConversationDisplayText } from './displayText';
|
|
5
|
+
import type { ConversationMessage, SendMessage, ResponseComponents, TextContentBlock, ImageContentBlock } from '../../types';
|
|
6
|
+
import type { ControlsContextProps } from './context/ControlsContext';
|
|
7
|
+
import type { AIConversationProviderProps } from './AIConversationProvider';
|
|
8
8
|
export interface Controls {
|
|
9
9
|
Avatars: AvatarControl;
|
|
10
10
|
ActionsBar: ActionsBarControl;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ScrollViewProps } from '@aws-amplify/ui-react';
|
|
2
|
+
import type { ConversationMessage } from '../../types';
|
|
3
|
+
interface ConverationScrollProps extends Pick<ScrollViewProps, 'onScroll' | 'autoScroll'> {
|
|
4
|
+
}
|
|
5
|
+
export default function useConversationScrollProps(messages: ConversationMessage[]): ConverationScrollProps;
|
|
6
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ImageContentBlock, DocumentContentBlock } from '../../types';
|
|
1
|
+
import type { ImageContentBlock, DocumentContentBlock } from '../../types';
|
|
2
2
|
export declare function formatDate(date: Date): string;
|
|
3
3
|
export declare function convertBufferToBase64(buffer: ArrayBuffer, format: ImageContentBlock['format']): string;
|
|
4
4
|
export declare function getAttachmentFormat(file: File): string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { AIConversationElements } from '../../context/elements';
|
|
3
|
-
import { ConversationMessage } from '../../../../types';
|
|
3
|
+
import type { ConversationMessage } from '../../../../types';
|
|
4
4
|
export declare const ActionsBarControl: ActionsBarControl;
|
|
5
5
|
export interface ActionsBarControl {
|
|
6
6
|
(props: {
|
|
@@ -2,7 +2,7 @@ import React from 'react';
|
|
|
2
2
|
import { AIConversationElements } from '../../context/elements';
|
|
3
3
|
import { ActionsBarControl } from './ActionsBarControl';
|
|
4
4
|
import { AvatarControl } from './AvatarControl';
|
|
5
|
-
import { ConversationMessage } from '../../../../types';
|
|
5
|
+
import type { ConversationMessage } from '../../../../types';
|
|
6
6
|
export declare const DocumentContent: ({ format, name, source, }: NonNullable<ConversationMessage['content'][number]['document']>) => React.JSX.Element;
|
|
7
7
|
export declare const MessageControl: MessageControl;
|
|
8
8
|
interface MessageControl {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import { ConversationInputContextProps } from '../../context';
|
|
2
|
+
import type { ConversationInputContextProps } from '../../context';
|
|
3
3
|
export declare const Attachments: ({ files, setInput, }: {
|
|
4
4
|
files?: File[] | undefined;
|
|
5
5
|
setInput: ConversationInputContextProps['setInput'];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ControlsContextProps } from '../../context/ControlsContext';
|
|
1
|
+
import type { ControlsContextProps } from '../../context/ControlsContext';
|
|
2
2
|
export declare const Form: Required<ControlsContextProps>['Form'];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ControlsContextProps } from '../../context/ControlsContext';
|
|
1
|
+
import type { ControlsContextProps } from '../../context/ControlsContext';
|
|
2
2
|
export declare const MessageList: Required<ControlsContextProps>['MessageList'];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ControlsContextProps } from '../../context/ControlsContext';
|
|
1
|
+
import type { ControlsContextProps } from '../../context/ControlsContext';
|
|
2
2
|
export declare const PromptList: Required<ControlsContextProps>['PromptList'];
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { ConversationMessage, ConversationStreamEvent } from '../types';
|
|
1
|
+
import type { ConversationMessage, ConversationStreamEvent } from '../types';
|
|
2
2
|
export declare const contentFromEvents: (contentBlocks?: ConversationStreamEvent[][]) => ConversationMessage['content'];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { UseAIGenerationHookWrapper } from './useAIGeneration';
|
|
2
|
-
import { UseAIConversationHook } from './useAIConversation';
|
|
3
|
-
import { getSchema } from '../types';
|
|
1
|
+
import type { UseAIGenerationHookWrapper } from './useAIGeneration';
|
|
2
|
+
import type { UseAIConversationHook } from './useAIConversation';
|
|
3
|
+
import type { getSchema } from '../types';
|
|
4
4
|
type UseAIHooks<Client extends Record<'generations' | 'conversations', Record<string, any>>, Schema extends Record<any, any>> = {
|
|
5
5
|
useAIConversation: UseAIConversationHook<Extract<keyof Client['conversations'], string>>;
|
|
6
6
|
} & UseAIGenerationHookWrapper<keyof Client['generations'], Schema>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Conversation, ConversationMessage, ConversationRoute, SendMessage } from '../types';
|
|
2
|
-
import { AiClientState } from './shared';
|
|
1
|
+
import type { Conversation, ConversationMessage, ConversationRoute, SendMessage } from '../types';
|
|
2
|
+
import type { AiClientState } from './shared';
|
|
3
3
|
interface UseAIConversationInput {
|
|
4
4
|
id?: string;
|
|
5
5
|
onMessage?: (message: ConversationMessage) => void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ClientExtensions } from '@aws-amplify/data-schema/runtime';
|
|
2
|
-
import { getSchema } from '../types';
|
|
3
|
-
import { AiClientState } from './shared';
|
|
2
|
+
import type { getSchema } from '../types';
|
|
3
|
+
import type { AiClientState } from './shared';
|
|
4
4
|
export interface UseAIGenerationHookWrapper<Key extends keyof AIGenerationClient<Schema>['generations'], Schema extends Record<any, any>> {
|
|
5
5
|
useAIGeneration: <U extends Key>(routeName: U) => [
|
|
6
6
|
Awaited<AiClientState<Schema[U]['returnType']>>,
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export type { Avatars, CustomAction, ResponseComponent, SuggestedPrompt, } from './components';
|
|
2
|
+
export { createAIConversation, AIConversation } from './components';
|
|
2
3
|
export { createAIHooks } from './hooks';
|
|
3
|
-
export { ConversationMessage, ConversationMessageContent, SendMessage, SendMesageParameters, } from './types';
|
|
4
|
+
export type { ConversationMessage, ConversationMessageContent, SendMessage, SendMesageParameters, } from './types';
|
package/dist/types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.5.1";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aws-amplify/ui-react-ai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "dist/esm/index.mjs",
|
|
6
6
|
"exports": {
|
|
@@ -48,9 +48,9 @@
|
|
|
48
48
|
"react-dom": "^16.14 || ^17 || ^18 || ^19"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@aws-amplify/ui": "^6.
|
|
52
|
-
"@aws-amplify/ui-react": "^6.
|
|
53
|
-
"@aws-amplify/ui-react-core": "^3.
|
|
51
|
+
"@aws-amplify/ui": "^6.15.2",
|
|
52
|
+
"@aws-amplify/ui-react": "^6.15.2",
|
|
53
|
+
"@aws-amplify/ui-react-core": "^3.6.2"
|
|
54
54
|
},
|
|
55
55
|
"size-limit": [
|
|
56
56
|
{
|