-
Notifications
You must be signed in to change notification settings - Fork 15
Add API to send chat history to MCP platform for threat protection #105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 11 commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
30a75cb
Initial plan
Copilot 70b54d2
Add chat history models and send_chat_history method
Copilot f7bf975
Add unit tests for chat history models and operation result classes
Copilot 34a8605
Fix type annotation for chat_history_messages parameter
Copilot 6545d57
Add usage example for send_chat_history API
Copilot 6c49d71
Address PR feedback: update copyright headers, remove example file, u…
Copilot 4660d6c
Add type annotation for turn_context parameter
Copilot 38206e1
Remove TYPE_CHECKING and always import TurnContext, add microsoft-age…
Copilot 4443b7d
Add comprehensive unit tests for send_chat_history method
Copilot daed65e
Apply suggestion from @pontemonti
pontemonti 1b6f196
Run ruff format to fix code formatting
Copilot a79f8d9
Use consistent datetime import style in test_send_chat_history.py
Copilot e93e24e
Code review fixes/pr 105 (#114)
pontemonti 440549b
fix(tooling): add whitespace validation and type hints to model classes
22c3760
fix(tooling): improve send_chat_history validation and error handling
6f22dde
refactor(tooling): extract endpoint path to constant
8f9b0d4
test(tooling): add whitespace and empty list validation tests
b3e88ff
Code review fixes/pr 105 v3 (#115)
pontemonti 971ee1d
Update model classes to use pydantic instead of `@dataclass`.
1a7c827
chore: add changelog for new chat history API features
c3c77dc
style: format ChatHistoryMessage instantiation for improved readability
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
58 changes: 58 additions & 0 deletions
58
libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/operation_error.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
|
|
||
| """ | ||
| Encapsulates an error from an operation. | ||
| """ | ||
|
|
||
|
|
||
| class OperationError: | ||
| """ | ||
| Represents an error that occurred during an operation. | ||
|
|
||
| This class wraps an exception and provides a consistent interface for | ||
| accessing error information. | ||
| """ | ||
|
|
||
| def __init__(self, exception: Exception): | ||
| """ | ||
| Initialize a new instance of the OperationError class. | ||
|
|
||
| Args: | ||
| exception: The exception associated with the error. | ||
|
|
||
| Raises: | ||
| ValueError: If exception is None. | ||
| """ | ||
| if exception is None: | ||
| raise ValueError("exception cannot be None") | ||
| self._exception = exception | ||
|
|
||
| @property | ||
| def exception(self) -> Exception: | ||
| """ | ||
| Get the exception associated with the error. | ||
|
|
||
| Returns: | ||
| Exception: The exception associated with the error. | ||
| """ | ||
| return self._exception | ||
|
|
||
| @property | ||
| def message(self) -> str: | ||
| """ | ||
| Get the message associated with the error. | ||
|
|
||
| Returns: | ||
| str: The error message from the exception. | ||
| """ | ||
| return str(self._exception) | ||
|
|
||
| def __str__(self) -> str: | ||
| """ | ||
| Return a string representation of the error. | ||
|
|
||
| Returns: | ||
| str: A string representation of the error. | ||
| """ | ||
| return str(self._exception) |
91 changes: 91 additions & 0 deletions
91
libraries/microsoft-agents-a365-runtime/microsoft_agents_a365/runtime/operation_result.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
|
|
||
| """ | ||
| Represents the result of an operation. | ||
| """ | ||
|
|
||
| from typing import List, Optional | ||
|
|
||
| from .operation_error import OperationError | ||
|
|
||
|
|
||
| class OperationResult: | ||
| """ | ||
| Represents the result of an operation. | ||
|
|
||
| This class encapsulates the success or failure state of an operation along | ||
| with any associated errors. | ||
| """ | ||
|
|
||
| _success_instance: Optional["OperationResult"] = None | ||
|
|
||
| def __init__(self, succeeded: bool, errors: Optional[List[OperationError]] = None): | ||
| """ | ||
| Initialize a new instance of the OperationResult class. | ||
|
|
||
| Args: | ||
| succeeded: Flag indicating whether the operation succeeded. | ||
| errors: Optional list of errors that occurred during the operation. | ||
| """ | ||
| self._succeeded = succeeded | ||
| self._errors = errors if errors is not None else [] | ||
|
|
||
| @property | ||
| def succeeded(self) -> bool: | ||
| """ | ||
| Get a flag indicating whether the operation succeeded. | ||
|
|
||
| Returns: | ||
| bool: True if the operation succeeded, otherwise False. | ||
| """ | ||
| return self._succeeded | ||
|
|
||
| @property | ||
| def errors(self) -> List[OperationError]: | ||
| """ | ||
| Get the list of errors that occurred during the operation. | ||
|
|
||
| Returns: | ||
| List[OperationError]: List of operation errors. | ||
| """ | ||
| return self._errors | ||
|
|
||
| @staticmethod | ||
| def success() -> "OperationResult": | ||
| """ | ||
| Return an OperationResult indicating a successful operation. | ||
|
|
||
| Returns: | ||
| OperationResult: An OperationResult indicating a successful operation. | ||
| """ | ||
| if OperationResult._success_instance is None: | ||
| OperationResult._success_instance = OperationResult(succeeded=True) | ||
| return OperationResult._success_instance | ||
|
|
||
| @staticmethod | ||
| def failed(*errors: OperationError) -> "OperationResult": | ||
| """ | ||
| Create an OperationResult indicating a failed operation. | ||
|
|
||
| Args: | ||
| *errors: Variable number of OperationError instances. | ||
|
|
||
| Returns: | ||
| OperationResult: An OperationResult indicating a failed operation. | ||
| """ | ||
| error_list = list(errors) if errors else [] | ||
| return OperationResult(succeeded=False, errors=error_list) | ||
|
|
||
| def __str__(self) -> str: | ||
| """ | ||
| Convert the value of the current OperationResult object to its string representation. | ||
|
|
||
| Returns: | ||
| str: A string representation of the current OperationResult object. | ||
| """ | ||
| if self._succeeded: | ||
| return "Succeeded" | ||
| else: | ||
| error_messages = ", ".join(str(error.message) for error in self._errors) | ||
| return f"Failed : {error_messages}" |
7 changes: 5 additions & 2 deletions
7
libraries/microsoft-agents-a365-tooling/microsoft_agents_a365/tooling/models/__init__.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,15 @@ | ||
| # Copyright (c) Microsoft. All rights reserved. | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
|
|
||
| """ | ||
| Common models for MCP tooling. | ||
|
|
||
| This module defines data models used across the MCP tooling framework. | ||
| """ | ||
|
|
||
| from .chat_history_message import ChatHistoryMessage | ||
| from .chat_message_request import ChatMessageRequest | ||
| from .mcp_server_config import MCPServerConfig | ||
| from .tool_options import ToolOptions | ||
|
|
||
| __all__ = ["MCPServerConfig", "ToolOptions"] | ||
| __all__ = ["MCPServerConfig", "ToolOptions", "ChatHistoryMessage", "ChatMessageRequest"] |
56 changes: 56 additions & 0 deletions
56
...icrosoft-agents-a365-tooling/microsoft_agents_a365/tooling/models/chat_history_message.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
|
|
||
| """ | ||
| Chat History Message model. | ||
| """ | ||
|
|
||
| from dataclasses import dataclass | ||
| from datetime import datetime | ||
|
|
||
|
|
||
| @dataclass | ||
|
pontemonti marked this conversation as resolved.
Outdated
|
||
| class ChatHistoryMessage: | ||
|
pontemonti marked this conversation as resolved.
Outdated
|
||
| """ | ||
| Represents a single message in the chat history. | ||
|
|
||
| This class is used to send chat history to the MCP platform for real-time | ||
| threat protection analysis. | ||
| """ | ||
|
|
||
| #: The unique identifier for the chat message. | ||
| id: str | ||
|
|
||
| #: The role of the message sender (e.g., "user", "assistant", "system"). | ||
| role: str | ||
|
|
||
| #: The content of the chat message. | ||
| content: str | ||
|
|
||
| #: The timestamp of when the message was sent. | ||
| timestamp: datetime | ||
|
|
||
| def __post_init__(self): | ||
| """Validate the message after initialization.""" | ||
| if not self.id: | ||
| raise ValueError("id cannot be empty") | ||
| if not self.role: | ||
| raise ValueError("role cannot be empty") | ||
| if not self.content: | ||
| raise ValueError("content cannot be empty") | ||
| if not self.timestamp: | ||
| raise ValueError("timestamp cannot be empty") | ||
|
|
||
| def to_dict(self): | ||
| """ | ||
| Convert the message to a dictionary for JSON serialization. | ||
|
|
||
| Returns: | ||
| dict: Dictionary representation of the message. | ||
| """ | ||
| return { | ||
| "id": self.id, | ||
| "role": self.role, | ||
| "content": self.content, | ||
| "timestamp": self.timestamp.isoformat(), | ||
| } | ||
58 changes: 58 additions & 0 deletions
58
...icrosoft-agents-a365-tooling/microsoft_agents_a365/tooling/models/chat_message_request.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| # Copyright (c) Microsoft Corporation. | ||
| # Licensed under the MIT License. | ||
|
|
||
| """ | ||
| Chat Message Request model. | ||
| """ | ||
|
|
||
| from dataclasses import dataclass | ||
| from typing import List | ||
|
|
||
| from .chat_history_message import ChatHistoryMessage | ||
|
|
||
|
|
||
| @dataclass | ||
| class ChatMessageRequest: | ||
| """ | ||
| Represents the request payload for a real-time threat protection check on a chat message. | ||
|
|
||
| This class encapsulates the information needed to send chat history to the MCP platform | ||
| for threat analysis. | ||
| """ | ||
|
|
||
| #: The unique identifier for the conversation. | ||
| conversation_id: str | ||
|
|
||
| #: The unique identifier for the message within the conversation. | ||
| message_id: str | ||
|
|
||
| #: The content of the user's message. | ||
| user_message: str | ||
|
|
||
| #: The chat history messages. | ||
| chat_history: List[ChatHistoryMessage] | ||
|
|
||
| def __post_init__(self): | ||
| """Validate the request after initialization.""" | ||
| if not self.conversation_id: | ||
| raise ValueError("conversation_id cannot be empty") | ||
| if not self.message_id: | ||
| raise ValueError("message_id cannot be empty") | ||
| if not self.user_message: | ||
| raise ValueError("user_message cannot be empty") | ||
| if not self.chat_history: | ||
| raise ValueError("chat_history cannot be empty") | ||
|
|
||
| def to_dict(self): | ||
| """ | ||
| Convert the request to a dictionary for JSON serialization. | ||
|
|
||
| Returns: | ||
| dict: Dictionary representation of the request. | ||
| """ | ||
| return { | ||
| "conversationId": self.conversation_id, | ||
| "messageId": self.message_id, | ||
| "userMessage": self.user_message, | ||
| "chatHistory": [msg.to_dict() for msg in self.chat_history], | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.