Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
The Activity protocol is the communication protocol and standard protocol used across Microsoft in many Microsoft SDKs, services, and clients. This includes Microsoft 365 Copilot, Microsoft Copilot Studio, and the Microsoft 365 Agents SDK. The Activity protocol defines the shape of an Activity and how messages, events and interactions flow from channel, to your code and everywhere else in between. Agents can connect to one or more channels to interact with users and work with other agents. The Activity protocol standardizes the communication protocol between any client you're working with, including Microsoft and third party clients, so you don't have to create custom logic per channel you're working with.
What is an Activity?
An Activity is a structured JSON object that represents any interaction between a user and your agent. Activities aren't just text based messages, they can include various types of interaction including events such as a user joining or leaving for clients that support multiple users, typing indicators, file uploads, card actions, and custom events developers design themselves.
Every activity includes metadata about:
- Who sent it (from)
- Who should receive it (recipient)
- The conversation context
- The channel it originated from
- The type of interaction
- The payload data
Activity schema - key properties
This specification defines the Activity protocol: Activity protocol - Activity. Some of the key properties defined in the Activity protocol are:
| Property | Description |
|---|---|
Id |
Typically generated by the channel if originating from a channel |
Type |
The type controls the meaning of an activity, for example message type |
ChannelID |
The ChannelID references the channel that the activity originated from. For example: msteams. |
From |
The sender of the activity (which can be a user or agent) |
Recipient |
The intended recipient of the activity |
Text |
The text content of the message |
Attachment |
Rich content like cards, images of files |
Access activity Data
Developers need to access the data within the activity to complete actions from the TurnContext object.
You can find a TurnContext class in each language version of the Microsoft 365 Agents SDK:
- .NET: TurnContext
- Python: TurnContext
- JavaScript: TurnContext
Note
The code snippets in this article use C#. The syntax and API structure for the JavaScript and Python versions are similar.
The TurnContext is an important object that is used in every conversation turn in the Microsoft 365 Agents SDK. It provides access to the incoming activity, methods for sending responses, conversation state management, and the context needed to handle a single turn of conversation. It's used to maintain context, send appropriate responses and interact with your users in their client/channel effectively. Everytime your agent receives a new activity from a channel the Agents SDK creates a new TurnContext instance and passes it to your registered handlers/methods. This context object exists during the single turn and then disposed of once the turn ends.
A turn is defined as the round trip of a message sent from the client and making the journey to your code, your code handles that data and the code can optionally send a response back to complete the turn. That round trip can be broken up into:
- Incoming Activity: The user sends a message or performs an action that creates an activity.
- Your code receives the activity and the agent processes it using
TurnContext. - Your agent sends one or more activities back.
- The turn ends and the
TurnContextis disposed of.
Access data from the TurnContext, such as:
var messageText = turnContext.Activity.Text
var channelID = turnContext.Activity.ChannelId
This code snippet shows an example of a complete turn:
agent.OnActivity(ActivityTypes.Message, async (turnContext, turnState, cancellationToken) =>
{
var userMessage = turnContext.Activity.Text'
var response = $"you said: {userMessage}";
await turnContext.SendActivityAsync(MessageFactory.Text(response), cancellationToken);
});
Inside the TurnContext class, commonly used key information includes:
- Activity: The main way to get information from the Activity
- Adapter: The channel adapter that created the activity
- TurnState: The state for the turn
Activity types
The type of an activity is important as it defines what is required or expected in the rest of the activity between clients, users, and agents.
Message
A common type of activity is the Message type of Activity, that could include text, attachments, and suggested actions to name a few common uses for this type.
agent.OnActivity(ActivityTypes.Message, async (turnContext, turnState, cancellationToken) =>
{
var userMessage = turnContext.Activity.Text'
var response = $"you said: {userMessage}";
await turnContext.SendActivityAsync(MessageFactory.Text(response), cancellationToken);
});
ConversationUpdate
The ConversationUpdate type of Activity notifies your agent when members join or leave a conversation. Not all clients support this, a notable client that does is Microsoft Teams.
The following code snippet greets new members in a conversation:
agent.OnActivity(ActivityTypes.ConversationUpdate, async (turnContext turnState, cancellationToken) =>
{
var membersAdded = turnContext.Activity.MembersAdded
if (membersAdded != null)
{
foreach (var member in membersAdded)
{
if (member.Id != turnContext.Activity.Reciepient.Id)
{
await turnContext.SendActivityAsync(MessageFactory.Text($"Welcome {member.Name}!"), cancellationToken);
}
}
}
})
Events
The Event type of Activity are custom events that allow channels or clients to send structured data to your agent, which isn't predefined in the Activity payload structure.
You would need to create a method/route handler for the specific Event type and then manage the desired logic based on the:
Name - The event name or identifier from the client Value - Event payload that is typically a JSON object
agent.OnActivity(ActivityTypes.Event, async (turnContext turnState, cancellationToken) =>)
{
var eventName = turnContext.Activity.Name
var eventValue = turnContext.Activity.Value
// custom event (E.g. a switch on eventName)
}
Invoke
An Invoke type of Activity is a specific type of activity that a client is calling into an agent to perform a command or operation, and not just a message. Examples of these types of activities are common in Microsoft Teams for task/fetch and task/submit. Not all channels support these type of activities.
Typing
A Typing type of Activity is a classification of activity to indicate someone is typing in a conversation. This is commonly seen between human to human conversations in Microsoft Teams client for example. Typing activities aren't supported in every client, and notably Microsoft 365 Copilot doesn't support typing activities.
await turnContext.SendActivityAsync(new Activity { Type = ActivityTypes.Typing }, cancellationToken);
await Task.Delay(2000);
await turnContext.SendActivityAsync(MessageFactory.Text("Here is your answer..."), cancellationToken)
Create and send activities
To send responses, the 'TurnContext' provides multiple methods for sending responses back to the user.
agent.OnActivity(ActivityTypes.Message, async (turnContext, turnState, cancellationToken))
{
await turnContext.SendActivityAsync("hello!", cancellationToken: CancellationToken) // uses string directly
await turnContext.SendActivityAsync(MessageFactory.Text("Hello"), cancellationToken) // uses Message Factory
await turnContext.SendActivitiesAsync(activities, cancellationToken) // send multiple activities in an Activity array
}
Work with attachments
It's common for agents to work with attachments that have been submitted by users (or even other agents). The client sends a Message activity that includes an attachment (it's not a specific type of activity) and your code needs to handle receiving the message with the attachment, read the metadata, and securely fetch the file from the URL that the client provided. It would be typical to then move the file to your own storage.
To receive an attachment
The following code shows how to receive and attachment
agent.OnActivity(ActivityTypes.Message, async(turnContext, turnState, cancellationToken)) =>
{
var activity = turnContext.Activity;
if (activity.Attachments != null && activity.Attachments.Count >0)
{
foreach (var attachment in activity.Attachments)
{
// get metadata as required e.g. attachment.ContextType or attachment.ContentUrl
// use the URL to securely download the attachment and complete your business logic
}
}
}
Typically, to receive the document on the attachment the client sends an authenticated GET request to retrieve the actual contents - each adapter has its own way to get that data for example, Teams, OneDrive, and so on. It's also important to know that those urls are typically short lived, and so don't assume they'll stay there, which is why moving to your own storage is important if you need to refer to this later.
Citations
It's important to know that Attachment and Citation aren't the same object type. Citations are a handled by Clients, like Microsoft Teams, in their own ways, and use the Entities property of the Activity and can be added with activity.Entities.Add and add a new Entity object that has the specific Citation definition based on your client. It would get serialized as a JSON object that the client then deserializes based on how it renders in the client. Fundamentally, Attachments are messages, and Citations can reference attachments and are an another object sent in Entities of the Activity payload.
Channel specific considerations
The Microsoft 365 Agents SDK is built as a 'Hub' that allows the developers to create agents that can work with any client, including the clients we support and provide the tools for developers to build their own channel adapter using the same framework. This gives developers breadth when it comes to agents, and provides extensibility to clients to connect to that hub, which can be one or more clients like Microsoft Teams, Slack, and more.
Different channels have different capabilities and limitations, and the following is a summary of considerations when working with common clients.
You can check the channel you have received the activity from by inspecting the channelId property in the Activity.
Channels include specific data that doesn't conform to the generic Activity payload across all channels, and this can be accessed from the TurnContext.Activity.ChannelData and specifically casting it to variables for use in your code.
Microsoft Teams
- Supports rich Adaptive Cards with advanced features
- Supports message updates and deletions
- Has specific channel data for Teams features (mentions, meeting info, and so on)
- Supports invoke activities for task modules
Microsoft 365 Copilot
- Primarily focused on message activities
- Supports citations and references in responses
- Requires streaming responses
- Limited support for rich cards/adaptive cards
WebChat/DirectLine
Web Chat is an HTTP protocol used for agents to talk over HTTPS
- Full support for all activity types
- Supports custom channel data
Third party channels
These include Slack, Facebook, and more.
- Might have limited support for certain activity types
- Card rendering might be different or unsupported
- Always check specific channel documentation