Merge main into alpha/v2.0.0#393
Merged
heyitsaamir merged 8 commits intoalpha/v2.0.0from Apr 16, 2026
Merged
Conversation
## Summary - Introduces `CloudEnvironment` frozen dataclass with predefined presets (`PUBLIC`, `US_GOV`, `US_GOV_DOD`, `CHINA`) bundling all cloud-specific service endpoints - Threads cloud environment through `App`, `TokenManager`, `BotTokenClient`, `TokenValidator`, `ApiClient`, and `ApiClientSettings` - Supports `CLOUD` environment variable and programmatic `AppOptions.cloud` configuration - Adds `graph_scope` to `CloudEnvironment` for cloud-aware Microsoft Graph token acquisition - Simplifies `merge_api_client_settings` with `cloud` default to `PUBLIC`, removes `DEFAULT_API_CLIENT_SETTINGS` - Fixes cloud propagation through `ApiClient` -> `BotClient` -> `BotTokenClient` ### Note `graph_base_url` (Graph API endpoint per cloud) is intentionally deferred. This PR focuses on auth/token acquisition. Graph API routing is a separate concern. ### Sources - Bot Framework GCCH/DoD endpoints: https://learn.microsoft.com/en-us/azure/bot-service/how-to-deploy-gov-cloud-high - Bot Framework China endpoints: https://learn.microsoft.com/en-us/azure/bot-service/how-to-deploy-china-cloud - Graph national cloud deployments: https://learn.microsoft.com/en-us/graph/deployments ## Test plan - [x] `pytest packages/api/tests/` -- 168 tests pass - [x] `pytest packages/apps/tests/` -- 389 tests pass (1 pre-existing failure unrelated) - [x] E2E: Echo bot with `CLOUD=USGov` against real GCCH tenant -- message received, echo reply sent - [x] Copilot review feedback addressed 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Corina Gum <> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary - Removes the 10-item batch cap in `HttpStream._flush()` so each flush cycle drains the entire queue - Prevents a long streaming tail when the LLM finishes generating faster than chunks are sent to Teams - Port of [microsoft/teams.ts#520](microsoft/teams.ts#520) ## Test plan - [x] Existing `test_http_stream.py` tests pass (11/11) - [x] Updated `test_stream_multiple_emits_with_timer` to verify the first flush drains all 12 messages with no second flush scheduled - [x] Pre-commit hooks (ruff, pyright) pass 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <noreply@anthropic.com>
- Remove `with_reply_to_id()` method `reply_to_id` is a field on the activity that is used by the service, but any changes to it on the bot side are completely ignored. After thorough testing to confirm, this PR removes the misleading method `with_reply_to_id`; setting replyToId on outgoing activities is a no-op. Originally part of #321 but separated out due to timing concerns for GA
When `Client.clone()` was called with headers containing a `User-Agent`,
it would overwrite the base client's `User-Agent` rather than merging.
This loses the SDK's default UA token when callers supply their own.
## Changes
- **`packages/common/src/microsoft_teams/common/http/client.py`**
- Added `_merge_headers(base, overrides)` helper: performs a
case-insensitive `User-Agent` merge (space-concatenated, token-based
dedup to avoid substring false positives); all other headers follow
standard last-write-wins semantics
- `Client.clone()` now calls `_merge_headers()` instead of a plain dict
unpack
- **`packages/common/tests/test_client.py`**
- Added 7 tests covering: preservation without overrides, merge when
both sides define UA, non-UA overrides leave UA untouched,
case-insensitive key matching, duplicate-token suppression, substring
false-positive guard, and override-only UA when base has none
## Example
```python
client = Client(ClientOptions(headers={"User-Agent": "teams-py/1.0"}))
clone = client.clone(ClientOptions(headers={"User-Agent": "myapp/2.0"}))
# Before: "myapp/2.0" (SDK UA lost)
# After: "teams-py/1.0 myapp/2.0"
print(clone._options.headers["User-Agent"])
```
> [!WARNING]
>
> <details>
> <summary>Firewall rules blocked me from connecting to one or more
addresses (expand for details)</summary>
>
> #### I tried to connect to the following addresses, but was blocked by
firewall rules:
>
> - `releases.astral.sh`
> - Triggering command: `/home/REDACTED/.local/bin/uv uv sync
--all-packages --group dev` (dns block)
>
> If you need me to access, download, or install something from one of
these locations, you can either:
>
> - Configure [Actions setup
steps](https://gh.io/copilot/actions-setup-steps) to set up my
environment, which run before the firewall is enabled
> - Add the appropriate URLs or hosts to the custom allowlist in this
repository's [Copilot coding agent
settings](https://github.com/microsoft/teams.py/settings/copilot/coding_agent)
(admins only)
>
> </details>
<!-- START COPILOT ORIGINAL PROMPT -->
<details>
<summary>Original prompt</summary>
> Implement the change described by PR microsoft/teams.ts#508 ("Merge
User-Agent headers when cloning HTTP client") in the Python SDK
repository @microsoft/teams.py.
>
> Goal:
> - When the HTTP client is cloned (or a new client is created from an
existing client/session), ensure that `User-Agent` headers are merged
rather than overwritten.
> - Preserve any existing default `User-Agent` set by the library while
also incorporating a user-provided `User-Agent` (or additional UA
tokens) when cloning.
>
> Requirements:
> 1. Locate the HTTP client implementation and any clone/copy method(s)
in the repository.
> 2. Identify how headers are stored (e.g., requests.Session headers,
httpx.Client headers, custom dict) and how cloning currently works.
> 3. Modify cloning logic so that:
> - If both source and override headers contain `User-Agent`, the
resulting `User-Agent` should include both (e.g., concatenated with a
space, or comma per convention) without duplicating identical values.
> - If only one side has `User-Agent`, keep it.
> - Header merging should be case-insensitive for the header key.
> 4. Add/adjust unit tests to cover:
> - Cloning without overrides preserves original `User-Agent`.
> - Cloning with headers override that includes `User-Agent` results in
merged value.
> - Cloning with headers override without `User-Agent` leaves original
UA intact.
> - Case-insensitive behavior (`user-agent`, `User-Agent`).
> 5. Update any relevant docs or changelog entry if the repo uses one.
>
> Reference:
> - PR: microsoft/teams.ts#508
>
> Notes:
> - Ensure behavior is consistent across sync/async HTTP clients if both
exist.
> - Keep backward compatibility with existing public APIs.
>
>
> The following is the prior conversation context from the user's chat
exploration (may be truncated):
>
> User: Can you implement this in @microsoft/teams.py ?
>
> Assistant: I’ve queued up the implementation for `microsoft/teams.py`
and I’m now waiting on your confirmation in the prompt to proceed with
making the code changes and opening the PR.
>
>
</details>
<!-- START COPILOT CODING AGENT SUFFIX -->
*This pull request was created from Copilot chat.*
>
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: heyitsaamir <48929123+heyitsaamir@users.noreply.github.com>
Co-authored-by: heyitsaamir <ajawaid191@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.4.2 to 9.0.3. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/pytest-dev/pytest/releases">pytest's releases</a>.</em></p> <blockquote> <h2>9.0.3</h2> <h1>pytest 9.0.3 (2026-04-07)</h1> <h2>Bug fixes</h2> <ul> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/12444">#12444</a>: Fixed <code>pytest.approx</code> which now correctly takes into account <code>~collections.abc.Mapping</code> keys order to compare them.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/13634">#13634</a>: Blocking a <code>conftest.py</code> file using the <code>-p no:</code> option is now explicitly disallowed.</p> <p>Previously this resulted in an internal assertion failure during plugin loading.</p> <p>Pytest now raises a clear <code>UsageError</code> explaining that conftest files are not plugins and cannot be disabled via <code>-p</code>.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/13734">#13734</a>: Fixed crash when a test raises an exceptiongroup with <code>__tracebackhide__ = True</code>.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/14195">#14195</a>: Fixed an issue where non-string messages passed to <!-- raw HTML omitted -->unittest.TestCase.subTest()<!-- raw HTML omitted --> were not printed.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/14343">#14343</a>: Fixed use of insecure temporary directory (CVE-2025-71176).</p> </li> </ul> <h2>Improved documentation</h2> <ul> <li><a href="https://redirect.github.com/pytest-dev/pytest/issues/13388">#13388</a>: Clarified documentation for <code>-p</code> vs <code>PYTEST_PLUGINS</code> plugin loading and fixed an incorrect <code>-p</code> example.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest/issues/13731">#13731</a>: Clarified that capture fixtures (e.g. <code>capsys</code> and <code>capfd</code>) take precedence over the <code>-s</code> / <code>--capture=no</code> command-line options in <code>Accessing captured output from a test function <accessing-captured-output></code>.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest/issues/14088">#14088</a>: Clarified that the default <code>pytest_collection</code> hook sets <code>session.items</code> before it calls <code>pytest_collection_finish</code>, not after.</li> <li><a href="https://redirect.github.com/pytest-dev/pytest/issues/14255">#14255</a>: TOML integer log levels must be quoted: Updating reference documentation.</li> </ul> <h2>Contributor-facing changes</h2> <ul> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/12689">#12689</a>: The test reports are now published to Codecov from GitHub Actions. The test statistics is visible <a href="https://app.codecov.io/gh/pytest-dev/pytest/tests">on the web interface</a>.</p> <p>-- by <code>aleguy02</code></p> </li> </ul> <h2>9.0.2</h2> <h1>pytest 9.0.2 (2025-12-06)</h1> <h2>Bug fixes</h2> <ul> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/13896">#13896</a>: The terminal progress feature added in pytest 9.0.0 has been disabled by default, except on Windows, due to compatibility issues with some terminal emulators.</p> <p>You may enable it again by passing <code>-p terminalprogress</code>. We may enable it by default again once compatibility improves in the future.</p> <p>Additionally, when the environment variable <code>TERM</code> is <code>dumb</code>, the escape codes are no longer emitted, even if the plugin is enabled.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/13904">#13904</a>: Fixed the TOML type of the <code>tmp_path_retention_count</code> settings in the API reference from number to string.</p> </li> <li> <p><a href="https://redirect.github.com/pytest-dev/pytest/issues/13946">#13946</a>: The private <code>config.inicfg</code> attribute was changed in a breaking manner in pytest 9.0.0. Due to its usage in the ecosystem, it is now restored to working order using a compatibility shim. It will be deprecated in pytest 9.1 and removed in pytest 10.</p> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/pytest-dev/pytest/commit/a7d58d7a21b78581e636bbbdea13c66ad1657c1e"><code>a7d58d7</code></a> Prepare release version 9.0.3</li> <li><a href="https://github.com/pytest-dev/pytest/commit/089d98199c253d8f89a040243bc4f2aa6cd5ab22"><code>089d981</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14366">#14366</a> from bluetech/revert-14193-backport</li> <li><a href="https://github.com/pytest-dev/pytest/commit/8127eaf4ab7f6b2fdd0dc1b38343ec97aeef05ac"><code>8127eaf</code></a> Revert "Fix: assertrepr_compare respects dict insertion order (<a href="https://redirect.github.com/pytest-dev/pytest/issues/14050">#14050</a>) (<a href="https://redirect.github.com/pytest-dev/pytest/issues/14193">#14193</a>)"</li> <li><a href="https://github.com/pytest-dev/pytest/commit/99a7e6029e7a6e8d53e5df114b1346e035370241"><code>99a7e60</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14363">#14363</a> from pytest-dev/patchback/backports/9.0.x/95d8423bd...</li> <li><a href="https://github.com/pytest-dev/pytest/commit/ddee02a578da30dd43aedc39c1c1f1aaadfcee95"><code>ddee02a</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14343">#14343</a> from bluetech/cve-2025-71176-simple</li> <li><a href="https://github.com/pytest-dev/pytest/commit/74eac6916fee34726cb194f16c516e96fbd29619"><code>74eac69</code></a> doc: Update training info (<a href="https://redirect.github.com/pytest-dev/pytest/issues/14298">#14298</a>) (<a href="https://redirect.github.com/pytest-dev/pytest/issues/14301">#14301</a>)</li> <li><a href="https://github.com/pytest-dev/pytest/commit/f92dee777cfdb77d1c43633d02766ddf1f07c869"><code>f92dee7</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14267">#14267</a> from pytest-dev/patchback/backports/9.0.x/d6fa26c62...</li> <li><a href="https://github.com/pytest-dev/pytest/commit/7ee58acc8777c31ac6cf388d01addf5a414a7439"><code>7ee58ac</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/12378">#12378</a> from Pierre-Sassoulas/fix-implicit-str-concat-and-d...</li> <li><a href="https://github.com/pytest-dev/pytest/commit/37da870d37e3a2f5177cae075c7b9ae279432bf8"><code>37da870</code></a> Merge pull request <a href="https://redirect.github.com/pytest-dev/pytest/issues/14259">#14259</a> from mitre88/patch-4 (<a href="https://redirect.github.com/pytest-dev/pytest/issues/14268">#14268</a>)</li> <li><a href="https://github.com/pytest-dev/pytest/commit/c34bfa3b7acb65b594707c714f1d8461b0304eed"><code>c34bfa3</code></a> Add explanation for string context diffs (<a href="https://redirect.github.com/pytest-dev/pytest/issues/14257">#14257</a>) (<a href="https://redirect.github.com/pytest-dev/pytest/issues/14266">#14266</a>)</li> <li>Additional commits viewable in <a href="https://github.com/pytest-dev/pytest/compare/8.4.2...9.0.3">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.py/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…s/tab/Web (#388) Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.11 to 1.16.0. <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/follow-redirects/follow-redirects/commit/0c23a223067201c368035e82954c11eb2578a33b"><code>0c23a22</code></a> Release version 1.16.0 of the npm package.</li> <li><a href="https://github.com/follow-redirects/follow-redirects/commit/844c4d302ac963d29bdb5dc1754ec7df3d70d7f9"><code>844c4d3</code></a> Add sensitiveHeaders option.</li> <li><a href="https://github.com/follow-redirects/follow-redirects/commit/5e8b8d024e2c76f804a284258e585ecb49a575be"><code>5e8b8d0</code></a> ci: add Node.js 24.x to the CI matrix</li> <li><a href="https://github.com/follow-redirects/follow-redirects/commit/7953e2255aa0b93602eed3804f3bc5e6923a03af"><code>7953e22</code></a> ci: upgrade GitHub Actions to use setup-node@v6 and checkout@v6</li> <li><a href="https://github.com/follow-redirects/follow-redirects/commit/86dc1f86e4b56bcd642c78384d51f10f123aea75"><code>86dc1f8</code></a> Sanitizing input.</li> <li>See full diff in <a href="https://github.com/follow-redirects/follow-redirects/compare/v1.15.11...v1.16.0">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.py/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [python-multipart](https://github.com/Kludex/python-multipart) from 0.0.22 to 0.0.26. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/Kludex/python-multipart/releases">python-multipart's releases</a>.</em></p> <blockquote> <h2>Version 0.0.26</h2> <h2>What's Changed</h2> <ul> <li>Skip preamble before first multipart boundary by <a href="https://github.com/Kludex"><code>@Kludex</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/262">Kludex/python-multipart#262</a></li> <li>Silently discard epilogue data after the closing boundary by <a href="https://github.com/Kludex"><code>@Kludex</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/259">Kludex/python-multipart#259</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/Kludex/python-multipart/compare/0.0.25...0.0.26">https://github.com/Kludex/python-multipart/compare/0.0.25...0.0.26</a></p> <h2>Version 0.0.25</h2> <h2>What's Changed</h2> <ul> <li>Apply Apache-2.0 properly by <a href="https://github.com/Kludex"><code>@Kludex</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/247">Kludex/python-multipart#247</a></li> <li>Handle multipart headers case-insensitively by <a href="https://github.com/Kludex"><code>@Kludex</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/252">Kludex/python-multipart#252</a></li> <li>Emit <code>field_end</code> for trailing bare field names on finalize by <a href="https://github.com/bysiber"><code>@bysiber</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/230">Kludex/python-multipart#230</a></li> <li>Add <code>UPLOAD_DELETE_TMP</code> to <code>FormParser</code> config by <a href="https://github.com/Kludex"><code>@Kludex</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/254">Kludex/python-multipart#254</a></li> <li>Remove custom FormParser classes by <a href="https://github.com/Kludex"><code>@Kludex</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/257">Kludex/python-multipart#257</a></li> <li>Handle CTE values case-insensitively by <a href="https://github.com/Kludex"><code>@Kludex</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/258">Kludex/python-multipart#258</a></li> <li>Add MIME content type info to File by <a href="https://github.com/jhnstrk"><code>@jhnstrk</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/143">Kludex/python-multipart#143</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/Kludex/python-multipart/compare/0.0.24...0.0.25">https://github.com/Kludex/python-multipart/compare/0.0.24...0.0.25</a></p> <h2>Version 0.0.24</h2> <h2>What's Changed</h2> <ul> <li>Validate <code>chunk_size</code> in <code>parse_form()</code> by <a href="https://github.com/Kludex"><code>@Kludex</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/244">Kludex/python-multipart#244</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/Kludex/python-multipart/compare/0.0.23...0.0.24">https://github.com/Kludex/python-multipart/compare/0.0.23...0.0.24</a></p> <h2>Version 0.0.23</h2> <h2>What's Changed</h2> <ul> <li>Remove unused <code>trust_x_headers</code> parameter and <code>X-File-Name</code> fallback by <a href="https://github.com/jhnstrk"><code>@jhnstrk</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/196">Kludex/python-multipart#196</a></li> <li>Return processed length from <code>QuerystringParser._internal_write</code> by <a href="https://github.com/bysiber"><code>@bysiber</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/229">Kludex/python-multipart#229</a></li> <li>Cleanup metadata dunders from <code>__init__.py</code> by <a href="https://github.com/Chesars"><code>@Chesars</code></a> in <a href="https://redirect.github.com/Kludex/python-multipart/pull/227">Kludex/python-multipart#227</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/Chesars"><code>@Chesars</code></a> made their first contribution in <a href="https://redirect.github.com/Kludex/python-multipart/pull/227">Kludex/python-multipart#227</a></li> <li><a href="https://github.com/bysiber"><code>@bysiber</code></a> made their first contribution in <a href="https://redirect.github.com/Kludex/python-multipart/pull/229">Kludex/python-multipart#229</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/Kludex/python-multipart/compare/0.0.22...0.0.23">https://github.com/Kludex/python-multipart/compare/0.0.22...0.0.23</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/Kludex/python-multipart/blob/master/CHANGELOG.md">python-multipart's changelog</a>.</em></p> <blockquote> <h2>0.0.26 (2026-04-10)</h2> <ul> <li>Skip preamble before the first multipart boundary more efficiently <a href="https://redirect.github.com/Kludex/python-multipart/pull/262">#262</a>.</li> <li>Silently discard epilogue data after the closing multipart boundary <a href="https://redirect.github.com/Kludex/python-multipart/pull/259">#259</a>.</li> </ul> <h2>0.0.25 (2026-04-10)</h2> <ul> <li>Add MIME content type info to <code>File</code> <a href="https://redirect.github.com/Kludex/python-multipart/pull/143">#143</a>.</li> <li>Handle CTE values case-insensitively <a href="https://redirect.github.com/Kludex/python-multipart/pull/258">#258</a>.</li> <li>Remove custom <code>FormParser</code> classes <a href="https://redirect.github.com/Kludex/python-multipart/pull/257">#257</a>.</li> <li>Add <code>UPLOAD_DELETE_TMP</code> to <code>FormParser</code> config <a href="https://redirect.github.com/Kludex/python-multipart/pull/254">#254</a>.</li> <li>Emit <code>field_end</code> for trailing bare field names on finalize <a href="https://redirect.github.com/Kludex/python-multipart/pull/230">#230</a>.</li> <li>Handle multipart headers case-insensitively <a href="https://redirect.github.com/Kludex/python-multipart/pull/252">#252</a>.</li> <li>Apply Apache-2.0 properly <a href="https://redirect.github.com/Kludex/python-multipart/pull/247">#247</a>.</li> </ul> <h2>0.0.24 (2026-04-05)</h2> <ul> <li>Validate <code>chunk_size</code> in <code>parse_form()</code> <a href="https://redirect.github.com/Kludex/python-multipart/pull/244">#244</a>.</li> </ul> <h2>0.0.23 (2026-04-05)</h2> <ul> <li>Remove unused <code>trust_x_headers</code> parameter and <code>X-File-Name</code> fallback <a href="https://redirect.github.com/Kludex/python-multipart/pull/196">#196</a>.</li> <li>Return processed length from <code>QuerystringParser._internal_write</code> <a href="https://redirect.github.com/Kludex/python-multipart/pull/229">#229</a>.</li> <li>Cleanup metadata dunders from <code>__init__.py</code> <a href="https://redirect.github.com/Kludex/python-multipart/pull/227">#227</a>.</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/Kludex/python-multipart/commit/28f47859b4a40c2e11e02dc514b2e9743ceedd2e"><code>28f4785</code></a> Version 0.0.26 (<a href="https://redirect.github.com/Kludex/python-multipart/issues/263">#263</a>)</li> <li><a href="https://github.com/Kludex/python-multipart/commit/d4452a78bbde94995dd3c0d1b4aff3610a5c472f"><code>d4452a7</code></a> Silently discard epilogue data after the closing boundary (<a href="https://redirect.github.com/Kludex/python-multipart/issues/259">#259</a>)</li> <li><a href="https://github.com/Kludex/python-multipart/commit/6a7b76dd2653d99d8e5981d7ff09a4a047750b37"><code>6a7b76d</code></a> Skip preamble before first multipart boundary (<a href="https://redirect.github.com/Kludex/python-multipart/issues/262">#262</a>)</li> <li><a href="https://github.com/Kludex/python-multipart/commit/4addb60350fc843f77a1502f14247db91930b3bf"><code>4addb60</code></a> Version 0.0.25 (<a href="https://redirect.github.com/Kludex/python-multipart/issues/261">#261</a>)</li> <li><a href="https://github.com/Kludex/python-multipart/commit/d3a4698e0dc16cbd85f98076b2ebf9b696cd3604"><code>d3a4698</code></a> Add MIME content type info to File (<a href="https://redirect.github.com/Kludex/python-multipart/issues/143">#143</a>)</li> <li><a href="https://github.com/Kludex/python-multipart/commit/9a1ecbd074801fcd3911266f3f4442181d10ab92"><code>9a1ecbd</code></a> Handle CTE values case-insensitively (<a href="https://redirect.github.com/Kludex/python-multipart/issues/258">#258</a>)</li> <li><a href="https://github.com/Kludex/python-multipart/commit/ef2a0b94f95676ea6a7b77d2252b09f5797cb8ed"><code>ef2a0b9</code></a> Remove custom FormParser classes (<a href="https://redirect.github.com/Kludex/python-multipart/issues/257">#257</a>)</li> <li><a href="https://github.com/Kludex/python-multipart/commit/3a757d7cf209e654eb17cf7b7af868eed469f680"><code>3a757d7</code></a> Ignore local Claude state (<a href="https://redirect.github.com/Kludex/python-multipart/issues/255">#255</a>)</li> <li><a href="https://github.com/Kludex/python-multipart/commit/55e739617db7c40e2cd04c5ad8c7acf2ed0a1d19"><code>55e7396</code></a> fuzz: Add cifuzz (<a href="https://redirect.github.com/Kludex/python-multipart/issues/186">#186</a>)</li> <li><a href="https://github.com/Kludex/python-multipart/commit/d6d1d111e7de9ce3d3f8623fe5f5e4201c0a5fd1"><code>d6d1d11</code></a> Bump the github-actions group with 2 updates (<a href="https://redirect.github.com/Kludex/python-multipart/issues/249">#249</a>)</li> <li>Additional commits viewable in <a href="https://github.com/Kludex/python-multipart/compare/0.0.22...0.0.26">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.py/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This pull request significantly refactors the MCP server Teams bot sample to provide a robust, human-in-the-loop toolkit using the official `mcp` SDK, with clear separation of concerns and improved documentation. The changes introduce a modular structure, new tool definitions for user interaction and approvals, and improved state management. The README and project metadata are also updated for clarity and accuracy. **Key changes:** **1. Major refactor and modularization** - The codebase is split into clear modules: `app.py` (Teams bot handlers), `mcp_tools.py` (MCP tool definitions), `state.py` (in-memory state), and `main.py` (entry point and server wiring), replacing the previous monolithic and example-based implementation. **2. New MCP tools for human-in-the-loop workflows** - Defines five MCP tools in `mcp_tools.py`: `notify`, `ask`, `get_reply`, `request_approval`, and `get_approval`, enabling agents to notify users, ask questions, and request approvals through Teams with polling for responses. - Introduces helper models for tool inputs and outputs in `models.py`. **3. Improved state management** - Implements in-memory dictionaries in `state.py` to track conversations, pending asks, approvals, and user-to-request mappings, supporting the new tools and workflows. **4. Documentation and metadata updates** - Overhauls the `README.md` to explain setup, architecture, tool usage, workflows, and limitations, providing a much clearer guide for users and developers. - Updates `pyproject.toml` to accurately describe the project and its dependencies, switching to the `mcp` SDK. **5. Removal of legacy/demo code** - Removes the previous example tools (`echo`, `get_weather`, `calculate`, `alert`) and the old MCP server plugin setup, replacing them with the new modular and production-like approach.
lilyydu
approved these changes
Apr 16, 2026
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.
Summary
Merge latest main commits into alpha for the next alpha release:
with_reply_to_idmethod (Remove with_reply_to_id method #385)Test plan
alpha/v2.0.0after merge