DEV Community

Cover image for Simple A2A implementation with Strands
Shakir for AWS Community Builders

Posted on

Simple A2A implementation with Strands

A2A has become like a standard for enabling agent to agent communication, we could use the a2a-sdk for running and configuring the a2a server and its features such as agent card, agent skills, agent executor, request handler etc. However we are going to go with a simplified approach here with strands where the agent card will be fetched automatically. Let's get started!

Server

Initialize a uv project for the a2a server and switch to that directory.

uv init ~/strands-a2a-server
cd ~/strands-a2a-server 
Enter fullscreen mode Exit fullscreen mode

Add the required packages.

uv add python-dotenv==1.2.2 strands-agents[a2a]==1.42.0
Enter fullscreen mode Exit fullscreen mode

Change the code in main.py to look like below.

$ cat main.py 
from dotenv import load_dotenv
from strands import Agent
from strands.multiagent.a2a import A2AServer

load_dotenv()

def main():
    agent = Agent(
        callback_handler=None,
        description="A sample strands agent",
        model="us.amazon.nova-micro-v1:0",
    )
    a2a_server = A2AServer(agent=agent)
    a2a_server.serve()

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

I like the simplicity here, as you see above, it's quite simple to start a basic a2a server from with in strands, with just a couple of lines of code, we didn't have to install the a2a-sdk separately.

Run the code, to start the a2a server.

$ uv run main.py 

INFO:     Started server process [18006]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://127.0.0.1:9000 (Press CTRL+C to quit)
Enter fullscreen mode Exit fullscreen mode

Client

Let's now do the client part on a separate terminal. Initialize the project and switch the directory.

uv init ~/strands-a2a-client
cd ~/strands-a2a-client
Enter fullscreen mode Exit fullscreen mode

Modify main.py code to look as follows.

import asyncio

from strands.agent.a2a_agent import A2AAgent

async def main():
    agent = A2AAgent(endpoint="http://localhost:9000")
    agent_card = await agent.get_agent_card()

    print("Invoking remote agent with agent card:")
    for key, value in agent_card:
        print(key, ":", value)
    print('-' * 20)

    while True:
        prompt = input("User: ")
        if prompt.lower() == "exit":
            break

        async for event in agent.stream_async(prompt):
            if "result" in event:
                print("AI: ", event["result"], end="", flush=True)


if __name__ == "__main__":
    asyncio.run(main())
Enter fullscreen mode Exit fullscreen mode

We just call the remote endpoint, which is our a2a server, and iterate through the stream. We are also retrieving and printing the agent card of the remote agent.

Run the code.

$ uv run main.py 
Invoking remote agent with agent card:
additional_interfaces : None
capabilities : extensions=None push_notifications=None state_transition_history=None streaming=True
default_input_modes : ['text']
default_output_modes : ['text']
description : A sample strands agent
documentation_url : None
icon_url : None
name : my strands agent
preferred_transport : JSONRPC
protocol_version : 0.3.0
provider : None
security : None
security_schemes : None
signatures : None
skills : []
supports_authenticated_extended_card : None
url : http://127.0.0.1:9000/
version : 0.0.1
--------------------
User: hi, tell me abt yourself in a single line
AI:  I'm an artificial intelligence system designed to assist and provide information on a wide range of topics.

User: exit
Enter fullscreen mode Exit fullscreen mode

Tools

As you see in the output above, for now the remote agent card didn't show any skills, we can add a tool on the server and the a2a wrapper in strands should automatically convert that to skills. So, we don't have to define the skills manually and can save some effort here. Let's try that. For simplicity I am going to use a built in tool from strands itself, let's add that package. Before this, You can stop the server first with ctrl c if it's running...

uv add strands-agents-tools==0.8.0
Enter fullscreen mode Exit fullscreen mode

We shall do a couple of changes in main.py of the a2a server. We have to import the tool at the top.

from strands_tools import http_request
Enter fullscreen mode Exit fullscreen mode

And we just need to use this in the agent.

 tools=[http_request],
Enter fullscreen mode Exit fullscreen mode

So our updated code will look like:

$ cat main.py
from dotenv import load_dotenv
from strands import Agent
from strands.multiagent.a2a import A2AServer
from strands_tools import http_request

load_dotenv()

def main():
    agent = Agent(
        callback_handler=None,
        description="A sample strands agent",
        model="us.amazon.nova-micro-v1:0",
        name="my strands agent",
        tools=[http_request],
    )
    a2a_server = A2AServer(agent