Responses and Synchronous Messaging
Messages sent using Agent.send()
are sent asynchronously. This is in line with the expectations in an actor model.
Often though, we’d like to send a message to an agent and receive an associated response. Agents have multiple options for doing this.
Replying to Messages
The most basic response can be achieved simply using Agent.send()
along with Agent.current_message()
. For example:
class MyAgent(Agent):
@action
def say(self, content: str):
...
self.send({
"to": self.current_message()["from"], # reply to the sender
"action": {
"name": "say",
"args": {
"content": "Hello!"
}
}
})
The above will send the say
action back to the original sender.
Using Agent.respond_with
for Value Responses
Often it’s useful to send a value back to the sender of a message, similar to a return value from a function. In these cases, Agent.respond_with
may be used. Take the following two simple agents as an example.
class MyAgent(Agent):
@action
def ping(self):
self.respond_with("pong")
class SenderAgent(Agent):
...
def handle_action_value(self, value):
print(value)
When an instance of SenderAgent
sends a ping
action to MyAgent
, the handle_action_value
callback on SenderAgent
will be invoked with the value "pong"
.
Note that respond_with()
may be called multiple times in a single action. Each call will invoke the handle_action_value
callback on the sender.
Using Agent.raise_with
for Error Responses
Similar to Agent.respond_with
, Agent.raise_with
may be used to send an exception back to the sender of a message. For example:
class MyAgent(Agent):
@action
def ping(self):
self.raise_with(Exception("oops"))
class SenderAgent(Agent):
...
def handle_action_error(self, error: ActionError):
print(error.message)
In this example, an instance of SenderAgent
sends a ping
action to MyAgent
. The handle_action_error
callback on MyAgent
will be invoked with the exception ActionError("Exception: oops")
.
Similar to respond_with
, raise_with
may be called multiple times in a single action. Each call will invoke the handle_action_error
callback on the sender.
Note that when an action raises an exception, raise_with
will be automatically invoked for you, sending the exception back to the sender.
Using Agent.request()
for Synchronous Messaging
The Agent.request()
method is a synchronous version of the send()
method that allows you to call an action and receive its return value or exception synchronously without using the handle_action_*
callbacks.
If the action responds with an error, an ActionError
will be raised containing the original error message.
Here’s an example of how you might use request()
:
try:
return_value = self.request({
"to": "ExampleAgent",
"action": {
"name": "example_action",
"args": {
"content": "hello"
}
}
}, timeout=5)
except ActionError as e:
print(e.message)
Note that request()
may not be called within the after_add()
and before_remove()
callbacks, but may be used within actions or other callbacks.
Also notice the timeout value. The default is 3 seconds. Make sure to increase this appropriately for longer running requests.