2
0
Files
bot/apps/viewer/src/features/chat/api/utils/executeGroup.ts

177 lines
5.1 KiB
TypeScript
Raw Normal View History

import { deepParseVariable } from '@/features/variables'
2022-11-29 10:02:40 +01:00
import {
BubbleBlock,
BubbleBlockType,
2022-11-29 10:02:40 +01:00
ChatReply,
Group,
InputBlock,
InputBlockType,
RuntimeOptions,
2022-11-29 10:02:40 +01:00
SessionState,
} from '@typebot.io/schemas'
2022-11-29 10:02:40 +01:00
import {
isBubbleBlock,
isDefined,
2022-11-29 10:02:40 +01:00
isInputBlock,
isIntegrationBlock,
isLogicBlock,
} from '@typebot.io/lib'
2022-11-29 10:02:40 +01:00
import { executeLogic } from './executeLogic'
import { getNextGroup } from './getNextGroup'
import { executeIntegration } from './executeIntegration'
import { computePaymentInputRuntimeOptions } from '@/features/blocks/inputs/payment/api'
import { injectVariableValuesInButtonsInputBlock } from '@/features/blocks/inputs/buttons/api/utils/injectVariableValuesInButtonsInputBlock'
2022-11-29 10:02:40 +01:00
export const executeGroup =
(
state: SessionState,
currentReply?: ChatReply,
currentLastBubbleId?: string
) =>
2022-11-29 10:02:40 +01:00
async (
group: Group
): Promise<ChatReply & { newSessionState: SessionState }> => {
2022-11-29 10:02:40 +01:00
const messages: ChatReply['messages'] = currentReply?.messages ?? []
let clientSideActions: ChatReply['clientSideActions'] =
currentReply?.clientSideActions
let logs: ChatReply['logs'] = currentReply?.logs
2022-11-29 10:02:40 +01:00
let nextEdgeId = null
let lastBubbleBlockId: string | undefined = currentLastBubbleId
2022-11-29 10:02:40 +01:00
let newSessionState = state
for (const block of group.blocks) {
nextEdgeId = block.outgoingEdgeId
if (isBubbleBlock(block)) {
messages.push(
parseBubbleBlock(newSessionState.typebot.variables)(block)
)
lastBubbleBlockId = block.id
2022-11-29 10:02:40 +01:00
continue
}
if (isInputBlock(block))
return {
messages,
input: await injectVariablesValueInBlock(newSessionState)(block),
2022-11-29 10:02:40 +01:00
newSessionState: {
...newSessionState,
currentBlock: {
groupId: group.id,
blockId: block.id,
},
},
clientSideActions,
logs,
2022-11-29 10:02:40 +01:00
}
const executionResponse = isLogicBlock(block)
? await executeLogic(newSessionState, lastBubbleBlockId)(block)
2022-11-29 10:02:40 +01:00
: isIntegrationBlock(block)
? await executeIntegration(newSessionState, lastBubbleBlockId)(block)
2022-11-29 10:02:40 +01:00
: null
if (!executionResponse) continue
if (
'clientSideActions' in executionResponse &&
executionResponse.clientSideActions
)
clientSideActions = [
...(clientSideActions ?? []),
...executionResponse.clientSideActions,
]
if (executionResponse.logs)
logs = [...(logs ?? []), ...executionResponse.logs]
2022-11-29 10:02:40 +01:00
if (executionResponse.newSessionState)
newSessionState = executionResponse.newSessionState
if (executionResponse.outgoingEdgeId) {
2022-11-29 10:02:40 +01:00
nextEdgeId = executionResponse.outgoingEdgeId
break
}
2022-11-29 10:02:40 +01:00
}
if (!nextEdgeId)
return { messages, newSessionState, clientSideActions, logs }
2022-11-29 10:02:40 +01:00
const nextGroup = getNextGroup(newSessionState)(nextEdgeId)
if (nextGroup?.updatedContext) newSessionState = nextGroup.updatedContext
if (!nextGroup) {
return { messages, newSessionState, clientSideActions, logs }
2022-11-29 10:02:40 +01:00
}
return executeGroup(
newSessionState,
{
messages,
clientSideActions,
logs,
},
lastBubbleBlockId
)(nextGroup.group)
2022-11-29 10:02:40 +01:00
}
const computeRuntimeOptions =
(state: Pick<SessionState, 'result' | 'typebot'>) =>
(block: InputBlock): Promise<RuntimeOptions> | undefined => {
switch (block.type) {
case InputBlockType.PAYMENT: {
return computePaymentInputRuntimeOptions(state)(block.options)
}
}
}
const getPrefilledInputValue =
(variables: SessionState['typebot']['variables']) => (block: InputBlock) => {
const variableValue = variables.find(
(variable) =>
variable.id === block.options.variableId && isDefined(variable.value)
)?.value
if (!variableValue || Array.isArray(variableValue)) return
return variableValue
}
const parseBubbleBlock =
(variables: SessionState['typebot']['variables']) =>
(block: BubbleBlock): ChatReply['messages'][0] => {
switch (block.type) {
case BubbleBlockType.EMBED: {
const message = deepParseVariable(variables)(block)
return {
...message,
content: {
...message.content,
height:
typeof message.content.height === 'string'
? parseFloat(message.content.height)
: message.content.height,
},
}
}
default:
return deepParseVariable(variables)(block)
}
}
const injectVariablesValueInBlock =
(state: Pick<SessionState, 'result' | 'typebot'>) =>
async (block: InputBlock): Promise<ChatReply['input']> => {
switch (block.type) {
case InputBlockType.CHOICE: {
return injectVariableValuesInButtonsInputBlock(state.typebot.variables)(
block
)
}
default: {
return deepParseVariable(state.typebot.variables)({
...block,
runtimeOptions: await computeRuntimeOptions(state)(block),
prefilledValue: getPrefilledInputValue(state.typebot.variables)(
block
),
})
}
}
}