Skip to content

Commit c135a4e

Browse files
author
Davide Antelmo
committed
tools refactoring. customization guide. github copilot local-dev skill
1 parent c0ca377 commit c135a4e

16 files changed

Lines changed: 3228 additions & 1228 deletions

File tree

Lines changed: 332 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,332 @@
1+
---
2+
name: create-update-new-agent
3+
description: This skill provides instructions for creating or updating a new agent in the banking assistant project. It covers defining agent behavior, integrating with backend services, and testing the agent.
4+
license: MIT
5+
---
6+
7+
Follow these steps to create and integrate a new agent into the system:
8+
9+
#### Step 1: Create the Agent File
10+
11+
Choose the implementation version you're working with:
12+
- **Azure Chat version**: `app/backend/app/agents/azure_chat/your_agent_name.py`
13+
- **Foundry v2 version**: `app/backend/app/agents/foundry_v2/your_agent_name.py`
14+
15+
Create a new Python file for your agent:
16+
17+
**For Azure Chat version:**
18+
```python
19+
from agent_framework.azure import AzureOpenAIChatClient
20+
from agent_framework import Agent, MCPStreamableHTTPTool
21+
from datetime import datetime
22+
import logging
23+
24+
logger = logging.getLogger(__name__)
25+
26+
class YourAgentName:
27+
"""
28+
Your agent description and purpose.
29+
"""
30+
31+
instructions = """
32+
You are a specialized agent for [specific domain].
33+
Your responsibilities include:
34+
- [Responsibility 1]
35+
- [Responsibility 2]
36+
- [Responsibility 3]
37+
38+
"""
39+
40+
name = "YourAgentName"
41+
description = "This agent handles [brief description of agent's purpose]"
42+
43+
def __init__(self,
44+
azure_chat_client: AzureOpenAIChatClient,
45+
your_service_mcp_server_url: str):
46+
self.azure_chat_client = azure_chat_client
47+
self.your_service_mcp_server_url = your_service_mcp_server_url
48+
49+
async def build_af_agent(self) -> Agent:
50+
"""Build and return the Agent with dynamic context."""
51+
52+
logger.info(f"Initializing MCP server tools for {self.name}")
53+
54+
# Use async context manager for MCP tools
55+
async with MCPStreamableHTTPTool(
56+
name="Your Service MCP client",
57+
url=self.your_service_mcp_server_url
58+
) as your_mcp_server:
59+
60+
return Agent(
61+
client=self.azure_chat_client,
62+
instructions=YourAgentName.instructions,
63+
name=YourAgentName.name,
64+
tools=[your_mcp_server],
65+
)
66+
```
67+
68+
**For Foundry v2 version:**
69+
```python
70+
from agent_framework.azure import AzureAIClient
71+
from agent_framework import Agent, MCPStreamableHTTPTool
72+
# Similar structure but use AzureAIClient instead of AzureOpenAIChatClient
73+
```
74+
75+
#### Step 2: Define Agent Tools
76+
77+
If your agent needs custom tools, create them in `app/backend/app/tools/`:
78+
79+
```python
80+
# app/backend/app/tools/your_tool.py
81+
from typing import Annotated
82+
from agent_framework._tools import tool
83+
from pydantic import Field
84+
85+
class YourToolHelper:
86+
"""Helper class for your custom tool functionality."""
87+
88+
def __init__(self, dependency_service=None):
89+
"""Initialize the tool helper with any required dependencies."""
90+
self.dependency_service = dependency_service
91+
92+
@tool
93+
def your_custom_tool(
94+
self,
95+
param1: Annotated[str, Field(description="Description of param1")],
96+
param2: Annotated[int, Field(description="Description of param2")]
97+
) -> Annotated[dict, Field(description="Returns a dictionary with processing results")]:
98+
"""Tool description for the LLM. This docstring explains what the tool does."""
99+
# Implement tool logic
100+
result = {"status": "success", "data": f"Processed {param1} with {param2}"}
101+
return result
102+
```
103+
104+
**Key Points:**
105+
- Use `@tool` decorator from `agent_framework._tools`
106+
- Use `Annotated[type, Field(description="...")]` for parameters and return type
107+
- The docstring serves as the tool description for the LLM
108+
- Wrap tools in a class for better organization and dependency injection
109+
110+
**Register the tool in the DI container:**
111+
112+
Register your tool helper in `app/backend/app/config/container_azure_chat.py` (or `container_foundry_v2.py`):
113+
114+
First, add the import at the top of the file:
115+
```python
116+
from app.tools.your_tool import YourToolHelper
117+
```
118+
119+
Then, add the tool helper as a singleton in the Container class:
120+
```python
121+
class Container(containers.DeclarativeContainer):
122+
"""IoC container for application dependencies."""
123+
124+
# ... existing providers ...
125+
126+
# Your custom tool helper singleton
127+
your_tool_helper = providers.Singleton(
128+
YourToolHelper,
129+
dependency_service=some_dependency # Pass any required dependencies
130+
)
131+
```
132+
133+
Next, pass the tool helper to agents that need it. Update the agent provider:
134+
```python
135+
# In the Container class, update the agent that needs your tool
136+
your_agent = providers.Factory(
137+
YourAgent,
138+
azure_chat_client=_azure_chat_client,
139+
your_service_mcp_server_url=f"{settings.YOUR_SERVICE_MCP_URL}/mcp",
140+
your_tool_helper=your_tool_helper # Inject the tool helper
141+
)
142+
```
143+
144+
Finally, update your agent class to receive and use the tool:
145+
146+
```python
147+
# In your_agent.py
148+
class YourAgent:
149+
def __init__(self,
150+
azure_chat_client: AzureOpenAIChatClient,
151+
your_service_mcp_server_url: str,
152+
your_tool_helper: YourToolHelper): # Add tool helper parameter
153+
self.azure_chat_client = azure_chat_client
154+
self.your_service_mcp_server_url = your_service_mcp_server_url
155+
self.your_tool_helper = your_tool_helper # Store reference
156+
157+
async def build_af_agent(self) -> Agent:
158+
# ... MCP tool initialization ...
159+
160+
return Agent(
161+
client=self.azure_chat_client,
162+
instructions=YourAgent.instructions,
163+
name=YourAgent.name,
164+
tools=[
165+
your_mcp_server,
166+
self.your_tool_helper.your_custom_tool # Add tool method to tools list
167+
],
168+
)
169+
```
170+
171+
#### Step 3: Register MCP Tools (if using Business API)
172+
173+
If your agent needs to call business APIs via MCP:
174+
175+
1. Ensure the business API service exposes MCP tools
176+
2. Update `app/backend/app/config/settings.py` to include the MCP server URL:
177+
178+
```python
179+
# In settings.py
180+
YOUR_SERVICE_MCP_SERVER_URL: str = Field(
181+
default="http://localhost:8081/mcp",
182+
description="Your service MCP server URL"
183+
)
184+
```
185+
186+
3. Load MCP tools in your agent initialization
187+
188+
#### Step 4: Update the Dependency Injection Container
189+
190+
**For Azure Chat version**, edit `app/backend/app/config/container_azure_chat.py`:
191+
192+
First, add the import at the top of the file:
193+
```python
194+
from app.agents.azure_chat.your_agent_name import YourAgentName
195+
```
196+
197+
Then, add the agent factory in the container class:
198+
```python
199+
# Inside the Container class
200+
your_agent_name = providers.Factory(
201+
YourAgentName,
202+
azure_chat_client=_azure_chat_client,
203+
your_service_mcp_server_url=f"{settings.YOUR_SERVICE_MCP_URL}/mcp"
204+
)
205+
```
206+
207+
**For Foundry v2 version**, edit `app/backend/app/config/container_foundry_v2.py` similarly, but use the foundry client:
208+
```python
209+
your_agent_name = providers.Factory(
210+
YourAgentName,
211+
azure_ai_client=_azure_ai_client,
212+
your_service_mcp_server_url=f"{settings.YOUR_SERVICE_MCP_URL}/mcp"
213+
)
214+
```
215+
216+
#### Step 5: Update the Handoff Orchestrator
217+
218+
Edit the handoff orchestrator to include your new agent:
219+
220+
**File**: `app/backend/app/agents/azure_chat/handoff_orchestrator.py` (or `foundry_v2` version)
221+
222+
1. Update the HandoffOrchestrator class to include your agent in the workflow:
223+
```python
224+
class HandoffOrchestrator:
225+
triage_instructions = """
226+
You are a banking customer support agent triaging customer requests...
227+
228+
# Triage rules
229+
- If request is related to [your domain], call handoff_to_YourAgentName.
230+
...
231+
"""
232+
233+
def __init__(self,
234+
azure_chat_client: AzureOpenAIChatClient,
235+
account_agent: AccountAgent,
236+
transaction_agent: TransactionHistoryAgent,
237+
payment_agent: PaymentAgent,
238+
your_agent_name: YourAgentName): # Add parameter
239+
self.azure_chat_client = azure_chat_client
240+
self.account_agent = account_agent
241+
self.transaction_agent = transaction_agent
242+
self.payment_agent = payment_agent
243+
self.your_agent_name = your_agent_name # Store reference
244+
self.workflow = None
245+
246+
async def initialize(self, checkpoint_storage: CheckpointStorage):
247+
"""Initialize the workflow with async operations"""
248+
triage_agent = Agent(
249+
client=self.azure_chat_client,
250+
instructions=HandoffOrchestrator.triage_instructions,
251+
name="triage_agent"
252+
)
253+
254+
self.workflow = (
255+
HandoffBuilder(
256+
name="banking_assistant_handoff",
257+
participants=[
258+
triage_agent,
259+
await self.account_agent.build_af_agent(),
260+
await self.transaction_agent.build_af_agent(),
261+
await self.payment_agent.build_af_agent(),
262+
await self.your_agent_name.build_af_agent() # Add here
263+
],
264+
)
265+
.with_start_agent(triage_agent)
266+
.with_termination_condition(
267+
lambda conv: sum(1 for msg in conv if msg.role == "user") >= 20
268+
)
269+
.with_checkpointing(checkpoint_storage)
270+
.build()
271+
)
272+
```
273+
274+
2. Update the orchestrator factory in your DI container to add the new agent:
275+
276+
**In `app/backend/app/config/container_azure_chat.py`:**
277+
278+
```python
279+
# Update the handoff_orchestrator_chatkit factory
280+
handoff_orchestrator_chatkit = providers.Factory(
281+
HandoffOrchestratorChatKit,
282+
azure_chat_client=_azure_chat_client,
283+
account_agent=account_agent_chatkit,
284+
transaction_agent=transaction_agent_chatkit,
285+
payment_agent=payment_agent_chatkit,
286+
your_agent_name=your_agent_name # Add your new agent
287+
)
288+
```
289+
290+
#### Step 7: Add Tests
291+
292+
Create a test file: `app/backend/tests/test_your_agent_chatkit.py`
293+
294+
```python
295+
import pytest
296+
from app.agents.azure_chat.your_agent_name import YourAgentName
297+
298+
@pytest.mark.asyncio
299+
async def test_your_agent_initialization():
300+
"""Test agent initializes correctly."""
301+
agent = YourAgentName(model="gpt-4", tools=[])
302+
assert agent.name == "your_agent_name"
303+
assert agent.instructions is not None
304+
305+
```
306+
307+
Run tests:
308+
```bash
309+
cd app/backend
310+
uv run pytest tests/test_your_agent_chatkit.py -v
311+
```
312+
313+
#### Step 8: Test End-to-End
314+
315+
1. Start the backend server:
316+
```bash
317+
cd app/backend
318+
PROFILE=dev ENABLE_SENSITIVE_DATA=true \
319+
uv run uvicorn app.main_chatkit_server:app --reload --port 8080
320+
```
321+
322+
Or use VSCode debugger: Select **DEV - Chatkit Backend App** and press F5
323+
324+
2. Start the frontend:
325+
```bash
326+
cd app/frontend/banking-web
327+
npm run dev
328+
```
329+
330+
3. Test routing to your new agent through the chat interface
331+
332+
---

0 commit comments

Comments
 (0)