@aws-amplify/ui-react-ai 0.1.0 → 0.2.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.
Files changed (26) hide show
  1. package/dist/esm/components/AIConversation/AIConversation.mjs +2 -1
  2. package/dist/esm/components/AIConversation/context/DisplayTextContext.mjs +9 -0
  3. package/dist/esm/components/AIConversation/context/ResponseComponentsContext.mjs +10 -2
  4. package/dist/esm/components/AIConversation/createAIConversation.mjs +2 -1
  5. package/dist/esm/components/AIConversation/createProvider.mjs +19 -11
  6. package/dist/esm/components/AIConversation/displayText.mjs +7 -0
  7. package/dist/esm/components/AIConversation/views/Controls/ActionsBarControl.mjs +5 -0
  8. package/dist/esm/components/AIConversation/views/Controls/AttachFileControl.mjs +5 -0
  9. package/dist/esm/components/AIConversation/views/Controls/AttachmentListControl.mjs +5 -0
  10. package/dist/esm/components/AIConversation/views/Controls/AvatarControl.mjs +5 -0
  11. package/dist/esm/components/AIConversation/views/Controls/FieldControl.mjs +6 -5
  12. package/dist/esm/components/AIConversation/views/Controls/MessagesControl.mjs +15 -6
  13. package/dist/esm/components/AIConversation/views/Controls/PromptControl.mjs +5 -1
  14. package/dist/esm/components/AIConversation/views/default/Form.mjs +5 -2
  15. package/dist/esm/components/AIConversation/views/default/MessageList.mjs +25 -3
  16. package/dist/index.js +155 -104
  17. package/dist/types/components/AIConversation/AIConversation.d.ts +4 -4
  18. package/dist/types/components/AIConversation/context/DisplayTextContext.d.ts +5 -0
  19. package/dist/types/components/AIConversation/context/ResponseComponentsContext.d.ts +1 -0
  20. package/dist/types/components/AIConversation/context/index.d.ts +11 -7
  21. package/dist/types/components/AIConversation/createProvider.d.ts +2 -2
  22. package/dist/types/components/AIConversation/displayText.d.ts +2 -2
  23. package/dist/types/components/AIConversation/index.d.ts +2 -1
  24. package/dist/types/components/AIConversation/views/default/Form.d.ts +1 -1
  25. package/dist/types/index.d.ts +3 -3
  26. package/package.json +4 -4
@@ -14,7 +14,7 @@ import { PromptList } from './views/default/PromptList.mjs';
14
14
  import { ComponentClassName } from '@aws-amplify/ui';
15
15
  import createProvider from './createProvider.mjs';
16
16
 
17
- function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, }) {
17
+ function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, }) {
18
18
  const icons = useIcons('aiConversation');
19
19
  const defaultAvatars = {
20
20
  ai: {
@@ -42,6 +42,7 @@ function AIConversationBase({ actions, avatars, controls, handleSendMessage, mes
42
42
  Form,
43
43
  ...controls,
44
44
  },
45
+ displayText,
45
46
  });
46
47
  const providerProps = {
47
48
  messages,
@@ -0,0 +1,9 @@
1
+ import { createContextUtilities } from '@aws-amplify/ui-react-core';
2
+ import { defaultAIConversationDisplayTextEn } from '../displayText.mjs';
3
+
4
+ const { ConversationDisplayTextContext, ConversationDisplayTextProvider, useConversationDisplayText, } = createContextUtilities({
5
+ contextName: 'ConversationDisplayText',
6
+ defaultValue: defaultAIConversationDisplayTextEn,
7
+ });
8
+
9
+ export { ConversationDisplayTextContext, ConversationDisplayTextProvider, useConversationDisplayText };
@@ -1,8 +1,16 @@
1
1
  import React__default from 'react';
2
2
 
3
+ const RESPONSE_COMPONENT_PREFIX = 'AMPLIFY_UI_';
3
4
  const ResponseComponentsContext = React__default.createContext(undefined);
5
+ const prependResponseComponents = (responseComponents) => {
6
+ if (!responseComponents)
7
+ return responseComponents;
8
+ return Object.keys(responseComponents).reduce((prev, key) => ((prev[`${RESPONSE_COMPONENT_PREFIX}${key}`] = responseComponents[key]),
9
+ prev), {});
10
+ };
4
11
  const ResponseComponentsProvider = ({ children, responseComponents, }) => {
5
- return (React__default.createElement(ResponseComponentsContext.Provider, { value: responseComponents }, children));
12
+ const _responseComponents = React__default.useMemo(() => prependResponseComponents(responseComponents), [responseComponents]);
13
+ return (React__default.createElement(ResponseComponentsContext.Provider, { value: _responseComponents }, children));
6
14
  };
7
15
  const convertResponseComponentsToToolConfiguration = (responseComponents) => {
8
16
  if (!responseComponents) {
@@ -32,4 +40,4 @@ const convertResponseComponentsToToolConfiguration = (responseComponents) => {
32
40
  return { tools };
33
41
  };
34
42
 
35
- export { ResponseComponentsContext, ResponseComponentsProvider, convertResponseComponentsToToolConfiguration };
43
+ export { RESPONSE_COMPONENT_PREFIX, ResponseComponentsContext, ResponseComponentsProvider, convertResponseComponentsToToolConfiguration };
@@ -12,7 +12,7 @@ import createProvider from './createProvider.mjs';
12
12
  * @experimental
13
13
  */
14
14
  function createAIConversation(input = {}) {
15
- const { elements, suggestedPrompts, actions, responseComponents, variant, controls, } = input;
15
+ const { elements, suggestedPrompts, actions, responseComponents, variant, controls, displayText, } = input;
16
16
  const Provider = createProvider({
17
17
  elements,
18
18
  actions,
@@ -20,6 +20,7 @@ function createAIConversation(input = {}) {
20
20
  responseComponents,
21
21
  variant,
22
22
  controls,
23
+ displayText,
23
24
  });
24
25
  function AIConversation(props) {
25
26
  const { messages, avatars, handleSendMessage, isLoading } = props;
@@ -1,29 +1,37 @@
1
1
  import React__default from 'react';
2
2
  import { ElementsProvider } from '@aws-amplify/ui-react-core/elements';
3
+ import { defaultAIConversationDisplayTextEn } from './displayText.mjs';
3
4
  import { ActionsProvider } from './context/ActionsContext.mjs';
4
5
  import { AvatarsProvider } from './context/AvatarsContext.mjs';
5
6
  import { ConversationInputContextProvider } from './context/ConversationInputContext.mjs';
6
7
  import { MessagesProvider } from './context/MessagesContext.mjs';
7
- import { MessageVariantProvider } from './context/MessageVariantContext.mjs';
8
8
  import { SuggestedPromptProvider } from './context/SuggestedPromptsContext.mjs';
9
- import { ResponseComponentsProvider } from './context/ResponseComponentsContext.mjs';
10
- import { SendMessageContextProvider } from './context/SendMessageContext.mjs';
9
+ import { MessageVariantProvider } from './context/MessageVariantContext.mjs';
10
+ import { ConversationDisplayTextProvider } from './context/DisplayTextContext.mjs';
11
11
  import { ControlsProvider } from './context/ControlsContext.mjs';
12
12
  import { LoadingContextProvider } from './context/LoadingContext.mjs';
13
+ import { ResponseComponentsProvider } from './context/ResponseComponentsContext.mjs';
14
+ import { SendMessageContextProvider } from './context/SendMessageContext.mjs';
15
+ import './context/elements/definitions.mjs';
13
16
 
14
- function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, }) {
17
+ function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, }) {
15
18
  return function Provider({ children, messages, avatars, handleSendMessage, isLoading, }) {
19
+ const _displayText = {
20
+ ...defaultAIConversationDisplayTextEn,
21
+ ...displayText,
22
+ };
16
23
  return (React__default.createElement(ElementsProvider, { elements: elements },
17
24
  React__default.createElement(ControlsProvider, { controls: controls },
18
25
  React__default.createElement(SuggestedPromptProvider, { suggestedPrompts: suggestedPrompts },
19
26
  React__default.createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
20
- React__default.createElement(ConversationInputContextProvider, null,
21
- React__default.createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
22
- React__default.createElement(AvatarsProvider, { avatars: avatars },
23
- React__default.createElement(ActionsProvider, { actions: actions },
24
- React__default.createElement(MessageVariantProvider, { variant: variant },
25
- React__default.createElement(MessagesProvider, { messages: messages },
26
- React__default.createElement(LoadingContextProvider, { isLoading: isLoading }, children))))))))))));
27
+ React__default.createElement(ConversationDisplayTextProvider, { ..._displayText },
28
+ React__default.createElement(ConversationInputContextProvider, null,
29
+ React__default.createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
30
+ React__default.createElement(AvatarsProvider, { avatars: avatars },
31
+ React__default.createElement(ActionsProvider, { actions: actions },
32
+ React__default.createElement(MessageVariantProvider, { variant: variant },
33
+ React__default.createElement(MessagesProvider, { messages: messages },
34
+ React__default.createElement(LoadingContextProvider, { isLoading: isLoading }, children)))))))))))));
27
35
  };
