diff --git a/msteams-platform/agents-in-teams/agent-slash-commands.md b/msteams-platform/agents-in-teams/agent-slash-commands.md index d7150c02b44..67d5c59d353 100644 --- a/msteams-platform/agents-in-teams/agent-slash-commands.md +++ b/msteams-platform/agents-in-teams/agent-slash-commands.md @@ -27,7 +27,13 @@ Slash commands in Teams are text-based shortcuts that let users perform actions The slash commands feature enables apps and agents to add their own commands to this list to help users discover and use them. +[WIP: Gif file to be updated with Contoso instead of Copilot. ] + +:::image type="content" source="../assets/videos/slash-commands.gif" alt-text="This video shows how a slash command works within a Teams agent or app."::: + + ## Types of slash commands @@ -60,6 +66,27 @@ In channels, group chats, and meeting chats, the slash command autocomplete menu Invoking a command from the menu switches the compose box to targeted messaging mode for the agent and inserts the name of the command as the message text. Selecting **Send** sends the targeted message to the agent. +- **App-defined slash commands**: + + Agents or apps can explicitly declare the commands your agent supports, and Teams shows them in the slash command picker when a user types `/`. For example, a project management agent or bot app might expose commands such as: + + - `/create-task` to turn the current conversation into a tracked task, prefilled with the channel, requester, and due-date details based on context. + - `/list-tasks` to list open tasks or action items in the conversation with task details and its owner name. + - `/status-check` to retrieve the latest status for a work item, incident, or customer request without leaving the compose box. + +- **Natural-language support for slash commands**: + + In this model, the user enters the slash command and, optionally, a natural-language request. The agent response is delivered privately to the user, which makes the pattern well suited for drafting, lookup, summarization, lightweight workflow initiation, and other personal productivity tasks that benefit from staying in the context of the current conversation. For example: + + - `/contoso incident summarize the last 24 hours and suggest next steps` + - `/contoso create-task fix login issue for mobile users` + - `/contoso draft a customer update from this thread` + - `/contoso find the latest rollout plan and highlight open risks` + + Natural-language support is often preferable to relying only on explicit commands for high-confidence, repeatable actions: agents are most valuable when they can understand intent, parameters, and context expressed in natural language, so slash-command design should combine discoverable commands with flexible phrasing that lets users say what they need instead of learning a long command catalog. From a platform perspective, slash commands should support the experience, not define it end to end; use them to surface common actions in a way that’s easy to find and invoke, then let the agent handle natural-language requests, infer missing details when appropriate, and ask brief follow-up questions when something is unclear. Keep the command set small so users don’t need to memorize syntax or choose between nearly identical options. + + To support natural-language prompts, an agent must explicitly opt in. This keeps the behavior intentional. Agents that are designed to interpret free-form requests can enable natural-language prompting and provide a more conversational experience. + ### Message extension slash commands Apps that implement action-type [message extensions](../messaging-extensions/what-are-messaging-extensions.md) can surface them as slash commands. When a user activates one from the autocomplete menu, Teams immediately opens the associated task module or dialog. Activating a message extension slash command only opens the task module or dialog, and doesn't send a message. Search-type message extensions can't be exposed as commands. @@ -78,7 +105,19 @@ See [Receive targeted messages](targeted-messages.md#receive-targeted-messages) Agent slash commands require an agent to opt in to receive targeted messages; see [Receive targeted messages](targeted-messages.md#receive-targeted-messages). -Declare commands by configuring the `bots[].commandLists[]` section of the manifest as shown in the following example. +#### Triggers: slash and @mention + +The `triggers` property defines where a command appears and how users can invoke it from the Teams compose experience. For agent command lists, use `@mention` when the command should appear in the traditional @mention command menu, use `slash` when the command should appear in the slash command picker, or include both values when the same command should be available from both entry points. + +Use `slash` triggers for commands that users should be able to discover and invoke quickly from an empty compose box. Slash commands are well suited for frequent actions, private lookups, lightweight workflow starts, and commands that should be easy to find without first mentioning the agent.Use `@mention` triggers for commands that are closely tied to an explicit interaction with the agent. This pattern is useful when users are already addressing the agent directly, especially in personal scope or in conversations where the user expects the command to be part of a visible agent exchange. + +- Use `@mention` when users are intentionally addressing the agent and may expect an agent-visible conversation flow. +- Use `slash` when users need fast discovery, private command invocation, or a shortcut from the compose box. +- Use both when the same command should be available through both discovery surfaces without changing the command behavior. + + When a command supports both invocation patterns, declare both trigger values in the same command list. This keeps the command catalog consistent while giving users flexibility to start from either @mention or slash. You can choose to define separate command lists so that each trigger can have its own scope, command set, and user guidance. + +Declare commands and their triggers by configuring the `bots[].commandLists[]` section of the manifest as shown in the following example. ```json { diff --git a/msteams-platform/agents-in-teams/targeted-messages.md b/msteams-platform/agents-in-teams/targeted-messages.md index 418cdf797a0..4fd10aacace 100644 --- a/msteams-platform/agents-in-teams/targeted-messages.md +++ b/msteams-platform/agents-in-teams/targeted-messages.md @@ -2,8 +2,9 @@ title: Send and Receive Targeted Messages description: Use targeted messages to enable agents to privately interact with users in group conversations without distracting other users or revealing private information. ms.localizationpriority: high -ms.date: 05/27/2026 +ms.date: 06/16/2026 ms.topic: article +zone_pivot_groups: select-language --- @@ -46,6 +47,9 @@ Targeted messages: - Can be used only for one-to-one interactions between an agent and a user in channels, group chats, and meeting chats. - Support all the [capabilities of standard messages](../bots/build-conversational-capability.md#message-content) like buttons, images, Adaptive Cards, and files, but don't support reactions, replies, or forwarding. + + A targeted message can contain normal message content, but Teams doesn't let that targeted message participate in the usual social or threading actions that might expose it more broadly. Targeted messages are private, temporary, and visible to a single-user only in a shared conversation, so features that create secondary visible artifacts, shared thread context, or message redistribution are intentionally disabled. The default agent response to a slash command is targeted message, and then on approval to resend it as a public message rather than trying to reply to, react to, or forward the targeted one. + - Generally operate the same way as standard messages, with the same API operations. Users and agents can modify or delete targeted messages after sending them, but can't change their visibility. If a scenario calls for a private message to be made public, the sender should delete it and resend it as a standard message; see [Best practices and design guidance](#best-practices-and-design-guidance). - Expire 24 hours after being sent. When a targeted message expires, Teams deletes it from all clients, although it might be retained in secure storage based on organizational policy. - Aren't visible to untargeted users, even if they're using an older version of the Teams client that doesn't support targeted messages. @@ -64,6 +68,54 @@ Activating an agent's targeted message command switches the compose box to targe For more about slash commands, including how to register extra named slash commands that can be dispatched to your agent, see [Expose slash commands from agents and apps](agent-slash-commands.md). +### Integrate prompt preview in targeted messages + +Prompt Preview helps preserve conversational context for targeted messages by showing a compact preview of the user’s original request at the top of the agent’s response, especially when the response is targeted to a specific user. Targeted messages appear inline in a shared conversation but are visible only to the targeted recipient. It keeps targeted agent responses grounded in the user’s original request helping the user understand context without exposing the prompt to everyone else. A single agent response can include multiple prompt previews. However, it doesn't appear for normal messages. + +Prompt preview can appear in both private and public agent responses, but the implementation mechanism is the same in both cases: the agent includes `targetedMessageInfo` that references the original targeted message. The difference is only who can see the reply after it is sent: + +- **Private agent-to-user response**: The agent replies privately to the user's targeted message, so only the intended user can see the reply and the prompt preview. + + :::image type="content" source="../assets/images/agents-in-teams/agent-slash-commands/private-prompt-preview.png" alt-text="Image shows the prompt preview for private agent-to-user response." lightbox="../assets/images/agents-in-teams/agent-slash-commands/private-prompt-preview.png"::: + +- **Public agent-to-user response**: The agent sends a public resply to the user's request that includes the prompt preview. It's visible to everyone in the chat. + + :::image type="content" source="../assets/images/agents-in-teams/agent-slash-commands/public-prompt-preview.png" alt-text="Image shows the prompt preview for public agent-to-user response." lightbox="../assets/images/agents-in-teams/agent-slash-commands/public-prompt-preview.png"::: + +The implementation mechanism is the same in both cases. The agent includes `targetedMessageInfo` that references the original targeted message. The difference is only who can see the reply after it is sent. + +Prompt Preview can be added automatically in _reactive_ scenarios such as when replying with `send()` or `reply()` to a user’s targeted message or slash-command request through the Teams SDK or REST API. These SDK methods typically attach the `targetedMessageInfo` entity automatically, keeping the response associated with the incoming user interaction and tied to the original prompt. In _proactive_ flows, however, the agent sends the response outside the original turn, so it must explicitly add the `targetedMessageInfo` entity and reference the targeted message ID before sending the private or public message, ensuring the preview points to the correct original request. + +To render prompt preview, include a `targetedMessageInfo` entity in the reply activity and set its `messageId` value to the message ID of original targeted message. Teams uses that `messageId` to show the user's original request above the agent response. This example demonstrates the `entities` array needed to add prompt preview with `messageId` on a reply activity, so the original message appears in the prompt preview. + +```json + +"entities": [{ + "type": "targetedMessageInfo", + "messageId": "xxxxxxxxxxxxx" +}] +``` + +Suggested actions, such as Approve or Reject, can then provide a lightweight way to confirm sharing decisions while preserving the prompt context. + +Compared with [quoted replies](/microsoftteams/platform/teams-sdk/essentials/sending-messages/overview?pivots=csharp), Prompt Preview is purpose-built for targeted response workflows. Quoted replies point readers back to an earlier message in a thread, while Prompt Preview preserves the private prompt-response context and supports approval-based sharing from private to public. + +### Response visibility modes + +Response visibility is controlled by how the message is addressed and whether it is targeted. Use a targeted private response when the content is user-specific, sensitive, or needs review first; use a normal public response when the message is meant for the whole conversation. A common workflow is private-to-public: the agent sends a private response with Prompt Preview and options to share it with the rest of the conversation, and then explicitly approves whether it should be shared publicly. + +Setting `isTargeted: true` with `WithRecipient` delivers this message as a private, user-specific message inside a shared conversation. Setting `isTargeted: false` with `WithRecipient` sets the recipient metadata, but doesn't mark the message as privately targeted. In other words, Teams SDK lets you identify who the logical recipient is without necessarily turning the message into a targeted or ephemeral message. This distinction supports both addressed replies and normal visibility: Use `isTargeted: true` when privacy is part of the agent or app behavior and the message must be visible only to one user in a shared chat. Use `isTargeted: false` when you are building a normal message flow and don't want private visibility for messages. This boolean value avoids having separate APIs for setting a recipient and making a message private in a group context. You can implement the following agent-to-user response flows: + +- Private response mode (default) keeps slash command response focused between the user and the agent. Use private response flow for drafts, summaries, personal tasks. +- Public response mode lets the user share the response to the wider audience. +- Private-to-public response flow lets the user approve a private response to be shared publicly. + +For targeted messaging, the user approval matters because the agent’s first response is intentionally private. It is an important targeted-messaging safeguard. The private response can be reviewed in context with prompt preview. As the agent’s first response is private, the user should explicitly confirm before the agent or app publishes that response into the shared conversation. You can buuld this experience using Adaptive Cards, or suggested actions for offering options to the user such as approving, sharing, or updating the message. + +For more information on implementing prompt preview, see [Teams SDK](/microsoftteams/platform/teams-sdk/essentials/sending-messages/overview?pivots=csharp). + +::: zone pivot="typescript" + ## Implement targeted messages Targeted messages are sent and received using the same operations as [standard single-recipient messages](/microsoftteams/platform/teams-sdk/essentials/sending-messages/overview?pivots=typescript) in the Teams SDK, but have a boolean property indicating whether they're targeted. @@ -88,20 +140,7 @@ To opt in to receive targeted messages, an agent's `bots` entry in its app manif } ``` -Agents receive messages via standard message events. Targeted messages can be distinguished from public messages as shown in the following snippets. - -# [C#](#tab/dotnet1) - -```csharp - - teams.OnMessage(async (context, cancellationToken) => { - if (context.Activity.Recipient?.IsTargeted == true){ - // Handle message event - } - }); -``` - -# [TypeScript](#tab/ts1) +Agents receive messages via standard message events. Targeted messages can be distinguished from public messages as shown in the following snippet: ```typescript @@ -112,40 +151,9 @@ Agents receive messages via standard message events. Targeted messages can be di }); ``` -# [Python](#tab/Py1) - -```python - - @app.on_message - async def handle_message(ctx): - if getattr(ctx.activity.recipient, "is_targeted", False): - # Handle message event -``` - ---- - ### Send a targeted message -All agents in Teams are automatically eligible to send targeted messages. - -# [C#](#tab/dotnet1) - -To send a targeted message, use `WithRecipient` to specify a single recipient by their ID, and provide a value of `true` for the `isTargeted` argument. The recipient must be a member of the chat or channel. - -```csharp -app.OnMessage(async context => -{ -// Using WithRecipient with isTargeted=true explicitly targets the specified recipient -await context.Send( - new MessageActivity("This message is only visible to you!") - .WithRecipient(context.Activity.From, isTargeted: true) - ); -}); -``` - -# [TypeScript](#tab/ts1) - -To send a targeted message, use `withRecipient` to specify a single recipient by their ID, and provide a value of `true` for the `isTargeted` argument. The recipient must be a member of the chat or channel. +All agents in Teams are automatically eligible to send targeted messages. To send a targeted message, use `withRecipient` to specify a single recipient by their ID, and provide a value of `true` for the `isTargeted` argument. The recipient must be a member of the chat or channel. ```typescript import { MessageActivity } from '@microsoft/teams.api'; @@ -159,132 +167,117 @@ app.on('message', async ({ send, activity }) => { }); ``` -# [Python](#tab/Py1) +If attempting to send a targeted message results in an error, consider sending a 1:1 chat message as a fallback. -To send a targeted message, use `with_recipient` to specify a single recipient by their ID, and provide a value of `True` for the `is_targeted` argument. The recipient must be a member of the chat or channel. +::: zone-end -```python -from microsoft_teams.api import MessageActivity, MessageActivityInput -from microsoft_teams.apps import ActivityContext +::: zone pivot="csharp" -@app.on_message -async def handle_message(ctx: ActivityContext[MessageActivity]): - # Using with_recipient with is_targeted=True explicitly targets the specified recipient - await ctx.send( - MessageActivityInput(text="This message is only visible to you!") - .with_recipient(ctx.activity.from_, is_targeted=True) - ) -``` +## Implement targeted messages ---- +Targeted messages are sent and received using the same operations as [standard single-recipient messages](/microsoftteams/platform/teams-sdk/essentials/sending-messages/overview?pivots=typescript) in the Teams SDK, but have a boolean property indicating whether they're targeted. -If attempting to send a targeted message results in an error, consider sending a 1:1 chat message as a fallback. +### Receive targeted messages -### Update or delete a targeted message +An agent must opt in via its manifest to be able to receive targeted messages. If not opted in, Teams won't give users the option to send a targeted message to the agent. -Targeted messages can be updated and deleted in the same way as standard messages, with the following limitations: +Agents that opt in to receive targeted messages should always check the visibility of messages they receive and take it into consideration when generating responses and tracking the context of a conversation. For more information, see [Best practices and design guidance](#best-practices-and-design-guidance). -- The visibility of a targeted message can't be changed -- Targeted messages expire after 24 hours and are automatically deleted from clients. Attempting to modify or delete an expired message results in an error. +To opt in to receive targeted messages, an agent's `bots` entry in its app manifest must include a `true` value for the `supportsTargetedMessages` property. -To update a targeted message, use one of the following code snippets: +```json +{ + "bots": [ + { + "botId": "{{BOT_ID}}", + "scopes": ["personal", "team", "groupChat"], + "supportsTargetedMessages": true + } + ] +} +``` -# [C#](#tab/dotnet2) +Agents receive messages via standard message events. Targeted messages can be distinguished from public messages as shown in the following snippet: ```csharp -// Update -var response = await context.Send( - new MessageActivity("Original targeted message") - .WithRecipient(context.Activity.From, true), cancellationToken); -var conversationId = context.Activity.Conversation.Id; -var messageId = response.Id; - -var updatedMessage = new MessageActivity("This message has been updated!"); -await context.Api.Conversations.Activities.UpdateTargetedAsync(conversationId, messageId, updatedMessage); + + teams.OnMessage(async (context, cancellationToken) => { + if (context.Activity.Recipient?.IsTargeted == true){ + // Handle message event + } + }); ``` -# [TypeScript](#tab/ts2) +### Send a targeted message -```typescript -// Update -const response = await context.send( - new MessageActivity('Original targeted message') - .withRecipient(context.activity.from, true), cancellationToken); -const conversationId = context.activity.conversation.id; -const messageId = response.id; - -const updatedMessage = new MessageActivity('This message has been updated!'); -await api.conversations.activities.updateTargeted(conversationId, messageId, updatedMessage); -``` +All agents in Teams are automatically eligible to send targeted messages. -# [Python](#tab/Py2) +To send a targeted message, use `WithRecipient` to specify a single recipient by their ID, and provide a value of `true` for the `isTargeted` argument. The recipient must be a member of the chat or channel. -```python -# Update -response = await ctx.send( - MessageActivityInput(text="Original targeted message") - .with_recipient(ctx.activity.from_property, True), cancellation_token) -conversation_id = ctx.activity.conversation.id -message_id = response.id - -updated_message = MessageActivityInput(text="This message has been updated!") -await ctx.api.conversations.activities.update_targeted(conversation_id, message_id, updated_message) +```csharp +app.OnMessage(async context => +{ +// Using WithRecipient with isTargeted=true explicitly targets the specified recipient +await context.Send( + new MessageActivity("This message is only visible to you!") + .WithRecipient(context.Activity.From, isTargeted: true) + ); +}); ``` -# [HTTP](#tab/api2) +::: zone-end -The agent calls the `Edit TM` API using the message’s `activityId`. +::: zone pivot="python" -```REST -PUT {cloud}/v3/conversations/{conversationId}/activities?isTargetedActivity=true -PUT {cloud}/v3/conversations/{conversationId}/activities/{activityId}?isTargetedActivity=true -Authorization: Bearer eyJh... -Content-Type: application/json -{ - "type": "message", - "text": "This message has been updated" -} -``` +## Implement targeted messages ---- +Targeted messages are sent and received using the same operations as [standard single-recipient messages](/microsoftteams/platform/teams-sdk/essentials/sending-messages/overview?pivots=typescript) in the Teams SDK, but have a boolean property indicating whether they're targeted. -Delete a targeted message using one of the following code snippets: +### Receive targeted messages -# [C#](#tab/dotnet2) +An agent must opt in via its manifest to be able to receive targeted messages. If not opted in, Teams won't give users the option to send a targeted message to the agent. -```csharp -// Delete -await context.Api.Conversations.Activities.DeleteTargetedAsync(conversationId, messageId); +Agents that opt in to receive targeted messages should always check the visibility of messages they receive and take it into consideration when generating responses and tracking the context of a conversation. For more information, see [Best practices and design guidance](#best-practices-and-design-guidance). + +```python + + @app.on_message + async def handle_message(ctx): + if getattr(ctx.activity.recipient, "is_targeted", False): + # Handle message event ``` -# [TypeScript](#tab/ts2) +### Send a targeted message -```typescript -// Delete -await api.conversations.activities.deleteTargeted(conversationId, messageId); -``` +All agents in Teams are automatically eligible to send targeted messages. -# [Python](#tab/Py2) +To send a targeted message, use `with_recipient` to specify a single recipient by their ID, and provide a value of `True` for the `is_targeted` argument. The recipient must be a member of the chat or channel. ```python -#Delete -await ctx.api.conversations.activities.delete_targeted(conversation_id, message_id) +from microsoft_teams.api import MessageActivity, MessageActivityInput +from microsoft_teams.apps import ActivityContext + +@app.on_message +async def handle_message(ctx: ActivityContext[MessageActivity]): + # Using with_recipient with is_targeted=True explicitly targets the specified recipient + await ctx.send( + MessageActivityInput(text="This message is only visible to you!") + .with_recipient(ctx.activity.from_, is_targeted=True) + ) ``` -# [HTTP](#tab/api2) +If attempting to send a targeted message results in an error, consider sending a 1:1 chat message as a fallback. -Use the delete message API for enabling the agent to remove targeted messages. It avoids leaving stale content. +::: zone-end -```REST -DELETE {cloud}/v3/conversations/{conversationId}/activities?isTargetedActivity=true -DELETE {cloud}/v3/conversations/{conversationId}/activities/{activityId}?isTargetedActivity=true -Authorization: Bearer eyJh... -Content-Type: application/json +### Update or delete a targeted message -No body required. -``` +Targeted messages can be updated and deleted in the same way as standard messages, with the following limitations: ---- +- The visibility of a targeted message can't be changed +- Targeted messages expire after 24 hours and are automatically deleted from clients. Attempting to modify or delete an expired message results in an error. + +For more information on updating or deleting a targeted message, see [Teams SDK](/microsoftteams/platform/teams-sdk/essentials/sending-messages/overview?pivots=csharp). ## Best practices and design guidance diff --git a/msteams-platform/assets/images/agents-in-teams/agent-slash-commands/private-prompt-preview.png b/msteams-platform/assets/images/agents-in-teams/agent-slash-commands/private-prompt-preview.png index db2f5ad8628..bbb76b6bbea 100644 Binary files a/msteams-platform/assets/images/agents-in-teams/agent-slash-commands/private-prompt-preview.png and b/msteams-platform/assets/images/agents-in-teams/agent-slash-commands/private-prompt-preview.png differ diff --git a/msteams-platform/assets/images/agents-in-teams/agent-slash-commands/public-prompt-preview.png b/msteams-platform/assets/images/agents-in-teams/agent-slash-commands/public-prompt-preview.png index c5e8c72999c..311356fb213 100644 Binary files a/msteams-platform/assets/images/agents-in-teams/agent-slash-commands/public-prompt-preview.png and b/msteams-platform/assets/images/agents-in-teams/agent-slash-commands/public-prompt-preview.png differ diff --git a/msteams-platform/assets/videos/slash-commands.gif b/msteams-platform/assets/videos/slash-commands.gif new file mode 100644 index 00000000000..a51303ddb3b Binary files /dev/null and b/msteams-platform/assets/videos/slash-commands.gif differ diff --git a/msteams-platform/zone-pivot-groups.yml b/msteams-platform/zone-pivot-groups.yml index 44d96b6148b..fed7d41a26c 100644 --- a/msteams-platform/zone-pivot-groups.yml +++ b/msteams-platform/zone-pivot-groups.yml @@ -95,14 +95,14 @@ groups: - id: qs-csharp title: C# - id: qs-python - title: Python -- id: teams-sdk-languages - title: Teams SDK language - prompt: Select your Teams SDK language. + title: Python +- id: select-language + title: Select language + prompt: Before you begin, select the language in which you want to build. pivots: - - id: teams-sdk-csharp + - id: csharp title: C# - - id: teams-sdk-typescript - title: TypeScript - - id: teams-sdk-python - title: Python + - id: typescript + title: TypeScript + - id: python + title: Python