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 } { 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 }  
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 }  
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