28
36
  }
29
37
 
@@ -0,0 +1,7 @@
1
+ import { formatDate } from './utils.mjs';
2
+
3
+ const defaultAIConversationDisplayTextEn = {
4
+ getMessageTimestampText: (date) => formatDate(date),
5
+ };
6
+
7
+ export { defaultAIConversationDisplayTextEn };
@@ -6,6 +6,11 @@ import '../../context/ConversationInputContext.mjs';
6
6
  import '../../context/MessagesContext.mjs';
7
7
  import '../../context/SuggestedPromptsContext.mjs';
8
8
  import '../../context/MessageVariantContext.mjs';
9
+ import '../../context/DisplayTextContext.mjs';
10
+ import '../../context/ControlsContext.mjs';
11
+ import '../../context/LoadingContext.mjs';
12
+ import '../../context/ResponseComponentsContext.mjs';
13
+ import '../../context/SendMessageContext.mjs';
9
14
  import { AIConversationElements } from '../../context/elements/definitions.mjs';
10
15
 
11
16
  const { Button, Span, View } = AIConversationElements;
@@ -6,6 +6,11 @@ import { ConversationInputContext } from '../../context/ConversationInputContext
6
6
  import '../../context/MessagesContext.mjs';
7
7
  import '../../context/SuggestedPromptsContext.mjs';
8
8
  import '../../context/MessageVariantContext.mjs';
9
+ import '../../context/DisplayTextContext.mjs';
10
+ import '../../context/ControlsContext.mjs';
11
+ import '../../context/LoadingContext.mjs';
12
+ import '../../context/ResponseComponentsContext.mjs';
13
+ import '../../context/SendMessageContext.mjs';
9
14
  import { AIConversationElements } from '../../context/elements/definitions.mjs';
10
15
 
11
16
  const { Button, Icon, View } = AIConversationElements;
@@ -6,6 +6,11 @@ import { ConversationInputContext } from '../../context/ConversationInputContext
6
6
  import '../../context/MessagesContext.mjs';
7
7
  import '../../context/SuggestedPromptsContext.mjs';
8
8
  import '../../context/MessageVariantContext.mjs';
9
+ import '../../context/DisplayTextContext.mjs';
10
+ import '../../context/ControlsContext.mjs';
11
+ import '../../context/LoadingContext.mjs';
12
+ import '../../context/ResponseComponentsContext.mjs';
13
+ import '../../context/SendMessageContext.mjs';
9
14
  import { AIConversationElements } from '../../context/elements/definitions.mjs';
10
15
 
11
16
  const { Button, Icon, ListItem, UnorderedList: ListElement, Span, Text, View, } = AIConversationElements;
@@ -6,6 +6,11 @@ import '../../context/ConversationInputContext.mjs';
6
6
  import { RoleContext } from '../../context/MessagesContext.mjs';
7
7
  import '../../context/SuggestedPromptsContext.mjs';
8
8
  import '../../context/MessageVariantContext.mjs';
9
+ import '../../context/DisplayTextContext.mjs';
10
+ import '../../context/ControlsContext.mjs';
11
+ import '../../context/LoadingContext.mjs';
12
+ import '../../context/ResponseComponentsContext.mjs';
13
+ import '../../context/SendMessageContext.mjs';
9
14
  import { AIConversationElements } from '../../context/elements/definitions.mjs';
10
15
 
11
16
  const { Icon, Span, Text, View } = AIConversationElements;
@@ -6,14 +6,15 @@ import { ConversationInputContext } from '../../context/ConversationInputContext
6
6
  import { MessagesContext } from '../../context/MessagesContext.mjs';
7
7
  import '../../context/SuggestedPromptsContext.mjs';
8
8
  import '../../context/MessageVariantContext.mjs';
9
+ import '../../context/DisplayTextContext.mjs';
10
+ import { ControlsContext } from '../../context/ControlsContext.mjs';
11
+ import { LoadingContext } from '../../context/LoadingContext.mjs';
12
+ import { ResponseComponentsContext, convertResponseComponentsToToolConfiguration } from '../../context/ResponseComponentsContext.mjs';
13
+ import { SendMessageContext } from '../../context/SendMessageContext.mjs';
9
14
  import { AIConversationElements } from '../../context/elements/definitions.mjs';
10
15
  import { AttachFileControl } from './AttachFileControl.mjs';
11
16
  import { AttachmentListControl } from './AttachmentListControl.mjs';
