Prompt Preview Support#397
Prompt Preview Support#397ShanmathiMayuramKrithivasan wants to merge 4 commits intomicrosoft:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Adds “prompt preview” support so bots can reference an original targeted message by attaching a targetedMessageInfo entity (with the original message ID) to outgoing activities, enabling Teams to render a collapsible prompt preview.
Changes:
- Introduces
TargetedMessageInfoEntityto the API models and exports it via the entity model surface. - Auto-attaches
TargetedMessageInfoEntity(message_id=<incoming.id>)inActivityContext.send()when handling an inbound targeted message (unless already provided by the developer). - Adds unit tests and extends the targeted-messages example to demonstrate reactive and proactive usage.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/apps/src/microsoft_teams/apps/routing/activity_context.py | Auto-adds targetedMessageInfo entity during send for targeted inbound activities. |
| packages/apps/tests/test_activity_context.py | Adds tests validating auto-population, non-targeted behavior, and no-duplication. |
| packages/api/src/microsoft_teams/api/models/entity/targeted_message_info_entity.py | Defines the new entity model with type and message_id. |
| packages/api/src/microsoft_teams/api/models/entity/entity.py | Extends the Entity union to include TargetedMessageInfoEntity. |
| packages/api/src/microsoft_teams/api/models/entity/init.py | Exports TargetedMessageInfoEntity from the entity package. |
| packages/api/tests/unit/test_targeted_message_info_entity.py | Adds unit tests for default type, field behavior, and camelCase serialization. |
| examples/targeted-messages/src/main.py | Adds example commands demonstrating prompt preview usage (reactive/proactive). |
| @pytest.mark.asyncio | ||
| async def test_send_does_not_add_entity_for_non_message_activity(self) -> None: | ||
| """Non-message activities (e.g. typing) should not get targetedMessageInfo attached.""" | ||
| from microsoft_teams.api.activities.typing import TypingActivityInput |
There was a problem hiding this comment.
nit: can we move all these nested imports to top level?
| else: | ||
| activity = message | ||
|
|
||
| self._auto_add_targeted_message_info(activity) |
There was a problem hiding this comment.
can we add a check here if its a targeted msg first, otherwise all activities will be routed
| and attaches the entity automatically so the developer doesn't need to. | ||
| Skips if the developer already attached a targetedMessageInfo entity. | ||
| """ | ||
| incoming = self.activity |
There was a problem hiding this comment.
nits:
rename method to add_targeted_message_info_entity
instead of incoming, rename to activity (and change method param to activity_params) or something similiar
rename already_has to targeted_msg_info_entities or something alike
|
also curious, what does the UI look like for this? |
| def _auto_add_targeted_message_info(self, activity: ActivityParams) -> None: | ||
| """Auto-populate targetedMessageInfo entity when replying to a targeted message. | ||
|
|
||
| In the reactive flow, the SDK reads the incoming targeted message ID | ||
| and attaches the entity automatically so the developer doesn't need to. | ||
| Skips if the developer already attached a targetedMessageInfo entity. | ||
| """ | ||
| incoming = self.activity | ||
| if not (hasattr(incoming, "recipient") and hasattr(incoming.recipient, "is_targeted")): | ||
| return | ||
| if incoming.recipient.is_targeted is not True: | ||
| return | ||
| if not isinstance(activity, MessageActivityInput): | ||
| return | ||
|
|
||
| already_has = any(isinstance(e, TargetedMessageInfoEntity) for e in (activity.entities or [])) | ||
| if not already_has: | ||
| activity.add_entity(TargetedMessageInfoEntity(message_id=incoming.id)) |
There was a problem hiding this comment.
Also scan activity.entities for any entity with type == "quotedReply" targeting incoming.id, and scan activity.text for a matching <quoted messageId="<tm-id>"/> placeholder. If either is found, strip both and log. Per §6.1 of the prompt preview design, PP owns the preview surface for targeted message flows and qtdMsgs must not be set. Using the string "quotedReply" avoids taking a dependency on the quoted replies PR, which has not landed on main.
| from ..custom_base_model import CustomBaseModel | ||
|
|
||
|
|
||
| class TargetedMessageInfoEntity(CustomBaseModel): |
There was a problem hiding this comment.
No preview marker on this class. For parity with Account.is_targeted (field-level .. warning:: Preview docstring at account.py:36-40) and the SDK's @experimental("ExperimentalTeamsTargeted") decorator at packages/common/src/microsoft_teams/common/experimental.py:23-76, one of these should be added since the surface depends on the still-preview targeted messages feature.
| from ..custom_base_model import CustomBaseModel | ||
|
|
||
|
|
||
| class TargetedMessageInfoEntity(CustomBaseModel): |
There was a problem hiding this comment.
A parallel add_targeted_message_info(message_id: str) on MessageActivity would match the other add_* helpers and the TS addTargetedMessageInfo already in this PR. Gives a single home for the §1 P0 "one PP per message" dedup plus the usage docstring.
Prompt preview allows a bot to reference the original targeted message in its reply, so Teams can render a collapsible preview of the user's prompt.
When a bot replies to a targeted message (reactive scenarios), the SDK now passes the original message's messageId via a targetedMessageInfo entity in the activity's entities array.
For proactive replies, developers can attach the entity themselves with the messageId of the targeted message.