1- import logging
21import json
2+ import logging
33import os
4- from typing import Any , Dict , List , Mapping , Optional , Callable , Awaitable
4+ from typing import Any , Awaitable , Callable , Dict , List , Mapping , Optional , Union
55
66import semantic_kernel as sk
7+ from semantic_kernel .agents .azure_ai .azure_ai_agent import AzureAIAgent
78from semantic_kernel .functions import KernelFunction
8- from semantic_kernel .functions .kernel_function_decorator import kernel_function
99from semantic_kernel .functions .kernel_arguments import KernelArguments
10- from semantic_kernel .agents .azure_ai .azure_ai_agent import AzureAIAgent
10+ from semantic_kernel .functions .kernel_function_decorator import kernel_function
11+ from semantic_kernel .agents import AzureAIAgentThread
1112
1213# Updated imports for compatibility
1314try :
1415 # Try importing from newer structure first
15- from semantic_kernel .contents import ChatMessageContent , ChatHistory
16+ from semantic_kernel .contents import ChatHistory , ChatMessageContent
1617except ImportError :
1718 # Fall back to older structure for compatibility
1819 class ChatMessageContent :
@@ -30,7 +31,10 @@ def __init__(self):
3031 self .messages = []
3132
3233
34+ # Import the new AppConfig instance
35+ from app_config import config
3336from context .cosmos_memory_kernel import CosmosMemoryContext
37+ from event_utils import track_event_if_configured
3438from models .messages_kernel import (
3539 ActionRequest ,
3640 ActionResponse ,
@@ -39,10 +43,6 @@ def __init__(self):
3943 StepStatus ,
4044)
4145
42- # Import the new AppConfig instance
43- from app_config import config
44- from event_utils import track_event_if_configured
45-
4646# Default formatting instructions used across agents
4747DEFAULT_FORMATTING_INSTRUCTIONS = "Instructions: returning the output of this function call verbatim to the user in markdown. Then write AGENT SUMMARY: and then include a summary of what you did."
4848
@@ -77,6 +77,8 @@ def __init__(
7777 client: The client required by AzureAIAgent
7878 definition: The definition required by AzureAIAgent
7979 """
80+ # Add plugins if not already set
81+ # if not self.plugins:
8082 # If agent_type is provided, load tools from config automatically
8183 if agent_type and not tools :
8284 tools = self .get_tools_from_config (kernel , agent_type )
@@ -94,6 +96,7 @@ def __init__(
9496 super ().__init__ (
9597 kernel = kernel ,
9698 deployment_name = None , # Set as needed
99+ plugins = tools , # Use the loaded plugins,
97100 endpoint = None , # Set as needed
98101 api_version = None , # Set as needed
99102 token = None , # Set as needed
@@ -117,8 +120,14 @@ def __init__(
117120 # Required properties for AgentGroupChat compatibility
118121 self .name = agent_name # This is crucial for AgentGroupChat to identify agents
119122
120- # Register the handler functions
121- self ._register_functions ()
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
122131
123132 def _default_system_message (self , agent_name = None ) -> str :
124133 name = agent_name or getattr (self , "_agent_name" , "Agent" )
@@ -129,37 +138,17 @@ async def async_init(self):
129138
130139 This method must be called after creating the agent to complete initialization.
131140 """
141+ logging .info (f"Initializing agent: { self ._agent_name } " )
132142 # Create Azure AI Agent or fallback
133143 self ._agent = await config .create_azure_ai_agent (
134144 kernel = self ._kernel ,
135145 agent_name = self ._agent_name ,
136146 instructions = self ._system_message ,
147+ tools = self ._tools ,
137148 )
138149 # Tools are registered with the kernel via get_tools_from_config
139150 return self
140151
141- def _register_functions (self ):
142- """Register this agent's functions with the kernel."""
143- # Use the kernel function decorator approach instead of from_native_method
144- # which isn't available in SK 1.28.0
145- function_name = "handle_action_request"
146-
147- # Define the function using the kernel function decorator
148- @kernel_function (
149- description = "Handle an action request from another agent or the system" ,
150- name = function_name ,
151- )
152- async def handle_action_request_wrapper (* args , ** kwargs ):
153- # Forward to the instance method
154- return await self .handle_action_request (* args , ** kwargs )
155-
156- # Wrap the decorated function into a KernelFunction and register under this agent's plugin
157- kernel_func = KernelFunction .from_method (handle_action_request_wrapper )
158- # Use agent name as plugin for handler
159- self ._kernel .add_function (self ._agent_name , kernel_func )
160-
161- # Required method for AgentGroupChat compatibility
162-
163152 async def handle_action_request (self , action_request : ActionRequest ) -> str :
164153 """Handle an action request from another agent or the system.
165154
@@ -201,8 +190,13 @@ async def handle_action_request(self, action_request: ActionRequest) -> str:
201190 # chat_history = self._chat_history.copy()
202191
203192 # Call the agent to handle the action
193+ thread = None
194+ # thread = self.client.agents.get_thread(
195+ # thread=step.session_id
196+ # ) # AzureAIAgentThread(thread_id=step.session_id)
204197 async_generator = self ._agent .invoke (
205- f"{ action_request .action } \n \n Please perform this action"
198+ messages = f"{ action_request .action } \n \n Please perform this action" ,
199+ thread = thread ,
206200 )
207201
208202 response_content = ""
@@ -299,73 +293,11 @@ async def handle_action_request(self, action_request: ActionRequest) -> str:
299293
300294 return response .json ()
301295
302- async def invoke_tool (self , tool_name : str , arguments : Dict [str , Any ]) -> str :
303- """Invoke a specific tool by name with the provided arguments.
304-
305- Args:
306- tool_name: The name of the tool to invoke
307- arguments: A dictionary of arguments to pass to the tool
308-
309- Returns:
310- The result of the tool invocation as a string
311-
312- Raises:
313- ValueError: If the tool is not found
314- """
315- # Find the tool by name in the agent's tools list
316- tool = next ((t for t in self ._tools if t .name == tool_name ), None )
317-
318- if not tool :
319- # Try looking up the tool in the kernel's plugins
320- plugin_name = f"{ self ._agent_name .lower ().replace ('agent' , '' )} _plugin"
321- try :
322- tool = self ._kernel .get_function (plugin_name , tool_name )
323- except Exception :
324- raise ValueError (
325- f"Tool '{ tool_name } ' not found in agent tools or kernel plugins"
326- )
327-
328- if not tool :
329- raise ValueError (f"Tool '{ tool_name } ' not found" )
330-
331- try :
332- # Create kernel arguments from the dictionary
333- kernel_args = KernelArguments ()
334- for key , value in arguments .items ():
335- kernel_args [key ] = value
336-
337- # Invoke the tool
338- logging .info (f"Invoking tool '{ tool_name } ' with arguments: { arguments } " )
339-
340- # Use invoke_with_args_dict directly instead of relying on KernelArguments
341- if hasattr (tool , "invoke_with_args_dict" ) and callable (
342- tool .invoke_with_args_dict
343- ):
344- result = await tool .invoke_with_args_dict (arguments )
345- else :
346- # Fall back to standard invoke method
347- result = await tool .invoke (kernel_args )
348-
349- # Log telemetry if configured
350- track_event_if_configured (
351- "AgentToolInvocation" ,
352- {
353- "agent_name" : self ._agent_name ,
354- "tool_name" : tool_name ,
355- "session_id" : self ._session_id ,
356- "user_id" : self ._user_id ,
357- },
358- )
359-
360- return str (result )
361- except Exception as e :
362- logging .error (f"Error invoking tool '{ tool_name } ': { str (e )} " )
363- raise
364-
365296 @staticmethod
366297 def create_dynamic_function (
367298 name : str ,
368299 response_template : str ,
300+ description : Optional [str ] = None ,
369301 formatting_instr : str = DEFAULT_FORMATTING_INSTRUCTIONS ,
370302 ) -> Callable [..., Awaitable [str ]]:
371303 """Create a dynamic function for agent tools based on the name and template.
@@ -379,6 +311,13 @@ def create_dynamic_function(
379311 A dynamic async function that can be registered with the semantic kernel
380312 """
381313
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+
382321 async def dynamic_function (** kwargs ) -> str :
383322 try :
384323 # Format the template with the provided kwargs
@@ -396,7 +335,9 @@ async def dynamic_function(**kwargs) -> str:
396335 dynamic_function .__name__ = name
397336
398337 # Create a wrapped kernel function that matches the expected signature
399- @kernel_function (description = f"Dynamic function: { name } " , name = name )
338+ logging .info (f"Creating dynamic function: { name } { len (name )} " )
339+
340+ @kernel_function (description = f"Dynamic function { name } " , name = name )
400341 async def kernel_wrapper (
401342 kernel_arguments : KernelArguments = None , ** kwargs
402343 ) -> str :
@@ -477,7 +418,7 @@ def get_tools_from_config(
477418 plugin_name = f"{ agent_type } _plugin"
478419
479420 # Early return if no tools defined - prevent empty iteration
480- if not config .get ("tools" ):
421+ if not config .get ("tools" ): # or agent_type == "Product_Agent":
481422 logging .info (
482423 f"No tools defined for agent type '{ agent_type } '. Returning empty list."
483424 )
@@ -513,7 +454,7 @@ def get_tools_from_config(
513454 )
514455
515456 # Register the function with the kernel
516- kernel . add_function ( plugin_name , kernel_func )
457+
517458 kernel_functions .append (kernel_func )
518459 logging .info (
519460 f"Successfully created dynamic tool '{ function_name } ' for { agent_type } "
0 commit comments