fix(apps): source informative textFormat from the update + add textFormat to update() - #784
Merged
Merged
Conversation
…ities
HttpStream rebuilds outbound wire activities (TypingActivityInput chunks and
the final MessageActivityInput) from scratch each flush/close cycle. It
already carries forward attachments, entities, suggested actions, and
channelData from the last emitted message ("last message wins"), but did not
carry forward textFormat, so `stream.emit({ type: "message", text,
textFormat: "extendedmarkdown" })` was silently dropped from every
intermediate typing chunk and the final message. The timeout/plain-final
fallback (sendFinal) had the same gap.
- Model textFormat on ITypingActivity/TypingActivityInput (previously only
modeled on message activities), with a withTextFormat() builder method,
mirroring MessageActivityInput.
- HttpStream now reads the last emitted message's textFormat off
this.finalActivity (the existing last-message-wins state) and applies it to
every cumulative typing chunk, informative typing updates, the normal final
message, and the timed-out plain-final fallback.
- Add unit tests covering textFormat propagation across intermediate chunks,
the final message, and the timeout fallback.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…mple Adds an 'extended-markdown' trigger that streams a release-status update where each delta sets textFormat: 'extendedmarkdown', so task lists and strikethrough render while streaming. Also trims verbose textFormat comments per review feedback. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0073e3f0-b7b4-464a-9bdf-30f97d8081ec
…Format to update() Informative streaming updates now read textFormat from the update itself instead of the not-yet-set finalActivity, and IStreamer.update()/HttpStream.update() accept an optional nullable textFormat forwarded onto the informative typing activity. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0073e3f0-b7b4-464a-9bdf-30f97d8081ec
# Conflicts: # examples/stream/src/index.ts # packages/apps/src/http/http-stream.spec.ts # packages/apps/src/http/http-stream.ts
…am sample style Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0073e3f0-b7b4-464a-9bdf-30f97d8081ec
… normalization) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0073e3f0-b7b4-464a-9bdf-30f97d8081ec
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes how textFormat is handled for streamed informative typing updates in HttpStream, and extends the streaming API so update() can explicitly control formatting without requiring callers to hand-build a typing activity.
Changes:
- Fix
HttpStream.flush()to source informative updatetextFormatfrom the informative update itself (instead offinalActivity). - Extend
IStreamer.update()/HttpStream.update()to accept an optional, nullabletextFormat. - Add unit tests covering informative
textFormatbehavior and the newupdate()overload; update the streaming example to use the overload.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/apps/src/types/streamer.ts | Extends the IStreamer.update() signature and documents textFormat semantics. |
| packages/apps/src/http/http-stream.ts | Implements update(text, textFormat?) and fixes informative update textFormat sourcing in flush(). |
| packages/apps/src/http/http-stream.spec.ts | Adds tests for informative textFormat and the new update() overload behavior. |
| examples/stream/src/index.ts | Updates the extended-markdown sample to use the new update() overload and refreshes sample deltas. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…escribing Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0073e3f0-b7b4-464a-9bdf-30f97d8081ec
…OWN_MESSAGES Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0073e3f0-b7b4-464a-9bdf-30f97d8081ec
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 0073e3f0-b7b4-464a-9bdf-30f97d8081ec
Kavin (singhk97)
added a commit
to microsoft/teams.py
that referenced
this pull request
Aug 31, 2026
…format to update() Port of microsoft/teams.ts#784 (follow-up to #762). - HttpStream._flush() no longer overwrites an informative update's own text_format with the last emitted message's format; informative chunks now keep the value set on the update itself. - StreamerProtocol.update / HttpStream.update gain an optional text_format arg so informative updates can carry a format without hand-building a typing activity. - examples/stream: refresh the extended-markdown scenario and use the new update(text, 'markdown') overload. - Tests for informative-update format independence and the update() overload. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Lily Du (lilyydu)
approved these changes
Sep 1, 2026
Kavin (singhk97)
added a commit
to microsoft/teams.py
that referenced
this pull request
Sep 1, 2026
…vities (#581) ## Summary Ports [microsoft/teams.ts#762](microsoft/teams.ts#762) and its follow-up [#784](microsoft/teams.ts#784) to the Python SDK. On every `flush()`, `HttpStream` rebuilds the outbound typing chunk and forwards the last emitted message's attachments, entities, suggested actions, and channel data ("last message wins" via `self._final_activity`) — but not `text_format`. So `stream.emit(MessageActivityInput(text=...).with_text_format("extendedmarkdown"))` was dropped from every intermediate chunk, and streamed Extended Markdown (task lists, strikethrough) rendered as plain markdown until the message closed. The final message and timeout fallback (`_send_final`) already preserved `text_format`, since they reuse the real `_final_activity` object rather than rebuilding a copy (unlike TS). Only the streamed chunks needed fixing. ## Changes - Add `text_format` + a `with_text_format()` builder to `_TypingBase` (shared by `TypingActivity` / `TypingActivityInput`), mirroring `MessageActivityInput`. - `HttpStream._flush()` applies the last emitted message's `text_format` to the combined streamed-text chunk (last-message-wins). - **Informative updates keep their own `text_format`.** `_flush()` previously overwrote each informative update's format with `_final_activity.text_format`; it now leaves the update's own value intact (`_final_activity` isn't even set when informative updates are sent). - **`update()` gains an optional `text_format`.** `StreamerProtocol.update` / `HttpStream.update` now accept `text_format`; `None` → Teams default (`markdown`), an explicit value → that format. Previously the only way to format an informative update was to hand-build a typing activity and `emit()` it. - `examples/stream`: refresh the `extended-markdown` scenario and demo the new `update(text, "markdown")` overload. - Unit tests for `text_format` on typing activities, its propagation across streamed chunks / final message / timeout fallback, informative-update format independence (red/green against the old overwrite), and the `update()` overload. ## Testing - `ruff format --check`, `ruff check`, `pyright`, `pytest packages` (1107 passed) — all pass. - Verified live in Teams: streaming a message with `text_format="extendedmarkdown"` renders task lists and strikethrough on each intermediate chunk. _Created from a [Microsoft Teams conversation](https://teams.microsoft.com/l/message/19%3AeXvmZeTKJ1Myy2_qfz4vp4-YjeIqCMJ4xF6poI2GxtU1%40thread.tacv2/1787691375435?tenantId=72f988bf-86f1-41af-91ab-2d7cd011db47&groupId=1314f851-c930-4caa-b3e0-dbe9b8fe2737&parentMessageId=1787691375435)._ --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Kavin Singh <kavinsingh@microsoft.com> Co-authored-by: Kavin <115390646+singhk97@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #762. Two fixes for
textFormaton streamed informative updates:Source informative
textFormatfrom the update itself. InHttpStream.flush(), informative typing chunks previously took their format fromthis.finalActivity?.textFormat. ButfinalActivityis only set once a message is drained from the queue — which happens after informative updates are collected — so an informative update's owntextFormatwas ignored. It now readsinformativeUpdate.textFormatdirectly. The streamed-text chunk keeps its correct last-emitted-message-wins behavior.update()can now carry atextFormat.IStreamer.update(text)/HttpStream.update(text)gain an optional, nullabletextFormat:undefined/null→ Teams default (markdown); an explicit value (e.g.extendedmarkdown) → that format. Previously the only way to format an informative update was to hand-build a{ type: 'typing', ..., textFormat }object and callemit().Sample
examples/streamdemonstrates the newupdate()overload and cleans up theextended-markdownscenario's deltas to match the existing sample style while showcasing checkboxes andstrikethrough.Tests
Added to
http-stream.spec.ts:textFormat, independent offinalActivity(red/green — fails against the oldfinalActivity-sourced logic)update(text, 'extendedmarkdown')sends an informative chunk with that formatupdate(text)andupdate(text, null)omittextFormatAll apps tests pass (648/648), build + eslint clean.
Cross-language
Counterpart PRs (not yet merged) will fold in the equivalent changes: