Skip to content

Commit

Permalink
MAX Toolkit v2.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ramsrira committed Dec 8, 2023
1 parent db71a80 commit 0e00d49
Show file tree
Hide file tree
Showing 392 changed files with 21,004 additions and 5,496 deletions.

Large diffs are not rendered by default.

20 changes: 19 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Change Log

## v2.0.0
MAX Toolkit v2.0.0 is a major release that now allows Agents to communicate with MAX via Inter-Process Communication (IPC). This is facilitated by the MAX IPC framework which leverages gRPC C++ to provide IPC capabilities.

### MAX-API Changes
* Added a new `HashableInterface` which is used by the `ActivityRequestInterface` and the `DialogRequestInterface` (required for use cases introduced with IPC).
* Methods in `StartListeningCallback` and `ActivityRequestInterface` are made virtual.
* A new `registerAgent()` API is introduced in the `AgentManagerInterface`, to support single agent registration use cases like agent process crash recovery.

### Enhancements
* The MAX IPC framework is introduced along with two major packages - `MultiAgentExperience-IPC` and `MultiAgentExperience-IPC-gRPC`. The MAX IPC framework facilitates inter-process communication between the MAX process and any agent processes, and enhances security by isolating processes.
* Added a new package - `MultiAgentExperience-ThreadExecutor`.
* The MAX SampleApplication is updated to incorporate the MAX IPC framework. Read more here - [MAX_IPC.md](Documentation/MAX_IPC.md).

### Issue fixes
* Added a fix to address an issue which did not allow Alexa alerts to be stoppable after a power-cycling the device.

### Known Issues

## v1.3.0

### MAX-API Changes
Expand All @@ -10,7 +28,7 @@ APIs supported by MAX Library are provided in a separate MAX-API Directory with
### Enhancements
* Added the ability to temporarily store any activity/dialog requests in a buffer, during agent re-registration, when the MAX process recovers from a crash. After all agents have executed their OnCompletionCallback (received in `AgentRegistrationInterface::onReady`), the requests stored in the buffer will be processed in a priority order based on the activity type of the request. This helps restore correct state of activities/dialogs when after a crash.
* Changed the set of shared ControlTypes given to an agent during a dialog from “any controls available for other actors” to “only the controls for foreground experiences of other actors”.
* The logger has been extracted out of `MAX` and bundled separately in this package named `MultiAgentExperience-Logger`. This doesnt disturb any client operation but helps make the code more modular.
* The logger has been extracted out of `MAX` and bundled separately in this package named `MultiAgentExperience-Logger`. This doesn't disturb any client operation but helps make the code more modular.
* Added MAX integration for pending notifications.
* Added MAX integration for 'Do Not Disturb'.
* Added integration for UDC in Alexa Cloud and AVS-SDK.
Expand Down
15 changes: 9 additions & 6 deletions Documentation/Integrating_A_Device_With_MAX_Library.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,17 +113,17 @@ class MAXInterface {
public:
virtual ~MAXInterface() = default;

virtual std::shared_ptr<multiAgentExperience::agent::AgentManagerInterface> AgentManager() = 0;
virtual std::shared_ptr<multiAgentExperience::agent::AgentManagerInterface> getAgentManager() = 0;

virtual std::shared_ptr<multiAgentExperience::experience::ExperienceManagerInterface> ExperienceManager() = 0;
virtual std::shared_ptr<multiAgentExperience::experience::ExperienceManagerInterface> getExperienceManager() = 0;

virtual std::shared_ptr<multiAgentExperience::activity::ActivityManagerInterface> ActivityManager() = 0;
virtual std::shared_ptr<multiAgentExperience::activity::ActivityManagerInterface> getActivityManager() = 0;

virtual std::shared_ptr<multiAgentExperience::control::ControlManagerInterface> ControlManager() = 0;
virtual std::shared_ptr<multiAgentExperience::control::ControlManagerInterface> getControlManager() = 0;

virtual std::shared_ptr<multiAgentExperience::control::ControlInvokerInterface> ControlInvoker() = 0;
virtual std::shared_ptr<multiAgentExperience::control::ControlInvokerInterface> getControlInvoker() = 0;

virtual std::shared_ptr<multiAgentExperience::device::SetupManagerInterface> SetupManager() = 0;
virtual std::shared_ptr<multiAgentExperience::device::SetupManagerInterface> getSetupManager() = 0;

virtual void setLogLevel(multiAgentExperience::utils::Log::Level level) = 0;
};
Expand All @@ -142,6 +142,9 @@ public:
virtual bool registerAgents(
std::set<std::shared_ptr<multiAgentExperience::agent::AgentRegistrationInterface>> agentRegistrations) = 0;
virtual bool registerAgent(
std::shared_ptr<multiAgentExperience::agent::AgentRegistrationInterface> agentRegistration) = 0;
virtual void deregisterAgent(
std::shared_ptr<multiAgentExperience::agent::AgentRegistrationInterface>>) = 0;
};
Expand Down
6 changes: 4 additions & 2 deletions Documentation/Integrating_An_Agent_With_MAX_Library.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Integrating an Agent with MAX Library
## Introduction
An Agent uses the Multi Agent Experience (MAX) Library v1.3.0 to collaborate with other Agents to create a cohesive experience for customers. Each part of MAX Library helps facilitate this by providing tools Agents can use to help enable a multi-agent experience. The library also surfaces multi-agent features such as client-side support for Universal Device Commands, which enable experiences that are not possible without device side inter-agent coordination. This document describes the capabilities an Agent has available through the MAX Library, as well as suggestions of what any Agent will have to consider during integration.
The Multi-Agent Experience (MAX) Library provides tools that Agents can use to help enable a multi-agent experience. The library also surfaces multi-agent features such as client-side support for Universal Device Commands, which enable experiences that are not possible without device side inter-agent coordination. This document describes the capabilities an Agent has available through the MAX Library, as well as suggestions of what any Agent will have to consider during integration.



