Giter Site home page Giter Site logo

microsoft / botbuilder-js Goto Github PK

View Code? Open in Web Editor NEW
652.0 73.0 274.0 47.08 MB

Welcome to the Bot Framework SDK for JavaScript repository, which is the home for the libraries and packages that enable developers to build sophisticated bot applications using JavaScript.

Home Page: https://github.com/Microsoft/botframework

License: MIT License

JavaScript 44.20% Batchfile 0.17% Shell 0.15% TypeScript 54.74% HTML 0.16% ANTLR 0.29% CSS 0.02% PowerShell 0.10% Smarty 0.15%
bot bots bot-framework sdk nodejs js microsoft-bot-framework microsoft-cognitive-services

botbuilder-js's Introduction

Bot Framework SDK v4 for JavaScript

This repository contains code for the JavaScript version of the Microsoft Bot Framework SDK, which is part of the Microsoft Bot Framework - a comprehensive framework for building enterprise-grade conversational AI experiences.

This SDK enables developers to model conversation and build sophisticated bot applications using JavaScript. SDKs for .NET, Python and Java (preview) are also available.

To get started building bots using the SDK, see the Azure Bot Service Documentation. If you are an existing user, then you can also find out what's new with Bot Framework.

For more information jump to a section below.

Build Status

Branch Description Test Status Coverage Status Windows Bot Test Status Linux Bot Test Status Browser Functional Tests
main 4.15.x Tests Test Status Coverage Status Build Status Build Status Build Status

Packages

Name NPM Package
adaptive-expressions BotBuilder Badge
adaptive-expressions-ie11 BotBuilder Badge
botbuilder BotBuilder Badge
botbuilder-ai BotBuilder Badge
botbuilder-ai-orchestrator BotBuilder Badge
botbuilder-ai-luis BotBuilder Badge
botbuilder-ai-qna BotBuilder Badge
botbuilder-applicationinsights BotBuilder Badge
botbuilder-azure BotBuilder Badge
botbuilder-azure-blobs BotBuilder Badge
botbuilder-azure-queues BotBuilder Badge
botbuilder-core BotBuilder Badge
botbuilder-dialogs BotBuilder Badge
botbuilder-dialogs-adaptive BotBuilder Badge
botbuilder-dialogs-adaptive-runtime BotBuilder Badge
botbuilder-dialogs-adaptive-runtime-core BotBuilder Badge
botbuilder-dialogs-adaptive-runtime-integration-express BotBuilder Badge
botbuilder-dialogs-adaptive-runtime-integration-azure-functions BotBuilder Badge
botbuilder-dialogs-adaptive-runtime-integration-restify BotBuilder Badge
botbuilder-dialogs-adaptive-testing BotBuilder Badge
botbuilder-dialogs-declarative BotBuilder Badge
botbuilder-lg BotBuilder Badge
botbuilder-stdlib BotBuilder Badge
botbuilder-testing BotBuilder Badge
botframework-config BotBuilder Badge
botframework-connector BotBuilder Badge
botframework-schema BotBuilder Badge
botframework-streaming BotBuilder Badge

To view package interdependencies, see the dependency graph.

Getting Started

To get started building bots using the SDK, see the Azure Bot Service Documentation.

The Bot Framework Samples includes a rich set of samples repository.

If you want to debug an issue, would like to contribute, or understand how the Bot Builder SDK works, instructions for building and testing the SDK are below.

Prerequisites

Clone

Clone a copy of the repo:

git clone https://github.com/microsoft/botbuilder-js.git

Change to the SDK's directory:

cd botbuilder-js

Build and test locally

Install the prerequisites.

yarn

Then use the following command to build the SDK.

yarn build

Running unit tests

Use the following command to run the unit tests.

yarn test

The prep-test.cmd command is run to install test keys and start the Azure Storage Emulator if its installed. Any unit tests needing test keys or the storage emulator are designed to be skipped if their dependencies are missing so most developers won't need to worry about running this command.

