Skip to content

List and download pasted inline images through ctx.files - #629

Merged
Corina (corinagum) merged 11 commits into
mainfrom
cg/inline-images-py
Oct 15, 2026
Merged

Corina (corinagum) merged 11 commits into
mainfrom
cg/inline-images-py

Conversation

@corinagum

Copy link
Copy Markdown
Contributor

What this does

Images a user pastes into a message are now listed by ctx.files alongside attached files, and download through the same download() call. Each listed file has a new attachment_style of "file" or "inlineImage", and list() and first() accept attachment_style= to return only one kind.

Inline images are read from the Bot API with the same token the app uses to reply in that conversation, not through Graph. That makes them work for traditional bots and agentic users alike, in personal chats, group chats and channels. The token is resolved lazily, so a turn that never downloads an inline image never acquires one.

Naming and formats

  • A pasted image has no file name, so it is named image-<attachmentId>, with an extension and MIME type taken from the format hint in the message HTML.
  • PNG, JPEG and WebP are named and typed as themselves. Teams stores a pasted GIF as a static PNG, so it is listed as .gif and downloads as PNG; the downloaded type is detected from the bytes.
  • Formats the platform cannot convert, such as BMP and AVIF, fail to download with InlineImageTransformationError (415). The same image sent as a file downloads normally.
  • A refused token raises InlineImageAccessError (401 or 403), distinct from FileAccessError, which is about Graph.

Where the token is sent

The Bot API token is only sent to an https URL under the activity's service_url. An inline image hosted anywhere else is skipped with a warning. Redirects keep Authorization only while they stay on the original origin and are refused if they leave https; this PR adds tests that pin that behavior for the inline and Graph paths.

Behavior change for existing code

list() and first() previously returned only attached files. They now include pasted images by default, so an app that treats every listed item as an uploaded document should pass attachment_style="file".

Testing

  • Unit tests for the format helpers, the download route, the accessor, the credential selection, and the redirect handling.
  • Live in a test tenant with the ai-file-analysis example, which now shows pasted images: PNG, JPEG, GIF and WebP in one message, as a traditional bot and as an agentic user, in a personal chat, a group chat, a channel post and a channel thread reply.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 21:28

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.

🟡 Changes recommended

The HTML image-tag regex has quadratic behavior on malformed user-controlled input.

1 open finding
What changed in this PR

Adds pasted inline-image support to ctx.files, including filtering, secure Bot API downloads, format detection, errors, tests, and example updates.

Changes:

  • Lists and filters uploaded files and pasted images.
  • Downloads inline images using lazily resolved Bot API credentials.
  • Adds format detection, redirect protections, errors, and coverage.
File Description
packages/​apps/​tests/​test_inline_image.py Tests image parsing and format detection.
packages/​apps/​tests/​test_files_download_inline.py Tests inline-image downloads and security.
packages/​apps/​tests/​test_files_download_graph.py Expands redirect credential tests.
packages/​apps/​tests/​test_files_credential.py Tests lazy Bot API credentials.
packages/​apps/​tests/​test_files_accessor_inline.py Tests inline-image listing and filtering.
packages/​apps/​tests/​test_app_process.py Tests context credential wiring.
packages/​apps/​src/​microsoft_teams/​apps/​routing/​activity_context.py Passes Bot API credentials to files.
packages/​apps/​src/​microsoft_teams/​apps/​files/​types.py Defines attachment styles.
packages/​apps/​src/​microsoft_teams/​apps/​files/​inline_image.py Parses and identifies inline images.
packages/​apps/​src/​microsoft_teams/​apps/​files/​incoming_file.py Supports inline-image downloads and typing.
packages/​apps/​src/​microsoft_teams/​apps/​files/​files_accessor.py Lists and filters inline images.
packages/​apps/​src/​microsoft_teams/​apps/​files/​errors.py Adds inline-image-specific errors.
packages/​apps/​src/​microsoft_teams/​apps/​files/​downloaded_file.py Documents resolved image metadata.
packages/​apps/​src/​microsoft_teams/​apps/​files/​download.py Implements secure Bot API fetching.
packages/​apps/​src/​microsoft_teams/​apps/​files/​__init__.py Exports new public APIs.
packages/​apps/​src/​microsoft_teams/​apps/​files_credential.py Selects lazy inline-image credentials.
packages/​apps/​src/​microsoft_teams/​apps/​app_process.py Builds credentials per activity.
examples/​ai-file-analysis/​src/​main.py Handles pasted-image downloads.
examples/​ai-file-analysis/​src/​file_card.py Displays attachment style.
examples/​ai-file-analysis/​README.md Documents inline-image behavior.

🧠 Review effort: Balanced


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

Comment thread packages/apps/src/microsoft_teams/apps/files/inline_image.py Outdated
Comment thread packages/apps/src/microsoft_teams/apps/files/errors.py Outdated
Comment thread packages/apps/src/microsoft_teams/apps/files/inline_image.py Outdated
Comment thread packages/apps/src/microsoft_teams/apps/files/download.py Outdated
Comment thread packages/apps/src/microsoft_teams/apps/files/files_accessor.py
Corina (corinagum) and others added 11 commits October 14, 2026 10:18
Inside FilesAccessor, `list` resolves to the accessor's own `list()` method, so Pyright could not type the parameter.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Compare service URL paths case-sensitively, match img tags in linear time with quote awareness, and skip inline image hint parsing when listing only file attachments.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@corinagum
Corina (corinagum) merged commit 057b243 into main Oct 15, 2026
8 checks passed
@corinagum
Corina (corinagum) deleted the cg/inline-images-py branch October 15, 2026 22:42
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.

3 participants