Skip to content

[Teams Chatbot] Enable image input through Teams connector downloads - #17428

Open
Jialin Huang (JialinHuang803) wants to merge 19 commits into
mainfrom
jialinhuang/teams-image-recognition
Open

Jialin Huang (JialinHuang803) wants to merge 19 commits into
mainfrom
jialinhuang/teams-image-recognition

Conversation

@JialinHuang803

@JialinHuang803 Jialin Huang (JialinHuang803) commented Oct 29, 2026 •

Copy link
Copy Markdown
Member

Summary

Enable the Teams chatbot to use inline screenshots when answering channel messages.
Addresses Azure/azure-sdk-pr#2316.

The Logic App downloads images through its existing Teams connection; the backend receives image bytes and does not need Graph download permissions.
Image recognition happens in the hosted agent's vision-capable model.

Data flow: Teams HTML → image attachment URLs → connector downloads → base64 data URIs → frontend → backend → model input_image.

Changes by component

1. Backend: activity converter

services/activity_converter_service.py

  • Extract <img src> references from message HTML and add deduplicated image/* attachments to the Bot Framework activity.
  • Resolve relative URLs and verify that Graph hosted-content images belong to the source message, including thread replies.
  • Preserve the original message text and HTML attachment; do not download images at this stage.

2. Logic App: image downloads

pipelines/logicapp/template.json

  • Keep the existing text-based intention check before activity conversion and image downloading.
  • Send messages without image attachments directly to the bot.
  • For image-bearing messages, select the first four image attachments, then download their Graph hosted-content URLs through the Teams connector.
  • Use sequential loops and reset the download array per message to prevent batched messages from mixing image results.
  • Replace successful, size-bounded downloads with base64 data URIs; keep unresolved URLs when a download fails or exceeds the size guard.
  • Hide image-bearing payloads in action history and send the bot a complete JSON POST, without Logic Apps' chunked-upload protocol.

3. Frontend: Teams bot

src/index.ts, src/input/, src/models/RAGModel.ts, src/backend/rag.ts

  • Raise the JSON body limit to 30 MiB to accommodate four base64-encoded images plus activity metadata.
  • Forward connector-supplied data URIs through the existing prompt.images → additional_infos[].link contract.
  • Omit image bytes from activity/prompt/payload logs and avoid logging Axios request bodies on failures.
  • Exclude inline data URIs from Azure Table prompt storage without changing current-turn forwarding; retain remote image URLs.

4. Backend: chat service and image validation

services/chat_service.py, utils/teams_image.py

  • Accept connector-supplied data URIs without authentication or another download.
  • Enforce four image attempts per request and 5 MiB decoded per image, with strict base64, supported MIME-type, and file-signature checks.
  • Send valid images as Responses API input_image items, with guidance to treat instructions inside images as untrusted content.
  • Skip unavailable or excess images and add a notice instructing the model to disclose missing image context rather than guess.
  • Preserve the existing native Bot Framework download path, with bounded downloads and no redirects; do not download Graph or SharePoint URLs in the backend.

5. Teams manifest and environment tags

  • Update the manifest to schema 1.25 and declare supportsChannelFeatures: "tier1".
  • Update frontend image tags to dev-0.0.32, preprod-0.0.15, and prod-0.0.14.

Scope and limitations

  • Supported image types: PNG, JPEG, GIF, and WebP.
  • Uploaded SharePoint file attachments and forwarded images belonging to another message are not supported.
  • The four-image limit selects attachments in order; a failed download does not cause the fifth attachment to be substituted.
  • Inline image bytes are not retained in frontend Table Storage history or replayed from that stored prompt after recovery.
  • Latency: An image download takes approximately 3 seconds in observed testing; downloads are sequential, so posts containing images incur additional latency before bot processing begins, and the download time accumulates with each image. Actual timing varies.

Validation

  • Backend: 165 targeted tests passed across converter, image utility, and chat-service suites.
  • Frontend: 21 tests passed across the changed transport, prompt, and conversation suites; build succeeded, including after merging latest main.
  • Earlier dev testing confirmed a single-image connector-to-bot flow and successful replies.
  • The latest revisions, multiple-image messages, and partial download failures have not been reverified end to end in a live Teams flow.

Testing: Teams Post Teams Post
Logic app run history

Preserve Teams image attachments, download Graph hosted content through the Logic App Teams connection, and forward validated inline image bytes to Foundry. Handle payload size, logging, and conversation storage constraints.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

# Conflicts:
#	tools/sdk-ai-bots/azure-sdk-qa-bot-agent/tests/chat_service_test.py

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

HTTPX INFO logging exposes full preauthenticated SharePoint/OneDrive download URLs and their access-granting query parameters in backend logs despite the exception-logging safeguard.

1 open issue
What changed in this PR

Adds image context to the Teams QA bot’s answer-generation flow, using the existing Teams connector to download Graph-hosted images and forward them to Foundry.

Changes:

  • Preserves inline images and uploaded image references, with authenticated backend downloads as a fallback.
  • Adds image format validation, four-image and 5 MiB limits, and notices for unavailable image context.
  • Increases the bot’s request-body limit, reduces image payload logging, and excludes inline bytes from conversation storage.
File Description
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​test/​ragImages.test.ts Tests payload forwarding and log redaction.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​test/​promptGenerator.test.ts Tests connector-image prompt handling.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​test/​messageBodyParser.test.ts Tests request-body size limits.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​test/​logicAppImages.test.ts Tests connector download configuration and image preparation.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​test/​conversation.test.ts Tests inline-byte exclusion from storage and updates constructor mocks.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​src/​models/​RAGModel.ts Replaces image-bearing logs with summaries.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​src/​input/​PromptGenerator.ts Omits image URLs from raw-prompt logs.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​src/​input/​messageBodyParser.ts Defines the 30 MiB JSON parser.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​src/​input/​ConversationHandler.ts Excludes inline image bytes from stored prompts.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​src/​index.ts Enables the larger request-body parser.
tools/​sdk-ai-bots/​azure-sdk-qa-bot/​src/​backend/​rag.ts Redacts inline payloads and limits Axios error logging.
tools/​sdk-ai-bots/​azure-sdk-qa-bot-agent/​utils/​teams_image.py Validates image data and handles bounded authenticated downloads.
tools/​sdk-ai-bots/​azure-sdk-qa-bot-agent/​tests/​teams_image_test.py Covers authentication, validation, redirects, and image forwarding.
tools/​sdk-ai-bots/​azure-sdk-qa-bot-agent/​tests/​chat_service_test.py Tests model image content, limits, and failure notices.
tools/​sdk-ai-bots/​azure-sdk-qa-bot-agent/​tests/​activity_converter_service_test.py Tests image extraction, source validation, and deduplication.
tools/​sdk-ai-bots/​azure-sdk-qa-bot-agent/​services/​chat_service.py Enforces image-count limits and reports unavailable context.
tools/​sdk-ai-bots/​azure-sdk-qa-bot-agent/​services/​activity_converter_service.py Preserves supported inline and file-image attachments.
tools/​sdk-ai-bots/​azure-sdk-qa-bot-agent/​README.md Documents permissions, deployment, testing, and limitations.
tools/​sdk-ai-bots/​azure-sdk-qa-bot-agent/​pipelines/​logicapp/​template.json Downloads connector images and forwards data URIs with protected action history.

Review effort: Balanced

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace foreach result aggregation with four guarded download slots, preserving secure image payloads through direct capture outputs. Continue after failed or unused slots and cover the secured-output topology with regression tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep image preparation in one scope, start all four guarded downloads after filtering, and join direct secured capture outputs. Gate bot invocation on successful activity preparation so failed downloads do not block a ready reply.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Invoke the bot directly after successful image preparation while retaining partial download fallback and secured HTTP inputs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Check converted attachments before entering image processing, and send non-image activities directly to the bot with secured request inputs.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

This branch has not been deployed

No deployments
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.

4 participants