If you have a need to re-generate the LUIS or connector clients using the latest swagger you'll need to install autorest (requires Node 7.10.0 or higher), which you can do with the following command.

yarn global add global autorest

Getting support and providing feedback

Below are the various channels that are available to you for obtaining support and providing feedback. Please pay carful attention to which channel should be used for which type of content. e.g. general "how do I..." questions should be asked on Stack Overflow, Twitter or Gitter, with GitHub issues being for feature requests and bug reports.

Github issues

Github issues should be used for bugs and feature requests.

Stack overflow

Stack Overflow is a great place for getting high-quality answers. Our support team, as well as many of our community members are already on Stack Overflow providing answers to 'how-to' questions.

Azure Support

If you issues relates to Azure Bot Service, you can take advantage of the available Azure support options.

Twitter

We use the @msbotframework account on twitter for announcements and members from the development team watch for tweets for @msbotframework.

Gitter Chat Room

The Gitter Channel provides a place where the Community can get together and collaborate.

Contributing and our code of conduct

We welcome contributions and suggestions. Please see our contributing guidelines for more information.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact [email protected] with any additional questions or comments.

Reporting Security Issues

Security issues and bugs should be reported privately, via email, to the Microsoft Security Response Center (MSRC) at [email protected]. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the Security TechCenter.

Copyright (c) Microsoft Corporation. All rights reserved.

Licensed under the MIT License.

botbuilder-js's People

Contributors

aliandi avatar benbrown avatar bill7zz avatar carlosscastro avatar ceciliaavila avatar chon219 avatar chrimc62 avatar cleemullins avatar cosmicshuai avatar danieladu avatar daveta avatar ddefromor avatar denscollo avatar dependabot[bot] avatar enzocano avatar gasper-az avatar jeffders avatar johnataylor avatar jonathanfingold avatar joshgummersall avatar juanar avatar mdrichardson avatar pcostantini avatar stevengum avatar stevenic avatar sw-joelmut avatar tomlm avatar tracyboehrer avatar tsuwandy avatar zerryth avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

botbuilder-js's Issues

Add support for "invoke" activity to adapter

We need to support "invoke" activities which are complex because the protocol changes such that we need to send an HTTP StatusCode and Body in response to the received "invoke" activity. To do that we need to somehow get that code and body down to the connector while it holds open the response object.

The idea we've come up with is to add a new "result" or "invoke-result" activity type (we can discuss name more) that is a fake activity much like the "delay" activity. This activity will contain the StatusCode & Body the bot would like to return and when the connector receives this activity in it's post() method it will store it in a table keyed by channelId+activityId. Then when the request naturally unwinds the connector can retrieve the result from the table and complete the response.

This feature is used by payments and heavily used by Teams so we need it before //build.

idea: consolidate 3 middleware pipes into 1

To begin with this idea is not trying to address typing and context mucking issues raised by @billba in issue #56. This is to address an issue I've ran into several times while implementing middleware for the v4 SDK.

An issue I keep running into is the need to pass some information from one middleware pipe like contextCreated() to another pipe like sendActivity. Take this simple logger plugin below:

export class MyLogger implements Middleware {
    static id = 0;
    private key: string;

    constructor() {
        this.key = 'myLogger:' + MyLogger.id++;
    }

    public contextCreated(ctx, next) {
        const logger = new Logger();
        ctx[this.key] = logger;
        logger.log(`started`);
        return next()
            .then(() => logger.log(`ended`));
    }

    public sendActivity(ctx, activities, next) {
        const logger = ctx[this.key];
        logger.log(`sending`);
        return next()
            .then(() => logger.log(`sent`));
    }
}

bot.use(new MyLogger());

I want to log all activity flowing into an out of the bot so in contextCreated() I create my logger and all is well. The problem is I want to use the same logger when logging outgoing activities in sendActivity() so I some how need it get it from closure where I created it to this other closure. Short of caching it in a map my only other option is to tack it onto the context object and let it haul it over to the other closure for me. To avoid potential collisions I need to essentially use a GUID to store it which I create when the plugin is created.

