Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

Sync wave from `chat@4.31.0` to `chat@4.41.1` (tracking #184). `UPSTREAM_PARITY` stays `4.31.0` until #203.

- **Teams outbound: reactions, targeted ephemeral messages, placeholder-aware native streaming** (#219). Ports vercel/chat `5eb8b846` (#734), `160140e3` (#737) and `93a58af5` (#709) from chat@4.35.0, and `85089037` (#951, chat@4.41.0). A live Teams check is pending.
- **Consumer-visible (Teams):** `add_reaction` / `remove_reaction` now call the Teams conversations reactions API instead of logging a warning, and can raise (`AuthenticationError`, `AdapterPermissionError`, `NetworkError`, `AdapterRateLimitError`). `check`, `eyes`, `pin`, `rocket`, `thinking`, `thumbs_up` and `x` map to their Teams IDs; any other name is sent as a native Teams reaction ID (`like`, `heart`, `1f440_eyes`, ...).
- **Consumer-visible (Teams):** `TeamsAdapter.post_ephemeral` is new. In channels and group chats, `thread.post_ephemeral(user, ...)` now sends a native targeted message that only `user` sees (`used_fallback=False`), instead of opening a DM. The app must be installed in that conversation. In a 1:1 chat it posts normally with `used_fallback=True`. Edits and deletes of a targeted message go through the targeted endpoint: the sent id is recorded in the state adapter under `teams:targetedActivity:{conversationId}:{messageId}` for 24 hours (the key upstream uses), and state errors fall back to the plain endpoint.
- **Consumer-visible (Teams streaming):** only apps that set `fallback_streaming_placeholder_text` explicitly see a change. In a DM with a native streamer, the placeholder is sent as the Teams informative status line before the first chunk. In group chats, channels and proactive messages, `TeamsAdapter.stream()` returns `None`, so core posts the placeholder and edits it as text arrives, instead of posting one buffered message. `""` counts as set. Unset or `None` keeps the previous behaviour exactly. `TeamsAdapter.stream()` now returns `RawMessage | None`.
- **Python-specific (divergence from upstream):** a reaction ID that is not `[A-Za-z0-9_-]+` raises `ValidationError` before any request, because the Python SDK puts it in the URL path unescaped. `_stream_via_emit` waits at most 30 s (`STREAM_FIRST_CHUNK_ID_TIMEOUT_S`) for the first chunk's id, then settles the stream and, if nothing was delivered and the user did not cancel, posts the accumulated text as one ordinary message: on `microsoft-teams-apps` 2.0.16+, a terminal 403 on the first flush (for example "Content stream is not allowed") never delivers a chunk and never sets `canceled`, so the wait used to hang the DM handler, and the reply was never delivered. See `docs/UPSTREAM_SYNC.md`.
- Works on `microsoft-teams-apps` 2.0.13 to 2.1: reactions use `conversations.add_reaction` / `delete_reaction` where the SDK has them (2.0.16+) and `ApiClient.reactions` otherwise.
- **Turn cancellation, typing lifecycle and agent-session events** (#201; core half of vercel/chat `2ce2be00` #862, chat@4.39.0). No default behavior change: state polling runs only for adapters that set `supports_turn_cancellation` (none in-repo yet; Slack lands in #215).
- **New `thread.signal`** (a `TurnSignal`: `aborted`, `await signal.wait()`, `add_listener(cb)`), aborted when the turn is stopped. Pass it to model calls so a stop also stops generation. Streams posted from the turn stop being consumed when it is aborted: the reply is finalized with what was already streamed, and the source generator is closed. Outside a message handler the signal is never aborted.
- **New `chat.abort_turn(thread_id)`**: aborts the thread's running turn in this process and, when the turn's adapter opted in, in any process sharing the state backend (`active-turn:` / `abort-turn:` keys, 1 h TTL, polled every 250 ms per running turn).
Expand Down
Loading
Loading