Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .azdo/ci-pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ steps:
python -m pip install ./dist/microsoft_agents_authentication*.whl
python -m pip install ./dist/microsoft_agents_connector*.whl
python -m pip install ./dist/microsoft_agents_client*.whl
python -m pip install ./dist/microsoft_agents_botbuilder*.whl
python -m pip install ./dist/microsoft_agents_builder*.whl
python -m pip install ./dist/microsoft_agents_authorization_msal*.whl
python -m pip install ./dist/microsoft_agents_copilotstudio_client*.whl
python -m pip install ./dist/microsoft_agents_hosting_aiohttp*.whl
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ jobs:
python -m pip install ./dist/microsoft_agents_authentication*.whl
python -m pip install ./dist/microsoft_agents_connector*.whl
python -m pip install ./dist/microsoft_agents_client*.whl
python -m pip install ./dist/microsoft_agents_botbuilder*.whl
python -m pip install ./dist/microsoft_agents_builder*.whl
python -m pip install ./dist/microsoft_agents_authorization_msal*.whl
python -m pip install ./dist/microsoft_agents_copilotstudio_client*.whl
python -m pip install ./dist/microsoft_agents_hosting_aiohttp*.whl
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from typing import Protocol, Optional

from microsoft.agents.authentication import BotAuthConfiguration
from microsoft.agents.authentication import AgentAuthConfiguration

from .auth_types import AuthTypes


class MsalAuthConfiguration(BotAuthConfiguration, Protocol):
class MsalAuthConfiguration(AgentAuthConfiguration, Protocol):
"""
Configuration for MSAL authentication.
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Import necessary modules
from .activity_handler import ActivityHandler
from .bot import Bot
from .agent import Agent
from .channel_adapter import ChannelAdapter
from .channel_api_handler_protocol import ChannelApiHandlerProtocol
from .channel_service_adapter import ChannelServiceAdapter
Expand All @@ -13,7 +13,7 @@
# Define the package's public interface
__all__ = [
"ActivityHandler",
"Bot",
"Agent",
"ChannelAdapter",
"ChannelApiHandlerProtocol",
"ChannelServiceAdapter",
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
from .turn_context import TurnContext


class Bot(Protocol):
class Agent(Protocol):
"""
Represents a bot that can operate on incoming activities.
Represents an agent that can operate on incoming activities.
"""

@abstractmethod
async def on_turn(self, context: TurnContext):
"""
When implemented in a bot, handles an incoming activity.
When implemented in an agent, handles an incoming activity.
:param context: The context object for this turn.
:return:
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@


class ChannelAdapter(ABC, ChannelAdapterProtocol):
BOT_IDENTITY_KEY = "BotIdentity"
OAUTH_SCOPE_KEY = "Microsoft.Agents.BotBuilder.ChannelAdapter.OAuthScope"
AGENT_IDENTITY_KEY = "AgentIdentity"
OAUTH_SCOPE_KEY = "Microsoft.Agents.Builder.ChannelAdapter.OAuthScope"
INVOKE_RESPONSE_KEY = "ChannelAdapter.InvokeResponse"

on_turn_error: Callable[[TurnContext, Exception], Awaitable] = None
Expand Down Expand Up @@ -50,7 +50,7 @@ async def update_activity(self, context: TurnContext, activity: Activity):
:param context: The context object for the turn.
:type context: :class:`TurnContext`
:param activity: New replacement activity.
:type activity: :class:`botbuilder.schema.Activity`
:type activity: :class:`builder.schema.Activity`
:return:
"""
raise NotImplementedError()
Expand All @@ -65,7 +65,7 @@ async def delete_activity(
:param context: The context object for the turn.
:type context: :class:`TurnContext`
:param reference: Conversation reference for the activity to delete.
:type reference: :class:`botbuilder.schema.ConversationReference`
:type reference: :class:`builder.schema.ConversationReference`
:return:
"""
raise NotImplementedError()
Expand All @@ -82,24 +82,24 @@ def use(self, middleware):

async def continue_conversation(
self,
bot_id: str, # pylint: disable=unused-argument
agent_id: str, # pylint: disable=unused-argument
reference: ConversationReference,
callback: Callable[[TurnContext], Awaitable],
):
"""
Sends a proactive message to a conversation. Call this method to proactively send a message to a conversation.
Most channels require a user to initiate a conversation with a bot before the bot can send activities
Most channels require a user to initiate a conversation with an agent before the agent can send activities
to the user.

:param bot_id: The application ID of the bot. This parameter is ignored in
single tenant the Adapters (Console, Test, etc) but is critical to the BotFrameworkAdapter
:param agent_id: The application ID of the agent. This parameter is ignored in
single tenant the Adapters (Console, Test, etc) but is critical to the ChannelAdapter
which is multi-tenant aware.
:param reference: A reference to the conversation to continue.
:type reference: :class:`botbuilder.schema.ConversationReference`
:param callback: The method to call for the resulting bot turn.
:type reference: :class:`builder.schema.ConversationReference`
:param callback: The method to call for the resulting agent turn.
:type callback: :class:`typing.Callable`
:param claims_identity: A :class:`botframework.connector.auth.ClaimsIdentity` for the conversation.
:type claims_identity: :class:`botframework.connector.auth.ClaimsIdentity`
:param claims_identity: A :class:`microsoft.agents.authentication.ClaimsIdentity` for the conversation.
:type claims_identity: :class:`microsoft.agents.authentication.ClaimsIdentity`
:param audience:A value signifying the recipient of the proactive message.
:type audience: str
"""
Expand All @@ -115,14 +115,14 @@ async def continue_conversation_with_claims(
):
"""
Sends a proactive message to a conversation. Call this method to proactively send a message to a conversation.
Most channels require a user to initiate a conversation with a bot before the bot can send activities
Most channels require a user to initiate a conversation with an agent before the agent can send activities
to the user.

:param claims_identity: A :class:`botframework.connector.auth.ClaimsIdentity` for the conversation.
:type claims_identity: :class:`botframework.connector.auth.ClaimsIdentity`
:param claims_identity: A :class:`microsoft.agents.authentication.ClaimsIdentity` for the conversation.
:type claims_identity: :class:`microsoft.agents.authentication.ClaimsIdentity`
:param continuation_activity: The activity to send.
:type continuation_activity: :class:`botbuilder
:param callback: The method to call for the resulting bot turn.
:type continuation_activity: :class:`builder
:param callback: The method to call for the resulting agent turn.
:type callback: :class:`typing.Callable`
:param audience: A value signifying the recipient of the proactive message.
:type audience: str
Expand All @@ -131,7 +131,7 @@ async def continue_conversation_with_claims(

async def create_conversation(
self,
bot_app_id: str,
agent_app_id: str,
channel_id: str,
service_url: str,
audience: str,
Expand All @@ -142,7 +142,7 @@ async def create_conversation(
Starts a new conversation with a user. Used to direct message to a member of a group.

:param reference: The conversation reference that contains the tenant
:type reference: :class:`botbuilder.schema.ConversationReference`
:type reference: :class:`builder.schema.ConversationReference`
:param logic: The logic to use for the creation of the conversation
:type logic: :class:`typing.Callable`
:param conversation_parameters: The information to use to create the conversation
Expand All @@ -151,15 +151,15 @@ async def create_conversation(
:type channel_id: :class:`typing.str`
:param service_url: The channel's service URL endpoint.
:type service_url: :class:`typing.str`
:param credentials: The application credentials for the bot.
:type credentials: :class:`botframework.connector.auth.AppCredentials`
:param credentials: The application credentials for the agent.
:type credentials: :class:`microsoft.agents.authentication.AppCredentials`

:raises: It raises a generic exception error.

:return: A task representing the work queued to execute.

.. remarks::
To start a conversation, your bot must know its account information and the user's
To start a conversation, your agent must know its account information and the user's
account information on that channel.
Most channels only support initiating a direct message (non-group) conversation.
The adapter attempts to create a new conversation on the channel, and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ async def on_get_conversations(
continuation_token: Optional[str] = None,
) -> ConversationsResult:
"""
List the Conversations in which this bot has participated.
List the Conversations in which this agent has participated.
"""
raise NotImplementedError()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@
class ChannelServiceAdapter(ChannelAdapter, ABC):
CONNECTOR_FACTORY_KEY = "ConnectorFactory"
USER_TOKEN_CLIENT_KEY = "UserTokenClient"
BOT_CALLBACK_HANDLER_KEY = "BotCallbackHandler"
AGENT_CALLBACK_HANDLER_KEY = "AgentCallbackHandler"
CHANNEL_SERVICE_FACTORY_KEY = "ChannelServiceClientFactory"
_BOT_CONNECTOR_CLIENT_KEY = "ConnectorClient"
_INVOKE_RESPONSE_KEY = "BotFrameworkAdapter.InvokeResponse"
_AGENT_CONNECTOR_CLIENT_KEY = "ConnectorClient"
_INVOKE_RESPONSE_KEY = "ChannelServiceAdapter.InvokeResponse"

def __init__(self, channel_service_client_factory: ChannelServiceClientFactoryBase):
super().__init__()
Expand Down Expand Up @@ -82,7 +82,7 @@ async def send_activities(
else:
connector_client = cast(
ConnectorClientBase,
context.turn_state.get(self._BOT_CONNECTOR_CLIENT_KEY),
context.turn_state.get(self._AGENT_CONNECTOR_CLIENT_KEY),
)
if not connector_client:
raise Error("Unable to extract ConnectorClient from turn context.")
Expand Down Expand Up @@ -117,7 +117,8 @@ async def update_activity(self, context: TurnContext, activity: Activity):
raise TypeError("Expected Activity but got None instead")

connector_client = cast(
ConnectorClientBase, context.turn_state.get(self._BOT_CONNECTOR_CLIENT_KEY)
ConnectorClientBase,
context.turn_state.get(self._AGENT_CONNECTOR_CLIENT_KEY),
)
if not connector_client:
raise Error("Unable to extract ConnectorClient from turn context.")
Expand All @@ -136,7 +137,8 @@ async def delete_activity(
raise TypeError("Expected ConversationReference but got None instead")

connector_client = cast(
ConnectorClientBase, context.turn_state.get(self._BOT_CONNECTOR_CLIENT_KEY)
ConnectorClientBase,
context.turn_state.get(self._AGENT_CONNECTOR_CLIENT_KEY),
)
if not connector_client:
raise Error("Unable to extract ConnectorClient from turn context.")
Expand All @@ -147,23 +149,23 @@ async def delete_activity(

async def continue_conversation( # pylint: disable=arguments-differ
self,
bot_app_id: str,
agent_app_id: str,
continuation_activity: Activity,
callback: Callable[[TurnContext], Awaitable],
):
"""
Sends a proactive message to a conversation.
Call this method to proactively send a message to a conversation.
Most channels require a user to initiate a conversation with a bot before the bot can send activities
Most channels require a user to initiate a conversation with an agent before the agent can send activities
to the user.

