diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/__init__.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/__init__.py index b12f85c7..14f725c1 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/__init__.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/__init__.py @@ -9,19 +9,19 @@ # Main notification handler class from .agent_notification import ( - AgentNotification, AgentHandler, + AgentNotification, ) # Import all models from the models subpackage from .models import ( + AgentLifecycleEvent, AgentNotificationActivity, + AgentSubChannel, EmailReference, - WpxComment, EmailResponse, NotificationTypes, - AgentSubChannel, - AgentLifecycleEvent, + WpxComment, ) __all__ = [ diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/agent_notification.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/agent_notification.py index 8a5f94de..099f2c70 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/agent_notification.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/agent_notification.py @@ -1,3 +1,5 @@ +# Copyright (c) Microsoft. All rights reserved. + from __future__ import annotations from collections.abc import Awaitable, Callable, Iterable @@ -6,17 +8,69 @@ from microsoft_agents.activity import ChannelId from microsoft_agents.hosting.core import TurnContext from microsoft_agents.hosting.core.app.state import TurnState + +from .models.agent_lifecycle_event import AgentLifecycleEvent from .models.agent_notification_activity import AgentNotificationActivity, NotificationTypes from .models.agent_subchannel import AgentSubChannel -from .models.agent_lifecycle_event import AgentLifecycleEvent TContext = TypeVar("TContext", bound=TurnContext) TState = TypeVar("TState", bound=TurnState) +#: Type alias for agent notification handler functions. +#: +#: Agent handlers are async functions that process notifications from Microsoft 365 +#: applications. They receive the turn context, application state, and a typed +#: notification activity wrapper. +#: +#: Args: +#: context: The turn context for the current conversation turn. +#: state: The application state for the current turn. +#: notification: The typed notification activity with parsed entities. +#: +#: Example: +#: ```python +#: async def handle_email( +#: context: TurnContext, +#: state: TurnState, +#: notification: AgentNotificationActivity +#: ) -> None: +#: email = notification.email +#: if email: +#: print(f"Processing email: {email.id}") +#: ``` AgentHandler = Callable[[TContext, TState, AgentNotificationActivity], Awaitable[None]] class AgentNotification: + """Handler for agent notifications from Microsoft 365 applications. + + This class provides decorators for registering handlers that respond to notifications + from various Microsoft 365 channels and subchannels. It supports routing based on + channel ID, subchannel, and lifecycle events. + + Args: + app: The application instance that will handle the routed notifications. + known_subchannels: Optional iterable of recognized subchannels. If None, + defaults to all values in the AgentSubChannel enum. + known_lifecycle_events: Optional iterable of recognized lifecycle events. If None, + defaults to all values in the AgentLifecycleEvent enum. + + Example: + ```python + from microsoft_agents.hosting import Application + from microsoft_agents_a365.notifications import AgentNotification + + app = Application() + notifications = AgentNotification(app) + + @notifications.on_email() + async def handle_email(context, state, notification): + email = notification.email + if email: + await context.send_activity(f"Received email: {email.id}") + ``` + """ + def __init__( self, app: Any, @@ -56,6 +110,31 @@ def on_agent_notification( channel_id: ChannelId, **kwargs: Any, ): + """Register a handler for notifications from a specific channel and subchannel. + + This decorator registers a handler function to be called when a notification is + received from the specified channel and optional subchannel. The handler will + receive a typed AgentNotificationActivity wrapper. + + Args: + channel_id: The channel ID specifying the channel and optional subchannel + to listen for. Use "*" as the subchannel to match all subchannels. + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + from microsoft_agents.activity import ChannelId + + @notifications.on_agent_notification( + ChannelId(channel="agents", sub_channel="email") + ) + async def handle_custom_channel(context, state, notification): + print(f"Received notification on {notification.channel}/{notification.sub_channel}") + ``` + """ registered_channel = channel_id.channel.lower() registered_subchannel = (channel_id.sub_channel or "*").lower() @@ -90,6 +169,26 @@ def on_agent_lifecycle_notification( lifecycle_event: str, **kwargs: Any, ): + """Register a handler for agent lifecycle event notifications. + + This decorator registers a handler function to be called when lifecycle events + occur, such as user creation, deletion, or workload onboarding updates. + + Args: + lifecycle_event: The lifecycle event to listen for. Use "*" to match all + lifecycle events, or specify a specific event from AgentLifecycleEvent. + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + @notifications.on_agent_lifecycle_notification("agenticuseridentitycreated") + async def handle_user_created(context, state, notification): + print("New user created") + ``` + """ def route_selector(context: TurnContext) -> bool: ch = context.activity.channel_id received_channel = ch.channel if ch else "" @@ -121,6 +220,31 @@ def decorator(handler: AgentHandler): def on_email( self, **kwargs: Any ) -> Callable[[AgentHandler], Callable[[TurnContext, TurnState], Awaitable[None]]]: + """Register a handler for Outlook email notifications. + + This is a convenience decorator that registers a handler for notifications + from the email subchannel. + + Args: + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + @notifications.on_email() + async def handle_email(context, state, notification): + email = notification.email + if email: + print(f"Received email: {email.id}") + # Send a response + response = EmailResponse.create_email_response_activity( + "

