Skip to content

Commit a7b3bc6

Browse files
authored
Merge branch 'main' into users/johanb/CodeReviewSkill
2 parents 8904029 + acf29a0 commit a7b3bc6

20 files changed

Lines changed: 3050 additions & 34 deletions

File tree

CLAUDE.md

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,11 +168,45 @@ Place it before imports with one blank line after.
168168

169169
### Python Conventions
170170

171-
- Type hints preferred (Pydantic models heavily used)
171+
- Type hints required on all function parameters and return types
172172
- Async/await patterns for I/O operations
173173
- Use explicit `None` checks: `if x is not None:` not `if x:`
174174
- Local imports should be moved to top of file
175175
- Return defensive copies of mutable data to protect singletons
176+
- **Async method naming**: Do NOT use `_async` suffix on async methods. The `_async` suffix is only appropriate when providing both sync and async versions of the same method. Since this SDK is async-only, use plain method names (e.g., `send_chat_history_messages` not `send_chat_history_messages_async`)
177+
178+
### Type Hints - NEVER Use `Any`
179+
180+
**CRITICAL: Never use `typing.Any` in this codebase.** Using `Any` defeats the purpose of type checking and can hide bugs. Instead:
181+
182+
1. **Use actual types from external SDKs** - When integrating with external libraries (OpenAI, LangChain, etc.), import and use their actual types:
183+
```python
184+
from agents.memory import Session
185+
from agents.items import TResponseInputItem
186+
187+
async def send_chat_history(self, session: Session) -> OperationResult:
188+
...
189+
```
190+
191+
2. **Use `Union` for known possible types**:
192+
```python
193+
from typing import Union
194+
MessageType = Union[UserMessage, AssistantMessage, SystemMessage, Dict[str, object]]
195+
```
196+
197+
3. **Use `object` for truly unknown types** that you only pass through:
198+
```python
199+
def log_item(item: object) -> None: ...
200+
```
201+
202+
4. **Use `Protocol` only as a last resort** - If external types cannot be found or imported, define a Protocol. However, **confirm with the developer first** before proceeding with this approach, as it may indicate a missing dependency or incorrect understanding of the external API.
203+
204+
**Why this matters:**
205+
- `Any` disables all type checking for that variable
206+
- Bugs that type checkers would catch go unnoticed
207+
- Code readability suffers - developers don't know what types to expect
208+
- Using actual SDK types provides better IDE support and ensures compatibility
209+
- This applies to both production code AND test files
176210

177211
## CI/CD
178212

docs/design.md

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,51 @@ Framework-specific adapters for MCP tool integration:
227227
|---------|---------|------------|
228228
| `extensions-agentframework` | Adapt MCP tools to Microsoft Agents SDK | [design.md](../libraries/microsoft-agents-a365-tooling-extensions-agentframework/docs/design.md) |
229229
| `extensions-azureaifoundry` | Azure AI Foundry tool integration | [design.md](../libraries/microsoft-agents-a365-tooling-extensions-azureaifoundry/docs/design.md) |
230-
| `extensions-openai` | OpenAI function calling integration | [design.md](../libraries/microsoft-agents-a365-tooling-extensions-openai/docs/design.md) |
230+
| `extensions-openai` | OpenAI function calling integration and chat history | [design.md](../libraries/microsoft-agents-a365-tooling-extensions-openai/docs/design.md) |
231231
| `extensions-semantickernel` | Semantic Kernel plugin integration | [design.md](../libraries/microsoft-agents-a365-tooling-extensions-semantickernel/docs/design.md) |
232232