12
- import { SendMessageContext } from '../../context/SendMessageContext.mjs';
13
- import { ResponseComponentsContext, convertResponseComponentsToToolConfiguration } from '../../context/ResponseComponentsContext.mjs';
14
- import { ControlsContext } from '../../context/ControlsContext.mjs';
15
17
  import { getImageTypeFromMimeType } from '../../utils.mjs';
16
- import { LoadingContext } from '../../context/LoadingContext.mjs';
17
18
 
18
19
  const { Button, Icon, Label: LabelElement, TextArea, View, } = AIConversationElements;
19
20
  const FIELD_BLOCK = 'ai-field';
@@ -116,7 +117,7 @@ const FieldControl = () => {
116
117
  const fileContent = {
117
118
  image: {
118
119
  format: getImageTypeFromMimeType(file.type),
119
- source: { bytes: Uint8Array.from(Buffer.from(buffer)) },
120
+ source: { bytes: new Uint8Array(buffer) },
120
121
  },
121
122
  };
122
123
  submittedContent.push(fileContent);
@@ -6,12 +6,15 @@ import '../../context/ConversationInputContext.mjs';
6
6
  import { RoleContext, MessagesContext } from '../../context/MessagesContext.mjs';
7
7
  import '../../context/SuggestedPromptsContext.mjs';
8
8
  import { MessageVariantContext } from '../../context/MessageVariantContext.mjs';
9
+ import { useConversationDisplayText } from '../../context/DisplayTextContext.mjs';
10
+ import { ControlsContext } from '../../context/ControlsContext.mjs';
11
+ import '../../context/LoadingContext.mjs';
12
+ import { ResponseComponentsContext, RESPONSE_COMPONENT_PREFIX } from '../../context/ResponseComponentsContext.mjs';
13
+ import '../../context/SendMessageContext.mjs';
9
14
  import { AIConversationElements } from '../../context/elements/definitions.mjs';
10
- import { convertBufferToBase64, formatDate } from '../../utils.mjs';
15
+ import { convertBufferToBase64 } from '../../utils.mjs';
11
16
  import { ActionsBarControl } from './ActionsBarControl.mjs';
12
17
  import { AvatarControl } from './AvatarControl.mjs';
13
- import { ResponseComponentsContext } from '../../context/ResponseComponentsContext.mjs';
14
- import { ControlsContext } from '../../context/ControlsContext.mjs';
15
18
 
16
19
  const { Image, Span, Text, View } = AIConversationElements;
17
20
  const MESSAGES_BLOCK = 'ai-messages';
@@ -43,7 +46,9 @@ const MessageControl = ({ message }) => {
43
46
  else if (content.toolUse) {
44
47
  // For now tool use is limited to custom response components
45
48
  const { name, input } = content.toolUse;
46
- if (!responseComponents || !name) {
49
+ if (!responseComponents ||
50
+ !name ||
51
+ !name.startsWith(RESPONSE_COMPONENT_PREFIX)) {
47
52
  return;
48
53
  }
49
54
  else {
@@ -81,6 +86,7 @@ const Layout = React__default.forwardRef(function Layout(props, ref) {
81
86
  const MessagesControl = ({ renderMessage }) => {
82
87
  const messages = React__default.useContext(MessagesContext);
83
88
  const controls = React__default.useContext(ControlsContext);
89
+ const { getMessageTimestampText } = useConversationDisplayText();
84
90
  const messagesRef = React__default.useRef([]);
85
91
  const [focusedItemIndex, setFocusedItemIndex] = React__default.useState(messages ? messages.length - 1 : 0);
86
92
  const handleFocus = (index) => setFocusedItemIndex(index);
@@ -113,13 +119,16 @@ const MessagesControl = ({ renderMessage }) => {
113
119
  if (controls?.MessageList) {
114
120
  return React__default.createElement(controls.MessageList, { messages: messages });
115
121
  }
116
- return (React__default.createElement(Layout, null, messages?.map((message, index) => {
122
+ const messagesWithRenderableContent = messages?.filter((message) => message.content.some((content) => content.image ??
123
+ content.text ??
124
+ content.toolUse?.name.startsWith(RESPONSE_COMPONENT_PREFIX))) ?? [];
125
+ return (React__default.createElement(Layout, null, messagesWithRenderableContent?.map((message, index) => {
117
126
  return renderMessage ? (renderMessage(message)) : (React__default.createElement(RoleContext.Provider, { value: message.role, key: `message-${index}` },
118
127
  React__default.createElement(MessageContainer, { "data-testid": `message`, key: `message-${index}`, tabIndex: focusedItemIndex === index ? 0 : -1, onFocus: () => handleFocus(index), onKeyDown: (event) => onKeyDown(index, event), ref: (el) => (messagesRef.current[index] = el) },
119
128
  React__default.createElement(HeaderContainer, null,
120
129
  React__default.createElement(AvatarControl, null),
121
130
  React__default.createElement(Separator, null),
122
- React__default.createElement(Timestamp, null, formatDate(new Date(message.createdAt)))),
131
+ React__default.createElement(Timestamp, null, getMessageTimestampText(new Date(message.createdAt)))),
123
132
  React__default.createElement(MessageControl, { message: message }),
124
133
  message.role === 'assistant' ? (React__default.createElement(ActionsBarControl, { message: message, focusable: focusedItemIndex === index })) : null)));
125
134
  })));
@@ -6,9 +6,13 @@ import { ConversationInputContext } from '../../context/ConversationInputContext
6
6
  import { MessagesContext } from '../../context/MessagesContext.mjs';
7
7
  import { SuggestedPromptsContext } from '../../context/SuggestedPromptsContext.mjs';
8
8
  import '../../context/MessageVariantContext.mjs';
9
+ import '../../context/DisplayTextContext.mjs';
10
+ import { ControlsContext } from '../../context/ControlsContext.mjs';
11
+ import '../../context/LoadingContext.mjs';
12
+ import '../../context/ResponseComponentsContext.mjs';
13
+ import '../../context/SendMessageContext.mjs';
9
14
  import { AIConversationElements } from '../../context/elements/definitions.mjs';
10
15
  import { classNames } from '@aws-amplify/ui';
11
- import { ControlsContext } from '../../context/ControlsContext.mjs';
12
16
 
13
17
  const { View, Button, Text, Heading, Icon } = AIConversationElements;
14
18
  const PROMPT_BLOCK = 'ai-prompts';
@@ -24,6 +24,9 @@ const Form = ({ setInput, input, handleSubmit, }) => {
24
24
  React.createElement(View, { as: "form", className: ComponentClassName.AIConversationForm, onSubmit: handleSubmit },
25
25
  React.createElement(Button, { className: ComponentClassName.AIConversationFormAttach, onClick: () => {
26
26
  hiddenInput?.current?.click();
27
+ if (hiddenInput?.current) {
28
+ hiddenInput.current.value = '';
29
+ }
27
30
  } },
28
31
  React.createElement("span", null, attachIcon),
29
32
  React.createElement(VisuallyHidden, null,
@@ -36,8 +39,8 @@ const Form = ({ setInput, input, handleSubmit, }) => {
36
39
  ...prevValue,
37
40
  files: [...(prevValue?.files ?? []), ...Array.from(files)],
38
41
  }));
39
- }, multiple: true, accept: "*" }))),
40
- React.createElement(TextAreaField, { className: ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', onKeyDown: (e) => {
42
+ }, multiple: true, accept: "*", "data-testid": "hidden-file-input" }))),
43
+ React.createElement(TextAreaField, { className: ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', testId: "text-input", onKeyDown: (e) => {
41
44
  // Submit on enter key if shift is not pressed also
42
45
  const shouldSubmit = !e.shiftKey && e.key === 'Enter';
43
46
  if (shouldSubmit && isHTMLFormElement(e.target)) {
@@ -7,19 +7,35 @@ import '../../context/ConversationInputContext.mjs';
7
7
  import { RoleContext } from '../../context/MessagesContext.mjs';
8
8
  import '../../context/SuggestedPromptsContext.mjs';
9
9
  import { MessageVariantContext } from '../../context/MessageVariantContext.mjs';
10
+ import { useConversationDisplayText } from '../../context/DisplayTextContext.mjs';
11
+ import '../../context/ControlsContext.mjs';
12
+ import { LoadingContext } from '../../context/LoadingContext.mjs';
13
+ import { RESPONSE_COMPONENT_PREFIX } from '../../context/ResponseComponentsContext.mjs';
14
+ import '../../context/SendMessageContext.mjs';
10
15
  import '../../context/elements/definitions.mjs';
11
- import { formatDate } from '../../utils.mjs';
12
16
  import { ComponentClassName, classNames, classNameModifier } from '@aws-amplify/ui';
13
17
 
14
18
  const MessageMeta = ({ message }) => {
15
19
  // need to pass this in as props in order for it to be overridable
16
20
  const avatars = React.useContext(AvatarsContext);
17
21
  const role = React.useContext(RoleContext);
22
+ const { getMessageTimestampText } = useConversationDisplayText();
18
23
  // maybe rename 'avatar' to something else
19
24
  const avatar = role === 'assistant' ? avatars?.ai : avatars?.user;
20
25
  return (React.createElement(View, { className: ComponentClassName.AIConversationMessageSender },
21
26
  React.createElement(Text, { className: ComponentClassName.AIConversationMessageSenderUsername }, avatar?.username),
22
- React.createElement(Text, { className: ComponentClassName.AIConversationMessageSenderTimestamp }, formatDate(new Date(message.createdAt)))));
27
+ React.createElement(Text, { className: ComponentClassName.AIConversationMessageSenderTimestamp }, getMessageTimestampText(new Date(message.createdAt)))));
28
+ };
29
+ const LoadingMessage = () => {
30
+ const avatars = React.useContext(AvatarsContext);
31
+ const variant = React.useContext(MessageVariantContext);
32
+ const avatar = avatars?.ai;
33
+ return (React.createElement(View, { className: classNames(ComponentClassName.AIConversationMessage, classNameModifier(ComponentClassName.AIConversationMessage, variant), classNameModifier(ComponentClassName.AIConversationMessage, 'assistant')) },
34
+ React.createElement(View, { className: ComponentClassName.AIConversationMessageAvatar },
35
+ React.createElement(Avatar, { isLoading: true }, avatar?.avatar)),
36
+ React.createElement(View, { className: ComponentClassName.AIConversationMessageBody },
37
+ React.createElement(View, { className: ComponentClassName.AIConversationMessageSender },
38
+ React.createElement(Text, { className: ComponentClassName.AIConversationMessageSenderUsername }, avatar?.username)))));
23
39
  };
24
40
  const Message = ({ message }) => {
25
41
  const avatars = React.useContext(AvatarsContext);
@@ -35,7 +51,13 @@ const Message = ({ message }) => {
35
51
  React.createElement(MessageControl, { message: message }))))));
36
52
  };
37
53
  const MessageList = ({ messages, }) => {
38
- return (React.createElement(View, { className: ComponentClassName.AIConversationMessageList }, messages.map((message, i) => (React.createElement(Message, { key: `message-${i}`, message: message })))));
54
+ const isLoading = React.useContext(LoadingContext);
55
+ const messagesWithRenderableContent = messages?.filter((message) => message.content.some((content) => content.image ??
56
+ content.text ??
57
+ content.toolUse?.name.startsWith(RESPONSE_COMPONENT_PREFIX))) ?? [];
58
+ return (React.createElement(View, { className: ComponentClassName.AIConversationMessageList },
59
+ messagesWithRenderableContent.map((message, i) => (React.createElement(Message, { key: `message-${i}`, message: message }))),
60
+ isLoading ? React.createElement(LoadingMessage, null) : null));
39
61
  };
40
62
 
41
63
  export { MessageList };
package/dist/index.js CHANGED
@@ -4,10 +4,10 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var React = require('react');
6
6
  var elements = require('@aws-amplify/ui-react-core/elements');
7
+ var uiReactCore = require('@aws-amplify/ui-react-core');
7
8
  var ui = require('@aws-amplify/ui');
8
9
  var uiReact = require('@aws-amplify/ui-react');
9
10
  var internal = require('@aws-amplify/ui-react/internal');
10
- var uiReactCore = require('@aws-amplify/ui-react-core');
11
11
 
12
12
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
13
13
 
@@ -154,6 +154,108 @@ const MessageVariantProvider = ({ children, variant, }) => {
154
154
  return (React__default["default"].createElement(MessageVariantContext.Provider, { value: variant }, children));
155
155
  };
156
156
 
157
+ function formatDate(date) {
158
+ const dateString = date.toLocaleDateString('en-US', {
159
+ weekday: 'short',
160
+ month: 'short',
161
+ day: 'numeric',
162
+ });
163
+ const timeString = date.toLocaleTimeString('en-US', {
164
+ hour: 'numeric',
165
+ minute: 'numeric',
166
+ hour12: true,
167
+ });
168
+ return `${dateString} at ${timeString}`;
169
+ }
170
+ function arrayBufferToBase64(buffer) {
171
+ let binary = '';
172
+ const bytes = new Uint8Array(buffer);
173
+ const len = bytes.byteLength;
174
+ for (let i = 0; i < len; i++) {
175
+ binary += String.fromCharCode(bytes[i]);
176
+ }
177
+ return window.btoa(binary);
178
+ }
179
+ function convertBufferToBase64(buffer, format) {
180
+ let base64string = '';
181
+ // Use node-based buffer if available
182
+ // fall back on browser if not
183
+ if (typeof Buffer !== 'undefined') {
184
+ base64string = Buffer.from(new Uint8Array(buffer)).toString('base64');
185
+ }
186
+ else {
187
+ base64string = arrayBufferToBase64(buffer);
188
+ }
189
+ return `data:image/${format};base64,${base64string}`;
190
+ }
191
+ function getImageTypeFromMimeType(mimeType) {
192
+ return mimeType.split('/')[1];
193
+ }
194
+
195
+ const defaultAIConversationDisplayTextEn = {
196
+ getMessageTimestampText: (date) => formatDate(date),
197
+ };
198
+
199
+ const { ConversationDisplayTextContext, ConversationDisplayTextProvider, useConversationDisplayText, } = uiReactCore.createContextUtilities({
200
+ contextName: 'ConversationDisplayText',
201
+ defaultValue: defaultAIConversationDisplayTextEn,
202
+ });
203
+
204
+ const ControlsContext = React__default["default"].createContext(undefined);
205
+ const ControlsProvider = ({ children, controls, }) => {
206
+ return (React__default["default"].createElement(ControlsContext.Provider, { value: controls }, children));
207
+ };
208
+
209
+ const LoadingContext = React__default["default"].createContext(undefined);
210
+ const LoadingContextProvider = ({ children, isLoading, }) => {
211
+ return (React__default["default"].createElement(LoadingContext.Provider, { value: isLoading }, children));
212
+ };
213
+
214
+ const RESPONSE_COMPONENT_PREFIX = 'AMPLIFY_UI_';
215
+ const ResponseComponentsContext = React__default["default"].createContext(undefined);
216
+ const prependResponseComponents = (responseComponents) => {
217
+ if (!responseComponents)
218
+ return responseComponents;
219
+ return Object.keys(responseComponents).reduce((prev, key) => ((prev[`${RESPONSE_COMPONENT_PREFIX}${key}`] = responseComponents[key]),
220
+ prev), {});
221
+ };
222
+ const ResponseComponentsProvider = ({ children, responseComponents, }) => {
223
+ const _responseComponents = React__default["default"].useMemo(() => prependResponseComponents(responseComponents), [responseComponents]);
224
+ return (React__default["default"].createElement(ResponseComponentsContext.Provider, { value: _responseComponents }, children));
225
+ };
226
+ const convertResponseComponentsToToolConfiguration = (responseComponents) => {
227
+ if (!responseComponents) {
228
+ return;
229
+ }
230
+ const tools = {};
231
+ Object.keys(responseComponents).forEach((toolName) => {
232
+ const { props } = responseComponents[toolName];
233
+ const requiredProps = [];
234
+ Object.keys(props).forEach((propName) => {
235
+ if (props[propName].required)
236
+ requiredProps.push(propName);
237
+ });
238
+ tools[toolName] = {
239
+ description: responseComponents[toolName].description,
240
+ inputSchema: {
241
+ json: {
242
+ type: 'object',
243
+ required: requiredProps,
244
+ properties: {
245
+ ...props,
246
+ },
247
+ },
248
+ },
249
+ };
250
+ });
251
+ return { tools };
252
+ };
253
+
254
+ const SendMessageContext = React__default["default"].createContext(undefined);
255
+ const SendMessageContextProvider = ({ children, handleSendMessage, }) => {
256
+ return (React__default["default"].createElement(SendMessageContext.Provider, { value: handleSendMessage }, children));
257
+ };
258
+
157
259
  const { Button: Button$5, Span: Span$3, View: View$7 } = AIConversationElements;
158
260
  const ACTIONS_BAR_BLOCK = 'ai-actions-bar';
159
261
  const ActionIcon = elements.withBaseElementProps(Span$3, {
@@ -370,91 +472,6 @@ const AttachmentListControl = () => {
370
472
  AttachmentListControl.List = UnorderedList;
371
473
  AttachmentListControl.Item = AttachmentControl;
372
474
 
373
- const SendMessageContext = React__default["default"].createContext(undefined);
374
- const SendMessageContextProvider = ({ children, handleSendMessage, }) => {
375
- return (React__default["default"].createElement(SendMessageContext.Provider, { value: handleSendMessage }, children));
376
- };
377
-
378
- const ResponseComponentsContext = React__default["default"].createContext(undefined);
379
- const ResponseComponentsProvider = ({ children, responseComponents, }) => {
380
- return (React__default["default"].createElement(ResponseComponentsContext.Provider, { value: responseComponents }, children));
381
- };
382
- const convertResponseComponentsToToolConfiguration = (responseComponents) => {
383
- if (!responseComponents) {
384
- return;
385
- }
386
- const tools = {};
387
- Object.keys(responseComponents).forEach((toolName) => {
388
- const { props } = responseComponents[toolName];
389
- const requiredProps = [];
390
- Object.keys(props).forEach((propName) => {
391
- if (props[propName].required)
392
- requiredProps.push(propName);
393
- });
394
- tools[toolName] = {
395
- description: responseComponents[toolName].description,
396
- inputSchema: {
397
- json: {
398
- type: 'object',
399
- required: requiredProps,
400
- properties: {
401
- ...props,
402
- },
403
- },
404
- },
405
- };
406
- });
407
- return { tools };
408
- };
409
-
410
- const ControlsContext = React__default["default"].createContext(undefined);
411
- const ControlsProvider = ({ children, controls, }) => {
412
- return (React__default["default"].createElement(ControlsContext.Provider, { value: controls }, children));
413
- };
414
-
415
- function formatDate(date) {
416
- const dateString = date.toLocaleDateString('en-US', {
417
- weekday: 'short',
418
- month: 'short',
419
- day: 'numeric',
420
- });
421
- const timeString = date.toLocaleTimeString('en-US', {
422
- hour: 'numeric',
423
- minute: 'numeric',
424
- hour12: true,
425
- });
426
- return `${dateString} at ${timeString}`;
427
- }
428
- function arrayBufferToBase64(buffer) {
429
- let binary = '';
430
- const bytes = new Uint8Array(buffer);
431
- const len = bytes.byteLength;
432
- for (let i = 0; i < len; i++) {
433
- binary += String.fromCharCode(bytes[i]);
434
- }
435
- return window.btoa(binary);
436
- }
437
- function convertBufferToBase64(buffer, format) {
438
- let base64string = '';
439
- // Use node-based buffer if available
440
- // fall back on browser if not
441
- if (typeof Buffer !== 'undefined') {
442
- base64string = Buffer.from(new Uint8Array(buffer)).toString('base64');
443
- }
444
- else {
445
- base64string = arrayBufferToBase64(buffer);
446
- }
447
- return `data:image/${format};base64,${base64string}`;
448
- }
449
- function getImageTypeFromMimeType(mimeType) {
450
- return mimeType.split('/')[1];
451
- }
452
-
453
- const LoadingContext = React__default["default"].createContext(undefined);
454
- const LoadingContextProvider = ({ children, isLoading, }) => {
455
- return (React__default["default"].createElement(LoadingContext.Provider, { value: isLoading }, children));
456
- };
457
-
458
475
  const { Button: Button$1, Icon: Icon$1, Label: LabelElement, TextArea, View: View$2, } = AIConversationElements;
459
476
  const FIELD_BLOCK = 'ai-field';
460
477
  const SendIcon = elements.withBaseElementProps(Icon$1, {
@@ -556,7 +573,7 @@ const FieldControl = () => {
556
573
  const fileContent = {
557
574
  image: {
558
575
  format: getImageTypeFromMimeType(file.type),
559
- source: { bytes: Uint8Array.from(Buffer.from(buffer)) },
576
+ source: { bytes: new Uint8Array(buffer) },
560
577
  },
561
578
  };
562
579
  submittedContent.push(fileContent);
@@ -635,7 +652,9 @@ const MessageControl = ({ message }) => {
635
652
  else if (content.toolUse) {
636
653
  // For now tool use is limited to custom response components
637
654
  const { name, input } = content.toolUse;
638
- if (!responseComponents || !name) {
655
+ if (!responseComponents ||
656
+ !name ||
657
+ !name.startsWith(RESPONSE_COMPONENT_PREFIX)) {
639
658
  return;
640
659
  }
641
660
  else {
@@ -673,6 +692,7 @@ const Layout = React__default["default"].forwardRef(function Layout(props, ref)
673
692
  const MessagesControl = ({ renderMessage }) => {
674
693
  const messages = React__default["default"].useContext(MessagesContext);
675
694
  const controls = React__default["default"].useContext(ControlsContext);
695
+ const { getMessageTimestampText } = useConversationDisplayText();
676
696
  const messagesRef = React__default["default"].useRef([]);
677
697
  const [focusedItemIndex, setFocusedItemIndex] = React__default["default"].useState(messages ? messages.length - 1 : 0);
678
698
  const handleFocus = (index) => setFocusedItemIndex(index);
@@ -705,13 +725,16 @@ const MessagesControl = ({ renderMessage }) => {
705
725
  if (controls?.MessageList) {
706
726
  return React__default["default"].createElement(controls.MessageList, { messages: messages });
707
727
  }
708
- return (React__default["default"].createElement(Layout, null, messages?.map((message, index) => {
728
+ const messagesWithRenderableContent = messages?.filter((message) => message.content.some((content) => content.image ??
729
+ content.text ??
730
+ content.toolUse?.name.startsWith(RESPONSE_COMPONENT_PREFIX))) ?? [];
731
+ return (React__default["default"].createElement(Layout, null, messagesWithRenderableContent?.map((message, index) => {
709
732
  return renderMessage ? (renderMessage(message)) : (React__default["default"].createElement(RoleContext.Provider, { value: message.role, key: `message-${index}` },
710
733
  React__default["default"].createElement(MessageContainer, { "data-testid": `message`, key: `message-${index}`, tabIndex: focusedItemIndex === index ? 0 : -1, onFocus: () => handleFocus(index), onKeyDown: (event) => onKeyDown(index, event), ref: (el) => (messagesRef.current[index] = el) },
711
734
  React__default["default"].createElement(HeaderContainer, null,
712
735
  React__default["default"].createElement(AvatarControl, null),
713
736
  React__default["default"].createElement(Separator, null),
714
- React__default["default"].createElement(Timestamp, null, formatDate(new Date(message.createdAt)))),
737
+ React__default["default"].createElement(Timestamp, null, getMessageTimestampText(new Date(message.createdAt)))),
715
738
  React__default["default"].createElement(MessageControl, { message: message }),
716
739
  message.role === 'assistant' ? (React__default["default"].createElement(ActionsBarControl, { message: message, focusable: focusedItemIndex === index })) : null)));
717
740
  })));
@@ -807,19 +830,24 @@ function Conversation() {
807
830
  React__default["default"].createElement(FieldControl, null))));
808
831
  }
809
832
 
810
- function createProvider({ elements: elements$1, actions, suggestedPrompts, responseComponents, variant, controls, }) {
833
+ function createProvider({ elements: elements$1, actions, suggestedPrompts, responseComponents, variant, controls, displayText, }) {
811
834
  return function Provider({ children, messages, avatars, handleSendMessage, isLoading, }) {
835
+ const _displayText = {
836
+ ...defaultAIConversationDisplayTextEn,
837
+ ...displayText,
838
+ };
812
839
  return (React__default["default"].createElement(elements.ElementsProvider, { elements: elements$1 },
813
840
  React__default["default"].createElement(ControlsProvider, { controls: controls },
814
841
  React__default["default"].createElement(SuggestedPromptProvider, { suggestedPrompts: suggestedPrompts },
815
842
  React__default["default"].createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
816
- React__default["default"].createElement(ConversationInputContextProvider, null,
817
- React__default["default"].createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
818
- React__default["default"].createElement(AvatarsProvider, { avatars: avatars },
819
- React__default["default"].createElement(ActionsProvider, { actions: actions },
820
- React__default["default"].createElement(MessageVariantProvider, { variant: variant },
821
- React__default["default"].createElement(MessagesProvider, { messages: messages },
822
- React__default["default"].createElement(LoadingContextProvider, { isLoading: isLoading }, children))))))))))));
843
+ React__default["default"].createElement(ConversationDisplayTextProvider, { ..._displayText },
844
+ React__default["default"].createElement(ConversationInputContextProvider, null,
845
+ React__default["default"].createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
846
+ React__default["default"].createElement(AvatarsProvider, { avatars: avatars },
847
+ React__default["default"].createElement(ActionsProvider, { actions: actions },
848
+ React__default["default"].createElement(MessageVariantProvider, { variant: variant },
849
+ React__default["default"].createElement(MessagesProvider, { messages: messages },
850
+ React__default["default"].createElement(LoadingContextProvider, { isLoading: isLoading }, children)))))))))))));
823
851
  };
824
852
  }
825
853
 
@@ -827,7 +855,7 @@ function createProvider({ elements: elements$1, actions, suggestedPrompts, respo
827
855
  * @experimental
828
856
  */
829
857
  function createAIConversation(input = {}) {
830
- const { elements, suggestedPrompts, actions, responseComponents, variant, controls, } = input;
858
+ const { elements, suggestedPrompts, actions, responseComponents, variant, controls, displayText, } = input;
831
859
  const Provider = createProvider({
832
860
  elements,
833
861
  actions,
@@ -835,6 +863,7 @@ function createAIConversation(input = {}) {
835
863
  responseComponents,
836
864
  variant,
837
865
  controls,
866
+ displayText,
838
867
  });
839
868
  function AIConversation(props) {
840
869
  const { messages, avatars, handleSendMessage, isLoading } = props;
@@ -859,11 +888,23 @@ const MessageMeta = ({ message }) => {
859
888
  // need to pass this in as props in order for it to be overridable
860
889
  const avatars = React__namespace.useContext(AvatarsContext);
861
890
  const role = React__namespace.useContext(RoleContext);
891
+ const { getMessageTimestampText } = useConversationDisplayText();
862
892
  // maybe rename 'avatar' to something else
863
893
  const avatar = role === 'assistant' ? avatars?.ai : avatars?.user;
864
894
  return (React__namespace.createElement(uiReact.View, { className: ui.ComponentClassName.AIConversationMessageSender },
865
895
  React__namespace.createElement(uiReact.Text, { className: ui.ComponentClassName.AIConversationMessageSenderUsername }, avatar?.username),
866
- React__namespace.createElement(uiReact.Text, { className: ui.ComponentClassName.AIConversationMessageSenderTimestamp }, formatDate(new Date(message.createdAt)))));
896
+ React__namespace.createElement(uiReact.Text, { className: ui.ComponentClassName.AIConversationMessageSenderTimestamp }, getMessageTimestampText(new Date(message.createdAt)))));
897
+ };
898
+ const LoadingMessage = () => {
899
+ const avatars = React__namespace.useContext(AvatarsContext);
900
+ const variant = React__namespace.useContext(MessageVariantContext);
901
+ const avatar = avatars?.ai;
902
+ return (React__namespace.createElement(uiReact.View, { className: ui.classNames(ui.ComponentClassName.AIConversationMessage, ui.classNameModifier(ui.ComponentClassName.AIConversationMessage, variant), ui.classNameModifier(ui.ComponentClassName.AIConversationMessage, 'assistant')) },
903
+ React__namespace.createElement(uiReact.View, { className: ui.ComponentClassName.AIConversationMessageAvatar },
904
+ React__namespace.createElement(uiReact.Avatar, { isLoading: true }, avatar?.avatar)),
905
+ React__namespace.createElement(uiReact.View, { className: ui.ComponentClassName.AIConversationMessageBody },
906
+ React__namespace.createElement(uiReact.View, { className: ui.ComponentClassName.AIConversationMessageSender },
907
+ React__namespace.createElement(uiReact.Text, { className: ui.ComponentClassName.AIConversationMessageSenderUsername }, avatar?.username)))));
867
908
  };
868
909
  const Message = ({ message }) => {
869
910
  const avatars = React__namespace.useContext(AvatarsContext);
@@ -879,7 +920,13 @@ const Message = ({ message }) => {
879
920
  React__namespace.createElement(MessageControl, { message: message }))))));
880
921
  };
881
922
  const MessageList = ({ messages, }) => {
882
- return (React__namespace.createElement(uiReact.View, { className: ui.ComponentClassName.AIConversationMessageList }, messages.map((message, i) => (React__namespace.createElement(Message, { key: `message-${i}`, message: message })))));
923
+ const isLoading = React__namespace.useContext(LoadingContext);
924
+ const messagesWithRenderableContent = messages?.filter((message) => message.content.some((content) => content.image ??
925
+ content.text ??
926
+ content.toolUse?.name.startsWith(RESPONSE_COMPONENT_PREFIX))) ?? [];
927
+ return (React__namespace.createElement(uiReact.View, { className: ui.ComponentClassName.AIConversationMessageList },
928
+ messagesWithRenderableContent.map((message, i) => (React__namespace.createElement(Message, { key: `message-${i}`, message: message }))),
929
+ isLoading ? React__namespace.createElement(LoadingMessage, null) : null));
883
930
  };
884
931
 
885
932
  const Attachment = ({ file, handleRemove, }) => {
@@ -924,6 +971,9 @@ const Form = ({ setInput, input, handleSubmit, }) => {
924
971
  React__namespace.createElement(uiReact.View, { as: "form", className: ui.ComponentClassName.AIConversationForm, onSubmit: handleSubmit },
925
972
  React__namespace.createElement(uiReact.Button, { className: ui.ComponentClassName.AIConversationFormAttach, onClick: () => {
926
973
  hiddenInput?.current?.click();
974
+ if (hiddenInput?.current) {
975
+ hiddenInput.current.value = '';
976
+ }
927
977
  } },
928
978
  React__namespace.createElement("span", null, attachIcon),
929
979
  React__namespace.createElement(uiReact.VisuallyHidden, null,
@@ -936,8 +986,8 @@ const Form = ({ setInput, input, handleSubmit, }) => {
936
986
  ...prevValue,
937
987
  files: [...(prevValue?.files ?? []), ...Array.from(files)],
938
988
  }));
939
- }, multiple: true, accept: "*" }))),
940
- React__namespace.createElement(uiReact.TextAreaField, { className: ui.ComponentClassName.AIConversationFormField, label: "input", labelHidden: true, autoResize: true, flex: "1", rows: 1, value: input?.text ?? '', onKeyDown: (e) => {
989
+ }, multiple: true, accept: "*", "data-testid": "hidden-file-input" }))),
990
+ 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", onKeyDown: (e) => {
941
991
  // Submit on enter key if shift is not pressed also
942
992
  const shouldSubmit = !e.shiftKey && e.key === 'Enter';
943
993
  if (shouldSubmit && isHTMLFormElement(e.target)) {
@@ -969,7 +1019,7 @@ const PromptList = ({ setInput, suggestedPrompts = [], }) => {
969
1019
  })));
970
1020
  };
971
1021
 
972
- function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, }) {
1022
+ function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, }) {
973
1023
  const icons = internal.useIcons('aiConversation');
974
1024
  const defaultAvatars = {
975
1025
  ai: {
@@ -997,6 +1047,7 @@ function AIConversationBase({ actions, avatars, controls, handleSendMessage, mes
997
1047
  Form,
998
1048
  ...controls,
999
1049
  },
1050
+ displayText,
1000
1051
  });
1001
1052
  const providerProps = {
1002
1053
  messages,
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import { AIConversationInput, AIConversationProps } from './types';
3
3
  interface AIConversationBaseProps extends AIConversationProps, AIConversationInput {
4
4
  }
5
- declare function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, }: AIConversationBaseProps): JSX.Element;
5
+ declare function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, }: AIConversationBaseProps): JSX.Element;
6
6
  /**
7
7
  * @experimental
8
8
  */
