Repository navigation
feat(apps): add Socket Mode to TeamsBotApplication - #686
Merged
teddy arida-moody (teddyam) merged 49 commits intoOct 1, 2026
Merged
Conversation
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Refactor OnActivity to await readiness before handling activity. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Adds an internal GeoSocket that keeps one geo connected: initial startup within a monotonic budget, Retry-After/backoff retries, reconnect after unexpected closure, and make-before-break token rotation with a retiring handoff window. Dispatch is fenced to the active or retiring generation, and every connection is stopped and disposed exactly once. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Resolve per-geo negotiate endpoints, start every geo with fail-fast startup, stop all geos, aggregate status internally, and dispatch envelopes with invoke/ack replies and 500 on handler failure. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Adds an internal GeoSocket that keeps one geo connected: initial startup within a monotonic budget, Retry-After/backoff retries, reconnect after unexpected closure, and make-before-break token rotation with a retiring handoff window. Dispatch is fenced to the active or retiring generation, and every connection is stopped and disposed exactly once. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Resolve per-geo negotiate endpoints, start every geo with fail-fast startup, stop all geos, aggregate status internally, and dispatch envelopes with invoke/ack replies and 500 on handler failure. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…om/microsoft/teams.net into teddyam-socket-mode-geo-supervisor
Log connection stop/dispose failures instead of throwing so they cannot mask the original startup failure or end a geo's supervisor, and mark every geo as Stopped when the transport stops. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
A faulted supervisor is already logged; rethrowing it from stop could mask the original startup failure in the transport. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…om/microsoft/teams.net into teddyam-socket-mode-geo-supervisor
The bot pipeline already logs handler failures before wrapping them in BotHandlerException, so the transport now only logs failures the pipeline has not logged. It still replies 500 in both cases. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Echo bot that receives activities over Socket Mode on a generic host with no web server, using UseSocketMode() and UseTeamsSocketApplication(). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…file in sample Development enables service validation on build, which failed on a generic host because Core's authorization services need routing that only a web app registers. AddSocketMode now registers routing. SocketModeBot now takes credentials from a launchSettings.json copied from a template, like the other samples, setting DOTNET_ENVIRONMENT because a generic host doesn't read ASPNETCORE_ENVIRONMENT. Also ignore launchSettings.json on case-sensitive filesystems. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Socket Mode negotiate is only available on canary for now; production returns 503. Matches the TS and Python samples' override. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ration test and docs - Negotiate 401/403 is non-retryable with actionable messages: startup fails immediately, and a rejected reconnect or rotation stops that geo (including a connection still serving) and reports it disconnected. Other geos and other failures are unaffected. Matches microsoft/teams.ts#875 and teams.py. - Add a generic-host test that sends a message over the socket and asserts the reply is posted through the conversation API. - Document Socket Mode in the Apps README and list SocketModeBot in samples. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
teddy arida-moody (teddyam)
added this pull request to stack #684
September 28, 2026 23:59
|
Azure Pipelines: There may be pipelines that require an authorized user to comment /azp run to run. |
Replace UseTeamsSocketApplication with a socket flag on UseTeamsBotApplication so the entry point no longer differs by transport. The flag must match UseSocketMode(); a mismatch throws. A WebApplication overload keeps existing calls unambiguous. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot started reviewing on behalf of
teddy arida-moody (teddyam)
September 29, 2026 00:11
View session
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
The promised hosting API is absent, and Socket Mode currently discards envelope correlation vectors.
Review effort: Balanced
Findings: 2
Open (2)
What changed in this PR
Adds Socket Mode integration for receiving Teams activities through outbound WebSocket connections on a headless generic host.
Changes:
- Adds Socket Mode options, hosting, dispatch, and lifecycle handling.
- Adds transport-neutral activity processing and invoke-response capture.
- Adds extensive tests, documentation, and a sample bot.
| File | Description |
|---|---|
.gitignore |
Ignores correctly cased launch settings. |
Microsoft.Teams.slnx |
Adds the Socket Mode sample. |
README.md |
Lists the new sample. |
samples/SocketModeBot/Program.cs |
Implements the echo bot. |
samples/SocketModeBot/README.md |
Documents sample setup and use. |
samples/SocketModeBot/SocketModeBot.csproj |
Defines the sample project. |
samples/SocketModeBot/appsettings.json |
Configures sample logging. |
samples/SocketModeBot/Properties/launchSettings.TEMPLATE.json |
Provides credential placeholders. |
src/Microsoft.Teams.Apps/README.md |
Documents Socket Mode. |
src/Microsoft.Teams.Apps/TeamsBotApplication.cs |
Captures invoke responses for non-HTTP transports. |
src/Microsoft.Teams.Apps/TeamsBotApplication.HostingExtensions.cs |
Registers and selects hosting transports. |
src/Microsoft.Teams.Apps/TeamsBotApplicationOptions.cs |
Adds Socket Mode configuration. |
src/Microsoft.Teams.Apps/SocketMode/GeoSocket.cs |
Handles terminal authorization failures. |
src/Microsoft.Teams.Apps/SocketMode/SocketModeHostedService.cs |
Manages transport lifetime. |
src/Microsoft.Teams.Apps/SocketMode/SocketModeNegotiator.cs |
Classifies authorization failures. |
src/Microsoft.Teams.Apps/SocketMode/SocketModeOptions.cs |
Defines public options. |
src/Microsoft.Teams.Apps/SocketMode/SocketModeProtocol.cs |
Uses the canary endpoint. |
src/Microsoft.Teams.Apps/SocketMode/SocketModeServiceRegistration.cs |
Wires Socket Mode into DI. |
src/Microsoft.Teams.Apps/SocketMode/SocketModeTransport.cs |
Integrates dispatch error handling. |
src/Microsoft.Teams.Core/BotApplication.cs |
Adds transport-neutral processing. |
test/Microsoft.Teams.Core.UnitTests/BotApplicationTests.cs |
Tests the new processing overload. |
test/Microsoft.Teams.Apps.UnitTests/TeamsBotApplicationTests.cs |
Tests invoke-response capture. |
test/Microsoft.Teams.Apps.UnitTests/SocketMode/GeoSocketTests.cs |
Tests terminal authorization failures. |
test/Microsoft.Teams.Apps.UnitTests/SocketMode/SocketModeEndToEndTests.cs |
Updates endpoint expectations. |
test/Microsoft.Teams.Apps.UnitTests/SocketMode/SocketModeHostingTests.cs |
Tests hosting and end-to-end dispatch. |
test/Microsoft.Teams.Apps.UnitTests/SocketMode/SocketModeNegotiatorTests.cs |
Tests authorization classification. |
test/Microsoft.Teams.Apps.UnitTests/SocketMode/SocketModeOptionsTests.cs |
Tests public options. |
test/Microsoft.Teams.Apps.UnitTests/SocketMode/SocketModeTransportTests.cs |
Tests dispatch logging and defaults. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Revert the SDK default to https://botapi.skype.com to match TS and Python. The SocketModeBot sample sets NegotiateBaseUrl to the canary ring, where Socket Mode is available today. Also mark the sample non-packable so CI's pack step does not try to publish it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove the socket flag from UseTeamsBotApplication. The transport is now chosen only by UseSocketMode in AddTeamsBotApplication, and UseTeamsBotApplication() is the same call for HTTP and Socket Mode. The WebApplication overloads keep the same parameters as main and exist only so a WebApplication binds unambiguously. UseSocketMode gains a bool overload, matching TS/Python's boolean | SocketModeOptions: UseSocketMode() or UseSocketMode(true) enables it with defaults, UseSocketMode(false) clears earlier configuration, and UseSocketMode(configure) enables it with custom settings. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Mark SocketModeOptions and UseSocketMode with
[Experimental("ExperimentalTeamsSocketMode")], matching TS's
@experimental and the repo's ExperimentalTeams<Feature> convention.
The SDK's own internal references suppress the diagnostic; the sample
and unit tests opt in with NoWarn, and the docs explain how to.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
added 4 commits
October 1, 2026 10:24
…or' into teddyam-socket-mode-app-integration
…or' into teddyam-socket-mode-app-integration
Lily Du (lilyydu)
approved these changes
Oct 1, 2026
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Lily Du (lilyydu)
approved these changes
Oct 1, 2026
teddy arida-moody (teddyam)
deleted the
teddyam-socket-mode-app-integration
branch
October 1, 2026 22:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Wires the Socket Mode transport from #682, #683, and #685 into
TeamsBotApplication, so a bot can receive activities over outbound WebSocket connections instead of an HTTP messaging endpoint. Brings .NET to parity with microsoft/teams.ts#716, microsoft/teams.ts#743, microsoft/teams.ts#875, and microsoft/teams.py#608.Stacked on #685.
Usage
Socket Mode is experimental, so callers suppress
ExperimentalTeamsSocketMode(for example,<NoWarn>$(NoWarn);ExperimentalTeamsSocketMode</NoWarn>).Changes
Core
BotApplication.ProcessAsync(CoreActivity, ClaimsPrincipal?, string? correlationVector, CancellationToken)overload that runs the activity pipeline without anHttpContext. The HTTP path now delegates to it.Apps
SocketModeOptions(negotiate URL, geos, startup/readiness timeouts, reconnect delays, keep-alive, server timeout).TeamsBotApplicationOptions.UseSocketModeis the only transport switch, mirroring TS/Python'sboolean | SocketModeOptions:UseSocketMode()orUseSocketMode(true)enables it with defaults.UseSocketMode(false)clears any earlier Socket Mode configuration, so the bot uses HTTP.UseSocketMode(s => ...)enables it with custom settings.SocketModeOptionsandUseSocketModeare marked[Experimental("ExperimentalTeamsSocketMode")], matching TS's@experimentaland the repo'sExperimentalTeams<Feature>convention.UseTeamsBotApplication()is the same call for both transports and reads the choice fromUseSocketMode. Socket Mode runs on a generic host with no web server:UseTeamsBotApplication(this IHost)overloads for a generic host.UseTeamsBotApplication(this WebApplication, string routePath)overloads with the same parameters as the existingIEndpointRouteBuilderoverloads. They exist only becauseWebApplicationis both anIHostand anIEndpointRouteBuilder, which would otherwise make existing HTTP calls ambiguous.WebApplicationthrows, and a host that includes a web server fails to start. HTTP on a generic host throws.amer,emea,apacby default) and blocks startup until all are ready.Samples and docs
samples/SocketModeBot: a quoted echo reply, with credentials supplied throughlaunchSettings.TEMPLATE.json.NegotiateBaseUrltohttps://canary.botapi.skype.com.Validation
UseSocketMode(false)), hosting (generic host, the web app rejection, Development DI validation), dispatch, 401/403 handling, and an end-to-end test from a message over the socket to the reply posted to the conversation API.SocketModeBot: all three geos connected and the bot replied.