:param reference: A reference to the conversation to continue.
:type reference: :class:`botbuilder.schema.ConversationReference`
:param callback: The method to call for the resulting bot turn.
:type reference: :class:`builder.schema.ConversationReference`
:param callback: The method to call for the resulting agent turn.
:type callback: :class:`typing.Callable`
:param bot_app_id: The application Id of the bot. This is the appId returned by the Azure portal registration,
:param agent_app_id: The application Id of the agent. This is the appId returned by the Azure portal registration,
and is generally found in the `MicrosoftAppId` parameter in `config.py`.
:type bot_app_id: :class:`typing.str`
:type agent_app_id: :class:`typing.str`
"""
if not callable:
raise TypeError(
Expand All @@ -172,7 +174,7 @@ async def continue_conversation( # pylint: disable=arguments-differ

self._validate_continuation_activity(continuation_activity)

claims_identity = self.create_claims_identity(bot_app_id)
claims_identity = self.create_claims_identity(agent_app_id)

return await self.process_proactive(
claims_identity,
Expand All @@ -194,7 +196,7 @@ async def continue_conversation_with_claims(

async def create_conversation( # pylint: disable=arguments-differ
self,
bot_app_id: str,
agent_app_id: str,
channel_id: str,
service_url: str,
audience: str,
Expand All @@ -213,7 +215,7 @@ async def create_conversation( # pylint: disable=arguments-differ
raise TypeError("CloudAdapter.create_conversation(): callback is required.")

# Create a ClaimsIdentity, to create the connector and for adding to the turn context.
claims_identity = self.create_claims_identity(bot_app_id)
claims_identity = self.create_claims_identity(agent_app_id)
claims_identity.claims[AuthenticationConstants.SERVICE_URL_CLAIM] = service_url

# Create the connector client to use for outbound requests.
Expand Down Expand Up @@ -314,23 +316,23 @@ async def process_activity(
:return: A task that represents the work queued to execute.

.. remarks::
This class processes an activity received by the bots web server. This includes any messages
This class processes an activity received by the agents web server. This includes any messages
sent from a user and is the method that drives what's often referred to as the
bots *reactive messaging* flow.
agent *reactive messaging* flow.
Call this method to reactively send a message to a conversation.
If the task completes successfully, then an :class:`InvokeResponse` is returned;
otherwise. `null` is returned.
"""
scopes: list[str] = None
outgoing_audience: str = None

