Skip to content

Commit

Permalink
feat: Add start stream message function
Browse files Browse the repository at this point in the history
  • Loading branch information
tjtanjin committed Nov 22, 2024
1 parent ee6071e commit e1b24ba
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 25 deletions.
13 changes: 13 additions & 0 deletions __tests__/hooks/internal/useMessagesInternal.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ describe("useMessagesInternal", () => {
it("should return expected functions and values", () => {
const { result } = renderHook(() => useMessagesInternal());

expect(result.current).toHaveProperty("startStreamMessage");
expect(result.current).toHaveProperty("endStreamMessage");
expect(result.current).toHaveProperty("injectMessage");
expect(result.current).toHaveProperty("removeMessage");
Expand Down Expand Up @@ -107,6 +108,18 @@ describe("useMessagesInternal", () => {
expect(mockStreamMessageMap.current.has("BOT")).toBeTruthy();
});

it("should start stream message correctly", async () => {
mockStreamMessageMap.current.set("BOT", "test-id");
const { result } = renderHook(() => useMessagesInternal());

await act(async () => {
const success = await result.current.startStreamMessage("BOT");
expect(success).toBeTruthy();
});

expect(mockStreamMessageMap.current.has("BOT")).toBeTruthy();
});

it("should end stream message correctly", async () => {
mockStreamMessageMap.current.set("BOT", "test-id");
const { result } = renderHook(() => useMessagesInternal());
Expand Down
1 change: 1 addition & 0 deletions __tests__/services/BlockService/BlockService.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ describe("BlockService", () => {
setTextAreaValue: jest.fn(),
streamMessage: jest.fn(),
removeMessage: jest.fn(),
startStreamMessage: jest.fn(),
endStreamMessage: jest.fn(),
showToast: jest.fn(),
dismissToast: jest.fn(),
Expand Down
1 change: 1 addition & 0 deletions __tests__/services/BlockService/PathProcessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const params: Params = {
injectMessage: jest.fn(),
streamMessage: jest.fn(),
removeMessage: jest.fn(),
startStreamMessage: jest.fn(),
endStreamMessage: jest.fn(),
showToast: jest.fn(),
dismissToast: jest.fn(),
Expand Down
1 change: 1 addition & 0 deletions __tests__/services/FunctionProcessor.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe('processFunction', () => {
injectMessage: jest.fn(),
streamMessage: jest.fn(),
removeMessage: jest.fn(),
startStreamMessage: jest.fn(),
endStreamMessage: jest.fn(),
showToast: jest.fn(),
dismissToast: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,13 @@ const FileAttachmentButton = () => {
const { styles } = useStylesContext();

// handles messages
const { injectMessage, streamMessage, removeMessage, endStreamMessage } = useMessagesInternal();
const {
injectMessage,
streamMessage,
removeMessage,
endStreamMessage,
startStreamMessage,
} = useMessagesInternal();

// handles paths and blocks
const { getCurrPath, getPrevPath, goToPath, blockAllowsAttachment } = usePathsInternal();
Expand Down Expand Up @@ -124,7 +130,7 @@ const FileAttachmentButton = () => {
await handleSubmitText("📄 " + fileNames.join(", "), settings.fileAttachment?.sendFileName);
await fileHandler({userInput: inputRef.current?.value as string, prevPath: getPrevPath(),
currPath: getCurrPath(), goToPath, setTextAreaValue, injectMessage, streamMessage,
removeMessage, endStreamMessage, openChat, showToast, dismissToast, files
removeMessage, startStreamMessage, endStreamMessage, openChat, showToast, dismissToast, files
});
}
};
Expand Down
5 changes: 3 additions & 2 deletions src/hooks/internal/useBotEffectsInternal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const useBotEffectsInternal = () => {

// handles messages
const {
startStreamMessage,
endStreamMessage,
injectMessage,
removeMessage,
Expand Down Expand Up @@ -234,8 +235,8 @@ export const useBotEffectsInternal = () => {
}

const params = {prevPath: getPrevPath(), currPath: getCurrPath(), goToPath, setTextAreaValue,
userInput: paramsInputRef.current, endStreamMessage, injectMessage, removeMessage, streamMessage,
openChat, showToast, dismissToast
userInput: paramsInputRef.current, startStreamMessage, endStreamMessage, injectMessage,
removeMessage, streamMessage, openChat, showToast, dismissToast
};

// calls the new block for preprocessing upon change to path.
Expand Down
61 changes: 42 additions & 19 deletions src/hooks/internal/useMessagesInternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,24 +209,8 @@ export const useMessagesInternal = () => {
sender = sender.toUpperCase();

if (!streamMessageMap.current.has(sender)) {
const message = createMessage(content, sender);
// handles start stream message event
if (settings.event?.rcbStartStreamMessage) {
const event = await callRcbEvent(RcbEvent.START_STREAM_MESSAGE, {message});
if (event.defaultPrevented) {
return null;
}
}

setIsBotTyping(false);
setMessages((prevMessages) => {
const updatedMessages = [...prevMessages, message];
handlePostMessagesUpdate(updatedMessages);
return [...prevMessages, message];
});
setUnreadCount(prev => prev + 1);
streamMessageMap.current.set(sender, message.id);
return message.id;
await startStreamMessage(sender);
return streamMessageMap.current.get(sender) ?? null;
}

const message = {...createMessage(content, sender), id: streamMessageMap.current.get(sender) as string};
Expand Down Expand Up @@ -254,7 +238,45 @@ export const useMessagesInternal = () => {
},[callRcbEvent, settings.event?.rcbChunkStreamMessage, settings.event?.rcbStartStreamMessage, streamMessageMap]);

/**
* Sets the streaming mode of the chatbot.
* Starts the stream for specified sender.
*
* @param sender sender whose stream is being started
*
* Note: This is not strictly needed, since there are auto-detections to start stream
* of messages in place. However, it is recommended to specify this for code clarity and
* for future-proofing.
*/
const startStreamMessage = useCallback(async (sender = "BOT"): Promise<boolean> => {
// always convert to uppercase for checks
sender = sender.toUpperCase();

// nothing to start if already streaming
if (streamMessageMap.current.has(sender)) {
return true;
}

// handles start stream message event
const message = createMessage("", sender);
if (settings.event?.rcbStartStreamMessage) {
const event = await callRcbEvent(RcbEvent.START_STREAM_MESSAGE, {message});
if (event.defaultPrevented) {
return false;
}
}

setIsBotTyping(false);
setMessages((prevMessages) => {
const updatedMessages = [...prevMessages, message];
handlePostMessagesUpdate(updatedMessages);
return [...prevMessages, message];
});
setUnreadCount(prev => prev + 1);
streamMessageMap.current.set(sender, message.id);
return true;
}, [callRcbEvent, messages, settings.event?.rcbStartStreamMessage, streamMessageMap])

/**
* Ends the stream for specified sender.
*
* @param sender sender whose stream is being ended
*
Expand Down Expand Up @@ -346,6 +368,7 @@ export const useMessagesInternal = () => {
}, [handlePostMessagesUpdate])

return {
startStreamMessage,
endStreamMessage,
injectMessage,
removeMessage,
Expand Down
11 changes: 9 additions & 2 deletions src/hooks/internal/useSubmitInputInternal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ export const useSubmitInputInternal = () => {
const { settings } = useSettingsContext();

// handles messages
const { endStreamMessage, injectMessage, removeMessage, streamMessage } = useMessagesInternal();
const {
startStreamMessage,
endStreamMessage,
injectMessage,
removeMessage,
streamMessage
} = useMessagesInternal();

// handles paths
const { getCurrPath, getPrevPath, goToPath } = usePathsInternal();
Expand Down Expand Up @@ -143,7 +149,8 @@ export const useSubmitInputInternal = () => {

setTimeout(async () => {
const params = {prevPath: getPrevPath(), currPath: getCurrPath(), goToPath, setTextAreaValue, userInput,
injectMessage, streamMessage, removeMessage, endStreamMessage, openChat, showToast, dismissToast
injectMessage, streamMessage, removeMessage, startStreamMessage, endStreamMessage, openChat,
showToast, dismissToast
};
const hasNextPath = await postProcessBlock(flowRef.current as Flow, path, params, goToPath);
if (!hasNextPath) {
Expand Down
2 changes: 2 additions & 0 deletions src/hooks/useMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useMessagesInternal } from "./internal/useMessagesInternal";
export const useMessages = () => {
// handles messages
const {
startStreamMessage,
endStreamMessage,
injectMessage,
removeMessage,
Expand All @@ -15,6 +16,7 @@ export const useMessages = () => {
} = useMessagesInternal();

return {
startStreamMessage,
endStreamMessage,
injectMessage,
removeMessage,
Expand Down
1 change: 1 addition & 0 deletions src/types/Params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type Params = {
injectMessage: (content: string | JSX.Element, sender?: string) => Promise<string | null>;
streamMessage: (content: string | JSX.Element, sender?: string) => Promise<string | null>;
removeMessage: (id: string) => Promise<string | null>;
startStreamMessage: (sender: string) => Promise<boolean>;
endStreamMessage: (sender: string) => Promise<boolean>;
showToast: (content: string | JSX.Element, timeout?: number) => Promise<string | null>;
dismissToast: (id: string) => Promise<string | null>;
Expand Down

0 comments on commit e1b24ba

Please sign in to comment.