Files
google--adk-python/tests/unittests/workflow/utils/test_transfer_utils.py
T
wehub-resource-sync ec2b666284
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
chore: import upstream snapshot with attribution
2026-07-13 13:25:13 +08:00

189 lines
5.7 KiB
Python

# 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.
"""Tests for agent transfer utilities."""
from __future__ import annotations
from unittest.mock import MagicMock
from google.adk.agents.llm_agent import LlmAgent
from google.adk.workflow.utils._transfer_utils import resolve_and_derive_transfer_context
import pytest
def test_resolve_and_derive_transfer_context_raises_value_error_on_self_transfer():
"""resolve_and_derive_transfer_context raises ValueError when target is the current agent."""
# Arrange
current = LlmAgent(name='current')
root = LlmAgent(name='root', sub_agents=[current])
# Act & Assert
with pytest.raises(ValueError, match='cannot transfer to itself'):
resolve_and_derive_transfer_context(
'current', current, root, MagicMock(), None
)
def test_resolve_and_derive_transfer_context_returns_child_context():
"""resolve_and_derive_transfer_context returns current context as parent context for CHILD transfers."""
# Arrange
target = LlmAgent(name='target')
current = LlmAgent(name='current', sub_agents=[target])
root = LlmAgent(name='root', sub_agents=[current])
curr_ctx = MagicMock()
# Act
resolved_agent, parent_ctx = resolve_and_derive_transfer_context(
'target', current, root, curr_ctx, None
)
# Assert
assert resolved_agent is target
assert parent_ctx is curr_ctx
def test_resolve_and_derive_transfer_context_returns_sibling_context():
"""resolve_and_derive_transfer_context returns parent context for SIBLING transfers."""
# Arrange
current = LlmAgent(name='current')
target = LlmAgent(name='target')
root = LlmAgent(name='root', sub_agents=[current, target])
parent_ctx = MagicMock()
# Act
resolved_agent, derived_ctx = resolve_and_derive_transfer_context(
'target', current, root, MagicMock(), parent_ctx
)
# Assert
assert resolved_agent is target
assert derived_ctx is parent_ctx
def test_resolve_and_derive_transfer_context_climbs_parent_context():
"""resolve_and_derive_transfer_context climbs context chain to find the target parent's parent context."""
# Arrange
root_ctx = MagicMock()
root_ctx.node = MagicMock()
root_ctx.node.name = 'root'
root_ctx.parent_ctx = MagicMock()
root_ctx.parent_ctx.node = None
root_ctx.parent_ctx.parent_ctx = None
child_ctx = MagicMock()
child_ctx.node = MagicMock()
child_ctx.node.name = 'child'
child_ctx.parent_ctx = root_ctx
# Target is 'root', current is 'child'
child = LlmAgent(name='child')
root = LlmAgent(name='root', sub_agents=[child])
child.parent_agent = root
# Act
resolved_agent, derived_ctx = resolve_and_derive_transfer_context(
'root', child, root, child_ctx, None
)
# Assert
assert resolved_agent is root
assert derived_ctx is root_ctx.parent_ctx
def test_resolve_and_derive_transfer_context_returns_root_context_when_parent_bypassed():
"""resolve_and_derive_transfer_context returns root context for PARENT transfers when parent was bypassed."""
# Arrange
root_ctx = MagicMock()
root_ctx.node = None
root_ctx.parent_ctx = None
child_ctx = MagicMock()
child_ctx.node = MagicMock()
child_ctx.node.name = 'child'
child_ctx.parent_ctx = root_ctx
# Target is 'root', current is 'child'
child = LlmAgent(name='child')
root = LlmAgent(name='root', sub_agents=[child])
child.parent_agent = root
# Act
resolved_agent, derived_ctx = resolve_and_derive_transfer_context(
'root', child, root, child_ctx, None
)
# Assert
assert resolved_agent is root
assert derived_ctx is root_ctx
def test_resolve_and_derive_transfer_context_returns_none_when_agent_not_found():
"""resolve_and_derive_transfer_context returns (None, None) when target agent is not found."""
# Arrange
current = LlmAgent(name='current')
root = LlmAgent(name='root', sub_agents=[current])
# Act
resolved_agent, derived_ctx = resolve_and_derive_transfer_context(
'target', current, root, MagicMock(), None
)
# Assert
assert resolved_agent is None
assert derived_ctx is None
def test_resolve_and_derive_transfer_context_returns_target_and_none_when_no_relationship():
"""resolve_and_derive_transfer_context returns (target_agent, None) for unrelated transfers."""
# Arrange
current = LlmAgent(name='current')
target = LlmAgent(name='target')
root1 = LlmAgent(name='root1', sub_agents=[current])
root2 = LlmAgent(name='root2', sub_agents=[target])
# Act
resolved_agent, derived_ctx = resolve_and_derive_transfer_context(
'target', current, root2, MagicMock(), None
)
# Assert
assert resolved_agent is target
assert derived_ctx is None
def test_resolve_and_derive_transfer_context_works_with_cloned_agents():
"""resolve_and_derive_transfer_context works correctly when the current agent is cloned (name-based matching)."""
# Arrange
target = LlmAgent(name='target')
current = LlmAgent(name='current', sub_agents=[target])
root = LlmAgent(name='root', sub_agents=[current])
cloned_current = current.clone()
assert cloned_current is not current
assert cloned_current.name == current.name
curr_ctx = MagicMock()
# Act
resolved_agent, derived_ctx = resolve_and_derive_transfer_context(
'target', cloned_current, root, curr_ctx, None
)
# Assert
assert resolved_agent is target
assert derived_ctx is curr_ctx