A Beginner’s Journey into AI with Fetch.ai: Exploring the AI Agents(Part -3)

Abhi gangani
Fetch.ai
Published in
8 min readSep 19, 2024

Dialogues : Enhancing AI Agents Communication in Fetch.ai Ecosystem

In one of the recent updates to uAgents and AI-Engine Fetch.ai has introduced dialogues which enhances agent communication by providing structure and consistency to communicate. In this article, we will delve into how does dialogues work, how they enhances and optimises communication between AI Agents and walk through examples of open-ended and pre-defined dialogues.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Understanding Dialogues

Dialogues are structured and optimised way to how AI Agents communicate. Through dialogues agents enables multi-message sessions, state tracking and parallel conversations, providing a more robust framework than simple protocols which we checked out in previous parts. Essentially, dialogues are like “super-powered” protocols that offer more control and flexibility.

Difference between dialogues and Protocols

  • Protocols: Provides flexibility in conversations, but developers need to manage all messaging scenarios, including defining data-models and message handlers.
  • Dialogues: Add structure by enforcing state transitions and supporting multi-session tracking. They are represented by directed graphs where nodes are states, and edges are messages defining the communication flow.

Communication Patterns

In Dialogues we define communication patterns using a graph-based structure, providing every possible flow and branch in the interaction process. This ensures clear entry, transition, and exit points, making agent communication consistent and reliable.

How Dialogues can be used by Application Developers and Core Developers

  • Application Developers: Use predefined patterns to quickly implement agent use cases without designing communication structures from scratch.
  • Core Developers: Define and refine communication patterns, providing a flexible infrastructure for various applications.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Open Dialogue Chit-Chat: Interactive Conversations

Open Dialogue Chit-Chat allows for interactive agent-based conversations, where each step and state transition is visible. This type of dialogue is ideal for understanding the flow of messages and state transitions in real-time.

Step 1: Define the Dialogue Structure

  1. Create the dialogue script:
  • Open a terminal and create a directory using mkdir Dialogues and navigate into it with cd Dialogues.
  • Create a Python file named chitchat.py using touch chitchat.py.

2. Import Required Libraries:

from typing import Type
from uagents import Model
from uagents.experimental.dialogues import Dialogue, Edge, Node

3. Define Dialogue Nodes and Edges:

  • Nodes represent different states in the dialogue (e.g., default, initiate, chitchat, and conclude).
# default state of dialogue

default_state = Node(
name="Default State", # name of the node
description=(
"This is the default state of the dialogue. Every session starts in "
"this state and is automatically updated once the dialogue starts."
) # description about the node
)

# initialising state of dialogue
init_state = Node(
name="Initiated",
description=(
"This is the initial state of the dialogue that is only available at "
"the receiving agent."
),
)
  • Edges define possible transitions between these states (e.g., initiate session, start dialogue, continue dialogue, and end session).
# Edge definition for the dialogue transitions
init_session = Edge(
name="initiate_session",
description="Every dialogue starts with this transition.",
parent=None,
child=init_state,
)

Please refer open-ended dialogues example to check what nodes are needed and how are they connected using edges.

4. Define the ChitChatDialogue Class:

class ChitChatDialogue(Dialogue):
"""
This is the specific definition of the rules for the chit-chat dialogue
The rules will be predefined and the actual messages will be passed into it
"""

def __init__(
self,
version: str | None = None,
agent_address: str | None = None,
) -> None:
super().__init__(
name="ChitChatDialogue",
version=version,
agent_address=agent_address,
nodes=[
default_state,
init_state,
chatting_state,
end_state,
],
edges=[
init_session,
reject_session,
start_dialogue,
cont_dialogue,
end_session,
],
)

def on_initiate_session(self, model: Type[Model]):
"""
This handler is triggered when the initial message of the
dialogue is received. From here you can either accept or reject.
Logic that is needed to complete any kind of handshake or considers
global agent state should go here.
"""
return super()._on_state_transition(init_session.name, model)

More state transitions can be found on the same example.

Step 2: Setting up the agents

  1. Agent1: Receives and responds to messages according to the dialogue structure.