@@ -12,10 +12,10 @@ export declare const AIConversation: typeof AIConversationBase & {
12
12
  }> | undefined;
13
13
  PromptList: React.ComponentType<{
14
14
  suggestedPrompts?: import("./types").SuggestedPrompt[] | undefined;
15
- setInput: React.Dispatch<React.SetStateAction<import("./context/ConversationInputContext").ConversationInput | undefined>> | undefined;
15
+ setInput: React.Dispatch<React.SetStateAction<import("./context").ConversationInput | undefined>> | undefined;
16
16
  }> | undefined;
17
- Form: React.ComponentType<{
17
+ Form: NonNullable<React.ComponentType<{
18
18
  handleSubmit: (e: React.FormEvent<HTMLFormElement>) => void;
19
- } & Required<import("./context").ConversationInputContext>> | undefined;
19
+ } & Required<import("./context").ConversationInputContext>> | undefined>;
20
20
  };
21
21
  export {};
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ import { ConversationDisplayText } from '../displayText';
3
+ export declare const ConversationDisplayTextContext: import("react").Context<Required<ConversationDisplayText> | undefined>, ConversationDisplayTextProvider: import("react").ComponentType<import("react").PropsWithChildren<Required<ConversationDisplayText>>>, useConversationDisplayText: (params?: {
4
+ errorMessage?: string | undefined;
5
+ } | undefined) => Required<ConversationDisplayText>;
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  import { ResponseComponents } from '../types';
3
3
  import { ToolConfiguration } from '../../../types';
