Skip to content

fix(msteams): fix inline pasted image downloads#10902

Closed
jlian wants to merge 1 commit intoopenclaw:mainfrom
jlian:fix/msteams-inline-images
Closed

fix(msteams): fix inline pasted image downloads#10902
jlian wants to merge 1 commit intoopenclaw:mainfrom
jlian:fix/msteams-inline-images

Conversation

@jlian
Copy link
Copy Markdown

@jlian jlian commented Feb 7, 2026

Fixes #5448

Problem

Inline pasted images in MS Teams (clipboard paste, not drag-and-drop file attachments) were silently dropped, and the gateway never received the image bytes.

Root Cause

Four independent bugs in the MSTeams extension's media download pipeline:

1. Bot Framework attachment URLs return JSON metadata, not binary content

Teams sends pasted images as attachments with Bot Framework URLs like:

https://smba.trafficmanager.net/.../v3/attachments/{id}

Fetching that bare URL returns a JSON metadata envelope. The binary lives at /views/original:

https://smba.trafficmanager.net/.../v3/attachments/{id}/views/original

Fix: Added isBotFrameworkAttachmentUrl() regex helper and /views/original suffix in download.ts. Trailing slashes are stripped before appending.

2. trafficmanager.net missing from auth host allowlist

fetchWithAuthFallback checks DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST before retrying with a Bearer token on 401 responses. trafficmanager.net (used by smba.trafficmanager.net Bot Framework service URLs) was not listed, so auth fallback was silently skipped.

Fix: Added trafficmanager.net to DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST in shared.ts.

3. Inbound media gate required ALL attachments to be text/html

