Skip to content

Commit

Permalink
Adding a new IVoxaIntentEvent interface (#157)
Browse files Browse the repository at this point in the history
* Adding a new IVoxaIntentEvent interface

* Couple lint fixes
  • Loading branch information
armonge committed Oct 10, 2018
1 parent 8cccba1 commit b83b8da
Show file tree
Hide file tree
Showing 15 changed files with 101 additions and 97 deletions.
4 changes: 0 additions & 4 deletions hello-world/hello-world.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,6 @@ app.onBeforeReplySent(request => {
});

app.onState("likesVoxa?", request => {
if (!request.intent) {
throw new Error("Not an intent request");
}

if (request.intent.name === "YesIntent") {
return { tell: "doesLikeVoxa" };
}
Expand Down
28 changes: 12 additions & 16 deletions src/StateMachine/StateMachine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import * as bluebird from "bluebird";
import * as _ from "lodash";

import { UnhandledState, UnknownState } from "../errors";
import { IVoxaEvent, IVoxaIntent } from "../VoxaEvent";
import { IVoxaIntent, IVoxaIntentEvent } from "../VoxaEvent";
import { IVoxaReply } from "../VoxaReply";
import {
isState,
Expand All @@ -35,18 +35,18 @@ import {
} from "./transitions";

export type IStateMachineCb = (
event: IVoxaEvent,
event: IVoxaIntentEvent,
reply: IVoxaReply,
transition: ITransition,
) => Promise<ITransition>;

export type IUnhandledStateCb = (
event: IVoxaEvent,
event: IVoxaIntentEvent,
stateName: string,
) => Promise<ITransition>;

export type IOnBeforeStateChangedCB = (
event: IVoxaEvent,
event: IVoxaIntentEvent,
reply: IVoxaReply,
state: IState,
) => Promise<void>;
Expand Down Expand Up @@ -95,7 +95,7 @@ export class StateMachine {
* we use the onUnhandledState handler
*/
public async checkOnUnhandledState(
voxaEvent: IVoxaEvent,
voxaEvent: IVoxaIntentEvent,
voxaReply: IVoxaReply,
transition: ITransition,
): Promise<ITransition> {
Expand Down Expand Up @@ -131,7 +131,7 @@ export class StateMachine {
* in the entry controller
*/
public async checkForEntryFallback(
voxaEvent: IVoxaEvent,
voxaEvent: IVoxaIntentEvent,
reply: IVoxaReply,
transition: ITransition,
): Promise<ITransition> {
Expand All @@ -142,10 +142,6 @@ export class StateMachine {

if (!transition && this.currentState.name !== "entry") {
// If no response try falling back to entry
if (!voxaEvent.intent) {
throw new Error("Running the state machine without an intent");
}

voxaEvent.log.debug(
`No reply for ${voxaEvent.intent.name} in [${
this.currentState.name
Expand All @@ -159,7 +155,7 @@ export class StateMachine {
}

public async onAfterStateChanged(
voxaEvent: IVoxaEvent,
voxaEvent: IVoxaIntentEvent,
reply: IVoxaReply,
transition: ITransition,
): Promise<ITransition> {
Expand All @@ -185,7 +181,7 @@ export class StateMachine {

public async runTransition(
currentStateName: string,
voxaEvent: IVoxaEvent,
voxaEvent: IVoxaIntentEvent,
reply: IVoxaReply,
): Promise<ITransition> {
this.currentState = this.getCurrentState(
Expand Down Expand Up @@ -231,7 +227,7 @@ export class StateMachine {
}

public async runCurrentState(
voxaEvent: IVoxaEvent,
voxaEvent: IVoxaIntentEvent,
reply: IVoxaReply,
): Promise<ITransition> {
if (!voxaEvent.intent) {
Expand Down Expand Up @@ -307,7 +303,7 @@ export class StateMachine {
return { to: dest };
}

protected runCallbacks(fn: IUnhandledStateCb, voxaEvent: IVoxaEvent) {
protected runCallbacks(fn: IUnhandledStateCb, voxaEvent: IVoxaIntentEvent) {
if (!isState(this.currentState)) {
throw new Error("this.currentState is not a state");
}
Expand All @@ -328,7 +324,7 @@ export class StateMachine {
}

protected async runOnBeforeStateChanged(
voxaEvent: IVoxaEvent,
voxaEvent: IVoxaIntentEvent,
reply: IVoxaReply,
) {
const onBeforeState = this.onBeforeStateChangedCallbacks;
Expand All @@ -345,7 +341,7 @@ export class StateMachine {

protected getFinalTransition(
sysTransition: SystemTransition,
voxaEvent: IVoxaEvent,
voxaEvent: IVoxaIntentEvent,
reply: IVoxaReply,
) {
let to;
Expand Down
26 changes: 15 additions & 11 deletions src/VoxaApp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ import {
ITransition,
StateMachine,
} from "./StateMachine";
import { IBag, IVoxaEvent } from "./VoxaEvent";
import { IBag, IVoxaEvent, IVoxaIntentEvent } from "./VoxaEvent";
import { IVoxaReply } from "./VoxaReply";

export interface IVoxaAppConfig extends IRendererConfig {
Expand Down Expand Up @@ -153,7 +153,7 @@ export class VoxaApp {
}

public async handleOnSessionEnded(
event: IVoxaEvent,
event: IVoxaIntentEvent,
response: IVoxaReply,
): Promise<IVoxaReply> {
const sessionEndedHandlers = this.getOnSessionEndedHandlers(
Expand Down Expand Up @@ -221,11 +221,13 @@ export class VoxaApp {
},
);

// call all onSessionStarted callbacks serially.
await bluebird.mapSeries(
this.getOnSessionStartedHandlers(voxaEvent.platform.name),
(fn: IEventHandler) => fn(voxaEvent, reply),
);
if (voxaEvent.session.new) {
// call all onSessionStarted callbacks serially.
await bluebird.mapSeries(
this.getOnSessionStartedHandlers(voxaEvent.platform.name),
(fn: IEventHandler) => fn(voxaEvent, reply),
);
}
// Route the request to the proper handler which may have been overriden.
return await requestHandler(voxaEvent, reply);
}
Expand Down Expand Up @@ -428,7 +430,7 @@ export class VoxaApp {
}

public async runStateMachine(
voxaEvent: IVoxaEvent,
voxaEvent: IVoxaIntentEvent,
response: IVoxaReply,
): Promise<IVoxaReply> {
let fromState = voxaEvent.session.new
Expand Down Expand Up @@ -487,16 +489,18 @@ export class VoxaApp {
const directivesKeyOrder = _.map(directiveClasses, "key");
if (transition.reply) {
// special handling for `transition.reply`
const reply = await voxaEvent.t(transition.reply, {
returnObjects: true,
});
const reply = await voxaEvent.renderer.renderPath(
transition.reply,
voxaEvent,
);
const replyKeys = _.keys(reply);
const replyTransition = _(replyKeys)
.map((key) => {
return [key, transition.reply + "." + key];
})
.fromPairs()
.value();

transition = _.merge({}, transition, replyTransition);
}

Expand Down
23 changes: 21 additions & 2 deletions src/VoxaEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,29 @@ export interface IVoxaRequest {
}

export interface IVoxaEventClass {
new(rawEvent: any, logOptions: LambdaLogOptions, context: any): IVoxaEvent;
new (rawEvent: any, logOptions: LambdaLogOptions, context: any): IVoxaEvent;
}

export abstract class IVoxaEvent {
export interface IVoxaIntentEvent extends IVoxaEvent {
intent: IVoxaIntent;
}

export interface IVoxaEvent {
rawEvent: any; // the raw event as sent by the service
session: IVoxaSession;
intent?: IVoxaIntent;
request: IVoxaRequest;
model: Model;
t: i18n.TranslationFunction;
log: LambdaLog;
renderer: Renderer;
user: IVoxaUser;
platform: VoxaPlatform;
supportedInterfaces: string[];
executionContext?: AWSLambdaContext | AzureContext;
}

export abstract class VoxaEvent implements IVoxaEvent {
public abstract get supportedInterfaces(): string[];
public rawEvent: any; // the raw event as sent by the service
public session!: IVoxaSession;
Expand Down
6 changes: 3 additions & 3 deletions src/errors/UnhandledState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { IVoxaEvent } from "../VoxaEvent";
import { IVoxaIntentEvent } from "../VoxaEvent";

export class UnhandledState extends Error {
public voxaEvent: IVoxaEvent;
public voxaEvent: IVoxaIntentEvent;
public fromState: string;
public transition: any;

constructor(voxaEvent: IVoxaEvent, transition: any, fromState: string) {
constructor(voxaEvent: IVoxaIntentEvent, transition: any, fromState: string) {
let message: string;
if (voxaEvent.intent) {
message = `${voxaEvent.intent.name} went unhandled on ${fromState} state`;
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

export { Tell, Say, SayP, Ask, Reprompt } from "./directives";
export { VoxaPlatform } from "./platforms";
export { IVoxaEvent, IVoxaIntent } from "./VoxaEvent";
export { IVoxaEvent, IVoxaIntentEvent, IVoxaIntent } from "./VoxaEvent";
export { IVoxaReply } from "./VoxaReply";
export {
AlexaReply,
Expand Down
48 changes: 22 additions & 26 deletions src/platforms/alexa/AlexaEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,17 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

import { RequestEnvelope, User as IAlexaUser } from "ask-sdk-model";
import {
canfulfill,
IntentRequest,
RequestEnvelope,
User as IAlexaUser,
} from "ask-sdk-model";
import { Context as AWSLambdaContext } from "aws-lambda";
import { Context as AzureContext } from "azure-functions-ts-essentials";
import { LambdaLogOptions } from "lambda-log";
import * as _ from "lodash";
import { IVoxaEvent, IVoxaIntent, IVoxaSession } from "../../VoxaEvent";
import { IVoxaIntent, VoxaEvent } from "../../VoxaEvent";
import { AlexaIntent } from "./AlexaIntent";
import {
CustomerContact,
Expand All @@ -35,8 +40,9 @@ import {
Lists,
} from "./apis";

export class AlexaEvent extends IVoxaEvent {
public intent!: IVoxaIntent;
export class AlexaEvent extends VoxaEvent {
public intent?: IVoxaIntent;
public rawEvent!: RequestEnvelope;
public alexa!: {
customerContact: CustomerContact;
deviceAddress: DeviceAddress;
Expand All @@ -46,25 +52,10 @@ export class AlexaEvent extends IVoxaEvent {
};

public requestToIntent: any = {
"AlexaSkillEvent.SkillDisabled": "AlexaSkillEvent.SkillDisabled",
"AlexaSkillEvent.SkillEnabled": "AlexaSkillEvent.SkillEnabled",
"AudioPlayer.PlaybackFailed": "AudioPlayer.PlaybackFailed",
"AudioPlayer.PlaybackFinished": "AudioPlayer.PlaybackFinished",
"AudioPlayer.PlaybackNearlyFinished": "AudioPlayer.PlaybackNearlyFinished",
"AudioPlayer.PlaybackStarted": "AudioPlayer.PlaybackStarted",
"AudioPlayer.PlaybackStopped": "AudioPlayer.PlaybackStopped",
"Connections.Response": "Connections.Response",
"Display.ElementSelected": "Display.ElementSelected",
"GameEngine.InputHandlerEvent": "GameEngine.InputHandlerEvent",
"LaunchRequest": "LaunchIntent",
"PlaybackController.NextCommandIssued":
"PlaybackController.NextCommandIssued",
"PlaybackController.PauseCommandIssued":
"PlaybackController.PauseCommandIssued",
"PlaybackController.PlayCommandIssued":
"PlaybackController.PlayCommandIssued",
"PlaybackController.PreviousCommandIssued":
"PlaybackController.PreviousCommandIssued",
};

constructor(
Expand Down Expand Up @@ -134,13 +125,18 @@ export class AlexaEvent extends IVoxaEvent {
}

protected initIntents() {
if (
_.includes(
["IntentRequest", "CanFulfillIntentRequest"],
this.request.type,
)
) {
this.intent = new AlexaIntent(this.rawEvent.request.intent);
const { request } = this.rawEvent;
if (isIntentRequest(request)) {
this.intent = new AlexaIntent(request.intent);
}
}
}

function isIntentRequest(
request: any,
): request is IntentRequest | canfulfill.CanFulfillIntentRequest {
return (
request.type === "IntentRequest" ||
request.type === "CanFulfillIntentRequest"
);
}
14 changes: 5 additions & 9 deletions src/platforms/alexa/AlexaPlatform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { Context as AzureContext } from "azure-functions-ts-essentials";
import * as _ from "lodash";
import { OnSessionEndedError } from "../../errors";
import { VoxaApp } from "../../VoxaApp";
import { IVoxaEvent } from "../../VoxaEvent";
import { IVoxaEvent, IVoxaIntentEvent } from "../../VoxaEvent";
import { IVoxaReply } from "../../VoxaReply";
import { IVoxaPlatformConfig, VoxaPlatform } from "../VoxaPlatform";
import { AlexaEvent } from "./AlexaEvent";
Expand Down Expand Up @@ -86,7 +86,7 @@ export class AlexaPlatform extends VoxaPlatform {
this.config = config;

this.app.onCanFulfillIntentRequest(
(event: AlexaEvent, reply: AlexaReply) => {
(event: IVoxaIntentEvent, reply: AlexaReply) => {
if (_.includes(this.config.defaultFulfillIntents, event.intent.name)) {
reply.fulfillIntent("YES");

Expand Down Expand Up @@ -141,13 +141,9 @@ export class AlexaPlatform extends VoxaPlatform {
}

protected checkSessionEndedRequest(alexaEvent: AlexaEvent): void {
if (
alexaEvent.request.type === "SessionEndedRequest" &&
alexaEvent.rawEvent.request.reason === "ERROR"
) {
throw new OnSessionEndedError(
_.get(alexaEvent.rawEvent, "request.error"),
);
const { request } = alexaEvent.rawEvent;
if (request.type === "SessionEndedRequest" && request.reason === "ERROR") {
throw new OnSessionEndedError(request.error);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/platforms/botframework/BotFrameworkEvent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from "botbuilder";
import { LambdaLogOptions } from "lambda-log";
import * as _ from "lodash";
import { ITypeMap, IVoxaEvent, IVoxaIntent, IVoxaUser } from "../../VoxaEvent";
import { ITypeMap, IVoxaIntent, IVoxaUser, VoxaEvent } from "../../VoxaEvent";

const MicrosoftCortanaIntents: ITypeMap = {
"Microsoft.Launch": "LaunchIntent",
Expand All @@ -23,7 +23,7 @@ export interface IBotframeworkPayload {
intent?: IVoxaIntent;
}

export class BotFrameworkEvent extends IVoxaEvent {
export class BotFrameworkEvent extends VoxaEvent {
public rawEvent!: IBotframeworkPayload;

public requestToRequest: ITypeMap = {
Expand Down
Loading

0 comments on commit b83b8da

Please sign in to comment.