4
4
  type ResponseComponentsContextProps = ResponseComponents | undefined;
5
+ export declare const RESPONSE_COMPONENT_PREFIX = "AMPLIFY_UI_";
5
6
  export declare const ResponseComponentsContext: React.Context<ResponseComponentsContextProps>;
6
7
  export declare const ResponseComponentsProvider: ({ children, responseComponents, }: {
7
8
  children?: React.ReactNode;
@@ -1,8 +1,12 @@
1
- import { ActionsContext } from './ActionsContext';
2
- import { AvatarsContext } from './AvatarsContext';
3
- import { ConversationInputContext } from './ConversationInputContext';
4
- import { MessagesContext, RoleContext } from './MessagesContext';
5
- import { SuggestedPromptsContext } from './SuggestedPromptsContext';
6
- import { MessageVariantContext } from './MessageVariantContext';
7
- export { ActionsContext, AvatarsContext, ConversationInputContext, MessagesContext, RoleContext, SuggestedPromptsContext, MessageVariantContext, };
1
+ export { ActionsContext, ActionsProvider } from './ActionsContext';
2
+ export { AvatarsContext, AvatarsProvider } from './AvatarsContext';
3
+ export { ConversationInputContext, ConversationInput, ConversationInputContextProvider, } from './ConversationInputContext';
4
+ export { MessagesContext, RoleContext, MessagesProvider, } from './MessagesContext';
5
+ export { SuggestedPromptsContext, SuggestedPromptProvider, } from './SuggestedPromptsContext';
6
+ export { MessageVariantContext, MessageVariantProvider, } from './MessageVariantContext';
7
+ export { ConversationDisplayTextContext, useConversationDisplayText, ConversationDisplayTextProvider, } from './DisplayTextContext';
8
+ export { ControlsContext, ControlsContextProps, ControlsProvider, } from './ControlsContext';
9
+ export { LoadingContextProvider } from './LoadingContext';
10
+ export { ResponseComponentsProvider, RESPONSE_COMPONENT_PREFIX, } from './ResponseComponentsContext';
11
+ export { SendMessageContextProvider } from './SendMessageContext';
8
12
  export * from './elements';
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
2
  import { AIConversationInput, AIConversationProps } from './types';
3
- export default function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, }: Pick<AIConversationInput, 'elements' | 'actions' | 'suggestedPrompts' | 'responseComponents' | 'variant' | 'controls'>): ({ children, messages, avatars, handleSendMessage, isLoading, }: {
3
+ export default function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, }: Pick<AIConversationInput, 'elements' | 'actions' | 'suggestedPrompts' | 'responseComponents' | 'variant' | 'controls' | 'displayText'>): ({ children, messages, avatars, handleSendMessage, isLoading, }: {
4
4
  children?: React.ReactNode;
5
- } & Pick<AIConversationProps, "avatars" | "messages" | "handleSendMessage" | "isLoading">) => React.JSX.Element;
5
+ } & Pick<AIConversationProps, "avatars" | "messages" | "isLoading" | "handleSendMessage">) => React.JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { DisplayTextTemplate } from '@aws-amplify/ui';
2
2
  export type ConversationDisplayText = {
3
- conversationHeaderText?: string;
3
+ getMessageTimestampText?: (date: Date) => string;
4
4
  };
