From b9acf9d0c7ea4fddf509aaa9f0e9e2d0ce6823fb Mon Sep 17 00:00:00 2001 From: Mohamed Marrouchi Date: Thu, 12 Jun 2025 11:34:17 +0100 Subject: [PATCH] refactor: block fallback options --- api/src/chat/constants/block.ts | 17 +++++++++++++ api/src/chat/constants/conversation.ts | 28 +++++++++++++++++++++ api/src/chat/schemas/conversation.schema.ts | 19 ++------------ api/src/chat/schemas/types/options.ts | 16 ++++++------ api/src/chat/services/block.service.ts | 15 +++++++++++ api/src/chat/services/bot.service.ts | 7 ++---- 6 files changed, 73 insertions(+), 29 deletions(-) create mode 100644 api/src/chat/constants/block.ts create mode 100644 api/src/chat/constants/conversation.ts diff --git a/api/src/chat/constants/block.ts b/api/src/chat/constants/block.ts new file mode 100644 index 00000000..d8c36afe --- /dev/null +++ b/api/src/chat/constants/block.ts @@ -0,0 +1,17 @@ +/* + * Copyright © 2025 Hexastack. All rights reserved. + * + * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: + * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. + * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). + */ + +import { FallbackOptions } from '../schemas/types/options'; + +export function getDefaultFallbackOptions(): FallbackOptions { + return { + active: false, + max_attempts: 0, + message: [], + }; +} diff --git a/api/src/chat/constants/conversation.ts b/api/src/chat/constants/conversation.ts new file mode 100644 index 00000000..2191e90d --- /dev/null +++ b/api/src/chat/constants/conversation.ts @@ -0,0 +1,28 @@ +/* + * Copyright © 2025 Hexastack. All rights reserved. + * + * Licensed under the GNU Affero General Public License v3.0 (AGPLv3) with the following additional terms: + * 1. The name "Hexabot" is a trademark of Hexastack. You may not use this name in derivative works without express written permission. + * 2. All derivative works must include clear attribution to the original creator and software, Hexastack and Hexabot, in a prominent location (e.g., in the software's "About" section, documentation, and README file). + */ + +import { Subscriber } from '../schemas/subscriber.schema'; +import { Context } from '../schemas/types/context'; + +export function getDefaultConversationContext(): Context { + return { + vars: {}, // Used for capturing vars from user entries + user: { + first_name: '', + last_name: '', + // @TODO: Typing is not correct + } as Subscriber, + user_location: { + // Used for capturing geolocation from QR + lat: 0.0, + lon: 0.0, + }, + skip: {}, // Used for list pagination + attempt: 0, // Used to track fallback max attempts + }; +} diff --git a/api/src/chat/schemas/conversation.schema.ts b/api/src/chat/schemas/conversation.schema.ts index 6d5a0aae..312745bf 100644 --- a/api/src/chat/schemas/conversation.schema.ts +++ b/api/src/chat/schemas/conversation.schema.ts @@ -17,27 +17,12 @@ import { THydratedDocument, } from '@/utils/types/filter.types'; +import { getDefaultConversationContext } from '../constants/conversation'; + import { Block } from './block.schema'; import { Subscriber } from './subscriber.schema'; import { Context } from './types/context'; -export function getDefaultConversationContext(): Context { - return { - vars: {}, // Used for capturing vars from user entries - user: { - first_name: '', - last_name: '', - } as Subscriber, - user_location: { - // Used for capturing geolocation from QR - lat: 0.0, - lon: 0.0, - }, - skip: {}, // Used for list pagination - attempt: 0, // Used to track fallback max attempts - }; -} - @Schema({ timestamps: true, minimize: false }) class ConversationStub extends BaseSchema { @Prop({ diff --git a/api/src/chat/schemas/types/options.ts b/api/src/chat/schemas/types/options.ts index f413a56d..b483a8f6 100644 --- a/api/src/chat/schemas/types/options.ts +++ b/api/src/chat/schemas/types/options.ts @@ -29,16 +29,18 @@ export const contentOptionsSchema = z.object({ export type ContentOptions = z.infer; +export const fallbackOptionsSchema = z.object({ + active: z.boolean(), + message: z.array(z.string()), + max_attempts: z.number().finite(), +}); + +export type FallbackOptions = z.infer; + export const BlockOptionsSchema = z.object({ typing: z.number().optional(), content: contentOptionsSchema.optional(), - fallback: z - .object({ - active: z.boolean(), - message: z.array(z.string()), - max_attempts: z.number().finite(), - }) - .optional(), + fallback: fallbackOptionsSchema.optional(), assignTo: z.string().optional(), effects: z.array(z.string()).optional(), }); diff --git a/api/src/chat/services/block.service.ts b/api/src/chat/services/block.service.ts index af561a7e..54a76eeb 100644 --- a/api/src/chat/services/block.service.ts +++ b/api/src/chat/services/block.service.ts @@ -23,6 +23,7 @@ import { FALLBACK_DEFAULT_NLU_PENALTY_FACTOR } from '@/utils/constants/nlp'; import { BaseService } from '@/utils/generics/base-service'; import { getRandomElement } from '@/utils/helpers/safeRandom'; +import { getDefaultFallbackOptions } from '../constants/block'; import { BlockDto } from '../dto/block.dto'; import { EnvelopeFactory } from '../helpers/envelope-factory'; import { BlockRepository } from '../repositories/block.repository'; @@ -40,6 +41,7 @@ import { StdOutgoingEnvelope, StdOutgoingSystemEnvelope, } from '../schemas/types/message'; +import { FallbackOptions } from '../schemas/types/options'; import { NlpPattern, PayloadPattern } from '../schemas/types/pattern'; import { Payload } from '../schemas/types/quick-reply'; import { SubscriberContext } from '../schemas/types/subscriberContext'; @@ -775,6 +777,19 @@ export class BlockService extends BaseService< throw new Error('Invalid message format.'); } + /** + * Retrieves the fallback options for a block. + * + * @param block - The block to retrieve fallback options from. + * @returns The fallback options for the block, or default options if not specified. + */ + getFallbackOptions(block: T): FallbackOptions { + const fallbackOptions: FallbackOptions = block.options?.fallback + ? block.options.fallback + : getDefaultFallbackOptions(); + return fallbackOptions; + } + /** * Updates the `trigger_labels` and `assign_labels` fields of a block when a label is deleted. * diff --git a/api/src/chat/services/bot.service.ts b/api/src/chat/services/bot.service.ts index 7052d961..0eeaf5ea 100644 --- a/api/src/chat/services/bot.service.ts +++ b/api/src/chat/services/bot.service.ts @@ -14,13 +14,10 @@ import EventWrapper from '@/channel/lib/EventWrapper'; import { LoggerService } from '@/logger/logger.service'; import { SettingService } from '@/setting/services/setting.service'; +import { getDefaultConversationContext } from '../constants/conversation'; import { MessageCreateDto } from '../dto/message.dto'; import { BlockFull } from '../schemas/block.schema'; -import { - Conversation, - ConversationFull, - getDefaultConversationContext, -} from '../schemas/conversation.schema'; +import { Conversation, ConversationFull } from '../schemas/conversation.schema'; import { Context } from '../schemas/types/context'; import { IncomingMessageType,