From b43cfe015a2075d4edd338f9215e4305e8aa6949 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Tue, 2 Dec 2025 11:25:26 +0100 Subject: [PATCH 01/21] docs: add a how to guide for serving and consuming A2A Agents using Manager Workers --- .../source/core/code_examples/howto_a2a.py | 151 ++++++++++++++++++ .../source/core/howtoguides/howto_a2a.rst | 105 ++++++++++++ .../source/core/howtoguides/index.rst | 1 + 3 files changed, 257 insertions(+) create mode 100644 docs/wayflowcore/source/core/code_examples/howto_a2a.py create mode 100644 docs/wayflowcore/source/core/howtoguides/howto_a2a.rst diff --git a/docs/wayflowcore/source/core/code_examples/howto_a2a.py b/docs/wayflowcore/source/core/code_examples/howto_a2a.py new file mode 100644 index 000000000..425c6f431 --- /dev/null +++ b/docs/wayflowcore/source/core/code_examples/howto_a2a.py @@ -0,0 +1,151 @@ +# Copyright © 2025 Oracle and/or its affiliates. +# +# This software is under the Apache License 2.0 +# (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License +# (UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option. + +# isort:skip_file +# fmt: off +# mypy: ignore-errors +# docs-title: How to use Serve and Consume Agents using A2A + +# Server part +from typing import Annotated + +from wayflowcore.a2a.server import A2AServer +from wayflowcore.agent import Agent +from wayflowcore.models import VllmModel +from wayflowcore.tools import tool + +# .. start-##_llm +llm = VllmModel( + model_id="LLAMA_MODEL_ID", + host_port="LLAMA_API_URL", +) +# .. end-##_llm + +(llm,) = _update_globals(["vision_llm"]) # docs-skiprow # type: ignore + + +# .. start-##_Server_Setup_Prime_Agent +def get_prime_agent(): + @tool + def check_prime(a: Annotated[int, "first required integer"]) -> bool: + "Check if the first number (a) is a prime number." + if a < 2: + return False + for i in range(2, int(a**0.5) + 1): + if a % i == 0: + return False + return True + + agent = Agent( + llm=llm, + name="prime_agent", + custom_instruction="You are a math agent that can check whether a number is prime or not using the equipped tool.", + tools=[check_prime], + can_finish_conversation=True, + ) + return agent + + +# .. end-##_Server_Setup_Prime_Agent + + +# .. start-##_Server_Setup_Sample_Agent +def get_sample_agent(): + @tool + def sample_number(a: Annotated[int, "first required integer"]) -> int: + "Simulate sampling from a range, return a random number between 1 and the specified value." + import random + + result = random.randint(1, a) + return result + + agent = Agent( + llm=llm, + name="sample_agent", + custom_instruction="You are an agent that can generate a random number between 1 and a specified value.", + tools=[sample_number], + can_finish_conversation=True, + ) + return agent + + +# .. end-##_Server_Setup_Sample_Agent + +# .. start-##_Server_Startup_Logic +# Start both sample and prime servers +sample_agent = get_sample_agent() +sample_server = A2AServer() +sample_server.serve_agent(sample_agent, "http://") +# Note: Uncomment the line below to start the server +# sample_server.serve() + +prime_agent = get_prime_agent() +prime_server = A2AServer() +prime_server.serve_agent(prime_agent, "http://") +# Note: Uncomment the line below to start the server +# prime_server.serve(port=8001) +# .. end-##_Server_Startup_Logic + +(sample_server,) = _update_globals(["sample_a2a_server"]) # docs-skiprow # type: ignore +(prime_server,) = _update_globals(["prime_a2a_server"]) # docs-skiprow # type: ignore + +from wayflowcore.a2a.a2aagent import A2AAgent, A2AConnectionConfig + +# Client part +from wayflowcore.agent import Agent +from wayflowcore.models import VllmModel + +# .. start-##_Client_Setup +sample_agent = A2AAgent( + name="sample_agent", + agent_url="http://", + description="Agent that can generate random numbers", + connection_config=A2AConnectionConfig(verify=False), +) +prime_agent = A2AAgent( + name="prime_agent", + agent_url="http://", + description="Agent that handles checking if numbers are prime.", + connection_config=A2AConnectionConfig(verify=False), +) +# .. end-##_Client_Setup + +(sample_agent, prime_agent) = _update_globals( + ["sample_a2a_agent", "prime_a2a_agent"] +) # docs-skiprow # type: ignore + +# .. start-##_Manager_Setup +MANAGER_SYSTEM_PROMPT = """ +You are a helpful assistant that can sample numbers and check if the sampled numbers are prime. +You delegate sampling tasks to the `sample_agent` and prime checking tasks to the `prime_agent`. +Follow these steps: +1. If the user asks to sample a number, delegate to the `sample_agent`. +2. If the user asks to check primes, delegate to the `prime_agent`. +3. If the user asks to sample a number and then check if the result is prime, call `sample_agent` first, then pass the result to `prime_agent`. +Always clarify the results before proceeding. +""".strip() + +manager = Agent( + name="PrimeChecker", + description="You are a PrimeChecker who can sample integers and check if they are prime.", + llm=llm, + custom_instruction=MANAGER_SYSTEM_PROMPT, +) +# .. end-##_Manager_Setup + +# .. start-##_ManagerWorkers_Execution +from wayflowcore.managerworkers import ManagerWorkers + +group = ManagerWorkers( + group_manager=manager, + workers=[sample_agent, prime_agent], +) + +main_conversation = group.start_conversation() +main_conversation.append_user_message("Sample a number from 1 to 20 and check if it's prime") +main_conversation.execute() +print(main_conversation.get_messages()) +# .. end-##_ManagerWorkers_Execution diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst new file mode 100644 index 000000000..538032bbf --- /dev/null +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst @@ -0,0 +1,105 @@ +.. _top-howtoa2a: + +============================================= +How to use Serve and Consume Agents using A2A +============================================= + +.. |python-icon| image:: ../../_static/icons/python-icon.svg + :width: 40px + :height: 40px + +.. grid:: 2 + + .. grid-item-card:: |python-icon| Download Python Script + :link: ../end_to_end_code_examples/howto_a2a.py + :link-alt: A2A servers and clients how-to script + + Python script/notebook for this guide. + +.. admonition:: Prerequisites + + This guide assumes familiarity with: + + - :doc:`LLM configuration <../howtoguides/llm_from_different_providers>` + - :doc:`Using agents ` + +This guide provides a step-by-step walkthrough on how to use the `Agent-to-Agent (A2A) protocol ` within Wayflow, covering both the serving and consuming roles from start to finish. +The A2A protocol allows agents to seamlessly communicate and delegate tasks to one another. + +We'll demonstrate its functionality by creating two agents: one responsible for checking if a number is prime and another for generating random numbers. These agents will interact under the coordination of a manager agent. +Through this example, we'll highlight how the A2A protocol enables easy integration of specialized agents independent on how its implemented, allowing for flexible, plug-and-play capabilities across different tasks. + +Server Setup for Agents +======================= + +In this section, we set up servers for two agents: a ``prime_agent`` for checking prime numbers and a ``sample_agent`` for generating random numbers. + +Prime Agent Server +------------------ + +.. literalinclude:: ../code_examples/howto_a2a.py + :language: python + :start-after: .. start-##_Server_Setup_Prime_Agent + :end-before: .. end-##_Server_Setup_Prime_Agent + +Sample Agent Server +------------------- + +.. literalinclude:: ../code_examples/howto_a2a.py + :language: python + :start-after: .. start-##_Server_Setup_Sample_Agent + :end-before: .. end-##_Server_Setup_Sample_Agent + +Starting the Servers +-------------------- + +.. literalinclude:: ../code_examples/howto_a2a.py + :language: python + :start-after: .. start-##_Server_Startup_Logic + :end-before: .. end-##_Server_Startup_Logic + +Client Setup for A2A Agents +=========================== + +On the client side, we create A2A agents that connect to the respective servers. + +.. literalinclude:: ../code_examples/howto_a2a.py + :language: python + :start-after: .. start-##_Client_Setup + :end-before: .. end-##_Client_Setup + +Manager Agent Setup +=================== + +A manager agent is created to coordinate tasks between the sample and prime agents. + +.. literalinclude:: ../code_examples/howto_a2a.py + :language: python + :start-after: .. start-##_Manager_Setup + :end-before: .. end-##_Manager_Setup + +Executing Tasks with ManagerWorkers +=================================== + +Finally, we use the :ref:`ManagerWorkers ` to execute a conversation where the manager agent delegates tasks to the appropriate agents. + +.. literalinclude:: ../code_examples/howto_a2a.py + :language: python + :start-after: .. start-##_ManagerWorkers_Execution + :end-before: .. end-##_ManagerWorkers_Execution + +Next steps +========== + +This guide provided a complete example of implementing the A2A protocol in Wayflow. By setting up servers for specialized agents and coordinating their interactions through a manager agent, you can create powerful distributed systems where tasks are delegated efficiently. + +For more and fine grained details on serving agents with A2A, refer to :doc:`A2A Serving ` and on using A2A agents, refer to :doc:`A2A Consuming `. + +Full code +========= + +Click on the card at the :ref:`top of this page ` to download the full code for this guide or copy the code below. + +.. literalinclude:: ../end_to_end_code_examples/howto_a2a.py + :language: python + :linenos: diff --git a/docs/wayflowcore/source/core/howtoguides/index.rst b/docs/wayflowcore/source/core/howtoguides/index.rst index a45cf6a4d..d7ca9ee96 100644 --- a/docs/wayflowcore/source/core/howtoguides/index.rst +++ b/docs/wayflowcore/source/core/howtoguides/index.rst @@ -66,6 +66,7 @@ These how-to guides demonstrate how to use the main features to create and custo Build a Hierarchical Multi-Agent System Build a Swarm of Agents Build a ManagerWorkers of Agents + How to use Serve and Consume Agents using A2A .. toctree:: From 787de88106dce707fd451d84bc264a0c6319afa3 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Tue, 2 Dec 2025 11:25:59 +0100 Subject: [PATCH 02/21] refactor: allow A2AAgent in ManagerWorkers --- .../src/wayflowcore/executors/_managerworkersexecutor.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py b/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py index c3d59cf55..768a98437 100644 --- a/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py +++ b/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py @@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Sequence, Union from wayflowcore import Conversation +from wayflowcore.a2a.a2aagent import A2AAgent from wayflowcore.agent import Agent, CallerInputMode from wayflowcore.executors._agenticpattern_helpers import ( _SEND_MESSAGE_TOOL_NAME, @@ -59,7 +60,7 @@ def _validate_agent_unicity( agent_by_name: Dict[str, Union["Agent", "ManagerWorkers"]] = {} for agent in agents: - if not isinstance(agent, (Agent, ManagerWorkers)): + if not isinstance(agent, (Agent, ManagerWorkers, A2AAgent)): raise TypeError( f"Only Agent and ManagerWorker type are supported in ManagerWorkers, got component of type '{agent.__class__.__name__}'" ) From b3bd7e9db405e1e45a0526054b9de994e99de43e Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Tue, 2 Dec 2025 11:26:30 +0100 Subject: [PATCH 03/21] test: have A2A servers and clients for the doc example --- wayflowcore/tests/a2a/conftest.py | 47 +++++++++++++++++++++++ wayflowcore/tests/a2a/start_a2a_server.py | 44 +++++++++++++++++++++ wayflowcore/tests/test_docs_examples.py | 19 ++++++++- 3 files changed, 108 insertions(+), 2 deletions(-) diff --git a/wayflowcore/tests/a2a/conftest.py b/wayflowcore/tests/a2a/conftest.py index 69ff0a617..ca5b08df6 100644 --- a/wayflowcore/tests/a2a/conftest.py +++ b/wayflowcore/tests/a2a/conftest.py @@ -13,6 +13,7 @@ import pytest from ..utils import LogTee, _check_server_is_up, _terminate_process_tree, get_available_port +from wayflowcore.a2a.a2aagent import A2AAgent, A2AConnectionConfig from .start_a2a_server import AgentType _START_SERVER_FILE_PATH = str(Path(__file__).parent / "start_a2a_server.py") @@ -110,3 +111,49 @@ def adk_a2a_server_fixture(session_tmp_path): yield url finally: _terminate_process_tree(process, timeout=5.0) + + +@pytest.fixture(scope="session", name="sample_a2a_server") +def sample_a2a_server_fixture(request, session_tmp_path): + agent_type = getattr(request, "param", AgentType.SAMPLE_AGENT) + + host = "localhost" + port = get_available_port(session_tmp_path) + process, url = _start_a2a_server(host=host, port=port, agent_type=agent_type) + try: + yield url + time.sleep(0.5) + finally: + _terminate_process_tree(process, timeout=5.0) + + +@pytest.fixture(scope="session", name="prime_a2a_server") +def prime_a2a_server_fixture(request, session_tmp_path): + agent_type = getattr(request, "param", AgentType.PRIME_AGENT) + host = "localhost" + port = get_available_port(session_tmp_path) + process, url = _start_a2a_server(host=host, port=port, agent_type=agent_type) + try: + yield url + finally: + _terminate_process_tree(process, timeout=5.0) + + +@pytest.fixture(scope="session", name="sample_a2a_agent") +def sample_a2a_agent_fixture(sample_a2a_server): + return A2AAgent( + name="sample_agent", + agent_url=sample_a2a_server, + description="Agent that can generate random numbers", + connection_config=A2AConnectionConfig(verify=False), + ) + + +@pytest.fixture(scope="session", name="prime_a2a_agent") +def prime_a2a_agent_fixture(prime_a2a_server): + return A2AAgent( + name="prime_agent", + agent_url=prime_a2a_server, + description="Agent that handles checking if numbers are prime.", + connection_config=A2AConnectionConfig(verify=False), + ) diff --git a/wayflowcore/tests/a2a/start_a2a_server.py b/wayflowcore/tests/a2a/start_a2a_server.py index 58b132163..5b6fb7ddb 100644 --- a/wayflowcore/tests/a2a/start_a2a_server.py +++ b/wayflowcore/tests/a2a/start_a2a_server.py @@ -60,6 +60,8 @@ class AgentType(str, Enum): MANAGER_WORKERS = "manager_workers" SWARM = "swarm" ADK_AGENT = "adk_agent" + SAMPLE_AGENT = "sample_agent" + PRIME_AGENT = "prime_agent" # ============== Agent functions ============== @@ -247,6 +249,48 @@ def get_swarm() -> Swarm: return Swarm(first_agent=first_agent, relationships=[(first_agent, second_agent)]) +@register_agent(AgentType.SAMPLE_AGENT) +def get_sample_agent() -> Agent: + @tool + def sample_number(a: Annotated[int, "upper bound for random selection"]) -> int: + "Simulate sampling a random number between 1 and the specified upper bound." + import random + + result = random.randint(1, a) + return result + + agent = Agent( + llm=llm, + name="sample_agent", + custom_instruction="You are an agent that can generate a random number between 1 and a specified value.", + tools=[sample_number], + can_finish_conversation=True, + ) + return agent + + +@register_agent(AgentType.PRIME_AGENT) +def get_prime_agent() -> Agent: + @tool + def check_prime(a: Annotated[int, "first required integer"]) -> bool: + "Check if the input number is a prime number." + if a < 2: + return False + for i in range(2, int(a**0.5) + 1): + if a % i == 0: + return False + return True + + agent = Agent( + llm=llm, + name="prime_agent", + custom_instruction="You are a math agent that can check whether a number is prime or not using the equipped tool.", + tools=[check_prime], + can_finish_conversation=True, + ) + return agent + + # ============== Server ============== def create_server(agent_type: AgentType, host: str, port: int): """Create and configure the A2A server""" diff --git a/wayflowcore/tests/test_docs_examples.py b/wayflowcore/tests/test_docs_examples.py index e359cef54..a8d578421 100644 --- a/wayflowcore/tests/test_docs_examples.py +++ b/wayflowcore/tests/test_docs_examples.py @@ -17,7 +17,13 @@ from wayflowcore.datastore.inmemory import _INMEMORY_USER_WARNING from wayflowcore.transforms.summarization import _SUMMARIZATION_WARNING_MESSAGE -from .a2a.conftest import a2a_server_fixture # noqa +from .a2a.conftest import ( # noqa + a2a_server_fixture, + prime_a2a_agent_fixture, + prime_a2a_server_fixture, + sample_a2a_agent_fixture, + sample_a2a_server_fixture, +) from .a2a.test_a2aagent import a2a_agent, connection_config_no_verify # noqa from .mcptools.conftest import sse_mcp_server_http # noqa from .mcptools.test_mcp_tools import MCP_USER_QUERY @@ -128,8 +134,17 @@ def _update_globals(varnames_to_update: List[str]) -> Tuple[Any, ...]: replacements["oci_agent"] = pytest_request.getfixturevalue("oci_agent") if "a2a_agent" in varnames_to_update: replacements["a2a_agent"] = pytest_request.getfixturevalue("a2a_agent") - elif "sse_mcp_server" in varnames_to_update: + if "sse_mcp_server" in varnames_to_update: replacements["sse_mcp_server"] = pytest_request.getfixturevalue("sse_mcp_server_http") + # Support for A2A examples like howto_a2a.py + if "sample_a2a_agent" in varnames_to_update: + replacements["sample_a2a_agent"] = pytest_request.getfixturevalue("sample_a2a_agent") + if "prime_a2a_agent" in varnames_to_update: + replacements["prime_a2a_agent"] = pytest_request.getfixturevalue("prime_a2a_agent") + if "sample_a2a_server" in varnames_to_update: + replacements["sample_a2a_server"] = pytest_request.getfixturevalue("sample_a2a_server") + if "prime_a2a_server" in varnames_to_update: + replacements["prime_a2a_server"] = pytest_request.getfixturevalue("prime_a2a_server") return tuple(replacements[name] for name in varnames_to_update) From a78fb4e70494783e00c343c484bd363352505742 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Tue, 2 Dec 2025 14:45:20 +0100 Subject: [PATCH 04/21] docs: fix typo in howto_a2a --- docs/wayflowcore/source/core/howtoguides/howto_a2a.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst index 538032bbf..657388869 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst @@ -23,7 +23,7 @@ How to use Serve and Consume Agents using A2A - :doc:`LLM configuration <../howtoguides/llm_from_different_providers>` - :doc:`Using agents ` -This guide provides a step-by-step walkthrough on how to use the `Agent-to-Agent (A2A) protocol ` within Wayflow, covering both the serving and consuming roles from start to finish. +This guide provides a step-by-step walkthrough on how to use the `Agent-to-Agent (A2A) protocol `_ within Wayflow, covering both the serving and consuming roles from start to finish. The A2A protocol allows agents to seamlessly communicate and delegate tasks to one another. We'll demonstrate its functionality by creating two agents: one responsible for checking if a number is prime and another for generating random numbers. These agents will interact under the coordination of a manager agent. From 697bd300ffc69ebb77499b5abed69fd4dbb2f304 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Wed, 3 Dec 2025 15:09:15 +0100 Subject: [PATCH 05/21] docs: clean up the descriptions --- .../source/core/code_examples/howto_a2a.py | 4 --- .../source/core/howtoguides/howto_a2a.rst | 35 +++++++++++-------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/docs/wayflowcore/source/core/code_examples/howto_a2a.py b/docs/wayflowcore/source/core/code_examples/howto_a2a.py index 425c6f431..973b9a44e 100644 --- a/docs/wayflowcore/source/core/code_examples/howto_a2a.py +++ b/docs/wayflowcore/source/core/code_examples/howto_a2a.py @@ -47,8 +47,6 @@ def check_prime(a: Annotated[int, "first required integer"]) -> bool: can_finish_conversation=True, ) return agent - - # .. end-##_Server_Setup_Prime_Agent @@ -70,8 +68,6 @@ def sample_number(a: Annotated[int, "first required integer"]) -> int: can_finish_conversation=True, ) return agent - - # .. end-##_Server_Setup_Sample_Agent # .. start-##_Server_Startup_Logic diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst index 657388869..e2e28aa32 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst @@ -23,28 +23,24 @@ How to use Serve and Consume Agents using A2A - :doc:`LLM configuration <../howtoguides/llm_from_different_providers>` - :doc:`Using agents ` -This guide provides a step-by-step walkthrough on how to use the `Agent-to-Agent (A2A) protocol `_ within Wayflow, covering both the serving and consuming roles from start to finish. -The A2A protocol allows agents to seamlessly communicate and delegate tasks to one another. +This step-by-step guide demonstrates how to use the `Agent-to-Agent (A2A) protocol `_ in Wayflow for both serving and consuming agents. -We'll demonstrate its functionality by creating two agents: one responsible for checking if a number is prime and another for generating random numbers. These agents will interact under the coordination of a manager agent. -Through this example, we'll highlight how the A2A protocol enables easy integration of specialized agents independent on how its implemented, allowing for flexible, plug-and-play capabilities across different tasks. +The A2A protocol enables agents to communicate and delegate tasks seamlessly. In this example, you'll create two agents: one for checking if numbers are prime, and another for generating random numbers. +A manager agent will coordinate their interactions, demonstrating the plug-and-play flexibility offered by the protocol for integrating specialized agents, regardless of their implementation details. Server Setup for Agents ======================= -In this section, we set up servers for two agents: a ``prime_agent`` for checking prime numbers and a ``sample_agent`` for generating random numbers. +In this section, you'll set up servers for two agents: ``prime_agent`` checks if numbers are prime, and ``sample_agent`` generates random numbers. -Prime Agent Server ------------------- +Setting up the Agents +--------------------- .. literalinclude:: ../code_examples/howto_a2a.py :language: python :start-after: .. start-##_Server_Setup_Prime_Agent :end-before: .. end-##_Server_Setup_Prime_Agent -Sample Agent Server -------------------- - .. literalinclude:: ../code_examples/howto_a2a.py :language: python :start-after: .. start-##_Server_Setup_Sample_Agent @@ -58,20 +54,26 @@ Starting the Servers :start-after: .. start-##_Server_Startup_Logic :end-before: .. end-##_Server_Startup_Logic +For further details, see :ref:`A2AServer `. + Client Setup for A2A Agents =========================== -On the client side, we create A2A agents that connect to the respective servers. +On the client side, create ``A2AAgent`` instances to connect to the servers started above. .. literalinclude:: ../code_examples/howto_a2a.py :language: python :start-after: .. start-##_Client_Setup :end-before: .. end-##_Client_Setup +See also :ref:`A2AAgent ` for more information. + Manager Agent Setup =================== -A manager agent is created to coordinate tasks between the sample and prime agents. +While each agent has limited standalone capability, combining them unlocks powerful workflows. +Using :ref:`ManagerWorkers `, you can implement a manager agent that efficiently coordinates tasks between the sample and prime agents. +This modular, scalable architecture allows each agent to specialize, increasing system capability and flexibility. .. literalinclude:: ../code_examples/howto_a2a.py :language: python @@ -81,7 +83,7 @@ A manager agent is created to coordinate tasks between the sample and prime agen Executing Tasks with ManagerWorkers =================================== -Finally, we use the :ref:`ManagerWorkers ` to execute a conversation where the manager agent delegates tasks to the appropriate agents. +Now, execute a conversation in which the manager agent delegates tasks to the most appropriate agent. .. literalinclude:: ../code_examples/howto_a2a.py :language: python @@ -91,9 +93,12 @@ Finally, we use the :ref:`ManagerWorkers ` to execute a conversa Next steps ========== -This guide provided a complete example of implementing the A2A protocol in Wayflow. By setting up servers for specialized agents and coordinating their interactions through a manager agent, you can create powerful distributed systems where tasks are delegated efficiently. +This guide demonstrated end-to-end implementation of the A2A protocol: setting up agent servers and coordinating interactions through a manager agent to create distributed systems with effective task delegation. + +For more details: -For more and fine grained details on serving agents with A2A, refer to :doc:`A2A Serving ` and on using A2A agents, refer to :doc:`A2A Consuming `. +- On serving with A2A, see :doc:`A2A Serving ` +- On using A2A agents, see :doc:`A2A Consuming ` Full code ========= From 6d570442b4f1f3126178d3f94c6e41490b2d8cd9 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Wed, 3 Dec 2025 15:11:33 +0100 Subject: [PATCH 06/21] docs: update the title --- docs/wayflowcore/source/core/howtoguides/howto_a2a.rst | 6 +++--- docs/wayflowcore/source/core/howtoguides/index.rst | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst index e2e28aa32..27d77a392 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst @@ -1,8 +1,8 @@ .. _top-howtoa2a: -============================================= -How to use Serve and Consume Agents using A2A -============================================= +================================== +How to use A2A with ManagerWorkers +================================== .. |python-icon| image:: ../../_static/icons/python-icon.svg :width: 40px diff --git a/docs/wayflowcore/source/core/howtoguides/index.rst b/docs/wayflowcore/source/core/howtoguides/index.rst index d7ca9ee96..61a87bcd2 100644 --- a/docs/wayflowcore/source/core/howtoguides/index.rst +++ b/docs/wayflowcore/source/core/howtoguides/index.rst @@ -66,7 +66,7 @@ These how-to guides demonstrate how to use the main features to create and custo Build a Hierarchical Multi-Agent System Build a Swarm of Agents Build a ManagerWorkers of Agents - How to use Serve and Consume Agents using A2A + How to use A2A with ManagerWorkers .. toctree:: From 05047ba06e0e94ce40ec59bdbf6618868d378e64 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Wed, 3 Dec 2025 16:35:56 +0100 Subject: [PATCH 07/21] docs: clean up the headings of the sections --- docs/wayflowcore/source/core/howtoguides/howto_a2a.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst index 27d77a392..7d9478fd0 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst @@ -28,8 +28,8 @@ This step-by-step guide demonstrates how to use the `Agent-to-Agent (A2A) protoc The A2A protocol enables agents to communicate and delegate tasks seamlessly. In this example, you'll create two agents: one for checking if numbers are prime, and another for generating random numbers. A manager agent will coordinate their interactions, demonstrating the plug-and-play flexibility offered by the protocol for integrating specialized agents, regardless of their implementation details. -Server Setup for Agents -======================= +Server Setup for A2A +==================== In this section, you'll set up servers for two agents: ``prime_agent`` checks if numbers are prime, and ``sample_agent`` generates random numbers. @@ -56,8 +56,8 @@ Starting the Servers For further details, see :ref:`A2AServer `. -Client Setup for A2A Agents -=========================== +Client Setup for A2A +==================== On the client side, create ``A2AAgent`` instances to connect to the servers started above. From cafebbc476e1e95abacedabb1c2a214831990972 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Mon, 15 Dec 2025 22:20:58 +0100 Subject: [PATCH 08/21] docs: refactor a2a how to guide --- .../source/core/howtoguides/howto_a2a.rst | 114 +++++++++++++----- .../source/core/howtoguides/index.rst | 2 +- 2 files changed, 82 insertions(+), 34 deletions(-) diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst index 7d9478fd0..9245cfb84 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst @@ -1,8 +1,8 @@ .. _top-howtoa2a: -================================== -How to use A2A with ManagerWorkers -================================== +============== +How to Use A2A +============== .. |python-icon| image:: ../../_static/icons/python-icon.svg :width: 40px @@ -23,19 +23,80 @@ How to use A2A with ManagerWorkers - :doc:`LLM configuration <../howtoguides/llm_from_different_providers>` - :doc:`Using agents ` -This step-by-step guide demonstrates how to use the `Agent-to-Agent (A2A) protocol `_ in Wayflow for both serving and consuming agents. +`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 step-by-step guide demonstrates how to use the protocol in WayFlow in different ways, focusing on consuming hosted agents. +For serving using A2A, refer :doc:`A2A Serving `. -The A2A protocol enables agents to communicate and delegate tasks seamlessly. In this example, you'll create two agents: one for checking if numbers are prime, and another for generating random numbers. -A manager agent will coordinate their interactions, demonstrating the plug-and-play flexibility offered by the protocol for integrating specialized agents, regardless of their implementation details. +A2A Agents +========== -Server Setup for A2A -==================== +In this section, you will learn how to connect to a remote agent using this protocol with the :ref:`A2AAgent `. -In this section, you'll set up servers for two agents: ``prime_agent`` checks if numbers are prime, and ``sample_agent`` generates random numbers. +Basic Usage +----------- + +To get started with an A2A agent, you need the URL of the remote server agent you wish to connect to. Once you have this information, creating your A2A agent is straightforward and can be done in just a few lines of code: + +.. literalinclude:: ../code_examples/howto_a2aagent.py + :language: python + :start-after: .. start-##_Creating_the_agent + :end-before: .. end-##_Creating_the_agent + +Then, use the agent as shown below: + +.. literalinclude:: ../code_examples/howto_a2aagent.py + :language: python + :start-after: .. start-##_Running_the_agent + :end-before: .. end-##_Running_the_agent + +Agent Spec Exporting/Loading +---------------------------- + +You can export the assistant configuration to its Agent Spec configuration using the ``AgentSpecExporter``. + +.. literalinclude:: ../code_examples/howto_a2aagent.py + :language: python + :start-after: .. start-##_Export_config_to_Agent_Spec + :end-before: .. end-##_Export_config_to_Agent_Spec + +Here is what the **Agent Spec representation will look like ↓** + +.. collapse:: Click here to see the assistant configuration. + + .. tabs:: + + .. tab:: JSON + + .. literalinclude:: ../config_examples/howto_a2aagent.json + :language: json + + .. tab:: YAML + + .. literalinclude:: ../config_examples/howto_a2aagent.yaml + :language: yaml + +You can then load the configuration back to an assistant using the ``AgentSpecLoader``. + +.. literalinclude:: ../code_examples/howto_a2aagent.py + :language: python + :start-after: .. start-##_Load_Agent_Spec_config + :end-before: .. end-##_Load_Agent_Spec_config + +Manager Workers with A2A Agents +=============================== + +While each agent has limited standalone capability, combining them unlocks powerful workflows. +Using :ref:`ManagerWorkers `, you can implement a manager agent that efficiently coordinates tasks between different specialized agents. +This modular, scalable architecture allows each agent to focus on specific tasks, increasing overall system capability and flexibility. + +In this example, you'll create two agents: one for checking if numbers are prime, and another for generating random numbers. +A manager agent will coordinate their interactions, demonstrating the plug-and-play flexibility offered by the protocol for integrating specialized agents, regardless of their implementation details. Setting up the Agents --------------------- +In this section, you'll set up servers for two agents: ``prime_agent`` checks if numbers are prime, and ``sample_agent`` generates random numbers. + .. literalinclude:: ../code_examples/howto_a2a.py :language: python :start-after: .. start-##_Server_Setup_Prime_Agent @@ -46,9 +107,6 @@ Setting up the Agents :start-after: .. start-##_Server_Setup_Sample_Agent :end-before: .. end-##_Server_Setup_Sample_Agent -Starting the Servers --------------------- - .. literalinclude:: ../code_examples/howto_a2a.py :language: python :start-after: .. start-##_Server_Startup_Logic @@ -56,9 +114,6 @@ Starting the Servers For further details, see :ref:`A2AServer `. -Client Setup for A2A -==================== - On the client side, create ``A2AAgent`` instances to connect to the servers started above. .. literalinclude:: ../code_examples/howto_a2a.py @@ -66,41 +121,34 @@ On the client side, create ``A2AAgent`` instances to connect to the servers star :start-after: .. start-##_Client_Setup :end-before: .. end-##_Client_Setup -See also :ref:`A2AAgent ` for more information. - -Manager Agent Setup -=================== - -While each agent has limited standalone capability, combining them unlocks powerful workflows. -Using :ref:`ManagerWorkers `, you can implement a manager agent that efficiently coordinates tasks between the sample and prime agents. -This modular, scalable architecture allows each agent to specialize, increasing system capability and flexibility. +Now you can use these agents in :ref:`ManagerWorkers ` setup. .. literalinclude:: ../code_examples/howto_a2a.py :language: python :start-after: .. start-##_Manager_Setup :end-before: .. end-##_Manager_Setup -Executing Tasks with ManagerWorkers -=================================== +Executing Tasks +--------------- -Now, execute a conversation in which the manager agent delegates tasks to the most appropriate agent. +Now, execute a conversation in which the manager agent delegates tasks to the most appropriate agent based on their capabilities. +This demonstrates how ManagerWorkers can be used to orchestrate complex interactions seamlessly. .. literalinclude:: ../code_examples/howto_a2a.py :language: python :start-after: .. start-##_ManagerWorkers_Execution :end-before: .. end-##_ManagerWorkers_Execution -Next steps -========== +A2A Agents in Flow +================== -This guide demonstrated end-to-end implementation of the A2A protocol: setting up agent servers and coordinating interactions through a manager agent to create distributed systems with effective task delegation. -For more details: +Next Steps +========== -- On serving with A2A, see :doc:`A2A Serving ` -- On using A2A agents, see :doc:`A2A Consuming ` +This guide covered the basics of using A2A agents and coordinating interactions through manager workers in WayFlow. -Full code +Full Code ========= Click on the card at the :ref:`top of this page ` to download the full code for this guide or copy the code below. diff --git a/docs/wayflowcore/source/core/howtoguides/index.rst b/docs/wayflowcore/source/core/howtoguides/index.rst index 61a87bcd2..230ef76f8 100644 --- a/docs/wayflowcore/source/core/howtoguides/index.rst +++ b/docs/wayflowcore/source/core/howtoguides/index.rst @@ -66,7 +66,7 @@ These how-to guides demonstrate how to use the main features to create and custo Build a Hierarchical Multi-Agent System Build a Swarm of Agents Build a ManagerWorkers of Agents - How to use A2A with ManagerWorkers + How to Use A2A .. toctree:: From b87b9bfc8b094e620bd3f88070fc2929b796bafb Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Mon, 15 Dec 2025 22:25:39 +0100 Subject: [PATCH 09/21] refactor: make A2AAgent work in agent execution step --- wayflowcore/src/wayflowcore/steps/agentexecutionstep.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wayflowcore/src/wayflowcore/steps/agentexecutionstep.py b/wayflowcore/src/wayflowcore/steps/agentexecutionstep.py index 893877282..0ad108817 100644 --- a/wayflowcore/src/wayflowcore/steps/agentexecutionstep.py +++ b/wayflowcore/src/wayflowcore/steps/agentexecutionstep.py @@ -8,6 +8,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union from wayflowcore._metadata import MetadataType +from wayflowcore.a2a.a2aagent import A2AAgent from wayflowcore.agent import Agent, CallerInputMode from wayflowcore.conversationalcomponent import _mutate from wayflowcore.executors.executionstatus import ( @@ -271,7 +272,7 @@ def might_yield(self) -> bool: self.agent.caller_input_mode == CallerInputMode.ALWAYS or self.caller_input_mode == CallerInputMode.ALWAYS ) - elif isinstance(self.agent, OciAgent): + elif isinstance(self.agent, (OciAgent, A2AAgent)): return True else: raise NotImplementedError(f"{self.agent} not supported in the agent execution step.") From 9f41c15860221b2c1033db13135a17b6e8e7c81f Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Tue, 6 Jan 2026 14:14:25 +0100 Subject: [PATCH 10/21] docs: clean up A2A Agent how to guide --- .../source/core/howtoguides/howto_a2a.rst | 6 +- .../core/howtoguides/howto_a2a_serving.rst | 2 +- .../core/howtoguides/howto_a2aagent.rst | 101 ------------------ .../source/core/howtoguides/index.rst | 1 - 4 files changed, 2 insertions(+), 108 deletions(-) delete mode 100644 docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst index 9245cfb84..b2a9d3054 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst @@ -89,7 +89,7 @@ While each agent has limited standalone capability, combining them unlocks power Using :ref:`ManagerWorkers `, you can implement a manager agent that efficiently coordinates tasks between different specialized agents. This modular, scalable architecture allows each agent to focus on specific tasks, increasing overall system capability and flexibility. -In this example, you'll create two agents: one for checking if numbers are prime, and another for generating random numbers. +In this example, you'll create two A2A agents: one for checking if numbers are prime, and another for generating random numbers. A manager agent will coordinate their interactions, demonstrating the plug-and-play flexibility offered by the protocol for integrating specialized agents, regardless of their implementation details. Setting up the Agents @@ -139,10 +139,6 @@ This demonstrates how ManagerWorkers can be used to orchestrate complex interact :start-after: .. start-##_ManagerWorkers_Execution :end-before: .. end-##_ManagerWorkers_Execution -A2A Agents in Flow -================== - - Next Steps ========== diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a_serving.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2a_serving.rst index 45e95edc2..346ab4425 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2a_serving.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2a_serving.rst @@ -129,7 +129,7 @@ Below is example Flow that is valid for serving, along with how it can be served Next steps ========== -Now that you have learned how to serve WayFlow assistants using A2A protocol, you may proceed to :doc:`How to Build A2A Agents ` to learn how consume an A2A-served agent. +Now that you have learned how to serve WayFlow assistants using A2A protocol, you may proceed to :doc:`How to Use A2A ` to learn how consume an A2A-served agent. Full code ========= diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst deleted file mode 100644 index 066fbf340..000000000 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst +++ /dev/null @@ -1,101 +0,0 @@ -.. _top-howtoa2aagent: - -============================ -How to Connect to A2A Agents -============================ - -.. |python-icon| image:: ../../_static/icons/python-icon.svg - :width: 40px - :height: 40px - -.. grid:: 2 - - .. grid-item-card:: |python-icon| Download Python Script - :link: ../end_to_end_code_examples/howto_a2aagent.py - :link-alt: A2A Agent how-to script - - Python script/notebook for this guide. - -.. admonition:: Prerequisites - - This guide assumes familiarity with: - - - :doc:`LLM configuration <../howtoguides/llm_from_different_providers>` - - :doc:`Using agents ` - - -`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. - -In this guide, you will learn how to connect to a remote agent using this protocol with the :ref:`A2AAgent ` -class from the ``wayflowcore`` package. - - -Basic usage -=========== - -To get started with an A2A agent, you need the URL of the remote server agent you wish to connect to. -Once you have this information, creating your A2A agent is straightforward and can be done in just a few lines of code: - -.. literalinclude:: ../code_examples/howto_a2aagent.py - :language: python - :start-after: .. start-##_Creating_the_agent - :end-before: .. end-##_Creating_the_agent - -Then, use the agent as shown below: - -.. literalinclude:: ../code_examples/howto_a2aagent.py - :language: python - :start-after: .. start-##_Running_the_agent - :end-before: .. end-##_Running_the_agent - -Agent Spec Exporting/Loading -============================ - -You can export the assistant configuration to its Agent Spec configuration using the ``AgentSpecExporter``. - -.. literalinclude:: ../code_examples/howto_a2aagent.py - :language: python - :start-after: .. start-##_Export_config_to_Agent_Spec - :end-before: .. end-##_Export_config_to_Agent_Spec - - -Here is what the **Agent Spec representation will look like ↓** - -.. collapse:: Click here to see the assistant configuration. - - .. tabs:: - - .. tab:: JSON - - .. literalinclude:: ../config_examples/howto_a2aagent.json - :language: json - - .. tab:: YAML - - .. literalinclude:: ../config_examples/howto_a2aagent.yaml - :language: yaml - -You can then load the configuration back to an assistant using the ``AgentSpecLoader``. - - -.. literalinclude:: ../code_examples/howto_a2aagent.py - :language: python - :start-after: .. start-##_Load_Agent_Spec_config - :end-before: .. end-##_Load_Agent_Spec_config - - -Next steps -========== - -Now that you have learned how to use A2A Agents in WayFlow, you may proceed to :doc:`How to Use Agents in Flows `. - - -Full code -========= - -Click on the card at the :ref:`top of this page ` to download the full code for this guide or copy the code below. - -.. literalinclude:: ../end_to_end_code_examples/howto_a2aagent.py - :language: python - :linenos: diff --git a/docs/wayflowcore/source/core/howtoguides/index.rst b/docs/wayflowcore/source/core/howtoguides/index.rst index 230ef76f8..d91e38cc3 100644 --- a/docs/wayflowcore/source/core/howtoguides/index.rst +++ b/docs/wayflowcore/source/core/howtoguides/index.rst @@ -42,7 +42,6 @@ These how-to guides demonstrate how to use the main features to create and custo Create a ReAct Agent How to Send Images to LLMs and Agents Use OCI Generative AI Agents - How to Connect to A2A Agents Use Templates for Advanced Prompting Techniques .. toctree:: From 121837269d27b95f0ddcc7b4029ecf899f17cc8f Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Wed, 14 Jan 2026 15:50:37 +0100 Subject: [PATCH 11/21] docs: clean up the tutorial --- .../source/core/code_examples/howto_a2a.py | 147 ------------ .../core/code_examples/howto_a2aagent.py | 158 ++++++++++++- ...to_a2aagent.json => howto_a2aagent_1.json} | 8 +- .../config_examples/howto_a2aagent_1.yaml | 26 +++ .../config_examples/howto_a2aagent_2.json | 213 ++++++++++++++++++ .../config_examples/howto_a2aagent_2.yaml | 183 +++++++++++++++ .../core/howtoguides/howto_a2a_serving.rst | 2 +- .../{howto_a2a.rst => howto_a2aagent.rst} | 67 ++++-- .../source/core/howtoguides/index.rst | 3 +- 9 files changed, 631 insertions(+), 176 deletions(-) delete mode 100644 docs/wayflowcore/source/core/code_examples/howto_a2a.py rename docs/wayflowcore/source/core/config_examples/{howto_a2aagent.json => howto_a2aagent_1.json} (77%) create mode 100644 docs/wayflowcore/source/core/config_examples/howto_a2aagent_1.yaml create mode 100644 docs/wayflowcore/source/core/config_examples/howto_a2aagent_2.json create mode 100644 docs/wayflowcore/source/core/config_examples/howto_a2aagent_2.yaml rename docs/wayflowcore/source/core/howtoguides/{howto_a2a.rst => howto_a2aagent.rst} (71%) diff --git a/docs/wayflowcore/source/core/code_examples/howto_a2a.py b/docs/wayflowcore/source/core/code_examples/howto_a2a.py deleted file mode 100644 index 973b9a44e..000000000 --- a/docs/wayflowcore/source/core/code_examples/howto_a2a.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright © 2025 Oracle and/or its affiliates. -# -# This software is under the Apache License 2.0 -# (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License -# (UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option. - -# isort:skip_file -# fmt: off -# mypy: ignore-errors -# docs-title: How to use Serve and Consume Agents using A2A - -# Server part -from typing import Annotated - -from wayflowcore.a2a.server import A2AServer -from wayflowcore.agent import Agent -from wayflowcore.models import VllmModel -from wayflowcore.tools import tool - -# .. start-##_llm -llm = VllmModel( - model_id="LLAMA_MODEL_ID", - host_port="LLAMA_API_URL", -) -# .. end-##_llm - -(llm,) = _update_globals(["vision_llm"]) # docs-skiprow # type: ignore - - -# .. start-##_Server_Setup_Prime_Agent -def get_prime_agent(): - @tool - def check_prime(a: Annotated[int, "first required integer"]) -> bool: - "Check if the first number (a) is a prime number." - if a < 2: - return False - for i in range(2, int(a**0.5) + 1): - if a % i == 0: - return False - return True - - agent = Agent( - llm=llm, - name="prime_agent", - custom_instruction="You are a math agent that can check whether a number is prime or not using the equipped tool.", - tools=[check_prime], - can_finish_conversation=True, - ) - return agent -# .. end-##_Server_Setup_Prime_Agent - - -# .. start-##_Server_Setup_Sample_Agent -def get_sample_agent(): - @tool - def sample_number(a: Annotated[int, "first required integer"]) -> int: - "Simulate sampling from a range, return a random number between 1 and the specified value." - import random - - result = random.randint(1, a) - return result - - agent = Agent( - llm=llm, - name="sample_agent", - custom_instruction="You are an agent that can generate a random number between 1 and a specified value.", - tools=[sample_number], - can_finish_conversation=True, - ) - return agent -# .. end-##_Server_Setup_Sample_Agent - -# .. start-##_Server_Startup_Logic -# Start both sample and prime servers -sample_agent = get_sample_agent() -sample_server = A2AServer() -sample_server.serve_agent(sample_agent, "http://") -# Note: Uncomment the line below to start the server -# sample_server.serve() - -prime_agent = get_prime_agent() -prime_server = A2AServer() -prime_server.serve_agent(prime_agent, "http://") -# Note: Uncomment the line below to start the server -# prime_server.serve(port=8001) -# .. end-##_Server_Startup_Logic - -(sample_server,) = _update_globals(["sample_a2a_server"]) # docs-skiprow # type: ignore -(prime_server,) = _update_globals(["prime_a2a_server"]) # docs-skiprow # type: ignore - -from wayflowcore.a2a.a2aagent import A2AAgent, A2AConnectionConfig - -# Client part -from wayflowcore.agent import Agent -from wayflowcore.models import VllmModel - -# .. start-##_Client_Setup -sample_agent = A2AAgent( - name="sample_agent", - agent_url="http://", - description="Agent that can generate random numbers", - connection_config=A2AConnectionConfig(verify=False), -) -prime_agent = A2AAgent( - name="prime_agent", - agent_url="http://", - description="Agent that handles checking if numbers are prime.", - connection_config=A2AConnectionConfig(verify=False), -) -# .. end-##_Client_Setup - -(sample_agent, prime_agent) = _update_globals( - ["sample_a2a_agent", "prime_a2a_agent"] -) # docs-skiprow # type: ignore - -# .. start-##_Manager_Setup -MANAGER_SYSTEM_PROMPT = """ -You are a helpful assistant that can sample numbers and check if the sampled numbers are prime. -You delegate sampling tasks to the `sample_agent` and prime checking tasks to the `prime_agent`. -Follow these steps: -1. If the user asks to sample a number, delegate to the `sample_agent`. -2. If the user asks to check primes, delegate to the `prime_agent`. -3. If the user asks to sample a number and then check if the result is prime, call `sample_agent` first, then pass the result to `prime_agent`. -Always clarify the results before proceeding. -""".strip() - -manager = Agent( - name="PrimeChecker", - description="You are a PrimeChecker who can sample integers and check if they are prime.", - llm=llm, - custom_instruction=MANAGER_SYSTEM_PROMPT, -) -# .. end-##_Manager_Setup - -# .. start-##_ManagerWorkers_Execution -from wayflowcore.managerworkers import ManagerWorkers - -group = ManagerWorkers( - group_manager=manager, - workers=[sample_agent, prime_agent], -) - -main_conversation = group.start_conversation() -main_conversation.append_user_message("Sample a number from 1 to 20 and check if it's prime") -main_conversation.execute() -print(main_conversation.get_messages()) -# .. end-##_ManagerWorkers_Execution diff --git a/docs/wayflowcore/source/core/code_examples/howto_a2aagent.py b/docs/wayflowcore/source/core/code_examples/howto_a2aagent.py index 21d9f54b4..98eecb170 100644 --- a/docs/wayflowcore/source/core/code_examples/howto_a2aagent.py +++ b/docs/wayflowcore/source/core/code_examples/howto_a2aagent.py @@ -7,7 +7,9 @@ # isort:skip_file # fmt: off # mypy: ignore-errors -# docs-title: Code Example - How to Use A2A Agents +# docs-title: How to Use A2A Agents + +### Basic Usage # .. start-##_Creating_the_agent from wayflowcore.a2a.a2aagent import A2AAgent, A2AConnectionConfig @@ -35,13 +37,159 @@ print(f"Invalid execution status, expected UserMessageRequestStatus, received {type(status)}") # .. end-##_Running_the_agent -# .. start-##_Export_config_to_Agent_Spec +# .. start-##_Export_config_to_Agent_Spec1 from wayflowcore.agentspec import AgentSpecExporter serialized_assistant = AgentSpecExporter().to_json(agent) -# .. end-##_Export_config_to_Agent_Spec -# .. start-##_Load_Agent_Spec_config +# .. end-##_Export_config_to_Agent_Spec1 +# .. start-##_Load_Agent_Spec_config1 +from wayflowcore.agentspec import AgentSpecLoader + +agent: A2AAgent = AgentSpecLoader().load_json(serialized_assistant) +# .. end-##_Load_Agent_Spec_config1 + +### Manager Workers Usage + +# Server part +import random +from typing import Annotated + +from wayflowcore.agentserver.server import A2AServer +from wayflowcore.agent import Agent +from wayflowcore.models import VllmModel +from wayflowcore.tools import tool + +# .. start-##_llm +llm = VllmModel( + model_id="LLAMA_MODEL_ID", + host_port="LLAMA_API_URL", +) +# .. end-##_llm + +(llm,) = _update_globals(["vision_llm"]) # docs-skiprow # type: ignore + + +# .. start-##_Server_Setup_Prime_Agent +def get_prime_agent(): + @tool + def check_prime(a: Annotated[int, "first required integer"]) -> bool: + "Check if the first number (a) is a prime number." + if a < 2: + return False + for i in range(2, int(a**0.5) + 1): + if a % i == 0: + return False + return True + agent = Agent( + llm=llm, + name="prime_agent", + custom_instruction="You are a math agent that can check whether a number is prime or not using the equipped tool.", + tools=[check_prime], + can_finish_conversation=True, + ) + return agent +# .. end-##_Server_Setup_Prime_Agent + + +# .. start-##_Server_Setup_Sample_Agent +def get_sample_agent(): + @tool + def sample_number(a: Annotated[int, "first required integer"]) -> int: + "Simulate sampling from a range, return a random number between 1 and the specified value." + result = random.randint(1, a) # nosec + return result + agent = Agent( + llm=llm, + name="sample_agent", + custom_instruction="You are an agent that can generate a random number between 1 and a specified value.", + tools=[sample_number], + can_finish_conversation=True, + ) + return agent +# .. end-##_Server_Setup_Sample_Agent + +# .. start-##_Server_Startup_Logic +# Start both sample and prime servers +sample_agent = get_sample_agent() +sample_server = A2AServer() +sample_server.serve_agent(sample_agent, "http://") +# Note: Uncomment the line below to start the server +# sample_server.serve() + +prime_agent = get_prime_agent() +prime_server = A2AServer() +prime_server.serve_agent(prime_agent, "http://") +# Note: Uncomment the line below to start the server +# prime_server.serve(port=8001) +# .. end-##_Server_Startup_Logic + +(sample_server,) = _update_globals(["sample_a2a_server"]) # docs-skiprow # type: ignore +(prime_server,) = _update_globals(["prime_a2a_server"]) # docs-skiprow # type: ignore + +# Client part +from wayflowcore.a2a.a2aagent import A2AAgent, A2AConnectionConfig +from wayflowcore.agent import Agent +from wayflowcore.models import VllmModel + +# .. start-##_Client_Setup +sample_agent = A2AAgent( + name="sample_agent", + agent_url="http://", + description="Agent that can generate random numbers", + connection_config=A2AConnectionConfig(verify=False), +) +prime_agent = A2AAgent( + name="prime_agent", + agent_url="http://", + description="Agent that handles checking if numbers are prime.", + connection_config=A2AConnectionConfig(verify=False), +) +# .. end-##_Client_Setup + +(sample_agent, prime_agent) = _update_globals( + ["sample_a2a_agent", "prime_a2a_agent"] +) # docs-skiprow # type: ignore + +# .. start-##_Manager_Setup +MANAGER_SYSTEM_PROMPT = """ +You are a helpful assistant that can sample numbers and check if the sampled numbers are prime. +You delegate sampling tasks to the `sample_agent` and prime checking tasks to the `prime_agent`. +Follow these steps: +1. If the user asks to sample a number, delegate to the `sample_agent`. +2. If the user asks to check primes, delegate to the `prime_agent`. +3. If the user asks to sample a number and then check if the result is prime, call `sample_agent` first, then pass the result to `prime_agent`. +Always clarify the results before proceeding. +""".strip() + +manager = Agent( + name="PrimeChecker", + description="You are a PrimeChecker who can sample integers and check if they are prime.", + llm=llm, + custom_instruction=MANAGER_SYSTEM_PROMPT, +) +# .. end-##_Manager_Setup + +# .. start-##_ManagerWorkers_Execution +from wayflowcore.managerworkers import ManagerWorkers + +group = ManagerWorkers( + group_manager=manager, + workers=[sample_agent, prime_agent], +) + +main_conversation = group.start_conversation() +main_conversation.append_user_message("Sample a number from 1 to 20 and check if it's prime") +main_conversation.execute() +print(main_conversation.get_messages()) +# .. end-##_ManagerWorkers_Execution + +# .. start-##_Export_config_to_Agent_Spec2 +from wayflowcore.agentspec import AgentSpecExporter + +serialized_assistant = AgentSpecExporter().to_json(group) +# .. end-##_Export_config_to_Agent_Spec2 +# .. start-##_Load_Agent_Spec_config2 from wayflowcore.agentspec import AgentSpecLoader agent: A2AAgent = AgentSpecLoader().load_json(serialized_assistant) -# .. end-##_Load_Agent_Spec_config +# .. end-##_Load_Agent_Spec_config2 diff --git a/docs/wayflowcore/source/core/config_examples/howto_a2aagent.json b/docs/wayflowcore/source/core/config_examples/howto_a2aagent_1.json similarity index 77% rename from docs/wayflowcore/source/core/config_examples/howto_a2aagent.json rename to docs/wayflowcore/source/core/config_examples/howto_a2aagent_1.json index 41c11f5c5..d96ebc927 100644 --- a/docs/wayflowcore/source/core/config_examples/howto_a2aagent.json +++ b/docs/wayflowcore/source/core/config_examples/howto_a2aagent_1.json @@ -1,7 +1,7 @@ { "component_type": "A2AAgent", - "id": "5ba508ef-7cae-417a-9197-8f2aeee870b6", - "name": "a2a_agent_4311ebd5__auto", + "id": "47b982ac-dbbe-4674-8c97-f6d82a21554c", + "name": "a2a_agent_a5ea926f__auto", "description": "", "metadata": { "__metadata_info__": {} @@ -11,8 +11,8 @@ "agent_url": "http://", "connection_config": { "component_type": "A2AConnectionConfig", - "id": "c01ebe14-f467-4c01-a25b-0f3f22bfa550", - "name": "connection_config", + "id": "1912133f-0bc6-4846-a140-2a5bfb5f9c42", + "name": "", "description": null, "metadata": {}, "timeout": 600.0, diff --git a/docs/wayflowcore/source/core/config_examples/howto_a2aagent_1.yaml b/docs/wayflowcore/source/core/config_examples/howto_a2aagent_1.yaml new file mode 100644 index 000000000..9181af24a --- /dev/null +++ b/docs/wayflowcore/source/core/config_examples/howto_a2aagent_1.yaml @@ -0,0 +1,26 @@ +component_type: A2AAgent +id: 47b982ac-dbbe-4674-8c97-f6d82a21554c +name: a2a_agent_a5ea926f__auto +description: '' +metadata: + __metadata_info__: {} +inputs: [] +outputs: [] +agent_url: http:// +connection_config: + component_type: A2AConnectionConfig + id: 1912133f-0bc6-4846-a140-2a5bfb5f9c42 + name: '' + description: null + metadata: {} + timeout: 600.0 + headers: null + verify: false + key_file: null + cert_file: null + ssl_ca_cert: null +session_parameters: + timeout: 60.0 + poll_interval: 2.0 + max_retries: 5 +agentspec_version: 25.4.2 diff --git a/docs/wayflowcore/source/core/config_examples/howto_a2aagent_2.json b/docs/wayflowcore/source/core/config_examples/howto_a2aagent_2.json new file mode 100644 index 000000000..30b61391e --- /dev/null +++ b/docs/wayflowcore/source/core/config_examples/howto_a2aagent_2.json @@ -0,0 +1,213 @@ +{ + "component_type": "ManagerWorkers", + "id": "21f138e2-c8c7-4373-af60-508cf0c1fd2e", + "name": "managerworkers_44603868__auto", + "description": "", + "metadata": { + "__metadata_info__": {} + }, + "inputs": [], + "outputs": [], + "group_manager": { + "component_type": "ExtendedAgent", + "id": "02709a13-1916-4720-89e1-56b0c0ea6922", + "name": "PrimeChecker", + "description": "You are a PrimeChecker who can sample integers and check if they are prime.", + "metadata": { + "__metadata_info__": {} + }, + "inputs": [], + "outputs": [], + "llm_config": { + "component_type": "VllmConfig", + "id": "91a8480a-3d6b-4160-b4a1-e1cd57b7c9a4", + "name": "llm_647ebd5e__auto", + "description": null, + "metadata": { + "__metadata_info__": {} + }, + "default_generation_parameters": null, + "url": "LLAMA_API_URL", + "model_id": "LLAMA_MODEL_ID", + "api_type": "chat_completions", + "api_key": null + }, + "system_prompt": "You are a helpful assistant that can sample numbers and check if the sampled numbers are prime.\nYou delegate sampling tasks to the `sample_agent` and prime checking tasks to the `prime_agent`.\nFollow these steps:\n1. If the user asks to sample a number, delegate to the `sample_agent`.\n2. If the user asks to check primes, delegate to the `prime_agent`.\n3. If the user asks to sample a number and then check if the result is prime, call `sample_agent` first, then pass the result to `prime_agent`.\nAlways clarify the results before proceeding.", + "tools": [], + "toolboxes": [], + "human_in_the_loop": true, + "context_providers": null, + "can_finish_conversation": false, + "raise_exceptions": false, + "max_iterations": 10, + "initial_message": "Hi! How can I help you?", + "caller_input_mode": "always", + "agents": [], + "flows": [], + "agent_template": { + "component_type": "PluginPromptTemplate", + "id": "23e82423-7df6-461e-a45b-31a6633348fe", + "name": "", + "description": null, + "metadata": { + "__metadata_info__": {} + }, + "messages": [ + { + "role": "system", + "contents": [ + { + "type": "text", + "content": "{% if custom_instruction %}{{custom_instruction}}{% endif %}" + } + ], + "tool_requests": null, + "tool_result": null, + "display_only": false, + "sender": null, + "recipients": [], + "time_created": "2026-01-14T14:27:15.835239+00:00", + "time_updated": "2026-01-14T14:27:15.835239+00:00" + }, + { + "role": "system", + "contents": [ + { + "type": "text", + "content": "$$__CHAT_HISTORY_PLACEHOLDER__$$" + } + ], + "tool_requests": null, + "tool_result": null, + "display_only": false, + "sender": null, + "recipients": [], + "time_created": "2026-01-14T14:27:15.831100+00:00", + "time_updated": "2026-01-14T14:27:15.831101+00:00" + }, + { + "role": "system", + "contents": [ + { + "type": "text", + "content": "{% if __PLAN__ %}The current plan you should follow is the following: \n{{__PLAN__}}{% endif %}" + } + ], + "tool_requests": null, + "tool_result": null, + "display_only": false, + "sender": null, + "recipients": [], + "time_created": "2026-01-14T14:27:15.835267+00:00", + "time_updated": "2026-01-14T14:27:15.835267+00:00" + } + ], + "output_parser": null, + "inputs": [ + { + "description": "\"custom_instruction\" input variable for the template", + "type": "string", + "title": "custom_instruction", + "default": "" + }, + { + "description": "\"__PLAN__\" input variable for the template", + "type": "string", + "title": "__PLAN__", + "default": "" + }, + { + "type": "array", + "items": {}, + "title": "__CHAT_HISTORY__" + } + ], + "pre_rendering_transforms": null, + "post_rendering_transforms": [ + { + "component_type": "PluginRemoveEmptyNonUserMessageTransform", + "id": "ffeb49dd-9a2e-485b-9ee3-c764e6340098", + "name": "removeemptynonusermessage_messagetransform", + "description": null, + "metadata": { + "__metadata_info__": {} + }, + "component_plugin_name": "MessageTransformPlugin", + "component_plugin_version": "26.1.0.dev5" + } + ], + "tools": null, + "native_tool_calling": true, + "response_format": null, + "native_structured_generation": true, + "generation_config": null, + "component_plugin_name": "PromptTemplatePlugin", + "component_plugin_version": "26.1.0.dev5" + }, + "component_plugin_name": "AgentPlugin", + "component_plugin_version": "26.1.0.dev5" + }, + "workers": [ + { + "component_type": "A2AAgent", + "id": "b554446e-9c21-4aaf-b393-1e91cc9aeab8", + "name": "sample_agent", + "description": "Agent that can generate random numbers", + "metadata": { + "__metadata_info__": {} + }, + "inputs": [], + "outputs": [], + "agent_url": "http://", + "connection_config": { + "component_type": "A2AConnectionConfig", + "id": "061d0a87-cfec-49e4-a427-fec4b4326724", + "name": "", + "description": null, + "metadata": {}, + "timeout": 600.0, + "headers": null, + "verify": false, + "key_file": null, + "cert_file": null, + "ssl_ca_cert": null + }, + "session_parameters": { + "timeout": 60.0, + "poll_interval": 2.0, + "max_retries": 5 + } + }, + { + "component_type": "A2AAgent", + "id": "d6e6a95b-c144-469b-91ad-972121406b83", + "name": "prime_agent", + "description": "Agent that handles checking if numbers are prime.", + "metadata": { + "__metadata_info__": {} + }, + "inputs": [], + "outputs": [], + "agent_url": "http://", + "connection_config": { + "component_type": "A2AConnectionConfig", + "id": "54c3ebde-5101-4c4c-9718-bced0142754c", + "name": "", + "description": null, + "metadata": {}, + "timeout": 600.0, + "headers": null, + "verify": false, + "key_file": null, + "cert_file": null, + "ssl_ca_cert": null + }, + "session_parameters": { + "timeout": 60.0, + "poll_interval": 2.0, + "max_retries": 5 + } + } + ], + "agentspec_version": "25.4.2" +} diff --git a/docs/wayflowcore/source/core/config_examples/howto_a2aagent_2.yaml b/docs/wayflowcore/source/core/config_examples/howto_a2aagent_2.yaml new file mode 100644 index 000000000..122ac4d01 --- /dev/null +++ b/docs/wayflowcore/source/core/config_examples/howto_a2aagent_2.yaml @@ -0,0 +1,183 @@ +component_type: ManagerWorkers +id: 21f138e2-c8c7-4373-af60-508cf0c1fd2e +name: managerworkers_44603868__auto +description: '' +metadata: + __metadata_info__: {} +inputs: [] +outputs: [] +group_manager: + component_type: ExtendedAgent + id: 02709a13-1916-4720-89e1-56b0c0ea6922 + name: PrimeChecker + description: You are a PrimeChecker who can sample integers and check if they are + prime. + metadata: + __metadata_info__: {} + inputs: [] + outputs: [] + llm_config: + component_type: VllmConfig + id: 91a8480a-3d6b-4160-b4a1-e1cd57b7c9a4 + name: llm_647ebd5e__auto + description: null + metadata: + __metadata_info__: {} + default_generation_parameters: null + url: LLAMA_API_URL + model_id: LLAMA_MODEL_ID + api_type: chat_completions + api_key: null + system_prompt: 'You are a helpful assistant that can sample numbers and check if + the sampled numbers are prime. + + You delegate sampling tasks to the `sample_agent` and prime checking tasks to + the `prime_agent`. + + Follow these steps: + + 1. If the user asks to sample a number, delegate to the `sample_agent`. + + 2. If the user asks to check primes, delegate to the `prime_agent`. + + 3. If the user asks to sample a number and then check if the result is prime, + call `sample_agent` first, then pass the result to `prime_agent`. + + Always clarify the results before proceeding.' + tools: [] + toolboxes: [] + human_in_the_loop: true + context_providers: null + can_finish_conversation: false + raise_exceptions: false + max_iterations: 10 + initial_message: Hi! How can I help you? + caller_input_mode: always + agents: [] + flows: [] + agent_template: + component_type: PluginPromptTemplate + id: 23e82423-7df6-461e-a45b-31a6633348fe + name: '' + description: null + metadata: + __metadata_info__: {} + messages: + - role: system + contents: + - type: text + content: '{% if custom_instruction %}{{custom_instruction}}{% endif %}' + tool_requests: null + tool_result: null + display_only: false + sender: null + recipients: [] + time_created: '2026-01-14T14:27:15.835239+00:00' + time_updated: '2026-01-14T14:27:15.835239+00:00' + - role: system + contents: + - type: text + content: $$__CHAT_HISTORY_PLACEHOLDER__$$ + tool_requests: null + tool_result: null + display_only: false + sender: null + recipients: [] + time_created: '2026-01-14T14:27:15.831100+00:00' + time_updated: '2026-01-14T14:27:15.831101+00:00' + - role: system + contents: + - type: text + content: "{% if __PLAN__ %}The current plan you should follow is the following:\ + \ \n{{__PLAN__}}{% endif %}" + tool_requests: null + tool_result: null + display_only: false + sender: null + recipients: [] + time_created: '2026-01-14T14:27:15.835267+00:00' + time_updated: '2026-01-14T14:27:15.835267+00:00' + output_parser: null + inputs: + - description: '"custom_instruction" input variable for the template' + type: string + title: custom_instruction + default: '' + - description: '"__PLAN__" input variable for the template' + type: string + title: __PLAN__ + default: '' + - type: array + items: {} + title: __CHAT_HISTORY__ + pre_rendering_transforms: null + post_rendering_transforms: + - component_type: PluginRemoveEmptyNonUserMessageTransform + id: 34f49abb-027f-4df6-96ab-a90763aeabbc + name: removeemptynonusermessage_messagetransform + description: null + metadata: + __metadata_info__: {} + component_plugin_name: MessageTransformPlugin + component_plugin_version: 26.1.0.dev5 + tools: null + native_tool_calling: true + response_format: null + native_structured_generation: true + generation_config: null + component_plugin_name: PromptTemplatePlugin + component_plugin_version: 26.1.0.dev5 + component_plugin_name: AgentPlugin + component_plugin_version: 26.1.0.dev5 +workers: +- component_type: A2AAgent + id: b554446e-9c21-4aaf-b393-1e91cc9aeab8 + name: sample_agent + description: Agent that can generate random numbers + metadata: + __metadata_info__: {} + inputs: [] + outputs: [] + agent_url: http:// + connection_config: + component_type: A2AConnectionConfig + id: 061d0a87-cfec-49e4-a427-fec4b4326724 + name: '' + description: null + metadata: {} + timeout: 600.0 + headers: null + verify: false + key_file: null + cert_file: null + ssl_ca_cert: null + session_parameters: + timeout: 60.0 + poll_interval: 2.0 + max_retries: 5 +- component_type: A2AAgent + id: d6e6a95b-c144-469b-91ad-972121406b83 + name: prime_agent + description: Agent that handles checking if numbers are prime. + metadata: + __metadata_info__: {} + inputs: [] + outputs: [] + agent_url: http:// + connection_config: + component_type: A2AConnectionConfig + id: 54c3ebde-5101-4c4c-9718-bced0142754c + name: '' + description: null + metadata: {} + timeout: 600.0 + headers: null + verify: false + key_file: null + cert_file: null + ssl_ca_cert: null + session_parameters: + timeout: 60.0 + poll_interval: 2.0 + max_retries: 5 +agentspec_version: 25.4.2 diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a_serving.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2a_serving.rst index 346ab4425..b8e6c595a 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2a_serving.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2a_serving.rst @@ -129,7 +129,7 @@ Below is example Flow that is valid for serving, along with how it can be served Next steps ========== -Now that you have learned how to serve WayFlow assistants using A2A protocol, you may proceed to :doc:`How to Use A2A ` to learn how consume an A2A-served agent. +Now that you have learned how to serve WayFlow assistants using A2A protocol, you may proceed to :doc:`How to Use A2A Agents ` to learn how consume an A2A-served agent. Full code ========= diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst similarity index 71% rename from docs/wayflowcore/source/core/howtoguides/howto_a2a.rst rename to docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst index b2a9d3054..3007adcd3 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2a.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst @@ -1,8 +1,8 @@ .. _top-howtoa2a: -============== -How to Use A2A -============== +===================== +How to Use A2A Agents +===================== .. |python-icon| image:: ../../_static/icons/python-icon.svg :width: 40px @@ -11,7 +11,7 @@ How to Use A2A .. grid:: 2 .. grid-item-card:: |python-icon| Download Python Script - :link: ../end_to_end_code_examples/howto_a2a.py + :link: ../end_to_end_code_examples/howto_a2aagent.py :link-alt: A2A servers and clients how-to script Python script/notebook for this guide. @@ -56,8 +56,8 @@ You can export the assistant configuration to its Agent Spec configuration using .. literalinclude:: ../code_examples/howto_a2aagent.py :language: python - :start-after: .. start-##_Export_config_to_Agent_Spec - :end-before: .. end-##_Export_config_to_Agent_Spec + :start-after: .. start-##_Export_config_to_Agent_Spec1 + :end-before: .. end-##_Export_config_to_Agent_Spec1 Here is what the **Agent Spec representation will look like ↓** @@ -67,20 +67,20 @@ Here is what the **Agent Spec representation will look like ↓** .. tab:: JSON - .. literalinclude:: ../config_examples/howto_a2aagent.json + .. literalinclude:: ../config_examples/howto_a2aagent_1.json :language: json .. tab:: YAML - .. literalinclude:: ../config_examples/howto_a2aagent.yaml + .. literalinclude:: ../config_examples/howto_a2aagent_1.yaml :language: yaml You can then load the configuration back to an assistant using the ``AgentSpecLoader``. .. literalinclude:: ../code_examples/howto_a2aagent.py :language: python - :start-after: .. start-##_Load_Agent_Spec_config - :end-before: .. end-##_Load_Agent_Spec_config + :start-after: .. start-##_Load_Agent_Spec_config1 + :end-before: .. end-##_Load_Agent_Spec_config1 Manager Workers with A2A Agents =============================== @@ -97,17 +97,17 @@ Setting up the Agents In this section, you'll set up servers for two agents: ``prime_agent`` checks if numbers are prime, and ``sample_agent`` generates random numbers. -.. literalinclude:: ../code_examples/howto_a2a.py +.. literalinclude:: ../code_examples/howto_a2aagent.py :language: python :start-after: .. start-##_Server_Setup_Prime_Agent :end-before: .. end-##_Server_Setup_Prime_Agent -.. literalinclude:: ../code_examples/howto_a2a.py +.. literalinclude:: ../code_examples/howto_a2aagent.py :language: python :start-after: .. start-##_Server_Setup_Sample_Agent :end-before: .. end-##_Server_Setup_Sample_Agent -.. literalinclude:: ../code_examples/howto_a2a.py +.. literalinclude:: ../code_examples/howto_a2aagent.py :language: python :start-after: .. start-##_Server_Startup_Logic :end-before: .. end-##_Server_Startup_Logic @@ -116,14 +116,14 @@ For further details, see :ref:`A2AServer `. On the client side, create ``A2AAgent`` instances to connect to the servers started above. -.. literalinclude:: ../code_examples/howto_a2a.py +.. literalinclude:: ../code_examples/howto_a2aagent.py :language: python :start-after: .. start-##_Client_Setup :end-before: .. end-##_Client_Setup Now you can use these agents in :ref:`ManagerWorkers ` setup. -.. literalinclude:: ../code_examples/howto_a2a.py +.. literalinclude:: ../code_examples/howto_a2aagent.py :language: python :start-after: .. start-##_Manager_Setup :end-before: .. end-##_Manager_Setup @@ -134,11 +134,44 @@ Executing Tasks Now, execute a conversation in which the manager agent delegates tasks to the most appropriate agent based on their capabilities. This demonstrates how ManagerWorkers can be used to orchestrate complex interactions seamlessly. -.. literalinclude:: ../code_examples/howto_a2a.py +.. literalinclude:: ../code_examples/howto_a2aagent.py :language: python :start-after: .. start-##_ManagerWorkers_Execution :end-before: .. end-##_ManagerWorkers_Execution +Agent Spec Exporting/Loading +---------------------------- + +You can export the assistant configuration to its Agent Spec configuration using the ``AgentSpecExporter``. + +.. literalinclude:: ../code_examples/howto_a2aagent.py + :language: python + :start-after: .. start-##_Export_config_to_Agent_Spec2 + :end-before: .. end-##_Export_config_to_Agent_Spec2 + +Here is what the **Agent Spec representation will look like ↓** + +.. collapse:: Click here to see the assistant configuration. + + .. tabs:: + + .. tab:: JSON + + .. literalinclude:: ../config_examples/howto_a2aagent_2.json + :language: json + + .. tab:: YAML + + .. literalinclude:: ../config_examples/howto_a2aagent_2.yaml + :language: yaml + +You can then load the configuration back to an assistant using the ``AgentSpecLoader``. + +.. literalinclude:: ../code_examples/howto_a2aagent.py + :language: python + :start-after: .. start-##_Load_Agent_Spec_config2 + :end-before: .. end-##_Load_Agent_Spec_config2 + Next Steps ========== @@ -149,6 +182,6 @@ Full Code Click on the card at the :ref:`top of this page ` to download the full code for this guide or copy the code below. -.. literalinclude:: ../end_to_end_code_examples/howto_a2a.py +.. literalinclude:: ../end_to_end_code_examples/howto_a2aagent.py :language: python :linenos: diff --git a/docs/wayflowcore/source/core/howtoguides/index.rst b/docs/wayflowcore/source/core/howtoguides/index.rst index d91e38cc3..afee13353 100644 --- a/docs/wayflowcore/source/core/howtoguides/index.rst +++ b/docs/wayflowcore/source/core/howtoguides/index.rst @@ -42,6 +42,7 @@ These how-to guides demonstrate how to use the main features to create and custo Create a ReAct Agent How to Send Images to LLMs and Agents Use OCI Generative AI Agents + How to Use A2A Agents Use Templates for Advanced Prompting Techniques .. toctree:: @@ -65,8 +66,6 @@ These how-to guides demonstrate how to use the main features to create and custo Build a Hierarchical Multi-Agent System Build a Swarm of Agents Build a ManagerWorkers of Agents - How to Use A2A - .. toctree:: :maxdepth: 1 From 2e8be75ffda65e701c414805b5f06fbcb2c8231d Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Wed, 14 Jan 2026 15:52:57 +0100 Subject: [PATCH 12/21] chore: fix typo --- .../wayflowcore/source/core/code_examples/howto_a2aagent.py | 2 +- docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/wayflowcore/source/core/code_examples/howto_a2aagent.py b/docs/wayflowcore/source/core/code_examples/howto_a2aagent.py index 98eecb170..956737b60 100644 --- a/docs/wayflowcore/source/core/code_examples/howto_a2aagent.py +++ b/docs/wayflowcore/source/core/code_examples/howto_a2aagent.py @@ -7,7 +7,7 @@ # isort:skip_file # fmt: off # mypy: ignore-errors -# docs-title: How to Use A2A Agents +# docs-title: Code Example - How to Use A2A Agents ### Basic Usage diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst index 3007adcd3..31e01b011 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst @@ -1,4 +1,4 @@ -.. _top-howtoa2a: +.. _top-howtoa2agent: ===================== How to Use A2A Agents @@ -12,7 +12,7 @@ How to Use A2A Agents .. grid-item-card:: |python-icon| Download Python Script :link: ../end_to_end_code_examples/howto_a2aagent.py - :link-alt: A2A servers and clients how-to script + :link-alt: A2A Agent how-to script Python script/notebook for this guide. @@ -180,7 +180,7 @@ This guide covered the basics of using A2A agents and coordinating interactions Full Code ========= -Click on the card at the :ref:`top of this page ` to download the full code for this guide or copy the code below. +Click on the card at the :ref:`top of this page ` to download the full code for this guide or copy the code below. .. literalinclude:: ../end_to_end_code_examples/howto_a2aagent.py :language: python From 5677ffe2a53677f244471d382c54df8497e0c8d3 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Thu, 15 Jan 2026 11:10:38 +0100 Subject: [PATCH 13/21] chore: remove unnecessary file --- .../core/config_examples/howto_a2aagent.yaml | 26 ------------------- 1 file changed, 26 deletions(-) delete mode 100644 docs/wayflowcore/source/core/config_examples/howto_a2aagent.yaml diff --git a/docs/wayflowcore/source/core/config_examples/howto_a2aagent.yaml b/docs/wayflowcore/source/core/config_examples/howto_a2aagent.yaml deleted file mode 100644 index 58ea22406..000000000 --- a/docs/wayflowcore/source/core/config_examples/howto_a2aagent.yaml +++ /dev/null @@ -1,26 +0,0 @@ -component_type: A2AAgent -id: 5ba508ef-7cae-417a-9197-8f2aeee870b6 -name: a2a_agent_4311ebd5__auto -description: '' -metadata: - __metadata_info__: {} -inputs: [] -outputs: [] -agent_url: http:// -connection_config: - component_type: A2AConnectionConfig - id: 7d7a7c03-616b-4740-bd8e-ebcfed45092c - name: connection_config - description: null - metadata: {} - timeout: 600.0 - headers: null - verify: false - key_file: null - cert_file: null - ssl_ca_cert: null -session_parameters: - timeout: 60.0 - poll_interval: 2.0 - max_retries: 5 -agentspec_version: 25.4.2 From 2812124ce4a6a658cf4dc1cb30615aede59e9342 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Thu, 29 Jan 2026 11:31:22 +0100 Subject: [PATCH 14/21] refactor: only allow workers to also be A2AAgents --- .../executors/_managerworkersexecutor.py | 21 ++++++++++++------- wayflowcore/src/wayflowcore/managerworkers.py | 2 +- .../wayflowcore/steps/agentexecutionstep.py | 3 +-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py b/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py index 768a98437..29cd66cb1 100644 --- a/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py +++ b/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py @@ -55,15 +55,20 @@ def _create_manager_agent(group_manager: Union[Agent, LlmModel]) -> Agent: def _validate_agent_unicity( - agents: List[Union[Agent, ManagerWorkers]], -) -> Dict[str, Union[Agent, ManagerWorkers]]: + worker_agents: List[Union[Agent, ManagerWorkers]], manager_agent: Agent) -> Dict[str, Union[Agent, ManagerWorkers]]: agent_by_name: Dict[str, Union["Agent", "ManagerWorkers"]] = {} - - for agent in agents: - if not isinstance(agent, (Agent, ManagerWorkers, A2AAgent)): - raise TypeError( - f"Only Agent and ManagerWorker type are supported in ManagerWorkers, got component of type '{agent.__class__.__name__}'" - ) + all_agents = worker_agents + [manager_agent] + for agent in all_agents: + if agent.name != manager_agent.name: + if not isinstance(agent, (Agent, ManagerWorkers, A2AAgent)): + raise TypeError( + f"Only Agent, ManagerWorker and A2AAgent types are supported as workers for ManagerWorkers, got component of type '{agent.__class__.__name__}'" + ) + else: + if not isinstance(agent, Agent): + raise TypeError( + f"Only Agents are supported as managers for ManagerWorkers, got component of type '{agent.__class__.__name__}'" + ) # Checking for missing name if not agent.name: diff --git a/wayflowcore/src/wayflowcore/managerworkers.py b/wayflowcore/src/wayflowcore/managerworkers.py index 84923541c..a1dbdc0f2 100644 --- a/wayflowcore/src/wayflowcore/managerworkers.py +++ b/wayflowcore/src/wayflowcore/managerworkers.py @@ -126,7 +126,7 @@ def __init__( self.workers = workers self._agent_by_name: Dict[str, Union["Agent", "ManagerWorkers"]] = _validate_agent_unicity( - self.workers + [self.manager_agent] + self.workers, self.manager_agent ) # Create send message tools for the group manager diff --git a/wayflowcore/src/wayflowcore/steps/agentexecutionstep.py b/wayflowcore/src/wayflowcore/steps/agentexecutionstep.py index 0ad108817..893877282 100644 --- a/wayflowcore/src/wayflowcore/steps/agentexecutionstep.py +++ b/wayflowcore/src/wayflowcore/steps/agentexecutionstep.py @@ -8,7 +8,6 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union from wayflowcore._metadata import MetadataType -from wayflowcore.a2a.a2aagent import A2AAgent from wayflowcore.agent import Agent, CallerInputMode from wayflowcore.conversationalcomponent import _mutate from wayflowcore.executors.executionstatus import ( @@ -272,7 +271,7 @@ def might_yield(self) -> bool: self.agent.caller_input_mode == CallerInputMode.ALWAYS or self.caller_input_mode == CallerInputMode.ALWAYS ) - elif isinstance(self.agent, (OciAgent, A2AAgent)): + elif isinstance(self.agent, OciAgent): return True else: raise NotImplementedError(f"{self.agent} not supported in the agent execution step.") From 5f9e2f4ef3826887c25b869080d2300d405d19a6 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Thu, 29 Jan 2026 17:49:34 +0100 Subject: [PATCH 15/21] chore: fix typo --- docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst index 31e01b011..dd8ad3b60 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst @@ -1,4 +1,4 @@ -.. _top-howtoa2agent: +.. _top-howtoa2aagent: ===================== How to Use A2A Agents From 40bdc9c65e8d4c6f05a98efddc66001f25dc39a2 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Fri, 30 Jan 2026 00:35:33 +0100 Subject: [PATCH 16/21] refactor: return types in _validate_agent_unicity --- .../src/wayflowcore/executors/_managerworkersexecutor.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py b/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py index 29cd66cb1..70b0a85c9 100644 --- a/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py +++ b/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py @@ -55,8 +55,9 @@ def _create_manager_agent(group_manager: Union[Agent, LlmModel]) -> Agent: def _validate_agent_unicity( - worker_agents: List[Union[Agent, ManagerWorkers]], manager_agent: Agent) -> Dict[str, Union[Agent, ManagerWorkers]]: - agent_by_name: Dict[str, Union["Agent", "ManagerWorkers"]] = {} + worker_agents: List[Union[Agent, ManagerWorkers, A2AAgent]], manager_agent: Agent +) -> Dict[str, Union[Agent, ManagerWorkers, A2AAgent]]: + agent_by_name: Dict[str, Union["Agent", "ManagerWorkers", "A2AAgent"]] = {} all_agents = worker_agents + [manager_agent] for agent in all_agents: if agent.name != manager_agent.name: From 951d7f2fa0918920694af825e4c5ccbbdee83765 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Fri, 30 Jan 2026 08:43:08 +0100 Subject: [PATCH 17/21] fix: convert from agentspec to wayflow --- wayflowcore/src/wayflowcore/managerworkers.py | 4 ++-- .../_builtins_deserialization_plugin.py | 13 ++++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/wayflowcore/src/wayflowcore/managerworkers.py b/wayflowcore/src/wayflowcore/managerworkers.py index a1dbdc0f2..46e460584 100644 --- a/wayflowcore/src/wayflowcore/managerworkers.py +++ b/wayflowcore/src/wayflowcore/managerworkers.py @@ -125,8 +125,8 @@ def __init__( self.workers = workers - self._agent_by_name: Dict[str, Union["Agent", "ManagerWorkers"]] = _validate_agent_unicity( - self.workers, self.manager_agent + self._agent_by_name: Dict[str, Union["Agent", "ManagerWorkers", "A2AAgent"]] = ( + _validate_agent_unicity(self.workers, self.manager_agent) ) # Create send message tools for the group manager diff --git a/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py b/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py index f6c82f79e..0a6b38af1 100644 --- a/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py +++ b/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py @@ -802,10 +802,17 @@ def convert_to_wayflow( ) raise ValueError(f"Unexpected tool type provided in the tool_registry: {type(tool)}") elif isinstance(agentspec_component, AgentSpecManagerWorkers): - for agent in [agentspec_component.group_manager] + agentspec_component.workers: # type: ignore[assignment] - if not isinstance(agent, AgentSpecAgent): + if not isinstance(agentspec_component.group_manager, AgentSpecAgent): + raise ValueError( + f"WayFlow ManagerWorkers' manager only supports agents of type `Agent`, " + f"but received `{type(agent).__name__}` instead." + ) + for agent in agentspec_component.workers: # type: ignore[assignment] + if not isinstance( + agent, (AgentSpecAgent, AgentSpecManagerWorkers, AgentSpecA2AAgent) + ): raise ValueError( - f"WayFlow ManagerWorkers only supports agents of type `Agent`, " + f"WayFlow ManagerWorkers' workers only supports agents of type `Agent`, " f"but received `{type(agent).__name__}` instead." ) From a4a3273c27adbf8cedc6815013369e5520fda500 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Fri, 30 Jan 2026 09:19:37 +0100 Subject: [PATCH 18/21] fix: types --- .../executors/_managerworkersconversation.py | 16 +++++++++++----- .../executors/_managerworkersexecutor.py | 12 +++++++++--- wayflowcore/src/wayflowcore/managerworkers.py | 10 +++++++--- .../_builtins_deserialization_plugin.py | 2 +- 4 files changed, 28 insertions(+), 12 deletions(-) diff --git a/wayflowcore/src/wayflowcore/executors/_managerworkersconversation.py b/wayflowcore/src/wayflowcore/executors/_managerworkersconversation.py index 980cebdff..dda7c56e3 100644 --- a/wayflowcore/src/wayflowcore/executors/_managerworkersconversation.py +++ b/wayflowcore/src/wayflowcore/executors/_managerworkersconversation.py @@ -8,6 +8,7 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Dict, List, Optional, Union +from wayflowcore.a2a.a2aagent import A2AAgent from wayflowcore.agent import Agent from wayflowcore.conversation import Conversation from wayflowcore.executors._executionstate import ConversationExecutionState @@ -17,6 +18,7 @@ if TYPE_CHECKING: from wayflowcore.contextproviders import ContextProvider + from wayflowcore.executors._a2aagentconversation import A2AAgentConversation from wayflowcore.executors._agentconversation import AgentConversation logger = logging.getLogger(__name__) @@ -25,11 +27,13 @@ @dataclass class ManagerWorkersConversationExecutionState(ConversationExecutionState): current_agent_name: str - subconversations: Dict[str, Union["AgentConversation", "ManagerWorkersConversation"]] + subconversations: Dict[ + str, Union["AgentConversation", "ManagerWorkersConversation", "A2AAgentConversation"] + ] def _create_subconversation_for_agent( - self, agent: Union[Agent, ManagerWorkers] - ) -> Union["AgentConversation", "ManagerWorkersConversation"]: + self, agent: Union[Agent, ManagerWorkers, A2AAgent] + ) -> Union["AgentConversation", "ManagerWorkersConversation", "A2AAgentConversation"]: subconv = agent.start_conversation() self.subconversations[agent.name] = subconv @@ -48,7 +52,9 @@ def managerworkers(self) -> "ManagerWorkers": @property def subconversations( self, - ) -> Dict[str, Union["AgentConversation", "ManagerWorkersConversation"]]: + ) -> Dict[ + str, Union["AgentConversation", "ManagerWorkersConversation", "A2AAgentConversation"] + ]: return self.state.subconversations @property @@ -71,7 +77,7 @@ def __str__(self) -> str: def _get_agent_subconversation( self, agent_name: str - ) -> Optional[Union["AgentConversation", "ManagerWorkersConversation"]]: + ) -> Optional[Union["AgentConversation", "ManagerWorkersConversation", "A2AAgentConversation"]]: return self.state.subconversations.get(agent_name) def _get_main_subconversation( diff --git a/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py b/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py index 70b0a85c9..6e0686cd9 100644 --- a/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py +++ b/wayflowcore/src/wayflowcore/executors/_managerworkersexecutor.py @@ -31,6 +31,7 @@ if TYPE_CHECKING: from wayflowcore.agentconversation import AgentConversation + from wayflowcore.executors._a2aagentconversation import A2AAgentConversation from wayflowcore.executors._managerworkersconversation import ManagerWorkersConversation logger = logging.getLogger(__name__) @@ -153,7 +154,9 @@ async def _run_manager_round( @staticmethod async def _run_worker_round( - current_conversation: Union["AgentConversation", "ManagerWorkersConversation"], + current_conversation: Union[ + "AgentConversation", "ManagerWorkersConversation", "A2AAgentConversation" + ], execution_interrupts: Optional[Sequence[ExecutionInterrupt]] = None, ) -> ExecutionStatus: return await current_conversation.execute_async( @@ -165,6 +168,7 @@ async def execute_async( conversation: Conversation, execution_interrupts: Optional[Sequence[ExecutionInterrupt]] = None, ) -> ExecutionStatus: + from wayflowcore.executors._a2aagentconversation import A2AAgentConversation from wayflowcore.executors._managerworkersconversation import ManagerWorkersConversation if not isinstance(conversation, ManagerWorkersConversation): @@ -190,9 +194,11 @@ async def execute_async( if current_agent_name == managerworkers_config.manager_agent.name: current_agent = managerworkers_config.manager_agent - if isinstance(current_conversation, ManagerWorkersConversation): + if isinstance( + current_conversation, (ManagerWorkersConversation, A2AAgentConversation) + ): raise ValueError( - "Manager Conversation cannot be of type `ManagerWorkersConversation`." + "Manager Conversation cannot be of type `ManagerWorkersConversation` or `A2AAgentConversation`." ) # Handle pending tool requests of manager diff --git a/wayflowcore/src/wayflowcore/managerworkers.py b/wayflowcore/src/wayflowcore/managerworkers.py index 46e460584..411d9c003 100644 --- a/wayflowcore/src/wayflowcore/managerworkers.py +++ b/wayflowcore/src/wayflowcore/managerworkers.py @@ -9,6 +9,7 @@ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union from wayflowcore._metadata import MetadataType +from wayflowcore.a2a.a2aagent import A2AAgent from wayflowcore.agent import Agent, CallerInputMode from wayflowcore.conversationalcomponent import ConversationalComponent from wayflowcore.idgeneration import IdGenerator @@ -30,7 +31,7 @@ @dataclass(init=False) class ManagerWorkers(ConversationalComponent, SerializableDataclassMixin, SerializableObject): group_manager: Union[LlmModel, Agent] - workers: List[Union[Agent, "ManagerWorkers"]] + workers: List[Union[Agent, "ManagerWorkers", A2AAgent]] caller_input_mode: CallerInputMode managerworkers_template: "PromptTemplate" input_descriptors: List["Property"] @@ -43,7 +44,7 @@ class ManagerWorkers(ConversationalComponent, SerializableDataclassMixin, Serial def __init__( self, group_manager: Union[LlmModel, Agent], - workers: List[Union[Agent, "ManagerWorkers"]], + workers: List[Union[Agent, "ManagerWorkers", A2AAgent]], caller_input_mode: CallerInputMode = CallerInputMode.ALWAYS, managerworkers_template: Optional["PromptTemplate"] = None, input_descriptors: Optional[List["Property"]] = None, @@ -177,6 +178,7 @@ def start_conversation( from wayflowcore.agentconversation import AgentConversation from wayflowcore.events.event import ConversationCreatedEvent from wayflowcore.events.eventlistener import record_event + from wayflowcore.executors._a2aagentconversation import A2AAgentConversation from wayflowcore.executors._managerworkersconversation import ( ManagerWorkersConversation, ManagerWorkersConversationExecutionState, @@ -198,7 +200,9 @@ def start_conversation( ) ) - subconversations: Dict[str, Union[AgentConversation, ManagerWorkersConversation]] = {} + subconversations: Dict[ + str, Union[AgentConversation, ManagerWorkersConversation, A2AAgentConversation] + ] = {} subconversations[self.manager_agent.name] = self.manager_agent.start_conversation( inputs=inputs, messages=messages, diff --git a/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py b/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py index 0a6b38af1..5792f670c 100644 --- a/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py +++ b/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py @@ -805,7 +805,7 @@ def convert_to_wayflow( if not isinstance(agentspec_component.group_manager, AgentSpecAgent): raise ValueError( f"WayFlow ManagerWorkers' manager only supports agents of type `Agent`, " - f"but received `{type(agent).__name__}` instead." + f"but received `{type(agentspec_component.group_manager).__name__}` instead." ) for agent in agentspec_component.workers: # type: ignore[assignment] if not isinstance( From 10113b1740464c18d0b182b92a92c4a34d1fe1eb Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Fri, 30 Jan 2026 10:19:29 +0100 Subject: [PATCH 19/21] chore: sort imports --- wayflowcore/tests/a2a/conftest.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wayflowcore/tests/a2a/conftest.py b/wayflowcore/tests/a2a/conftest.py index ca5b08df6..c4f093707 100644 --- a/wayflowcore/tests/a2a/conftest.py +++ b/wayflowcore/tests/a2a/conftest.py @@ -12,8 +12,9 @@ import pytest -from ..utils import LogTee, _check_server_is_up, _terminate_process_tree, get_available_port from wayflowcore.a2a.a2aagent import A2AAgent, A2AConnectionConfig + +from ..utils import LogTee, _check_server_is_up, _terminate_process_tree, get_available_port from .start_a2a_server import AgentType _START_SERVER_FILE_PATH = str(Path(__file__).parent / "start_a2a_server.py") From 2417c48449a4e266f12ea73f2a12047175460acd Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Fri, 30 Jan 2026 11:38:21 +0100 Subject: [PATCH 20/21] refactor: error message in agent spec deseriaization for ManagerWorkers --- .../serialization/_builtins_deserialization_plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py b/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py index 5792f670c..ba629d772 100644 --- a/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py +++ b/wayflowcore/src/wayflowcore/serialization/_builtins_deserialization_plugin.py @@ -812,7 +812,7 @@ def convert_to_wayflow( agent, (AgentSpecAgent, AgentSpecManagerWorkers, AgentSpecA2AAgent) ): raise ValueError( - f"WayFlow ManagerWorkers' workers only supports agents of type `Agent`, " + f"WayFlow ManagerWorkers' workers only supports agents of type `Agent`, `ManagerWorker`, `A2AAgent`, " f"but received `{type(agent).__name__}` instead." ) From 5d97938eb5a4a232f9e3c680e1a63d134e7e8ff9 Mon Sep 17 00:00:00 2001 From: Sathvik Bhagavan Date: Fri, 30 Jan 2026 13:50:05 +0100 Subject: [PATCH 21/21] docs: address comments --- docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst b/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst index dd8ad3b60..216c436bd 100644 --- a/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst +++ b/docs/wayflowcore/source/core/howtoguides/howto_a2aagent.rst @@ -85,7 +85,7 @@ You can then load the configuration back to an assistant using the ``AgentSpecLo Manager Workers with A2A Agents =============================== -While each agent has limited standalone capability, combining them unlocks powerful workflows. +While each agent has limited standalone capabilities, combining them unlocks powerful workflows. Using :ref:`ManagerWorkers `, you can implement a manager agent that efficiently coordinates tasks between different specialized agents. This modular, scalable architecture allows each agent to focus on specific tasks, increasing overall system capability and flexibility. @@ -131,7 +131,7 @@ Now you can use these agents in :ref:`ManagerWorkers ` setup. Executing Tasks --------------- -Now, execute a conversation in which the manager agent delegates tasks to the most appropriate agent based on their capabilities. +Now, you can execute a conversation in which the manager agent delegates tasks to the most appropriate agent based on their capabilities. This demonstrates how ManagerWorkers can be used to orchestrate complex interactions seamlessly. .. literalinclude:: ../code_examples/howto_a2aagent.py