SDK Integration

The AI components work seamlessly with the React Native SDK.

StreamingMessageView

Integrating the StreamingMessageView within the SDK is relatively easy.

The SDK already comes prebuilt with a isMessageAIGenerated factory function that lets the underlying contexts know when we consider a message to be AI generated and renders its internal StreamingMessageView whenever this is true.

Let us say that a message is considered AI generated if the message.ai_generated property is set to true.

In that case, our factory function would look something like this:

const isMessageAIGenerated = (message: LocalMessage) => !!message.ai_generated;

Then, we can simply pass our new StreamingMessageView like so:

import { StreamingMessageView } from "@stream-io/chat-react-native-ai";

const CustomStreamingMessageView = () => {
  const { message } = useMessageContext();
  return (
    <View style={{ width: "100%", paddingHorizontal: 16 }}>
      <StreamingMessageView text={message.text ?? ""} />
    </View>
  );
};

// ...

<Channel
  {...otherChannelProps}
  StreamingMessageView={CustomStreamingMessageView}
/>;

and this will create a full width message that uses the StreamingMessageView from @stream-io/chat-react-native-ai instead of the default one.

ComposerView

To use the ComposerView, you’ll only really need to create a resolver for the purposes of sending a message and then use it instead of our standard MessageInput.

That would look something like this:

import { ComposerView } from "@stream-io/chat-react-native-ai";

const CustomComposerView = () => {
  const messageComposer = useMessageComposer();
  const { sendMessage } = useMessageInputContext();
  const { channel } = useChannelContext();

  const { aiState } = useAIState(channel);

  const stopGenerating = useCallback(
    () => channel?.stopAIResponse(),
    [channel],
  );

  const isGenerating = [AIStates.Thinking, AIStates.Generating].includes(
    aiState,
  );

  const serializeToMessage = useStableCallback(
    async ({ text, attachments }: { text: string; attachments?: any[] }) => {
      messageComposer.textComposer.setText(text);
      if (attachments && attachments.length > 0) {
        const localAttachments = await Promise.all(
          attachments.map((a) =>
            messageComposer.attachmentManager.fileToLocalUploadAttachment(a),
          ),
        );
        messageComposer.attachmentManager.upsertAttachments(localAttachments);
      }

      await sendMessage();
    },
  );

  return (
    <ComposerView
      onSendMessage={serializeToMessage}
      isGenerating={isGenerating}
      stopGenerating={stopGenerating}
    />
  );
};

What this does is the following:

  • It accepts the text and attachment props and sets them to our messageComposer state, through messageComposer.setText and messageComposer.upsertAttachments
  • It invokes sendMessage from our MessageInputContext once the composer is updated and let the SDK handle all the rest
  • It also passes isGenerating and stopGenerating to the composer so we also get the stop generating button

AITypingIndicatorView

You can also add thinking indicators, for example just below the MessageList and just above the ComposerView (or MessageInput).

Doing that would look something like this:

import { AITypingIndicatorView } from "@stream-io/chat-react-native-ai";

const CustomAIThinkingIndicatorView = () => {
  const { channel } = useChannelContext();
  const { aiState } = useAIState(channel);

  const allowedStates = {
    [AIStates.Thinking]: "Thinking about the question...",
    [AIStates.Generating]: "Generating a response...",
    [AIStates.ExternalSources]: "Checking external sources...",
  };

  if (aiState === AIStates.Idle || aiState === AIStates.Error) {
    return null;
  }

  return (
    <View
      style={{
        paddingHorizontal: 24,
        paddingVertical: 12,
      }}
    >
      <AITypingIndicatorView text={allowedStates[aiState]} />
    </View>
  );
};

// ...

<Channel {...channelProps}>
  <MessageList />
  <CustomAIThinkingIndicatorView />
  <CustomComposerView />
</Channel>;
© Getstream.io, Inc. All Rights Reserved.