Simply HttpPlugin to only focus on server-concepts#249
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request simplifies the HttpPlugin by separating activity sending from HTTP transport concerns. The changes adapt the TypeScript PR #424 to Python, introducing a cleaner architectural separation.
Changes:
- Introduces a new
ActivitySenderclass dedicated to sending activities, removing this responsibility fromHttpPlugin - Removes the
Senderplugin interface and related coupling between transport and sending logic - Updates
ActivityContextand other components to useActivitySenderinstead of depending on plugins - Adds
app.initialize()method to enable proactive messaging without starting an HTTP server - Includes a new proactive-messaging example demonstrating serverless message sending
Reviewed changes
Copilot reviewed 22 out of 23 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| uv.lock | Adds proactive-messaging example package to workspace |
| packages/devtools/src/microsoft_teams/devtools/devtools_plugin.py | Updates to use PluginBase instead of Sender, converts Activity to CoreActivity |
| packages/botbuilder/src/microsoft_teams/botbuilder/botbuilder_plugin.py | Updates signature to accept CoreActivity parameter, calls parent with new signature |
| packages/apps/src/microsoft_teams/apps/routing/activity_context.py | Replaces Sender dependency with ActivitySender |
| packages/apps/src/microsoft_teams/apps/plugins/sender.py | Removes the Sender abstract class entirely |
| packages/apps/src/microsoft_teams/apps/plugins/plugin_error_event.py | Removes sender field from error events |
| packages/apps/src/microsoft_teams/apps/plugins/plugin_base.py | Removes send() and create_stream() methods from base plugin |
| packages/apps/src/microsoft_teams/apps/plugins/plugin_activity_sent_event.py | Removes sender field from activity sent events |
| packages/apps/src/microsoft_teams/apps/plugins/plugin_activity_response_event.py | Removes sender field from activity response events |
| packages/apps/src/microsoft_teams/apps/plugins/plugin_activity_event.py | Removes sender field from plugin activity events |
| packages/apps/src/microsoft_teams/apps/plugins/init.py | Removes Sender from exports |
| packages/apps/src/microsoft_teams/apps/http_plugin.py | Removes sending logic, updates to work with CoreActivity, changes to PluginBase |
| packages/apps/src/microsoft_teams/apps/events/types.py | Adds CoreActivity model, removes sender from event dataclasses |
| packages/apps/src/microsoft_teams/apps/events/init.py | Exports CoreActivity |
| packages/apps/src/microsoft_teams/apps/contexts/function_context.py | Uses ActivitySender instead of HttpPlugin for sending |
| packages/apps/src/microsoft_teams/apps/app_process.py | Updates to work without Sender, converts CoreActivity back to Activity |
| packages/apps/src/microsoft_teams/apps/app_plugins.py | Removes Sender dependency from plugin injection |
| packages/apps/src/microsoft_teams/apps/app_events.py | Updates event management to work without sender parameter |
| packages/apps/src/microsoft_teams/apps/app.py | Adds ActivitySender, implements initialize() method, updates send() to use ActivitySender |
| packages/apps/src/microsoft_teams/apps/activity_sender.py | New class handling activity sending and streaming |
| examples/proactive-messaging/src/main.py | Example demonstrating proactive messaging without server |
| examples/proactive-messaging/pyproject.toml | Package configuration for proactive messaging example |
| examples/proactive-messaging/README.md | Documentation for proactive messaging example |
Comments suppressed due to low confidence (1)
packages/apps/src/microsoft_teams/apps/http_plugin.py:317
- The route handler signature has changed from parsing the request body internally to expecting
core_activity: CoreActivityas a parameter. While FastAPI can automatically parse Pydantic models from request bodies, this pattern differs from the manual parsing approach used elsewhere in the codebase (e.g., in the func decorator whereawait r.json()is used).
Please verify that FastAPI correctly injects the CoreActivity parameter when the route is called. If this doesn't work as expected at runtime, consider either:
- Manually parsing the body:
body = await request.json(); core_activity = CoreActivity.model_validate(body) - Using FastAPI's Body annotation:
core_activity: CoreActivity = Body(...)
Note that existing tests likely need updates to match this new signature.
async def on_activity_request(self, core_activity: CoreActivity, request: Request, response: Response) -> Any:
"""Handle incoming Teams activity."""
# Get validated token from middleware (if present - will be missing if skip_auth is True)
if hasattr(request.state, "validated_token") and request.state.validated_token:
token = request.state.validated_token
else:
token = cast(
TokenProtocol,
SimpleNamespace(
app_id="",
app_display_name="",
tenant_id="",
service_url=core_activity.service_url or "",
from_="azure",
from_id="",
is_expired=lambda: False,
),
)
activity_type = core_activity.type or "unknown"
activity_id = core_activity.id or "unknown"
self.logger.debug(f"Received activity: {activity_type} (ID: {activity_id})")
self.logger.debug(f"Processing activity {activity_id} via handler...")
# Process the activity
result = await self._process_activity(core_activity, token)
return self._handle_activity_response(response, result)
def _setup_routes(self) -> None:
"""Setup FastAPI routes."""
self.app.post("/api/messages")(self.on_activity_request)
lilyydu
reviewed
Jan 26, 2026
heyitsaamir
force-pushed
the
aamirj/simplifyHttp
branch
from
March 10, 2026 07:09
3b5c763 to
285a002
Compare
8 tasks
lilyydu
reviewed
Mar 10, 2026
lilyydu
reviewed
Mar 11, 2026
heyitsaamir
commented
Mar 11, 2026
Collaborator
Author
|
@lilyydu - great points
Wdyt? |
Co-Authored-By: Claude Opus 4.6 <[email protected]>
Co-Authored-By: Claude Opus 4.6 <[email protected]>
heyitsaamir
force-pushed
the
aamirj/simplifyHttp
branch
from
March 12, 2026 19:45
8dc943a to
2c91aa4
Compare
lilyydu
approved these changes
Mar 12, 2026
Collaborator
Author
|
This change is part of the following stack: Change managed by git-spice. |
heyitsaamir
added a commit
that referenced
this pull request
Mar 13, 2026
## Summary - **Replace `HttpPlugin` with `HttpServer` + `HttpServerAdapter` pattern** — follows the [TS PR #433](AzureAD/microsoft-authentication-library-for-js#433) approach - `HttpServer` is no longer a plugin — it's owned directly by `App` - Introduces `HttpServerAdapter` protocol with `FastAPIAdapter` as the default implementation - Plugins inject `HttpServer` via DI and access the framework via `server.adapter` - Framework-agnostic handler pattern: `async (HttpRequest) -> HttpResponse` - Rewrites `remote_function_jwt_middleware` to be framework-agnostic - Adds `examples/http-adapters/` with Starlette adapter and non-managed FastAPI examples Stacked on #249 ## Test plan - [x] Update unit tests - [x] Run `poe test` — all tests pass - [x] Run AI sample end-to-end - [x] Run MCP sample end-to-end - [x] Run Echo Bot sample end-to-end - [x] Run Dialog sample end-to-end - [x] Run Tab sample end-to-end - [x] Run BotBuilder sample end-to-end 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
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.



This is a python adaptation of microsoft/teams.ts#424.
Separate activity sending from HTTP transport layer
The previous architecture tightly coupled HTTP transport concerns with activity sending logic:
Previous Architecture:
There are a few issues with this:
New Architecture
In this PR, I am mainly decoupling responsibilities of HttpPlugin from being BOTH a listener AND a sender, to being just a listener. The sender bit is now separated to a different
ActivitySenderclass. Other than better code organization, the main thing this lets us do is not require the app to run to be able to send proactive messages. This is a huge plus point because now the App can be used in scenarios where it doesn't necessarily need to listen to incoming messages (like agentic notifications!)