233+
#### OpenAI Extension: Chat History API
234+
235+
The OpenAI tooling extension provides methods to send chat history to the MCP platform for real-time threat protection:
236+
237+
**Key Classes:**
238+
239+
| Class | Purpose |
240+
|-------|---------|
241+
| `McpToolRegistrationService` | MCP tool registration and chat history management |
242+
243+
**Methods:**
244+
245+
| Method | Purpose |
246+
|--------|---------|
247+
| `send_chat_history(turn_context, session, limit, options)` | Extract messages from OpenAI Session and send to MCP platform |
248+
| `send_chat_history_messages(turn_context, messages, options)` | Send a list of OpenAI TResponseInputItem messages to MCP platform |
249+
250+
**Usage Example:**
251+
252+
```python
253+
from agents import Agent, Runner
254+
from microsoft_agents_a365.tooling.extensions.openai import McpToolRegistrationService
255+
256+
service = McpToolRegistrationService()
257+
agent = Agent(name="my-agent", model="gpt-4")
258+
259+
# In your agent handler:
260+
async with Runner.run(agent, messages) as result:
261+
session = result.session
262+
263+
# Option 1: Send from Session object
264+
op_result = await service.send_chat_history(turn_context, session)
265+
266+
# Option 2: Send from message list
267+
op_result = await service.send_chat_history_messages(turn_context, messages)
268+
269+
if op_result.succeeded:
270+
print("Chat history sent successfully")
271+
```
272+
273+
The methods convert OpenAI message types to `ChatHistoryMessage` format and delegate to the core `McpToolServerConfigurationService.send_chat_history()` method.
274+
233275
### 6. Notifications (`microsoft-agents-a365-notifications`)
234276

235277
> **Detailed documentation**: [libraries/microsoft-agents-a365-notifications/docs/design.md](../libraries/microsoft-agents-a365-notifications/docs/design.md)

libraries/microsoft-agents-a365-tooling-extensions-agentframework/docs/design.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,87 @@ mcp_tool = MCPStreamableHTTPTool(
7676
)
7777
```
7878

79+
### Chat History API
80+
81+
The service provides methods to send chat history to the MCP platform for real-time threat protection analysis. This enables security scanning of conversation content.
82+
83+
#### send_chat_history_messages
84+
85+
The primary method for sending chat history. Converts Agent Framework `ChatMessage` objects to the `ChatHistoryMessage` format expected by the MCP platform.
86+
87+
```python
88+
from agent_framework import ChatMessage, Role
89+
90+
service = McpToolRegistrationService()
91+
92+
# Create messages
93+
messages = [
94+
ChatMessage(role=Role.USER, text="Hello, how are you?"),
95+
ChatMessage(role=Role.ASSISTANT, text="I'm doing well, thank you!"),
96+
]
97+
98+
# Send to MCP platform for threat protection
99+
result = await service.send_chat_history_messages(messages, turn_context)
100+
101+
if result.succeeded:
102+
print("Chat history sent successfully")
103+
else:
104+
print(f"Failed: {result.errors}")
105+
```
106+
107+
#### send_chat_history_from_store
108+
109+
A convenience method that extracts messages from a `ChatMessageStoreProtocol` and delegates to `send_chat_history_messages`.
110+
111+
```python
112+
# Using a ChatMessageStore directly
113+
result = await service.send_chat_history_from_store(
114+
thread.chat_message_store,
115+
turn_context
116+
)
117+
```
118+
119+
#### Chat History API Parameters
120+
121+
| Method | Parameter | Type | Description |
122+
|--------|-----------|------|-------------|
123+
| `send_chat_history_messages` | `chat_messages` | `Sequence[ChatMessage]` | Messages to send |
124+
| | `turn_context` | `TurnContext` | Conversation context |
125+
| | `tool_options` | `ToolOptions \| None` | Optional configuration |
126+
| `send_chat_history_from_store` | `chat_message_store` | `ChatMessageStoreProtocol` | Message store |
127+
| | `turn_context` | `TurnContext` | Conversation context |
128+
| | `tool_options` | `ToolOptions \| None` | Optional configuration |
129+
130+
#### Chat History Integration Flow
131+
132+
```
133+
Agent Framework ChatMessage objects
134+
135+
136+
McpToolRegistrationService.send_chat_history_messages()
137+
138+
├── Convert ChatMessage → ChatHistoryMessage
139+
│ ├── Extract role via .value property
140+
│ ├── Generate UUID if message_id is None
141+
│ ├── Filter out empty/whitespace content
142+
│ └── Filter out None roles
143+
144+
145+
McpToolServerConfigurationService.send_chat_history()
146+
147+
148+
MCP Platform Real-Time Threat Protection Endpoint
149+
```
150+
151+
#### Message Filtering Behavior
152+
153+
The conversion process filters out invalid messages:
154+
- Messages with `None` role are skipped (logged at WARNING level)
155+
- Messages with empty or whitespace-only content are skipped
156+
- If all messages are filtered out, the method returns success without calling the backend
157+
158+
This ensures only valid, meaningful messages are sent for threat analysis.
159+
79160
## File Structure
80161

81162
```

0 commit comments

Comments
 (0)