Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/install-flex-plugin/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ runs:
using: "composite"
steps:
- name: Install the Twilio CLI and plugins
run: npm install -g twilio-cli && twilio plugins:install @twilio-labs/plugin-flex@7.0.0
run: npm install -g twilio-cli && twilio plugins:install @twilio-labs/plugin-flex@7.1.2
shell: bash
- name: Install plugin-hrm-form Packages
run: npm ci
Expand Down
10 changes: 3 additions & 7 deletions .github/workflows/e2e-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,19 @@ name: End to End Testing CI
# Action
on: [pull_request, workflow_dispatch]
concurrency: e2e
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
e2e_test:
name: E2E tests
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- name: Checkout Branch
uses: actions/checkout@v6

- name: Use Node.js
uses: actions/setup-node@v6
with:
node-version: '20.x' # some twilio dev deps still complain about node 22 :-(
node-version: '22.x'

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v5
Expand Down
6 changes: 2 additions & 4 deletions e2e-tests/chatScripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,13 @@ import {
import { getConfigValue } from './config';

export const defaultScript: ChatStatement[] = [
botStatement(
'Welcome. To help us better serve you, please answer the following questions. Are you calling about yourself? Please answer Yes or No.',
),
botStatement('Welcome to the helpline. Please answer the following questions.'),
callerStatement('yes'),
botStatement('How old are you?'),
callerStatement('10'),
botStatement('What is your gender?'),
callerStatement('girl'),
botStatement("We'll transfer you now. Please hold for a counsellor."),
botStatement('We will transfer you now. Please hold for a counsellor.'),
counselorAutoStatement('Hi, this is the counsellor. How can I help you?'),
callerStatement('CALLER TEST CHAT MESSAGE'),
counselorStatement('COUNSELLOR TEST CHAT MESSAGE'),
Expand Down
4 changes: 2 additions & 2 deletions e2e-tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
"test": "npx playwright test --workers 1",
"test:ui": "npx playwright test --workers 1 --config ui-tests/playwright.ui-test.config.ts",
"test:local": "cross-env DEBUG=pw:api LOAD_SSM_CONFIG=true npm run test",
"test:local:debug": "cross-env DEBUG=pw:api LOAD_SSM_CONFIG=true npm run test -- --headed --debug --retries 0 caselist.spec.ts",
"test:local:debug": "cross-env DEBUG=pw:api LOAD_SSM_CONFIG=true npm run test -- --headed --debug --retries 0 offline",
"test:development:as": "cross-env DEBUG=pw:api LOAD_SSM_CONFIG=true HL_ENV=development HL=as SKIP_DATA_UPDATE=true npm run test",
"test:development:as:debug": "cross-env DEBUG=pw:api LOAD_SSM_CONFIG=true HL_ENV=development HL=as SKIP_DATA_UPDATE=true npm run test -- --headed --retries 0 login",
"test:development:as:debug": "cross-env DEBUG=pw:api LOAD_SSM_CONFIG=true HL_ENV=development HL=as SKIP_DATA_UPDATE=true npm run test -- --headed --retries 0",
"test:development:e2e": "cross-env DEBUG=pw:api LOAD_SSM_CONFIG=true HL_ENV=development HL=e2e npm run test",
"test:development:e2e:local": "cross-env LOAD_SSM_CONFIG=true HL_ENV=development HL=e2e npm run test -- --headed",
"test:development:e2e:debug": "cross-env DEBUG=pw:api LOAD_SSM_CONFIG=true HL_ENV=development HL=e2e npm run test -- --headed --debug --retries 0 login",
Expand Down
49 changes: 10 additions & 39 deletions lambdas/account-scoped/src/channelCapture/channelCaptureHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,10 @@ const releaseTypes = ['triggerStudioFlow', 'postSurveyComplete'] as const;
export type ReleaseTypes = (typeof releaseTypes)[number];

export type CapturedChannelAttributes = {
enableLexV2: boolean;
userId: string;
environment: string;
helplineCode: string;
botLanguage: string;
botLanguageV1: string;
botSuffix: string;
controlTaskSid: string;
releaseType: ReleaseTypes;
Expand Down Expand Up @@ -93,12 +91,10 @@ const updateChannelWithCapture = async (
attributes: CapturedChannelAttributes,
) => {
const {
enableLexV2,
userId,
environment,
helplineCode,
botLanguage,
botLanguageV1,
botSuffix,
controlTaskSid,
chatbotCallbackWebhookSid,
Expand All @@ -125,12 +121,10 @@ const updateChannelWithCapture = async (
participantSid: userIdentityOrParticipantId,
// All of this can be passed as url params to the webhook instead
capturedChannelAttributes: {
enableLexV2,
userId,
environment,
helplineCode,
botLanguage,
botLanguageV1,
botSuffix,
controlTaskSid,
chatbotCallbackWebhookSid,
Expand All @@ -152,11 +146,9 @@ const updateChannelWithCapture = async (

type CaptureChannelOptions = {
accountSid: AccountSID;
enableLexV2: boolean;
environment: string;
helplineCode: string;
botLanguage: string;
botLanguageV1: string;
botSuffix: string;
inputText: string;
userId: string;
Expand Down Expand Up @@ -185,13 +177,11 @@ const triggerWithUserMessage = async (
channelOrConversation: ChannelInstance | ConversationInstance,
{
accountSid,
enableLexV2,
userId,
environment,
helplineCode,
botSuffix,
botLanguage,
botLanguageV1,
inputText,
controlTaskSid,
releaseType,
Expand All @@ -205,16 +195,12 @@ const triggerWithUserMessage = async (
) => {
// trigger Lex first, in order to reduce the time between the creating the webhook and sending the message
const lexResult = await LexClient.postText({
enableLexV2,
postTextParams: {
botLanguage,
botLanguageV1,
botSuffix,
environment,
helplineCode,
inputText,
sessionId: userId,
},
botLanguage,
botSuffix,
environment,
helplineCode,
inputText,
sessionId: userId,
});

let webhook;
Expand All @@ -235,12 +221,10 @@ const triggerWithUserMessage = async (
}

await updateChannelWithCapture(channelOrConversation, {
enableLexV2,
userId,
environment,
helplineCode,
botLanguage,
botLanguageV1,
botSuffix,
controlTaskSid,
releaseType,
Expand All @@ -261,17 +245,13 @@ const triggerWithUserMessage = async (
throw lexResult.error;
}

const { lexResponse, lexVersion } = lexResult.data;
const { lexResponse } = lexResult.data;

let messages: string[] = [];
if (lexVersion === 'v1') {
messages.push(lexResponse.message || '');
} else if (lexVersion === 'v2') {
if (!lexResponse.messages) {
throw new Error('Lex response does not includes messages');
}
messages = messages.concat(lexResponse.messages.map(m => m.content || ''));
if (!lexResponse.messages) {
throw new Error('Lex response does not includes messages');
}
messages = messages.concat(lexResponse.messages.map(m => m.content || ''));

for (const message of messages) {
if (isConversation) {
Expand Down Expand Up @@ -299,12 +279,10 @@ const triggerWithNextMessage = async (
channelOrConversation: ChannelInstance | ConversationInstance,
{
accountSid,
enableLexV2,
userId,
environment,
helplineCode,
botLanguage,
botLanguageV1,
botSuffix,
inputText,
controlTaskSid,
Expand Down Expand Up @@ -348,12 +326,10 @@ const triggerWithNextMessage = async (

// const updated =
await updateChannelWithCapture(channelOrConversation, {
enableLexV2,
userId,
environment,
helplineCode,
botLanguage,
botLanguageV1,
botSuffix,
controlTaskSid,
releaseType,
Expand Down Expand Up @@ -572,17 +548,12 @@ export const handleChannelCapture = async (
? await twilioClient.conversations.v1.conversations(conversationSid).fetch()
: await twilioClient.chat.v2.services(chatServiceSid).channels(channelSid!).fetch();

const serviceConfig = await twilioClient.flexApi.v1.configuration.get().fetch();
const enableLexV2 = Boolean(serviceConfig.attributes.feature_flags.enable_lex_v2);

const options: CaptureChannelOptions = {
accountSid,
enableLexV2,
environment: environment.toLowerCase(),
helplineCode: helplineCode.toLowerCase(),
botSuffix,
botLanguage: languageSanitized.toLowerCase(),
botLanguageV1: languageSanitized,
releaseType,
studioFlowSid,
memoryAttribute,
Expand Down
36 changes: 10 additions & 26 deletions lambdas/account-scoped/src/channelCapture/chatbotCallback.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,27 +121,16 @@ export const handleChatbotCallback: AccountScopedHandler = async (
const capturedChannelAttributes =
channelAttributes.capturedChannelAttributes as CapturedChannelAttributes;

const {
const { botLanguage, botSuffix, environment, helplineCode, userId } =
capturedChannelAttributes;

const lexResult = await LexClient.postText({
botLanguage,
botLanguageV1,
botSuffix,
enableLexV2,
environment,
helplineCode,
userId,
} = capturedChannelAttributes;

const lexResult = await LexClient.postText({
enableLexV2,
postTextParams: {
botLanguage,
botLanguageV1,
botSuffix,
environment,
helplineCode,
inputText: Body,
sessionId: userId,
},
inputText: Body,
sessionId: userId,
});

if (isErr(lexResult)) {
Expand All @@ -160,27 +149,22 @@ export const handleChatbotCallback: AccountScopedHandler = async (

const twilioWorkspaceSid = await getWorkspaceSid(accountSid);

const { lexResponse, lexVersion } = lexResult.data;
const { lexResponse } = lexResult.data;
// If the session ended, we should unlock the channel to continue the Studio Flow
if (LexClient.isEndOfDialog({ enableLexV2, lexResponse })) {
if (LexClient.isEndOfDialog(lexResponse)) {
await chatbotCallbackCleanup({
accountSid,
twilioClient,
conversation,
channel,
channelAttributes,
memory: LexClient.getBotMemory({ enableLexV2, lexResponse }),
memory: LexClient.getBotMemory({ lexResponse }),
twilioWorkspaceSid,
});
}

// TODO: unify with functions/channelCapture/channelCaptureHandlers.ts
let messages: string[] = [];
if (lexVersion === 'v1') {
messages.push(lexResponse.message || '');
} else if (lexVersion === 'v2' && lexResponse.messages) {
messages = messages.concat(lexResponse.messages.map(m => m.content || ''));
}
const messages = (lexResponse.messages || []).map(m => m.content || '');

// TODO: unify with functions/channelCapture/channelCaptureHandlers.ts
for (const message of messages) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,8 @@ export const chatbotCallbackCleanup = async ({
}
};

const {
botLanguage,
botLanguageV1,
botSuffix,
enableLexV2,
environment,
helplineCode,
userId,
} = capturedChannelAttributes || {};
const { botLanguage, botSuffix, environment, helplineCode, userId } =
capturedChannelAttributes || {};

const shouldDeleteSession =
botLanguage && botSuffix && environment && helplineCode && userId;
Expand All @@ -120,15 +113,11 @@ export const chatbotCallbackCleanup = async ({
// Delete Lex session. This is not really needed as the session will expire, but that depends on the config of Lex.
shouldDeleteSession &&
LexClient.deleteSession({
enableLexV2,
deleteSessionParams: {
botLanguage,
botLanguageV1,
botSuffix,
environment,
helplineCode,
sessionId: userId,
},
botLanguage,
botSuffix,
environment,
helplineCode,
sessionId: userId,
}),
// Update channel attributes (remove channelCapturedByBot and add memory)
updateChannelOrConversationAttributes(releasedChannelAttributes),
Expand Down
Loading
Loading