Skip to content

New AttachmentDownloader and M365AttachmentDownloader implementations of InputFileDownloader interface - #604

Merged
Rodrigo Brandão (rodrigobr-msft) merged 24 commits into
mainfrom
users/robrandao/downloader
Sep 30, 2026
Merged

Rodrigo Brandão (rodrigobr-msft) merged 24 commits into
mainfrom
users/robrandao/downloader

Conversation

@rodrigobr-msft

@rodrigobr-msft Rodrigo Brandão (rodrigobr-msft) commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Ports attachment downloading support from the .NET Agents SDK to Python.

Changes

  • Added AttachmentDownloader for standard channel attachments.
  • Added M365AttachmentDownloader for Teams and Microsoft 365 Copilot.
  • Supports remote, inline, authenticated, and anonymous attachment downloads.
  • Added optional outbound host validation and safe localhost URL handling.
  • Added outgoing audience resolution to ClaimsIdentity.
  • Added filenames to InputFile.
  • Added connector support for generating attachment URIs.
  • Added a handling-attachments sample based on the .NET implementation.
  • Added unit and end-to-end tests covering downloader routing, authentication, URL validation, failure responses, and access through state.temp.input_files.

Validation

34 focused unit tests passed

@rodrigobr-msft Rodrigo Brandão (rodrigobr-msft) changed the title Porting two InputFileDownloaders from .NET New AttachmentDownloader and M365AttachmentDownloader as implementations of InputFileDownloader interface Sep 25, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Redirect-based host-validation bypasses and multiple downloader correctness issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 High severity · 10 Medium severity · 3 Low severity

Open (15)
What changed in this PR

Adds attachment downloading support to the hosting layer for standard channels, Teams, and Microsoft 365 Copilot.

Changes:

  • Adds generic and M365 attachment downloaders with authentication and host validation.
  • Extends attachment, identity, connector, and input-file APIs.
  • Adds a handling-attachments sample plus unit and integration coverage.
File Description
tests/​hosting_core/​connector/​test_connector_client.py Tests attachment URI generation.
tests/​hosting_core/​authorization/​test_claims_identity.py Tests outgoing audience resolution.
tests/​hosting_core/​app/​test_m365_attachment_downloader.py Tests M365 downloader behavior.
tests/​hosting_core/​app/​test_attachment_downloader.py Tests generic downloader behavior.
tests/​hosting_core/​app/​test_agent_application_file_downloaders.py Tests downloader application integration.
test_samples/​handling_attachments/​src/​main.py Hosts the sample application.
test_samples/​handling_attachments/​src/​agent.py Implements attachment sample handlers.
test_samples/​handling_attachments/​src/​__init__.py Defines the sample package.
test_samples/​handling_attachments/​requirements.txt Lists sample dependencies.
test_samples/​handling_attachments/​README.md Documents sample setup and usage.
test_samples/​handling_attachments/​env.TEMPLATE Provides sample configuration variables.
libraries/​.../​connector/​mcs/​mcs_connector_client.py Marks attachment URIs unsupported for MCS.
libraries/​.../​connector/​client/​connector_client.py Generates escaped attachment URIs.
libraries/​.../​connector/​attachments_base.py Extends the attachment operations protocol.
libraries/​.../​authorization/​claims_identity.py Resolves outgoing token audiences.
libraries/​.../​app/​m365_attachment_downloader.py Implements authenticated M365 downloads.
libraries/​.../​app/​input_file.py Adds optional filenames to input files.
libraries/​.../​app/​attachment_downloader.py Implements standard attachment downloads.
libraries/​.../​app/​_utils.py Adds URL and content-type helpers.
libraries/​.../​activity/​channels.py Adds an M365 Copilot channel constant.
libraries/​.../​activity/​attachment.py Corrects optional attachment annotations.
dev/​integration/​tests/​downloader/​test_m365_attachment_downloader.py Covers M365 end-to-end downloads.
dev/​integration/​tests/​downloader/​test_attachment_downloader.py Covers generic end-to-end downloads.
dev/​integration/​tests/​downloader/​scenario.py Defines the downloader integration scenario.
dev/​integration/​tests/​downloader/​conftest.py Provides a local download test server.
dev/​integration/​tests/​downloader/​__init__.py Defines the integration-test package.
changelog.md Records the new downloader feature and sample.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread test_samples/handling_attachments/src/agent.py
Comment thread test_samples/handling_attachments/src/agent.py
Comment thread test_samples/handling_attachments/src/main.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

URL validation and redirect handling expose security risks, while channel routing and attachment metadata contain functional errors.

Review effort: Balanced
Findings: None

Resolved since last review (15)
Previously missed (3)

In code that hasn't changed since last review

Medium severity Acquire tokens only for remote downloads

libraries/​microsoft-agents-hosting-core/​microsoft_agents/​hosting/​core/​app/​m365_attachment_downloader.py:86

Token acquisition happens before determining whether any attachment is remote. Consequently an inline-only M365 turn can fail because identity/provider resolution or token acquisition fails, even though inline serialization needs no authentication. Resolve the token lazily only when a remote download is attempted.

Medium severity Fall back when downloadUrl is null or empty

libraries/​microsoft-agents-hosting-core/​microsoft_agents/​hosting/​core/​app/​m365_attachment_downloader.py:134

If M365 metadata contains "downloadUrl": null or an empty string, dict.get does not use its default, so the valid content_url is ignored and the metadata is serialized as inline content. Use an or fallback so absent and empty download URLs both fall back correctly.

Low severity Include the required editable-mode config setting

test_samples/​handling_attachments/​README.md:22

These editable-install commands omit the repository-required --config-settings editable_mode=compat option. Match the documented setup and scripts/dev_setup.sh:5-15; otherwise contributors can get a different editable layout from the one this repository supports.

@rodrigobr-msft
Rodrigo Brandão (rodrigobr-msft) marked this pull request as ready for review September 28, 2026 19:31
@rodrigobr-msft Rodrigo Brandão (rodrigobr-msft) changed the title New AttachmentDownloader and M365AttachmentDownloader as implementations of InputFileDownloader interface New AttachmentDownloader and M365AttachmentDownloader implementations of InputFileDownloader interface Sep 28, 2026
@rodrigobr-msft
Rodrigo Brandão (rodrigobr-msft) merged commit 8117c81 into main Sep 30, 2026
10 checks passed
@rodrigobr-msft
Rodrigo Brandão (rodrigobr-msft) deleted the users/robrandao/downloader branch September 30, 2026 18:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create AttachmentDownloader and M365AttachmentDownloader implementing InputFileDownloader abstract class

4 participants