Fix async anti-patterns across all library projects#402
Conversation
…, 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>
There was a problem hiding this comment.
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
CancellationTokenthrough multiple call chains and updates theIChatPluginhook 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.
- 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>
There was a problem hiding this comment.
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
OnChunkswallows all exceptions from theonChunkcallback (catch { return; }). Since this is in the send/streaming path, failures become invisible and can leavebufferin a surprising state (it won’t be cleared on exception). At minimum, log or raiseErrorEventwith 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. Iffunc(arg)throws, the exception is captured on the discarded task and becomes unobserved. Also, the priorCancellationTokenSourceis canceled but never disposed, which can leak resources in long-running processes. Wrapfunc(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.
- 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>
There was a problem hiding this comment.
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; iffunc(arg)throws, the continuation will fault and can surface as an unobserved task exception. Wrapfunc(arg)in try/catch (or refactor to anasynccore similar to theFunc<Task>overload) so exceptions are observed/handled deterministically.
Libraries/Microsoft.Teams.AI/Prompts/ChatPrompt/ChatPrompt.Send.cs:65OnChunkswallows all exceptions from the user-providedonChunkcallback and returns without clearingbuffer. IfonChunkthrows once,bufferwill 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.
|
@copilot open a new pull request to apply changes based on the comments in this thread |
…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>
|
@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 All resolved:
Design choice (not a bug):
|
There was a problem hiding this comment.
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.
|
@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>
Resolved the merge conflicts against the latest 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:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@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>
Resolved the merge conflicts by merging 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:
If you need me to access, download, or install something from one of these locations, you can either:
|
… 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
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 />
[](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.
[](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…
Summary
GetAwaiter().GetResult()) by converting to properawaitinApplicationBuilder.Functions,Stream,ChatPrompt.Errors; addConfigureAwait(false)toServiceCollectionDI factoryOpenAIChatModel.Send,Context.Send,HttpClient.SendAsync; add missingCancellationTokenparameter toIChatPlugin.OnBuildInstructionscatch { }blocks with exception logging inApp.cs,Context.SignIn,McpClientPluginFlush()calls inAspNetCorePlugin.StreamviaFlushSafe()wrapper; replaceTask.Run(() => { })withTask.CompletedTask; use_ =discard pattern in debounce extensionsConfigureAwait(false)to ~380awaitcalls across all library projects to prevent deadlocks and unnecessary context captureTask.Runwrapping sync code with direct execution +Task.CompletedTaskinLocalStorage; fix unsafe reflection-basedTask.Resultaccess inMethodInfoExtensionsFixes #396, #397, #398, #399, #400, #401
Test plan
EmitAsyncmethod onIStream🤖 Generated with Claude Code