AI Agents
Agents name service
Bookmark

Agents name service

Introduction

A name service, in the context of computer networks and distributed systems, is a system which associates meaningful names with network resources. This is carried out to make it easier for humans to identify and access these resources rather than using numerical IP addresses. The Domain Name System (DNS) is a widely used name service on the internet. The DNS can be thought as the internet's phonebook. Domain names (for instance, example.com), are used by humans to access content online. Web browsers communicate using Internet Protocol (IP) addresses. DNS converts domain names to IP addresses so that browsers may access Internet resources. Each Internet-connected device has a unique IP address that other machines may use to locate that specific device. DNS servers remove the need for people to remember IP addresses by heart.

In the context of Fetch.ai's Agents, we have implemented a name service for agents to allow for quicker identification thanks to human-readable names instead of other identifiers and address. For a better understanding of this, we will create two agents, alice an bob, register them in the Almanac ↗️, but with agent bob being given a domain so to be easily found by any other agent.

Walk-through

For this example guide, we will make use of the uagents and cosmpy libraries. For further understanding and resources visit our documentation for either the uAgents Framework ↗️ and CosmPy ↗️, as well as Guides ↗️ and References ↗️ sections.

The first step we need to carry out is creating a dedicated directory for this task. Let's call this directory name_service. You can do so by running the following command: mkdir name_service.

Within this directory, we need to create two separate scripts, one for each agent we will develop:

  • Bob: touch agent_1.py
  • Alice: touch agent_2.py

Let's get started!

Agent 1: bob

