From df4206b652544735634799d70f73f6198d2a8635 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 02:28:23 +0000 Subject: [PATCH 1/3] Initial plan From 4c1e71602a6a3f1134185ce1363a0a3123a710a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 02:38:34 +0000 Subject: [PATCH 2/3] Add signin/failure invoke activity support Co-authored-by: heyitsaamir <48929123+heyitsaamir@users.noreply.github.com> --- .../api/activities/invoke/sign_in/__init__.py | 4 +- .../api/activities/invoke/sign_in/failure.py | 24 ++++++ .../teams/api/models/sign_in/__init__.py | 3 +- .../teams/api/models/sign_in/failure.py | 26 +++++++ .../unit/test_signin_failure_activity.py | 76 +++++++++++++++++++ .../teams/mcpplugin/server_plugin.py | 4 +- 6 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 packages/api/src/microsoft/teams/api/activities/invoke/sign_in/failure.py create mode 100644 packages/api/src/microsoft/teams/api/models/sign_in/failure.py create mode 100644 packages/api/tests/unit/test_signin_failure_activity.py diff --git a/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/__init__.py b/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/__init__.py index 04dd5668..d24cd546 100644 --- a/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/__init__.py +++ b/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/__init__.py @@ -7,16 +7,18 @@ from pydantic import Field +from .failure import SignInFailureInvokeActivity from .token_exchange import SignInTokenExchangeInvokeActivity from .verify_state import SignInVerifyStateInvokeActivity SignInInvokeActivity = Annotated[ - Union[SignInTokenExchangeInvokeActivity, SignInVerifyStateInvokeActivity], + Union[SignInTokenExchangeInvokeActivity, SignInVerifyStateInvokeActivity, SignInFailureInvokeActivity], Field(discriminator="name"), ] __all__ = [ "SignInTokenExchangeInvokeActivity", "SignInVerifyStateInvokeActivity", + "SignInFailureInvokeActivity", "SignInInvokeActivity", ] diff --git a/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/failure.py b/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/failure.py new file mode 100644 index 00000000..607046fe --- /dev/null +++ b/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/failure.py @@ -0,0 +1,24 @@ +""" +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the MIT License. +""" + +from typing import Literal + +from ....models import SignInFailure +from ...invoke_activity import InvokeActivity + + +class SignInFailureInvokeActivity(InvokeActivity): + """ + Sign-in failure invoke activity for signin/failure invokes. + + Represents an invoke activity when a sign-in operation fails + during the authentication process. + """ + + name: Literal["signin/failure"] = "signin/failure" # + """The name of the operation associated with an invoke or event activity.""" + + value: SignInFailure + """A value that is associated with the activity.""" diff --git a/packages/api/src/microsoft/teams/api/models/sign_in/__init__.py b/packages/api/src/microsoft/teams/api/models/sign_in/__init__.py index 2baa687a..ca4558b3 100644 --- a/packages/api/src/microsoft/teams/api/models/sign_in/__init__.py +++ b/packages/api/src/microsoft/teams/api/models/sign_in/__init__.py @@ -5,7 +5,8 @@ from .card import SignInCard from .exchange_token import SignInExchangeToken +from .failure import SignInFailure from .response import SignInUrlResponse from .state_verify_query import SignInStateVerifyQuery -__all__ = ["SignInUrlResponse", "SignInCard", "SignInExchangeToken", "SignInStateVerifyQuery"] +__all__ = ["SignInUrlResponse", "SignInCard", "SignInExchangeToken", "SignInStateVerifyQuery", "SignInFailure"] diff --git a/packages/api/src/microsoft/teams/api/models/sign_in/failure.py b/packages/api/src/microsoft/teams/api/models/sign_in/failure.py new file mode 100644 index 00000000..1bcaa061 --- /dev/null +++ b/packages/api/src/microsoft/teams/api/models/sign_in/failure.py @@ -0,0 +1,26 @@ +""" +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the MIT License. +""" + +from typing import Optional + +from ..custom_base_model import CustomBaseModel + + +class SignInFailure(CustomBaseModel): + """ + Sign-in failure information. + + Represents the details of a sign-in failure including + an error code and message. + """ + + code: Optional[str] = None + """ + The error code for the sign-in failure + """ + message: Optional[str] = None + """ + The error message for the sign-in failure + """ diff --git a/packages/api/tests/unit/test_signin_failure_activity.py b/packages/api/tests/unit/test_signin_failure_activity.py new file mode 100644 index 00000000..ca6ec9e0 --- /dev/null +++ b/packages/api/tests/unit/test_signin_failure_activity.py @@ -0,0 +1,76 @@ +""" +Copyright (c) Microsoft Corporation. All rights reserved. +Licensed under the MIT License. +""" + +import pytest +from microsoft.teams.api.activities.invoke.sign_in import SignInFailureInvokeActivity +from microsoft.teams.api.models import Account, ConversationAccount, SignInFailure + + +@pytest.mark.unit +class TestSignInFailureInvokeActivity: + """Unit tests for SignInFailureInvokeActivity class.""" + + def test_should_create_signin_failure_activity(self) -> None: + """Test creating a signin failure activity with code and message.""" + failure = SignInFailure(code="resourcematchfailed", message="Resource match failed") + user = Account(id="user-1", name="Test User") + bot = Account(id="bot-1", name="Test Bot") + conversation = ConversationAccount(id="conv-1") + + activity = SignInFailureInvokeActivity( + id="activity-1", + name="signin/failure", + value=failure, + from_=user, + conversation=conversation, + recipient=bot, + ) + + assert activity.name == "signin/failure" + assert activity.type == "invoke" + assert activity.value.code == "resourcematchfailed" + assert activity.value.message == "Resource match failed" + + def test_should_deserialize_signin_failure_activity(self) -> None: + """Test deserializing a signin failure activity from JSON-like dict.""" + activity_dict = { + "id": "activity-1", + "name": "signin/failure", + "type": "invoke", + "from": {"id": "user-1", "name": "Test User"}, + "conversation": {"id": "conv-1"}, + "recipient": {"id": "bot-1", "name": "Test Bot"}, + "value": {"code": "resourcematchfailed", "message": "Resource match failed"}, + } + + activity = SignInFailureInvokeActivity.model_validate(activity_dict) + + assert activity.name == "signin/failure" + assert activity.type == "invoke" + assert activity.value.code == "resourcematchfailed" + assert activity.value.message == "Resource match failed" + + def test_should_serialize_signin_failure_activity(self) -> None: + """Test serializing a signin failure activity to dict.""" + failure = SignInFailure(code="unauthorized", message="Unauthorized access") + user = Account(id="user-1", name="Test User") + bot = Account(id="bot-1", name="Test Bot") + conversation = ConversationAccount(id="conv-1") + + activity = SignInFailureInvokeActivity( + id="activity-1", + name="signin/failure", + value=failure, + from_=user, + conversation=conversation, + recipient=bot, + ) + + serialized = activity.model_dump() + + assert serialized["name"] == "signin/failure" + assert serialized["type"] == "invoke" + assert serialized["value"]["code"] == "unauthorized" + assert serialized["value"]["message"] == "Unauthorized access" diff --git a/packages/mcpplugin/src/microsoft/teams/mcpplugin/server_plugin.py b/packages/mcpplugin/src/microsoft/teams/mcpplugin/server_plugin.py index 43a3b1db..c095ad51 100644 --- a/packages/mcpplugin/src/microsoft/teams/mcpplugin/server_plugin.py +++ b/packages/mcpplugin/src/microsoft/teams/mcpplugin/server_plugin.py @@ -29,9 +29,7 @@ P = TypeVar("P", bound=BaseModel) -@Plugin( - name="mcp-server", version=version, description="MCP server plugin that exposes AI functions as MCP tools" -) +@Plugin(name="mcp-server", version=version, description="MCP server plugin that exposes AI functions as MCP tools") class McpServerPlugin(PluginBase): """ MCP Server Plugin for Teams Apps. From ce7c1e743a9ccce1427b56e43e9bca5d4c236032 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 6 Nov 2025 02:44:20 +0000 Subject: [PATCH 3/3] Remove trailing comment marker from failure.py Co-authored-by: heyitsaamir <48929123+heyitsaamir@users.noreply.github.com> --- .../microsoft/teams/api/activities/invoke/sign_in/failure.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/failure.py b/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/failure.py index 607046fe..9b6ada6a 100644 --- a/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/failure.py +++ b/packages/api/src/microsoft/teams/api/activities/invoke/sign_in/failure.py @@ -17,7 +17,7 @@ class SignInFailureInvokeActivity(InvokeActivity): during the authentication process. """ - name: Literal["signin/failure"] = "signin/failure" # + name: Literal["signin/failure"] = "signin/failure" """The name of the operation associated with an invoke or event activity.""" value: SignInFailure