Conversation
c03ea73 to
fdbb1bd
Compare
There was a problem hiding this comment.
Pull request overview
This PR updates the SDK’s quoted-reply support to use Teams’ modern quotedReply entity + <quoted messageId="..."/> placeholder format, adds APIs for creating/reading quoted replies, and introduces tests + a sample app to exercise the new behavior.
Changes:
- Introduces
QuotedReplyEntity/QuotedReplyDataand registers it in the entity JSON converter. - Adds
GetQuotedMessages()andAddQuotedReply(...)onMessageActivity, and updatesContext.Reply(...)plus newContext.QuoteReply(...)helpers to stamp quoted-reply metadata. - Adds unit tests and a new
Samples.QuotedRepliesproject demonstrating end-to-end usage.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| Tests/Microsoft.Teams.Apps.Tests/Microsoft.Teams.Apps.Tests.csproj | Suppresses experimental diagnostic for quoted replies in Apps tests. |
| Tests/Microsoft.Teams.Apps.Tests/Contexts/ContextQuotedReplyTests.cs | Adds context-level tests validating Reply() / QuoteReply() stamping behavior. |
| Tests/Microsoft.Teams.Api.Tests/Microsoft.Teams.Api.Tests.csproj | Suppresses experimental diagnostic for quoted replies in Api tests. |
| Tests/Microsoft.Teams.Api.Tests/Json/Entities/QuotedReplyEntity.json | Adds golden JSON payload for quoted reply entity serialization tests. |
| Tests/Microsoft.Teams.Api.Tests/Entities/QuotedReplyEntityTests.cs | Adds serialization/deserialization and helper API tests for quoted replies. |
| Samples/Samples.QuotedReplies/appsettings.json | Adds sample configuration for the quoted replies demo app. |
| Samples/Samples.QuotedReplies/Samples.QuotedReplies.csproj | Adds new sample project wired to experimental quoted-reply APIs. |
| Samples/Samples.QuotedReplies/README.md | Documents sample commands and quoted-reply usage patterns. |
| Samples/Samples.QuotedReplies/Properties/launchSettings.TEMPLATE.json | Adds launch profile template for the new sample. |
| Samples/Samples.QuotedReplies/Program.cs | Implements demo bot behavior showing read/write quoted replies. |
| Libraries/Microsoft.Teams.Apps/Contexts/Context.Send.cs | Updates Reply() quoting behavior and adds QuoteReply() context APIs. |
| Libraries/Microsoft.Teams.Api/Entities/QuotedReplyEntity.cs | Adds the new quoted reply entity types. |
| Libraries/Microsoft.Teams.Api/Entities/Entity.cs | Registers quotedReply in entity JSON (de)serialization. |
| Libraries/Microsoft.Teams.Api/Activities/Message/MessageActivity.cs | Adds GetQuotedMessages() and AddQuotedReply(...) builder. |
| Libraries/Microsoft.Teams.Api/Activities/Activity.cs | Removes WithReplyToId(), updates ToQuoteReply() and marks it obsolete. |
Comments suppressed due to low confidence (1)
Libraries/Microsoft.Teams.Api/Activities/Activity.cs:201
WithReplyToId(string)was removed fromActivity. If this library has external consumers, removing a public fluent setter is a breaking change; it may be safer to keep the method and mark it[Obsolete](or provide a compatible alternative) to avoid forcing downstream recompiles/changes.
public virtual Activity WithId(string value)
{
Id = value;
return this;
}
public virtual Activity WithChannelId(ChannelId value)
{
ChannelId = value;
return this;
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace Microsoft.Teams.Api.Entities; | ||
|
|
||
| [Experimental("ExperimentalTeamsQuotedReplies")] | ||
| public class QuotedReplyEntity : Entity | ||
| { | ||
| [JsonPropertyName("quotedReply")] | ||
| [JsonPropertyOrder(3)] | ||
| public QuotedReplyData QuotedReply { get; set; } | ||
|
|
||
| public QuotedReplyEntity() : base("quotedReply") { } | ||
| } | ||
|
|
||
| [Experimental("ExperimentalTeamsQuotedReplies")] | ||
| public class QuotedReplyData | ||
| { | ||
| [JsonPropertyName("messageId")] | ||
| public string MessageId { get; set; } | ||
|
|
There was a problem hiding this comment.
QuotedReplyEntity.QuotedReply and QuotedReplyData.MessageId are non-nullable but never initialized (no required, ctor assignment, or nullability). With TreatWarningsAsErrors=True in Libraries/Directory.Build.props, this will fail the build (CS8618). Consider making these required (matching other entities like MentionEntity.Mentioned) or adding constructors that set them, and/or marking them nullable if they’re legitimately optional. Also using System.Diagnostics.CodeAnalysis; is currently unused and will trigger CS8019 under warnings-as-errors.
| /// <summary> | ||
| /// send an activity to the conversation as a reply quoting a specific message by ID | ||
| /// </summary> | ||
| /// <param name="messageId">the id of the message to quote</param> | ||
| /// <param name="activity">activity to send</param> | ||
| /// <param name="cancellationToken">optional cancellation token</param> | ||
| public Task<T> QuoteReply<T>(string messageId, T activity, CancellationToken cancellationToken = default) where T : IActivity; | ||
|
|
||
| /// <summary> | ||
| /// send a message activity as a reply quoting a specific message by ID | ||
| /// </summary> | ||
| /// <param name="messageId">the id of the message to quote</param> | ||
| /// <param name="text">the text to send</param> | ||
| /// <param name="cancellationToken">optional cancellation token</param> | ||
| public Task<MessageActivity> QuoteReply(string messageId, string text, CancellationToken cancellationToken = default); |
There was a problem hiding this comment.
The new QuoteReply(...) APIs call into experimental quoted-replies types internally (suppressed via #pragma), but the methods themselves aren’t marked [Experimental("ExperimentalTeamsQuotedReplies")]. As a result, consumers won’t see the intended experimental/preview warning when using these APIs. Consider annotating the QuoteReply overloads (and any other new public quoted-reply entrypoints) with the Experimental attribute so the preview surface is clearly communicated.
WithReplyToId(), updateToQuoteReply()and mark it[Obsolete]QuotedReplyEntitywith nestedQuotedReplyData(MessageIdrequired,SenderId/SenderName/Preview/Time/IsReplyDeleted/ValidatedMessageReferenceoptional); register in Entity JSON converterGetQuotedMessages()onMessageActivityto read inbound quoted reply entitiesAddQuotedReply(messageId, response?)builder onMessageActivityReply()to stampQuotedReplyEntity + <quoted messageId="..."/>placeholder instead of blockquote HTML; remove;messageid=stripping fromConversation.Id(redundant - APX normalizes server-side)QuoteReply()on context[Experimental("ExperimentalTeamsQuotedReplies")]Reply()andQuoteReply()