The HTML-attachment gate used every(), requiring all attachments to be text/html before triggering the Graph API fallback (Tier 2). Teams sends mixed types (image/* + text/html) for pasted images, so the condition never matched.

Fix: Changed every()some() and renamed onlyHtmlAttachmentshasHtmlAttachments in inbound-media.ts.

4. Graph API hostedContents collection returns contentBytes: null

downloadGraphHostedContent only read contentBytes from the collection response, which is always null per Microsoft docs:

Note: contentBytes and contentType are always set to null.

The binary is available via the individual $value endpoint:

GET .../hostedContents/{id}/$value → 200 OK, content-type: image/png, <binary body>

Fix: Added $value endpoint fetch with Bearer auth as fallback when contentBytes is null in graph.ts. Kept the contentBytes fast path in case Microsoft starts populating it in the future.

Changes

File Change
extensions/msteams/src/attachments/download.ts isBotFrameworkAttachmentUrl() + /views/original URL rewriting
extensions/msteams/src/attachments/shared.ts trafficmanager.net added to auth allowlist
extensions/msteams/src/attachments/graph.ts $value endpoint fetch for hosted content
extensions/msteams/src/monitor-handler/inbound-media.ts every()some() for HTML gate
extensions/msteams/src/attachments.test.ts 4 new tests + updated existing tests
CHANGELOG.md Fix entry

Testing

  • Unit tests: 22/22 pass, including 4 new tests:
    • appends /views/original to Bot Framework attachment URLs
    • uses auth fallback for Bot Framework 401 responses
    • downloads hostedContents images via $value endpoint
    • skips hosted content when $value fetch fails
  • Live test: Pasted image in Teams chat → gateway downloaded (2025×1525 PNG), resized, and dispatched to agent successfully
  • Gate: pnpm build && pnpm check && pnpm test all pass

Greptile Overview

Greptile Summary

  • Fixes MSTeams inline pasted image handling by rewriting Bot Framework attachment URLs to fetch binary bytes via /views/original.
  • Expands the media auth allowlist to include trafficmanager.net, enabling Bearer-token retry when Bot Framework URLs return 401/403.
  • Adjusts inbound media Tier-2 (Graph) fallback gating to trigger when any text/html attachment is present (mixed attachment types).
  • Updates Graph hosted content download to fetch bytes from hostedContents/{id}/$value when collection contentBytes is null, with accompanying unit tests.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk.
  • Changes are narrowly scoped to MS Teams media download paths, include targeted unit tests for each regression, and preserve existing behavior via fast paths and allowlist checks.
  • No files require special attention

(4/5) You can add custom instructions or style guidelines for the agent here!

@openclaw-barnacle openclaw-barnacle bot added channel: msteams Channel integration: msteams docs Improvements or additions to documentation agents Agent runtime and tooling labels Feb 7, 2026
@jlian jlian force-pushed the fix/msteams-inline-images branch from 7062e84 to e27e7b3 Compare February 7, 2026 23:39
@openclaw-barnacle openclaw-barnacle bot removed docs Improvements or additions to documentation agents Agent runtime and tooling labels Feb 7, 2026
@jlian jlian force-pushed the fix/msteams-inline-images branch 3 times, most recently from bac5092 to 65dc440 Compare February 9, 2026 04:04
@jlian jlian force-pushed the fix/msteams-inline-images branch from 65dc440 to ad144dd Compare February 10, 2026 16:23
Four bugs prevented clipboard-pasted images from being received:

1. Bot Framework attachment URLs return JSON metadata, not binary content.
   Append /views/original to retrieve the actual image bytes.
2. trafficmanager.net was missing from DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST.
3. Inbound-media gate used every() but Teams sends mixed types for pasted
   images. Changed to some().
4. downloadGraphHostedContent only read contentBytes (always null for large
   images). Added fallback to fetch individual hostedContents endpoint.
@jlian jlian force-pushed the fix/msteams-inline-images branch from ad144dd to 4aac091 Compare February 18, 2026 21:46
jlian added a commit to jlian/openclaw that referenced this pull request Feb 18, 2026
…base)

Four bugs prevented clipboard-pasted images from being received:

1. Bot Framework attachment URLs return JSON metadata, not binary content.
   Append /views/original to retrieve the actual image bytes.
2. trafficmanager.net was missing from DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST.
3. Inbound-media gate used every() but Teams sends mixed types for pasted
   images. Changed to some().
4. downloadGraphHostedContent only read contentBytes (always null for large
   images). Added fallback to fetch individual hostedContents endpoint.
jlian added a commit to jlian/openclaw that referenced this pull request Feb 19, 2026
…base)

Four bugs prevented clipboard-pasted images from being received:

1. Bot Framework attachment URLs return JSON metadata, not binary content.
   Append /views/original to retrieve the actual image bytes.
2. trafficmanager.net was missing from DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST.
3. Inbound-media gate used every() but Teams sends mixed types for pasted
   images. Changed to some().
4. downloadGraphHostedContent only read contentBytes (always null for large
   images). Added fallback to fetch individual hostedContents endpoint.
jlian added a commit to jlian/openclaw that referenced this pull request Feb 19, 2026
…base)

Four bugs prevented clipboard-pasted images from being received:

1. Bot Framework attachment URLs return JSON metadata, not binary content.
   Append /views/original to retrieve the actual image bytes.
2. trafficmanager.net was missing from DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST.
3. Inbound-media gate used every() but Teams sends mixed types for pasted
   images. Changed to some().
4. downloadGraphHostedContent only read contentBytes (always null for large
   images). Added fallback to fetch individual hostedContents endpoint.
jlian added a commit to jlian/openclaw that referenced this pull request Feb 20, 2026
…base)

Four bugs prevented clipboard-pasted images from being received:

1. Bot Framework attachment URLs return JSON metadata, not binary content.
   Append /views/original to retrieve the actual image bytes.
2. trafficmanager.net was missing from DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST.
3. Inbound-media gate used every() but Teams sends mixed types for pasted
   images. Changed to some().
4. downloadGraphHostedContent only read contentBytes (always null for large
   images). Added fallback to fetch individual hostedContents endpoint.
jlian added a commit to jlian/openclaw that referenced this pull request Feb 20, 2026
…base)

Four bugs prevented clipboard-pasted images from being received:

1. Bot Framework attachment URLs return JSON metadata, not binary content.
   Append /views/original to retrieve the actual image bytes.
2. trafficmanager.net was missing from DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST.
3. Inbound-media gate used every() but Teams sends mixed types for pasted
   images. Changed to some().
4. downloadGraphHostedContent only read contentBytes (always null for large
   images). Added fallback to fetch individual hostedContents endpoint.
@steipete
Copy link
Copy Markdown
Contributor

Closing as AI-assisted stale-fix triage.

Linked issue #5448 ("MSTeams: hostedContents collection response missing contentBytes - images not downloaded in group chats") is currently CLOSED and was closed on 2026-02-19T04:13:02Z with state reason NOT_PLANNED.
Given that issue state, this fix PR is no longer needed in the active queue and is being closed as stale.

If the underlying bug is still reproducible on current main, please reopen this PR (or open a new focused fix PR) and reference both #5448 and #10902 for fast re-triage.

@steipete
Copy link
Copy Markdown
Contributor

Closed after AI-assisted stale-fix triage (closed issue duplicate/stale fix).

@steipete steipete closed this Feb 24, 2026
jlian added a commit to jlian/openclaw that referenced this pull request Feb 28, 2026
…base)

Four bugs prevented clipboard-pasted images from being received:

1. Bot Framework attachment URLs return JSON metadata, not binary content.
   Append /views/original to retrieve the actual image bytes.
2. trafficmanager.net was missing from DEFAULT_MEDIA_AUTH_HOST_ALLOWLIST.
3. Inbound-media gate used every() but Teams sends mixed types for pasted
   images. Changed to some().
4. downloadGraphHostedContent only read contentBytes (always null for large
   images). Added fallback to fetch individual hostedContents endpoint.
jlian added a commit to jlian/openclaw that referenced this pull request Mar 18, 2026
jlian added a commit to jlian/openclaw that referenced this pull request Mar 18, 2026
jlian added a commit to jlian/openclaw that referenced this pull request Mar 18, 2026
@jlian
Copy link
Copy Markdown
Author

jlian commented Mar 18, 2026

@steipete issue still repros with latest stable. Opened a new issue as per original issue closure reason #50043 and also opened a new focused fix PR at #50044

jlian added a commit to jlian/openclaw that referenced this pull request Mar 18, 2026
jlian added a commit to jlian/openclaw that referenced this pull request Mar 18, 2026
jlian added a commit to jlian/openclaw that referenced this pull request Mar 18, 2026
jlian added a commit to jlian/openclaw that referenced this pull request Mar 18, 2026
jlian added a commit to jlian/openclaw that referenced this pull request Mar 18, 2026
jlian added a commit to jlian/openclaw that referenced this pull request Mar 19, 2026
jlian added a commit to jlian/openclaw that referenced this pull request Mar 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: msteams Channel integration: msteams size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MSTeams: hostedContents collection response missing contentBytes - images not downloaded in group chats

2 participants