chore: import upstream snapshot with attribution
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,117 @@
|
||||
# Parallel Function Test Agent
|
||||
|
||||
This agent demonstrates parallel function calling functionality in ADK. It includes multiple tools with different processing times to showcase how parallel execution improves performance compared to sequential execution.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multiple async tool types**: All functions use proper async patterns for true parallelism
|
||||
- **Thread safety testing**: Tools modify shared state to verify thread-safe operations
|
||||
- **Performance demonstration**: Clear time differences between parallel and sequential execution
|
||||
- **GIL-aware design**: Uses `await asyncio.sleep()` instead of `time.sleep()` to avoid blocking
|
||||
|
||||
## Tools
|
||||
|
||||
1. **get_weather(city)** - Async function, 2-second delay
|
||||
1. **get_currency_rate(from_currency, to_currency)** - Async function, 1.5-second delay
|
||||
1. **calculate_distance(city1, city2)** - Async function, 1-second delay
|
||||
1. **get_population(cities)** - Async function, 0.5 seconds per city
|
||||
|
||||
**Important**: All functions use `await asyncio.sleep()` instead of `time.sleep()` to ensure true parallel execution. Using `time.sleep()` would block Python's GIL and force sequential execution despite asyncio parallelism.
|
||||
|
||||
## Testing Parallel Function Calling
|
||||
|
||||
### Basic Parallel Test
|
||||
|
||||
```
|
||||
Get the weather for New York, London, and Tokyo
|
||||
```
|
||||
|
||||
Expected: 3 parallel get_weather calls (~2 seconds total instead of ~6 seconds sequential)
|
||||
|
||||
### Mixed Function Types Test
|
||||
|
||||
```
|
||||
Get the weather in Paris, the USD to EUR exchange rate, and the distance between New York and London
|
||||
```
|
||||
|
||||
Expected: 3 parallel async calls with different functions (~2 seconds total)
|
||||
|
||||
### Complex Parallel Test
|
||||
|
||||
```
|
||||
Compare New York and London by getting weather, population, and distance between them
|
||||
```
|
||||
|
||||
Expected: Multiple parallel calls combining different data types
|
||||
|
||||
### Performance Comparison Test
|
||||
|
||||
You can test the timing difference by asking for the same information in different ways:
|
||||
|
||||
**Sequential-style request:**
|
||||
|
||||
```
|
||||
First get the weather in New York, then get the weather in London, then get the weather in Tokyo
|
||||
```
|
||||
|
||||
*Expected time: ~6 seconds (2s + 2s + 2s)*
|
||||
|
||||
**Parallel-style request:**
|
||||
|
||||
```
|
||||
Get the weather in New York, London, and Tokyo
|
||||
```
|
||||
|
||||
*Expected time: ~2 seconds (max of parallel 2s delays)*
|
||||
|
||||
The parallel version should be **3x faster** due to concurrent execution.
|
||||
|
||||
## Thread Safety Testing
|
||||
|
||||
All tools modify the agent's state (`tool_context.state`) with request logs including timestamps. This helps verify that:
|
||||
|
||||
- Multiple tools can safely modify state concurrently
|
||||
- No race conditions occur during parallel execution
|
||||
- State modifications are preserved correctly
|
||||
|
||||
## Running the Agent
|
||||
|
||||
```bash
|
||||
# Start the agent in interactive mode
|
||||
adk run contributing/samples/parallel_functions
|
||||
|
||||
# Or use the web interface
|
||||
adk web
|
||||
```
|
||||
|
||||
## Example Queries
|
||||
|
||||
- "Get weather for New York, London, Tokyo, and Paris" *(4 parallel calls, ~2s total)*
|
||||
- "What's the USD to EUR rate and GBP to USD rate?" *(2 parallel calls, ~1.5s total)*
|
||||
- "Compare New York and San Francisco: weather, population, and distance" *(3 parallel calls, ~2s total)*
|
||||
- "Get population data for Tokyo, London, Paris, and Sydney" *(1 call with 4 cities, ~2s total)*
|
||||
- "What's the weather in Paris and the distance from Paris to London?" *(2 parallel calls, ~2s total)*
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### ❌ Problem: Functions still execute sequentially (6+ seconds for 3 weather calls)
|
||||
|
||||
**Root Cause**: Using blocking operations like `time.sleep()` in function implementations.
|
||||
|
||||
**Solution**: Always use async patterns:
|
||||
|
||||
```python
|
||||
# ❌ Wrong - blocks the GIL, forces sequential execution
|
||||
def my_tool():
|
||||
time.sleep(2) # Blocks entire event loop
|
||||
|
||||
# ✅ Correct - allows true parallelism
|
||||
async def my_tool():
|
||||
await asyncio.sleep(2) # Non-blocking, parallel-friendly
|
||||
```
|
||||
|
||||
### ✅ Verification: Check execution timing
|
||||
|
||||
- Parallel execution: ~2 seconds for 3 weather calls
|
||||
- Sequential execution: ~6 seconds for 3 weather calls
|
||||
- If you see 6+ seconds, your functions are blocking the GIL
|
||||
@@ -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
|
||||
@@ -0,0 +1,242 @@
|
||||
# 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.
|
||||
|
||||
"""Sample agent for testing parallel function calling."""
|
||||
|
||||
import asyncio
|
||||
import time
|
||||
from typing import List
|
||||
|
||||
from google.adk import Agent
|
||||
from google.adk.tools.tool_context import ToolContext
|
||||
|
||||
|
||||
async def get_weather(city: str, tool_context: ToolContext) -> dict:
|
||||
"""Get the current weather for a city.
|
||||
|
||||
Args:
|
||||
city: The name of the city to get weather for.
|
||||
|
||||
Returns:
|
||||
A dictionary with weather information.
|
||||
"""
|
||||
# Simulate some async processing time (non-blocking)
|
||||
await asyncio.sleep(2)
|
||||
|
||||
# Mock weather data
|
||||
weather_data = {
|
||||
'New York': {'temp': 72, 'condition': 'sunny', 'humidity': 45},
|
||||
'London': {'temp': 60, 'condition': 'cloudy', 'humidity': 80},
|
||||
'Tokyo': {'temp': 68, 'condition': 'rainy', 'humidity': 90},
|
||||
'San Francisco': {'temp': 65, 'condition': 'foggy', 'humidity': 85},
|
||||
'Paris': {'temp': 58, 'condition': 'overcast', 'humidity': 70},
|
||||
'Sydney': {'temp': 75, 'condition': 'sunny', 'humidity': 60},
|
||||
}
|
||||
|
||||
result = weather_data.get(
|
||||
city,
|
||||
{
|
||||
'temp': 70,
|
||||
'condition': 'unknown',
|
||||
'humidity': 50,
|
||||
'note': (
|
||||
f'Weather data not available for {city}, showing default values'
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
# Store in context for testing thread safety
|
||||
if 'weather_requests' not in tool_context.state:
|
||||
tool_context.state['weather_requests'] = []
|
||||
tool_context.state['weather_requests'].append(
|
||||
{'city': city, 'result': result}
|
||||
)
|
||||
|
||||
return {
|
||||
'city': city,
|
||||
'temperature': result['temp'],
|
||||
'condition': result['condition'],
|
||||
'humidity': result['humidity'],
|
||||
**({'note': result['note']} if 'note' in result else {}),
|
||||
}
|
||||
|
||||
|
||||
async def get_currency_rate(
|
||||
from_currency: str, to_currency: str, tool_context: ToolContext
|
||||
) -> dict:
|
||||
"""Get the exchange rate between two currencies.
|
||||
|
||||
Args:
|
||||
from_currency: The source currency code (e.g., 'USD').
|
||||
to_currency: The target currency code (e.g., 'EUR').
|
||||
|
||||
Returns:
|
||||
A dictionary with exchange rate information.
|
||||
"""
|
||||
# Simulate async processing time
|
||||
await asyncio.sleep(1.5)
|
||||
|
||||
# Mock exchange rates
|
||||
rates = {
|
||||
('USD', 'EUR'): 0.85,
|
||||
('USD', 'GBP'): 0.75,
|
||||
('USD', 'JPY'): 110.0,
|
||||
('EUR', 'USD'): 1.18,
|
||||
('EUR', 'GBP'): 0.88,
|
||||
('GBP', 'USD'): 1.33,
|
||||
('GBP', 'EUR'): 1.14,
|
||||
('JPY', 'USD'): 0.009,
|
||||
}
|
||||
|
||||
rate = rates.get((from_currency, to_currency), 1.0)
|
||||
|
||||
# Store in context for testing thread safety
|
||||
if 'currency_requests' not in tool_context.state:
|
||||
tool_context.state['currency_requests'] = []
|
||||
tool_context.state['currency_requests'].append({
|
||||
'from': from_currency,
|
||||
'to': to_currency,
|
||||
'rate': rate,
|
||||
})
|
||||
|
||||
return {
|
||||
'from_currency': from_currency,
|
||||
'to_currency': to_currency,
|
||||
'exchange_rate': rate,
|
||||
}
|
||||
|
||||
|
||||
async def calculate_distance(
|
||||
city1: str, city2: str, tool_context: ToolContext
|
||||
) -> dict:
|
||||
"""Calculate the distance between two cities.
|
||||
|
||||
Args:
|
||||
city1: The first city.
|
||||
city2: The second city.
|
||||
|
||||
Returns:
|
||||
A dictionary with distance information.
|
||||
"""
|
||||
# Simulate async processing time (non-blocking)
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# Mock distances (in kilometers)
|
||||
city_coords = {
|
||||
'New York': (40.7128, -74.0060),
|
||||
'London': (51.5074, -0.1278),
|
||||
'Tokyo': (35.6762, 139.6503),
|
||||
'San Francisco': (37.7749, -122.4194),
|
||||
'Paris': (48.8566, 2.3522),
|
||||
'Sydney': (-33.8688, 151.2093),
|
||||
}
|
||||
|
||||
# Simple distance calculation (mock)
|
||||
if city1 in city_coords and city2 in city_coords:
|
||||
coord1 = city_coords[city1]
|
||||
coord2 = city_coords[city2]
|
||||
# Simplified distance calculation
|
||||
distance = int(
|
||||
((coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2) ** 0.5
|
||||
* 111
|
||||
) # rough km conversion
|
||||
else:
|
||||
distance = 5000 # default distance
|
||||
|
||||
# Store in context for testing thread safety
|
||||
if 'distance_requests' not in tool_context.state:
|
||||
tool_context.state['distance_requests'] = []
|
||||
tool_context.state['distance_requests'].append({
|
||||
'city1': city1,
|
||||
'city2': city2,
|
||||
'distance': distance,
|
||||
})
|
||||
|
||||
return {
|
||||
'city1': city1,
|
||||
'city2': city2,
|
||||
'distance_km': distance,
|
||||
'distance_miles': int(distance * 0.621371),
|
||||
}
|
||||
|
||||
|
||||
async def get_population(cities: List[str], tool_context: ToolContext) -> dict:
|
||||
"""Get population information for multiple cities.
|
||||
|
||||
Args:
|
||||
cities: A list of city names.
|
||||
|
||||
Returns:
|
||||
A dictionary with population data for each city.
|
||||
"""
|
||||
# Simulate async processing time proportional to number of cities (non-blocking)
|
||||
await asyncio.sleep(len(cities) * 0.5)
|
||||
|
||||
# Mock population data
|
||||
populations = {
|
||||
'New York': 8336817,
|
||||
'London': 9648110,
|
||||
'Tokyo': 13960000,
|
||||
'San Francisco': 873965,
|
||||
'Paris': 2161000,
|
||||
'Sydney': 5312163,
|
||||
}
|
||||
|
||||
results = {}
|
||||
for city in cities:
|
||||
results[city] = populations.get(city, 1000000) # default 1M if not found
|
||||
|
||||
# Store in context for testing thread safety
|
||||
if 'population_requests' not in tool_context.state:
|
||||
tool_context.state['population_requests'] = []
|
||||
tool_context.state['population_requests'].append(
|
||||
{'cities': cities, 'results': results}
|
||||
)
|
||||
|
||||
return {
|
||||
'populations': results,
|
||||
'total_population': sum(results.values()),
|
||||
'cities_count': len(cities),
|
||||
}
|
||||
|
||||
|
||||
root_agent = Agent(
|
||||
name='parallel_function_test_agent',
|
||||
description=(
|
||||
'Agent for testing parallel function calling performance and thread'
|
||||
' safety.'
|
||||
),
|
||||
instruction="""
|
||||
You are a helpful assistant that can provide information about weather, currency rates,
|
||||
distances between cities, and population data. You have access to multiple tools and
|
||||
should use them efficiently.
|
||||
|
||||
When users ask for information about multiple cities or multiple types of data,
|
||||
you should call multiple functions in parallel to provide faster responses.
|
||||
|
||||
For example:
|
||||
- If asked about weather in multiple cities, call get_weather for each city in parallel
|
||||
- If asked about weather and currency rates, call both functions in parallel
|
||||
- If asked to compare cities, you might need weather, population, and distance data in parallel
|
||||
|
||||
Always aim to be efficient and call multiple functions simultaneously when possible.
|
||||
Be informative and provide clear, well-structured responses.
|
||||
""",
|
||||
tools=[
|
||||
get_weather,
|
||||
get_currency_rate,
|
||||
calculate_distance,
|
||||
get_population,
|
||||
],
|
||||
)
|
||||
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"author": "user",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "Tell me about Paris and Sydney: weather, distance between them, and their populations."
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-1",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "parallel_function_test_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"city": "Paris"
|
||||
},
|
||||
"id": "fc-1",
|
||||
"name": "get_weather"
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"city": "Sydney"
|
||||
},
|
||||
"id": "fc-2",
|
||||
"name": "get_weather"
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"city1": "Paris",
|
||||
"city2": "Sydney"
|
||||
},
|
||||
"id": "fc-3",
|
||||
"name": "calculate_distance"
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"cities": [
|
||||
"Paris",
|
||||
"Sydney"
|
||||
]
|
||||
},
|
||||
"id": "fc-4",
|
||||
"name": "get_population"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-2",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "parallel_function_test_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"actions": {
|
||||
"stateDelta": {
|
||||
"distance_requests": [
|
||||
{
|
||||
"city1": "Paris",
|
||||
"city2": "Sydney",
|
||||
"distance": 18903
|
||||
}
|
||||
],
|
||||
"population_requests": [
|
||||
{
|
||||
"cities": [
|
||||
"Paris",
|
||||
"Sydney"
|
||||
],
|
||||
"results": {
|
||||
"Paris": 2161000,
|
||||
"Sydney": 5312163
|
||||
}
|
||||
}
|
||||
],
|
||||
"weather_requests": [
|
||||
{
|
||||
"city": "Paris",
|
||||
"result": {
|
||||
"condition": "overcast",
|
||||
"humidity": 70,
|
||||
"temp": 58
|
||||
}
|
||||
},
|
||||
{
|
||||
"city": "Sydney",
|
||||
"result": {
|
||||
"condition": "sunny",
|
||||
"humidity": 60,
|
||||
"temp": 75
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"author": "parallel_function_test_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-1",
|
||||
"name": "get_weather",
|
||||
"response": {
|
||||
"city": "Paris",
|
||||
"condition": "overcast",
|
||||
"humidity": 70,
|
||||
"temperature": 58
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-2",
|
||||
"name": "get_weather",
|
||||
"response": {
|
||||
"city": "Sydney",
|
||||
"condition": "sunny",
|
||||
"humidity": 60,
|
||||
"temperature": 75
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-3",
|
||||
"name": "calculate_distance",
|
||||
"response": {
|
||||
"city1": "Paris",
|
||||
"city2": "Sydney",
|
||||
"distance_km": 18903,
|
||||
"distance_miles": 11745
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-4",
|
||||
"name": "get_population",
|
||||
"response": {
|
||||
"cities_count": 2,
|
||||
"populations": {
|
||||
"Paris": 2161000,
|
||||
"Sydney": 5312163
|
||||
},
|
||||
"total_population": 7473163
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-3",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "parallel_function_test_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "parallel_function_test_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "Here's the information about Paris and Sydney:\n\n**Paris:**\n* **Weather:** The current weather in Paris is overcast with a temperature of 58\u00b0F and 70% humidity.\n* **Population:** The population of Paris is 2,161,000.\n\n**Sydney:**\n* **Weather:** The current weather in Sydney is sunny with a temperature of 75\u00b0F and 60% humidity.\n* **Population:** The population of Sydney is 5,312,163.\n\n**Distance between Paris and Sydney:**\nThe distance between Paris and Sydney is 18,903 km (11,745 miles)."
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-4",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "parallel_function_test_agent@1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"author": "user",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "What is the weather in Tokyo and the exchange rate from USD to EUR?"
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-1",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "parallel_function_test_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"city": "Tokyo"
|
||||
},
|
||||
"id": "fc-1",
|
||||
"name": "get_weather"
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"from_currency": "USD",
|
||||
"to_currency": "EUR"
|
||||
},
|
||||
"id": "fc-2",
|
||||
"name": "get_currency_rate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-2",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "parallel_function_test_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"actions": {
|
||||
"stateDelta": {
|
||||
"currency_requests": [
|
||||
{
|
||||
"from": "USD",
|
||||
"rate": 0.85,
|
||||
"to": "EUR"
|
||||
}
|
||||
],
|
||||
"weather_requests": [
|
||||
{
|
||||
"city": "Tokyo",
|
||||
"result": {
|
||||
"condition": "rainy",
|
||||
"humidity": 90,
|
||||
"temp": 68
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"author": "parallel_function_test_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-1",
|
||||
"name": "get_weather",
|
||||
"response": {
|
||||
"city": "Tokyo",
|
||||
"condition": "rainy",
|
||||
"humidity": 90,
|
||||
"temperature": 68
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-2",
|
||||
"name": "get_currency_rate",
|
||||
"response": {
|
||||
"exchange_rate": 0.85,
|
||||
"from_currency": "USD",
|
||||
"to_currency": "EUR"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-3",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "parallel_function_test_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "parallel_function_test_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "The weather in Tokyo is rainy with a temperature of 68 degrees Fahrenheit and 90% humidity. The exchange rate from USD to EUR is 0.85."
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-4",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "parallel_function_test_agent@1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
{
|
||||
"events": [
|
||||
{
|
||||
"author": "user",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "What is the weather in New York and London?"
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-1",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "parallel_function_test_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"city": "New York"
|
||||
},
|
||||
"id": "fc-1",
|
||||
"name": "get_weather"
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionCall": {
|
||||
"args": {
|
||||
"city": "London"
|
||||
},
|
||||
"id": "fc-2",
|
||||
"name": "get_weather"
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-2",
|
||||
"invocationId": "i-1",
|
||||
"longRunningToolIds": [],
|
||||
"nodeInfo": {
|
||||
"path": "parallel_function_test_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"actions": {
|
||||
"stateDelta": {
|
||||
"weather_requests": [
|
||||
{
|
||||
"city": "New York",
|
||||
"result": {
|
||||
"condition": "sunny",
|
||||
"humidity": 45,
|
||||
"temp": 72
|
||||
}
|
||||
},
|
||||
{
|
||||
"city": "London",
|
||||
"result": {
|
||||
"condition": "cloudy",
|
||||
"humidity": 80,
|
||||
"temp": 60
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"author": "parallel_function_test_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-1",
|
||||
"name": "get_weather",
|
||||
"response": {
|
||||
"city": "New York",
|
||||
"condition": "sunny",
|
||||
"humidity": 45,
|
||||
"temperature": 72
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"functionResponse": {
|
||||
"id": "fc-2",
|
||||
"name": "get_weather",
|
||||
"response": {
|
||||
"city": "London",
|
||||
"condition": "cloudy",
|
||||
"humidity": 80,
|
||||
"temperature": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"role": "user"
|
||||
},
|
||||
"id": "e-3",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "parallel_function_test_agent@1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"author": "parallel_function_test_agent",
|
||||
"content": {
|
||||
"parts": [
|
||||
{
|
||||
"text": "The weather in New York is sunny with a temperature of 72 degrees Fahrenheit and 45% humidity. In London, it is cloudy with a temperature of 60 degrees Fahrenheit and 80% humidity."
|
||||
}
|
||||
],
|
||||
"role": "model"
|
||||
},
|
||||
"finishReason": "STOP",
|
||||
"id": "e-4",
|
||||
"invocationId": "i-1",
|
||||
"nodeInfo": {
|
||||
"path": "parallel_function_test_agent@1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user