@aws-amplify/ui-react-ai 0.3.1 → 0.3.2

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.
@@ -12,7 +12,7 @@ import { MessageList } from './views/default/MessageList.mjs';
12
12
  import { Form } from './views/default/Form.mjs';
13
13
  import { PromptList } from './views/default/PromptList.mjs';
14
14
  import { ComponentClassName } from '@aws-amplify/ui';
15
- import createProvider from './createProvider.mjs';
15
+ import { AIConversationProvider } from './AIConversationProvider.mjs';
16
16
 
17
17
  function AIConversationBase({ actions, avatars, controls, handleSendMessage, messages, responseComponents, suggestedPrompts, variant, isLoading, displayText, allowAttachments, }) {
18
18
  const icons = useIcons('aiConversation');
@@ -26,7 +26,14 @@ function AIConversationBase({ actions, avatars, controls, handleSendMessage, mes
26
26
  avatar: icons?.user ?? React.createElement(IconUser, null),
27
27
  },
28
28
  };
29
- const Provider = createProvider({
29
+ const providerProps = {
30
+ messages,
31
+ handleSendMessage,
32
+ avatars: {
33
+ ...defaultAvatars,
34
+ ...avatars,
35
+ },
36
+ isLoading,
30
37
  elements: {
31
38
  Text: React.forwardRef(function _Text(props, ref) {
32
39
  return React.createElement(Text, { ...props, ref: ref });
@@ -44,17 +51,8 @@ function AIConversationBase({ actions, avatars, controls, handleSendMessage, mes
44
51
  },
45
52
  displayText,
46
53
  allowAttachments,
47
- });
48
- const providerProps = {
49
- messages,
50
- handleSendMessage,
51
- avatars: {
52
- ...defaultAvatars,
53
- ...avatars,
54
- },
55
- isLoading,
56
54
  };
57
- return (React.createElement(Provider, { ...providerProps },
55
+ return (React.createElement(AIConversationProvider, { ...providerProps },
58
56
  React.createElement(Flex, { className: ComponentClassName.AIConversation },
59
57
  React.createElement(ScrollView, { autoScroll: "smooth", flex: "1" },
60
58
  React.createElement(AutoHidablePromptControl, null),
@@ -15,26 +15,24 @@ import { SendMessageContextProvider } from './context/SendMessageContext.mjs';
15
15
  import './context/elements/definitions.mjs';
16
16
  import { AttachmentProvider } from './context/AttachmentContext.mjs';
17
17
 
18
- function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, allowAttachments, }) {
19
- return function Provider({ children, messages, avatars, handleSendMessage, isLoading, }) {
20
- const _displayText = {
21
- ...defaultAIConversationDisplayTextEn,
22
- ...displayText,
23
- };
24
- return (React__default.createElement(ElementsProvider, { elements: elements },
25
- React__default.createElement(ControlsProvider, { controls: controls },
26
- React__default.createElement(SuggestedPromptProvider, { suggestedPrompts: suggestedPrompts },
27
- React__default.createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
28
- React__default.createElement(AttachmentProvider, { allowAttachments: allowAttachments },
29
- React__default.createElement(ConversationDisplayTextProvider, { ..._displayText },
30
- React__default.createElement(ConversationInputContextProvider, null,
31
- React__default.createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
32
- React__default.createElement(AvatarsProvider, { avatars: avatars },
33
- React__default.createElement(ActionsProvider, { actions: actions },
34
- React__default.createElement(MessageVariantProvider, { variant: variant },
35
- React__default.createElement(MessagesProvider, { messages: messages },
36
- React__default.createElement(LoadingContextProvider, { isLoading: isLoading }, children))))))))))))));
18
+ const AIConversationProvider = ({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, allowAttachments, messages, handleSendMessage, avatars, isLoading, children, }) => {
19
+ const _displayText = {
20
+ ...defaultAIConversationDisplayTextEn,
21
+ ...displayText,
37
22
  };
38
- }
23
+ return (React__default.createElement(ElementsProvider, { elements: elements },
24
+ React__default.createElement(ControlsProvider, { controls: controls },
25
+ React__default.createElement(SuggestedPromptProvider, { suggestedPrompts: suggestedPrompts },
26
+ React__default.createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
27
+ React__default.createElement(AttachmentProvider, { allowAttachments: allowAttachments },
28
+ React__default.createElement(ConversationDisplayTextProvider, { ..._displayText },
29
+ React__default.createElement(ConversationInputContextProvider, null,
30
+ React__default.createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
31
+ React__default.createElement(AvatarsProvider, { avatars: avatars },
32
+ React__default.createElement(ActionsProvider, { actions: actions },
33
+ React__default.createElement(MessageVariantProvider, { variant: variant },
34
+ React__default.createElement(MessagesProvider, { messages: messages },
35
+ React__default.createElement(LoadingContextProvider, { isLoading: isLoading }, children))))))))))))));
36
+ };
39
37
 
40
- export { createProvider as default };
38
+ export { AIConversationProvider };
@@ -6,26 +6,30 @@ import { HeaderControl } from './views/Controls/HeaderControl.mjs';
6
6
  import { FieldControl } from './views/Controls/FieldControl.mjs';
7
7
  import { MessagesControl } from './views/Controls/MessagesControl.mjs';
8
8
  import { PromptControl } from './views/Controls/PromptControl.mjs';
9
- import createProvider from './createProvider.mjs';
9
+ import { AIConversationProvider } from './AIConversationProvider.mjs';
10
10
 
11
11
  /**
12
12
  * @experimental
13
13
  */
14
14
  function createAIConversation(input = {}) {
15
15
  const { elements, suggestedPrompts, actions, responseComponents, variant, controls, displayText, allowAttachments, } = input;
16
- const Provider = createProvider({
17
- elements,
18
- actions,
19
- suggestedPrompts,
20
- responseComponents,
21
- variant,
22
- controls,
23
- displayText,
24
- allowAttachments,
25
- });
26
16
  function AIConversation(props) {
27
17
  const { messages, avatars, handleSendMessage, isLoading } = props;
28
- return (React__default.createElement(Provider, { messages: messages, avatars: avatars, handleSendMessage: handleSendMessage, isLoading: isLoading },
18
+ const providerProps = {
19
+ elements,
20
+ actions,
21
+ suggestedPrompts,
22
+ responseComponents,
23
+ variant,
24
+ controls,
25
+ displayText,
26
+ allowAttachments,
27
+ messages,
28
+ avatars,
29
+ handleSendMessage,
30
+ isLoading,
31
+ };
32
+ return (React__default.createElement(AIConversationProvider, { ...providerProps },
29
33
  React__default.createElement(Conversation, null)));
30
34
  }
31
35
  const Controls = {
@@ -36,7 +40,7 @@ function createAIConversation(input = {}) {
36
40
  Messages: MessagesControl,
37
41
  SuggestedPrompts: PromptControl,
38
42
  };
39
- AIConversation.Provider = Provider;
43
+ AIConversation.Provider = AIConversationProvider;
40
44
  AIConversation.Conversation = Conversation;
41
45
  AIConversation.Controls = Controls;
42
46
  return { AIConversation };
@@ -1,21 +1,35 @@
1
- import { useDataState } from '@aws-amplify/ui-react-core';
1
+ import * as React from 'react';
2
2
 
3
+ // default state
4
+ const INITIAL_STATE = {
5
+ hasError: false,
6
+ isLoading: false,
7
+ messages: undefined,
8
+ };
9
+ const LOADING_STATE = { hasError: false, isLoading: true, messages: undefined };
10
+ const ERROR_STATE = { hasError: true, isLoading: false };
3
11
  function createUseAIGeneration(client) {
4
12
  const useAIGeneration = (routeName) => {
5
- const handleGenerate = client.generations[routeName];
6
- const updateAIGenerationStateAction = async (_prev, input) => {
7
- const result = await handleGenerate(input);
8
- // handleGenerate returns a Promised wrapper around Schema[Key]['returnType'] which includes data, errors, and clientExtensions
9
- // The type of data is Schema[Key]['returnType'] which useDataState also wraps in a data return
10
- // TODO: follow up with how to type handleGenerate to properly return the promise wrapper shape
11
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
12
- const data = result.data;
13
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
14
- const graphqlErrors = result.errors;
15
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-assignment
16
- return { ...data, ...(graphqlErrors ? { graphqlErrors } : {}) };
17
- };
18
- return useDataState(updateAIGenerationStateAction, {});
13
+ const [dataState, setDataState] = React.useState(() => ({
14
+ ...INITIAL_STATE,
15
+ data: undefined,
16
+ }));
17
+ const handleGeneration = React.useCallback(async (input) => {
18
+ setDataState(({ data }) => ({ ...LOADING_STATE, data }));
19
+ const result = await client.generations[routeName](input);
20
+ const { data, errors } = result;
21
+ if (errors) {
22
+ setDataState({
23
+ ...ERROR_STATE,
24
+ data,
25
+ messages: errors,
26
+ });
27
+ }
28
+ else {
29
+ setDataState({ ...INITIAL_STATE, data });
30
+ }
31
+ }, [routeName]);
32
+ return [dataState, handleGeneration];
19
33
  };
20
34
  return useAIGeneration;
21
35
  }
package/dist/index.js CHANGED
@@ -844,46 +844,48 @@ function Conversation() {
844
844
  React__namespace["default"].createElement(FieldControl, null))));
845
845
  }
846
846
 
847
- function createProvider({ elements: elements$1, actions, suggestedPrompts, responseComponents, variant, controls, displayText, allowAttachments, }) {
848
- return function Provider({ children, messages, avatars, handleSendMessage, isLoading, }) {
849
- const _displayText = {
850
- ...defaultAIConversationDisplayTextEn,
851
- ...displayText,
852
- };
853
- return (React__namespace["default"].createElement(elements.ElementsProvider, { elements: elements$1 },
854
- React__namespace["default"].createElement(ControlsProvider, { controls: controls },
855
- React__namespace["default"].createElement(SuggestedPromptProvider, { suggestedPrompts: suggestedPrompts },
856
- React__namespace["default"].createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
857
- React__namespace["default"].createElement(AttachmentProvider, { allowAttachments: allowAttachments },
858
- React__namespace["default"].createElement(ConversationDisplayTextProvider, { ..._displayText },
859
- React__namespace["default"].createElement(ConversationInputContextProvider, null,
860
- React__namespace["default"].createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
861
- React__namespace["default"].createElement(AvatarsProvider, { avatars: avatars },
862
- React__namespace["default"].createElement(ActionsProvider, { actions: actions },
863
- React__namespace["default"].createElement(MessageVariantProvider, { variant: variant },
864
- React__namespace["default"].createElement(MessagesProvider, { messages: messages },
865
- React__namespace["default"].createElement(LoadingContextProvider, { isLoading: isLoading }, children))))))))))))));
847
+ const AIConversationProvider = ({ elements: elements$1, actions, suggestedPrompts, responseComponents, variant, controls, displayText, allowAttachments, messages, handleSendMessage, avatars, isLoading, children, }) => {
848
+ const _displayText = {
849
+ ...defaultAIConversationDisplayTextEn,
850
+ ...displayText,
866
851
  };
867
- }
852
+ return (React__namespace["default"].createElement(elements.ElementsProvider, { elements: elements$1 },
853
+ React__namespace["default"].createElement(ControlsProvider, { controls: controls },
854
+ React__namespace["default"].createElement(SuggestedPromptProvider, { suggestedPrompts: suggestedPrompts },
855
+ React__namespace["default"].createElement(ResponseComponentsProvider, { responseComponents: responseComponents },
856
+ React__namespace["default"].createElement(AttachmentProvider, { allowAttachments: allowAttachments },
857
+ React__namespace["default"].createElement(ConversationDisplayTextProvider, { ..._displayText },
858
+ React__namespace["default"].createElement(ConversationInputContextProvider, null,
859
+ React__namespace["default"].createElement(SendMessageContextProvider, { handleSendMessage: handleSendMessage },
860
+ React__namespace["default"].createElement(AvatarsProvider, { avatars: avatars },
861
+ React__namespace["default"].createElement(ActionsProvider, { actions: actions },
862
+ React__namespace["default"].createElement(MessageVariantProvider, { variant: variant },
863
+ React__namespace["default"].createElement(MessagesProvider, { messages: messages },
864
+ React__namespace["default"].createElement(LoadingContextProvider, { isLoading: isLoading }, children))))))))))))));
865
+ };
868
866
 
869
867
  /**
870
868
  * @experimental
871
869
  */
872
870
  function createAIConversation(input = {}) {
873
871
  const { elements, suggestedPrompts, actions, responseComponents, variant, controls, displayText, allowAttachments, } = input;
874
- const Provider = createProvider({
875
- elements,
876
- actions,
877
- suggestedPrompts,
878
- responseComponents,
879
- variant,
880
- controls,
881
- displayText,
882
- allowAttachments,
883
- });
884
872
  function AIConversation(props) {
885
873
  const { messages, avatars, handleSendMessage, isLoading } = props;
886
- return (React__namespace["default"].createElement(Provider, { messages: messages, avatars: avatars, handleSendMessage: handleSendMessage, isLoading: isLoading },
874
+ const providerProps = {
875
+ elements,
876
+ actions,
877
+ suggestedPrompts,
878
+ responseComponents,
879
+ variant,
880
+ controls,
881
+ displayText,
882
+ allowAttachments,
883
+ messages,
884
+ avatars,
885
+ handleSendMessage,
886
+ isLoading,
887
+ };
888
+ return (React__namespace["default"].createElement(AIConversationProvider, { ...providerProps },
887
889
  React__namespace["default"].createElement(Conversation, null)));
888
890
  }
889
891
  const Controls = {
@@ -894,7 +896,7 @@ function createAIConversation(input = {}) {
894
896
  Messages: MessagesControl,
895
897
  SuggestedPrompts: PromptControl,
896
898
  };
897
- AIConversation.Provider = Provider;
899
+ AIConversation.Provider = AIConversationProvider;
898
900
  AIConversation.Conversation = Conversation;
899
901
  AIConversation.Controls = Controls;
900
902
  return { AIConversation };
@@ -1059,7 +1061,14 @@ function AIConversationBase({ actions, avatars, controls, handleSendMessage, mes
1059
1061
  avatar: icons?.user ?? React__namespace.createElement(internal.IconUser, null),
1060
1062
  },
1061
1063
  };
1062
- const Provider = createProvider({
1064
+ const providerProps = {
1065
+ messages,
1066
+ handleSendMessage,
1067
+ avatars: {
1068
+ ...defaultAvatars,
1069
+ ...avatars,
1070
+ },
1071
+ isLoading,
1063
1072
  elements: {
1064
1073
  Text: React__namespace.forwardRef(function _Text(props, ref) {
1065
1074
  return React__namespace.createElement(uiReact.Text, { ...props, ref: ref });
@@ -1077,17 +1086,8 @@ function AIConversationBase({ actions, avatars, controls, handleSendMessage, mes
1077
1086
  },
1078
1087
  displayText,
1079
1088
  allowAttachments,
1080
- });
1081
- const providerProps = {
1082
- messages,
1083
- handleSendMessage,
1084
- avatars: {
1085
- ...defaultAvatars,
1086
- ...avatars,
1087
- },
1088
- isLoading,
1089
1089
  };
1090
- return (React__namespace.createElement(Provider, { ...providerProps },
1090
+ return (React__namespace.createElement(AIConversationProvider, { ...providerProps },
1091
1091
  React__namespace.createElement(uiReact.Flex, { className: ui.ComponentClassName.AIConversation },
1092
1092
  React__namespace.createElement(uiReact.ScrollView, { autoScroll: "smooth", flex: "1" },
1093
1093
  React__namespace.createElement(AutoHidablePromptControl, null),
@@ -1120,22 +1120,36 @@ const AIContextProvider = ({ children, }) => {
1120
1120
  return React__namespace["default"].createElement(AIContext.Provider, { value: context }, children);
1121
1121
  };
1122
1122
 
1123
+ // default state
1124
+ const INITIAL_STATE = {
1125
+ hasError: false,
1126
+ isLoading: false,
1127
+ messages: undefined,
1128
+ };
1129
+ const LOADING_STATE = { hasError: false, isLoading: true, messages: undefined };
1130
+ const ERROR_STATE = { hasError: true, isLoading: false };
1123
1131
  function createUseAIGeneration(client) {
1124
1132
  const useAIGeneration = (routeName) => {
1125
- const handleGenerate = client.generations[routeName];
1126
- const updateAIGenerationStateAction = async (_prev, input) => {
1127
- const result = await handleGenerate(input);
1128
- // handleGenerate returns a Promised wrapper around Schema[Key]['returnType'] which includes data, errors, and clientExtensions
1129
- // The type of data is Schema[Key]['returnType'] which useDataState also wraps in a data return
1130
- // TODO: follow up with how to type handleGenerate to properly return the promise wrapper shape
1131
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1132
- const data = result.data;
1133
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
1134
- const graphqlErrors = result.errors;
1135
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-assignment
1136
- return { ...data, ...(graphqlErrors ? { graphqlErrors } : {}) };
1137
- };
1138
- return uiReactCore.useDataState(updateAIGenerationStateAction, {});
1133
+ const [dataState, setDataState] = React__namespace.useState(() => ({
1134
+ ...INITIAL_STATE,
1135
+ data: undefined,
1136
+ }));
1137
+ const handleGeneration = React__namespace.useCallback(async (input) => {
1138
+ setDataState(({ data }) => ({ ...LOADING_STATE, data }));
1139
+ const result = await client.generations[routeName](input);
1140
+ const { data, errors } = result;
1141
+ if (errors) {
1142
+ setDataState({
1143
+ ...ERROR_STATE,
1144
+ data,
1145
+ messages: errors,
1146
+ });
1147
+ }
1148
+ else {
1149
+ setDataState({ ...INITIAL_STATE, data });
1150
+ }
1151
+ }, [routeName]);
1152
+ return [dataState, handleGeneration];
1139
1153
  };
1140
1154
  return useAIGeneration;
1141
1155
  }
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { AIConversationInput, AIConversationProps } from './types';
3
+ interface AIConversationProviderProps extends AIConversationInput, AIConversationProps {
4
+ children?: React.ReactNode;
5
+ }
6
+ export declare const AIConversationProvider: ({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, allowAttachments, messages, handleSendMessage, avatars, isLoading, children, }: AIConversationProviderProps) => React.JSX.Element;
7
+ export {};
@@ -3,14 +3,24 @@ import { V6Client } from '@aws-amplify/api-graphql';
3
3
  import { getSchema } from '../types';
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
- Awaited<DataState<Schema[U]['returnType']>>,
6
+ Awaited<GenerationState<Schema[U]['returnType']>>,
7
7
  (input: Schema[U]['args']) => void
8
8
  ];
9
9
  }
10
10
  export type UseAIGenerationHook<Key extends keyof AIGenerationClient<Schema>['generations'], Schema extends Record<any, any>> = (routeName: Key) => [
11
- Awaited<DataState<Schema[Key]['returnType']>>,
11
+ Awaited<GenerationState<Schema[Key]['returnType']>>,
12
12
  (input: Schema[Key]['args']) => void
13
13
  ];
14
14
  type AIGenerationClient<T extends Record<any, any>> = Pick<V6Client<T>, 'generations'>;
15
+ interface GraphQLFormattedError {
16
+ readonly message: string;
17
+ readonly errorType: string;
18
+ readonly errorInfo: null | {
19
+ [key: string]: unknown;
20
+ };
21
+ }
22
+ type GenerationState<T> = Omit<DataState<T>, 'message'> & {
23
+ messages?: GraphQLFormattedError[];
24
+ };
15
25
  export declare function createUseAIGeneration<Client extends Record<'generations' | 'conversations', Record<string, any>>, Schema extends getSchema<Client>>(client: Client): UseAIGenerationHook<keyof Client['generations'], Client>;
16
26
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aws-amplify/ui-react-ai",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
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.0 || ^17.0 || ^18.0"
49
49
  },
50
50
  "dependencies": {
51
- "@aws-amplify/ui": "^6.6.3",
52
- "@aws-amplify/ui-react": "^6.5.3",
53
- "@aws-amplify/ui-react-core": "^3.0.27"
51
+ "@aws-amplify/ui": "^6.6.4",
52
+ "@aws-amplify/ui-react": "^6.5.4",
53
+ "@aws-amplify/ui-react-core": "^3.0.28"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@types/jest-when": "^3.5.0",
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
- import { AIConversationInput, AIConversationProps } from './types';
3
- export default function createProvider({ elements, actions, suggestedPrompts, responseComponents, variant, controls, displayText, allowAttachments, }: Pick<AIConversationInput, 'elements' | 'actions' | 'suggestedPrompts' | 'responseComponents' | 'variant' | 'controls' | 'displayText' | 'allowAttachments'>): ({ children, messages, avatars, handleSendMessage, isLoading, }: {
4
- children?: React.ReactNode;
5
- } & Pick<AIConversationProps, "avatars" | "messages" | "isLoading" | "handleSendMessage">) => React.JSX.Element;