Skip to content

Instantly share code, notes, and snippets.

@krisdover
Last active December 16, 2022 01:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krisdover/5902070bfcd6ddfb0638d7680c777b0d to your computer and use it in GitHub Desktop.
Save krisdover/5902070bfcd6ddfb0638d7680c777b0d to your computer and use it in GitHub Desktop.
An AWS Lambda codehook for a Twilio Lex web chatbot
import {
LexV2Handler,
LexV2Event,
LexV2Result,
} from "aws-lambda";
type LexRequestAttributes = {
channelType: string;
channelSid: string;
userIdentifier?: string;
name: string;
subject?: string;
location?: string;
instanceSid: string;
accountSid: string;
};
/**
* Constructs a plain-text chatbot response and ends the conversation
* @param event the incoming Lex event
* @param content the message text
* @param sessionAttributes
* @param dialogActionType the type of action Lex should take for this result
* @returns
*/
const plainTextResponse = (
{ sessionState }: LexV2Event,
content: string,
sessionAttributes = sessionState.sessionAttributes,
dialogActionType: "Close" | "ElicitIntent" = "Close"
): LexV2Result => {
const response: LexV2Result = {
sessionState: {
dialogAction: {
type: dialogActionType,
},
intent: {
name: sessionState.intent.name,
state: "Fulfilled",
},
sessionAttributes,
},
messages: [
{
contentType: "PlainText",
content,
},
],
};
console.log("response: ", response);
return response;
};
/**
* Returns a simple `Fulfilled` or `Failed` response and delegates control
* back to Lex as part of a CodeHook invocation, for determining conditional branching.
* @param event
* @param result
* @param sessionAttributes
* @param slots
* @returns
*/
const codeHookResult = (
{
sessionState: { intent, sessionAttributes: existingSessionAttributes },
}: LexV2Event,
result: "Fulfilled" | "Failed" | "ReadyForFulfillment",
sessionAttributes = existingSessionAttributes,
slots = intent.slots
) => {
const response: LexV2Result = {
sessionState: {
dialogAction: {
type: "Delegate",
},
intent: {
...intent,
state: result,
slots,
},
sessionAttributes,
},
};
console.log("response: ", response);
return response;
};
export const handler: LexV2Handler = async (event): Promise<LexV2Result> => {
console.log("event:", event);
const {
sessionState: { intent },
} = event;
if (intent.name === "agent-handoff") {
const { accountSid, instanceSid, channelSid: chatChannelSid } =
event.requestAttributes as LexRequestAttributes;
// create agent chat task
await twilio(accountSid, process.env.TWILIO_AUTH_TOKEN!, {
edge: "sydney",
})
.taskrouter.workspaces(process.env.TASKROUTER_WORKSPACE_SID)
.tasks.create({
attributes: JSON.stringify(event.requestAttributes),
taskChannel: "chat",
process.env.TASKROUTER_WORKFLOW_SID,
});
return plainTextResponse(event, "I'm connecting you with an agent now.");
}
if (intent.name === "end-chat") {
const sessionAttribs =
intent.confirmationState === "Confirmed"
? { status: "INACTIVE" }
: undefined;
return codeHookResult(event, "Fulfilled", sessionAttribs);
}
throw new Error(`Unsupported intent: ${intent.name}`);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment