chore: import upstream snapshot with attribution
Continuous Integration / Pre-commit Linter (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.10) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.11) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.12) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.10) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.11) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.12) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.14) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Waiting to run
Copybara PR Handler / close-imported-pr (push) Waiting to run
Continuous Integration / Pre-commit Linter (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.10) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.11) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.12) (push) Waiting to run
Continuous Integration / Mypy Check (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.10) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.11) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.12) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.13) (push) Waiting to run
Continuous Integration / Unit Tests (Python 3.14) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Waiting to run
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Waiting to run
Copybara PR Handler / close-imported-pr (push) Waiting to run
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
# Workflow Triage Sample
|
||||
|
||||
This sample demonstrates how to build a multi-agent workflow that intelligently triages incoming requests and delegates them to appropriate specialized agents.
|
||||
|
||||
## Overview
|
||||
|
||||
The workflow consists of three main components:
|
||||
|
||||
1. **Execution Manager Agent** (`agent.py`) - Analyzes user input and determines which execution agents are relevant
|
||||
1. **Plan Execution Agent** - Sequential agent that coordinates execution and summarization
|
||||
1. **Worker Execution Agents** (`execution_agent.py`) - Specialized agents that execute specific tasks in parallel
|
||||
|
||||
## Architecture
|
||||
|
||||
### Execution Manager Agent (`root_agent`)
|
||||
|
||||
- **Model**: gemini-2.5-flash
|
||||
- **Name**: `execution_manager_agent`
|
||||
- **Role**: Analyzes user requests and updates the execution plan
|
||||
- **Tools**: `update_execution_plan` - Updates which execution agents should be activated
|
||||
- **Sub-agents**: Delegates to `plan_execution_agent` for actual task execution
|
||||
- **Clarification**: Asks for clarification if user intent is unclear before proceeding
|
||||
|
||||
### Plan Execution Agent
|
||||
|
||||
- **Type**: SequentialAgent
|
||||
- **Name**: `plan_execution_agent`
|
||||
- **Components**:
|
||||
- `worker_parallel_agent` (ParallelAgent) - Runs relevant agents in parallel
|
||||
- `execution_summary_agent` - Summarizes the execution results
|
||||
|
||||
### Worker Agents
|
||||
|
||||
The system includes two specialized execution agents that run in parallel:
|
||||
|
||||
- **Code Agent** (`code_agent`): Handles code generation tasks
|
||||
- Uses `before_agent_callback_check_relevance` to skip if not relevant
|
||||
- Output stored in `code_agent_output` state key
|
||||
- **Math Agent** (`math_agent`): Performs mathematical calculations
|
||||
- Uses `before_agent_callback_check_relevance` to skip if not relevant
|
||||
- Output stored in `math_agent_output` state key
|
||||
|
||||
### Execution Summary Agent
|
||||
|
||||
- **Model**: gemini-2.5-flash
|
||||
- **Name**: `execution_summary_agent`
|
||||
- **Role**: Summarizes outputs from all activated agents
|
||||
- **Dynamic Instructions**: Generated based on which agents were activated
|
||||
- **Content Inclusion**: Set to "none" to focus on summarization
|
||||
|
||||
## Key Features
|
||||
|
||||
- **Dynamic Agent Selection**: Automatically determines which agents are needed based on user input
|
||||
- **Parallel Execution**: Multiple relevant agents can work simultaneously via `ParallelAgent`
|
||||
- **Relevance Filtering**: Agents skip execution if they're not relevant to the current state using callback mechanism
|
||||
- **Stateful Workflow**: Maintains execution state through `ToolContext`
|
||||
- **Execution Summarization**: Automatically summarizes results from all activated agents
|
||||
- **Sequential Coordination**: Uses `SequentialAgent` to ensure proper execution flow
|
||||
|
||||
## Usage
|
||||
|
||||
The workflow follows this pattern:
|
||||
|
||||
1. User provides input to the root agent (`execution_manager_agent`)
|
||||
1. Manager analyzes the request and identifies relevant agents (`code_agent`, `math_agent`)
|
||||
1. If user intent is unclear, manager asks for clarification before proceeding
|
||||
1. Manager updates the execution plan using `update_execution_plan`
|
||||
1. Control transfers to `plan_execution_agent`
|
||||
1. `worker_parallel_agent` (ParallelAgent) runs only relevant agents based on the updated plan
|
||||
1. `execution_summary_agent` summarizes the results from all activated agents
|
||||
|
||||
### Example Queries
|
||||
|
||||
**Vague requests requiring clarification:**
|
||||
|
||||
```
|
||||
> hi
|
||||
> Help me do this.
|
||||
```
|
||||
|
||||
The root agent (`execution_manager_agent`) will greet the user and ask for clarification about their specific task.
|
||||
|
||||
**Math-only requests:**
|
||||
|
||||
```
|
||||
> What's 1+1?
|
||||
```
|
||||
|
||||
Only the `math_agent` executes while `code_agent` is skipped.
|
||||
|
||||
**Multi-domain requests:**
|
||||
|
||||
```
|
||||
> What's 1+11? Write a python function to verify it.
|
||||
```
|
||||
|
||||
Both `code_agent` and `math_agent` execute in parallel, followed by summarization.
|
||||
|
||||
## Available Execution Agents
|
||||
|
||||
- `code_agent` - For code generation and programming tasks
|
||||
- `math_agent` - For mathematical computations and analysis
|
||||
|
||||
## Implementation Details
|
||||
|
||||
- Uses Google ADK agents framework
|
||||
- Implements callback-based relevance checking via `before_agent_callback_check_relevance`
|
||||
- Maintains state through `ToolContext` and state keys
|
||||
- Supports parallel agent execution with `ParallelAgent`
|
||||
- Uses `SequentialAgent` for coordinated execution flow
|
||||
- Dynamic instruction generation for summary agent based on activated agents
|
||||
- Agent outputs stored in state with `{agent_name}_output` keys
|
||||
@@ -0,0 +1,15 @@
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from . import agent
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from google.adk.agents.llm_agent import Agent
|
||||
from google.adk.tools.tool_context import ToolContext
|
||||
|
||||
from . import execution_agent
|
||||
|
||||
|
||||
def update_execution_plan(
|
||||
execution_agents: list[str], tool_context: ToolContext
|
||||
) -> str:
|
||||
"""Updates the execution plan for the agents to run."""
|
||||
|
||||
tool_context.state["execution_agents"] = execution_agents
|
||||
return "execution_agents updated."
|
||||
|
||||
|
||||
root_agent = Agent(
|
||||
name="execution_manager_agent",
|
||||
instruction="""\
|
||||
You are the Execution Manager Agent, responsible for setting up execution plan and delegate to plan_execution_agent for the actual plan execution.
|
||||
|
||||
You ONLY have the following worker agents: `code_agent`, `math_agent`.
|
||||
|
||||
You should do the following:
|
||||
|
||||
1. Analyze the user input and decide any worker agents that are relevant;
|
||||
2. If none of the worker agents are relevant, you should explain to user that no relevant agents are available and ask for something else;
|
||||
3. Update the execution plan with the relevant worker agents using `update_execution_plan` tool.
|
||||
4. Transfer control to the plan_execution_agent for the actual plan execution.
|
||||
|
||||
When calling the `update_execution_plan` tool, you should pass the list of worker agents that are relevant to user's input.
|
||||
|
||||
NOTE:
|
||||
|
||||
* If you are not clear about user's intent, you should ask for clarification first;
|
||||
* Only after you're clear about user's intent, you can proceed to step #3.
|
||||
""",
|
||||
sub_agents=[
|
||||
execution_agent.plan_execution_agent,
|
||||
],
|
||||
tools=[update_execution_plan],
|
||||
)
|
||||
@@ -0,0 +1,116 @@
|
||||
# Copyright 2026 Google LLC
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from google.adk.agents import Agent
|
||||
from google.adk.agents import ParallelAgent
|
||||
from google.adk.agents.base_agent import BeforeAgentCallback
|
||||
from google.adk.agents.callback_context import CallbackContext
|
||||
from google.adk.agents.readonly_context import ReadonlyContext
|
||||
from google.adk.agents.sequential_agent import SequentialAgent
|
||||
from google.genai import types
|
||||
|
||||
|
||||
def before_agent_callback_check_relevance(
|
||||
agent_name: str,
|
||||
) -> BeforeAgentCallback:
|
||||
"""Callback to check if the state is relevant before executing the agent."""
|
||||
|
||||
def callback(callback_context: CallbackContext) -> Optional[types.Content]:
|
||||
"""Check if the state is relevant."""
|
||||
if agent_name not in callback_context.state["execution_agents"]:
|
||||
return types.Content(
|
||||
parts=[
|
||||
types.Part(
|
||||
text=(
|
||||
f"Skipping execution agent {agent_name} as it is not"
|
||||
" relevant to the current state."
|
||||
)
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
return callback
|
||||
|
||||
|
||||
code_agent = Agent(
|
||||
name="code_agent",
|
||||
instruction="""\
|
||||
You are the Code Agent, responsible for generating code.
|
||||
|
||||
NOTE: You should only generate code and ignore other askings from the user.
|
||||
""",
|
||||
before_agent_callback=before_agent_callback_check_relevance("code_agent"),
|
||||
output_key="code_agent_output",
|
||||
)
|
||||
|
||||
math_agent = Agent(
|
||||
name="math_agent",
|
||||
instruction="""\
|
||||
You are the Math Agent, responsible for performing mathematical calculations.
|
||||
|
||||
NOTE: You should only perform mathematical calculations and ignore other askings from the user.
|
||||
""",
|
||||
before_agent_callback=before_agent_callback_check_relevance("math_agent"),
|
||||
output_key="math_agent_output",
|
||||
)
|
||||
|
||||
|
||||
worker_parallel_agent = ParallelAgent(
|
||||
name="worker_parallel_agent",
|
||||
sub_agents=[
|
||||
code_agent,
|
||||
math_agent,
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
def instruction_provider_for_execution_summary_agent(
|
||||
readonly_context: ReadonlyContext,
|
||||
) -> str:
|
||||
"""Provides the instruction for the execution agent."""
|
||||
activated_agents = readonly_context.state["execution_agents"]
|
||||
prompt = f"""\
|
||||
You are the Execution Summary Agent, responsible for summarizing the execution of the plan in the current invocation.
|
||||
|
||||
In this invocation, the following agents were involved: {', '.join(activated_agents)}.
|
||||
|
||||
Below are their outputs:
|
||||
"""
|
||||
for agent_name in activated_agents:
|
||||
output = readonly_context.state.get(f"{agent_name}_output", "")
|
||||
prompt += f"\n\n{agent_name} output:\n{output}"
|
||||
|
||||
prompt += (
|
||||
"\n\nPlease summarize the execution of the plan based on the above"
|
||||
" outputs."
|
||||
)
|
||||
return prompt.strip()
|
||||
|
||||
|
||||
execution_summary_agent = Agent(
|
||||
name="execution_summary_agent",
|
||||
instruction=instruction_provider_for_execution_summary_agent,
|
||||
include_contents="none",
|
||||
)
|
||||
|
||||
plan_execution_agent = SequentialAgent(
|
||||
name="plan_execution_agent",
|
||||
sub_agents=[
|
||||
worker_parallel_agent,
|
||||
execution_summary_agent,
|
||||
],
|
||||
)
|
||||
Reference in New Issue
Block a user