How to Serve Assistants with A2A Protocol#
A2A Protocol is an open standard that defines how two agents can communicate with each other. It covers both the serving and consumption aspects of agent interaction.
This guide will show you how to serve a WayFlow assistant using this protocol either through the A2AServer or from the command line.
Basic implementation#
With the provided A2AServer, you can:
Serve any conversational component in WayFlow, including Agent, Flow, ManagerWorkers, and Swarm.
Serve from a serialized AgentSpec JSON/YAML string
Serve from a path to an AgentSpec config file.
In this guide, we start with serving a simple math agent equipped with a multiplication tool.
To define the agent, you will need access to a large language model (LLM). WayFlow supports several LLM API providers. Select an LLM from the options below:
from wayflowcore.models import OCIGenAIModel, OCIClientConfigWithApiKey
llm = OCIGenAIModel(
model_id="provider.model-id",
compartment_id="compartment-id",
client_config=OCIClientConfigWithApiKey(
service_endpoint="https://url-to-service-endpoint.com",
),
)
from wayflowcore.models import VllmModel
llm = VllmModel(
model_id="model-id",
host_port="VLLM_HOST_PORT",
)
from wayflowcore.models import OllamaModel
llm = OllamaModel(
model_id="model-id",
)
Creating the agent#
from typing import Annotated
from wayflowcore.agent import Agent
from wayflowcore.tools import tool
@tool
def multiply(
a: Annotated[int, "first required integer"],
b: Annotated[int, "second required integer"],
) -> int:
"Return the result of multiplication between number a and b."
return a * b
agent = Agent(
llm=llm,
name="math_agent",
custom_instruction="You are a Math agent that can do multiplication using the equipped tool.",
can_finish_conversation=True,
)
We recommend setting can_finish_conversation=True because, in A2A, each user request is treated as a Task that should complete once the request is processed.
Enabling this option allows the agent to return a completed status to clearly indicate that the task has finished.
Serving the agent with A2AServer#
from wayflowcore.agentserver.server import A2AServer
server = A2AServer()
server.serve_agent(agent=agent, url="https://<the_public_url_where_agent_can_be_found>")
# server.run(host="127.0.0.1", port=8002) # Uncomment this line to start the server
API Reference: A2AServer
You must specify the public URL where the agent will be reachable. This URL is used to specify the agent’s address in the Agent Card.
When doing server.run, the agent will be served at the specified host and port.
The server exposes the following standard A2A endpoints:
/message/send: for sending message requests/tasks/get: for getting the information of a task/.well-known/agent-card.json: for getting the agent card
By default, when a client sends a message request, the server responds that the task has been submitted.
The client must then poll /tasks/get using the returned task_id.
If the client prefers to block and wait for the final response, it can set blocking=True when sending the message request.
Serving the agent via CLI#
You can also serve an agent using its serialized AgentSpec configuration directly from the CLI:
wayflow serve \
--api a2a \
--agent-config agent.json \
--tool-registry <path to a Python module exposing a `tool_registry` dictionary for agent server tools>
Since the agent uses a tool, you must pass the tool_registry.
See the API reference for a complete description of all arguments.
Advanced usage#
Storage configuration#
By default, InMemoryDatastore is used.
This is suitable for testing or local development, but not production.
For production, configure a persistent datastore through ServerStorageConfig.
We support the following types of datastores:
InMemoryDatastore(not persistent)OracleDatastore(persistent)PostGresDatastore(persistent)
Serving other WayFlow components#
We support serving all conversational components in WayFlow.
For Flows:
Only Flows that yield are supported—that is, Flows containing InputMessageStep or AgentExecutionStep.
A Flow should include an OutputMessageStep so that its final result can be returned to the client as a message.
Below is example Flow that is valid for serving, along with how it can be served:
from wayflowcore.agent import Agent, CallerInputMode
from wayflowcore.property import StringProperty
from wayflowcore.flow import Flow
from wayflowcore.steps import AgentExecutionStep, OutputMessageStep
agent = Agent(llm=llm, can_finish_conversation=True)
agent_step = AgentExecutionStep(
name="agent_step",
agent=agent,
caller_input_mode=CallerInputMode.NEVER,
output_descriptors=[StringProperty(name="output")],
)
user_output_step = OutputMessageStep(
name="user_output_step", input_mapping={"message": "output"}
)
flow = Flow.from_steps([agent_step, user_output_step])
server = A2AServer()
server.serve_agent(
agent=flow,
url="https://<the_public_url_where_agent_can_be_found>"
)
API Reference: Flow, InputMessageStep, AgentExecutionStep, OutputMessageStep
Next steps#
Now that you have learned how to serve WayFlow assistants using A2A protocol, you may proceed to How to Build A2A Agents to learn how consume an A2A-served agent.
Full code#
Click on the card at the top of this page to download the full code for this guide or copy the code below.
1# Copyright © 2025 Oracle and/or its affiliates.
2#
3# This software is under the Apache License 2.0
4# %%[markdown]
5# How to Serve Agents with A2A Protocol
6# -------------------------------------
7
8# How to use:
9# Create a new Python virtual environment and install the latest WayFlow version.
10# ```bash
11# python -m venv venv-wayflowcore
12# source venv-wayflowcore/bin/activate
13# pip install --upgrade pip
14# pip install "wayflowcore==26.1"
15# ```
16
17# You can now run the script
18# 1. As a Python file:
19# ```bash
20# python howto_a2a_serving.py
21# ```
22# 2. As a Notebook (in VSCode):
23# When viewing the file,
24# - press the keys Ctrl + Enter to run the selected cell
25# - or Shift + Enter to run the selected cell and move to the cell below# (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License
26# (UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option.
27
28
29
30
31# %%[markdown]
32## Create the agent
33
34# %%
35from typing import Annotated
36from wayflowcore.agent import Agent
37from wayflowcore.tools import tool
38
39@tool
40def multiply(
41 a: Annotated[int, "first required integer"],
42 b: Annotated[int, "second required integer"],
43) -> int:
44 "Return the result of multiplication between number a and b."
45 return a * b
46
47agent = Agent(
48 llm=llm,
49 name="math_agent",
50 custom_instruction="You are a Math agent that can do multiplication using the equipped tool.",
51 can_finish_conversation=True,
52)
53
54
55# %%[markdown]
56## Serve the agent
57
58# %%
59from wayflowcore.agentserver.server import A2AServer
60
61server = A2AServer()
62server.serve_agent(agent=agent, url="https://<the_public_url_where_agent_can_be_found>")
63# server.run(host="127.0.0.1", port=8002) # Uncomment this line to start the server
64
65
66# %%[markdown]
67## Serve a flow
68
69# %%
70from wayflowcore.agent import Agent, CallerInputMode
71from wayflowcore.property import StringProperty
72from wayflowcore.flow import Flow
73from wayflowcore.steps import AgentExecutionStep, OutputMessageStep
74
75agent = Agent(llm=llm, can_finish_conversation=True)
76agent_step = AgentExecutionStep(
77 name="agent_step",
78 agent=agent,
79 caller_input_mode=CallerInputMode.NEVER,
80 output_descriptors=[StringProperty(name="output")],
81)
82
83user_output_step = OutputMessageStep(
84 name="user_output_step", input_mapping={"message": "output"}
85)
86
87flow = Flow.from_steps([agent_step, user_output_step])
88
89server = A2AServer()
90server.serve_agent(
91 agent=flow,
92 url="https://<the_public_url_where_agent_can_be_found>"
93)