The whole thing feels pretty gross and I wouldn't have to do this at all if everything was under the umbrella of a single closure. We still need the separate pipes though so what would that look like?

bot.use((ctx, next) => {
    const logger = new Logger();
    logger.log(`started`);
    
    ctx.onSend((ctx, next) => {
        logger.log(`sending`);
        return next()
            .then(() => logger.log(`sent`));
    });

    return next()
        .then(() => logger.log(`ended`));
});

This looks a lot more like a traditional piece of middleware you'd define in Express or Redux but there's no loss of functionality. A single outer closure now replaces the contextCreated pipe but functionally it works the same way. The key difference is that where the other pipe like receiveActivity and sendActivity were statically defined before as part of the middleware registration they now get dynamically registered with the context object at runtime which makes them look a lot like events.

This approach lets the other pipes run under the hood of the outer closure and lets us use closure scope to hold shared things like the logger. As you can see the code is simplified quite a bit from the original example.

To see a more complete example lets look at an entire processing stack built out using this new approach:

const storage = new MemoryStorage();
const bot = new Bot(adapter)
    // Log incoming and outgoing activities
    .use((ctx, next) => {
        console.log(`begin turn.`)

        ctx.onSend((ctx, activities, next) => {
            console.log(`sending activities.`);
            return next();
        });

        return next()
            .then(() => console.log(`end of turn`), (err) => console.error(`error occurred`))
    })

    // Report an errors thrown to the user
    .use((ctx, next) => {
        return next()
            .catch((err) => {
                return ctx.send(`An error occurred`).then(() => err);
            });
    })

    // Read/write bots conversation state
    .use((ctx, next) => {
        const key = 'convo:' + ctx.reequest.conversation.id;
        return storage.read(key)
            .then((state) => ctx.state = state)
            .then(() => next())
            .then(() => storage.write(key, state));
    })

    // Route received activities through bots logic.
    .onReceive((ctx) => {
        ctx.state.count = (ctx.state.count || 0) + 1;
        return ctx.send(`${ctx.state.count}: You said: ${ctx.request.text}`);
    });

This bots stack first uses a piece of logging middleware which will log all incoming and outgoing activities, next an error reporter watches for an errors and notifies the user, then our bot state middleware runs, and finally the bots logic. When the bots logic completes everything unwinds back up the stack and even though there's no change in functionality it feels less like we're making multiple passes through the stack because now we're just calling what feel like event subscribers.

Bonus is that other parts of your bot logic can subscribe to send notifications as well.

suggestion: for proactive messages set context.request to an activity of type 'proactive'

One of @billba suggestions in issue #56 is to set context.request to an activity that has a new type of 'proactive'. Today this is left undefined and I can see a couple of advantages to changing to the suggested approach:

  • Today you can't safely just say something like context.request.type in your code because in the proactive case context.request might be undefined. This change would make your code generally safer.
  • Now that 'proactive' is a type you can potentially use that in a switch statement to run conditional code for a proactive case more cleanly.
  • We can populate this 'proactive' activity with the information off the conversation reference making the request look more like a legitimate activity object just lacking a value for text.

That's all goodness and I was trying to decide if it means will could simplify the middleware model some by combining the contextCreated and postActivity pipes into one pipe. The idea being that if a recognizer didn't want to run during the proactive case it could just look at the request.type to make that decision. Unfortunately, I'm not sure its that simple. There are at least 2 cases today where the developer needs to be able to explicitly create a context object:

  • There's the classic proactive case where you're wanting to initiate a conversation with the user by sending them a message that you may or may not expect them to respond to.
  • The other case is the human handoff scenario where the bot needs to act as a proxy between the user and a support engineer. In that scenario the bot needs to create a second context object for the support engineer so that it can relay the users message to them and vice versa.

