Skip to content

Update quoted replies & new quotes features#389

Open
corinagum wants to merge 15 commits intomainfrom
cg/quoted-replies
Open

Update quoted replies & new quotes features#389
corinagum wants to merge 15 commits intomainfrom
cg/quoted-replies

Conversation

@corinagum
Copy link
Copy Markdown
Contributor

@corinagum corinagum commented Mar 23, 2026

image
  • Remove WithReplyToId(), update ToQuoteReply() and mark it [Obsolete]
  • Add QuotedReplyEntity with nested QuotedReplyData (MessageId required, SenderId/SenderName/Preview/Time/IsReplyDeleted/ValidatedMessageReference optional); register in Entity JSON converter
  • Add GetQuotedMessages() on MessageActivity to read inbound quoted reply entities
  • Add AddQuote(messageId, text?) builder on MessageActivity (appends quote placeholder + optional text)
  • Add PrependQuote(messageId) on MessageActivity (prepends quote placeholder before existing text, used internally by Reply()/Quote())
  • Update Reply() to delegate to Quote() when Activity.Id is set; remove conversation copy (redundant — AspNetCorePlugin.Send() handles it) and ;messageid= stripping (redundant — APX normalizes server-side)
  • Add Quote() on context — sends a message with a quoted message reference prepended to the text. Entity + placeholder only stamped for MessageActivity.
  • Mark all quoted reply types and methods as [Experimental("ExperimentalTeamsQuotedReplies")]
  • Add context-level unit tests for Reply() and Quote()
  • Add Samples.QuotedReplies sample exercising all APIs

@corinagum corinagum marked this pull request as ready for review March 24, 2026 18:19
Copilot AI review requested due to automatic review settings March 24, 2026 18:19
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 / QuotedReplyData and registers it in the entity JSON converter.
  • Adds GetQuotedMessages() and AddQuotedReply(...) on MessageActivity, and updates Context.Reply(...) plus new Context.QuoteReply(...) helpers to stamp quoted-reply metadata.
  • Adds unit tests and a new Samples.QuotedReplies project 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 from Activity. 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.

@corinagum corinagum changed the title Update quoted replies Update quoted replies & new quotes features Mar 25, 2026
Copilot AI review requested due to automatic review settings March 25, 2026 21:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

Libraries/Microsoft.Teams.Api/Activities/Activity.cs:203

  • WithReplyToId(string) was removed from the fluent Activity API. Since the rest of WithXyz(...) methods remain, removing this public method is a source/binary breaking change for consumers that used it to set ReplyToId. Consider keeping it (at least temporarily) as an [Obsolete] shim that assigns ReplyToId and returns this, or ensure the breaking change is intentional and called out in release notes/versioning.
    public virtual Activity WithId(string value)
    {
        Id = value;
        return this;
    }

    public virtual Activity WithChannelId(ChannelId value)
    {
        ChannelId = value;
        return this;
    }

    public virtual Activity WithFrom(Account value)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings March 26, 2026 00:25
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings March 26, 2026 23:09
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI review requested due to automatic review settings April 2, 2026 01:33
Corina Gum and others added 11 commits April 1, 2026 18:34
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Reply<T>() now delegates to QuoteReply<T>() when Activity.Id is set
- QuoteReply<T>() only stamps entity + placeholder for MessageActivity
- Remove redundant conversation copy (AspNetCorePlugin.Send overwrites it)
- Update test fixture time values to IC3 epoch format

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

Libraries/Microsoft.Teams.Api/Activities/Activity.cs:201

  • WithReplyToId(string value) was removed from Activity, which is a breaking change for consumers relying on the fluent builder API. If the goal is to deprecate this surface, consider keeping the method and marking it [Obsolete] (or providing an alternative builder) rather than removing it outright, and ensure the change is reflected in the public API/semver strategy.
    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.

Comment on lines 33 to 42
/// <summary>
/// send an activity to the conversation as a reply
/// send an activity to the conversation as a reply, automatically quoting the inbound message
/// </summary>
/// <param name="activity">activity activity to send</param>
/// <param name="activity">activity to send</param>
/// <param name="cancellationToken">optional cancellation token</param>
public Task<T> Reply<T>(T activity, CancellationToken cancellationToken = default) where T : IActivity;

/// <summary>
/// send a message activity to the conversation as a reply
/// send a message activity to the conversation as a reply, automatically quoting the inbound message
/// </summary>
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The XML docs for Reply(...) say it “automatically quotes the inbound message”, but the implementation only prepends a quote for MessageActivity (non-message activities pass through unchanged). Please clarify the docs (e.g., “for message activities”) to match the actual behavior and avoid misleading consumers.

Copilot uses AI. Check for mistakes.
Comment on lines +54 to +63
/// <summary>
/// Send a message to the conversation with a quoted message reference prepended to the text.
/// Teams renders the quoted message as a preview bubble above the response text.
/// </summary>
/// <param name="messageId">the ID of the message to quote</param>
/// <param name="activity">the activity to send — a quote placeholder for messageId will be prepended to its text</param>
/// <param name="cancellationToken">optional cancellation token</param>
[Experimental("ExperimentalTeamsQuotedReplies")]
public Task<T> Quote<T>(string messageId, T activity, CancellationToken cancellationToken = default) where T : IActivity;

Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quote<T>(string messageId, T activity, ...) is documented as “Send a message … with a quoted message reference prepended”, but the method accepts any IActivity and only mutates MessageActivity. Consider constraining this overload to MessageActivity (and/or adding a MessageActivity-specific overload) or updating the docs to state that quoting is applied only when activity is a MessageActivity.

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +8
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>$(NoWarn);ExperimentalTeamsQuotedReplies</NoWarn>
</PropertyGroup>
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description mentions adding a Samples.QuotedReplies sample, but the added sample project is Samples.Quoting. Please align the PR description (and any external docs) with the actual sample name/path to avoid confusion for readers.

Copilot uses AI. Check for mistakes.
@corinagum corinagum force-pushed the cg/quoted-replies branch from ed385fb to 90cbb31 Compare April 2, 2026 01:39
Copilot AI review requested due to automatic review settings April 2, 2026 01:40
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

Libraries/Microsoft.Teams.Api/Activities/Activity.cs:201

  • Removing the public fluent helper WithReplyToId(...) is a breaking change for consumers (especially those using the builder-style API), even if ReplyToId remains. Consider keeping the method as [Obsolete] (forwarding to ReplyToId) for at least one release, or ensure this ships with an appropriate major version bump/release note.
    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.

Comment on lines +1 to +3
# Example: Quoting

A bot that demonstrates various ways to quote previous messages in Microsoft Teams.
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR description mentions adding a Samples.QuotedReplies sample, but this PR adds Samples/Samples.Quoting. Either update the PR description to match the actual sample name/path or rename the sample folder/project to avoid confusion for readers.

Copilot uses AI. Check for mistakes.
@corinagum
Copy link
Copy Markdown
Contributor Author

Re: Copilot review comments

  • messageId validation: messageId is an APX-controlled IC3 ID, not user input. No escaping needed.
  • Non-message activity guard on Reply(): Handled in Quote() — non-message activities bypass entity stamping.
  • Quote() missing conversation reference: Handled at the Send() layer, same as all other SDKs.
  • Entity order in PrependQuote: Entity position in the list doesn't affect rendering; APX matches by type.
  • GetQuotedMessages() allocation: Acceptable for this usage pattern.
  • Stale naming (QuoteReply, ToQuote, etc.): Already renamed in latest commits.
  • Sample README formatting: Fixed as part of QuotedReplies → Quoting rename.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants