Skip to content

Fix async anti-patterns across all library projects#402

Merged
rido-min merged 11 commits into
mainfrom
fix/async-issues-396-401
May 27, 2026
Merged

Fix async anti-patterns across all library projects#402
rido-min merged 11 commits into
mainfrom
fix/async-issues-396-401

Conversation

@rido-min
Copy link
Copy Markdown
Member

@rido-min rido-min commented Mar 26, 2026

Summary

Fixes #396, #397, #398, #399, #400, #401

Test plan

  • Solution builds with 0 errors
  • All existing tests pass (122 Apps tests, 15 AspNetCore tests, 9 McpClient tests, 3 Graph tests)
  • Verify streaming behavior works correctly with the new EmitAsync method on IStream
  • Verify cancellation propagation works for OpenAI API calls
  • Verify OAuth sign-in flow logs errors appropriately instead of silently swallowing

🤖 Generated with Claude Code

…, fire-and-forget, ConfigureAwait(false)

Comprehensive fix for async anti-patterns across all library projects:

- #396: Replace sync-over-async GetAwaiter().GetResult() with proper await
  in ApplicationBuilder.Functions, Stream, ChatPrompt.Errors, ServiceCollection
- #397: Propagate CancellationToken correctly in OpenAIChatModel.Send,
  Context.Send, HttpClient; add CancellationToken to OnBuildInstructions
- #398: Replace empty catch blocks with exception logging in App.cs,
  Context.SignIn, McpClientPlugin
- #399: Add error handling to fire-and-forget Flush() in AspNetCorePlugin.Stream,
  replace Task.Run(() => {}) with Task.CompletedTask, use _ = discard with
  ConfigureAwait in debounce extensions
- #400: Add ConfigureAwait(false) to ~380 await calls across all library projects
- #401: Replace Task.Run wrapping sync code with direct execution in LocalStorage,
  fix unsafe reflection-based Task.Result access in MethodInfoExtensions

Fixes #396, #397, #398, #399, #400, #401

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 26, 2026 16:11
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 addresses widespread async/await correctness and reliability issues across the Teams SDK libraries by removing sync-over-async patterns, improving cancellation propagation, reducing unobserved task exceptions, and standardizing ConfigureAwait(false) usage in library code.

Changes:

  • Propagates CancellationToken through multiple call chains and updates the IChatPlugin hook signature accordingly.
  • Replaces several fire-and-forget / sync-blocking async patterns with awaited flows and safer wrappers.
  • Adds ConfigureAwait(false) broadly across library awaits to reduce context capture and deadlock risk.

Reviewed changes

Copilot reviewed 114 out of 114 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
Tests/Microsoft.Teams.AI.Tests/Utils/TestChatPlugin.cs Update test plugin hook signature
Tests/Microsoft.Teams.AI.Tests/ChatPluginTests.cs Update hook verification for token
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.External/Microsoft.Teams.Plugins.External.McpClient/McpClientPlugin.cs ConfigureAwait + exception logging
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.External/Microsoft.Teams.Plugins.External.Mcp/Extensions/McpServerBuilder.cs ConfigureAwait in prompt send
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore/Extensions/ApplicationBuilder.cs ConfigureAwait in endpoint handler
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore/Extensions/ApplicationBuilder.Tabs.cs ConfigureAwait on Results execution
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore/Extensions/ApplicationBuilder.Functions.cs Remove unobserved handler tasks
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore/AspNetCorePlugin.cs ConfigureAwait in send/parse/do
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore/AspNetCorePlugin.Stream.cs Add FlushSafe + ConfigureAwait
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/WebSocketCollection.cs ConfigureAwait for websocket send
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/DevToolsPlugin.cs ConfigureAwait in middleware/events
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/Controllers/DevToolsController.cs ConfigureAwait in websocket loop
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.DevTools/Controllers/ActivityController.cs ConfigureAwait in activity creation
Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore.BotBuilder/Controllers/MessageController.cs ConfigureAwait + plugin fallback await
Libraries/Microsoft.Teams.Extensions/Microsoft.Teams.Extensions.Hosting/Microsoft.Teams.Apps.Extensions/TeamsService.cs ConfigureAwait on startup
Libraries/Microsoft.Teams.Extensions/Microsoft.Teams.Extensions.Hosting/Microsoft.Teams.Apps.Extensions/ServiceCollection.cs ConfigureAwait in sync DI factory
Libraries/Microsoft.Teams.Common/Storage/LocalStorage.cs Remove Task.Run for sync ops
Libraries/Microsoft.Teams.Common/Http/HttpClient.cs Propagate cancellation + ConfigureAwait
Libraries/Microsoft.Teams.Common/Extensions/TaskExtensions.cs ConfigureAwait in retry delays
Libraries/Microsoft.Teams.Common/Extensions/MethodInfoExtensions.cs Safer Task result extraction
Libraries/Microsoft.Teams.Common/Extensions/ActionExtensions.cs Debounce: discard + ConfigureAwait
Libraries/Microsoft.Teams.Apps/Routing/Route.cs ConfigureAwait on route invoke
Libraries/Microsoft.Teams.Apps/Events/Topic.cs ConfigureAwait in topic emit
Libraries/Microsoft.Teams.Apps/Events/EventEmitter.cs ConfigureAwait in emitter handlers
Libraries/Microsoft.Teams.Apps/Contexts/Context.cs Replace no-op Task.Run default
Libraries/Microsoft.Teams.Apps/Contexts/Context.SignIn.cs Log instead of empty catch; ConfigureAwait
Libraries/Microsoft.Teams.Apps/Contexts/Context.Send.cs Fix cancellation token propagation
Libraries/Microsoft.Teams.Apps/Contexts/Client/FunctionContext.cs ConfigureAwait in conversation bootstrap
Libraries/Microsoft.Teams.Apps/AppRouting.cs ConfigureAwait across invoke flows
Libraries/Microsoft.Teams.Apps/AppPlugins.cs ConfigureAwait in plugin event broadcast
Libraries/Microsoft.Teams.Apps/AppEvents.cs ConfigureAwait + propagate to plugins
Libraries/Microsoft.Teams.Apps/App.cs ConfigureAwait + log suppressed errors
Libraries/Microsoft.Teams.Apps/Activities/TypingActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Messages/MessageUpdateActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Messages/MessageReactionActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Messages/MessageDeleteActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Messages/MessageActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Tasks/SubmitActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Tasks/FetchActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Tabs/SubmitActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Tabs/FetchActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/SignIn/VerifyStateAcitivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/SignIn/TokenExchangeActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/SignIn/FailureActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Search/TypeaheadSearchActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Search/SearchActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Search/AnswerSearchActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Messages/SubmitActionActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Messages/FeedbackActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/MessageExtensions/SubmitActionActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/MessageExtensions/SettingsActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/MessageExtensions/SelectItemActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/MessageExtensions/QuerySettingsUrlActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/MessageExtensions/QueryLinkActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/MessageExtensions/QueryActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/MessageExtensions/FetchTaskActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/MessageExtensions/CardButtonClickedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/MessageExtensions/AnonQueryLinkActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/InvokeActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/HandoffActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/FileConsentActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/ExecuteActionActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Configs/SubmitActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/Configs/FetchActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Invokes/AdaptiveCards/ActionActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Installs/UnInstallActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Installs/InstallUpdateActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Installs/InstallActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Events/ReadReceiptActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Events/MeetingStartActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Events/MeetingLeaveActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Events/MeetingJoinActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Events/MeetingEndActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Events/EventActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/TeamUnArchivedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/TeamRestoredActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/TeamRenamedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/TeamDeletedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/TeamArchivedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/MembersRemovedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/MembersAddedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ConversationUpdateActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ConversationEndActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ChannelUnsharedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ChannelSharedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ChannelRestoredActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ChannelRenamedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ChannelMemberRemovedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ChannelMemberAddedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ChannelDeletedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Conversations/ChannelCreatedActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/CommandResultActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/CommandActivity.cs ConfigureAwait in handler wrappers
Libraries/Microsoft.Teams.Apps/Activities/Activity.cs ConfigureAwait in activity handlers
Libraries/Microsoft.Teams.Apps.Testing/Plugins/TestPlugin.cs ConfigureAwait in test plugin
Libraries/Microsoft.Teams.Api/Clients/UserTokenClient.cs ConfigureAwait in token calls
Libraries/Microsoft.Teams.Api/Clients/TeamClient.cs ConfigureAwait in team calls
Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs ConfigureAwait in reaction calls
Libraries/Microsoft.Teams.Api/Clients/MemberClient.cs ConfigureAwait in member calls
Libraries/Microsoft.Teams.Api/Clients/MeetingClient.cs ConfigureAwait in meeting calls
Libraries/Microsoft.Teams.Api/Clients/ConversationClient.cs ConfigureAwait in conversation create
Libraries/Microsoft.Teams.Api/Clients/BotTokenClient.cs ConfigureAwait in token resolve
Libraries/Microsoft.Teams.Api/Clients/BotSignInClient.cs ConfigureAwait in sign-in calls
Libraries/Microsoft.Teams.Api/Clients/ActivityClient.cs ConfigureAwait in activity calls
Libraries/Microsoft.Teams.Api/Auth/TokenCredentials.cs ConfigureAwait in token factory
Libraries/Microsoft.Teams.Api/Auth/ClientCredentials.cs ConfigureAwait + cancellation in auth
Libraries/Microsoft.Teams.AI/Stream.cs Add async emission API
Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Send.cs ConfigureAwait + token propagation
Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Functions.cs ConfigureAwait in function invoke
Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Errors.cs Async error handler registration
Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Chain.cs ConfigureAwait in chained send
Libraries/Microsoft.Teams.AI/ChatPlugin.cs Add CancellationToken to hook
Libraries/Microsoft.Teams.AI/BaseChatPlugin.cs Add CancellationToken to base hook
Libraries/Microsoft.Teams.AI.Models.OpenAI/OpenAIChatModel.Send.cs Propagate token + async streaming

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

Comment thread Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Errors.cs Outdated
Comment thread Libraries/Microsoft.Teams.AI/Stream.cs Outdated
Comment thread Libraries/Microsoft.Teams.AI/Stream.cs
Comment thread Libraries/Microsoft.Teams.Common/Extensions/ActionExtensions.cs Outdated
- FlushSafe: catch specific Exception type with explanatory comment
  about transient flush errors
- McpClientPlugin: pass full Exception object to logger instead of
  just ex.Message, preserving stack traces for diagnostics
- ChatPrompt.Errors: avoid async void event handler by using
  fire-and-forget pattern instead of async lambda
- IStream: use default interface method for EmitAsync to avoid
  breaking external implementers; mark sync Emit as Obsolete
- ActionExtensions: replace ContinueWith(async ...) with proper
  async local function to avoid Task<Task> unwrapping issues

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 114 out of 114 changed files in this pull request and generated 6 comments.

Comments suppressed due to low confidence (2)

Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Send.cs:65

  • OnChunk swallows all exceptions from the onChunk callback (catch { return; }). Since this is in the send/streaming path, failures become invisible and can leave buffer in a surprising state (it won’t be cleared on exception). At minimum, log or raise ErrorEvent with the exception (and consider whether the buffer should be reset) so callback failures are diagnosable.
            try
            {
                await onChunk(buffer).ConfigureAwait(false);
                buffer = string.Empty;
            }
            catch { return; }
        }

Libraries/Microsoft.Teams.Common/Extensions/ActionExtensions.cs:25

  • Debounce<T> discards the continuation task. If func(arg) throws, the exception is captured on the discarded task and becomes unobserved. Also, the prior CancellationTokenSource is canceled but never disposed, which can leak resources in long-running processes. Wrap func(arg) in a try/catch (or observe/log continuation faults) and ensure old token sources are disposed (e.g., dispose the previous CTS after cancel, or dispose the per-invocation CTS in the continuation).

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

Comment thread Libraries/Microsoft.Teams.Apps/App.cs Outdated
Comment thread Libraries/Microsoft.Teams.Apps/Contexts/Context.SignIn.cs
Comment thread Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Errors.cs Outdated
Comment thread Libraries/Microsoft.Teams.Common/Extensions/ActionExtensions.cs
- FlushSafe: reschedule retry timer on failure to prevent Close()
  from spinning forever when _id is null after a transient send error
- App.cs, Context.SignIn.cs: pass full Exception object to logger
  instead of interpolated ex.Message, preserving stack traces
- ApplicationBuilder.Functions: use FirstOrDefault() instead of
  First() for Authorization header to avoid throwing on missing header
- ChatPrompt.Errors: observe fire-and-forget task faults via
  ContinueWith and log them, instead of silently discarding
- ActionExtensions: catch non-cancellation exceptions in DebounceCore
  to prevent UnobservedTaskException; dispose previous CTS to avoid
  resource leaks

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 114 out of 114 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

Libraries/Microsoft.Teams.Common/Extensions/ActionExtensions.cs:25

  • Debounce<T> fires a continuation task and discards it; if func(arg) throws, the continuation will fault and can surface as an unobserved task exception. Wrap func(arg) in try/catch (or refactor to an async core similar to the Func<Task> overload) so exceptions are observed/handled deterministically.
    Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Send.cs:65
  • OnChunk swallows all exceptions from the user-provided onChunk callback and returns without clearing buffer. If onChunk throws once, buffer will keep growing on subsequent chunks, which can cause unbounded memory growth and makes failures invisible. Consider logging and either clearing the buffer on failure or stopping streaming/propagating the error.
            try
            {
                await onChunk(buffer).ConfigureAwait(false);
                buffer = string.Empty;
            }
            catch { return; }
        }

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

Comment thread Libraries/Microsoft.Teams.AI/Stream.cs Outdated
@rido-min
Copy link
Copy Markdown
Member Author

@copilot open a new pull request to apply changes based on the comments in this thread

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 26, 2026

@rido-min I've opened a new pull request, #403, to work on those changes. Once the pull request is ready, I'll request review from you.

