2
2
3
3
This module provides utilities for creating agents from configuration files or dictionaries.
4
4
5
- Note: Configuration-based agent setup only works for tools that don't require code-based
6
- instantiation. For tools that need constructor arguments or complex setup, use the
5
+ Note: Configuration-based agent setup only works for tools that don't require code-based
6
+ instantiation. For tools that need constructor arguments or complex setup, use the
7
7
programmatic approach after creating the agent:
8
8
9
9
agent = config_to_agent("config.json")
10
10
# Add tools that need code-based instantiation
11
11
agent.process_tools([ToolWithConfigArg(HttpsConnection("localhost"))])
12
12
"""
13
13
14
- import importlib
15
14
import json
16
- import os
17
15
from pathlib import Path
16
+ from typing import Any
18
17
19
18
import jsonschema
20
19
from jsonschema import ValidationError
28
27
"description" : "Configuration schema for creating agents" ,
29
28
"type" : "object" ,
30
29
"properties" : {
31
- "name" : {
32
- "description" : "Name of the agent" ,
33
- "type" : ["string" , "null" ],
34
- "default" : None
35
- },
30
+ "name" : {"description" : "Name of the agent" , "type" : ["string" , "null" ], "default" : None },
36
31
"model" : {
37
32
"description" : "The model ID to use for this agent. If not specified, uses the default model." ,
38
33
"type" : ["string" , "null" ],
39
- "default" : None
34
+ "default" : None ,
40
35
},
41
36
"prompt" : {
42
37
"description" : "The system prompt for the agent. Provides high level context to the agent." ,
43
38
"type" : ["string" , "null" ],
44
- "default" : None
39
+ "default" : None ,
45
40
},
46
41
"tools" : {
47
- "description" : "List of tools the agent can use. Can be file paths, Python module names, or @tool annotated functions in files." ,
42
+ "description" : "List of tools the agent can use. Can be file paths, "
43
+ "Python module names, or @tool annotated functions in files." ,
48
44
"type" : "array" ,
49
- "items" : {
50
- "type" : "string"
51
- },
52
- "default" : []
53
- }
45
+ "items" : {"type" : "string" },
46
+ "default" : [],
47
+ },
54
48
},
55
- "additionalProperties" : False
49
+ "additionalProperties" : False ,
56
50
}
57
51
58
52
# Pre-compile validator for better performance
59
53
_VALIDATOR = jsonschema .Draft7Validator (AGENT_CONFIG_SCHEMA )
60
54
61
55
62
- def _is_filepath (tool_path : str ) -> bool :
63
- """Check if the tool string is a file path."""
64
- return os .path .exists (tool_path ) or tool_path .endswith ('.py' )
65
-
66
-
67
- def _validate_tools (tools : list [str ]) -> None :
68
- """Validate that tools can be loaded as files or modules."""
69
- for tool in tools :
70
- if _is_filepath (tool ):
71
- # File path - will be handled by Agent's tool loading
72
- continue
73
-
74
- try :
75
- # Try to import as module
76
- importlib .import_module (tool )
77
- except ImportError :
78
- # Not a file and not a module - check if it might be a function reference
79
- if '.' in tool :
80
- module_path , func_name = tool .rsplit ('.' , 1 )
81
- try :
82
- module = importlib .import_module (module_path )
83
- if not hasattr (module , func_name ):
84
- raise ValueError (
85
- f"Function '{ func_name } ' not found in module '{ module_path } '. "
86
- f"Ensure the function exists and is annotated with @tool."
87
- )
88
- except ImportError :
89
- raise ValueError (
90
- f"Module '{ module_path } ' not found. "
91
- f"Ensure the module exists and is importable, or use a valid file path."
92
- )
93
- else :
94
- raise ValueError (
95
- f"Tool '{ tool } ' not found. "
96
- f"The configured tool is not annotated with @tool, and is not a module or file."
97
- )
98
-
99
-
100
- def config_to_agent (config : str | dict [str , any ], ** kwargs ) -> Agent :
56
+ def config_to_agent (config : str | dict [str , Any ], ** kwargs : dict [str , Any ]) -> Agent :
101
57
"""Create an Agent from a configuration file or dictionary.
102
-
58
+
103
59
This function supports tools that can be loaded declaratively (file paths, module names,
104
60
or @tool annotated functions). For tools requiring code-based instantiation with constructor
105
61
arguments, add them programmatically after creating the agent:
106
-
62
+
107
63
agent = config_to_agent("config.json")
108
64
agent.process_tools([ToolWithConfigArg(HttpsConnection("localhost"))])
109
-
65
+
110
66
Args:
111
67
config: Either a file path (with optional file:// prefix) or a configuration dictionary
112
68
**kwargs: Additional keyword arguments to pass to the Agent constructor
113
-
69
+
114
70
Returns:
115
71
Agent: A configured Agent instance
116
-
72
+
117
73
Raises:
118
74
FileNotFoundError: If the configuration file doesn't exist
119
75
json.JSONDecodeError: If the configuration file contains invalid JSON
120
76
ValueError: If the configuration is invalid or tools cannot be loaded
121
-
77
+
122
78
Examples:
123
79
Create agent from file:
124
80
>>> agent = config_to_agent("/path/to/config.json")
125
-
81
+
126
82
Create agent from file with file:// prefix:
127
83
>>> agent = config_to_agent("file:///path/to/config.json")
128
-
84
+
129
85
Create agent from dictionary:
130
86
>>> config = {"model": "anthropic.claude-3-5-sonnet-20241022-v2:0", "tools": ["calculator"]}
131
87
>>> agent = config_to_agent(config)
@@ -134,53 +90,49 @@ def config_to_agent(config: str | dict[str, any], **kwargs) -> Agent:
134
90
if isinstance (config , str ):
135
91
# Handle file path
136
92
file_path = config
137
-
93
+
138
94
# Remove file:// prefix if present
139
95
if file_path .startswith ("file://" ):
140
96
file_path = file_path [7 :]
141
-
97
+
142
98
# Load JSON from file
143
99
config_path = Path (file_path )
144
100
if not config_path .exists ():
145
101
raise FileNotFoundError (f"Configuration file not found: { file_path } " )
146
-
147
- with open (config_path , 'r' ) as f :
102
+
103
+ with open (config_path , "r" ) as f :
148
104
config_dict = json .load (f )
149
105
elif isinstance (config , dict ):
150
106
config_dict = config .copy ()
151
107
else :
152
108
raise ValueError ("Config must be a file path string or dictionary" )
153
-
109
+
154
110
# Validate configuration against schema
155
111
try :
156
112
_VALIDATOR .validate (config_dict )
157
113
except ValidationError as e :
158
114
# Provide more detailed error message
159
115
error_path = " -> " .join (str (p ) for p in e .absolute_path ) if e .absolute_path else "root"
160
116
raise ValueError (f"Configuration validation error at { error_path } : { e .message } " ) from e
161
-
162
- # Validate tools can be loaded
163
- if "tools" in config_dict and config_dict ["tools" ]:
164
- _validate_tools (config_dict ["tools" ])
165
-
117
+
166
118
# Prepare Agent constructor arguments
167
119
agent_kwargs = {}
168
-
120
+
169
121
# Map configuration keys to Agent constructor parameters
170
122
config_mapping = {
171
123
"model" : "model" ,
172
- "prompt" : "system_prompt" ,
124
+ "prompt" : "system_prompt" ,
173
125
"tools" : "tools" ,
174
126
"name" : "name" ,
175
127
}
176
-
128
+
177
129
# Only include non-None values from config
178
130
for config_key , agent_param in config_mapping .items ():
179
131
if config_key in config_dict and config_dict [config_key ] is not None :
180
132
agent_kwargs [agent_param ] = config_dict [config_key ]
181
-
133
+
182
134
# Override with any additional kwargs provided
183
135
agent_kwargs .update (kwargs )
184
-
136
+
185
137
# Create and return Agent
186
138
return Agent (** agent_kwargs )
0 commit comments