Jovo v4.5: Dependency Injection and Intent Scoping

Published by Alex Swetlow & Jan König on Nov 22, 2022.

Jovo v4.5

Jovo v4.5 builds on top of our major v4 release last year. Learn more below.

Introduction

Jovo v4.5 includes the following larger updates:

v4.5 also comes with many other improvements and bugfixes. You can find all releases on GitHub and the Jovo News page.

A huge thank you for everyone who keeps helping to improve Jovo: Mark, Palle, Nico, Florian, David, Pete, Gianluca, and many more who are part of the Jovo community!

New Features

The v4.5 release comes with many improvements and 4 larger additions:

Here are some more pull requests that are part of latest releases:

Dependency Injection

Dependency injection is a feature that can be helpful to access instantiated service providers (and values) in components and output classes:

// src/services/OrderService.ts

import { Injectable } from '@jovotech/framework';
// ...

@Injectable()
class OrderService {
  async performOrder() {
    // ...
  }
}

They can be added to the app config:

// src/app.ts

import { OrderService } from './services/OrderService';
// ...

const app = new App({
  providers: [
    OrderService,
    // ...
  ],
});

And then accessed in any component our output class using the constructor():

// src/components/OrderPizzaComponent.ts

@Component()
class OrderPizzaComponent extends BaseComponent {
  constructor(
    jovo: Jovo,
    options: UnknownObject | undefined,
    private readonly orderService: OrderService
  ) {
    super(jovo, options);
  }

  @Intents('ConfirmOrderIntent')
  async confirmOrder() {
    try {
      await this.orderService.performOrder();
      // ...
    } catch (e) {
      // ...
    }
  }
}

This feature is especially helpful if you want to mock API calls in unit testing.

Thank you Palle for contributing this great feature!

Intent Scoping

As part of our goal to make it easier for you to improve NLU performance, we added a feature called intent scoping.

Some NLU services support the ability to prioritize certain intents. This helps if you have a large language model, but want to listen to specific input.

In Jovo, you can now pass a list of intents using the listen output property:

{
  message: `Which city do you want to visit?`,
  listen: {
    intents: [ 'CityIntent' ],
  },
}

This feature currently works with Snips NLU.

Native NLU Data

For more transparency and easier debugging, we added a native property to the NLU data that gets added to the $input property. It includes the full API response from the NLU service:

{
  type: 'TEXT',
  text: 'My name is Max',
  nlu: {
    intent: 'MyNameIsIntent',
    entities: {
      name: {
        value: 'Max',
        // ...
      },
    },
    native: {
      // Raw API response from the NLU service
    },
  },
}

Component Inheritance

Components can now inherit handlers from their superclass. This is useful for components that offer similar workflows, like a help handler.

import { BaseComponent } from '@jovotech/framework';

abstract class ComponentWithHelp extends BaseComponent {
  abstract showHelp(): Promise<void>;
  
  async repeatLastResponse() {
    // ...
  }
  
  @Intents('HelpIntent')
  async help() {
    await this.showHelp();
    await this.repeatLastResponse();
  }
}

@Component()
class YourComponent extends ComponentWithHelp {
  async showHelp() {
    // ...
  }
}

Thank you Palle for contributing this great feature!

New Examples

We also added 2 Jovo examples:

Breaking Changes

The dependency injection feature comes with a small breaking change.

It changes the constructor signature for BaseComponent and BaseOutput. By changing from options?: TYPE to options: undefined | TYPE, subsequent parameters are not required to be optional.

In your constructor(), make sure to add undefined as a potential value for options, for example:

@Component()
class OrderPizzaComponent extends BaseComponent {
  constructor(
    jovo: Jovo,
    options: ComponentOptions<UnknownObject> | undefined,
    private readonly orderService: OrderService
  ) {
    super(jovo, options);
  }

  @Intents('ConfirmOrderIntent')
  async confirmOrder() {
    try {
      await this.orderService.performOrder();
      // ...
    } catch (e) {
      // ...
    }
  }
}

Learn more in its pull request.

Also, in v4.4, we dropped support for Node v12.

Getting Started with Jovo

There are several ways how you can get started with Jovo:

Thanks a lot for being part of Jovo!