The first case I think it might be ok, and maybe even desirable, to have things flow through the standard routing logic. In the second case I think its less desirable to the point of potentially being advised that you don't go through routing for the second context object.

I definitely like the idea of having the context.request always populated but I think keeping the context creation separate from activity routing just allows for more flexibility. Truth be told you could do this today using the following block of code:

const activity = { type: 'proactive' };
botbuilder.applyConversationReference(activity, reference);
bot.receive(activity);

That uses the applyConversationReference to compose a 'proactive' activity that will get routed through everything as if it came from the adapter.

fix middleware/context model

Currently middleware developers are encouraged to add functionality to context by adding properties and methods directly to it. This has a number of issues and, crucially, won't work in languages like Java.

This repo details the problems and illustrates that there are other ways to accomplish the same thing: https://github.com/billba/middleware

TableStorage provider should add gzip option

I'm assuming that our TableStorage provider only supports storing objects in a single text column which limits us to 64k. We should add a gzip option as lots of people will want to store more data then that in conversation state.

We can also up the limit by spanning objects across multiple text columns.

optimizeWrites required by StorageMiddleware

Example is not valid:
bot.use(new FileStorage({
path: path.join(__dirname, 'storage')
}));

Fails because not passed "optimizeWrites" in FileStorageSettings (which inherits from StorageSettings)

Do you want optimizeWrite to be optional in StorageSettings and given the value of true if it isn't set?

proposal: trimmed down context object

One of the biggest things we've talked about for M2 is stripping down the core botbuilder package to its essence. Thought I'd start with proposing a trimmed down context object:

see updated shape proposal #66 (comment)

export interface BotContext {
    /** The Bot object for this context. */
    bot: Bot;

    /** The received activity. */
    request: Activity;

    /** Queue of responses to send to the user. */
    responses: Partial<Activity>[];

    /** If true at least one response has been sent for the current turn of conversation. */
    readonly responded: boolean;

    /** Deletes an existing activity. */
    deleteActivity(id: string): Promise<void>;
    
    /** Sends a set of activities to the user. */
    postActivity(activities: Partial<Activity>[]): Promise<ConversationResourceResponse[]>;

    /** Flushes the response queue. Calls postActivity() */
    flushResponses(): Promise<ConversationResourceResponse[]>;

    /** Replaces an existing activity. */
    updateActivity(activity: Partial<Activity>): Promise<void>;
}

Let me go through and try to justify each part on the context object...

bot

This is really to provide access to the adapter as we've found you often need access to this. In particular, Middleware for MS Teams needs access to the underlying adapter to get an access token for calling other REST services they need to call.

request

Obviously provides access to the received activity.

responded

This is a flag that indicates whether a reply has been sent for the current turn. This is potentially useful from within middleware to know if you should run logic on the trailing edge of a request. For instance, QnA Maker can look at this flag on the trailing edge of the request and only call the service in a fallback case should no other logic in the bot respond.

responses and flushResponses()

This provides a means of queuing up outbound responses. Bots often end up sending more than one message to the user for the same turn and given that your bots logic might be spread across multiple components it's possible for several components to queue up an outgoing response on the same turn. Since the bots state is written out every time activities are sent it's best to queue up all of the responses so that you can collapse state updates down to a single write per turn.

The flushResponses() method gives you a way of manually flushing the response queue should you need to and it's also the method called when the context is about to be destroyed. All this method would do is call the new postActivity() method and then delete the flushed responses on completion.

postActivity(), updateActivity(), and deleteActivity()

These are new methods I'm proposing to explicitly perform CRUD operations against the underlying adapter in a way that goes through middleware. We recently realized that while we have a postActivity middleware pipe we're missing delete and update pipes. Currently updates and deletes for existing activities need to happen using the adapter directly which bypasses middleware meaning that updates & deletes won't be logged.

