aichaos / rivescript-js

A RiveScript interpreter for JavaScript. RiveScript is a scripting language for chatterbots.
https://www.rivescript.com/
MIT License
377 stars 144 forks source link

Calling multiple functions in a single response #335

Closed aimsor closed 3 years ago

aimsor commented 4 years ago

I'm trying to set a userVar and then setting a response based on the userVar that I just set up in the same response. The first object macro: <call>getUserCountry</call> calls an API from a database that gets the userCountry and then sets the userCountry as a Rive variable. This object macro is created on the backend of the chat in a different file. The other object is written within the Rive file and the macro: <call>userCountryProductChat</call> basically does this:

> object productCountryChat javascript

  const userVars = rs.getUservars(rs.currentUser());
  let result = '';

  return new Promise((res) => {
    userVars.then(({ userCountry }) => {
      if (userCountry === 'Mexico') {
        result = 'Some Mexico dependent chat here';
      } else if (userCountry === 'Canada') {
        result = 'Some Canada dependent chat here';
      } else {
        result = 'Other country chat';
      }
      res(result);
    }).catch((err) => {
      console.log(err);
      result = 'Something went wrong';
      res(result);
    });
  });

< object

When I try to trigger that response with a block like this:

+ *
- <call>getUserCountry</call><call>userCountryProductChat</call>

If I check the Rivestate, the variable seems to be set correctly, but the else statement is always showing up. Why is this the case? Am I able to call two functions subsequently and set the variable before using that variable for a variable dependent call?

kirsle commented 3 years ago

It looks like from the code that it should be calling objects serially one after the other: https://github.com/aichaos/rivescript-js/blob/2a92d5b29423025e18a42e3ae4e8989529fd3f08/src/brain.js#L943-L985

There may be some other moving parts at play here, like, if you're using a User Variable Session Manager that isn't the default in-memory session store (e.g. Redis-backed) there may be a race condition there somewhere, you'd have to get in and debug it to find out for sure.

For what you're doing I'd recommend consolidating the logic into a single <call>; you can chain any number of promises then and resolve when you have the final results.

In a past version of rivescript-js it used to gather up all the <call> tags and run them all in parallel, and there's other similar timing-based issues in RiveScript too, like, an object macro that calls setUservar() and a <get> tag in the same reply, the <get> won't see the set user variable since the object macro is run at the very end, after the <get> tag had already been processed.