Interface

The Nyra framework's messaging system facilitates interaction at the level of individual messages. However, real-world functionalities often require a series of coordinated messages, such as multiple commands and data exchanges. For instance, Speech-to-Text (STT) functionality involves a combination of commands and data messages, collectively referred to as an interface. An extension that supports all the messages defined by an interface can seamlessly operate in any context requiring that interface.

To simplify development, the Nyra framework aggregates messages within an interface. Extensions can declare their support for or dependence on an interface, avoiding the need to explicitly list every individual message in their manifest.

The framework provides the following primitive APIs to enable this functionality:

  • cmd_in

  • cmd_out

  • data_in

  • data_out

  • audio_frame_in

  • audio_frame_out

  • video_frame_in

  • video_frame_out

In addition to these, the framework also supports composite API mechanisms:

  • interface_in

  • interface_out

Interface Syntax

The basic syntax for defining an interface includes a mandatory name field. This name serves the same purpose as the name field in cmd_in and cmd_out, representing the name of the interface. It is significant only within the extension’s context and must be unique within that scope.

.json
{
  "api": {
    "interface_in": [
      {
        "name": "foo"
      }
    ],
    "interface_out": [
      {
        "name": "foo"
      }
    ]
  }
}

Using Interfaces in Graphs

The name of an interface is primarily utilized in graphs to define routing between extensions. In the example below, src_extension relies on the foo interface provided by dest_extension.

  • src_extension identifies the foo interface through its interface_out definition.

  • dest_extension identifies the foo interface through its interface_in definition.

.json
{
  "predefined_graphs": [{
    "name": "default",
    "auto_start": true,
    "nodes": [
      {
        "type": "extension_group",
        "name": "default_extension_group",
        "addon": "default_extension_group"
      },
      {
        "type": "extension",
        "name": "src_extension",
        "addon": "src_extension",
        "extension_group": "default_extension_group"
      },
      {
        "type": "extension",
        "name": "dest_extension",
        "addon": "dest_extension",
        "extension_group": "default_extension_group"
      }
    ],
    "connections": [{
      "extension": "src_extension",
      "interface": [{
        "name": "foo",
        "dest": [{
          "extension": "dest_extension"
        }]
      }]
    }]
  }]
}

Meaning of interface_in and interface_out

  1. interface_in

Indicates that the extension supports the specified interface's functionality.

.json
{
  "api": {
    "interface_in": [
      {
        "name": "foo"
        // Interface content
      }
    ]
  }
}
  1. interface_out

Indicates that the extension requires another extension to provide the specified interface's functionality.

.json
{
  "api": {
    "interface_out": [
      {
        "name": "foo"
        // Interface content
      }
    ]
  }
}

Interface and Message Declaration

  • Declaring the interface in interface_in implicitly includes the three commands in cmd_in and the data message in data_in.

  • Declaring the interface in interface_out implicitly includes the three commands in cmd_out and the data message in data_out.

If an interface specifies three commands and one data message:

Example: Interface with Multiple Messages

Extensions declaring an interface in their manifest are not required to explicitly list the messages contained in that interface. When the extension sends or receives a command, such as foo, the Nyra runtime references the interface definition in the manifest to process the command appropriately.

Manifest Implications

This interface mechanism acts as syntactic sugar, bundling a predefined set of messages for reuse across multiple extensions.

  • interface_in: The extension provides these three commands as part of the interface.

  • interface_out: The extension requires these three commands from another extension.

When an extension declares an interface in its manifest, it implicitly includes all the messages defined within that interface. For example, if an interface foo specifies three commands, the following applies:

Supporting Multiple Interfaces with the Same Message Name

In the current design, an extension cannot declare support for two interfaces that define messages with the same name under a single API item. For instance, if both the foo and bar interfaces define a command named xxx, the following scenarios are either permitted or restricted:

  • Not allowed

.json
{
  "api": {
    "interface_in": [
      {
        "name": "foo"
        // Interface foo content
      },
      {
        "name": "bar"
        // Interface bar content
      }
    ]
  }
}
  • Allowed

.json
{
  "api": {
    "interface_out": [
      {
        "name": "foo"
        // Interface foo content
      },
      {
        "name": "bar"
        // Interface bar content
      }
    ]
  }
}
.json
{
  "api": {
    "interface_in": [
      {
        "name": "foo"
        // Interface foo content
      }
    ],
    "interface_out": [
      {
        "name": "bar"
        // Interface bar content
      }
    ]
  }
}

Interface Definition Content

An interface definition closely resembles the api field in a manifest. Below is an example of how an interface is defined:

.json
{
  "cmd": [
    {
      "name": "cmd_foo",
      "property": {
        "foo": {
          "type": "int8"
        },
        "bar": {
          "type": "string"
        }
      },
      "result": {
        "property": {
          "aaa": {
            "type": "int8"
          },
          "bbb": {
            "type": "string"
          }
        }
      }
    }
  ],
  "data": [
    {
      "name": "data_foo",
      "property": {
        "foo": {
          "type": "int8"
        },
        "bar": {
          "type": "string"
        }
      }
    }
  ],
  "video_frame": [],
  "audio_frame": []
}

The Nyra framework incorporates an interface's definitions into the extension's manifest under the api field. For example, commands specified in interface_in are mapped to cmd_in, while those in interface_out are integrated into cmd_out.

Specifying Interface Content

There are two ways to specify the content of an interface:

Directly embed the interface definition in the manifest. Example:

.json
{
  "api": {
    "interface_in": [
      {
        "name": "foo",
        "cmd": [],
        "data": [],
        "video_frame": [],
        "audio_frame": []
      }
    ]
  }
}

Utilize a reference to define the interface, analogous to the $ref syntax used in JSON schemas.

.json
{
  "api": {
    "interface_in": [
      {
        "name": "foo",
        "$ref": "http://www.github.com/darth_vader/fight.json"
      }
    ]
  }
}

Determining Interface Compatibility

As an interface serves as syntactic sugar, its connectivity is determined by the compatibility of the underlying messages. When a source extension specifies an output interface foo, and a destination extension specifies an input interface bar, the Nyra runtime verifies whether the foo interface from the source is compatible with the bar interface at the destination.

.json
{
  "api": {
    "interface_out": "foo"
    // Interface content
  }
}
.json
{
  "api": {
    "interface_in": "bar"
    // Interface content
  }
}
.json
{
  "extension_group": {
    "addon": "default_extension_group",
    "name": "default_extension_group"
  },
  "extension": {
    "addon": "extension_A",
    "name": "extension_A"
  },
  "interface": [
    {
      "name": "foo",
      "dest": [
        {
          "extension_group": {
            "addon": "default_extension_group",
            "name": "default_extension_group"
          },
          "extension": {
            "addon": "dest_extension",
            "name": "dest_extension"
          }
        }
      ]
    }
  ]
}

The Nyra framework examines the foo interface definition in the interface_out section of the source extension's manifest. It validates each message defined within the interface against the destination extension’s manifest, including its explicit message definitions and any interfaces declared in interface_in. If any message fails to meet the schema validation rules enforced by the Nyra framework, the graph configuration is deemed invalid.

Last updated