if claims_identity.is_bot_claim():
if claims_identity.is_agent_claim():
outgoing_audience = claims_identity.get_token_audience()
scopes = [f"{claims_identity.get_outgoing_app_id()}/.default"]
activity.caller_id = f"{CallerIdConstants.bot_to_bot_prefix}{claims_identity.get_outgoing_app_id()}"
activity.caller_id = f"{CallerIdConstants.agent_to_agent_prefix}{claims_identity.get_outgoing_app_id()}"
else:
outgoing_audience = AuthenticationConstants.BOT_FRAMEWORK_SCOPE
scopes = [f"{AuthenticationConstants.BOT_FRAMEWORK_SCOPE}/.default"]
outgoing_audience = AuthenticationConstants.AGENTS_SDK_SCOPE
scopes = [f"{AuthenticationConstants.AGENTS_SDK_SCOPE}/.default"]

use_anonymous_auth_callback = False
if (
Expand Down Expand Up @@ -375,11 +377,11 @@ async def process_activity(
# If there are any results they will have been left on the TurnContext.
return self._process_turn_results(context)

def create_claims_identity(self, bot_app_id: str = "") -> ClaimsIdentity:
def create_claims_identity(self, agent_app_id: str = "") -> ClaimsIdentity:
return ClaimsIdentity(
{
AuthenticationConstants.AUDIENCE_CLAIM: bot_app_id,
AuthenticationConstants.APP_ID_CLAIM: bot_app_id,
AuthenticationConstants.AUDIENCE_CLAIM: agent_app_id,
AuthenticationConstants.APP_ID_CLAIM: agent_app_id,
},
False,
)
Expand Down Expand Up @@ -417,7 +419,7 @@ def _create_create_activity(
tenant_id=conversation_parameters.tenant_id,
)
activity.channel_data = conversation_parameters.channel_data
activity.recipient = conversation_parameters.bot
activity.recipient = conversation_parameters.agent

return activity

Expand All @@ -432,10 +434,10 @@ def _create_turn_context(
) -> TurnContext:
context = TurnContext(self, activity)

context.turn_state[self.BOT_IDENTITY_KEY] = claims_identity
context.turn_state[self._BOT_CONNECTOR_CLIENT_KEY] = connector_client
context.turn_state[self.AGENT_IDENTITY_KEY] = claims_identity
context.turn_state[self._AGENT_CONNECTOR_CLIENT_KEY] = connector_client
context.turn_state[self.USER_TOKEN_CLIENT_KEY] = user_token_client
context.turn_state[self.BOT_CALLBACK_HANDLER_KEY] = callback
context.turn_state[self.AGENT_CALLBACK_HANDLER_KEY] = callback
context.turn_state[self.CHANNEL_SERVICE_FACTORY_KEY] = (
self._channel_service_client_factory
)
Expand All @@ -454,7 +456,7 @@ def _process_turn_results(self, context: TurnContext) -> InvokeResponse:
).model_dump(mode="json", by_alias=True, exclude_unset=True),
)

# Handle Invoke scenarios where the bot will return a specific body and return code.
# Handle Invoke scenarios where the agent will return a specific body and return code.
if context.activity.type == ActivityTypes.invoke:
activity_invoke_response: Activity = context.turn_state.get(
self._INVOKE_RESPONSE_KEY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ def attachment_activity(

class MessageFactory:
"""
A set of utility functions designed to assist with the formatting of the various message types a
bot can return.
A set of utility functions designed to assist with the formatting of the various message types
an agent can return.
"""

@staticmethod
Expand Down
Loading