I have another proposal coming which will recommend we add new updateActivity and deleteActivity pipes to middleware. What's nice about these 3 new methods I'm proposing is that they will a) provide a direct means of posting activities (something we've been asked for) and b) they will align name wise with the names of the middleware pipes that will get run when each method is called. Should make it clearer what triggers the running of those pipes.

Short-circuiting is broken in intentRecognizerSet

intentRecognizerSet doesn't seem to be short-circuiting the recognizers when recognizeOrder is series and stopOnExactMatch is true. I believe this is due to a bug in hasExactMatch:

private hasExactMatch(intents: Intent[]): boolean { 
        intents.forEach((intent) => { 
            if (intent.score >= 1.0) { 
                return true; 
            } 
        }); 
        return false; 
    } 

where the return true is returning in the forEach callback rather than the outer function.

Need a TestBotContext

After spending a week creating middleware, and doing it with TDD, the thing I settled on above all is the need for a TestBotContext. When calling any of the middleware functions (events), what's really happening is the state of the context is being modified in many (most?) cases.

For example, in the case of human handoff, where messages need to be sent back on the context passed in, and not via the bot, all that's really happening is the responses array is having another Activity pushed on it. Something like this (with logic assumed):

onReceive(context: Partial<BotContext>, next: () => Promise<void>) {
  if(userWantsAgent) context.reply("Connecting you to an agent."); // modifies context.responses
}

It's much simpler to test if I can pass a context in, and then inspect it afterwards, to ensure there's a particular reply waiting in the wings. As best I can tell, there isn't an easy way to just create an empty context, so I wound up implementing one on my own. The moment I did that, my tests became easier to write and more elegant. My implementation isn't complete, but it was what I needed for my tests.

class TestContext implements BotContext {
    constructor(conversationReference: ConversationReference, request: Activity | string) {
        if(typeof request !== "object") {
            request = { type: "message", text: request };
        }
        this.conversationReference = conversationReference;
        this.request = request;
        this.bot = new Bot(new TestAdapter);
        this.bot.createContext =
            (reference: ConversationReference, onReady: (context: BotContext) => void) => {
                onReady(this);
                return new Promise(() => {});
            };

        this.responses = [];
    }
    public request: Activity;
    public responses: Activity[];
    public bot: Bot;
    public responded: boolean = false;
    public conversationReference: ConversationReference;
    public state: BotState;
    public templateManager: TemplateManager;

    public delay(duration: number) { return this; }
    public dispose() {}
    public endOfConversation(code?: string) { return this; }
    public replyWith(id: string, data: any) { return this; }
    public flushResponses() { 
        return new Promise<ConversationResourceResponse[]>(
            (value) => {}
        );
    }
    public showTyping() {
        return this;
    }

    public reply(textOrActivity : string | Activity) {
        if(typeof textOrActivity !== "object") {
            textOrActivity = { type: "message", text: textOrActivity };
        }
        this.responses.unshift(textOrActivity);
        return this;
    }
}

// sample test:
    it("Agent can list queue", (done) => {
        const context = new TestContext(agentReference, "#list");
        const provider = getProvider(HandoffUserState.queued);

        new HandoffMiddleware(provider).receiveActivity(context, next);

        assert(provider.getQueue.called, "getQueue not called");
        assert(next.notCalled, "next called"); // (a sinon spy)
        assert(context.responses.length === 1, "Wrong number of responses");
        assert(context.responses[0].text.indexOf(userReference.user.name) > -1, "Name not listed")
        done();
    });

proposal: new Middleware.updateActivity() and Middleware.deleteActivity() methods

We recently realized that we're missing updateActivity() and deleteActivity() middleware pipes. You currently have to use the adapter directly if you need to modify or delete an existing activity. The issue with that is it bypasses middleware meaning that you log out changes or deletes which you really want to log.

The proposal is to add two new middleware pipes and then extend the context object with some new methods for calling the adapter through those pipes. See issue #66 for that proposal.

Add goodbye middleware

Another important piece of middleware is a component that is always listening for the user to say "goodbye" or "I'd like to start over". When it detects either of these intents it should first clear the conversation sand then send a reply to the user or return them to the beginning of the conversation.

This could be done as a sample or middleware but it's another important feature that every production bot needs to help combat users getting into a stuck state.

Sample code snippets

add state
Simple Conversation Modeling (Echo Bot, primitives)
Complex Conversation Modeling (Alarm Bot, multi-dialogs, cards)
LUIS
QnA
Cards
Proactive Messages
Middleware
Directline - sample

In intentRecognizerSet, "exact match" threshold is not configurable

intentRecognizerSet only short-circuits the recognizers if an intent meets a hardcoded threshold of 1.0. See filter here:

private hasExactMatch(intents: Intent[]): boolean {
    return intents.filter((intent) => intent.score >= 1.0).length > 0;
}

This threshold is not configurable, but in some cases we may want to consider a lower score as an "exact match" (or a "good enough" match).

More generally, it'd be nice to be able to configure a different value for each recognizer in the set (e.g. 1.0 for my regex recognizer, but 0.8 for my LUIS recognizer).

Add warning if requests take longer then 10 seconds to process

The bot has roughly 10-12 seconds to respond to a received activity before the channel times out. A channel timing out can result in some cases the message being re-delivered and in the case of cortana the skill being prematurely ended.

This feature would add a piece of middleware or sample that would log out that the bot is taking too long and the developer should investigate why. It could for instance log a warning for requests longer than 8 seconds and an error for requests longer then 12 seconds.

Add dialog version middleware

v3 has a dialog version middleware which is useful for you adding a major.minor version to your bots conversational system. This version number gets stamped on every conversation state object an anytime the conversations major versions no longer match the state will be automatically deleted and the user will be sent a message saying "A system update has occurred and we need to start over." Why do you need to do that?

If you deploy a major update to your bot you run the risk of users getting into a stuck state due to the fact their current conversation state no longer reflects the structure of the bot that was just deployed. In some cases this can result in your bot throwing an exception which is actual a good thing because we'll catch that and automatically deleted the conversation state. The more difficult scenario is that instead of throwing an exception you can end up trapping the user in an infinite loop that they can't get out of. Given the user a way to always say "goodbye" and force a conversation state deletion is one way to get them out but incrementing your bots major version number is a more automatic way of doing this and prevent the user just having to know they can say "goodbye".

I can't say enough how critical a feature this is so while it could be done as a sample its probably best as a piece of middleware that we encourage all developers to always include in their bot somewhere after the ConversationStateStore middleware.

Phase 1 packages

Botbuilder
Botbuilder-AI
Botbuilder-Azure
Botbuilder-Node
Botbuilder-browser

FileStorage occasionally get corrupted. No way to recover

We've found using FileStorage that occasionally the files on disk get corrupted (i.e. file is truncated or otherwise not valid JSON). Not quite sure what causes this condition. Perhaps when node process is prematurely stopped?

More importantly, there doesn't appear to be a graceful way to recover from this condition other than manually deleting the storage files from disk. One can catch the failed reads, but there's no obvious way to clear the bad file.

Any suggestions?

bug: @types/react package breaks build

I can't figure out where this is coming from but if you sync and do lerna bootstrap --hoist you will get an @types/react package added to the root node_modules directory which will prevent any of the packages from building. Manually deleting this package fixes the build break.

I can't seem to figure out where it's getting pulled in from and furthermore have no clue as to why it causes every build to break given that none of the packages being built depend on it. If anyone has cycles too dig into this further that would be awesome.

BaseUri for LuisRecognizer is missing /luis

https://github.com/Microsoft/botbuilder-js/blob/a10e27053e166800faa54f3cd673a8dfb0bfdc2d/libraries/botbuilder-ai/src/luisRecognizer.ts#L49

Expected:
The third parameter to LuisRecognizer is optional and should default to the correct endpoint.
This allows user to program such as:

const luisRecognizer = new LuisRecognizer("<removed-app-id>", "<removed-subscription-key>")
...

bot.use(luisRecognizer)

Actual:

Because the base url is wrong, the requestUrl generated will be:
https://westus.api.cognitive.microsoft.com/v2.0/apps/<appId>?subscription-key=<subscription-key>
Which will return 404 and leave developer confused thinking their app id is wrong.

However, it should be:
https://westus.api.cognitive.microsoft.com/luis/v2.0/apps/<appId>?subscription-key=<subscription-key>

The work around is that the user must manually enter the base url as:

const luisRecognizer = new LuisRecognizer("<app-id>", "<subscription-key>", "https://westus.api.cognitive.microsoft.com/luis")

Add error message middleware

This could be done as a sample versus an actual piece of middleware we ship but we need a piece of middleware that you install first in your bot and it listens for an error to be thrown and then simply sends a message to the user telling the something wen't wrong. Other middleware on the stack should have already processed/logged the error so this middleware is just about telling the user something happened.

I think the general strategy we want for all middleware error wise is to handle the error and then re-throw it so someone else can handle it.

In JS I think this middleware looks like:

bot.use({
    contextCreated: (context, next) => {
        return new Promise((resolve, reject) => {
            next().then(
                () => { resolve() },
                (err) => {
                    context.responses.push({ type: 'message', text: `Oops... Something went wrong.`});
                    reject(err);
                }
            );
        });
    }
});

Add staging boolean option to LuisRecognizerOptions

From what I see there is no way to configure the LuisRecognizer to use the staging deployment slot.

It needs to construct the url with the staging=true query parameter; however, there no option in LuisRecognizerOptions for staging.

I looked into submitting PR to add the boolean; but the request url is generated inside the LuisClient which is constructed from a swagger file and that needs to understand the staging option.

  • Update botframework-luis swagger to have staging query parameter
  • Regenerate client
  • Add staging: boolean to LuisRecognizerOptions

[bug] Bots using Console Adapter throw an unhandled promise exception for all incoming messages

Environment details

  • node version: 8.2.1
  • relevant tsconfig:
{
    "target": "es6",
    "module": "commonjs",   
    "moduleResolution": "node"
}

relevant dependency versions:

{
    "botbuilder": "^4.0.0-m1.0",
    "botbuilder-node": "^4.0.0-alpha2",
    "botbuilder-services": "^4.0.0-m1.0",
}

Repro steps

import { Bot, MemoryStorage, BotStateManager } from 'botbuilder';
import { ConsoleAdapter } from 'botbuilder-node';

const adapter = new ConsoleAdapter().listen();

const bot = new Bot(adapter)
    .use(new MemoryStorage())
    .use(new BotStateManager())
    .onReceive((context) => {
        context.reply('HELLO!');
    });

send any message to the bot from the console

Expected behavior

bot responds hey

Actual behavior

no bot response, but logged error of:

(node:63716) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 2): TypeError: Cannot read property 'id' of undefined
(node:63716) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

Research

I've found the source of the error, which happens on this line in the bot state manager. There is no user defined for the ref.

The value of ref at the time of the error is:

{
    channelId:"console",
    conversation:Object {id: "Convo1"},
    from:Object {id: "user", name: "User1"},
    id:"0",
    recipient:Object {id: "bot", name: "Bot"},
    text:"hey",
    timestamp:"2018-02-24T02:28:37.669Z",
    type:undefined
}

bug: autorest doesn't support any or union types

We have an issue with the connector schema that most of the value properties are technically supposed to be of type any meaning that you can pass either an object or a string for the value. That's an issue because the autorest client which we use to gen our connector is based off Swagger 2.0 and doesn't yet support any or union types. As such we had been modeling value as an object which causes outgoing activities to be rejected client side anytime you try to send a string value. I've filed an issue with the autorest team, they've confirmed the issue, and I'm waiting for a workaround:

Azure/autorest#2855

In the interim I've manually switched most of the value properties in the swagger to be of type string given this is the required type for many of the CardAction types and allows for tunneling through other value types in string form. This change is in PR #91.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.