@@ -59,7 +59,6 @@ def __init__(
5959 memory_store : CosmosMemoryContext ,
6060 tools : Optional [List [KernelFunction ]] = None ,
6161 system_message : Optional [str ] = None ,
62- agent_type : Optional [str ] = None ,
6362 client = None ,
6463 definition = None ,
6564 ):
@@ -77,20 +76,9 @@ def __init__(
7776 client: The client required by AzureAIAgent
7877 definition: The definition required by AzureAIAgent
7978 """
80- # Add plugins if not already set
81- # if not self.plugins:
82- # If agent_type is provided, load tools from config automatically
83- if agent_type and not tools :
84- tools = self .get_tools_from_config (kernel , agent_type )
85- # If system_message isn't provided, try to get it from config
86- if not system_message :
87- config = self .load_tools_config (agent_type )
88- system_message = config .get (
89- "system_message" , self ._default_system_message (agent_name )
90- )
91- else :
92- tools = tools or []
93- system_message = system_message or self ._default_system_message (agent_name )
79+
80+ tools = tools or []
81+ system_message = system_message or self .default_system_message (agent_name )
9482
9583 # Call AzureAIAgent constructor with required client and definition
9684 super ().__init__ (
@@ -128,9 +116,9 @@ def __init__(
128116 # A list of plugins, or None if not applicable.
129117 # """
130118 # return None
131-
132- def _default_system_message ( self , agent_name = None ) -> str :
133- name = agent_name or getattr ( self , "_agent_name" , "Agent" )
119+ @ staticmethod
120+ def default_system_message ( agent_name = None ) -> str :
121+ name = agent_name
134122 return f"You are an AI assistant named { name } . Help the user by providing accurate and helpful information."
135123
136124 async def async_init (self ):
@@ -293,179 +281,6 @@ async def handle_action_request(self, action_request: ActionRequest) -> str:
293281
294282 return response .json ()
295283
296- @staticmethod
297- def create_dynamic_function (
298- name : str ,
299- response_template : str ,
300- description : Optional [str ] = None ,
301- formatting_instr : str = DEFAULT_FORMATTING_INSTRUCTIONS ,
302- ) -> Callable [..., Awaitable [str ]]:
303- """Create a dynamic function for agent tools based on the name and template.
304-
305- Args:
306- name: The name of the function to create
307- response_template: The template string to use for the response
308- formatting_instr: Optional formatting instructions to append to the response
309-
310- Returns:
311- A dynamic async function that can be registered with the semantic kernel
312- """
313-
314- # Truncate function name to 64 characters if it exceeds the limit
315- if len (name ) > 64 :
316- logging .warning (
317- f"Function name '{ name } ' exceeds 64 characters (length: { len (name )} ). Truncating to 64 characters."
318- )
319- name = name [:64 ]
320-
321- async def dynamic_function (** kwargs ) -> str :
322- try :
323- # Format the template with the provided kwargs
324- formatted_response = response_template .format (** kwargs )
325- # Append formatting instructions if not already included in the template
326- if formatting_instr and formatting_instr not in formatted_response :
327- formatted_response = f"{ formatted_response } \n { formatting_instr } "
328- return formatted_response
329- except KeyError as e :
330- return f"Error: Missing parameter { e } for { name } "
331- except Exception as e :
332- return f"Error processing { name } : { str (e )} "
333-
334- # Name the function properly for better debugging
335- dynamic_function .__name__ = name
336-
337- # Create a wrapped kernel function that matches the expected signature
338- logging .info (f"Creating dynamic function: { name } { len (name )} " )
339-
340- @kernel_function (description = f"Dynamic function { name } " , name = name )
341- async def kernel_wrapper (
342- kernel_arguments : KernelArguments = None , ** kwargs
343- ) -> str :
344- # Combine all arguments into one dictionary
345- all_args = {}
346- if kernel_arguments :
347- for key , value in kernel_arguments .items ():
348- all_args [key ] = value
349- all_args .update (kwargs )
350- return await dynamic_function (** all_args )
351-
352- return kernel_wrapper
353-
354- @staticmethod
355- def load_tools_config (
356- filename : str , config_path : Optional [str ] = None
357- ) -> Dict [str , Any ]:
358- """Load tools configuration from a JSON file.
359-
360- Args:
361- filename: The filename without extension (e.g., "hr", "marketing")
362- config_path: Optional explicit path to the configuration file
363-
364- Returns:
365- A dictionary containing the configuration
366- """
367- if config_path is None :
368- # Default path relative to the tools directory
369- current_dir = os .path .dirname (os .path .abspath (__file__ ))
370- backend_dir = os .path .dirname (
371- current_dir
372- ) # Just one level up to get to backend dir
373-
374- # Normalize filename to avoid issues with spaces and capitalization
375- # Convert "Hr Agent" to "hr" and "TechSupport Agent" to "tech_support"
376- logging .info (f"Normalizing filename: { filename } " )
377- normalized_filename = filename .replace (" " , "_" ).replace ("-" , "_" ).lower ()
378- # If it ends with "_agent", remove it
379- if normalized_filename .endswith ("_agent" ):
380- normalized_filename = normalized_filename [:- 6 ]
381-
382- config_path = os .path .join (
383- backend_dir , "tools" , f"{ normalized_filename } _tools.json"
384- )
385- logging .info (f"Looking for tools config at: { config_path } " )
386-
387- try :
388- with open (config_path , "r" ) as f :
389- return json .load (f )
390- except Exception as e :
391- logging .error (f"Error loading { filename } tools configuration: { e } " )
392- # Return empty default configuration
393- return {
394- "agent_name" : f"{ filename .capitalize ()} Agent" ,
395- "system_message" : "You are an AI assistant" ,
396- "tools" : [],
397- }
398-
399- @classmethod
400- def get_tools_from_config (
401- cls , kernel : sk .Kernel , agent_type : str , config_path : Optional [str ] = None
402- ) -> List [KernelFunction ]:
403- """Get the list of tools for an agent from configuration.
404-
405- Args:
406- kernel: The semantic kernel instance
407- agent_type: The type of agent (e.g., "marketing", "hr")
408- config_path: Optional explicit path to the configuration file
409-
410- Returns:
411- A list of KernelFunction objects representing the tools
412- """
413- # Load configuration
414- config = cls .load_tools_config (agent_type , config_path )
415-
416- # Convert the configured tools to kernel functions
417- kernel_functions = []
418- plugin_name = f"{ agent_type } _plugin"
419-
420- # Early return if no tools defined - prevent empty iteration
421- if not config .get ("tools" ): # or agent_type == "Product_Agent":
422- logging .info (
423- f"No tools defined for agent type '{ agent_type } '. Returning empty list."
424- )
425- return kernel_functions
426-
427- for tool in config .get ("tools" , []):
428- try :
429- function_name = tool ["name" ]
430- description = tool .get ("description" , "" )
431- # Create a dynamic function using the JSON response_template
432- response_template = (
433- tool .get ("response_template" ) or tool .get ("prompt_template" ) or ""
434- )
435-
436- # Generate a dynamic function using our improved approach
437- dynamic_fn = cls .create_dynamic_function (
438- function_name , response_template
439- )
440-
441- # Create kernel function from the decorated function
442- kernel_func = KernelFunction .from_method (dynamic_fn )
443-
444- # Add parameter metadata from JSON to the kernel function
445- for param in tool .get ("parameters" , []):
446- param_name = param .get ("name" , "" )
447- param_desc = param .get ("description" , "" )
448- param_type = param .get ("type" , "string" )
449-
450- # Set this parameter in the function's metadata
451- if param_name :
452- logging .info (
453- f"Adding parameter '{ param_name } ' to function '{ function_name } '"
454- )
455-
456- # Register the function with the kernel
457-
458- kernel_functions .append (kernel_func )
459- logging .info (
460- f"Successfully created dynamic tool '{ function_name } ' for { agent_type } "
461- )
462- except Exception as e :
463- logging .error (
464- f"Failed to create tool '{ tool .get ('name' , 'unknown' )} ': { str (e )} "
465- )
466-
467- return kernel_functions
468-
469284 def save_state (self ) -> Mapping [str , Any ]:
470285 """Save the state of this agent."""
471286 return {"memory" : self ._memory_store .save_state ()}
0 commit comments