Defining Actions

The @action decorator is used to define actions on instance methods of the Agent class, and takes the following keyword arguments:

  • name: The name of the action. Defaults to the method name
  • help: The description of the action. Defaults to an autogenerated object
  • access_policy: The access policy of the action. Defaults to ACCESS_PERMITTED

Defining Action Help Information

Below is an example of the help information automatically generated by default from the @action decorator. It uses the docstring of the method, and its signature to generate the default help information.

{
  "shell_command": {
    "description": "Execute a shell command",
    "args": {
      "command": {
        "type": "string"
        "description": "The command to execute"
      }
    },
    "returns": {
      "type": "string"
      "description": "The output of the command"
    }
  },
  ...
}

This help object is supplied to other agents when requesting help.

The following example shows how the help information above can be specified from a docstring that follows the Google style guide:

@action
def shell_command(self, command: str) -> str:
    """
    Execute a shell command

    Args:
        command (str): The command to execute

    Returns:
        str: The output of the command
    """

When generating help information, the action name is determined by the method name. Types are determined by looking at the docstring and the signature, with the signature type hint taking precedence. Action and argument descriptions are parsed from the docstring.

Overriding Help Information

The default help data structure described above can be overridden by supplying a custom help object to the @action decorator.

@action(
    help={
      "You": "can define",
      "any": {
        "structure": ["you", "want", "here."]
      }
    }
)
def say(self, content: str):

When a custom help object is provided, it overrides the generated object entirely. You can use this to experiment with different help information schemas.

Access Policies

❗️Access control is experimental. Please share your feedback.

Access policies may be used to control when actions can be invoked by agents. All actions may declare an access policy like the following example:

@action(access_policy=ACCESS_PERMITTED)
def my_action(self):
    ...

An access policy can currently be one of three values:

  • ACCESS_PERMITTED - (Default) Permits any agent to use that action at any time.
  • ACCESS_DENIED - Prevents access to that action.
  • ACCESS_REQUESTED - Prompts the receiving agent for permission when access is attempted. Access will await approval or denial.

If ACCESS_REQUESTED is used, the receiving agent will be prompted to approve the action via the request_permission() callback method.

If any actions declare a policy of ACCESS_REQUESTED, you must implement the request_permission() method with the following signature in order to receive permission requests.

def request_permission(self, proposed_message: dict) -> bool:
    ...

Your implementation should inspect proposed_message and return a boolean indicating whether or not to permit the action.

You can use this approach to protect against dangerous actions being taken. For example if you allow terminal access, you may want to review commands before they are invoked.