Run cd .. on terminal to go out of Dialogues directory and create Python script: touch agent1.py; copy the below script into that.

# Import required libraries
import json

from uagents import Agent, Context, Model
from uagents.setup import fund_agent_if_low
from dialogues.chitchat import ChitChatDialogue

CHAT_AGENT_ADDRESS = "<your_agent_2_address>"

agent = Agent(
name="chit_agent",
seed="<random_string_of_choice>",
port=8001,
endpoint="http://127.0.0.1:8001/submit",
)

fund_agent_if_low(agent.wallet.address())

# Define dialogue messages; each transition needs a separate message
class InitiateChitChatDialogue(Model):
pass

class AcceptChitChatDialogue(Model):
pass

class ChitChatDialogueMessage(Model):
text: str

class ConcludeChitChatDialogue(Model):
pass

class RejectChitChatDialogue(Model):
pass

# Instantiate the dialogues
chitchat_dialogue = ChitChatDialogue(
version="0.1",
agent_address=agent.address,
)

# Get an overview of the dialogue structure
print("Dialogue overview:")
print(json.dumps(chitchat_dialogue.get_overview(), indent=4))
print("---")

@chitchat_dialogue.on_initiate_session(InitiateChitChatDialogue)
async def start_chitchat(
ctx: Context,
sender: str,
_msg: InitiateChitChatDialogue,
):
ctx.logger.info(f"Received init message from {sender}")
# Do something when the dialogue is initiated
await ctx.send(sender, AcceptChitChatDialogue())

@chitchat_dialogue.on_start_dialogue(AcceptChitChatDialogue)
async def accept_chitchat(
ctx: Context,
sender: str,
_msg: AcceptChitChatDialogue,
):
ctx.logger.info(
f"session with {sender} was accepted. I'll say 'Hello!' to start the ChitChat"
)
# Do something after the dialogue is started; e.g. send a message
await ctx.send(sender, ChitChatDialogueMessage(text="Hello!"))

@chitchat_dialogue.on_reject_session(RejectChitChatDialogue)
async def reject_chitchat(
ctx: Context,
sender: str,
_msg: RejectChitChatDialogue,
):
# Do something when the dialogue is rejected and nothing has been sent yet
ctx.logger.info(f"Received reject message from: {sender}")

@chitchat_dialogue.on_continue_dialogue(ChitChatDialogueMessage)
async def continue_chitchat(
ctx: Context,
sender: str,
msg: ChitChatDialogueMessage,
):
# Do something when the dialogue continues
ctx.logger.info(f"Received message: {msg.text}")
try:
my_msg = input("Please enter your message:\n> ")
if my_msg != "exit":
await ctx.send(sender, ChitChatDialogueMessage(text=my_msg))
else:
await ctx.send(sender, ConcludeChitChatDialogue())
ctx.logger.info(
f"Received conclude message from: {sender}; accessing history:"
)
ctx.logger.info(chitchat_dialogue.get_conversation(ctx.session))
except EOFError:
await ctx.send(sender, ConcludeChitChatDialogue())

@chitchat_dialogue.on_end_session(ConcludeChitChatDialogue)
async def conclude_chitchat(
ctx: Context,
sender: str,
_msg: ConcludeChitChatDialogue,
):
# Do something when the dialogue is concluded after messages have been exchanged
ctx.logger.info(f"Received conclude message from: {sender}; accessing history:")
ctx.logger.info(chitchat_dialogue.get_conversation(ctx.session))

agent.include(chitchat_dialogue)

if __name__ == "__main__":
print(f"Agent address: {agent.address}")
agent.run()

2. Agent2: Initiates the conversation and continues the dialogue.

execute touch agent2.py; and create a similar script as done for agent1. You can find the script here.

Step 3: Run the Dialogue

  • Start Agent 1: Run agent1.py to set it up to accept and respond to messages.
  • Start Agent 2: Run agent2.py to automatically initiate the dialogue with Agent 1.

For expected output please refer here.

