Repository navigation
feat(apps): integrate socket mode with app (PR 2 of 2) - #608
Conversation
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved lifecycle, endpoint, awaitable-handling, error-reporting, and reconnection findings remain.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 3
Open (3)
What changed in this PR
Adds public Socket Mode support to App, including transport integration, lifecycle handling, tests, and an example application.
Changes:
- Adds
SocketModeAdapterandSocketModeOptions. - Integrates Socket Mode as an alternative inbound transport.
- Adds connection handoff behavior, tests, documentation, and a sample.
Review findings:
- Moderate (2 votes): cancellation may leave transport resources running.
- Moderate (3 votes): non-coroutine awaitables may not be awaited.
- Moderate (2 votes): the default negotiate endpoint is currently unavailable.
- Moderate (1 vote): pipeline errors may be reported twice.
- Moderate (1 vote): reconnect events may be emitted without a delivery gap.
- Nit (1 vote): re-export
SocketModeEventTypefrom the top-level package.
| File | Description |
|---|---|
uv.lock |
Registers the new example workspace. |
packages/apps/tests/test_socket_mode_transport.py |
Tests connection rotation and handoff behavior. |
packages/apps/tests/test_socket_mode_adapter.py |
Tests adapter and App integration. |
packages/apps/src/microsoft_teams/apps/socket_mode/transport.py |
Exposes negotiate URL construction. |
packages/apps/src/microsoft_teams/apps/socket_mode/geo_socket.py |
Supports connection rotation and retirement. |
packages/apps/src/microsoft_teams/apps/socket_mode/adapter.py |
Implements the public adapter and activity handling. |
packages/apps/src/microsoft_teams/apps/socket_mode/__init__.py |
Exports Socket Mode types. |
packages/apps/src/microsoft_teams/apps/options.py |
Adds Socket Mode options. |
packages/apps/src/microsoft_teams/apps/app.py |
Integrates Socket Mode with App. |
packages/apps/src/microsoft_teams/apps/__init__.py |
Re-exports public APIs. |
examples/socket/src/main.py |
Adds a Socket Mode sample app. |
examples/socket/README.md |
Documents the sample. |
examples/socket/pyproject.toml |
Defines sample dependencies. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
7d739ef to
ec6ff13
Compare
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Handle asyncio.CancelledError during transport start. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
|
This is exciting news for our Dataiku DSS Teams integration! Removing the inbound public endpoint/tunnel would simplify both development and deployment. We’re particularly interested in understanding:
|
|
Hey Alex Bitar (@AlxBit) ! We're very glad to hear your team is interested in this feature! As changes are across various backend services, to ensure reliability- we will be shipping this upcoming preview only for development bots. For your knowledge, we currently don't have a firm release date as we are rigorously testing internally. Socket mode will be an alternative inbound delivery path for Teams agents and it will not require a publicly reachable HTTPS endpoint. However, existing outbound activity flows will remain HTTP-based. In terms of multiple instances, each instance connects independently, with its own per-geo connections. |
…nvelope metadata (microsoft#875) Brings TS Socket Mode to parity with microsoft/teams.py#608 (commit `95a0b0fc`). This re-lands the intent of microsoft#810, which merged into a stacked branch and never reached `main`. ## Changes ### Stop retrying Socket Mode negotiate on 401/403 - `NegotiateError` carries the HTTP `statusCode` and an `isAuthError` flag. `statusCode` is an optional third constructor argument, so existing calls still compile. - `NegotiateError` is now exported from `@microsoft/teams.apps`, so `disconnected` listeners can inspect `statusCode` and `isAuthError`. - The 401 and 403 error messages now say what to fix: the bot credentials for a 401, the bot registration and Socket Mode access for a 403. - **Startup:** a 401 or 403 fails `App.start()` right away instead of retrying until the startup timeout runs out. - **Reconnect or planned token rotation:** a 401 or 403 closes every connection for that geo, including a predecessor still serving and any sockets in their handoff window. The geo then stops reconnecting. Other geos are unaffected. - It logs one error saying delivery for the geo has stopped until the app is restarted, without the usual "paused" warning. - It emits `disconnected` with the auth error and `terminal: true`. - **Late rejections after `stop()`:** negotiate isn't abortable, so a 401 or 403 can arrive after `stop()`. That rejection is now ignored: it's not logged and doesn't emit `disconnected`. - Other failures (429, 5xx, ...) are still retried. ### `disconnected` event: new `terminal` field - The payload is now `{ geo, error?, terminal }`. - `terminal` is `true` when the geo has stopped for good after a 401 or 403, and `false` for an ordinary drop that will reconnect. So after a network drop followed by an auth rejection, listeners see two events: `terminal: false`, then `terminal: true`. - `status` and `geoStatuses` are unchanged and report `disconnected` in both cases. - The `examples/socket` sample and its README now handle `terminal`. ### Parse Socket Mode envelope delivery metadata - Adds `botKey`, `deadlineMs` and `headers` to `SocketActivityEnvelope`, in camelCase or PascalCase. - These are typed fields only: they are not validated at runtime, so malformed values pass through like any other envelope field. - Reply frames still carry the locally configured bot id. ## Testing - `npm run build` and `eslint src/socket-mode` in `packages/apps`, plus type-checking and lint for `examples/socket` - `npx jest` in `packages/apps`: 49 suites, 873 tests passed - New tests cover: - 401 and 403 at startup - 401 and 403 on reconnect, including the `terminal` flag on each event and that only the terminal error is logged - a 403 during a planned rotation with multiple geos - a 401 that arrives after `stop()` being ignored - 503 still being retried - `NegotiateError` being exported from the package root - envelopes carrying the new metadata fields are still dispatched - Each new behavior test was checked red-green: it fails with the behavior disabled and passes with it enabled. --------- Co-authored-by: Teddy Arida-Moody <teddyam@Teddys-MacBook-Pro.local> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Stacks on #604. Adds the public layer.
SocketModeAdapterimplements theHttpServerAdapterprotocol, so Socket Mode replaces the inbound transport instead of adding a second ingress. Enable withApp(socket_mode=True)or passSocketModeOptions.Envelopes dispatch through the normal activity pipeline. The socket is authenticated at negotiate time, so the adapter synthesizes the token the pipeline expects; it stringifies to
""so it can never be forwarded. HTTP JWT validation is untouched.Rejects a custom
http_server_adapterand non-public clouds. Addsexamples/socket.