From c53ce349af438676010b7aade9206cf65238ed60 Mon Sep 17 00:00:00 2001 From: Baptiste Arnaud Date: Thu, 23 May 2024 16:30:56 +0200 Subject: [PATCH] :zap: (api) Add textBubbleContentFormat option Closes #1111 --- .../features/whatsapp/startWhatsAppPreview.ts | 1 + .../src/features/chat/api/continueChat.ts | 27 +++++++++++------ .../features/chat/api/legacy/sendMessageV1.ts | 8 ++++- .../features/chat/api/legacy/sendMessageV2.ts | 8 ++++- .../src/features/chat/api/startChatPreview.ts | 2 ++ apps/viewer/src/test/chat.spec.ts | 18 +++++++++++ .../bot-engine/apiHandlers/continueChat.ts | 9 +++++- packages/bot-engine/apiHandlers/startChat.ts | 3 ++ .../apiHandlers/startChatPreview.ts | 3 ++ packages/bot-engine/continueBotFlow.ts | 29 +++++++++++++----- packages/bot-engine/executeGroup.ts | 4 +++ packages/bot-engine/parseBubbleBlock.ts | 30 ++++++++++++------- packages/bot-engine/startBotFlow.ts | 4 +++ packages/bot-engine/startSession.ts | 2 ++ .../whatsapp/convertInputToWhatsAppMessage.ts | 3 +- .../convertMessageToWhatsAppMessage.ts | 2 ++ .../bot-engine/whatsapp/resumeWhatsAppFlow.ts | 1 + .../whatsapp/sendChatReplyToWhatsApp.ts | 12 ++++++-- .../whatsapp/startWhatsAppSession.ts | 1 + .../embeds/js/src/queries/startChatQuery.ts | 7 +++-- packages/logic/computeResultTranscript.ts | 5 ++-- packages/schemas/features/chat/schema.ts | 13 +++++++- 22 files changed, 155 insertions(+), 37 deletions(-) diff --git a/apps/builder/src/features/whatsapp/startWhatsAppPreview.ts b/apps/builder/src/features/whatsapp/startWhatsAppPreview.ts index 54e18ab7e..f3ada19db 100644 --- a/apps/builder/src/features/whatsapp/startWhatsAppPreview.ts +++ b/apps/builder/src/features/whatsapp/startWhatsAppPreview.ts @@ -116,6 +116,7 @@ export const startWhatsAppPreview = authenticatedProcedure startFrom, userId: user.id, isStreamEnabled: false, + textBubbleContentFormat: 'richText', }, initialSessionState: { whatsApp: (existingSession?.state as SessionState | undefined) diff --git a/apps/viewer/src/features/chat/api/continueChat.ts b/apps/viewer/src/features/chat/api/continueChat.ts index e628382c2..9af18d22e 100644 --- a/apps/viewer/src/features/chat/api/continueChat.ts +++ b/apps/viewer/src/features/chat/api/continueChat.ts @@ -19,15 +19,24 @@ export const continueChat = publicProcedure .describe( 'The session ID you got from the [startChat](./start-chat) response.' ), + textBubbleContentFormat: z + .enum(['richText', 'markdown']) + .default('richText'), }) ) .output(continueChatResponseSchema) - .mutation(async ({ input: { sessionId, message }, ctx: { origin, res } }) => { - const { corsOrigin, ...response } = await continueChatFn({ - origin, - sessionId, - message, - }) - if (corsOrigin) res.setHeader('Access-Control-Allow-Origin', corsOrigin) - return response - }) + .mutation( + async ({ + input: { sessionId, message, textBubbleContentFormat }, + ctx: { origin, res }, + }) => { + const { corsOrigin, ...response } = await continueChatFn({ + origin, + sessionId, + message, + textBubbleContentFormat, + }) + if (corsOrigin) res.setHeader('Access-Control-Allow-Origin', corsOrigin) + return response + } + ) diff --git a/apps/viewer/src/features/chat/api/legacy/sendMessageV1.ts b/apps/viewer/src/features/chat/api/legacy/sendMessageV1.ts index 2d99e0d1d..34af6f4f0 100644 --- a/apps/viewer/src/features/chat/api/legacy/sendMessageV1.ts +++ b/apps/viewer/src/features/chat/api/legacy/sendMessageV1.ts @@ -92,6 +92,7 @@ export const sendMessageV1 = publicProcedure : startParams.typebot, message, userId: user?.id, + textBubbleContentFormat: 'richText', } : { type: 'live', @@ -101,6 +102,7 @@ export const sendMessageV1 = publicProcedure prefilledVariables: startParams.prefilledVariables, resultId: startParams.resultId, message, + textBubbleContentFormat: 'richText', }, message, }) @@ -179,7 +181,11 @@ export const sendMessageV1 = publicProcedure lastMessageNewFormat, visitedEdges, setVariableHistory, - } = await continueBotFlow(message, { version: 1, state: session.state }) + } = await continueBotFlow(message, { + version: 1, + state: session.state, + textBubbleContentFormat: 'richText', + }) const allLogs = clientLogs ? [...(logs ?? []), ...clientLogs] : logs diff --git a/apps/viewer/src/features/chat/api/legacy/sendMessageV2.ts b/apps/viewer/src/features/chat/api/legacy/sendMessageV2.ts index 2ef11b9c1..ddf4c7a79 100644 --- a/apps/viewer/src/features/chat/api/legacy/sendMessageV2.ts +++ b/apps/viewer/src/features/chat/api/legacy/sendMessageV2.ts @@ -92,6 +92,7 @@ export const sendMessageV2 = publicProcedure : startParams.typebot, message, userId: user?.id, + textBubbleContentFormat: 'richText', } : { type: 'live', @@ -101,6 +102,7 @@ export const sendMessageV2 = publicProcedure prefilledVariables: startParams.prefilledVariables, resultId: startParams.resultId, message, + textBubbleContentFormat: 'richText', }, message, }) @@ -178,7 +180,11 @@ export const sendMessageV2 = publicProcedure lastMessageNewFormat, visitedEdges, setVariableHistory, - } = await continueBotFlow(message, { version: 2, state: session.state }) + } = await continueBotFlow(message, { + version: 2, + state: session.state, + textBubbleContentFormat: 'richText', + }) const allLogs = clientLogs ? [...(logs ?? []), ...clientLogs] : logs diff --git a/apps/viewer/src/features/chat/api/startChatPreview.ts b/apps/viewer/src/features/chat/api/startChatPreview.ts index f24873e39..e2fab093f 100644 --- a/apps/viewer/src/features/chat/api/startChatPreview.ts +++ b/apps/viewer/src/features/chat/api/startChatPreview.ts @@ -28,6 +28,7 @@ export const startChatPreview = publicProcedure typebot: startTypebot, prefilledVariables, sessionId, + textBubbleContentFormat, }, ctx: { user }, }) => @@ -41,5 +42,6 @@ export const startChatPreview = publicProcedure userId: user?.id, prefilledVariables, sessionId, + textBubbleContentFormat, }) ) diff --git a/apps/viewer/src/test/chat.spec.ts b/apps/viewer/src/test/chat.spec.ts index edddd66c0..6d14715d0 100644 --- a/apps/viewer/src/test/chat.spec.ts +++ b/apps/viewer/src/test/chat.spec.ts @@ -48,6 +48,7 @@ test('API chat execution should work on preview bot', async ({ request }) => { data: { isOnlyRegistering: false, isStreamEnabled: false, + textBubbleContentFormat: 'richText', } satisfies Omit, }) ).json() @@ -120,6 +121,7 @@ test('API chat execution should work on published bot', async ({ request }) => { data: { isOnlyRegistering: false, isStreamEnabled: false, + textBubbleContentFormat: 'richText', } satisfies Omit, }) ).json() @@ -302,6 +304,7 @@ test('API chat execution should work on published bot', async ({ request }) => { message: 'Hey', isStreamEnabled: false, isOnlyRegistering: false, + textBubbleContentFormat: 'richText', } satisfies Omit, } ) @@ -317,4 +320,19 @@ test('API chat execution should work on published bot', async ({ request }) => { }, ]) }) + await test.step('Markdown text bubble format should work', async () => { + const { messages } = await ( + await request.post(`/api/v1/typebots/${typebotId}/preview/startChat`, { + data: { + isOnlyRegistering: false, + isStreamEnabled: false, + textBubbleContentFormat: 'markdown', + } satisfies Omit, + }) + ).json() + expect(messages[0].content.markdown).toStrictEqual('Hi there! 👋') + expect(messages[1].content.markdown).toStrictEqual( + 'Welcome. What's your name?' + ) + }) }) diff --git a/packages/bot-engine/apiHandlers/continueChat.ts b/packages/bot-engine/apiHandlers/continueChat.ts index 778c2ff06..6d3f1d5ce 100644 --- a/packages/bot-engine/apiHandlers/continueChat.ts +++ b/packages/bot-engine/apiHandlers/continueChat.ts @@ -11,8 +11,14 @@ type Props = { origin: string | undefined message?: string sessionId: string + textBubbleContentFormat: 'richText' | 'markdown' } -export const continueChat = async ({ origin, sessionId, message }: Props) => { +export const continueChat = async ({ + origin, + sessionId, + message, + textBubbleContentFormat, +}: Props) => { const session = await getSession(sessionId) if (!session) { @@ -57,6 +63,7 @@ export const continueChat = async ({ origin, sessionId, message }: Props) => { version: 2, state: session.state, startTime: Date.now(), + textBubbleContentFormat, }) if (newSessionState) diff --git a/packages/bot-engine/apiHandlers/startChat.ts b/packages/bot-engine/apiHandlers/startChat.ts index a7558fd06..5776f417e 100644 --- a/packages/bot-engine/apiHandlers/startChat.ts +++ b/packages/bot-engine/apiHandlers/startChat.ts @@ -12,6 +12,7 @@ type Props = { isStreamEnabled: boolean prefilledVariables?: Record resultId?: string + textBubbleContentFormat: 'richText' | 'markdown' } export const startChat = async ({ @@ -22,6 +23,7 @@ export const startChat = async ({ isStreamEnabled, prefilledVariables, resultId: startResultId, + textBubbleContentFormat, }: Props) => { const { typebot, @@ -43,6 +45,7 @@ export const startChat = async ({ publicId, prefilledVariables, resultId: startResultId, + textBubbleContentFormat, }, message, }) diff --git a/packages/bot-engine/apiHandlers/startChatPreview.ts b/packages/bot-engine/apiHandlers/startChatPreview.ts index 82d2f65db..e2f488ee6 100644 --- a/packages/bot-engine/apiHandlers/startChatPreview.ts +++ b/packages/bot-engine/apiHandlers/startChatPreview.ts @@ -14,6 +14,7 @@ type Props = { userId?: string prefilledVariables?: Record sessionId?: string + textBubbleContentFormat: 'richText' | 'markdown' } export const startChatPreview = async ({ @@ -26,6 +27,7 @@ export const startChatPreview = async ({ userId, prefilledVariables, sessionId, + textBubbleContentFormat, }: Props) => { const { typebot, @@ -49,6 +51,7 @@ export const startChatPreview = async ({ userId, prefilledVariables, sessionId, + textBubbleContentFormat, }, message, }) diff --git a/packages/bot-engine/continueBotFlow.ts b/packages/bot-engine/continueBotFlow.ts index ac6c83065..c144f4f4f 100644 --- a/packages/bot-engine/continueBotFlow.ts +++ b/packages/bot-engine/continueBotFlow.ts @@ -50,10 +50,11 @@ type Params = { version: 1 | 2 state: SessionState startTime?: number + textBubbleContentFormat: 'richText' | 'markdown' } export const continueBotFlow = async ( reply: Reply, - { state, version, startTime }: Params + { state, version, startTime, textBubbleContentFormat }: Params ): Promise< ContinueChatResponse & { newSessionState: SessionState @@ -66,7 +67,8 @@ export const continueBotFlow = async ( const visitedEdges: VisitedEdge[] = [] const setVariableHistory: SetVariableHistoryItem[] = [] - if (!newSessionState.currentBlockId) return startBotFlow({ state, version }) + if (!newSessionState.currentBlockId) + return startBotFlow({ state, version, textBubbleContentFormat }) const { block, group, blockIndex } = getBlockById( newSessionState.currentBlockId, @@ -167,7 +169,10 @@ export const continueBotFlow = async ( if (parsedReplyResult.status === 'fail') return { - ...(await parseRetryMessage(newSessionState)(block)), + ...(await parseRetryMessage(newSessionState)( + block, + textBubbleContentFormat + )), newSessionState, visitedEdges: [], setVariableHistory: [], @@ -197,6 +202,7 @@ export const continueBotFlow = async ( setVariableHistory, firstBubbleWasStreamed, startTime, + textBubbleContentFormat, } ) return { @@ -243,6 +249,7 @@ export const continueBotFlow = async ( visitedEdges, setVariableHistory, startTime, + textBubbleContentFormat, }) return { @@ -287,7 +294,8 @@ const saveVariableValueIfAny = const parseRetryMessage = (state: SessionState) => async ( - block: InputBlock + block: InputBlock, + textBubbleContentFormat: 'richText' | 'markdown' ): Promise> => { const retryMessage = block.options && @@ -302,9 +310,16 @@ const parseRetryMessage = { id: block.id, type: BubbleBlockType.TEXT, - content: { - richText: [{ type: 'p', children: [{ text: retryMessage }] }], - }, + content: + textBubbleContentFormat === 'richText' + ? { + type: 'richText', + richText: [{ type: 'p', children: [{ text: retryMessage }] }], + } + : { + type: 'markdown', + markdown: retryMessage, + }, }, ], input: await parseInput(state)(block), diff --git a/packages/bot-engine/executeGroup.ts b/packages/bot-engine/executeGroup.ts index 285a33ba2..1861803ba 100644 --- a/packages/bot-engine/executeGroup.ts +++ b/packages/bot-engine/executeGroup.ts @@ -42,6 +42,7 @@ type ContextProps = { visitedEdges: VisitedEdge[] setVariableHistory: SetVariableHistoryItem[] startTime?: number + textBubbleContentFormat: 'richText' | 'markdown' } export const executeGroup = async ( @@ -55,6 +56,7 @@ export const executeGroup = async ( currentLastBubbleId, firstBubbleWasStreamed, startTime, + textBubbleContentFormat, }: ContextProps ): Promise< ContinueChatResponse & { @@ -98,6 +100,7 @@ export const executeGroup = async ( version, variables: newSessionState.typebotsQueue[0].typebot.variables, typebotVersion: newSessionState.typebotsQueue[0].typebot.version, + textBubbleContentFormat, }) ) lastBubbleBlockId = block.id @@ -250,6 +253,7 @@ export const executeGroup = async ( }, currentLastBubbleId: lastBubbleBlockId, startTime: newStartTime, + textBubbleContentFormat, }) } diff --git a/packages/bot-engine/parseBubbleBlock.ts b/packages/bot-engine/parseBubbleBlock.ts index 74da1c4a2..dfca6ad70 100644 --- a/packages/bot-engine/parseBubbleBlock.ts +++ b/packages/bot-engine/parseBubbleBlock.ts @@ -11,15 +11,17 @@ import { getVariablesToParseInfoInText, parseVariables, } from '@typebot.io/variables/parseVariables' -import { TDescendant } from '@udecode/plate-common' +import { TDescendant, TElement } from '@udecode/plate-common' import { BubbleBlockType } from '@typebot.io/schemas/features/blocks/bubbles/constants' import { defaultVideoBubbleContent } from '@typebot.io/schemas/features/blocks/bubbles/video/constants' import { convertMarkdownToRichText } from '@typebot.io/lib/markdown/convertMarkdownToRichText' +import { convertRichTextToMarkdown } from '@typebot.io/lib/markdown/convertRichTextToMarkdown' type Params = { version: 1 | 2 typebotVersion: Typebot['version'] variables: Variable[] + textBubbleContentFormat: 'richText' | 'markdown' } export type BubbleBlockWithDefinedContent = BubbleBlock & { @@ -28,7 +30,7 @@ export type BubbleBlockWithDefinedContent = BubbleBlock & { export const parseBubbleBlock = ( block: BubbleBlockWithDefinedContent, - { version, variables, typebotVersion }: Params + { version, variables, typebotVersion, textBubbleContentFormat }: Params ): ContinueChatResponse['messages'][0] => { switch (block.type) { case BubbleBlockType.TEXT: { @@ -36,21 +38,29 @@ export const parseBubbleBlock = ( return { ...block, content: { - ...block.content, + type: 'richText', richText: (block.content?.richText ?? []).map( deepParseVariables(variables) ), }, } + + const richText = parseVariablesInRichText(block.content?.richText ?? [], { + variables, + takeLatestIfList: typebotVersion !== '6', + }).parsedElements return { ...block, - content: { - ...block.content, - richText: parseVariablesInRichText(block.content?.richText ?? [], { - variables, - takeLatestIfList: typebotVersion !== '6', - }).parsedElements, - }, + content: + textBubbleContentFormat === 'richText' + ? { + type: 'richText', + richText, + } + : { + type: 'markdown', + markdown: convertRichTextToMarkdown(richText as TElement[]), + }, } } diff --git a/packages/bot-engine/startBotFlow.ts b/packages/bot-engine/startBotFlow.ts index 1f9a18f56..366c638bd 100644 --- a/packages/bot-engine/startBotFlow.ts +++ b/packages/bot-engine/startBotFlow.ts @@ -15,6 +15,7 @@ type Props = { state: SessionState startFrom?: StartFrom startTime?: number + textBubbleContentFormat: 'richText' | 'markdown' } export const startBotFlow = async ({ @@ -22,6 +23,7 @@ export const startBotFlow = async ({ state, startFrom, startTime, + textBubbleContentFormat, }: Props): Promise< ContinueChatResponse & { newSessionState: SessionState @@ -47,6 +49,7 @@ export const startBotFlow = async ({ visitedEdges, setVariableHistory, startTime, + textBubbleContentFormat, }) } const firstEdgeId = getFirstEdgeId({ @@ -74,5 +77,6 @@ export const startBotFlow = async ({ visitedEdges, setVariableHistory, startTime, + textBubbleContentFormat, }) } diff --git a/packages/bot-engine/startSession.ts b/packages/bot-engine/startSession.ts index 05e89c11a..b1644fe0a 100644 --- a/packages/bot-engine/startSession.ts +++ b/packages/bot-engine/startSession.ts @@ -184,6 +184,7 @@ export const startSession = async ({ startFrom: startParams.type === 'preview' ? startParams.startFrom : undefined, startTime: Date.now(), + textBubbleContentFormat: startParams.textBubbleContentFormat, }) // If params has message and first block is an input block, we can directly continue the bot flow @@ -218,6 +219,7 @@ export const startSession = async ({ ...newSessionState, currentBlockId: firstBlock.id, }, + textBubbleContentFormat: startParams.textBubbleContentFormat, }) } } diff --git a/packages/bot-engine/whatsapp/convertInputToWhatsAppMessage.ts b/packages/bot-engine/whatsapp/convertInputToWhatsAppMessage.ts index 0926fd99d..062c30543 100644 --- a/packages/bot-engine/whatsapp/convertInputToWhatsAppMessage.ts +++ b/packages/bot-engine/whatsapp/convertInputToWhatsAppMessage.ts @@ -13,7 +13,8 @@ export const convertInputToWhatsAppMessages = ( lastMessage: ContinueChatResponse['messages'][number] | undefined ): WhatsAppSendingMessage[] => { const lastMessageText = - lastMessage?.type === BubbleBlockType.TEXT + lastMessage?.type === BubbleBlockType.TEXT && + lastMessage.content.type === 'richText' ? convertRichTextToMarkdown(lastMessage.content.richText ?? [], { flavour: 'whatsapp', }) diff --git a/packages/bot-engine/whatsapp/convertMessageToWhatsAppMessage.ts b/packages/bot-engine/whatsapp/convertMessageToWhatsAppMessage.ts index 4ba7d2867..e189a39d7 100644 --- a/packages/bot-engine/whatsapp/convertMessageToWhatsAppMessage.ts +++ b/packages/bot-engine/whatsapp/convertMessageToWhatsAppMessage.ts @@ -17,6 +17,8 @@ export const convertMessageToWhatsAppMessage = ( ): WhatsAppSendingMessage | null => { switch (message.type) { case BubbleBlockType.TEXT: { + if (message.content.type === 'markdown') + throw new Error('Expect rich text message') if (!message.content.richText || message.content.richText.length === 0) return null return { diff --git a/packages/bot-engine/whatsapp/resumeWhatsAppFlow.ts b/packages/bot-engine/whatsapp/resumeWhatsAppFlow.ts index 852643033..a6b826203 100644 --- a/packages/bot-engine/whatsapp/resumeWhatsAppFlow.ts +++ b/packages/bot-engine/whatsapp/resumeWhatsAppFlow.ts @@ -93,6 +93,7 @@ export const resumeWhatsAppFlow = async ({ ? await continueBotFlow(reply, { version: 2, state: { ...session.state, whatsApp: { contact } }, + textBubbleContentFormat: 'richText', }) : workspaceId ? await startWhatsAppSession({ diff --git a/packages/bot-engine/whatsapp/sendChatReplyToWhatsApp.ts b/packages/bot-engine/whatsapp/sendChatReplyToWhatsApp.ts index a7c9ffe98..62b53f8bf 100644 --- a/packages/bot-engine/whatsapp/sendChatReplyToWhatsApp.ts +++ b/packages/bot-engine/whatsapp/sendChatReplyToWhatsApp.ts @@ -58,7 +58,11 @@ export const sendChatReplyToWhatsApp = async ({ const result = await executeClientSideAction({ to, credentials })(action) if (!result) continue const { input, newSessionState, messages, clientSideActions } = - await continueBotFlow(result.replyToSend, { version: 2, state }) + await continueBotFlow(result.replyToSend, { + version: 2, + state, + textBubbleContentFormat: 'richText', + }) return sendChatReplyToWhatsApp({ to, @@ -124,7 +128,11 @@ export const sendChatReplyToWhatsApp = async ({ ) if (!result) continue const { input, newSessionState, messages, clientSideActions } = - await continueBotFlow(result.replyToSend, { version: 2, state }) + await continueBotFlow(result.replyToSend, { + version: 2, + state, + textBubbleContentFormat: 'richText', + }) return sendChatReplyToWhatsApp({ to, diff --git a/packages/bot-engine/whatsapp/startWhatsAppSession.ts b/packages/bot-engine/whatsapp/startWhatsAppSession.ts index c257343f9..88cb96fe9 100644 --- a/packages/bot-engine/whatsapp/startWhatsAppSession.ts +++ b/packages/bot-engine/whatsapp/startWhatsAppSession.ts @@ -96,6 +96,7 @@ export const startWhatsAppSession = async ({ publicId: publicTypebot.typebot.publicId as string, isOnlyRegistering: false, isStreamEnabled: false, + textBubbleContentFormat: 'richText', }, initialSessionState: { whatsApp: { diff --git a/packages/embeds/js/src/queries/startChatQuery.ts b/packages/embeds/js/src/queries/startChatQuery.ts index 67ec82b07..682ec7e00 100644 --- a/packages/embeds/js/src/queries/startChatQuery.ts +++ b/packages/embeds/js/src/queries/startChatQuery.ts @@ -88,7 +88,7 @@ export async function startChatQuery({ sessionId, } satisfies Omit< StartPreviewChatInput, - 'typebotId' | 'isOnlyRegistering' + 'typebotId' | 'isOnlyRegistering' | 'textBubbleContentFormat' >, timeout: false, } @@ -113,7 +113,10 @@ export async function startChatQuery({ prefilledVariables, resultId, isOnlyRegistering: false, - } satisfies Omit, + } satisfies Omit< + StartChatInput, + 'publicId' | 'textBubbleContentFormat' + >, timeout: false, } ) diff --git a/packages/logic/computeResultTranscript.ts b/packages/logic/computeResultTranscript.ts index d6a6eda54..cdb21beb5 100644 --- a/packages/logic/computeResultTranscript.ts +++ b/packages/logic/computeResultTranscript.ts @@ -147,6 +147,7 @@ const executeGroup = ({ version: 2, variables: typebotsQueue[0].typebot.variables, typebotVersion: typebotsQueue[0].typebot.version, + textBubbleContentFormat: 'markdown', } ) const newMessage = @@ -321,11 +322,11 @@ const convertChatMessageToTranscriptMessage = ( ): TranscriptMessage | null => { switch (chatMessage.type) { case BubbleBlockType.TEXT: { - if (!chatMessage.content.richText) return null + if (chatMessage.content.type === 'richText') return null return { role: 'bot', type: 'text', - text: convertRichTextToMarkdown(chatMessage.content.richText), + text: chatMessage.content.markdown, } } case BubbleBlockType.IMAGE: { diff --git a/packages/schemas/features/chat/schema.ts b/packages/schemas/features/chat/schema.ts index f3f27e856..828fb3299 100644 --- a/packages/schemas/features/chat/schema.ts +++ b/packages/schemas/features/chat/schema.ts @@ -47,7 +47,16 @@ export type ChatSession = z.infer const textMessageSchema = z .object({ type: z.literal(BubbleBlockType.TEXT), - content: textBubbleContentSchema, + content: z.discriminatedUnion('type', [ + z.object({ + type: z.literal('richText'), + richText: z.any(), + }), + z.object({ + type: z.literal('markdown'), + markdown: z.string(), + }), + ]), }) .openapi({ title: 'Text', @@ -211,6 +220,7 @@ export const startChatInputSchema = z.object({ Email: 'john@gmail.com', }, }), + textBubbleContentFormat: z.enum(['richText', 'markdown']).default('richText'), }) export type StartChatInput = z.infer @@ -265,6 +275,7 @@ export const startPreviewChatInputSchema = z.object({ .describe( 'If provided, will be used as the session ID and will overwrite any existing session with the same ID.' ), + textBubbleContentFormat: z.enum(['richText', 'markdown']).default('richText'), }) export type StartPreviewChatInput = z.infer