…ancellationToken propagation in McpClientPlugin (#403)

Three issues flagged in review of the async anti-pattern fixes PR were
left unaddressed.

## Changes

- **`Stream.Emit`** – Remove unnecessary `EmitAsync` indirection; call
`onChunk(text).GetAwaiter().GetResult()` directly.
`ConfigureAwait(false)` on a synchronously-blocked call has no effect.

- **`AspNetCorePlugin.Stream` / `FlushSafe`** – Add optional `ILogger?
Logger` property to the nested `Stream` class. `CreateStream` wires it
to `Logger.Child("stream")`. `FlushSafe` now logs at `Warn` with the
full exception before scheduling the retry timer, making send failures
diagnosable in production.

- **`McpClientPlugin`** – Thread `CancellationToken` from
`OnBuildFunctions` through the full discovery call chain:
  ```
  OnBuildFunctions(cancellationToken)
    → FetchToolsIfNeeded(cancellationToken)
      → FetchToolsFromServer(..., cancellationToken)
→ McpClientFactory.CreateAsync(..., cancellationToken:
cancellationToken)
        → client.ListToolsAsync(cancellationToken: cancellationToken)
  ```
Previously the token was accepted but never forwarded, so callers could
not cancel in-flight tool discovery.

<!-- START COPILOT CODING AGENT TIPS -->
---

⌨️ Start Copilot coding agent tasks without leaving your editor —
available in [VS Code](https://gh.io/cca-vs-code-docs), [Visual
Studio](https://gh.io/cca-visual-studio-docs), [JetBrains
IDEs](https://gh.io/cca-jetbrains-docs) and
[Eclipse](https://gh.io/cca-eclipse-docs).

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>
@rido-min
Copy link
Copy Markdown
Member Author

@copilot review the status of the comments on this PR with the latest commits, and resolve comments that are not applicable anymore

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 26, 2026

@copilot review the status of the comments on this PR with the latest commits, and resolve comments that are not applicable anymore

I've reviewed all review comments against the current code (latest commit 9ba530e). Here's the status:

All resolved:

  1. FlushSafe suppresses exceptions (3 rounds of feedback) — Now logs via Logger?.Warn(...) with full exception, plus retry timer for forward progress.
  2. McpClientPlugin catch drops stack trace — Now passes ex object to logger.
  3. ChatPrompt.Errors async void / unobserved task — Uses ContinueWith with OnlyOnFaulted + Logger.Error(t.Exception).
  4. Stream.Emit sync-over-async indirection — Marked [Obsolete], calls onChunk(text).GetAwaiter().GetResult() directly.
  5. ActionExtensions.Debounce Task<Task> / unobserved exceptions — Rewritten with DebounceCore async local function + try/catch, CTS disposed before reuse.
  6. App.cs / Context.SignIn log only ex.Message — Both now pass the exception object to the logger.
  7. ApplicationBuilder.Functions Authorization.First() throws — Changed to FirstOrDefault() is null.
  8. McpClientPlugin ignores CancellationToken — Token threaded through FetchToolsIfNeededFetchToolsFromServer → MCP SDK calls.

Design choice (not a bug):

  1. IStream.EmitAsync breaking changeEmitAsync has a default interface implementation that delegates to Emit(), so existing external implementers won't break. This is an intentional design decision.

MehakBindra
MehakBindra previously approved these changes Mar 31, 2026
Copilot AI review requested due to automatic review settings March 31, 2026 20:41
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 114 out of 114 changed files in this pull request and generated 2 comments.


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

@rido-min
Copy link
Copy Markdown
Member Author

rido-min commented May 8, 2026

@copilot resolve the merge conflicts in this pull request

Agent-Logs-Url: https://github.com/microsoft/teams.net/sessions/0884830b-36b2-44a7-ac0e-05f46dbf2b4f

Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 8, 2026

@copilot resolve the merge conflicts in this pull request

Resolved the merge conflicts against the latest main and pushed the update in commit 8d8dd09. I also ran targeted Microsoft.Teams.Api.Tests and Microsoft.Teams.Apps.Tests successfully after resolving the conflicted files.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • token.botframework.com
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net10.0/Microsoft.Teams.Apps.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net10.0/Microsoft.Teams.Apps.Tests.deps.json /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net10.0/testhost.dll --port 38611 --endpoint 127.0.0.1:038611 --role client --parentprocessid 6256 --telemetryoptedin false (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net8.0/Microsoft.Teams.Apps.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net8.0/Microsoft.Teams.Apps.Tests.deps.json /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net8.0/testhost.dll --port 38481 --endpoint 127.0.0.1:038481 --role client --parentprocessid 6255 --telemetryoptedin false (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

@rido-min
Copy link
Copy Markdown
Member Author

rido-min commented May 8, 2026

@copilot resolve the merge conflicts in this pull request

# Conflicts:
#	Libraries/Microsoft.Teams.Api/Clients/BotTokenClient.cs
#	Libraries/Microsoft.Teams.Api/Clients/UserTokenClient.cs
#	Libraries/Microsoft.Teams.Apps/App.cs
#	Libraries/Microsoft.Teams.Apps/AppEvents.cs
#	Libraries/Microsoft.Teams.Apps/AppRouting.cs

Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>
Copy link
Copy Markdown
Contributor

Copilot AI commented May 8, 2026

@copilot resolve the merge conflicts in this pull request

Resolved the merge conflicts by merging origin/main into this branch and finalized a true merge commit with both parents. The update is pushed in commit 5ee0ebd, and targeted Microsoft.Teams.Api.Tests and Microsoft.Teams.Apps.Tests pass.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • token.botframework.com
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net8.0/Microsoft.Teams.Apps.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net8.0/Microsoft.Teams.Apps.Tests.deps.json /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net8.0/testhost.dll --port 46513 --endpoint 127.0.0.1:046513 --role client --parentprocessid 5417 --telemetryoptedin false (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net10.0/Microsoft.Teams.Apps.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net10.0/Microsoft.Teams.Apps.Tests.deps.json /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net10.0/testhost.dll --port 34519 --endpoint 127.0.0.1:034519 --role client --parentprocessid 5416 --telemetryoptedin false (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net8.0/Microsoft.Teams.Apps.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net8.0/Microsoft.Teams.Apps.Tests.deps.json /home/REDACTED/work/teams.net/teams.net/Tests/Microsoft.Teams.Apps.Tests/bin/Debug/net8.0/testhost.dll --port 42823 --endpoint 127.0.0.1:042823 --role client --parentprocessid 6046 --telemetryoptedin false (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI review requested due to automatic review settings May 15, 2026 18:28
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 113 out of 113 changed files in this pull request and generated 8 comments.

Comment thread Libraries/Microsoft.Teams.Common/Http/HttpClient.cs Outdated
Comment thread Libraries/Microsoft.Teams.Common/Http/HttpClient.cs Outdated
Comment thread Libraries/Microsoft.Teams.Common/Extensions/ActionExtensions.cs
Comment thread Libraries/Microsoft.Teams.Apps/App.cs
Comment thread Libraries/Microsoft.Teams.Apps/Contexts/Context.cs
Comment thread Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Errors.cs Outdated
… stream retry logic

- ServiceCollection.cs: fix misleading comment about ConfigureAwait(false) during sync DI resolution
- HttpClient.cs: pass cancellationToken to ParseErrorBody to avoid hanging on error reads after cancellation
- ActionExtensions.cs: observe exceptions in fire-and-forget Debounce<T> continuation to prevent UnobservedTaskException
- AspNetCorePlugin.Stream.cs: fix Flush() to retry accumulated state when queue is drained but _id is still null
- App.cs: re-throw OperationCanceledException from broad catch in AutoUserTokenLookup block
- Context.Send.cs: use cancellationToken method parameter instead of this.CancellationToken
- ChatPrompt.Errors.cs: explicitly discard ContinueWith task to avoid CS4014 build warning
Copilot AI review requested due to automatic review settings May 27, 2026 17:06
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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@rido-min rido-min added this pull request to the merge queue May 27, 2026
Merged via the queue into main with commit 80aa830 May 27, 2026
10 checks passed
@rido-min rido-min deleted the fix/async-issues-396-401 branch May 27, 2026 21:38
singhk97 added a commit that referenced this pull request May 28, 2026
commit fc3aaaa893e8dc8579b4ba466641ce906b766977
Author: Mehak Bindra <mhk0397@gmail.com>
Date:   Wed May 27 16:47:13 2026 -0700

    Simplify dependency management for TeamsBotApplication (#521)

    This pull request refactors the Teams bot application hosting model to
    simplify bot setup and handler registration, unify options management,
    and streamline dependency injection. Key changes include updating the
    `TeamsBotApplication` constructor and options pattern, consolidating
    handler registration into bot subclasses, and improving the `ApiClient`
    interface. The sample bots and tests are updated to reflect these
    changes.

    **TeamsBotApplication and Options Refactoring:**

    * The `TeamsBotApplication` constructor now takes an `ApiClient`,
    `IHttpContextAccessor`, a logger, and an optional
    `TeamsBotApplicationOptions`, consolidating the previously separate
    conversation and user token clients into the `ApiClient`. The options
    class now inherits from `BotApplicationOptions` for unified
    configuration.

    **Sample Bot Simplification:**

    * The ExtAIBot sample is refactored: handler registration is moved from
    a static extension method into the `ExtAIBotApp` class constructor, and
    the DI registration is updated to use the new hosting model.

    **ApiClient Interface Improvements:**

    * `ApiClient` now exposes `ConversationClient` and `UserTokenClient` as
    internal properties instead of private fields, improving testability and
    consistency. All constructors and copy methods are updated accordingly.

    **Configuration and Dependency Injection Updates:**

    * The Teams bot options now automatically set the `AppId` from the
    resolved bot configuration. The ExtAIBot sample's `appsettings.json` and
    DI registrations are updated to match the new options and Azure OpenAI
    configuration pattern.

    **Test and Code Cleanup:**

    * Unit tests are updated to use the new constructor patterns, and
    unnecessary project references are removed.

    ---------

    Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
    Co-authored-by: Rido <rido-min@users.noreply.github.com>

commit 80aa830d46099d0ea75b4845d4440d5910c9b542
Author: Rido <rido-min@users.noreply.github.com>
Date:   Wed May 27 14:34:43 2026 -0700

    Fix async anti-patterns across all library projects (#402)

    - **#396** - Fix sync-over-async blocking calls
    (`GetAwaiter().GetResult()`) by converting to proper `await` in
    `ApplicationBuilder.Functions`, `Stream`, `ChatPrompt.Errors`; add
    `ConfigureAwait(false)` to `ServiceCollection` DI factory
    - **#397** - Fix CancellationToken misuse: propagate tokens correctly in
    `OpenAIChatModel.Send`, `Context.Send`, `HttpClient.SendAsync`; add
    missing `CancellationToken` parameter to
    `IChatPlugin.OnBuildInstructions`
    - **#398** - Replace empty `catch { }` blocks with exception logging in
    `App.cs`, `Context.SignIn`, `McpClientPlugin`
    - **#399** - Add error handling to fire-and-forget `Flush()` calls in
    `AspNetCorePlugin.Stream` via `FlushSafe()` wrapper; replace
    `Task.Run(() => { })` with `Task.CompletedTask`; use `_ =` discard
    pattern in debounce extensions
    - **#400** - Add `ConfigureAwait(false)` to ~380 `await` calls across
    all library projects to prevent deadlocks and unnecessary context
    capture
    - **#401** - Replace `Task.Run` wrapping sync code with direct execution
    + `Task.CompletedTask` in `LocalStorage`; fix unsafe reflection-based
    `Task.Result` access in `MethodInfoExtensions`

    Fixes #396, #397, #398, #399, #400, #401

    - [x] Solution builds with 0 errors
    - [x] All existing tests pass (122 Apps tests, 15 AspNetCore tests, 9
    McpClient tests, 3 Graph tests)
    - [x] Verify streaming behavior works correctly with the new `EmitAsync`
    method on `IStream`
    - [x] Verify cancellation propagation works for OpenAI API calls
    - [x] Verify OAuth sign-in flow logs errors appropriately instead of
    silently swallowing

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

    ---------

    Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>

commit db32621c33c32541440282437ab0b9f7e6504b19
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Wed May 27 12:59:58 2026 -0700

    Reject unauthenticated requests when no credentials are configured (#530)

    `AddTeamsTokenAuthentication` currently engages the `RequireAssertion(_
    => true)` bypass policy whenever `skipAuth: true` is passed **or** the
    configured `ClientId` is empty. That means an empty `ClientId` silently
    disables auth for any deployment that forgot to set credentials, with no
    opt-in.

    This change splits the condition: `skipAuth: true` still bypasses, but a
    missing `ClientId` without `skipAuth` now fails closed
    (`RequireAssertion(_ => false)`). Callers that intentionally want
    unauthenticated local development pass `skipAuth: true` to
    `AddTeams(...)`.

    Aligns with the equivalent change in TypeScript (microsoft/teams.ts#506)
    and Python (microsoft/teams.py#360).

    - [ ] Existing test suite passes
    - [ ] Add a test asserting requests are rejected (401/403) when
    `ClientId` is empty and `skipAuth` is not set
    - [ ] Add a test asserting requests still bypass when `skipAuth: true`
    is explicitly passed with empty `ClientId`
    - [ ] Manual: run a sample with no credentials configured and confirm
    requests now fail closed unless `skipAuth: true` is set

commit 3ddf9fa76ec1801a0e3ca312c6d9855879571ac1
Author: Kavin <115390646+singhk97@users.noreply.github.com>
Date:   Wed May 27 15:56:07 2026 -0400

    sync main with patches in releases/core (#505)

    applied some patches to releases/core to fix the released version.
    syncing main now.

commit e975f15ad3b690524ba51d6d16962a8dbbb5efaa
Author: Kavin <115390646+singhk97@users.noreply.github.com>
Date:   Wed May 27 14:47:40 2026 -0400

    feat: SuggestedActionSubmit handler for 2.1 (#528)

    Ports the `suggestedActions/submit` invoke support from Libraries/
    (#464) to core/:

    - `InvokeNames.SuggestedActionSubmit` constant and `ActionType.Submit`
    - `OnSuggestedActionSubmit()` handler extension on `TeamsBotApplication`
    - `SuggestedActionBot` sample
    - Unit tests

    All new API surface marked
    `[Experimental("ExperimentalTeamsSuggestedAction")]`.

    - [x] `dotnet build core.slnx` — clean
    - [x] `dotnet test core.slnx` — 755/755 pass on both net8.0 and net10.0
    - [x] E2E verified against Teams client

    <img width="671" height="289" alt="image"
    src="https://github.com/user-attachments/assets/2959f3c9-f194-4e1f-9e06-9cdf6bbb86d0"
    />

    ---------

    Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    Co-authored-by: Rido <rido-min@users.noreply.github.com>

commit 733a37f2b7310e6fd954187427f2af0e713dc286
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Wed May 27 11:41:17 2026 -0700

    feat: deprecate DevTools (Libraries 2.0) in favor of Microsoft 365 Agents Playground (#522)

    - **`[Obsolete]` on `DevToolsPlugin` and `AddTeamsDevTools()`** in
    `Microsoft.Teams.Plugins.AspNetCore.DevTools`. Consumers see CS0618 on
    their `.AddTeamsDevTools()` calls with a clear migration message.
    - **Add anonymous-mode startup warning** in
    `AddTeamsTokenAuthentication` when `Teams:ClientId` is empty. Customers
    running with no credentials get an explicit signal that their bot
    accepts unauthenticated requests on `/api/messages`.
    - **Remove `AddTeamsDevTools()`** and the DevTools `ProjectReference`
    from all 16 samples. The samples now demonstrate the SDK without
    DevTools; users should run Microsoft 365 Agents Playground for local
    testing.
    - **`PackageReleaseNotes` and `[DEPRECATED]`-prefixed
    `PackageDescription`** on the DevTools csproj so the deprecation
    metadata surfaces in NuGet package browsers.
    - **README banner** on the DevTools package pointing at Microsoft 365
    Agents Playground.

    DevTools is being replaced by Microsoft 365 Agents Playground. The
    replacement is a standalone CLI tool; customers install it separately
    and run it alongside their bot. For the grace period, `DevToolsPlugin`
    keeps working but loudly signals its deprecation through `[Obsolete]`,
    package metadata, and the README.

    The deprecation message wording stays version-agnostic per team
    convention ("a later version", not a specific version number).

    - The DevTools library's own internal `DevToolsController` references
    `DevToolsPlugin` (by design). To avoid breaking its build under
    `TreatWarningsAsErrors=true`, the DevTools csproj adds `CS0618` to its
    `NoWarn` list. Consumer code outside the library still sees the warning.
    - Three samples (`Samples.AI`, `Samples.Cards`, `Samples.Dialogs`) were
    pulling `Microsoft.Teams.Plugins.AspNetCore` in transitively through
    DevTools. Each gets an explicit `ProjectReference` so they keep
    building.
    - The project-wide `CS0618` suppression in
    `Samples/Directory.Build.props` is removed now that no sample calls
    `AddTeamsDevTools()`.

    The warning is emitted inline in `AddTeamsTokenAuthentication` via a
    small helper that looks up the host's already-registered
    `ILoggerFactory` instance directly off the service collection, falling
    back to `NullLogger` if no factory is registered yet. This mirrors the
    `GetLoggerFromServices` helper in
    `core/src/Microsoft.Teams.Core/Hosting/AddBotApplicationExtensions.cs`.
    The pattern was chosen over two earlier iterations after review
    feedback:

    - A standalone `LoggerFactory.Create(b => b.AddConsole())` would force
    console output regardless of consumer logging configuration.
    - An `IHostedService` (one of the intermediate iterations) was
    structurally heavyweight for a single startup warning.

    The warning text says "No Teams:ClientId configured" rather than
    mirroring the `CLIENT_ID / CLIENT_SECRET / TENANT_ID` env-var phrasing
    used in teams.ts and teams.py, because the .NET SDK binds settings
    through the `Teams:*` configuration section.

    - [x] `dotnet build Microsoft.Teams.sln` (0 errors, 1 pre-existing
    warning on `Samples.Tab` unrelated to this change)
    - [x] Confirmed `DevToolsPlugin` and `AddTeamsDevTools()` emit CS0618 to
    external consumers when used
    - [x] Anonymous-mode warning verified to fire from the inline `ILogger`
    lookup path (helper returns the registered factory's logger when
    present)
    - [ ] Reviewer to spot-check one or two samples compile and run cleanly
    without DevTools

    The corresponding `nuget.org` deprecation flag should be set on
    `Microsoft.Teams.Plugins.AspNetCore.DevTools` after this ships, so
    consumers running `dotnet add package` see a deprecation banner. Tracked
    separately by the publishing engineer.

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

    ---------

    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit 763c2cf3c2405fce5db7765b35c0a09d3d398b28
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Wed May 27 10:47:17 2026 -0700

    ci: add merge_group trigger to Build & Test & Lint (#531)

    - Adds `merge_group:` to the `on:` triggers of
    `.github/workflows/build-test-lint.yml` so the workflow runs on
    `gh-readonly-queue/*` refs created by GitHub's merge queue.
    - No behavior change until a merge queue is enabled on the `main`
    ruleset; the trigger is dormant otherwise.
    - Prereq for turning on "Require merge queue" — without this, the
    required `Build & Test & Lint` check would never report on queued PRs
    and the queue would stall.

    - [x] Confirm CI still runs as expected on this PR (pull_request trigger
    unchanged)
    - [ ] After merge, enable "Require merge queue" on the `main` ruleset
    and verify the workflow fires against the queue's temporary refs

    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit 0fce0f91010f05e6e843920182e741b84c527cbd
Author: Kavin <115390646+singhk97@users.noreply.github.com>
Date:   Wed May 27 13:30:42 2026 -0400

    feat: SuggestedActionSubmitActivity for suggestedActions/submit invoke (#464)

    Adds first-class support for the `suggestedAction/submit` invoke
    activity (the platform-side dispatch of an `Action.Submit`
    suggested-action click).

    - New typed activity `SuggestedActionSubmitActivity` and
    `OnSuggestedActionSubmit` route extension, modeled after
    `HandoffActivity` / `OnHandoff`.
    - New `Microsoft.Teams.Api.Cards.ActionType.Submit` value, so bots can
    construct outbound `suggestedActions.actions[]` chips with `type:
    "Action.Submit"`, `title`, and structured `value`.
    - All new public surface marked
    `[Experimental("ExperimentalTeamsSuggestedAction")]`. Internal
    references suppress via `#pragma`.
    - New `Samples.SuggestedAction` project demonstrates both directions:
    bot replies with Approve/Reject chips, then handles the resulting
    invoke.

    - [x] `dotnet build Microsoft.Teams.sln` — clean
    - [x] `dotnet test Microsoft.Teams.sln` — 1293/1293 pass on both
    `net8.0` and `net10.0`. Includes a wire-format test asserting the
    outgoing `suggestedActions.actions[].{type,title,value}` JSON matches
    the design spec.
    - [x] Verified end-to-end against the running sample: posted a
    synthesized invoke, confirmed typed dispatch into
    `SuggestedActionSubmitActivity` and that `activity.Value` round-trips as
    a `JsonElement`.
    - [x] Manual verification with a payload from the Teams chat client once
    the platform side ships.

    ---------

    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

commit c90350b892696836fbfd69ca336aa96d5c92e16c
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Wed May 27 10:25:51 2026 -0700

    Bump qs from 6.15.1 to 6.15.2 in /Samples/Samples.Tab/Web (#524)

    Bumps [qs](https://github.com/ljharb/qs) from 6.15.1 to 6.15.2.
    <details>
    <summary>Changelog</summary>
    <p><em>Sourced from <a
    href="https://github.com/ljharb/qs/blob/main/CHANGELOG.md">qs's
    changelog</a>.</em></p>
    <blockquote>
    <h2><strong>6.15.2</strong></h2>
    <ul>
    <li>[Fix] <code>stringify</code>: skip null/undefined entries in
    <code>arrayFormat: 'comma'</code> + <code>encodeValuesOnly</code>
    instead of crashing in <code>encoder</code></li>
    <li>[Fix] <code>stringify</code>: use configured <code>delimiter</code>
    after <code>charsetSentinel</code> (<a
    href="https://redirect.github.com/ljharb/qs/issues/555">#555</a>)</li>
    <li>[Fix] <code>stringify</code>: apply <code>formatter</code> to
    encoded key under <code>strictNullHandling</code> (<a
    href="https://redirect.github.com/ljharb/qs/issues/554">#554</a>)</li>
    <li>[Fix] <code>stringify</code>: skip null/undefined filter-array
    entries instead of crashing in <code>encoder</code> (<a
    href="https://redirect.github.com/ljharb/qs/issues/551">#551</a>)</li>
    <li>[Fix] <code>parse</code>: handle nested bracket groups and add
    regression tests (<a
    href="https://redirect.github.com/ljharb/qs/issues/530">#530</a>)</li>
    <li>[readme] fix grammar (<a
    href="https://redirect.github.com/ljharb/qs/issues/550">#550</a>)</li>
    <li>[Dev Deps] update <code>@ljharb/eslint-config</code></li>
    <li>[Tests] add regression tests for keys containing percent-encoded
    bracket text</li>
    </ul>
    </blockquote>
    </details>
    <details>
    <summary>Commits</summary>
    <ul>
    <li><a
    href="https://github.com/ljharb/qs/commit/9aca4076fe788338c67cf7e115f0be6bc58d85a8"><code>9aca407</code></a>
    v6.15.2</li>
    <li><a
    href="https://github.com/ljharb/qs/commit/5e33d33447ed0bf1ddab9abc41d27dea4687d992"><code>5e33d33</code></a>
    [Dev Deps] update <code>@ljharb/eslint-config</code></li>
    <li><a
    href="https://github.com/ljharb/qs/commit/21f80b33e5c8b3f7eba1034fff0da4a4a37a1d41"><code>21f80b3</code></a>
    [Fix] <code>stringify</code>: skip null/undefined entries in
    <code>arrayFormat: 'comma'</code> + `e...</li>
    <li><a
    href="https://github.com/ljharb/qs/commit/a0a81ea2071acce3eff41a040f719ac8f5c4f64c"><code>a0a81ea</code></a>
    [Fix] <code>stringify</code>: use configured <code>delimiter</code>
    after <code>charsetSentinel</code></li>
    <li><a
    href="https://github.com/ljharb/qs/commit/e3062f78f5233b338ceeb8e8dfa5a07dea4b32a8"><code>e3062f7</code></a>
    [Fix] <code>stringify</code>: apply <code>formatter</code> to encoded
    key under <code>strictNullHandling</code></li>
    <li><a
    href="https://github.com/ljharb/qs/commit/0c180a40adb8c6703fffc85b2ff06ca209f5c1e0"><code>0c180a4</code></a>
    [Fix] <code>stringify</code>: skip null/undefined filter-array entries
    instead of crashi...</li>
    <li><a
    href="https://github.com/ljharb/qs/commit/3a8b94aec19bd664720f6f6b1e66c4a0dfe4b656"><code>3a8b94a</code></a>
    [Tests] add regression tests for keys containing percent-encoded bracket
    text</li>
    <li><a
    href="https://github.com/ljharb/qs/commit/96755abd357c0e534dd3442a84a04d08864bfe0d"><code>96755ab</code></a>
    [readme] fix grammar</li>
    <li><a
    href="https://github.com/ljharb/qs/commit/a419ce5bbfcdb98a299f1a0bb47ea055baef20e6"><code>a419ce5</code></a>
    [Fix] <code>parse</code>: handle nested bracket groups and add
    regression tests</li>
    <li>See full diff in <a
    href="https://github.com/ljharb/qs/compare/v6.15.1...v6.15.2">compare
    view</a></li>
    </ul>
    </details>
    <br />

    [![Dependabot compatibility
    score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=qs&package-manager=npm_and_yarn&previous-version=6.15.1&new-version=6.15.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

    Dependabot will resolve any conflicts with this PR as long as you don't
    alter it yourself. You can also trigger a rebase manually by commenting
    `@dependabot rebase`.

    [//]: # (dependabot-automerge-start)
    [//]: # (dependabot-automerge-end)

    ---

    <details>
    <summary>Dependabot commands and options</summary>
    <br />

    You can trigger Dependabot actions by commenting on this PR:
    - `@dependabot rebase` will rebase this PR
    - `@dependabot recreate` will recreate this PR, overwriting any edits
    that have been made to it
    - `@dependabot show <dependency name> ignore conditions` will show all
    of the ignore conditions of the specified dependency
    - `@dependabot ignore this major version` will close this PR and stop
    Dependabot creating any more for this major version (unless you reopen
    the PR or upgrade to it yourself)
    - `@dependabot ignore this minor version` will close this PR and stop
    Dependabot creating any more for this minor version (unless you reopen
    the PR or upgrade to it yourself)
    - `@dependabot ignore this dependency` will close this PR and stop
    Dependabot creating any more for this dependency (unless you reopen the
    PR or upgrade to it yourself)
    You can disable automated security fix PRs for this repo from the
    [Security Alerts
    page](https://github.com/microsoft/teams.net/network/alerts).

    </details>

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: Kavin <115390646+singhk97@users.noreply.github.com>

commit e2f98f1d2472ee96733aa109e0d33532e82a77d2
Author: Rido <rido-min@users.noreply.github.com>
Date:   Wed May 27 09:46:53 2026 -0700

    Fix GetLoggerFromServices returning NullLogger during DI setup (#526)
    - **Fixed** `GetLoggerFromServices` always returning `NullLogger`
    because it only checked `ImplementationInstance` for `ILoggerFactory`,
    which is `null` in typical ASP.NET Core apps where `AddLogging()`
    registers via factory delegate.
    - **Extracted** a shared `ResolveFromServices<T>` helper that tries
    `ImplementationInstance` first, then falls back to a temporary
    `ServiceProvider` — unifying the pattern already used in
    `BotConfig.Resolve` for `IConfiguration`.
    - [ ] Verify DI setup logs (e.g. `InferringUserAssignedManagedIdentity`)
    now appear in configured logging providers
    - [ ] Verify `BotConfig.Resolve` still resolves `IConfiguration`
    correctly
    - [ ] Run existing integration/unit tests to confirm no regressions

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

    ---------

    Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

commit f065e0a2fc43586e8f4b811d71d825634f5bfd0f
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Wed May 27 09:37:53 2026 -0700

    Security hardening: gate DevTools WebSocket behind same-origin check (#527)

    Replaces the DevTools WebSocket `WebSocketOptions.AllowedOrigins = { "*"
    }` policy with a same-origin middleware that rejects upgrades whose
    `Origin` header does not match the request `Host` (and rejects absent
    `Origin`).

    The DevTools UI is always loaded from the same origin as the bot server,
    so legitimate clients send an `Origin` matching `Host`. Allowing any
    origin permitted any web page open in the developer's browser during
    local dev to open `ws://localhost:<port>/devtools/sockets` and inject or
    sniff DevTools traffic. Same-origin policy closes this without affecting
    the DevTools UI's own use of the endpoint.

    - No public API change.
    - No behavior change for the DevTools UI in normal use (it always loads
    same-origin).
    - DevTools is already environment-guarded (cannot start in
    `Production`), so this change tightens dev-mode behavior only.

    The Origin check inspects the `Upgrade` and `Origin` request headers
    directly rather than using `context.WebSockets.IsWebSocketRequest`, so
    the middleware does not depend on `UseWebSockets()` having registered
    `IHttpWebSocketFeature` first.

    - Full solution `dotnet build` and `dotnet test -f net10.0` clean.
    - `Samples.Echo` with DevTools enabled:
    - Same-origin upgrade (`Origin: http://localhost:3978`) → 101 Switching
    Protocols
    - Cross-origin upgrade (`Origin: https://attacker.example`) → 403
    Forbidden
      - Missing `Origin` → 403 Forbidden
      - Plain GET `/devtools/` → 200 (UI still serves)

    `core/` does not register a similar WebSocket origin policy; the
    equivalent DevTools surface there does not currently exist. This PR
    scopes to `Libraries/`.

commit d5bc4f2e7528460891592b5bcf5e629cdee57a7b
Author: Mehak Bindra <mhk0397@gmail.com>
Date:   Tue May 26 14:07:08 2026 -0700

    Improvements to MCP Server Sample (#518)

    This pull request introduces several significant improvements to the MCP
    server sample, focusing on user search, adaptive card-based asks, and
    enhanced approval/reply handling. The most important changes include
    adding a `find_user` tool to search for users by name or email,
    switching the "ask" flow to use adaptive cards (allowing multiple
    outstanding asks per user), and introducing efficient wait-based APIs
    for replies and approvals. The changes also update the handling of user
    IDs to always use Azure AD object IDs, and update the documentation
    accordingly.

    **User Search and Identity Handling**
    * Added a new `GraphClient` class and dependency to enable searching for
    users in the tenant by partial name, email, or UPN, returning their
    Azure AD object IDs. This is exposed via the new `find_user` tool and
    associated models (`UserMatch`, `FindUserResult`).
    * All tools now use the Azure AD object ID (`userId`) for identifying
    users, and the documentation clarifies this.

    **Adaptive Card-based Ask Flow**
    * The `ask` tool now sends an adaptive card with a reply box to the
    user, allowing multiple outstanding asks per user (previously only one
    was allowed). The reply is handled via adaptive card action, and the old
    single-ask logic is removed.
    * Added a handler for the new "ask_reply" adaptive card action, updating
    the pending ask and unblocking any waiters.

    **Wait-based APIs for Replies and Approvals**
    * Added `wait_for_reply` and `wait_for_approval` APIs that block (with
    timeout) until a reply or approval decision is received, using
    `TaskCompletionSource` for efficient waiting. Manual polling APIs
    (`get_reply`, `get_approval`) remain for compatibility

    **Other Improvements**
    * Updated the README to document the new tools and clarify user ID
    usage.
    * Refactored internal state handling to support the new flows and
    concurrency model.

    These changes modernize the MCP sample, improve user experience, and
    enable more robust automation scenarios.

commit 0cabd5fe0a13eb9638a77b3ee5984d052fae16c4
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Tue May 26 10:27:41 2026 -0700

    Security: lock JsonWebToken trust-boundary contract (#6 disposition) (#517)

    Documents the layered authentication model the SDK uses for inbound JSON
    Web Tokens. .NET half of a 3-SDK PR set.

    Security scan finding "JsonWebToken No Signature Verification" flagged
    the `JsonWebToken` accessor class for using
    `JwtSecurityTokenHandler.ReadJwtToken()` (decode-only, no signature
    verification). A cross-SDK audit confirmed this is intentional
    architecture: signature verification runs at the ASP.NET Core JwtBearer
    middleware configured by `TokenValidator.ConfigureValidation`
    (`Libraries/Microsoft.Teams.Plugins/Microsoft.Teams.Plugins.AspNetCore/Extensions/TokenValidator.cs`),
    applied to endpoints via `.RequireAuthorization(...)`. The accessor
    exists as a typed view over already-validated payloads. Every consumer
    of decoded claims is downstream of either a JwtBearer validation or a
    trusted identity-infrastructure source.

    This PR makes the architectural invariant explicit at the constructor
    site so future readers (and the scanner on its next pass) see the design
    intent locally.

    XML documentation on both `JsonWebToken` constructors explaining that
    they perform no signature verification, where verification actually
    happens, and the rule that callers must not construct from raw network
    input.

    `core/` was audited separately and does not have an equivalent
    decode-only public accessor. Its inbound JWT validation is enforced at
    the middleware level with `ValidateIssuerSigningKey = true` and
    `RequireSignedTokens = true` hardcoded; there is no public API to
    misuse. The finding does not apply to `core/`. This PR scopes to
    `Libraries/` only.

    - No runtime behavior change. No signature verification added or
    removed.
    - No API surface change. `JsonWebToken` keeps its current name (verified
    public in the packable `Microsoft.Teams.Api` assembly, including via
    `IContext<TActivity>.UserGraphToken` and
    `AspNetCorePlugin.ExtractToken()` return type; a rename would have been
    breaking).
    - No effect on the activity pipeline. JWT validation continues to happen
    via JwtBearer middleware exactly as before.

    - TypeScript: microsoft/teams.ts#586
    - Python: microsoft/teams.py#432
    - Documentation: microsoft/teams-sdk#2850

commit 37577ede8e0bfdd8e5b76b553e6fd1c409b3afdd
Author: Rido <rido-min@users.noreply.github.com>
Date:   Fri May 22 11:15:10 2026 -0700

    Update README and icon for core packages (#520)

    Revise the README files to clarify the setup process for the Teams bot
    application and remove outdated OAuth scope references. This update
    enhances the documentation's accuracy and relevance.

commit 8d6b4f151680cef16b0a14160132096bed16a177
Author: Mehak Bindra <mhk0397@gmail.com>
Date:   Fri May 22 09:20:22 2026 -0700

    Deprecating Microsoft.Teams.AI and Microsoft.Teams.AI.Models.OpenAI (#519)

    This pull request deprecates both the `Microsoft.Teams.AI` and
    `Microsoft.Teams.AI.Models.OpenAI` libraries, signaling that they will
    be removed by the end of summer 2026. T

    The most important changes are:

    **Deprecation Annotations in Code:**

    * Added `[Obsolete("Microsoft.Teams.AI is deprecated and will be removed
    by end of summer 2026.")]` to all major public classes and interfaces in
    the `Microsoft.Teams.AI` library, including `ChatPluginAttribute`,
    `FunctionAttribute`, `ParamAttribute`, `PromptAttribute`,
    `BaseChatPlugin`, `IChatPlugin`, `IFunction`, `Function`, and
    `FunctionCollection`.
    * Added `[Obsolete("Microsoft.Teams.AI.Models.OpenAI is deprecated and
    will be removed by end of summer 2026.")]` to all major public classes
    in the `Microsoft.Teams.AI.Models.OpenAI` library, such as
    `OpenAIChatModel`, `OpenAIChatPrompt`, `SequenceBuilder`,
    `StreamingChatToolCallsBuilder`, `MessageExtensions`, and
    `OpenAIChatModel.Options`.

    **Project Metadata and Documentation:**

    * Updated the NuGet package description and tags in
    `Microsoft.Teams.AI.Models.OpenAI.csproj` to reflect deprecation and
    added a warning suppression for obsolete usage.
    * Added a prominent deprecation notice at the top of the `README.md` for
    `Microsoft.Teams.AI.Models.OpenAI`.

    **Attribute Classes:**

    * Deprecated all attribute classes in both `Microsoft.Teams.AI` and
    `Microsoft.Teams.AI.Models.OpenAI`, including nested attributes like
    `Prompt.DescriptionAttribute`, `Prompt.InstructionsAttribute`,
    `Prompt.NameAttribute`, and `Function.DescriptionAttribute`.

    These changes ensure that developers are clearly warned about the
    upcoming removal of these libraries and are discouraged from using them
    in new projects.

commit 6f33abacc55fe7e8c03129b1bfe04117efa5e636
Author: Mehak Bindra <mhk0397@gmail.com>
Date:   Thu May 21 14:05:44 2026 -0700

    address model gaps (#472)

    This pull request introduces several deprecations and minor API
    adjustments across the Microsoft Teams API codebase. The primary focus
    is on marking certain properties, methods, and types as obsolete (to be
    removed by end of summer 2026), particularly in activity and
    account-related classes. There are also corresponding updates to
    constructors, serialization logic, and method usages to ensure
    compatibility and suppress deprecation warnings where necessary.
    Additionally, some usage of deprecated fields is being removed from
    application code.

    **Deprecations and Obsolescence Markings**

    * Marked several properties and types as `[Obsolete]`, including
    `RelatesTo` in `Activity`, multiple properties in `MessageActivity`
    (such as `Speak`, `InputHint`, `Importance`, `Expiration`), the `Id`
    property in `Attachment`, and the entire `EndOfConversationActivity` and
    `EndOfConversationCode` classes. These are all scheduled for removal by
    end of summer 2026.
    [[1]](diffhunk://#diff-875c3804dbdc89735553c417d023929c307dcfbead113a1b7a1e47871cab636aR59-R62)
    [[2]](diffhunk://#diff-875c3804dbdc89735553c417d023929c307dcfbead113a1b7a1e47871cab636aR127-R132)
    [[3]](diffhunk://#diff-05c926d7e09179d91c9c54a68c6b5efffb854bfddb70b431df77d6b2d280c44dR26-R31)
    [[4]](diffhunk://#diff-05c926d7e09179d91c9c54a68c6b5efffb854bfddb70b431df77d6b2d280c44dR56)
    [[5]](diffhunk://#diff-05c926d7e09179d91c9c54a68c6b5efffb854bfddb70b431df77d6b2d280c44dR65)
    [[6]](diffhunk://#diff-9151c814fbd9c905d4ab694534593d3ea239d68233e09908d71cacb7e7ff8902R20)
    [[7]](diffhunk://#diff-5d3b4f7fef169802c636878afce22853b92fe74a13a0462ab4930fad2b4edaf8R16)
    [[8]](diffhunk://#diff-5d3b4f7fef169802c636878afce22853b92fe74a13a0462ab4930fad2b4edaf8R35)

    * Marked several properties in `ConversationClient.CreateRequest` as
    obsolete, including `IsGroup`, `Bot`, and `TopicName`.
    [[1]](diffhunk://#diff-aad328d6be5c2acc005e534ddc0a3aae3e50d04e088908e5dc1f24962eac2e57R72-R77)
    [[2]](diffhunk://#diff-aad328d6be5c2acc005e534ddc0a3aae3e50d04e088908e5dc1f24962eac2e57R86)

    * Marked the `DeleteAsync` method in `MemberClient` as obsolete.

    **Deprecation Handling and Suppression**

    * Added `#pragma warning disable/restore CS0618` blocks throughout the
    codebase to suppress deprecation warnings when accessing or using
    obsolete properties and types, especially for `RelatesTo` and
    `EndOfConversationActivity`.
    [[1]](diffhunk://#diff-875c3804dbdc89735553c417d023929c307dcfbead113a1b7a1e47871cab636aR182-R184)
    [[2]](diffhunk://#diff-875c3804dbdc89735553c417d023929c307dcfbead113a1b7a1e47871cab636aR490-R492)
    [[3]](diffhunk://#diff-7fa90c4296b48d7529f16099722140fbb80a6c32663ef8b0e3f34488cd90c4fbR30-R32)
    [[4]](diffhunk://#diff-920cb13ff64033134157a73545c9d9090b7704c37e6ec43f830a7de9decd1282R67-R69)
    [[5]](diffhunk://#diff-920cb13ff64033134157a73545c9d9090b7704c37e6ec43f830a7de9decd1282R125-R131)
    [[6]](diffhunk://#diff-c163f6c08b3d0e64812ff6b8d265a93e6080cf1b2e4a143a0783d4657684e035R4-R5)
    [[7]](diffhunk://#diff-05c926d7e09179d91c9c54a68c6b5efffb854bfddb70b431df77d6b2d280c44dR94-R108)
    [[8]](diffhunk://#diff-05c926d7e09179d91c9c54a68c6b5efffb854bfddb70b431df77d6b2d280c44dR136-R141)
    [[9]](diffhunk://#diff-05c926d7e09179d91c9c54a68c6b5efffb854bfddb70b431df77d6b2d280c44dR151-R156)
    [[10]](diffhunk://#diff-05c926d7e09179d91c9c54a68c6b5efffb854bfddb70b431df77d6b2d280c44dR249-R263)

    **API and Serialization Adjustments**

    * Updated JSON serialization/deserialization logic in
    `Activity.JsonConverter` to handle the obsolete
    `EndOfConversationActivity` while suppressing warnings.
    [[1]](diffhunk://#diff-920cb13ff64033134157a73545c9d9090b7704c37e6ec43f830a7de9decd1282R67-R69)
    [[2]](diffhunk://#diff-920cb13ff64033134157a73545c9d9090b7704c37e6ec43f830a7de9decd1282R125-R131)

    * Added a new `Type` property to the `Account` class to indicate account
    type (e.g., 'person', 'bot', 'channel'), primarily for mention entities.

    **Removal of Deprecated Usage in App Code**

    * Removed usage of deprecated fields (`Role`, `IsGroup`, `Bot`,
    `InputHint`, `RelatesTo`) from application-level code in `App.cs`,
    `FunctionContext.cs`, and `Context.SignIn.cs` to prepare for future
    removals and ensure cleaner API usage.
    [[1]](diffhunk://#diff-37dcc8bb9c3f222673c45d1b99f581b4018f0aa2f92b91892c34a8d26c09f480L198)
    [[2]](diffhunk://#diff-038090b4dce958c0e716f21cba9d4e6fc1cf9e6beb8a8ddee6f70b0b6a5e284cL77-L89)
    [[3]](diffhunk://#diff-e07011b4e8cd0d4623a33ceab9466457358d5c9dac2d863185cefe919d7a96a0L77)
    [[4]](diffhunk://#diff-e07011b4e8cd0d4623a33ceab9466457358d5c9dac2d863185cefe919d7a96a0L88-L89)
    [[5]](diffhunk://#diff-e07011b4e8cd0d4623a33ceab9466457358d5c9dac2d863185cefe919d7a96a0L104)
    [[6]](diffhunk://#diff-e07011b4e8cd0d4623a33ceab9466457358d5c9dac2d863185cefe919d7a96a0L140-L141)

commit df0d514e94824b583cc9c2d8e51216f0c25bba75
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Thu May 21 09:02:44 2026 -0700

    Bump version to 2.0.8-preview (#512)
    - Bumps `version.json` from `2.0.7-preview.{height}` to
    `2.0.8-preview.{height}` post-2.0.7 release
    - [ ] Verify next CI build picks up `2.0.8-preview.x` version

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

    ---------

    Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
    Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
    Co-authored-by: singhk97 <115390646+singhk97@users.noreply.github.com>

commit 84d0348d3c3d29df4d4de0b7229bd690a8a52e8f
Author: Mehak Bindra <mhk0397@gmail.com>
Date:   Thu May 21 07:19:48 2026 -0700

    A2A Sample (#490)

    This pull request introduces a new sample bot, `A2ABot`, which
    demonstrates proactive user handoff between two Teams bots (e.g., Alice
    and Bob) using the A2A protocol and the A2A .NET SDK. The sample is
    fully implemented with configuration, code, and documentation, showing
    how two bots can hand off users to each other and proactively open
    direct conversations in Teams. The main themes of the changes are the
    addition of the A2ABot sample, implementation of A2A protocol logic, and
    comprehensive documentation.

    **Addition of A2ABot sample and project setup:**

    * Added new sample project `A2ABot` to the solution, including its own
    `.csproj` file with dependencies on A2A, Teams SDKs, and Azure OpenAI.
    [[1]](diffhunk://#diff-19ad97af5c1b7109a9c62f830310091f393489def210b9ec1ffce152b8bf958cR13)
    [[2]](diffhunk://#diff-3db91520bb40fce7b5a3be0d4c62ca24c6f2c65980dc6270e9f2876f271beadfR1-R26)
    * Created environment-specific configuration files (e.g.,
    `appsettings.Alice.json`) for easy setup of multiple bot instances.

    **A2A protocol logic and Teams integration:**

    * Implemented outbound (`A2AClient.cs`) and inbound (`A2AServer.cs`) A2A
    handlers to support handoff between bots, including resolving peer
    AgentCards, sending and receiving handoff messages, and proactively
    opening 1:1 Teams conversations.
    [[1]](diffhunk://#diff-9d41f72056b2baf435a7454dcb006e5079e51414f2c17167cb88f8ce859b3649R1-R55)
    [[2]](diffhunk://#diff-1adf74a85a4cdc7172918b6c49c3e19594d1a6058f791bf63b7059d14a7547bdR1-R85)
    * Defined supporting types for A2A communication, such as `Config`,
    `HandoffMessage`, and `AgentCardFactory`.
    [[1]](diffhunk://#diff-6a29af170dfac36c617e5eab5d4d828a3c9734a8d4407b866aa08d770dca9c15R1-R13)
    [[2]](diffhunk://#diff-a6b8eb57329120a115be51c84a807c254a33cbc1116de05a07a7fa004961547cR1-R16)
    [[3]](diffhunk://#diff-405b712de415edd4ec33453a35f45254041503815277db27d9569875575939d2R1-R38)
    * Implemented the main agent logic (`Agent.cs`), including LLM
    integration, thread management, and tool for handing off users to peers.
    * Set up the ASP.NET Core entry point (`Program.cs`) to wire up the bot,
    A2A endpoints, Teams message handling, and configuration.

    **Documentation:**

    * Added a comprehensive `README.md` explaining the sample's
    architecture, flow, configuration, prerequisites, and caveats for
    running two bots that hand off users via A2A.

commit 61b00815cba5bafba022d8beb032c8c3be91e90b
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Wed May 20 16:28:42 2026 -0700

    Prompt Preview Support (core) follow-up: string overload + JsonContext (#506)

    Two small fixes responding to Copilot's post-merge review on #498, plus
    sample alignment with the public slash-commands spec.

    - **`Context.SendActivityAsync(string text, ...)` now routes through
    `SendActivityAsync(TeamsActivity, ...)`.** Previously the string
    overload built the reply directly and called
    `TeamsBotApplication.SendActivityAsync` itself, bypassing the typed
    overload's 1:1-chat guard and the reactive Prompt Preview auto-populate
    hook. The string overload now also preserves `TextFormat =
    TextFormats.Plain` so the wire payload doesn't silently flip to markdown
    for existing callers.
    - **`TargetedMessageInfoEntity` is registered in
    `TeamsActivityJsonContext`** alongside `QuotedReplyEntity`.
    Deserialization round-tripped today via reflection fallback, but the
    registration was missing and would have broken under Native AOT publish.
    - New tests in `PromptPreviewTests.cs` cover the string-overload paths;
    new `TargetedMessageInfoEntity_RoundTripsThroughSourceGenContext` in
    `TargetedMessageInfoEntityTests.cs` pins the JsonContext registration so
    a future removal would surface immediately.
    - **`TargetedMessages` sample improvements**:
    - New `manifest.json` opted into slash commands per the docs spec
    (microsoft/teams-sdk#2843, MicrosoftDocs/msteams-docs#14182):
    `bots[].supportsTargetedMessages: true` +
    `bots[].commandLists[].triggers: ["slash"]`. Uses `manifestVersion:
    "devPreview"` because those fields are only in the devPreview schema
    today.
    - New `README.md` documenting the commands, manifest configuration, and
    how slash commands surface as targeted-message activities.
    - New `test inbound` handler demonstrates
    `Activity.Recipient?.IsTargeted` inbound detection (the same signal
    slash commands arrive with).

    - [x] `dotnet build core.slnx` clean on net8.0 and net10.0
    - [x] `dotnet test core.slnx` passes (358 tests: 216 Apps + 101 Core +
    41 BotBuilder)
    - [x]
    `SendActivityAsync_StringOverload_AutoPopulatesTargetedMessageInfo_WhenInboundIsTargeted`
    exercises the auto-populate hook on the string overload path
    - [x] `SendActivityAsync_StringOverload_Succeeds_InPersonalChat`
    documents that the string overload cannot construct a targeted recipient
    and therefore can't trip the 1:1 guard
    - [x] `TargetedMessageInfoEntity_RoundTripsThroughSourceGenContext`
    exercises `TeamsActivityJsonContext.Default.TargetedMessageInfoEntity`
    (Native AOT regression guard)
    - [x] `TargetedMessages` sample `manifest.json` validates against the
    Teams devPreview schema (placeholder `YOUR_BOT_ID` excepted, matching
    peer-sample convention)
    - [x] Sample bot's `test inbound` handler verified live in Teams:
    broadcast branch fires when the inbound is not targeted (the targeted
    branch will fire once slash commands start delivering with
    `Recipient.IsTargeted = true`)

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

    ---------

    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit f663f43fac7c8794b658d4d984c82d33a9f56bf9
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Wed May 20 23:16:23 2026 +0000

    Bump ghcr.io/devcontainers/features/docker-in-docker from 2.17.0 to 3.0.0 (#516)

    Bumps ghcr.io/devcontainers/features/docker-in-docker from 2.17.0 to
    3.0.0.

    [![Dependabot compatibility
    score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ghcr.io/devcontainers/features/docker-in-docker&package-manager=devcontainers&previous-version=2.17.0&new-version=3.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

    Dependabot will resolve any conflicts with this PR as long as you don't
    alter it yourself. You can also trigger a rebase manually by commenting
    `@dependabot rebase`.

    [//]: # (dependabot-automerge-start)
    [//]: # (dependabot-automerge-end)

    ---

    <details>
    <summary>Dependabot commands and options</summary>
    <br />

    You can trigger Dependabot actions by commenting on this PR:
    - `@dependabot rebase` will rebase this PR
    - `@dependabot recreate` will recreate this PR, overwriting any edits
    that have been made to it
    - `@dependabot show <dependency name> ignore conditions` will show all
    of the ignore conditions of the specified dependency
    - `@dependabot ignore this major version` will close this PR and stop
    Dependabot creating any more for this major version (unless you reopen
    the PR or upgrade to it yourself)
    - `@dependabot ignore this minor version` will close this PR and stop
    Dependabot creating any more for this minor version (unless you reopen
    the PR or upgrade to it yourself)
    - `@dependabot ignore this dependency` will close this PR and stop
    Dependabot creating any more for this dependency (unless you reopen the
    PR or upgrade to it yourself)

    </details>

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
    Co-authored-by: Rido <rido-min@users.noreply.github.com>

commit 5893bff7cbc39c507d9461303a15d6c6d0dd3ccc
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Wed May 20 15:59:05 2026 -0700

    core: add sovereign cloud support via AzureAd configuration (#507)

    Enables sovereign cloud (GCC-High, DoD, China) Bot Framework token
    validation by making the three cloud-dependent values in `JwtExtensions`
    configurable, mirroring the `IConfiguration` pattern already used by
    `UserTokenClient`.

    Three new properties on `BotConfig`, populated by `BotConfig.Resolve`:

    | Property | Config key | Default | Purpose |
    |---|---|---|---|
    | `EntraInstance` | `AzureAd:Instance` |
    `https://login.microsoftonline.com/` | Entra login instance for
    validating Entra-issued tokens (standard Microsoft.Identity.Web key,
    stays in the AzureAd section) |
    | `OpenIdMetadataUrl` | `BotFramework:OpenIdMetadataUrl` |
    `https://login.botframework.com/v1/.well-known/openid-configuration` |
    Bot Framework OIDC metadata endpoint used to fetch signing keys for
    inbound BF tokens |
    | `BotTokenIssuer` | `BotFramework:BotTokenIssuer` |
    `https://api.botframework.com` | Expected `iss` claim on inbound Bot
    Framework tokens |

    Bot-Framework-specific keys live in a separate `BotFramework`
    configuration section so they are not conflated with MSAL's `AzureAd`
    section. `Instance` remains under `AzureAd` because it is a standard
    Microsoft.Identity.Web key.

    Each override is validated as an absolute URI in `BotConfig.Resolve`;
    malformed values throw `InvalidOperationException` with the
    `section:key` path so misconfiguration fails fast instead of deferring
    to a runtime JWT failure.

    `JwtExtensions.AddTeamsJwtBearer` resolves `BotConfig` once and uses
    these values in both the issuer-signing-key resolver
    (`ResolveSigningAuthority`) and the issuer validator
    (`ValidateTeamsIssuer`). When `IConfiguration` is not registered
    (manual-credentials callers on a plain `ServiceCollection`), all three
    fall back to the public-cloud defaults.

    ```json
    {
      "AzureAd": {
        "TenantId": "...",
        "ClientId": "...",
        "Instance": "https://login.microsoftonline.us/"
      },
      "BotFramework": {
        "OpenIdMetadataUrl": "https://login.botframework.azure.us/v1/.well-known/openid-configuration",
        "BotTokenIssuer": "https://api.botframework.us"
      }
    }
    ```

    - `Authority` fallback for `EntraInstance` is intentionally not
    implemented. `Instance` is the canonical Microsoft.Identity.Web field
    and matches the keys Microsoft Learn uses for sovereign cloud
    configuration.
    - `BotConfig` source formats other than the `AzureAd` schema are not
    extended in this PR.
    - v1.0 `sts.windows.net` issuer validation remains accepted (covers
    commercial v1.0 tokens).

    - [x] `dotnet build core/core.slnx` clean (0 warnings, 0 errors)
    - [x] `dotnet test core/test/Microsoft.Teams.Core.UnitTests` (130
    passed)
    - [x] Default values returned when overrides absent
    - [x] Configured values used for sovereign US Gov and China clouds
    - [x] Sovereign BF tokens route to the configured `OpenIdMetadataUrl`
    for key resolution
    - [x] Malformed URI in any of the three keys throws
    `InvalidOperationException` with the section:key path
    - [x] BotFramework section is read independently of the AzureAd section
    name
    - [x] Manual `AddBotAuthentication(clientId, tenantId)` overload does
    not require `IConfiguration`

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

    ---------

    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
    Co-authored-by: Rido <rido-min@users.noreply.github.com>

commit 1b83226b8b32bbf6bbede21afbc0fd5fb6808c55
Author: Mehak Bindra <mhk0397@gmail.com>
Date:   Wed May 20 14:14:23 2026 -0700

    Core/activity extensions (#515)

    This pull request primarily refactors and streamlines how activity
    entity extension methods are organized, accessed, and documented in the
    Teams SDK core. It consolidates and migrates extension methods for
    activities (such as quoting, citations, and targeted messages), updates
    the migration guides and breaking change documentation, and removes the
    obsolete `AllFeatures` sample. The changes also update sample usage to
    use the new builder and extension method patterns, and introduce new
    helper methods for entity access.

    **Refactoring and consolidation of activity entity extension methods:**

    * Removed `ActivityQuotedReplyExtensions.cs` and
    `ActivityTargetedMessageInfoExtensions.cs`, moving their logic into more
    appropriately named and organized extension classes (such as
    `MentionEntityExtensions`, `CitationEntityExtensions`, etc.), and
    updated usages throughout the codebase.
    [[1]](diffhunk://#diff-5b565cdafa365671ca7c917fabad6d126f7f290e010481b7e2b6404cd74a4cadL1-L82)
    [[2]](diffhunk://#diff-8bbc57126c4f493e1eac6296888b0b3df8441d36ad8d1784c63d339cdc742554L1-L66)
    [[3]](diffhunk://#diff-39b57f845e0f83ee2c8d332d8785f93c92128500aa0492ccc442916c8f0db84eR1-R55)
    [[4]](diffhunk://#diff-22cd31a51c97a37f8bf2cffb4c061f52cb71d0755523954f59cef55883c7d1ebL204-R204)
    * Introduced new extension methods and helpers for accessing entities
    (e.g., `GetMentions`, `GetQuotedMessages`, `GetCitation`, etc.) and
    updated documentation to reflect these changes.
    [[1]](diffhunk://#diff-8239e4655133747a84cff44bc0444f20907380d344b35e512d70a603ce1a3f8cL180-R198)
    [[2]](diffhunk://#diff-39b57f845e0f83ee2c8d332d8785f93c92128500aa0492ccc442916c8f0db84eR1-R55)

    **Sample and usage updates:**

    * Updated all sample code (`Quoting`, `TeamsBot`) to use the new builder
    pattern and extension methods for adding quotes and citations, replacing
    old direct usage of message entities.
    [[1]](diffhunk://#diff-bd68ef7114703a580af98ae0c650b648dd74909fea6665395b98516956157448L48-R57)
    [[2]](diffhunk://#diff-bd68ef7114703a580af98ae0c650b648dd74909fea6665395b98516956157448L69-R77)
    [[3]](diffhunk://#diff-bd68ef7114703a580af98ae0c650b648dd74909fea6665395b98516956157448L102)
    [[4]](diffhunk://#diff-691809f7a90c5bda6ee5e4335c2c393864a32101545fb0b35c24bc659623361bL113-R132)
    * Removed the obsolete `AllFeatures` sample project and its related
    files.
    [[1]](diffhunk://#diff-c6d02c3a9a28c1afb6380d7f24485630894a3488bd6529f31cca342583be4897L1-L13)
    [[2]](diffhunk://#diff-7c963be5ba9074d831ef650e68af0360787eb197181c39a12d0661a92c62fbc1L1-L6)
    [[3]](diffhunk://#diff-166193a2c938377ccf1794248deeb2df8cfafeb883aa6581b316b3fa9e361cdcL1-L28)
    [[4]](diffhunk://#diff-ea0a609f6688222857d8302f64ba6a7d75aa4ffb1f9a70588b86caacd73dbad1L1-L9)

    **Documentation improvements:**

    * Updated the migration guide and breaking changes documentation to
    clarify the new patterns for activity entity access and construction,
    including extension method availability and builder usage.
    [[1]](diffhunk://#diff-8239e4655133747a84cff44bc0444f20907380d344b35e512d70a603ce1a3f8cL180-R198)
    [[2]](diffhunk://#diff-8239e4655133747a84cff44bc0444f20907380d344b35e512d70a603ce1a3f8cL266-R300)
    [[3]](diffhunk://#diff-54d546db32e8cde5d5c68b70319c4c57859aaae3b11df4da4b699d389c153644L396-R418)

    **Project and solution cleanup:**

    * Removed the `docs/Architecture.md` file from the solution, likely as
    part of documentation consolidation.

commit 731d4bbf10324dc766a35201fd07dd32524e8a7a
Author: Kavin <115390646+singhk97@users.noreply.github.com>
Date:   Fri May 15 15:02:17 2026 -0400

    Make core packages compliant with Microsoft NuGet authoring requirements (#513)
    - Brings the three core packages (`Microsoft.Teams.Core`,
    `Microsoft.Teams.Apps`, `Microsoft.Teams.Apps.BotBuilder`) into
    compliance with the Microsoft NuGet package authoring requirements.
    - Adds `PackageProjectUrl`, fixes a broken `PackageIcon` packing path in
    `core/src/Directory.Build.props`, renames `Description` →
    `PackageDescription`, adds `PackageTags`, and adds MIT license/copyright
    header comments to each csproj.
    - Also bumps `versionHeightOffset` in `core/version.json` and
    `core/src/Microsoft.Teams.Apps/version.json`.
    | Requirement | Before | After |
    | --- | --- | --- |
    | `PackageProjectUrl` | missing |
    `https://microsoft.github.io/teams-sdk` |
    | `PackageIcon` packing | broken path
    (`(MSBuildThisFileDirectory)../../../../bot_icon.png`) |
    `$(MSBuildThisFileDirectory)../bot_icon.png` |
    | `PackageDescription` | used `Description` | `PackageDescription` |
    | `PackageTags` | missing |
    `microsoft;teams;msteams;copilot;ai;adaptive-cards;apps;bots` |
    | License header | missing | MIT header comment in each csproj |
    - `core/bot_icon.png` is 75x75; the authoring spec recommends 100x100
    (with clean downscaling to 32/48/64/128).
    - Strong-name signing (`SignAssembly` + `key.snk`) — not adopted in core
    yet, matches existing core stance.
    - [ ] `dotnet pack` the three core projects locally and inspect the
    produced `.nupkg` to confirm `bot_icon.png` and `README.md` are packed
    at the root and the metadata fields render correctly.
    - [ ] Verify the icon shows up on the nuget.org preview / `nuget.exe
    verify` step in CI.
    - [ ] CI build passes on the branch.

    ---------

    Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

commit 1ed9636ef8bc1a6a74e3de106baeaabde09cee24
Author: Mehak Bindra <mhk0397@gmail.com>
Date:   Fri May 15 11:14:14 2026 -0700

    Add AI/MCP Client example (#486)

    This pull request introduces a new sample Teams bot, `ExtAIBot`, that
    demonstrates the integration of Microsoft.Extensions.AI with Azure
    OpenAI and the Model Context Protocol (MCP) for advanced conversational
    capabilities. The main changes include the implementation of the bot’s
    core logic, support for streaming responses, per-conversation memory,
    local and remote tool invocation, and feedback handling. Additionally,
    supporting infrastructure and documentation are provided.

    **Key new features and infrastructure:**

    * Added the complete `ExtAIBot` sample including core files: `Agent.cs`
    (conversation logic with streaming, memory, and tool invocation),
    `LocalTools.cs` (local AI tool definitions), `McpTools.cs` (MCP client
    and tool wrapping for citations), and `CitationCollector.cs` (parsing
    and accumulating citations for Teams messages).
    * Implemented `Program.cs` to wire up the Teams bot, register message
    and feedback handlers, and delegate AI execution to the `Agent`.

    * Added support for Teams feedback via new invoke names and value types,
    including `message/fetchTask` and associated data classes in the Teams
    SDK.
    * Implemented feedback collection and UI in the sample bot, including
    Adaptive Card generation for feedback and console logging of user input.

    * Added `appsettings.json` and updated the project file to include all
    necessary dependencies and references for running the sample.
    * Provided a comprehensive `README.md` with setup instructions,
    architecture diagrams, and example interactions to help users understand
    and run the sample.

commit a987b1453c73b9554de50e4e1a9452f14192dc40
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Thu May 14 13:51:26 2026 -0700

    Mark reactions API as GA across Libraries and core (#509)

    Removes the `[Experimental("ExperimentalTeamsReactions")]` attributes
    from `ReactionClient`, `ReactionType`, `Reaction`, and the `Reactions`
    property on `ConversationApiClient`/`ConversationClient`, across both
    `Libraries/` and `core/`. Also removes the corresponding `#pragma
    warning disable/restore` blocks and `NoWarn` entries in test and sample
    `.csproj` files.

    The reactions feature is in sync across all three SDKs and the Teams
    service — no longer preview.

    **Attributes removed (5):**
    - `Libraries/Microsoft.Teams.Api/Clients/ReactionClient.cs`
    - `Libraries/Microsoft.Teams.Api/Messages/Reaction.cs` (`ReactionType`
    and `Reaction`)
    - `core/src/Microsoft.Teams.Apps/Api/Clients/ReactionClient.cs`
    - `core/src/Microsoft.Teams.Apps/Api/Clients/ConversationApiClient.cs`
    (`Reactions` property)

    **Suppressions removed (8 inline pragma locations + 5 NoWarn entries in
    .csproj files):**
    - `Libraries/Microsoft.Teams.Api/Clients/ConversationClient.cs` (5
    sites)
    - `Libraries/Microsoft.Teams.Api/Messages/Message.cs`
    -
    `Libraries/Microsoft.Teams.Api/Activities/Message/MessageReactionActivity.cs`
    (file-level)
    - `core/src/Microsoft.Teams.Apps/Api/Clients/ConversationApiClient.cs`
    - `.csproj` NoWarn: `Samples/Samples.Reactions`,
    `core/test/IntegrationTests`, `core/samples/TeamsBot`,
    `Tests/Microsoft.Teams.Api.Tests`, `Tests/Microsoft.Teams.Apps.Tests`

    The `Samples.Reactions/Program.cs` already demonstrates add → wait →
    delete cycle, so no sample change is needed here.

    Part of the cross-SDK Reactions-GA pass. Sibling PRs:
    - microsoft/teams.ts — Mark reactions API as GA
    - microsoft/teams.py — Mark reactions API as GA
    - microsoft/teams-sdk — drop .NET opt-in tip from the reactions guide

    - [x] `dotnet build Microsoft.Teams.sln --configuration Release` — 0
    errors
    - [x] `dotnet build core.slnx --configuration Release` — 0 errors
    - [x] `dotnet test Microsoft.Teams.sln` — all suites pass (Apps 146+146,
    Api 422, Common 63, AI 17, Graph 3, McpClient 9, AspNetCore 25+25
    net8/net10)
    - [x] `dotnet test core.slnx` — all suites pass (Apps.UnitTests 213+213,
    Core.UnitTests 101+101, BotBuilder.UnitTests 41)

    No `version.json` change in this PR. Bump happens as part of the release
    flow per RELEASE.md.

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

commit 475b11ff9640147b4b19450ae952388cef6f6176
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Wed May 13 12:47:34 2026 -0700

    Prompt Preview Support (core) (#498)

    Prompt Preview lets a bot reference the original targeted message in its
    reply so Teams can render a collapsible preview of the user's prompt
    above the response. This brings the feature to `core/` with parity to
    the Libraries implementation in #433.

    - New `TargetedMessageInfoEntity` in
    `Microsoft.Teams.Apps.Schema.Entities` carrying the `messageId` of the
    targeted prompt
    - `AddTargetedMessageInfo` extension on `MessageActivity` and
    `WithTargetedMessageInfo` on `TeamsActivityBuilder` for proactive use.
    Both strip existing `quotedReply` entities and matching `<quoted
    messageId="..."/>` placeholders to prevent collision with Quoted Replies
    - `Context.SendActivityAsync` auto-populates the entity in the reactive
    flow when the inbound activity's recipient was marked targeted
    - Personal-chat guard in `Context.SendActivityAsync` throws
    `InvalidOperationException` when a targeted send is attempted in a 1:1
    conversation (matches Libraries; teams.ts and teams.py have no guard)
    - `ConversationAccount.IsTargeted`, `WithRecipient(account, bool
    isTargeted)`, the new entity, and the new builder/extension methods are
    marked `[Experimental("ExperimentalTeamsTargeted")]`, matching the
    existing diagnostic on `ActivityClient.CreateTargetedAsync` etc.
    - New `TargetedMessages` sample bot demonstrating `test send`, `test
    update`, `test delete`, reactive `summarize`, and `test manual`

    - Setter on `ConversationAccount.IsTargeted` stays `public set` (not
    mirroring the Libraries `internal set` outlier) to match the uniform
    setter pattern across `core/` schema types.
    - The `MessageId` getter on `TargetedMessageInfoEntity` throws
    `InvalidOperationException` with a descriptive message if accessed after
    deserialization from JSON that omitted the `messageId` field. `required`
    enforces initialization in C# code but does not gate the underlying
    extension-properties dictionary path.

    - [x] `dotnet build` in `core/` is clean on net8.0 and net10.0
    - [x] `dotnet test` in `core/` passes (340 unit tests: 207 Apps + 92
    Core + 41 BotBuilder)
    - [x] Run the new `TargetedMessages` sample and confirm `test send` /
    `test update` / `test delete` render correctly in a Teams group chat
    - [x] Confirm `test send` from a personal chat surfaces the 1:1
    `InvalidOperationException`

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

commit b10c0fef711973fff199283cd9a3f9b9cd17eb78
Author: Kavin <115390646+singhk97@users.noreply.github.com>
Date:   Wed May 13 14:56:28 2026 -0400

    Switch Microsoft.Teams.Apps to 2.1.0-preview; bump core versionHeightOffset to -3 (#504)
    - Change `Microsoft.Teams.Apps` prerelease tag from `alpha` to `preview`
    (`2.1.0-alpha.{height}` → `2.1.0-preview.{height}`) so we move out of
    the burned `2.1.0-alpha-*` version namespace on the feed.
    - Remove the now-unneeded `versionHeightOffset` from
    `core/src/Microsoft.Teams.Apps/version.json` (the prerelease label
    change starts the height counter on a fresh namespace).
    - Bump `versionHeightOffset` from `-2` to `-3` in `core/version.json` to
    keep Core/BotBuilder versions where intended.
    - [x] Verify `nbgv get-version` on `releases/core` after merge produces
    `2.1.0-preview-0001` (or expected) for `Microsoft.Teams.Apps`.
    - [x] Verify Core/BotBuilder package versions are unchanged or as
    intended after the `-3` offset.
    - [x] Verify CI publishes the package successfully (no 409 conflict on
    the new version).

commit 3307d38daa28c1cc8ab30472d519b914e2199590
Author: Corina <14900841+corinagum@users.noreply.github.com>
Date:   Wed May 13 11:41:19 2026 -0700

    Add proactive threading helpers to core (port of #425) (#489)
    - Adds `Microsoft.Teams.Core.Schema.ConversationExtensions` with a
    `ThreadId(this Conversation)` extension method and a
    `ToThreadedConversationId(conversationId, messageId)` static validator
    (rejects non-numeric / zero `messageId`, strips any existing
    `;messageid=` suffix). Ported from
    `Libraries/Microsoft.Teams.Api/Conversation.cs`, where they live as
    instance/static members on `Conversation`; on core they live as a
    separate extension class so `Conversation` stays a pure POCO.
    - Replaces the inline `$"{conversationId};messageid={messageId}"`
    interpolation in proactive `TeamsBotApplication.ReplyAsync` with the
    validating helper.
    - Adds `core/samples/Threading/` modeled on `Samples/Samples.Threading/`
    to exercise reactive (`context.ReplyAsync` /
    `context.SendActivityAsync`) and proactive (`teamsApp.ReplyAsync` /
    `ConversationExtensions.ToThreadedConversationId` +
    `teamsApp.SendAsync`) paths.
    - Includes #493 (Rido), stacked on this PR: adds `Async`-suffixed
    methods to `Context` (`SendAsync`, `ReplyAsync`, `TypingAsync`,
    `SignInAsync`, `SignOutAsync`) and `TeamsBotApplication` (`SendAsync`,
    `ReplyAsync`) with the original names kept as backward-compat redirects;
    proactive `Send`/`Reply` accept an optional `AgenticIdentity?` for
    user-delegated token acquisition.
    - **`Context.ReplyAsync`** inherits the post-QR (PR #477) behavior on
    `main`: delegates to `Quote(Activity.Id, ...)` when the inbound activity
    has an id, producing a `<blockquote>`-rendered quoted reply. This PR
    doesn't change that delegation.
    - **Personal / 1:1 chats**: `test proactive` and `test manual` currently
    fail at the service with `BadArgument: Failed to decrypt conversation
    id` until the relevant ECS rollout completes. Channel scopes work today.
    `core/samples/Threading/README.md` documents this caveat.
    - [x] Unit: 12 `ConversationTests` (validator + `ThreadId` extension
    method)
    - [x] Unit: 3 `TeamsBotApplicationTests` (validator propagates from
    proactive `ReplyAsync`)
    - [x] Local CI: core-ci pipeline (325 tests on net8.0 + net10.0) + root
    build-test-lint / ci.yaml (813 tests + `dotnet pack`); 0 errors
    - [x] E2E in Teams: 6 turns covering `test reply`, `test send`, `test
    proactive`, `test manual`, `help` across an existing thread, a new
    thread, and channel root — all returned 201 with correct routing
    (`;messageid=<rootId>` preserved/created appropriately, `ReplyToId` set
    on reactive paths only)

    🤖 Generated with [Claude Code](https://claude.com/claude-code)

    ---------

    Co-authored-by: Rido <rido-min@users.noreply.github.com>
    Co-authored-by: Claude Opu…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

5 participants