1
- # ABOUTME: Experimental agent configuration with toAgent() method for creating Agent instances
2
- # ABOUTME: Extends core AgentConfig with experimental instantiation patterns using ToolPool
3
1
"""Experimental agent configuration with enhanced instantiation patterns."""
4
2
5
3
import json
6
4
import importlib
5
+ from typing import TYPE_CHECKING
7
6
8
- from .tool_pool import ToolPool
7
+ if TYPE_CHECKING :
8
+ # Import here to avoid circular imports:
9
+ # experimental/agent_config.py -> agent.agent -> event_loop.event_loop ->
10
+ # experimental.hooks -> experimental.__init__.py -> AgentConfig
11
+ from ..agent .agent import Agent
12
+
13
+ from .tool_box import ToolBox
9
14
10
15
# File prefix for configuration file paths
11
16
FILE_PREFIX = "file://"
16
21
17
22
18
23
class AgentConfig :
19
- """Agent configuration with toAgent() method and ToolPool integration."""
24
+ """Agent configuration with to_agent() method and ToolBox integration.
25
+
26
+ Example config.json:
27
+ {
28
+ "model": "anthropic.claude-3-5-sonnet-20241022-v2:0",
29
+ "prompt": "You are a helpful assistant",
30
+ "tools": ["file_read", "editor"]
31
+ }
32
+ """
20
33
21
- def __init__ (self , config_source : str | dict [str , any ], tool_pool : ToolPool | None = None , raise_exception_on_missing_tool : bool = True ):
34
+ def __init__ (self , config_source : str | dict [str , any ], tool_box : ToolBox | None = None , raise_exception_on_missing_tool : bool = True ):
22
35
"""Initialize AgentConfig from file path or dictionary.
23
36
24
37
Args:
25
38
config_source: Path to JSON config file (must start with 'file://') or config dictionary
26
- tool_pool : Optional ToolPool to select tools from when 'tools' is specified in config
39
+ tool_box : Optional ToolBox to select tools from when 'tools' is specified in config
27
40
raise_exception_on_missing_tool: If False, skip missing tools instead of raising ImportError
41
+
42
+ Example:
43
+ # Dictionary config
44
+ config = AgentConfig({
45
+ "model": "anthropic.claude-3-5-sonnet-20241022-v2:0",
46
+ "prompt": "You are a helpful assistant",
47
+ "tools": ["file_read", "editor"]
48
+ })
49
+
50
+ # File config
51
+ config = AgentConfig("file://config.json")
28
52
"""
29
53
if isinstance (config_source , str ):
30
54
# Require file:// prefix for file paths
@@ -45,40 +69,38 @@ def __init__(self, config_source: str | dict[str, any], tool_pool: ToolPool | No
45
69
46
70
# Process tools configuration if provided
47
71
config_tools = config_data .get ('tools' )
48
- if config_tools is not None and tool_pool is None :
49
- raise ValueError ("Tool names specified in config but no ToolPool provided" )
72
+ if config_tools is not None and tool_box is None :
73
+ raise ValueError ("Tool names specified in config but no ToolBox provided" )
50
74
51
- # Handle tool selection from ToolPool
52
- if tool_pool is not None :
53
- self ._tool_pool = tool_pool
75
+ # Handle tool selection from ToolBox
76
+ if tool_box is not None :
77
+ self ._toolbox = tool_box
54
78
else :
55
- # Create default ToolPool with strands_tools
56
- self ._tool_pool = self ._create_default_tool_pool ()
79
+ # Create default ToolBox with strands_tools
80
+ self ._toolbox = self ._create_default_toolbox ()
57
81
58
82
# Track configured tools separately from full tool pool
59
83
self ._configured_tools = []
60
84
61
85
# Apply tool selection if specified
62
86
if config_tools is not None :
63
- # Validate all tool names exist in the ToolPool
64
- available_tools = self ._tool_pool .list_tool_names ()
65
- for tool_name in config_tools :
66
- if tool_name not in available_tools :
67
- if self ._raise_exception_on_missing_tool :
68
- raise ValueError (f"Tool '{ tool_name } ' not found in ToolPool. Available tools: { available_tools } " )
69
- # Skip missing tools when flag is False
70
- continue
87
+ # Validate all tool names exist in the ToolBox
88
+ available_tools = self ._toolbox .list_tool_names ()
89
+
90
+ if any (tool_name not in available_tools for tool_name in config_tools ) and self ._raise_exception_on_missing_tool :
91
+ missing_tool = next (tool_name for tool_name in config_tools if tool_name not in available_tools )
92
+ raise ValueError (f"Tool '{ missing_tool } ' not found in ToolBox. Available tools: { available_tools } " )
71
93
72
- # Store selected tools from the ToolPool (only ones that exist)
73
- all_tools = self ._tool_pool . get_tools ()
94
+ # Store selected tools from the ToolBox (only ones that exist)
95
+ all_tools = self ._toolbox . list_tools ()
74
96
for tool in all_tools :
75
97
if tool .tool_name in config_tools :
76
98
self ._configured_tools .append (tool )
77
99
# If no tools specified in config, use no tools (empty list)
78
100
79
- def _create_default_tool_pool (self ) -> ToolPool :
80
- """Create default ToolPool with strands_tools."""
81
- pool = ToolPool ()
101
+ def _create_default_toolbox (self ) -> ToolBox :
102
+ """Create default ToolBox with strands_tools."""
103
+ pool = ToolBox ()
82
104
83
105
for tool in DEFAULT_TOOLS :
84
106
try :
@@ -88,23 +110,23 @@ def _create_default_tool_pool(self) -> ToolPool:
88
110
except ImportError :
89
111
if self ._raise_exception_on_missing_tool :
90
112
raise ImportError (
91
- f"strands_tools is not available and no ToolPool was specified. "
113
+ f"strands_tools is not available and no ToolBox was specified. "
92
114
f"Either install strands_tools with 'pip install strands-agents-tools' "
93
- f"or provide your own ToolPool with your own tools."
115
+ f"or provide your own ToolBox with your own tools."
94
116
)
95
117
# Skip missing tools when flag is False
96
118
continue
97
119
98
120
return pool
99
121
100
122
@property
101
- def tool_pool (self ) -> ToolPool :
102
- """Get the full ToolPool (superset of all available tools).
123
+ def toolbox (self ) -> ToolBox :
124
+ """Get the full ToolBox (superset of all available tools).
103
125
104
126
Returns:
105
- ToolPool instance containing all available tools
127
+ ToolBox instance containing all available tools
106
128
"""
107
- return self ._tool_pool
129
+ return self ._toolbox
108
130
109
131
@property
110
132
def configured_tools (self ) -> list :
@@ -115,7 +137,7 @@ def configured_tools(self) -> list:
115
137
"""
116
138
return self ._configured_tools
117
139
118
- def to_agent (self , ** kwargs : any ):
140
+ def to_agent (self , ** kwargs : any ) -> "Agent" :
119
141
"""Create an Agent instance from this configuration.
120
142
121
143
Args:
@@ -135,24 +157,22 @@ def to_agent(self, **kwargs: any):
135
157
agent = config.to_agent()
136
158
response = agent("Read the contents of README.md")
137
159
138
- # Using custom ToolPool
160
+ # Using custom ToolBox
139
161
from strands import tool
140
162
141
163
@tool
142
164
def custom_tool(input: str) -> str:
143
165
return f"Custom: {input}"
144
166
145
- custom_pool = ToolPool ([custom_tool])
167
+ custom_toolbox = ToolBox ([custom_tool])
146
168
config = AgentConfig({
147
169
"model": "anthropic.claude-3-5-sonnet-20241022-v2:0",
148
170
"prompt": "You are a custom assistant",
149
171
"tools": ["custom_tool"]
150
- }, tool_pool=custom_pool )
172
+ }, tool_box=custom_toolbox )
151
173
agent = config.to_agent()
152
174
"""
153
- # Import here to avoid circular imports:
154
- # experimental/agent_config.py -> agent.agent -> event_loop.event_loop ->
155
- # experimental.hooks -> experimental.__init__.py -> AgentConfig
175
+ # Import at runtime since TYPE_CHECKING import is not available during execution
156
176
from ..agent .agent import Agent
157
177
158
178
# Start with config values
0 commit comments