Skip to content

Commit 6bec982

Browse files
committed
clean up tools creation and AzureAIAgent
1 parent 67cd66b commit 6bec982

File tree

3 files changed

+28
-180
lines changed

3 files changed

+28
-180
lines changed

src/backend/app_config.py

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from semantic_kernel.kernel import Kernel
1010
from semantic_kernel.contents import ChatHistory
1111
from semantic_kernel.agents.azure_ai.azure_ai_agent import AzureAIAgent
12+
from semantic_kernel.functions import KernelFunction
1213

1314
# Load environment variables from .env file
1415
load_dotenv()
@@ -193,9 +194,7 @@ async def create_azure_ai_agent(
193194
kernel: Kernel,
194195
agent_name: str,
195196
instructions: str,
196-
agent_type: str = "assistant",
197-
tools=None,
198-
tool_resources=None,
197+
tools: Optional[List[KernelFunction]] = None,
199198
response_format=None,
200199
temperature: float = 0.0,
201200
):
@@ -228,7 +227,10 @@ async def create_azure_ai_agent(
228227

229228
# Create the agent instance directly with project_client and existing definition
230229
agent = AzureAIAgent(
231-
client=project_client, definition=existing_definition, kernel=kernel
230+
client=project_client,
231+
definition=existing_definition,
232+
kernel=kernel,
233+
plugins=tools,
232234
)
233235

234236
logging.info(
@@ -248,53 +250,23 @@ async def create_azure_ai_agent(
248250
f"Unexpected error while retrieving agent {agent_name}: {str(e)}. Attempting to create new agent."
249251
)
250252

251-
# Tool handling: We need to distinguish between our SK functions and
252-
# the tool definitions needed by project_client.agents.create_agent
253-
tool_definitions = None
254-
kernel_functions = []
255-
256-
# If tools are provided and they are SK KernelFunctions, we need to handle them differently
257-
# than if they are already tool definitions expected by AIProjectClient
258-
if tools:
259-
# Check if tools are SK KernelFunctions
260-
if all(
261-
hasattr(tool, "name") and hasattr(tool, "invoke") for tool in tools
262-
):
263-
# Store the kernel functions to register with the agent later
264-
kernel_functions = tools
265-
# For now, we don't extract tool definitions from kernel functions
266-
# This would require additional code to convert SK functions to AI Project tool definitions
267-
logging.warning(
268-
"Kernel functions provided as tools will be registered with the agent after creation"
269-
)
270-
else:
271-
# Assume these are already proper tool definitions for create_agent
272-
tool_definitions = tools
273-
274-
logging.info(f"Creating new agent with ID: {agent_name}")
275-
276253
# Create the agent using the project client with the agent_name as both name and assistantId
277254
agent_definition = await project_client.agents.create_agent(
278255
model=self.AZURE_OPENAI_DEPLOYMENT_NAME,
279256
name=agent_name,
280257
instructions=instructions,
281-
tools=tool_definitions,
282-
tool_resources=tool_resources,
283258
temperature=temperature,
284259
response_format=response_format,
285260
)
286261

287262
# Create the agent instance directly with project_client and definition
288263
agent = AzureAIAgent(
289-
client=project_client, definition=agent_definition, kernel=kernel
264+
client=project_client,
265+
definition=agent_definition,
266+
kernel=kernel,
267+
plugins=tools,
290268
)
291269

292-
# Register the kernel functions with the agent if any were provided
293-
if kernel_functions:
294-
for function in kernel_functions:
295-
if hasattr(agent, "add_function"):
296-
agent.add_function(function)
297-
298270
return agent
299271
except Exception as exc:
300272
logging.error("Failed to create Azure AI Agent: %s", exc)

src/backend/kernel_agents/agent_base.py

Lines changed: 8 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ def __init__(
9595
super().__init__(
9696
kernel=kernel,
9797
deployment_name=None, # Set as needed
98-
plugins=None, # Use the loaded plugins,
98+
plugins=tools, # Use the loaded plugins,
9999
endpoint=None, # Set as needed
100100
api_version=None, # Set as needed
101101
token=None, # Set as needed
@@ -119,9 +119,6 @@ def __init__(
119119
# Required properties for AgentGroupChat compatibility
120120
self.name = agent_name # This is crucial for AgentGroupChat to identify agents
121121

122-
# Register the handler functions
123-
self._register_functions()
124-
125122
# @property
126123
# def plugins(self) -> Optional[dict[str, Callable]]:
127124
# """Get the plugins for this agent.
@@ -140,37 +137,17 @@ async def async_init(self):
140137
141138
This method must be called after creating the agent to complete initialization.
142139
"""
140+
logging.info(f"Initializing agent: {self._agent_name}")
143141
# Create Azure AI Agent or fallback
144142
self._agent = await config.create_azure_ai_agent(
145143
kernel=self._kernel,
146144
agent_name=self._agent_name,
147145
instructions=self._system_message,
146+
tools=self._tools,
148147
)
149148
# Tools are registered with the kernel via get_tools_from_config
150149
return self
151150

152-
def _register_functions(self):
153-
"""Register this agent's functions with the kernel."""
154-
# Use the kernel function decorator approach instead of from_native_method
155-
# which isn't available in SK 1.28.0
156-
function_name = "handle_action_request"
157-
158-
# Define the function using the kernel function decorator
159-
@kernel_function(
160-
description="Handle an action request from another agent or the system",
161-
name=function_name,
162-
)
163-
async def handle_action_request_wrapper(*args, **kwargs):
164-
# Forward to the instance method
165-
return await self.handle_action_request(*args, **kwargs)
166-
167-
# Wrap the decorated function into a KernelFunction and register under this agent's plugin
168-
kernel_func = KernelFunction.from_method(handle_action_request_wrapper)
169-
# Use agent name as plugin for handler
170-
self._kernel.add_function(self._agent_name, kernel_func)
171-
172-
# Required method for AgentGroupChat compatibility
173-
174151
async def handle_action_request(self, action_request: ActionRequest) -> str:
175152
"""Handle an action request from another agent or the system.
176153
@@ -213,9 +190,7 @@ async def handle_action_request(self, action_request: ActionRequest) -> str:
213190

214191
# Call the agent to handle the action
215192
async_generator = self._agent.invoke(
216-
# messages=f"{json.dumps(self._chat_history)}\n\n
217193
messages=f"{action_request.action}\n\nPlease perform this action"
218-
# messages=action_request.action
219194
)
220195

221196
response_content = ""
@@ -312,73 +287,11 @@ async def handle_action_request(self, action_request: ActionRequest) -> str:
312287

313288
return response.json()
314289

315-
async def invoke_tool(self, tool_name: str, arguments: Dict[str, Any]) -> str:
316-
"""Invoke a specific tool by name with the provided arguments.
317-
318-
Args:
319-
tool_name: The name of the tool to invoke
320-
arguments: A dictionary of arguments to pass to the tool
321-
322-
Returns:
323-
The result of the tool invocation as a string
324-
325-
Raises:
326-
ValueError: If the tool is not found
327-
"""
328-
# Find the tool by name in the agent's tools list
329-
tool = next((t for t in self._tools if t.name == tool_name), None)
330-
331-
if not tool:
332-
# Try looking up the tool in the kernel's plugins
333-
plugin_name = f"{self._agent_name.lower().replace('agent', '')}_plugin"
334-
try:
335-
tool = self._kernel.get_function(plugin_name, tool_name)
336-
except Exception:
337-
raise ValueError(
338-
f"Tool '{tool_name}' not found in agent tools or kernel plugins"
339-
)
340-
341-
if not tool:
342-
raise ValueError(f"Tool '{tool_name}' not found")
343-
344-
try:
345-
# Create kernel arguments from the dictionary
346-
kernel_args = KernelArguments()
347-
for key, value in arguments.items():
348-
kernel_args[key] = value
349-
350-
# Invoke the tool
351-
logging.info(f"Invoking tool '{tool_name}' with arguments: {arguments}")
352-
353-
# Use invoke_with_args_dict directly instead of relying on KernelArguments
354-
if hasattr(tool, "invoke_with_args_dict") and callable(
355-
tool.invoke_with_args_dict
356-
):
357-
result = await tool.invoke_with_args_dict(arguments)
358-
else:
359-
# Fall back to standard invoke method
360-
result = await tool.invoke(kernel_args)
361-
362-
# Log telemetry if configured
363-
track_event_if_configured(
364-
"AgentToolInvocation",
365-
{
366-
"agent_name": self._agent_name,
367-
"tool_name": tool_name,
368-
"session_id": self._session_id,
369-
"user_id": self._user_id,
370-
},
371-
)
372-
373-
return str(result)
374-
except Exception as e:
375-
logging.error(f"Error invoking tool '{tool_name}': {str(e)}")
376-
raise
377-
378290
@staticmethod
379291
def create_dynamic_function(
380292
name: str,
381293
response_template: str,
294+
description: Optional[str] = None,
382295
formatting_instr: str = DEFAULT_FORMATTING_INSTRUCTIONS,
383296
) -> Callable[..., Awaitable[str]]:
384297
"""Create a dynamic function for agent tools based on the name and template.
@@ -409,7 +322,10 @@ async def dynamic_function(**kwargs) -> str:
409322
dynamic_function.__name__ = name
410323

411324
# Create a wrapped kernel function that matches the expected signature
412-
@kernel_function(description=f"Dynamic function: {name}", name=name)
325+
logging.info(f"Creating dynamic function: {name} {len(name)}")
326+
logging.info(f"Description: {description} {len(description)}")
327+
328+
@kernel_function(description=f"Dynamic function {name}", name=name)
413329
async def kernel_wrapper(
414330
kernel_arguments: KernelArguments = None, **kwargs
415331
) -> str:

src/backend/kernel_agents/agent_factory.py

Lines changed: 10 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -192,17 +192,14 @@ async def create_agent(
192192
# Create the agent definition using the AIProjectClient (project-based pattern)
193193
# For GroupChatManager, create a definition with minimal configuration
194194
if client is not None:
195-
try:
196-
definition = await client.agents.get_agent(agent_type_str)
197-
198-
except Exception as get_agent_exc:
199-
definition = await client.agents.create_agent(
200-
model=config.AZURE_OPENAI_DEPLOYMENT_NAME,
201-
name=agent_type_str,
202-
instructions=system_message,
203-
temperature=temperature,
204-
response_format=response_format, # Add response_format if required
205-
)
195+
196+
definition = await client.agents.create_agent(
197+
model=config.AZURE_OPENAI_DEPLOYMENT_NAME,
198+
name=agent_type_str,
199+
instructions=system_message,
200+
temperature=temperature,
201+
response_format=response_format, # Add response_format if required
202+
)
206203
logger.info(
207204
f"Successfully created agent definition for {agent_type_str}"
208205
)
@@ -242,14 +239,7 @@ async def create_agent(
242239
):
243240
init_result = await agent.async_init()
244241
logger.info(f"[DEBUG] Result of agent.async_init(): {init_result}")
245-
# Register tools with Azure AI Agent for LLM function calls
246-
if (
247-
hasattr(agent, "_agent")
248-
and hasattr(agent._agent, "add_function")
249-
and tools
250-
):
251-
for fn in tools:
252-
agent._agent.add_function(fn)
242+
253243
except Exception as e:
254244
logger.error(
255245
f"Error creating agent of type {agent_type} with parameters: {e}"
@@ -292,37 +282,7 @@ async def _load_tools_for_agent(
292282
return []
293283
except Exception as e:
294284
logger.warning(f"Error loading tools for {agent_type}: {e}")
295-
296-
# For other agent types, try to create a simple fallback tool
297-
try:
298-
# Use PromptTemplateConfig to create a simple tool
299-
300-
# Simple minimal prompt
301-
prompt = f"""You are a helpful assistant specialized in {agent_type} tasks. User query: {{$input}} Provide a helpful response."""
302-
303-
# Create a prompt template config
304-
prompt_config = PromptTemplateConfig(
305-
template=prompt,
306-
name=f"{agent_type}_help_with_tasks",
307-
description=f"A helper function for {agent_type} tasks",
308-
)
309-
310-
# Create the function using the prompt_config with explicit plugin_name
311-
function = KernelFunction.from_prompt(
312-
function_name=f"{agent_type}_help_with_tasks",
313-
plugin_name=f"{agent_type}_fallback_plugin",
314-
description=f"A helper function for {agent_type} tasks",
315-
prompt_template_config=prompt_config,
316-
)
317-
318-
logger.info(f"Created fallback tool for {agent_type}")
319-
return [function]
320-
except Exception as fallback_error:
321-
logger.error(
322-
f"Failed to create fallback tool for {agent_type}: {fallback_error}"
323-
)
324-
# Return an empty list if everything fails - the agent can still function without tools
325-
return []
285+
return []
326286

327287
@classmethod
328288
async def create_all_agents(

0 commit comments

Comments
 (0)