|
14 | 14 |
|
15 | 15 | from __future__ import annotations |
16 | 16 |
|
17 | | -import enum |
18 | 17 | from typing import Any |
19 | | -from typing import Dict |
20 | | -from typing import List |
21 | | -from typing import Optional |
| 18 | +import warnings |
22 | 19 |
|
23 | | -from google.genai import types as genai_types |
24 | | -from pydantic import BaseModel |
25 | | -from pydantic import Field |
26 | | -from pydantic import field_validator |
| 20 | +from google.adk.tools.environment_simulation.environment_simulation_config import EnvironmentSimulationConfig |
| 21 | +from google.adk.tools.environment_simulation.environment_simulation_config import InjectedError |
| 22 | +from google.adk.tools.environment_simulation.environment_simulation_config import InjectionConfig |
| 23 | +from google.adk.tools.environment_simulation.environment_simulation_config import MockStrategy |
| 24 | +from google.adk.tools.environment_simulation.environment_simulation_config import ToolSimulationConfig |
27 | 25 | from pydantic import model_validator |
28 | | -from pydantic_core import ValidationError |
29 | 26 |
|
| 27 | +warnings.warn( |
| 28 | + "google.adk.tools.agent_simulator.agent_simulator_config is moved to" |
| 29 | + " google.adk.tools.environment_simulation.environment_simulation_config", |
| 30 | + DeprecationWarning, |
| 31 | + stacklevel=2, |
| 32 | +) |
30 | 33 |
|
31 | | -class InjectedError(BaseModel): |
32 | | - """An error to be injected into a tool call.""" |
33 | 34 |
|
34 | | - injected_http_error_code: int |
35 | | - """Inject http error code to the tool call. Will present as "error_code" |
36 | | - in the tool response dict.""" |
| 35 | +class AgentSimulatorConfig(EnvironmentSimulationConfig): |
| 36 | + """Deprecated AgentSimulatorConfig alias. |
37 | 37 |
|
38 | | - error_message: str |
39 | | - """Inject error message to the tool call. Will present as |
40 | | - "error_message" in the tool response dict.""" |
| 38 | + Forwards tracing_path to tracing. |
| 39 | + """ |
41 | 40 |
|
42 | | - |
43 | | -class InjectionConfig(BaseModel): |
44 | | - """Injection configuration for a tool.""" |
45 | | - |
46 | | - injection_probability: float = 1.0 |
47 | | - """Probability of injecting the injected_value.""" |
48 | | - |
49 | | - match_args: Optional[Dict[str, Any]] = None |
50 | | - """Only apply injection if the request matches the match_args. |
51 | | - If match_args is not provided, the injection will be applied to all |
52 | | - requests.""" |
53 | | - |
54 | | - injected_latency_seconds: float = Field(default=0.0, le=120.0) |
55 | | - """Inject latency to the tool call. Please note it may not be accurate if │ |
56 | | - the interceptor is applied as after tool callback.""" |
57 | | - |
58 | | - random_seed: Optional[int] = None |
59 | | - """The random seed to use for this injection.""" |
60 | | - |
61 | | - injected_error: Optional[InjectedError] = None |
62 | | - """The injected error.""" |
63 | | - |
64 | | - injected_response: Optional[Dict[str, Any]] = None |
65 | | - """The injected response.""" |
66 | | - |
67 | | - @model_validator(mode="after") |
68 | | - def check_injected_error_or_response(self) -> Self: |
69 | | - """Checks that either injected_error or injected_response is set.""" |
70 | | - if bool(self.injected_error) == bool(self.injected_response): |
71 | | - raise ValueError( |
72 | | - "Either injected_error or injected_response must be set, but not" |
73 | | - " both, and not neither." |
74 | | - ) |
75 | | - return self |
76 | | - |
77 | | - |
78 | | -class MockStrategy(enum.Enum): |
79 | | - """Mock strategy for a tool.""" |
80 | | - |
81 | | - MOCK_STRATEGY_UNSPECIFIED = 0 |
82 | | - |
83 | | - MOCK_STRATEGY_TOOL_SPEC = 1 |
84 | | - """Use tool specifications to mock the tool response.""" |
85 | | - |
86 | | - MOCK_STRATEGY_TRACING = 2 |
87 | | - """Use provided tracing and tool specifications to mock the tool |
88 | | - response based on llm response. Need to provide tracing path in |
89 | | - command.""" |
90 | | - |
91 | | - |
92 | | -class ToolSimulationConfig(BaseModel): |
93 | | - """Simulation configuration for a single tool.""" |
94 | | - |
95 | | - tool_name: str |
96 | | - """Name of the tool to be simulated.""" |
97 | | - |
98 | | - injection_configs: List[InjectionConfig] = Field(default_factory=list) |
99 | | - """Injection configuration for the tool. If provided, the tool will be |
100 | | - injected with the injected_value with the injection_probability first, |
101 | | - the mock_strategy will be applied if no injection config is hit.""" |
102 | | - |
103 | | - mock_strategy_type: MockStrategy = MockStrategy.MOCK_STRATEGY_UNSPECIFIED |
104 | | - """The mock strategy to use.""" |
105 | | - |
106 | | - @model_validator(mode="after") |
107 | | - def check_mock_strategy_type(self) -> Self: |
108 | | - """Checks that mock_strategy_type is not UNSPECIFIED if no injections.""" |
109 | | - if ( |
110 | | - not self.injection_configs |
111 | | - and self.mock_strategy_type == MockStrategy.MOCK_STRATEGY_UNSPECIFIED |
112 | | - ): |
113 | | - raise ValueError( |
114 | | - "If injection_configs is empty, mock_strategy_type cannot be" |
115 | | - " MOCK_STRATEGY_UNSPECIFIED." |
116 | | - ) |
117 | | - return self |
118 | | - |
119 | | - |
120 | | -class AgentSimulatorConfig(BaseModel): |
121 | | - """Configuration for AgentSimulator.""" |
122 | | - |
123 | | - tool_simulation_configs: List[ToolSimulationConfig] = Field( |
124 | | - default_factory=list |
125 | | - ) |
126 | | - """A list of tool simulation configurations.""" |
127 | | - |
128 | | - simulation_model: str = Field(default="gemini-2.5-flash") |
129 | | - """The model to use for internal simulator LLM calls (tool analysis, mock responses).""" |
130 | | - |
131 | | - simulation_model_configuration: genai_types.GenerateContentConfig = Field( |
132 | | - default_factory=lambda: genai_types.GenerateContentConfig( |
133 | | - thinking_config=genai_types.ThinkingConfig( |
134 | | - include_thoughts=False, |
135 | | - thinking_budget=10240, |
136 | | - ) |
137 | | - ), |
138 | | - ) |
139 | | - """The configuration for the internal simulator LLM calls.""" |
140 | | - |
141 | | - tracing_path: Optional[str] = None |
142 | | - """The path to the tracing file to be used for mocking. Only used if the |
143 | | - mock_strategy_type is MOCK_STRATEGY_TRACING.""" |
144 | | - |
145 | | - environment_data: Optional[str] = None |
146 | | - """Environment-specific data (e.g., a minimal database dump in JSON string |
147 | | - format). This data is passed directly to mock strategies for contextual |
148 | | - mock generation.""" |
149 | | - |
150 | | - @field_validator("tool_simulation_configs") |
| 41 | + @model_validator(mode="before") |
151 | 42 | @classmethod |
152 | | - def check_tool_simulation_configs(cls, v: List[ToolSimulationConfig]): |
153 | | - """Checks that tool_simulation_configs is not empty.""" |
154 | | - if not v: |
155 | | - raise ValueError("tool_simulation_configs must be provided.") |
156 | | - seen_tool_names = set() |
157 | | - for tool_sim_config in v: |
158 | | - if tool_sim_config.tool_name in seen_tool_names: |
159 | | - raise ValueError( |
160 | | - f"Duplicate tool_name found: {tool_sim_config.tool_name}" |
161 | | - ) |
162 | | - seen_tool_names.add(tool_sim_config.tool_name) |
163 | | - return v |
| 43 | + def convert_tracing_path(cls, data: Any) -> Any: |
| 44 | + """Convert tracing_path to tracing.""" |
| 45 | + if isinstance(data, dict) and "tracing_path" in data: |
| 46 | + warnings.warn( |
| 47 | + "`tracing_path` is deprecated. Use `tracing` instead.", |
| 48 | + DeprecationWarning, |
| 49 | + stacklevel=2, |
| 50 | + ) |
| 51 | + if "tracing" not in data: |
| 52 | + data["tracing"] = data.pop("tracing_path") |
| 53 | + else: |
| 54 | + data.pop("tracing_path") |
| 55 | + return data |
| 56 | + |
| 57 | + |
| 58 | +__all__ = [ |
| 59 | + "AgentSimulatorConfig", |
| 60 | + "InjectedError", |
| 61 | + "InjectionConfig", |
| 62 | + "MockStrategy", |
| 63 | + "ToolSimulationConfig", |
| 64 | +] |
0 commit comments