Thank you for your email.

" + ) + await context.send_activity(response) + ``` + """ return self.on_agent_notification( ChannelId(channel="agents", sub_channel=AgentSubChannel.EMAIL), **kwargs ) @@ -128,6 +252,26 @@ def on_email( def on_word( self, **kwargs: Any ) -> Callable[[AgentHandler], Callable[[TurnContext, TurnState], Awaitable[None]]]: + """Register a handler for Microsoft Word comment notifications. + + This is a convenience decorator that registers a handler for notifications + from the Word subchannel. + + Args: + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + @notifications.on_word() + async def handle_word_comment(context, state, notification): + comment = notification.wpx_comment + if comment: + print(f"Received Word comment: {comment.comment_id}") + ``` + """ return self.on_agent_notification( ChannelId(channel="agents", sub_channel=AgentSubChannel.WORD), **kwargs ) @@ -135,6 +279,26 @@ def on_word( def on_excel( self, **kwargs: Any ) -> Callable[[AgentHandler], Callable[[TurnContext, TurnState], Awaitable[None]]]: + """Register a handler for Microsoft Excel comment notifications. + + This is a convenience decorator that registers a handler for notifications + from the Excel subchannel. + + Args: + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + @notifications.on_excel() + async def handle_excel_comment(context, state, notification): + comment = notification.wpx_comment + if comment: + print(f"Received Excel comment: {comment.comment_id}") + ``` + """ return self.on_agent_notification( ChannelId(channel="agents", sub_channel=AgentSubChannel.EXCEL), **kwargs ) @@ -142,6 +306,26 @@ def on_excel( def on_powerpoint( self, **kwargs: Any ) -> Callable[[AgentHandler], Callable[[TurnContext, TurnState], Awaitable[None]]]: + """Register a handler for Microsoft PowerPoint comment notifications. + + This is a convenience decorator that registers a handler for notifications + from the PowerPoint subchannel. + + Args: + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + @notifications.on_powerpoint() + async def handle_powerpoint_comment(context, state, notification): + comment = notification.wpx_comment + if comment: + print(f"Received PowerPoint comment: {comment.comment_id}") + ``` + """ return self.on_agent_notification( ChannelId(channel="agents", sub_channel=AgentSubChannel.POWERPOINT), **kwargs ) @@ -149,16 +333,70 @@ def on_powerpoint( def on_lifecycle( self, **kwargs: Any ) -> Callable[[AgentHandler], Callable[[TurnContext, TurnState], Awaitable[None]]]: + """Register a handler for all agent lifecycle event notifications. + + This is a convenience decorator that registers a handler for all lifecycle + events using the wildcard "*" matcher. + + Args: + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + @notifications.on_lifecycle() + async def handle_any_lifecycle_event(context, state, notification): + print(f"Lifecycle event type: {notification.notification_type}") + ``` + """ return self.on_lifecycle_notification("*", **kwargs) def on_user_created( self, **kwargs: Any ) -> Callable[[AgentHandler], Callable[[TurnContext, TurnState], Awaitable[None]]]: + """Register a handler for user creation lifecycle events. + + This is a convenience decorator that registers a handler specifically for + agentic user identity creation events. + + Args: + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + @notifications.on_user_created() + async def handle_user_created(context, state, notification): + print("New agentic user identity created") + ``` + """ return self.on_lifecycle_notification(AgentLifecycleEvent.USERCREATED, **kwargs) def on_user_workload_onboarding( self, **kwargs: Any ) -> Callable[[AgentHandler], Callable[[TurnContext, TurnState], Awaitable[None]]]: + """Register a handler for user workload onboarding update events. + + This is a convenience decorator that registers a handler for events that occur + when a user's workload onboarding status is updated. + + Args: + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + @notifications.on_user_workload_onboarding() + async def handle_onboarding_update(context, state, notification): + print("User workload onboarding status updated") + ``` + """ return self.on_lifecycle_notification( AgentLifecycleEvent.USERWORKLOADONBOARDINGUPDATED, **kwargs ) @@ -166,10 +404,36 @@ def on_user_workload_onboarding( def on_user_deleted( self, **kwargs: Any ) -> Callable[[AgentHandler], Callable[[TurnContext, TurnState], Awaitable[None]]]: + """Register a handler for user deletion lifecycle events. + + This is a convenience decorator that registers a handler specifically for + agentic user identity deletion events. + + Args: + **kwargs: Additional keyword arguments passed to the app's add_route method. + + Returns: + A decorator function that registers the handler with the application. + + Example: + ```python + @notifications.on_user_deleted() + async def handle_user_deleted(context, state, notification): + print("Agentic user identity deleted") + ``` + """ return self.on_lifecycle_notification(AgentLifecycleEvent.USERDELETED, **kwargs) @staticmethod def _normalize_subchannel(value: str | AgentSubChannel | None) -> str: + """Normalize a subchannel value to a lowercase string. + + Args: + value: The subchannel value to normalize, either as an enum or string. + + Returns: + The normalized lowercase subchannel string, or empty string if None. + """ if value is None: return "" resolved = value.value if isinstance(value, AgentSubChannel) else str(value) @@ -177,6 +441,14 @@ def _normalize_subchannel(value: str | AgentSubChannel | None) -> str: @staticmethod def _normalize_lifecycleevent(value: str | AgentLifecycleEvent | None) -> str: + """Normalize a lifecycle event value to a lowercase string. + + Args: + value: The lifecycle event value to normalize, either as an enum or string. + + Returns: + The normalized lowercase lifecycle event string, or empty string if None. + """ if value is None: return "" resolved = value.value if isinstance(value, AgentLifecycleEvent) else str(value) diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/__init__.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/__init__.py index a4ee9d2d..79d50579 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/__init__.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/__init__.py @@ -1,10 +1,19 @@ +# Copyright (c) Microsoft. All rights reserved. + +"""Models and data classes for agent notifications. + +This module contains the data models and enums used to represent notifications +from Microsoft 365 applications, including email references, document comments, +and lifecycle events. +""" + +from .agent_lifecycle_event import AgentLifecycleEvent from .agent_notification_activity import AgentNotificationActivity +from .agent_subchannel import AgentSubChannel from .email_reference import EmailReference -from .wpx_comment import WpxComment from .email_response import EmailResponse from .notification_types import NotificationTypes -from .agent_subchannel import AgentSubChannel -from .agent_lifecycle_event import AgentLifecycleEvent +from .wpx_comment import WpxComment __all__ = [ "AgentNotificationActivity", diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_lifecycle_event.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_lifecycle_event.py index 87d89c61..6af3793e 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_lifecycle_event.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_lifecycle_event.py @@ -1,7 +1,21 @@ +# Copyright (c) Microsoft. All rights reserved. + from enum import Enum class AgentLifecycleEvent(str, Enum): + """Enumeration of agent lifecycle event types. + + This enum defines the different lifecycle events that can occur for agentic user + identities in the Microsoft 365 ecosystem. + + Attributes: + USERCREATED: Event triggered when a new agentic user identity is created. + USERWORKLOADONBOARDINGUPDATED: Event triggered when a user's workload + onboarding status is updated. + USERDELETED: Event triggered when an agentic user identity is deleted. + """ + USERCREATED = "agenticuseridentitycreated" USERWORKLOADONBOARDINGUPDATED = "agenticuserworkloadonboardingupdated" USERDELETED = "agenticuseridentitydeleted" diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_notification_activity.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_notification_activity.py index c2de5e77..2f20c07a 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_notification_activity.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_notification_activity.py @@ -1,22 +1,50 @@ -from typing import Any, Optional, Type, TypeVar +# Copyright (c) Microsoft. All rights reserved. + +from typing import Any, TypeVar + from microsoft_agents.activity import Activity -from .notification_types import NotificationTypes + from .email_reference import EmailReference +from .notification_types import NotificationTypes from .wpx_comment import WpxComment TModel = TypeVar("TModel") class AgentNotificationActivity: - """Light wrapper around an Activity object with typed entities parsed at create time.""" + """Wrapper around an Activity object with typed notification entities. + + This class provides convenient access to typed notification entities extracted from + an Activity's entities collection. It automatically parses and validates email + notifications, Word/PowerPoint/Excel comments, and lifecycle events at construction + time. + + Args: + activity: The Activity object to wrap. Must not be None. + + Raises: + ValueError: If the activity parameter is None. + + Attributes: + activity: The underlying Activity object. + + Example: + ```python + async def email_handler(context: TurnContext, state: TurnState, notification: AgentNotificationActivity): + email = notification.email + if email: + print(f"Received email: {email.id}") + print(f"Body: {email.html_body}") + ``` + """ def __init__(self, activity: Activity): if not activity: raise ValueError("activity parameter is required and cannot be None") self.activity = activity - self._email: Optional[EmailReference] = None - self._wpx_comment: Optional[WpxComment] = None - self._notification_type: Optional[NotificationTypes] = None + self._email: EmailReference | None = None + self._wpx_comment: WpxComment | None = None + self._notification_type: NotificationTypes | None = None entities = self.activity.entities or [] for ent in entities: @@ -47,38 +75,102 @@ def __init__(self, activity: Activity): # ---- passthroughs ---- @property - def channel(self) -> Optional[str]: + def channel(self) -> str | None: + """The channel identifier from the activity's channel_id. + + Returns: + The channel name (e.g., 'agents', 'msteams') or None if not available. + """ ch = self.activity.channel_id return ch.channel if ch else None @property - def sub_channel(self) -> Optional[str]: + def sub_channel(self) -> str | None: + """The subchannel identifier from the activity's channel_id. + + Returns: + The subchannel name (e.g., 'email', 'word') or None if not available. + """ ch = self.activity.channel_id return ch.sub_channel if ch else None @property def value(self) -> Any: + """The value payload from the activity. + + Returns: + The activity's value, which may contain additional notification data. + """ return self.activity.value @property - def type(self) -> Optional[str]: + def type(self) -> str | None: + """The activity type. + + Returns: + The type of the activity (e.g., 'message', 'event') or None if not set. + """ return self.activity.type # --- typed entities available directly on the activity --- @property - def email(self) -> Optional[EmailReference]: + def email(self) -> EmailReference | None: + """The parsed email reference entity, if present. + + Returns: + An EmailReference object if an email notification entity was found and + successfully parsed, otherwise None. + """ return self._email @property - def wpx_comment(self) -> Optional[WpxComment]: + def wpx_comment(self) -> WpxComment | None: + """The parsed Word/PowerPoint/Excel comment entity, if present. + + Returns: + A WpxComment object if a comment entity was found and successfully parsed, + otherwise None. + """ return self._wpx_comment @property - def notification_type(self) -> Optional[NotificationTypes]: + def notification_type(self) -> NotificationTypes | None: + """The detected notification type. + + Returns: + The NotificationTypes enum value indicating the type of notification + (EMAIL_NOTIFICATION, WPX_COMMENT, or AGENT_LIFECYCLE), or None if the + notification type could not be determined. + """ return self._notification_type # Generic escape hatch - def as_model(self, model: Type[TModel]) -> Optional[TModel]: + def as_model(self, model: type[TModel]) -> TModel | None: + """Parse the activity value as a custom model type. + + This method provides a generic way to validate and parse the activity's value + payload into any Pydantic model type. Useful for custom notification types not + directly supported by the typed properties. + + Args: + model: A Pydantic model class to validate and parse the activity value into. + + Returns: + An instance of the specified model type if validation succeeds, otherwise None. + + Example: + ```python + from pydantic import BaseModel + + class CustomNotification(BaseModel): + custom_field: str + + notification = AgentNotificationActivity(activity) + custom = notification.as_model(CustomNotification) + if custom: + print(custom.custom_field) + ``` + """ try: return model.model_validate(self.value or {}) except Exception: diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_subchannel.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_subchannel.py index 2adbd521..b14e450a 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_subchannel.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/agent_subchannel.py @@ -1,7 +1,23 @@ +# Copyright (c) Microsoft. All rights reserved. + from enum import Enum class AgentSubChannel(str, Enum): + """Enumeration of agent subchannels within Microsoft 365 applications. + + This enum defines the different subchannels through which agents can receive + notifications and messages from specific Microsoft 365 applications. + + Attributes: + EMAIL: Email subchannel for Outlook-related notifications. + EXCEL: Excel subchannel for spreadsheet-related notifications. + WORD: Word subchannel for document-related notifications. + POWERPOINT: PowerPoint subchannel for presentation-related notifications. + FEDERATED_KNOWLEDGE_SERVICE: Federated Knowledge Service subchannel for + knowledge graph and search-related notifications. + """ + EMAIL = "email" EXCEL = "excel" WORD = "word" diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/email_reference.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/email_reference.py index 77e746ee..445b3586 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/email_reference.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/email_reference.py @@ -1,10 +1,26 @@ -from typing import Optional, Literal +# Copyright (c) Microsoft. All rights reserved. + +from typing import Literal + from microsoft_agents.activity.entity import Entity + from .notification_types import NotificationTypes class EmailReference(Entity): + """Entity representing an email notification reference. + + This class encapsulates information about an email notification that an agent + receives from Outlook, including the email ID, conversation context, and content. + + Attributes: + type: The notification type identifier, always set to "emailNotification". + id: The unique identifier of the email message. + conversation_id: The identifier of the conversation thread this email belongs to. + html_body: The HTML content of the email body. + """ + type: Literal["emailNotification"] = NotificationTypes.EMAIL_NOTIFICATION - id: Optional[str] = None - conversation_id: Optional[str] = None - html_body: Optional[str] = None + id: str | None = None + conversation_id: str | None = None + html_body: str | None = None diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/email_response.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/email_response.py index 6aff69c5..6d365a1e 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/email_response.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/email_response.py @@ -1,9 +1,22 @@ +# Copyright (c) Microsoft. All rights reserved. + from typing import Literal + from microsoft_agents.activity.activity import Activity from microsoft_agents.activity.entity import Entity class EmailResponse(Entity): + """Entity representing an email response to be sent by an agent. + + This class encapsulates the HTML content that will be sent as a response to an + email notification. It is used to construct reply messages in Outlook scenarios. + + Attributes: + type: The entity type identifier, always set to "emailResponse". + html_body: The HTML content of the email response body. Defaults to empty string. + """ + type: Literal["emailResponse"] = "emailResponse" html_body: str = "" @@ -11,11 +24,23 @@ class EmailResponse(Entity): def create_email_response_activity(email_response_html_body: str) -> Activity: """Create a new Activity with an EmailResponse entity. + This factory method constructs a message activity containing an EmailResponse + entity, which can be sent back to respond to an email notification. + Args: - email_response_html_body: The HTML content for the email response. + email_response_html_body: The HTML content for the email response body. Returns: - A new Activity instance with type='message' and the EmailResponse entity attached. + A new Activity instance with type set to 'message' and the EmailResponse + entity attached to its entities list. + + Example: + ```python + activity = EmailResponse.create_email_response_activity( + "

Thank you for your email. I'll get back to you soon.

" + ) + await context.send_activity(activity) + ``` """ working_activity = Activity(type="message") email_response = EmailResponse(html_body=email_response_html_body) diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/notification_types.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/notification_types.py index 5aea900b..2e6f8de9 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/notification_types.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/notification_types.py @@ -1,7 +1,21 @@ +# Copyright (c) Microsoft. All rights reserved. + from enum import Enum class NotificationTypes(str, Enum): + """Enumeration of notification types supported by Agent 365. + + This enum defines the different types of notifications that agents can receive + from Microsoft 365 applications and services. + + Attributes: + EMAIL_NOTIFICATION: Notification related to email events in Outlook. + WPX_COMMENT: Notification related to comments in Word, PowerPoint, or Excel. + AGENT_LIFECYCLE: Notification related to agent lifecycle events such as user + creation, deletion, or workload onboarding updates. + """ + EMAIL_NOTIFICATION = "emailNotification" WPX_COMMENT = "wpxComment" AGENT_LIFECYCLE = "agentLifecycle" diff --git a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/wpx_comment.py b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/wpx_comment.py index a57f8d84..c624670d 100644 --- a/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/wpx_comment.py +++ b/libraries/microsoft-agents-a365-notifications/microsoft_agents_a365/notifications/models/wpx_comment.py @@ -1,12 +1,30 @@ -from typing import Optional, Literal +# Copyright (c) Microsoft. All rights reserved. + +from typing import Literal + from microsoft_agents.activity.entity import Entity + from .notification_types import NotificationTypes class WpxComment(Entity): + """Entity representing a comment notification from Word, PowerPoint, or Excel. + + This class encapsulates information about a comment made in a Microsoft Office + document (Word, PowerPoint, or Excel), including the document context and + comment hierarchy. + + Attributes: + type: The notification type identifier, always set to "wpxComment". + odata_id: The OData identifier for the comment resource. + document_id: The unique identifier of the document containing the comment. + parent_comment_id: The identifier of the parent comment, if this is a reply. + comment_id: The unique identifier of this comment. + """ + type: Literal["wpxComment"] = NotificationTypes.WPX_COMMENT - odata_id: Optional[str] = None - document_id: Optional[str] = None - parent_comment_id: Optional[str] = None - comment_id: Optional[str] = None + odata_id: str | None = None + document_id: str | None = None + parent_comment_id: str | None = None + comment_id: str | None = None diff --git a/libraries/microsoft-agents-a365-notifications/setup.py b/libraries/microsoft-agents-a365-notifications/setup.py index 1c812d3b..d9687204 100644 --- a/libraries/microsoft-agents-a365-notifications/setup.py +++ b/libraries/microsoft-agents-a365-notifications/setup.py @@ -2,8 +2,9 @@ # Licensed under the MIT License. import sys -from pathlib import Path from os import environ +from pathlib import Path + from setuptools import setup # Get version from environment variable set by CI/CD