|
8 | 8 | from semantic_kernel.functions import KernelFunction |
9 | 9 | from semantic_kernel.functions.kernel_arguments import KernelArguments |
10 | 10 | from semantic_kernel.functions.kernel_function_decorator import kernel_function |
11 | | -from semantic_kernel.agents import AzureAIAgentThread |
12 | 11 |
|
13 | 12 | # Updated imports for compatibility |
14 | 13 | try: |
@@ -78,18 +77,7 @@ def __init__( |
78 | 77 | definition: The definition required by AzureAIAgent |
79 | 78 | """ |
80 | 79 | # 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 [] |
| 80 | + tools = tools or [] |
93 | 81 | system_message = system_message or self._default_system_message(agent_name) |
94 | 82 |
|
95 | 83 | # Call AzureAIAgent constructor with required client and definition |
@@ -120,15 +108,6 @@ def __init__( |
120 | 108 | # Required properties for AgentGroupChat compatibility |
121 | 109 | self.name = agent_name # This is crucial for AgentGroupChat to identify agents |
122 | 110 |
|
123 | | - # @property |
124 | | - # def plugins(self) -> Optional[dict[str, Callable]]: |
125 | | - # """Get the plugins for this agent. |
126 | | - |
127 | | - # Returns: |
128 | | - # A list of plugins, or None if not applicable. |
129 | | - # """ |
130 | | - # return None |
131 | | - |
132 | 111 | def _default_system_message(self, agent_name=None) -> str: |
133 | 112 | name = agent_name or getattr(self, "_agent_name", "Agent") |
134 | 113 | return f"You are an AI assistant named {name}. Help the user by providing accurate and helpful information." |
@@ -186,14 +165,10 @@ async def handle_action_request(self, action_request: ActionRequest) -> str: |
186 | 165 | ) |
187 | 166 |
|
188 | 167 | try: |
189 | | - # Use the agent to process the action |
190 | | - # chat_history = self._chat_history.copy() |
191 | 168 |
|
192 | 169 | # Call the agent to handle the action |
193 | 170 | thread = None |
194 | | - # thread = self.client.agents.get_thread( |
195 | | - # thread=step.session_id |
196 | | - # ) # AzureAIAgentThread(thread_id=step.session_id) |
| 171 | + |
197 | 172 | async_generator = self._agent.invoke( |
198 | 173 | messages=f"{action_request.action}\n\nPlease perform this action", |
199 | 174 | thread=thread, |
@@ -293,179 +268,6 @@ async def handle_action_request(self, action_request: ActionRequest) -> str: |
293 | 268 |
|
294 | 269 | return response.json() |
295 | 270 |
|
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 | | - |
469 | 271 | def save_state(self) -> Mapping[str, Any]: |
470 | 272 | """Save the state of this agent.""" |
471 | 273 | return {"memory": self._memory_store.save_state()} |
|
0 commit comments