Skip to content

Implement ReactionClient for message reactions API#280

Open
Copilot wants to merge 9 commits intomainfrom
copilot/implement-reactions-feature
Open

Implement ReactionClient for message reactions API#280
Copilot wants to merge 9 commits intomainfrom
copilot/implement-reactions-feature

Conversation

Copy link
Contributor

Copilot AI commented Feb 17, 2026

Implementation Complete: Reactions API Client

Based on teams.net PR #335, successfully implemented ReactionClient for managing message reactions in Teams.

Tasks Completed

  • Create ReactionClient class in packages/api/src/microsoft_teams/api/clients/reaction/
    • Create reaction/init.py with exports
    • Create reaction/client.py with ReactionClient class
      • add() method - Add a reaction to an activity (PUT request)
      • delete() method - Remove a reaction from an activity (DELETE request)
  • Update packages/api/src/microsoft_teams/api/clients/init.py to export ReactionClient
  • Add reactions client to ApiClient class
  • Create unit tests in packages/api/tests/unit/test_reaction_client.py
  • Update mock_transport in conftest.py to handle reaction endpoints
  • Code passes linting (ruff check) ✅
  • Code passes formatting (ruff format) ✅
  • Code passes type checking (pyright) ✅
  • Code passes security scan (codeql) ✅ - 0 alerts
  • Implementation validated
  • Add example under examples/ showing ReactionClient usage
  • Address PR review feedback:
    • Fix docstring format in main.py (separate copyright and description)
    • Remove DevTools from example (not supported)
    • Add return statements to prevent control flow fall-through
    • Change README to use pip instead of uv
    • Add assertions to unit tests

Example: examples/reactions

Complete working example demonstrating the ReactionClient:

  • Bot responds to react <type> commands to add reactions
  • Bot responds to unreact <type> commands to remove reactions
  • Includes comprehensive README with setup and usage instructions
  • Properly structured with return statements to prevent fall-through

Security Summary

✅ CodeQL analysis completed - 0 security alerts found


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits February 17, 2026 22:41
Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>
Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>
Copilot AI changed the title [WIP] Implement reactions feature based on Teams PR 335 Implement ReactionClient for message reactions API Feb 17, 2026
Copilot AI requested a review from rido-min February 17, 2026 22:45
@rido-min
Copy link
Member

@copilot add one sample under examples/ to show how to use the new reaction client

Co-authored-by: rido-min <14916339+rido-min@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Feb 18, 2026

@copilot add one sample under examples/ to show how to use the new reaction client

Added example under examples/reactions/ showing how to use the ReactionClient (commit c4e1da2).

The example demonstrates:

  • Adding reactions with react <type> commands
  • Removing reactions with unreact <type> commands
  • All supported reaction types (like, heart, laugh, surprised, sad, angry, plusOne)

Run it with:

cd examples/reactions
uv run python src/main.py

@rido-min rido-min marked this pull request as ready for review February 23, 2026 16:42
Copilot AI review requested due to automatic review settings February 23, 2026 16:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a ReactionClient to the Microsoft Teams SDK for Python, enabling bots to programmatically add and remove message reactions via the Bot Framework v3 API. The implementation follows established patterns from similar clients like ConversationActivityClient.

Changes:

  • Implements ReactionClient with add() and delete() methods for managing message reactions
  • Integrates ReactionClient into ApiClient as the reactions property with HTTP client propagation
  • Adds comprehensive example bot demonstrating reaction functionality with commands like "react like" and "unreact like"

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/api/src/microsoft_teams/api/clients/reaction/client.py Core ReactionClient implementation with add/delete methods using Bot Framework v3 API endpoints
packages/api/src/microsoft_teams/api/clients/reaction/init.py Module exports for ReactionClient
packages/api/src/microsoft_teams/api/clients/api_client.py Integration of ReactionClient as reactions property with HTTP client propagation
packages/api/src/microsoft_teams/api/clients/init.py Exports ReactionClient from the clients package
packages/api/tests/unit/test_reaction_client.py Unit tests for ReactionClient initialization and methods
packages/api/tests/conftest.py Mock transport handler for reaction API endpoints
examples/reactions/src/main.py Example bot demonstrating reaction add/remove functionality
examples/reactions/pyproject.toml Project configuration for reactions example
examples/reactions/README.md Documentation for reactions example with usage instructions
uv.lock Lock file update to include reactions example package

Comment on lines +34 to +76
if text.startswith("react "):
reaction_type = text[6:].strip()

await ctx.api.reactions.add(
conversation_id=conversation_id,
activity_id=activity_id,
reaction_type=reaction_type,
)

await ctx.reply(f"✅ Added {reaction_type} reaction to your message!")
print(f"[REACTION] Added '{reaction_type}' to activity {activity_id}")

# ============================================
# Remove Reaction
# ============================================
if text.startswith("unreact "):
reaction_type = text[8:].strip()

await ctx.api.reactions.delete(
conversation_id=conversation_id,
activity_id=activity_id,
reaction_type=reaction_type,
)

await ctx.reply(f"✅ Removed {reaction_type} reaction from your message!")
print(f"[REACTION] Removed '{reaction_type}' from activity {activity_id}")

# ============================================
# Help / Default
# ============================================
if "help" in text:
await ctx.reply(
"**Message Reactions Bot**\n\n"
"**Commands:**\n"
"- `react <type>` - Add a reaction to your message\n"
"- `unreact <type>` - Remove a reaction from your message\n\n"
"- `react like` - Adds a 👍 to your message\n"
"- `unreact like` - Removes the 👍 from your message"
)
return

# Default
await ctx.reply('Say "help" for available commands, or try "react like"!')
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

The command parsing logic has a control flow issue. When a user sends "react like", both the "react " condition (line 34) and the "help" condition (line 64) will execute because there's no early return after the react/unreact handlers. This means every reaction command will also trigger the default help message.

Add a return statement after the react handler (after line 44) and after the unreact handler (after line 59) to prevent fall-through to subsequent conditions.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit 0888d25. Added return statements after both the react and unreact handlers to prevent fall-through to subsequent conditions.


```bash
cd examples/reactions
uv run python src/main.py
Copy link
Collaborator

Choose a reason for hiding this comment

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

suggesting pip instead of uv

Copy link
Member

Choose a reason for hiding this comment

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

pip or python?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit 0888d25. Updated README to use pip install -e . instead of uv run.


await client.add(conversation_id, activity_id, reaction_type)

# Verify the request was made to the correct URL
Copy link
Collaborator

Choose a reason for hiding this comment

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

should there be assertions here?

Copy link
Member

Choose a reason for hiding this comment

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

@copilot add the asserts here

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed in commit 0888d25. Added assertions to verify that the methods return None and complete without raising exceptions, following the pattern used in other client tests.


MessageReactionType = Union[Literal["like", "heart", "laugh", "surprised", "sad", "angry", "plusOne"], str]
MessageReactionType = Union[
Literal["like", "heart", "1f440_eyes", "2705_whiteheavycheckmark", "launch", "1f4cc_pushpin"], str
Copy link
Collaborator

Choose a reason for hiding this comment

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

@rido-min are these correct reaction types?

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