Skip to content

Commit 8ebf91d

Browse files
committed
refactor(agents): Deduplicate DEFAULT_SAFE_IMPORTS and sync tracing.py with upstream
Addresses Gemini code review suggestion (PR google#4259): - Remove duplicate DEFAULT_SAFE_IMPORTS from coding_agent_config.py - Import DEFAULT_SAFE_IMPORTS from allowlist_validator.py (canonical source) - Create _DATA_SCIENCE_IMPORTS for numpy/pandas/scipy/matplotlib packages - Create _EXTENDED_SAFE_IMPORTS combining both for CodingAgentConfig default Resolves merge conflict in telemetry/tracing.py: - Sync with upstream main (new OTEL improvements, proper semconv imports) - Add CodingAgent-specific tracing functions: trace_code_generation, trace_code_execution, trace_import_validation, trace_tool_ipc Updates test to use _EXTENDED_SAFE_IMPORTS from coding_agent_config.py
1 parent 5711d01 commit 8ebf91d

File tree

2 files changed

+144
-195
lines changed

2 files changed

+144
-195
lines changed

src/google/adk/agents/coding_agent_config.py

Lines changed: 142 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -22,205 +22,154 @@
2222

2323
from pydantic import Field
2424

25+
from ..code_executors.allowlist_validator import DEFAULT_SAFE_IMPORTS
26+
from ..tools.tool_configs import ToolConfig
2527
from ..utils.feature_decorator import experimental
2628
from .base_agent_config import BaseAgentConfig
2729
from .common_configs import CodeConfig
28-
from ..tools.tool_configs import ToolConfig
29-
3030

31-
# Default set of safe imports for Python code execution
32-
DEFAULT_SAFE_IMPORTS: FrozenSet[str] = frozenset(
33-
{
34-
# Standard library - safe modules
35-
"json",
36-
"math",
37-
"re",
38-
"datetime",
39-
"collections",
40-
"collections.*",
41-
"itertools",
42-
"functools",
43-
"operator",
44-
"string",
45-
"textwrap",
46-
"unicodedata",
47-
"decimal",
48-
"fractions",
49-
"random",
50-
"statistics",
51-
"typing",
52-
"typing.*",
53-
"dataclasses",
54-
"enum",
55-
"abc",
56-
"copy",
57-
"pprint",
58-
"reprlib",
59-
"numbers",
60-
"cmath",
61-
"time",
62-
"calendar",
63-
"hashlib",
64-
"hmac",
65-
"base64",
66-
"binascii",
67-
"html",
68-
"html.*",
69-
"urllib.parse",
70-
"uuid",
71-
"struct",
72-
"codecs",
73-
"locale",
74-
"gettext",
75-
"bisect",
76-
"heapq",
77-
"array",
78-
"weakref",
79-
"types",
80-
"contextlib",
81-
"warnings",
82-
"traceback",
83-
"linecache",
84-
"difflib",
85-
"graphlib",
86-
"zoneinfo",
87-
# Common data science (can be enabled explicitly)
88-
"numpy",
89-
"numpy.*",
90-
"pandas",
91-
"pandas.*",
92-
"scipy",
93-
"scipy.*",
94-
"matplotlib",
95-
"matplotlib.*",
96-
}
31+
# Additional data science imports commonly used in coding agents
32+
_DATA_SCIENCE_IMPORTS: FrozenSet[str] = frozenset({
33+
"numpy",
34+
"numpy.*",
35+
"pandas",
36+
"pandas.*",
37+
"scipy",
38+
"scipy.*",
39+
"matplotlib",
40+
"matplotlib.*",
41+
})
42+
43+
# Extended safe imports including common data science packages
44+
_EXTENDED_SAFE_IMPORTS: FrozenSet[str] = (
45+
DEFAULT_SAFE_IMPORTS | _DATA_SCIENCE_IMPORTS
9746
)
9847

9948

10049
@experimental
10150
class CodingAgentConfig(BaseAgentConfig):
102-
"""Configuration for CodingAgent.
103-
104-
This config extends BaseAgentConfig with fields specific to agents that
105-
generate and execute Python code to accomplish tasks using tools.
106-
"""
107-
108-
agent_class: Union[Literal["CodingAgent"], str] = Field(
109-
default="CodingAgent",
110-
description="The class of the agent. Must be CodingAgent.",
111-
)
112-
113-
model: str = Field(
114-
default="",
115-
description=(
116-
"The model to use for the agent. When not set, the agent will "
117-
"inherit the model from its ancestor or use the default model."
118-
),
119-
)
120-
121-
model_code: Optional[CodeConfig] = Field(
122-
default=None,
123-
description=(
124-
"Optional. Code reference to a custom model instance. "
125-
"Takes precedence over the model field if both are set."
126-
),
127-
)
128-
129-
instruction: str = Field(
130-
default="",
131-
description=(
132-
"Dynamic instructions for the agent, guiding its behavior. "
133-
"Can contain placeholders like {variable_name} that will be "
134-
"resolved at runtime using session state and context."
135-
),
136-
)
137-
138-
tools: Optional[List[ToolConfig]] = Field(
139-
default=None,
140-
description=(
141-
"Optional. The list of tools available to the agent. "
142-
"Tools are exposed as Python functions that the agent can call "
143-
"in the generated code."
144-
),
145-
)
146-
147-
code_executor: Optional[CodeConfig] = Field(
148-
default=None,
149-
description=(
150-
"Optional. Code reference to a custom code executor instance. "
151-
"If not set, a default ContainerCodeExecutor will be used."
152-
),
153-
)
154-
155-
authorized_imports: FrozenSet[str] = Field(
156-
default=DEFAULT_SAFE_IMPORTS,
157-
description=(
158-
"Set of allowed import names/patterns. Supports wildcards "
159-
'(e.g., "collections.*" allows all collections submodules). '
160-
"Any imports not in this set will be rejected before execution."
161-
),
162-
)
163-
164-
max_iterations: int = Field(
165-
default=10,
166-
ge=1,
167-
le=100,
168-
description=(
169-
"Maximum number of ReAct loop iterations. Each iteration "
170-
"involves generating code, executing it, and processing results."
171-
),
172-
)
173-
174-
error_retry_attempts: int = Field(
175-
default=2,
176-
ge=0,
177-
le=10,
178-
description=(
179-
"Number of times to retry code execution on errors. "
180-
"Error messages are fed back to the LLM for correction."
181-
),
182-
)
183-
184-
stateful: bool = Field(
185-
default=False,
186-
description=(
187-
"Whether to maintain state across iterations. If True, "
188-
"execution history is preserved and re-executed to restore state."
189-
),
190-
)
191-
192-
tool_server_host: Optional[str] = Field(
193-
default=None,
194-
description=(
195-
"Host address for the tool execution server. If not set, "
196-
"auto-detection will try host.docker.internal first, "
197-
"then fall back to 172.17.0.1 for Linux."
198-
),
199-
)
200-
201-
tool_server_port: int = Field(
202-
default=8765,
203-
ge=1024,
204-
le=65535,
205-
description="Port for the tool execution server.",
206-
)
207-
208-
before_model_callbacks: Optional[List[CodeConfig]] = Field(
209-
default=None,
210-
description="Optional. Callbacks to be called before calling the LLM.",
211-
)
212-
213-
after_model_callbacks: Optional[List[CodeConfig]] = Field(
214-
default=None,
215-
description="Optional. Callbacks to be called after calling the LLM.",
216-
)
217-
218-
before_tool_callbacks: Optional[List[CodeConfig]] = Field(
219-
default=None,
220-
description="Optional. Callbacks to be called before calling a tool.",
221-
)
222-
223-
after_tool_callbacks: Optional[List[CodeConfig]] = Field(
224-
default=None,
225-
description="Optional. Callbacks to be called after calling a tool.",
226-
)
51+
"""Configuration for CodingAgent.
52+
53+
This config extends BaseAgentConfig with fields specific to agents that
54+
generate and execute Python code to accomplish tasks using tools.
55+
"""
56+
57+
agent_class: Union[Literal["CodingAgent"], str] = Field(
58+
default="CodingAgent",
59+
description="The class of the agent. Must be CodingAgent.",
60+
)
61+
62+
model: str = Field(
63+
default="",
64+
description=(
65+
"The model to use for the agent. When not set, the agent will "
66+
"inherit the model from its ancestor or use the default model."
67+
),
68+
)
69+
70+
model_code: Optional[CodeConfig] = Field(
71+
default=None,
72+
description=(
73+
"Optional. Code reference to a custom model instance. "
74+
"Takes precedence over the model field if both are set."
75+
),
76+
)
77+
78+
instruction: str = Field(
79+
default="",
80+
description=(
81+
"Dynamic instructions for the agent, guiding its behavior. "
82+
"Can contain placeholders like {variable_name} that will be "
83+
"resolved at runtime using session state and context."
84+
),
85+
)
86+
87+
tools: Optional[List[ToolConfig]] = Field(
88+
default=None,
89+
description=(
90+
"Optional. The list of tools available to the agent. "
91+
"Tools are exposed as Python functions that the agent can call "
92+
"in the generated code."
93+
),
94+
)
95+
96+
code_executor: Optional[CodeConfig] = Field(
97+
default=None,
98+
description=(
99+
"Optional. Code reference to a custom code executor instance. "
100+
"If not set, a default ContainerCodeExecutor will be used."
101+
),
102+
)
103+
104+
authorized_imports: FrozenSet[str] = Field(
105+
default=_EXTENDED_SAFE_IMPORTS,
106+
description=(
107+
"Set of allowed import names/patterns. Supports wildcards "
108+
'(e.g., "collections.*" allows all collections submodules). '
109+
"Any imports not in this set will be rejected before execution."
110+
),
111+
)
112+
113+
max_iterations: int = Field(
114+
default=10,
115+
ge=1,
116+
le=100,
117+
description=(
118+
"Maximum number of ReAct loop iterations. Each iteration "
119+
"involves generating code, executing it, and processing results."
120+
),
121+
)
122+
123+
error_retry_attempts: int = Field(
124+
default=2,
125+
ge=0,
126+
le=10,
127+
description=(
128+
"Number of times to retry code execution on errors. "
129+
"Error messages are fed back to the LLM for correction."
130+
),
131+
)
132+
133+
stateful: bool = Field(
134+
default=False,
135+
description=(
136+
"Whether to maintain state across iterations. If True, "
137+
"execution history is preserved and re-executed to restore state."
138+
),
139+
)
140+
141+
tool_server_host: Optional[str] = Field(
142+
default=None,
143+
description=(
144+
"Host address for the tool execution server. If not set, "
145+
"auto-detection will try host.docker.internal first, "
146+
"then fall back to 172.17.0.1 for Linux."
147+
),
148+
)
149+
150+
tool_server_port: int = Field(
151+
default=8765,
152+
ge=1024,
153+
le=65535,
154+
description="Port for the tool execution server.",
155+
)
156+
157+
before_model_callbacks: Optional[List[CodeConfig]] = Field(
158+
default=None,
159+
description="Optional. Callbacks to be called before calling the LLM.",
160+
)
161+
162+
after_model_callbacks: Optional[List[CodeConfig]] = Field(
163+
default=None,
164+
description="Optional. Callbacks to be called after calling the LLM.",
165+
)
166+
167+
before_tool_callbacks: Optional[List[CodeConfig]] = Field(
168+
default=None,
169+
description="Optional. Callbacks to be called before calling a tool.",
170+
)
171+
172+
after_tool_callbacks: Optional[List[CodeConfig]] = Field(
173+
default=None,
174+
description="Optional. Callbacks to be called after calling a tool.",
175+
)

tests/unittests/agents/test_coding_agent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222

2323
from google.adk.agents.coding_agent import CodingAgent
2424
from google.adk.agents.coding_agent import CodingAgentState
25+
from google.adk.agents.coding_agent_config import _EXTENDED_SAFE_IMPORTS
2526
from google.adk.agents.coding_agent_config import CodingAgentConfig
26-
from google.adk.agents.coding_agent_config import DEFAULT_SAFE_IMPORTS
2727
from google.adk.tools.base_tool import BaseTool
2828
import pytest
2929

@@ -41,7 +41,7 @@ def test_default_values(self):
4141
assert config.error_retry_attempts == 2
4242
assert config.stateful is False
4343
assert config.tool_server_port == 8765
44-
assert config.authorized_imports == DEFAULT_SAFE_IMPORTS
44+
assert config.authorized_imports == _EXTENDED_SAFE_IMPORTS
4545

4646
def test_custom_values(self):
4747
"""Test that custom values can be set."""

0 commit comments

Comments
 (0)