abc@xyz-MacBook-Pro dialogues % python3 agent1.py
Agent address: agent1qvhlqy2a4lk9gge8ug7l65a6k07wc92hh2d5jhwtat0zakrtg08njmfn00j
INFO: [chit_agent]: Almanac registration is up to date!
INFO: [chit_agent]: Starting server on http://0.0.0.0:8001 (Press CTRL+C to quit)
INFO: [chit_agent]: Received init message from agent1qgp7urkvx24a2gs8e7496fajzy78h4887vz7va4h7klzf7azzhthsz7zymu
INFO: [chit_agent]: Received message: Hello!
Please enter your message:
> Hello Chat agent, It's nice meeting you sir.
INFO: [chit_agent]: Received message: Do you know we are setting up example of how to use dialogues with agents.
Please enter your message:
> Ohh Really...!! Thats amazing.
INFO: [chit_agent]: Received message: We have done it, lets exit this conversation.
Please enter your message:
> exit




abc@xyz-MacBook-Pro dialogues % python3 agent2.py
agent address: agent1qgp7urkvx24a2gs8e7496fajzy78h4887vz7va4h7klzf7azzhthsz7zymu
INFO: [chat_agent]: Almanac registration is up to date!
INFO: [chat_agent]: Starting server on http://0.0.0.0:8002 (Press CTRL+C to quit)
INFO: [chat_agent]: session with agent1qvhlqy2a4lk9gge8ug7l65a6k07wc92hh2d5jhwtat0zakrtg08njmfn00j was accepted. I'll say 'Hello!' to start the ChitChat
INFO: [chat_agent]: Received message: Hello Chat agent, It's nice meeting you sir.
Please enter your message:
> Do you know we are setting up example of how to use dialogues with agents.
INFO: [chat_agent]: Received message: Ohh Really...!! Thats amazing.
Please enter your message:
> We have done it, lets exit this conversation.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Pre-Defined Dialogue Chit-Chat: Automating Conversations

Predefined dialogues use a hardcoded dialogue management system to automate interactions, minimizing manual intervention. This approach is ideal for scenarios where the dialogue flow is fixed and doesn’t require dynamic decision-making.

Step 1: Define the Dialogue Management

In a predefined dialogue system, nodes represent states of the dialogue (e.g., default, initiated, chatting, and concluded), while edges define the transitions between these states.

  1. Create the Dialogue Script:
  • Use hardcoded_chitchat.py to set up nodes and edges.
  • Define dialogue message models, states, transitions, and handlers.

2. Set Up Default Behavior for Dialogue Edges:

  • Map specific message types to predefined functions that manage the dialogue flow.

3. Define the ChitChatDialogue Class:

  • In the very similar fashion we will create predefined dialogues with a slight change of defining default behaviour for individual dialogue edges. Only the interaction that requires input from the user is exposed, making the other parts of the dialogue more robust and easier to maintain.
async def start_chitchat(ctx: Context,sender: str,_msg: Type[Model]):
ctx.logger.info(f"Received init message from {sender}. Accepting Dialogue.")
await ctx.send(sender, AcceptChitChatDialogue())

async def accept_chitchat(ctx: Context,sender: str,_msg: Type[Model],):
ctx.logger.info(
f"Dialogue session with {sender} was accepted. "
"I'll say 'Hello!' to start the ChitChat"
)
await ctx.send(sender, ChitChatDialogueMessage(text="Hello!"))

async def conclude_chitchat(ctx: Context,sender: str,_msg: Type[Model],):
ctx.logger.info(f"Received conclude message from: {sender}; accessing history:")
ctx.logger.info(ctx.dialogue)

async def default(_ctx: Context,_sender: str,_msg: Type[Model],):
warn(
"There is no handler for this message, please add your own logic by "
"using the `on_continue_dialogue` decorator.",
RuntimeWarning,
stacklevel=2,
)

async def persisting_function(ctx: Context,_sender: str,_msg: Type[Model],):
ctx.logger.info("I was not overwritten, hehe.")
  • In the provided code, specific message types associated with different dialogue states trigger predefined functions that manage the flow and actions of the dialogue, automating the transition between states and handling interactions within the dialogue system efficiently.