We start by defining the script for our agent bob.

  1. First of all, let's import all needed classes from cosmpy.aerial.wallet, uagents.network, uagents.setup, and uagents. Then, we define a message data model for types of messages to be exchanged between our agents:

    from cosmpy.aerial.wallet import LocalWallet
    from uagents.network import get_name_service_contract
    from uagents.setup import fund_agent_if_low
    from uagents import Agent, Context, Model
     
    class Message(Model):
        message: str
  2. We then need to initialize our agent bob and register it in the Almanac ↗️. We also initialize a wallet by ensuring it has enough funds in it, and then provide bob with a domain:

    bob = Agent(
        name="bob-0",
        seed="agent bob-0 secret phrase",
        port=8001,
        endpoint=["http://localhost:8001/submit"],
    )
     
    my_wallet = LocalWallet.from_unsafe_seed("registration test wallet")
    name_service_contract = get_name_service_contract(test=True)
    DOMAIN = "agent"
     
    for wallet in [my_wallet, bob.wallet]:
        fund_agent_if_low(wallet.address())

    Here, bob is initialized with a unique name, a secret seed for authentication, a specific port for communication, and an endpoint for submitting data. For additional information on endpoints, visit our documentation ↗️. A local wallet named my_wallet is then created using the seed phrase "registration test wallet".

    The name_service_contract variable is created to hold an instance of a name service contract related to registering and managing agent names. The test=True parameter indicates that this is a test environment. DOMAIN is set to "agent", indicating the domain for the agent names. The for loop iterates over the list of wallets (my_wallet and bob.wallet): for each wallet, it checks if the wallet's balance is low and if so, it funds the wallet using fund_agent_if_low().

  3. We now need to define the behavior and functions of `bob agent.

    @bob.on_event("startup")
    async def register_agent_name(ctx: Context):
        await name_service_contract.register(
            bob.ledger, my_wallet, ctx.address, ctx.name, DOMAIN
        )
     
    @bob.on_message(model=Message)
    async def message_handler(ctx: Context, sender: str, msg: Message):
        ctx.logger.info(f"Received message from {sender}: {msg.message}")
     
    if __name__ == "__main__":
        bob.run()

    Here, we defined a .on_event("startup") decorator on the register_agent_name() function. This decorator indicates that the function is executed when the agent starts up. The function takes a Context object as parameter, and registers the agent's name and domain using the name_service_contract variable we previously defined. The function uses information from the context (ctx) including the agent's ledger, wallet, address, name, and domain.

  4. Save the script.

The overall script should look as follows:

agent_1.py
from cosmpy.aerial.wallet import LocalWallet
 
from uagents.network import get_name_service_contract
from uagents.setup import fund_agent_if_low
from uagents import Agent, Context, Model
 
class Message(Model):
    message: str
 
bob = Agent(
    name="bob-0",
    seed="agent bob-0 secret phrase",
    port=8001,
    endpoint=["http://localhost:8001/submit"],
)
 
my_wallet = LocalWallet.from_unsafe_seed("registration test wallet")
name_service_contract = get_name_service_contract(test=True)
DOMAIN = "agent"
 
for wallet in [my_wallet, bob.wallet]:
    fund_agent_if_low(wallet.address())
 
@bob.on_event("startup")
async def register_agent_name(ctx: Context):
    await name_service_contract.register(
        bob.ledger, my_wallet, ctx.address, ctx.name, DOMAIN
    )
 
@bob.on_message(model=Message)
async def message_handler(ctx: Context, sender: str, msg: Message):
    ctx.logger.info(f"Received message from {sender}: {msg.message}")
 
if __name__ == "__main__":
    bob.run()

Agent 2: alice

We can now define the script for our second agent alice.

  1. First of all, let's import all needed classes from uagents.network, uagents.setup, and uagents. Then, we need to define a message data model for types of messages to be exchanged between our agents:

    from uagents.setup import fund_agent_if_low
    from uagents import Agent, Context, Model
     
    class Message(Model):
    message: str
  2. We then need to initialize our agent alice and register it in the Almanac ↗️ making sure it has enough funds in its wallet to register:

    alice = Agent(
        name="alice-0",
        seed="agent alice-0 secret phrase",
        port=8000,
        endpoint=["http://localhost:8000/submit"],
    )
     
    fund_agent_if_low(alice.wallet.address())
  3. We can now define the behavior of alice agent:

    @alice.on_interval(period=5)
    async def alice_interval_handler(ctx: Context):
        bob_name = "bob-0.agent"
        ctx.logger.info(f"Sending message to {bob_name}...")
        await ctx.send(bob_name, Message(message="Hello there bob."))
     
    if __name__ == "__main__":
        alice.run()

    Here we defined a alice_interval_handler() function. This function is a decorated with a .on_interval() decorator indicating that the function is executed at intervals of 5 seconds. This function sends a message to bob agent taking into account its name "bob-0.agent". The message being sent contains the a "Hello there bob." message

  4. Save the script.

The overall script should look as follows:

agent_2.py
from uagents.setup import fund_agent_if_low
from uagents import Agent, Context, Model
 
class Message(Model):
    message: str
 
alice = Agent(
    name="alice-0",
    seed="agent alice-0 secret phrase",
    port=8000,
    endpoint=["http://localhost:8000/submit"],
)
 
fund_agent_if_low(alice.wallet.address())
 
@alice.on_interval(period=5)
async def alice_interval_handler(ctx: Context):
    bob_name = "bob-0.agent"
    ctx.logger.info(f"Sending message to {bob_name}...")
    await ctx.send(bob_name, Message(message="Hello there bob."))
 
if __name__ == "__main__":
    alice.run()

Run the scripts

We are now ready to run the scripts. Remember to check if you are in the correct directory and to correctly activate your virtual environment.

Importantly, run agent_1.py before running agent_2.py scripts and run them from different terminals:

  • Terminal 1: python agent_1.py

  • Terminal 2: python agent_2.py

The output should be as follows, depending on the terminal:

  • bob

    [bob-0]: Registering on almanac contract...
    [bob-0]: Registering on almanac contract...complete
    [network]: Registering name...
    [network]: Registering name...complete
    [bob-0]: Starting server on http://0.0.0.0:8001 (Press CTRL+C to quit)
    [bob-0]: Received message from agent1qwquu2d237gntfugrnwch38g8jkl76vdr05qjm4wyps6ap04fvt8vtzhpqw: Hello there bob.
    [bob-0]: Received message from agent1qwquu2d237gntfugrnwch38g8jkl76vdr05qjm4wyps6ap04fvt8vtzhpqw: Hello there bob.
    [bob-0]: Received message from agent1qwquu2d237gntfugrnwch38g8jkl76vdr05qjm4wyps6ap04fvt8vtzhpqw: Hello there bob.
  • alice

    [alice-0]: Registering on almanac contract...
    [alice-0]: Registering on almanac contract...complete
    [alice-0]: Starting server on http://0.0.0.0:8000 (Press CTRL+C to quit)
    [alice-0]: Sending message to bob-0.agent...
    [alice-0]: Sending message to bob-0.agent...
    [alice-0]: Sending message to bob-0.agent...

Was this page helpful?

Bookmark