Skip to content

Route threaded replies through Bot Framework reply endpoint - #586

Open
Mehak Bindra (MehakBindra) wants to merge 10 commits into
mainfrom
mehakbindra-python-threading-endpoints
Open

Route threaded replies through Bot Framework reply endpoint#586
Mehak Bindra (MehakBindra) wants to merge 10 commits into
mainfrom
mehakbindra-python-threading-endpoints

Conversation

@MehakBindra

@MehakBindra Mehak Bindra (MehakBindra) commented Sep 1, 2026

Copy link
Copy Markdown
Member

Summary

  • route L2 group-chat and channel placement through Bot Framework reply endpoints while retaining L1 sends
  • add explicit regular and targeted conversation reply APIs; targeted L2 replies use POST /v3/conversations/{conversationId}/activities/{rootMessageId}?isTargetedActivity=true
  • infer targeted delivery from outbound recipient metadata in proactive App.reply() and reactive ActivityContext.send(), including targeted activities placed in existing threads
  • preserve proactive callers by translating valid legacy ;messageid= conversation IDs internally
  • expose typed, read-only inbound channelData.thread.id and apply the reactive personal/group-chat/channel scope matrix
  • keep placement independent from explicit MessageActivityInput.add_quote() metadata and preserve quote payloads on targeted replies
  • omit transport-only from and conversation fields from outbound payloads, matching .NET and preventing targeted quoted channel replies from being placed at L1
  • accept successful reply responses that omit an activity ID, as observed from APX for regular L2 replies
  • update the interacting-with-messages sample with default send, proactive thread, quote, targeted, and targeted+quote cases

Compatibility

Existing regular reply APIs and public send/reply signatures remain supported. Legacy threaded conversation IDs are translated before reaching APX, and the legacy constructor plus quote/reply conveniences are deprecated without changing runtime behavior. Personal-chat targeted restrictions remain unchanged. Transport routing remains in the endpoint/conversation reference rather than duplicated in serialized activity payloads.

Validation

  • 1,190 API/apps tests passed (wheel build test exercised separately by the successful package build)
  • focused targeted/reply/outbound payload suites passed
  • uv run poe check
  • uv run pyright
  • uv build --all-packages
  • echo sample startup smoke test
  • live channel validation: proactive targeted + quote remains in the selected thread

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings September 1, 2026 19:58

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

App.reply() currently rejects non-numeric thread root IDs, which blocks proactive thread placement for valid non-numeric roots (e.g., IDs coming from inbound channelData.thread.id / activity IDs).

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR updates the Teams Python SDK’s outbound message routing so that threaded placement (L2 group-chat and channel threads) uses the Bot Framework reply endpoint (POST /v3/conversations/{conversationId}/activities/{rootMessageId}) while keeping L1 sends on the standard create-activity endpoint. It also preserves compatibility for proactive callers that still pass legacy ;messageid=-suffixed conversation IDs by translating them internally.

Changes:

  • Add thread_root_id routing to the shared send path and route replies via conversations.reply_to_activity(...) when present.
  • Introduce parsing for legacy ;messageid= conversation IDs and use inbound channelData.thread.id (typed as ThreadInfo) to determine reactive thread placement.
  • Update API client reply behavior to use the reply endpoint (path-based root ID) and adjust examples/tests accordingly.
File summaries
File Description
packages/apps/tests/test_app.py Updates app-level tests to assert reply endpoint usage and legacy ID translation behavior.
packages/apps/tests/test_activity_context.py Adds coverage for reactive thread placement matrix (personal vs groupChat vs channel).
packages/apps/src/microsoft_teams/apps/utils/thread.py Adds legacy threaded conversation ID parsing and deprecates to_threaded_conversation_id.
packages/apps/src/microsoft_teams/apps/utils/init.py Keeps exporting deprecated threading helper with pyright suppression.
packages/apps/src/microsoft_teams/apps/routing/activity_context.py Computes thread root from inbound metadata / legacy suffix and threads sends via new routing.
packages/apps/src/microsoft_teams/apps/app.py Translates legacy suffixed IDs for proactive sends and adds explicit thread-root send path.
packages/apps/src/microsoft_teams/apps/activity_send.py Routes non-targeted sends via reply endpoint when thread_root_id is provided.
packages/apps/src/microsoft_teams/apps/init.py Maintains deprecated threading helper export with pyright suppression.
packages/api/tests/unit/test_empty_inbound_objects.py Adds test ensuring inbound channelData.thread.id is typed and read-only.
packages/api/tests/unit/test_conversation_client.py Updates unit tests to validate reply endpoint URL and payload semantics (no replyToId).
packages/api/src/microsoft_teams/api/models/channel_data/thread_info.py Introduces ThreadInfo model for inbound thread metadata.
packages/api/src/microsoft_teams/api/models/channel_data/channel_data.py Adds `ChannelData.thread: ThreadInfo
packages/api/src/microsoft_teams/api/models/channel_data/init.py Exports ThreadInfo.
packages/api/src/microsoft_teams/api/clients/conversation/activity.py Changes activities.reply(...) to POST to /activities/{activity_id} without replyToId in payload.
examples/interacting-with-messages/src/threading_handlers.py Updates sample to use app.reply(...) and inbound thread metadata rather than legacy threaded IDs.
examples/interacting-with-messages/README.md Updates sample documentation to reflect deprecations and new thread-manual behavior.
Review details
  • Files reviewed: 16/16 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 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/app.py
@MehakBindra
Mehak Bindra (MehakBindra) marked this pull request as draft September 1, 2026 20:10
@MehakBindra
Mehak Bindra (MehakBindra) marked this pull request as ready for review September 1, 2026 20:25
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a61da459-b09d-412b-9dd1-1310f6dfd42d
return True


def _thread_reference(ctx: ActivityContext[MessageActivity]) -> tuple[str, str]:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

should we consider offering this as apart of the SDK? vs having them write a helper fn

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

Copilot-Session: a61da459-b09d-412b-9dd1-1310f6dfd42d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a61da459-b09d-412b-9dd1-1310f6dfd42d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a61da459-b09d-412b-9dd1-1310f6dfd42d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a61da459-b09d-412b-9dd1-1310f6dfd42d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a61da459-b09d-412b-9dd1-1310f6dfd42d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a61da459-b09d-412b-9dd1-1310f6dfd42d
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: a61da459-b09d-412b-9dd1-1310f6dfd42d
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