init_session.set_message_handler(InitiateChitChatDialogue, start_chitchat)
start_dialogue.set_message_handler(AcceptChitChatDialogue, accept_chitchat)
cont_dialogue.set_message_handler(ChitChatDialogueMessage, default)
cont_dialogue.set_edge_handler(ChitChatDialogueMessage, persisting_function)
end_session.set_message_handler(ConcludeChitChatDialogue, conclude_chitchat)
  • Defining chitchat dialogue class:
class ChitChatDialogue(Dialogue):
def __init__(self, version: str | None = None, agent_address: str | None = None) -> None:
super().__init__(
name="ChitChatDialogue",
version=version,
agent_address=agent_address,
nodes=[init_state, chatting_state, end_state],
edges=[init_session, start_dialogue, cont_dialogue, end_session],
)

def on_continue_dialogue(self):
return super()._on_state_transition(cont_dialogue.name, ChitChatDialogueMessage)

Step 2: Setting Up the Agents

  1. Agent 1: Receives and responds to messages based on predefined rules.
  2. Agent 2: Automatically initiates a dialogue with Agent 1.

You can find scripts for agents here.

In these agents now we just need to include continue_chitchat handler as rest all are predefined in the dialogues itself.

Step 3: Run the Dialogue

  • Start Agent 1: Run agent1.py to have it ready for predefined interaction.
  • Start Agent 2: Run agent2.py to automatically initiate and follow the predefined dialogue flow.

For expected output please refer here.

abc@xyz-MacBook-Pro dialogues % python3 agent1.py
Agent address: agent1qfjvt60h0kh573fzy9mvmlsr50vff8xmdfeclfgy3g9g6qq6jxkuxh4cu3w
INFO: [chit_agent]: Almanac registration is up to date!
INFO: [chit_agent]: Starting server on http://0.0.0.0:8001 (Press CTRL+C to quit)
INFO: [chit_agent]: Received init message from agent1qwvecfwc255pfqqwtjznh9qqk6skl77xc6fzw8mr3ppfex32sr0kcad62n4. Accepting Dialogue.
INFO: [chit_agent]: I was not overwritten, hehe.
INFO: [chit_agent]: Received message: Hello!
Please enter your message:
> we are providing example for predefined dialogue
INFO: [chit_agent]: I was not overwritten, hehe.
INFO: [chit_agent]: Received message: we are providing example for predefined dialogue
Please enter your message:
> The message is sent but there is no functionality to get back
INFO: [chit_agent]: I was not overwritten, hehe.
INFO: [chit_agent]: Received message: The message is sent but there is no functionality to get back
Please enter your message:


abc@xyz dialogues % python3 agent2.py
Agent address: agent1qwvecfwc255pfqqwtjznh9qqk6skl77xc6fzw8mr3ppfex32sr0kcad62n4
INFO: [chat_agent]: Almanac registration is up to date!
INFO: [chat_agent]: Starting server on http://0.0.0.0:8002 (Press CTRL+C to quit)
INFO: [chat_agent]: Dialogue session with agent1qfjvt60h0kh573fzy9mvmlsr50vff8xmdfeclfgy3g9g6qq6jxkuxh4cu3w was accepted. I'll say 'Hello!' to start the ChitChat
INFO: [chat_agent]: I was not overwritten, hehe.
INFO: [chat_agent]: Returning: we are providing example for predefined dialogue
INFO: [chat_agent]: I was not overwritten, hehe.
INFO: [chat_agent]: Returning: The message is sent but there is no functionality to get back

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Conclusion

By leveraging the power of dialogues in Fetch.ai, we can create structured and efficient agent communications. Whether it’s open-ended dialogues for interactive experiences or predefined dialogues for automated interactions, the flexibility and control provided by dialogues enhance the capabilities of AI agents in various applications.

In the next part, we’ll explore AI-Engine Compatible Dialogues and Linear Dialogues, diving deeper into how these advanced conversational patterns can be implemented within the Fetch.ai ecosystem.

--

--