22
33This module provides utilities for creating agents from configuration files or dictionaries.
44
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
77programmatic approach after creating the agent:
88
99 agent = config_to_agent("config.json")
1010 # Add tools that need code-based instantiation
1111 agent.process_tools([ToolWithConfigArg(HttpsConnection("localhost"))])
1212"""
1313
14- import importlib
1514import json
16- import os
1715from pathlib import Path
16+ from typing import Any
1817
1918import jsonschema
2019from jsonschema import ValidationError
2827 "description" : "Configuration schema for creating agents" ,
2928 "type" : "object" ,
3029 "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 },
3631 "model" : {
3732 "description" : "The model ID to use for this agent. If not specified, uses the default model." ,
3833 "type" : ["string" , "null" ],
39- "default" : None
34+ "default" : None ,
4035 },
4136 "prompt" : {
4237 "description" : "The system prompt for the agent. Provides high level context to the agent." ,
4338 "type" : ["string" , "null" ],
44- "default" : None
39+ "default" : None ,
4540 },
4641 "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." ,
4844 "type" : "array" ,
49- "items" : {
50- "type" : "string"
51- },
52- "default" : []
53- }
45+ "items" : {"type" : "string" },
46+ "default" : [],
47+ },
5448 },
55- "additionalProperties" : False
49+ "additionalProperties" : False ,
5650}
5751
5852# Pre-compile validator for better performance
5953_VALIDATOR = jsonschema .Draft7Validator (AGENT_CONFIG_SCHEMA )
6054
6155
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 :
10157 """Create an Agent from a configuration file or dictionary.
102-
58+
10359 This function supports tools that can be loaded declaratively (file paths, module names,
10460 or @tool annotated functions). For tools requiring code-based instantiation with constructor
10561 arguments, add them programmatically after creating the agent:
106-
62+
10763 agent = config_to_agent("config.json")
10864 agent.process_tools([ToolWithConfigArg(HttpsConnection("localhost"))])
109-
65+
11066 Args:
11167 config: Either a file path (with optional file:// prefix) or a configuration dictionary
11268 **kwargs: Additional keyword arguments to pass to the Agent constructor
113-
69+
11470 Returns:
11571 Agent: A configured Agent instance
116-
72+
11773 Raises:
11874 FileNotFoundError: If the configuration file doesn't exist
11975 json.JSONDecodeError: If the configuration file contains invalid JSON
12076 ValueError: If the configuration is invalid or tools cannot be loaded
121-
77+
12278 Examples:
12379 Create agent from file:
12480 >>> agent = config_to_agent("/path/to/config.json")
125-
81+
12682 Create agent from file with file:// prefix:
12783 >>> agent = config_to_agent("file:///path/to/config.json")
128-
84+
12985 Create agent from dictionary:
13086 >>> config = {"model": "anthropic.claude-3-5-sonnet-20241022-v2:0", "tools": ["calculator"]}
13187 >>> agent = config_to_agent(config)
@@ -134,53 +90,49 @@ def config_to_agent(config: str | dict[str, any], **kwargs) -> Agent:
13490 if isinstance (config , str ):
13591 # Handle file path
13692 file_path = config
137-
93+
13894 # Remove file:// prefix if present
13995 if file_path .startswith ("file://" ):
14096 file_path = file_path [7 :]
141-
97+
14298 # Load JSON from file
14399 config_path = Path (file_path )
144100 if not config_path .exists ():
145101 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 :
148104 config_dict = json .load (f )
149105 elif isinstance (config , dict ):
150106 config_dict = config .copy ()
151107 else :
152108 raise ValueError ("Config must be a file path string or dictionary" )
153-
109+
154110 # Validate configuration against schema
155111 try :
156112 _VALIDATOR .validate (config_dict )
157113 except ValidationError as e :
158114 # Provide more detailed error message
159115 error_path = " -> " .join (str (p ) for p in e .absolute_path ) if e .absolute_path else "root"
160116 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+
166118 # Prepare Agent constructor arguments
167119 agent_kwargs = {}
168-
120+
169121 # Map configuration keys to Agent constructor parameters
170122 config_mapping = {
171123 "model" : "model" ,
172- "prompt" : "system_prompt" ,
124+ "prompt" : "system_prompt" ,
173125 "tools" : "tools" ,
174126 "name" : "name" ,
175127 }
176-
128+
177129 # Only include non-None values from config
178130 for config_key , agent_param in config_mapping .items ():
179131 if config_key in config_dict and config_dict [config_key ] is not None :
180132 agent_kwargs [agent_param ] = config_dict [config_key ]
181-
133+
182134 # Override with any additional kwargs provided
183135 agent_kwargs .update (kwargs )
184-
136+
185137 # Create and return Agent
186138 return Agent (** agent_kwargs )
0 commit comments