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.
To enable users to install an agent in a team or group chat, add the teams or groupchat scope. This allows all members of the conversation to interact with your agent. After the agent is installed, it has access to metadata about the conversation, such as the list of conversation members. Also, when it's installed in a team, the agent has access to details about that team and the full list of channels.
By default, agents in group chats and channels only receive messages when they're directly @mentioned. They don't receive other messages sent to the conversation. For example, your agent doesn't receive a message when the team or channel is mentioned, or when someone replies to a message from your agent without @mentioning it. The Teams SDK provides a dedicated mention activity route to handle @mention events.
Note
- Using resource-specific consent (RSC), an agent can receive all channel and group chat messages in conversations where it's installed without being @mentioned. For more information, see receive all messages for agents.
- Private channel support for agent apps is limited. You can add agent-enabled apps in private channels where private channel app support is enabled, but agents can't post messages or Adaptive Cards in private channel conversations. For private and shared channel app support details, see apps for shared and private channels.
Design guidelines
In group chats and channels, design your agent for collaborative conversations with clear value, concise responses, and minimal noise.
Threaded conversations
In Teams channels, messages can be organized into threads. When your agent receives a message in a thread, the conversation context already carries the thread ID. Use Send() to send a message in the same thread without quoting, or Reply() to send with a visual quote of the inbound message.
app.OnMessage(async (context, cancellationToken) =>
{
// Send in the same thread, no quote
await context.Send("Acknowledged", cancellationToken);
// Send in the same thread with a visual quote of the inbound message
await context.Reply("Got it!", cancellationToken);
});
When your agent receives a message in a thread, the conversation context already carries the thread ID. Use send() to send a message in the same thread without quoting, or reply() to send with a visual quote of the inbound message.
app.on('message', async ({ send, reply }) => {
// Send in the same thread, no quote
await send('Acknowledged');
// Send in the same thread with a visual quote of the inbound message
await reply('Got it!');
});
When your agent receives a message in a thread, the conversation context already carries the thread ID. Use send() to send a message in the same thread without quoting, or reply() to send with a visual quote of the inbound message.
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
# Send in the same thread, no quote
await ctx.send("Acknowledged")
# Send in the same thread with a visual quote of the inbound message
await ctx.reply("Got it!")
For sending messages into a thread proactively, see Proactive messages.
Send a message on installation
When your agent is first added to a group or team, you can send an introduction message by using the install.add lifecycle route. For more information, see proactive messaging.
If you send an introduction message, include a brief description of the agent's features and how to use them.
You can also store the conversationId during installation to enable proactive messaging later.
The following code shows an example of sending welcome messages on installation:
app.OnInstall(async context =>
{
await context.Send("Hello! I'm your agent. Here's what I can do...");
});
app.on('install.add', async ({ send }) =>
{
await send('Hello! I\'m your agent. Here\'s what I can do...');
});
@app.on_install_add
async def handle_install_add(ctx: ActivityContext[InstalledActivity]):
await ctx.send("Hello! I'm your agent. Here's what I can do...")
Don't send proactive welcome messages to users individually when the agent is installed in a team or group chat. If you send a welcome message, post it in the installed conversation and mention the person who added the agent.
Note
Ensure that the message sent by the agent is relevant and adds value to the initial message and doesn't spam the users.
Don't send a message in the following cases:
- When the team is large, for example, larger than 100 members. Your agent can be seen as spam and the person who added it can get complaints. You must clearly communicate your agent's value proposition to everyone who sees the welcome message.
- Your agent is first mentioned in a group or channel instead of being first added to a team.
- A group or channel is renamed.
- A team member is added to a group or channel.
Work with mentions
In group chats and channels, messages that @mention your agent include a mention entity in the message text. If your agent is configured to receive all messages, such as with RSC, some incoming messages might not include an @mention. Your agent can retrieve other users mentioned in a message and add mentions to messages it sends. Agents in group chats enable user mentions using @mention; however, they don’t support @everyone for mentions.
For messages that include @mentions, the message text contains mention markup such as <at>@agentname</at>.
Retrieve mentions
Mentions are returned in the entities object in the activity payload and contain both the unique ID of the user and the name of the user mentioned. The text of the message also includes the mention, such as <at>@John Smith<at>. However, don't rely on the text in the message to retrieve any information about the user. It's possible for the person sending the message to alter it. Therefore, use the entities object.
You can retrieve all mentions in the message by filtering the entities array in the activity for entries with type set to mention.
The following code shows an example of retrieving mentions:
app.OnMessage(async context =>
{
var mentions = context.Activity.Entities?
.Where(e => e.Type == "mention")
.ToList();
if (mentions != null && mentions.Any())
{
var firstMention = mentions[0].Properties["mentioned"]?["name"]?.ToString();
await context.Send($"Hello {firstMention}");
}
else
{
await context.Send("Aw, no one was mentioned.");
}
});
app.on('message', async ({ activity, send }) => {
const mentions = activity.entities?.filter(e => e.type === 'mention');
if (mentions && mentions.length > 0) {
const firstMention = mentions[0].mentioned;
await send(`Hello ${firstMention.name}.`);
} else {
await send('Aw, no one was mentioned.');
}
});
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
mentions = [e for e in (ctx.activity.entities or []) if e.type == "mention"]
if mentions:
first_mention = mentions[0].mentioned
await ctx.send(f"Hello {first_mention.name}")
else:
await ctx.send("Aw, no one was mentioned.")
{
"type": "message",
"text": "Hey <at>Pranav Smith</at> check out this message",
"timestamp": "2017-10-29T00:51:05.9908157Z",
"localTimestamp": "2017-10-28T17:51:05.9908157-07:00",
"serviceUrl": "https://skype.botframework.com",
"channelId": "msteams",
"from": {
"id": "29:9e52142b-5e5e-4d7b-bb3e-e82dcf620000",
"name": "Jane Smith"
},
"conversation": {
"id": "19:aebd0ad4d6ab42c8b9ed19c251c2fc37@thread.skype;messageid=1481567603816"
},
"recipient": {
"id": "8:orgid:6aebbad0-e5a5-424a-834a-20fb051f3c1a",
"name": "stlrgload100"
},
"attachments": [
{
"contentType": "image/png",
"contentUrl": "https://upload.wikimedia.org/wikipedia/en/a/a6/Bender_Rodriguez.png",
"name": "Bender_Rodriguez.png"
}
],
"entities": [
{
"type":"mention",
"mentioned":{
"id":"29:08q2j2o3jc09au90eucae",
"name":"Pranav Smith"
},
"text": "<at>@Pranav Smith</at>"
}
],
"replyToId": "3UP4UTkzUk1zzeyW"
}
Check for and strip @mention
In channels and group chats, users typically address an agent or app with an @mention. Before interpreting the message, check that the mention targets your agent or app, then remove the mention text and trim whitespace. This leaves only the user’s command or prompt for processing.
Removing the mention prevents the agent or app name from interfering with command matching, intent recognition, search, or natural-language processing. It also lets the same handler process messages consistently across personal chats, group chats, and channels. Preserve other mentions when they are part of the user’s request.
Note
The TypeScript and Python versions for Teams SDK include built-in functions to remove @mention.
string StripMentions(MessageActivity msg)
{
var text = msg.Text ?? "";
if (msg.Entities == null) return text;
foreach (var entity in msg.Entities)
{
if (entity is MentionEntity mention && mention.Text != null)
{
text = text.Replace(mention.Text, "");
}
}
return text.Trim();
}
This code snippet demonstrates how to clean a Teams message before command parsing:
msg.Entitiescontains structured metadata such as mentions.Replace(mention.Text, "")removes the visible mention such as@contosofrom the message.Trim()removes leftover spaces.
For example, @contoso summarize this thread becomes summarize this thread.
The function removes all mentions, not only the agent's or bot’s mention. If other mentions are meaningful input, verify that a mention refers to the current bot before removing it.
app.on('message', async ({ activity, send }) => {
const clean = activity.stripMentionsText().text;
await send(`You said: ${clean}`);
});
This code snippet demonstrates listening for incoming message activities and removing the @mention text before processing the user’s message.
activity.stripMentionsText()removes mention text such as @contoso from the activity..textretrieves the cleaned message content.send()echoes the cleaned text back to the user.
For example, @contoso summarize this chat becomes summarize this chat, so the agent can parse the command.
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
clean = ctx.activity.strip_mentions_text().text
await ctx.send(f"You said: {clean}")
This code snippets shows how to listen for incoming messages and remove @mention text before processing them.
ctx.activity.strip_mentions_text()removes mention text such as @contoso..textreturns the cleaned message.ctx.send()replies with the cleaned text.
For example, @contoso summarize this chat becomes summarize this chat, making the message easier to parse as a command or prompt.
Add mentions to your messages
Your agent can mention other users in messages posted in channels. To include a mention inline in your message, place the mention in the message text and add the mention details to the entities array. The text field in the mention entity must match the exact text in the message body.
The following code shows an example of adding mentions to your messages:
app.OnMessage(async context =>
{
var user = context.Activity.From;
var message = new MessageActivity($"Hello <at>{user.Name}</at>!").AddMention(user);
await context.Send(message);
});
app.on('message', async ({ send, activity }) => {
const user = activity.from;
const message = new MessageActivity(`Hello <at>${user.name}</at>!`).addMention(user);
await send(message);
});
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
await ctx.send(MessageActivityInput(text="Hello!").add_mention(account=ctx.activity.from_))
{
"type": "message",
"text": "Hey <at>Pranav Smith</at> check out this message",
"timestamp": "2017-10-29T00:51:05.9908157Z",
"localTimestamp": "2017-10-28T17:51:05.9908157-07:00",
"serviceUrl": "https://skype.botframework.com",
"channelId": "msteams",
"from": {
"id": "29:9e52142b-5e5e-4d7b-bb3e-e82dcf620000",
"name": "Jane Smith"
},
"conversation": {
"id": "19:aebd0ad4d6ab42c8b9ed19c251c2fc37@thread.skype;messageid=1481567603816"
},
"recipient": {
"id": "8:orgid:6aebbad0-e5a5-424a-834a-20fb051f3c1a",
"name": "stlrgload100"
},
"attachments": [
{
"contentType": "image/png",
"contentUrl": "https://upload.wikimedia.org/wikipedia/en/a/a6/Bender_Rodriguez.png",
"name": "Bender_Rodriguez.png"
}
],
"entities": [
{
"type":"mention",
"mentioned":{
"id":"29:08q2j2o3jc09au90eucae",
"name":"Pranav Smith"
},
"text": "<at>@Pranav Smith</at>"
}
],
"replyToId": "3UP4UTkzUk1zzeyW"
}
You can also mention users by their Microsoft Entra Object ID or User Principal Name (UPN), and mention tags in channel messages.
Support for Microsoft Entra Object ID and UPN in user mention
Bots can mention users by Microsoft Entra Object ID or User Principal Name (UPN), in addition to user IDs. Incoming Webhooks also support user mentions in Adaptive Cards using these ID types.
The following code snippet shows an example of mentioning users with Entra Object ID and UPN using the Teams SDK:
app.OnMessage(async context =>
{
// Mention a user by their User Principal Name (UPN)
var user = new Account { Id = "Adele@microsoft.com", Name = "Adele" };
await context.Send(new MessageActivity("Hello!").AddMention(user));
});
app.on('message', async ({ send }) => {
// Mention a user by their User Principal Name (UPN)
const user = { id: 'Adele@microsoft.com', name: 'Adele' };
await send(new MessageActivity('Hello!').addMention(user));
});
from microsoft_teams.api import Account, MessageActivityInput
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
# Mention a user by their User Principal Name (UPN)
user = Account(id="Adele@microsoft.com", name="Adele")
await ctx.send(MessageActivityInput(text="Hello!").add_mention(account=user))
{
"type": "mention",
"text": "<at>Adele</at>",
"mentioned": {
"id": "Adele@microsoft.com",
"name": "Adele"
}
}
Tag mention
Your agent can mention tags in text messages and Adaptive Cards posted in channels. When the agent @mentions the tag in a channel, the tag is highlighted and the people associated with the tag get notified. When a user hovers over the tag, a pop-up appears with the tag details.
Note
Tag mentions aren't supported in Teams operated by 21Vianet.
Mention tags in a text message
To mention a tag, include a mention entity with "type": "tag" in your message. The id field must be the base64-encoded tag ID from the List teamworkTags API.
app.OnMessage(async context =>
{
// Mention a tag using the tag's Graph API ID
var tag = new Account { Id = "<base64-encoded-tag-id>", Name = "Test Tag" };
await context.Send(new MessageActivity("Hello!").AddMention(tag));
});
app.on('message', async ({ send }) => {
// Mention a tag using the tag's Graph API ID
const tag = { id: '<base64-encoded-tag-id>', name: 'Test Tag' };
await send(new MessageActivity('Hello!').addMention(tag));
});
@app.on_message
async def handle_message(ctx: ActivityContext[MessageActivity]):
# Mention a tag using the tag's Graph API ID
tag = Account(id="<base64-encoded-tag-id>", name="Test Tag")
await ctx.send(MessageActivityInput(text="Hello!").add_mention(account=tag))
Note
When mentioning tags, the underlying wire format requires the "type": "tag" property in the mentioned object of the entity. If the "type": "tag" property isn't included, the agent treats the mention as a user mention.
Mention tags in an Adaptive Card
In the Adaptive Card schema, under the mentioned object, add the "type": "tag" property. If the "type": "tag" property isn't added, the agent treats the mention as a user mention.
You can get the list of the tags available in the channel using the List teamworkTags API.
Example:
{
"type": "mention",
"text": "<at>Test Tag</at>",
"mentioned": {
"id": "base64 encoded id",
"name": "Test Tag",
"type": "tag"
}
}
Query Parameters
| Name | Description |
|---|---|
type |
The type of mention. The supported type is tag. |
id |
The unique identifier for the tag. For more information, see teamworkTag. |
Error code
| Status code | Error code | Message values | Retry request | Developer action |
|---|---|---|---|---|
| 400 | Code: Bad Request |
Mentioned tag with ID {id string} doesn't exist in current team Tag can only be mentioned in channel Invalid mentioned tag because no tag exists in the team |
No | Reevaluate request payload for errors. Check returned error message for details. |
| 502 | Code: Bad Gateway |
Invalid team group ID Malformed tenant ID for the tag Mention ID can't be resolved |
No | Retry manually. |
Throttling limits
Any request can be evaluated against multiple limits, depending on the scope, the window type (short and long), number of tags per message, and other factors. The first limit to be reached triggers throttling behavior.
Ensure that you don't exceed the throttling limits to avoid failed message delivery. For example, an agent can send only two messages with tag mention in a five-second window and each message can have only up to 10 tags.
The following table lists the throttling limits for tag mentions in an agent:
| Scope | Window Type | Number of tags per message | Time windows (sec) | Maximum number of messages per time window |
|---|---|---|---|---|
| Per agent per thread | Short | 10 | 5 | 2 |
| Long | 10 | 60 | 5 | |
| All agents per thread | Short | 10 | 5 | 4 |
| Long | 10 | 60 | 5 |
Limitations
- Tag mentions are supported only in agent to client message flow with text and Adaptive Card.
- Tag mentions aren't supported in shared and private channels.
- Tag mentions aren't supported in connectors.
- Tag mentions don't support the invoke flow in an agent.
Next step
See also
Platform Docs