diff --git a/tests/cli/test_generated_agent_backend_codegen.py b/tests/cli/test_generated_agent_backend_codegen.py index 9884f6c2b..3a01bd811 100644 --- a/tests/cli/test_generated_agent_backend_codegen.py +++ b/tests/cli/test_generated_agent_backend_codegen.py @@ -15,10 +15,12 @@ from __future__ import annotations import asyncio +import copy import importlib.util import ipaddress import py_compile import socket +import threading import pytest from pydantic import ValidationError @@ -343,6 +345,36 @@ async def fake_create_agents(self, **kwargs): assert captured["agents"][0].nodes[0].instruction == instruction +def test_quick_mode_compat_toolset_survives_request_deepcopy(tmp_path) -> None: + project = generate_project_from_draft( + AgentDraft(name="quick-agent", dynamicAgentDelegation=True) + ) + compat_py = next( + file.content + for file in project.files + if file.path == "agents/quick_agent/quick_mode_compat.py" + ) + compat_path = tmp_path / "quick_mode_compat.py" + compat_path.write_text(compat_py, encoding="utf-8") + spec = importlib.util.spec_from_file_location( + "quick_mode_compat_deepcopy_test", + compat_path, + ) + assert spec is not None and spec.loader is not None + module = importlib.util.module_from_spec(spec) + spec.loader.exec_module(module) + + toolset = module.CreateAgentToolset(resource_sources=[]) + # Stand-in for an OpenTelemetry span processor lock held via bootstrap agents. + toolset._runtime_lock = threading.RLock() + # Mirrors LlmRequest.tools_dict, which holds bound methods of the toolset. + request_like = {"tools_dict": {"create_agents": toolset.create_agents}} + + copied = copy.deepcopy(request_like) + + assert copied["tools_dict"]["create_agents"].__self__ is toolset + + def test_quick_mode_compat_rejects_resources_without_collection( tmp_path, ) -> None: diff --git a/veadk/cli/generated_agent_codegen.py b/veadk/cli/generated_agent_codegen.py index 85f757e72..215299031 100644 --- a/veadk/cli/generated_agent_codegen.py +++ b/veadk/cli/generated_agent_codegen.py @@ -1625,6 +1625,12 @@ class CreateAgentToolset(_BaseCreateAgentToolset): _MAX_COMPLETED_CREATIONS = 128 + def __deepcopy__(self, memo: dict[int, Any]) -> CreateAgentToolset: + # Pinned runtimes before #1113 deep-copy LlmRequest for 429 retries, and + # tools_dict reaches this toolset, its bootstrap agents, tracers and locks. + memo[id(self)] = self + return self + def __init__(self, *args: Any, **kwargs: Any) -> None: kwargs.setdefault("resource_store", _ReusableResourceStore()) super().__init__(*args, **kwargs)