Skip to content

Commit 6f29775

Browse files
wukathcopybara-github
authored andcommitted
fix: Fix RemoteA2AAgent deepcopy errors
RemoteA2Agent's new _config attribute in v1.27.0 was not working with deepcopy() because it had Callable fields, causing agent engine deployment issues. This adds a custom deepcopy attribute that handles Callables by copying them by reference. Co-authored-by: Kathy Wu <wukathy@google.com> PiperOrigin-RevId: 893590078
1 parent eb4674b commit 6f29775

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

src/google/adk/a2a/agent/config.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
from __future__ import annotations
1818

19+
import copy
1920
from typing import Any
2021
from typing import Awaitable
2122
from typing import Callable
@@ -108,3 +109,16 @@ class A2aRemoteAgentConfig(BaseModel):
108109
)
109110

110111
request_interceptors: Optional[list[RequestInterceptor]] = None
112+
113+
def __deepcopy__(self, memo):
114+
cls = self.__class__
115+
copied_values = {}
116+
for k, v in self.__dict__.items():
117+
if not k.startswith('_'):
118+
if callable(v):
119+
copied_values[k] = v
120+
else:
121+
copied_values[k] = copy.deepcopy(v, memo)
122+
result = cls.model_construct(**copied_values)
123+
memo[id(self)] = result
124+
return result

tests/unittests/agents/test_remote_a2a_agent.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
import copy
1516
import json
1617
from pathlib import Path
1718
import tempfile
@@ -36,6 +37,7 @@
3637
from a2a.types import TextPart
3738
from google.adk.a2a.agent import ParametersConfig
3839
from google.adk.a2a.agent import RequestInterceptor
40+
from google.adk.a2a.agent.config import A2aRemoteAgentConfig
3941
from google.adk.a2a.agent.utils import execute_after_request_interceptors
4042
from google.adk.a2a.agent.utils import execute_before_request_interceptors
4143
from google.adk.agents.invocation_context import InvocationContext
@@ -2866,3 +2868,28 @@ async def test_execute_after_request_interceptors_no_after_request(
28662868
)
28672869

28682870
assert result is event
2871+
2872+
2873+
class TestRemoteA2aAgentDeepcopy:
2874+
"""Test deepcopy functionality for RemoteA2aAgent and its config."""
2875+
2876+
def test_deepcopy_config(self):
2877+
"""Test that A2aRemoteAgentConfig can be deepcopied with interceptors."""
2878+
config = A2aRemoteAgentConfig()
2879+
mock_interceptor = Mock()
2880+
config.request_interceptors = [mock_interceptor]
2881+
2882+
copied_config = copy.deepcopy(config)
2883+
assert copied_config is not None
2884+
2885+
# Verify that functions are shared (by reference)
2886+
assert copied_config.a2a_message_converter is config.a2a_message_converter
2887+
2888+
# Verify that request_interceptors list was copied
2889+
assert copied_config.request_interceptors is not None
2890+
assert len(copied_config.request_interceptors) == 1
2891+
# Standard objects inside lists should be deepcopied (new instances)
2892+
assert (
2893+
copied_config.request_interceptors[0]
2894+
is not config.request_interceptors[0]
2895+
)

0 commit comments

Comments
 (0)