Skip to content

v1.3.0

Compare
Choose a tag to compare
@operand operand released this 09 Aug 23:21
· 80 commits to main since this release
3e33f12

Summary of Changes

This release brings many API and internal improvements. I've incorporated a lot of the great feedback I've been getting and improved multiple areas in terms of clarity, organization, and implementation.

What I'm most excited about is that the API feels like it's beginning to reach a relatively clean and extensible form, enabling more possibilities to follow.

A number of syntactic and semantic changes have been made. I've summarized the changes here, but for full details also refer to the updated docs/ or readme.

As always please let me know what you think, especially if you find any issues!

Syntax and functional changes

  • Introduced a new @action decorator based syntax for defining actions and their metadata, replacing the @access_policy decorator. For example:

    @action
    def my_action(self):
        ...

    An example showing how the access_policy is now declared:

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

    Additionally, the _action__ prefix is no longer needed on action method names.

  • Agent id's are now enforced to be unique.

    Allowing duplicate id's creates more problems than it solves. If one needs to duplicate or distribute messages to multiple consumers, that can be achieved by simply sending multiple messages from the agent.

  • Leading underscores removed from several agent methods and callbacks.

    Moving forward, methods with leading underscores should be treated as internal API methods and should generally not be referenced in except when overriding methods or extending a class. To follow this convention, the following methods have been renamed:

    Agent class methods:

    • _send is now send

    • _before_add is now before_add

    • _after_add is now after_add

    • _before_remove is now before_remove

    • _after_remove is now after_remove

    • _request_permission is now request_permission

    • Additionally, the special action return is now renamed to response.

  • The signatures for response(formerly return) and error have changed to the following:

    @action
    def response(self, data, original_message_id: str):
        ...
    
    @action
    def error(self, error: str, original_message_id: str):
        ...

    Note that the original_message argument is replaced with the original_message_id parameter. This parameter is discussed with the message schema changes below.

  • Updated help functionality

    The help action now returns a new schema for describing actions. The data structure returned is now a dictionary similar to the following example:

    {
      "say": {
          "description": "Say something to this agent",
          "args": {
              "content": {
                  "type": "string"
                  "description": "The content to say"
              }
          },
          "returns": {
              "type": "string"
              "description": "A response"
          }
      },
      ...
    }

    The help structure above is automatically generated from the method's docstring and signature. Additionally, you can provide a custom help schema using the @action decorator.

    See the "Defining Actions" section for more details on the help schema.

  • Space.remove_all() method added for removing all agents who were added through the receiving space instance. In other words, in an AMQP distributed system, only the locally added agents would be removed.

Message schema changes

  • Added an optional id field. This field is automatically provided with response or error messages for you to correlate with the original message.

  • Added an optional meta field. This field is an optional dictionary of key-value pairs for you to attach metadata to a message. For example, you may use this to store timestamps, or a "thoughts" field for recording reasoning.

  • The to field is now required. To send a broadcast use the special address *.

  • The action field is now an object containing the name and args fields.

The full schema is summarized with this example:

{
    "id": "optional string id",
    "meta": {
        "an": "optional",
        "field": ["for", "metadata"]
    },
    "to": "an agent id", # or '*' to broadcast
    "from": "sender's id",
    "action": {
        "name": "my_action",
        "args": {
            "the": "args"
        }
    }
}

See the docs "Schema" section for more details.

Message routing changes

  • Broadcasts are now self received by default. This is the normal semantics for broadcasts.

    This behavior is now an option on the Agent class: receive_own_broadcasts: bool = True.

    Setting it to False will restore the previous behavior.

  • Messages sent to a non-existent agent will now be silently ignored. Previously this would result in an error message being returned. Note that calling a non-existent action on an existent agent will still result in an error message.

    This change brings us more in line with the Actor model. Reliability options may be added at the Agent level in the future.

Internal Improvements

  • Removed colorama dependency

  • Removed use of id_queue in AMQPSpace for checking agent existence.

  • Space._route() no longer sets the from field on messages. The entire
    message must be populated within the Agent instance before calling _route().

  • Threading improvements

    Threading code has been greatly cleaned up and improved. The updated implementation should make it easy to support additional forms of multi-processing like green threads and the multiprocessing module. I'm really happy about this change in particular.

  • Space classes (NativeSpace and AMQPSpace) moved to the agency.spaces namespace.

  • Tests have been better organized into separate files.

  • The Space class abstract methods have been changed. Space subclasses now implement the following methods:

    • _connect()
    • _disconnect()
    • _deliver()
    • _consume()

    This is a change from the previous interface. See the Space class for more details.

Demo improvements

  • OpenAIFunctionAgent now supplies argument descriptions to the OpenAI function calling API, enabled by the new help information schema.

  • Agent mixins have been refactored to better separate behavior.

  • Updated slash syntax in the UI. Slash commands now follow this example:

    /agent_id.action_name arg1:value1 arg2:value2 ...
    

    The agent_id above defines the to field of the message and is required.

    To broadcast an action, use the syntax:

    /*.action_name arg1:value1 arg2:value2 ...
    

    Note that unformatted text is still considered a broadcasted say action.

That's all for now!