### Terms
Many of the concepts in this document are defined in the [VII Multi-Agent Design Guide](https://developer.amazon.com/en-US/alexa/voice-interoperability/design-guide) but also expanded upon in this document. For concepts which are explored in depth in this document, there will be a reference to the relevant section. For other terms see the [Glossary](Glossary.md).
Expand Down Expand Up @@ -282,7 +284,7 @@ namespace dialog {
* and any request which is started is also stopped. Following these lifecycle callbacks allows Agents to interact with
* any other multi-agent experiences.
*/
class DialogRequestInterface {
class DialogRequestInterface : public utils::HashableInterface {
public:
/**
Expand Down
4 changes: 2 additions & 2 deletions Documentation/Integrating_With_MAX_StaticExperiences.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ Certain Experiences provided by an agent such as DND & Pending Notifications are

## Requesting a Static Experience

To start a Static Experience, a request is made to the `StaticExperienceManagerInterface`. When requesting a static experience via the `addStaticExperience` API, the agent is expected to provide an `ExperienceId` and a priority for the Static Experience. These will always be lower priority than Experiences (a.k.a Active Experiences). The agent is also provided APIs to stop a particular Static Experiences.
To start a Static Experience, a request is made to the `StaticExperienceManagerInterface`. When requesting a static experience via the `addStaticExperience` API, the agent is expected to provide an `ExperienceId` and a priority for the Static Experience. These will always be lower priority than Experiences (a.k.a Active Experiences). The agent is also provided APIs to stop a particular Static Experience.


## Rendering a Static Experience
Static Experiences are rendered in same manner as Active Experiences, by using the `ExperienceObserverInterface`.
Static Experiences are rendered in the same manner as Active Experiences, by using the `ExperienceObserverInterface`.
128 changes: 127 additions & 1 deletion Documentation/MAX_API_Documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Notice

This document provides an overview of material changes to the MAX Toolkit.
This document provides an overview of material changes to the MAX APIs and their usages, post MAX Toolkit v0.4.0.

## Introduction

Expand Down Expand Up @@ -141,6 +141,26 @@ public:
}
```

**Addition of new registerAgent API to AgentManagerInterface**
To facilitate re-registration of a single agent after the agent has recovered from a process crash, a new registerAgent() API is introduced in the AgentManagerInterface.

```
class AgentManagerInterface {
public:
...
/**
* Registers an agent with the manager, if it is not registered already.
*
* @param agentRegistration The agent to be registered
* @return true On success
* @return false On failure
*/
virtual bool registerAgent(
std::shared_ptr<AgentRegistrationInterface> agentRegistration) = 0;
...
};
```

#### Changes for the AgentRegistrationInterface

`AgentRegistrationInterface::onReady` will be called any time MAX is newly ready for to be used, which is only expected to be once per registration of the agent. Remember if MAX goes down, the device will be re-registering agents the next time MAX is brought up. The parameters include the MAX APIs ready to use (i.e. `ActivityManagerInterface` and `DialogManagerInterface`, and `StaticExperienceManagerInterface`) as well as an `OnCompletionCallbackInterface`. This callback is expected to be executed when the agent is ready. This either is immediately if there is no re-requesting of Activities or Dialogs, or it is expected to be held until those Activities and Dialogs have been re-requested. The new requests should not be waited on, just placed with the provided APIs. If the callback is not called, there will also be no impact. Once all agents have been registered, given APIs in onReady, and executed the `OnCompletionCallbackInterface`, MAX will evaluate all currently requested items and accept the ones which are still valid, placing them in the correct state. This will minimize user impact, and result in the state these features would have been in if MAX had never been down. `AgentRegistrationInterface` is now a pure virtual class.
Expand Down Expand Up @@ -179,6 +199,65 @@ public:
} // namespace multiAgentExperience
```

## Changes to Utils
### Addition of a new HashableInterface
A new HashableInterface with only one method - getHash() is introduced. The HashableInterface provides a default implementation for the getHash() method which calculates a unique hash for the object.

```
namespace multiAgentExperience {
namespace utils {
/**
* @brief The HashableInterface class defines an interface for objects that can be hashed.
*
* This interface provides a default implementation of the getHash() method,
* which generates a hash value based on the memory address of the object.
* Derived classes can override this method to provide custom hash calculation logic.
*/
class HashableInterface {
public:
/**
* Destructor.
*/
virtual ~HashableInterface() = default;
/**
* Get the hash value of the object, based on its memory address.
*
* @return The hash value of the object.
*/
virtual std::size_t getHash() const {
return std::hash<const void*>()(static_cast<const void*>(this));
}
};
} // namespace utils
} // namespace multiAgentExperience
```

The ActivityRequestInterface and the DialogRequestInterface both inherit from the HashableInterface.

```
class ActivityRequestInterface : public utils::HashableInterface {
public:
...
};
```

```
class DialogRequestInterface : public utils::HashableInterface {
public:
...
};
```

### Why was this introduced?
For activity and dialog requests, MAX calculates the hash of the request objects and stores information for that particular hash. With the introduction of the MAX IPC framework, instead of actual request objects, “proxies“ are requested to MAX. The MAX IPC framework may use multiple ”proxies” for the same request object. By providing a custom `getHash` implementation, the IPC framework can ensure correct functionality in MAX. The corresponding code in MAX is changed to use the new `getHash` APIs.

## Changes to Dialogs

### Adding DialogBargeInPriority for use with DialogRequestInterface
Expand Down Expand Up @@ -355,6 +434,40 @@ Simultaneous activities of the same type can now be scheduled by MAX. A correspo

Currently, the default activity behavior is to allow only a single activity of a particular type to be active at once. This means that any simultaneous activity across agents will always be stopped. Consider the use case of multiple simultaneous alerts (like timers, alarms, and reminders). If these alerts become active at the same time, each new activity will replace the older one. Hence, by adding an option to stack these activities, MAX will handle each requested activity until it is stopped by the user/agent.

### Making methods virtual in ActivityRequestInterface
All methods in the ActivityRequestInterface are made virtual.

```
class ActivityRequestInterface : public utils::HashableInterface {
public:
...
/**
* Destructor.
*/
virtual ~ActivityRequestInterface() = default;
/**
* @return The type of the requested activity.
*/
virtual ActivityType getType() const {
return m_activityType;
}
/**
* @return The handler for the requested activity.
*/
virtual std::shared_ptr<ActivityHandlerInterface> getHandler() const {
return m_handler;
}
/**
* @return The MixabilityType for the requested activity.
*/
virtual MixabilityType getMixabilityType() const {
return m_mixabilityType;
}
```

## Changes to Controls

Expand Down Expand Up @@ -435,6 +548,19 @@ Example code snippet for execution of the StartListeningCallback.
startListeningCallback->startListening();
```

##### Making the method virtual in StartListeningCallback
The StartListeningCallback::startListening method is made virtual.
```
class StartListeningCallback{
public:
...
virtual void startListening() {
...
}
};
```

## Changes to MAXFactory

The parameters required to create a `MAXInterface` by the device integrator is growing, with some potentially optional parameters. For example the device integrator may specify the policies which enable/disable different kinds of Barge-Ins (cross-agent, same-agent). To make this easier to provision correctly and clearly, the MAXFactory will be replaced by a `MAXBuilder` with clearer documentation on how to build the `MAXInterface`. The device integrator may set any of the policies mentioned in `MAXPolicies.h`, while building the `MAXInterface`.
Expand Down
10 changes: 10 additions & 0 deletions Documentation/MAX_IPC.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## MultiAgentExperience IPC

Agents and device makers should build an IPC solution so that the part of an agent that interacts with MAX can reside in the MAX process and the critical components part of the agents can be a separate process. This version of MAX implements an IPC solution to enable compartmentalization of each agent in separate processes, enhancing security. MAX IPC solution attempts to make this task simpler by providing an IPC implementation.

The current implementation of the MAX IPC is done using the gRPC library. Using the MAX IPC the following solution can be achieved.
![Overall Architecture](images/MAX-IPC.png)

It is highly recommended to separate the agent processes to ensure the isolation of the critical components in their respective process.

The MAX IPC component uses the gRPC to run a server. The server is run on the Agent process as well as the Device App process. API communication to the Device App process uses the server hosted in the Device App process and any callbacks or communication done to the Agent 1 process uses the server hosted in the Agent 1 process.
Loading

0 comments on commit 0e00d49

Please sign in to comment.