5
- export declare const defaultAIConversationDisplayText: Required<AIConversationDisplayText>;
5
+ export declare const defaultAIConversationDisplayTextEn: Required<AIConversationDisplayText>;
6
6
  export type AIConversationDisplayText = DisplayTextTemplate<ConversationDisplayText>;
@@ -1,3 +1,4 @@
1
1
  import { createAIConversation } from './createAIConversation';
2
2
  import { AIConversation } from './AIConversation';
3
- export { createAIConversation, AIConversation };
3
+ import { Avatars, CustomAction, ResponseComponent, SuggestedPrompt } from './types';
4
+ export { createAIConversation, AIConversation, Avatars, CustomAction, ResponseComponent, SuggestedPrompt, };
@@ -1,2 +1,2 @@
1
1
  import { ControlsContextProps } from '../../context/ControlsContext';
2
- export declare const Form: ControlsContextProps['Form'];
2
+ export declare const Form: NonNullable<ControlsContextProps['Form']>;
@@ -1,3 +1,3 @@
1
- import { createAIConversation, AIConversation } from './components';
2
- import { createAIHooks, AIContextProvider } from './hooks';
3
- export { createAIConversation, createAIHooks, AIContextProvider, AIConversation, };
1
+ export { createAIConversation, AIConversation, Avatars, CustomAction, ResponseComponent, SuggestedPrompt, } from './components';
2
+ export { createAIHooks, AIContextProvider } from './hooks';
3
+ export { ConversationMessage, ConversationMessageContent, SendMessage, SendMesageParameters, } from './types';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/ui-react-ai",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/esm/index.mjs",
6
6
  "exports": {
@@ -47,9 +47,9 @@
47
47
  "react-dom": "^16.14.0 || ^17.0 || ^18.0"
48
48
  },
49
49
  "dependencies": {
50
- "@aws-amplify/ui": "^6.4.0",
51
- "@aws-amplify/ui-react": "^6.3.0",
52
- "@aws-amplify/ui-react-core": "^3.0.21"
50
+ "@aws-amplify/ui": "^6.5.0",
51
+ "@aws-amplify/ui-react": "^6.4.0",
52
+ "@aws-amplify/ui-react-core": "^3.0.23"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@rollup/plugin-commonjs": "^22.0.1",