Skip to content

Commit 34314dd

Browse files
chore(release): cut 0.4.30 — Teams SDK migration + 4.30.0 parity (#93 PR 4/4) (#146)
* chore(release): cut 0.4.30 — Teams SDK migration + 4.30.0 parity (#93 PR 4/4) Final PR of the Teams SDK migration (issue #93). PRs 1-3 (inbound+auth, outbound, native streaming) are merged; this cuts the 0.4.30 release. - Version bump: pyproject 0.4.29 -> 0.4.30; UPSTREAM_PARITY "4.29.0" -> "4.30.0". - Fidelity re-pin chat@4.29.0 -> chat@4.30.0 in lint.yml + verify_test_fidelity.py (docstring, default parity fallback, clone hint). packages/chat/src is byte-for-byte identical between the two tags, so zero new test ports: strict fidelity stays 100% (732/732, 0 missing) against chat@4.30.0. Baseline regenerated (ts_parity -> chat@4.30.0; the recorded total_ts_tests literal 731 -> 732 corrects a stale count from the merged adapter waves, not the re-pin — the count is identical against both tags). - Docs: project-instructions version map + fidelity pin; README status line; CHANGELOG 0.4.30 entry (Twilio adapter, Telegram streaming, Slack subpaths, WhatsApp/Slack/gchat fixes, Teams #93 PRs 1-4); UPSTREAM_SYNC.md parity header + the Teams deferral row flipped to delivered. - Version-label normalization: malformed `adapter-teams@chat@4.30.0` and loose `adapter-teams@4.30.0` -> `@chat-adapter/teams@4.30.0` in adapter.py (5), bridge.py (1), UPSTREAM_SYNC.md (4). Comment/doc-only. Does NOT tag/publish — the release is a separate maintainer-gated step (live Teams 429 streaming check + PyPI authorization). * docs(release): clarify 0.4.30 core-parity wording + finish label normalization Review fast-follow for PR 4. The CHANGELOG now states the mapped core is content-identical *between the chat@4.29.0 and chat@4.30.0 upstream tags* (verified: thread.ts/types.ts/thread.test.ts and the full packages/chat/src tree are byte-identical) — the prior 'unchanged from 4.29.0' phrasing was accurate but misread as a claim about our code. Also sweeps the two remaining old-style `adapter-teams@chat@4.30.0` labels in the Teams test docstrings to the canonical `@chat-adapter/teams@4.30.0` npm tag, completing the normalization the PR's scope called for. No logic change. * docs(release): document 0.4.30 parity-audit wave + remaining exceptions CHANGELOG: add 'Pre-existing parity gaps closed (4.30 audit)' subsection covering the 7 ported fixes (PRs #147-#150) and a documented-exceptions note (Linear agent-sessions #151 deferred to 4.31 / #152; adapter-web and the GitHub/Linear native-client + message.subject halves stay Known Non-Parity). UPSTREAM_SYNC: - file-mapping table: add state-ioredis -> redis.py (IoRedisStateAdapter) and state-pg -> postgres.py rows (both ported + tested, were missing). - Known Non-Parity (platform gaps): add Linear agent-sessions row (#151) and an adapter-web row that splits the portable server-side WebAdapter (deferred) from the genuinely browser-only client subpaths, correcting the earlier over-broad 'browser-only; no Python runtime' note. - Correct the Google Chat file-uploads row: inbound attachment parsing is fully implemented (_create_attachment), so the gap is outbound file delivery only (post_message still logs 'not yet supported'). * docs(release): correct phantom-feature framing before PyPI cut CHANGELOG: - Drop false gchat file-delivery bullet (PR #112 never merged; upstream itself does not implement gchat outbound file delivery) - Fix Slack DM block-action citation to merged PR #137 (supersedes #133) - Re-point 0.4.27.1 vehicle from unmerged #120 to tag v0.4.27.1 + #117 - Drop numberless Twilio 'scaffolding PR' (only #142 exists) UPSTREAM_SYNC: - Reframe Google Chat outbound file delivery as parity (upstream also logs 'not yet supported' + media.upload TODO, index.ts:1282-1289) - Correct Teams cert-auth row: TS is not 'Supported' — config throws at startup in both SDKs (types.ts:31, config.ts:13); parity, issue #58 - Add Messenger get_user row: upstream has no getUser; raising stub is parity, Graph-API impl tracked as #132 * docs(changelog): clarify 0.4.30 audit-gap count (8 closed + 1 deferred = 9)
1 parent b4ea70d commit 34314dd

13 files changed

Lines changed: 74 additions & 37 deletions

File tree

.github/workflows/lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
- name: Clone upstream vercel/chat at pinned parity tag
6161
id: clone_upstream
6262
run: |
63-
git clone --depth 1 --branch chat@4.29.0 \
63+
git clone --depth 1 --branch chat@4.30.0 \
6464
https://github.com/vercel/chat.git /tmp/vercel-chat
6565
6666
- name: Test fidelity check (strict — zero missing in mapped core files)

CHANGELOG.md

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,49 @@
11
# Changelog
22

3-
## Unreleased
3+
## 0.4.30
44

5-
In flight toward `vercel/chat@4.30.0` (landing incrementally; `UPSTREAM_PARITY`
6-
stays `4.29.0` until the wave completes).
5+
Synced to upstream `vercel/chat@4.30.0`. The mapped core (`packages/chat/src`) is content-identical between the `chat@4.29.0` and `chat@4.30.0` upstream tags, so this wave is all adapter work: a **new Twilio adapter**, a **Telegram native-streaming** port, a **Slack primitives-subpath** wave, a batch of **WhatsApp / Slack / Google Chat** fixes, and the headline — the **Teams adapter migration to the official `microsoft-teams-apps` SDK** (issue #93, delivered across four PRs). Sets `UPSTREAM_PARITY = "4.30.0"`; CI fidelity re-pinned to `chat@4.30.0` (732/732 mapped-core tests still pass, 0 missing).
76

87
### New adapter: Twilio (SMS / MMS / Voice)
98

10-
- **`chat_sdk.adapters.twilio`** (vercel/chat#558). Twilio Programmable Messaging adapter (10th platform): inbound message webhooks with `X-Twilio-Signature` HMAC-SHA1 verification (`hmac.compare_digest`), outbound SMS/MMS through the Messages REST API (hand-rolled over an injectable transport — no official `twilio` SDK, mirroring upstream), 1:1 DM threads keyed `twilio:{sender}:{recipient}`, plus standalone `api` / `webhook` / `voice` helpers (TwiML builders, call + transcription parsing). New extra: `chat-sdk-python[twilio]`. Imports stay lazy so the package loads without `aiohttp` installed.
9+
- **`chat_sdk.adapters.twilio`** (vercel/chat#558; PR #142). Twilio Programmable Messaging adapter (10th platform): inbound message webhooks with `X-Twilio-Signature` HMAC-SHA1 verification (`hmac.compare_digest`), outbound SMS/MMS through the Messages REST API (hand-rolled over an injectable transport — no official `twilio` SDK, mirroring upstream), 1:1 DM threads keyed `twilio:{sender}:{recipient}`, plus standalone `api` / `webhook` / `voice` helpers (TwiML builders, call + transcription parsing). New extra: `chat-sdk-python[twilio]`. Imports stay lazy so the package loads without `aiohttp` installed.
10+
11+
### Teams adapter: migration to the official `microsoft-teams-apps` SDK (issue #93)
12+
13+
The hand-rolled Bot Framework REST + JWT stack is replaced by the official Microsoft Teams Python SDK (`microsoft-teams-apps` ≥ 2.0.13, added to the `[teams]` extra), mirroring upstream `@chat-adapter/teams@4.30.0`. Landed as four PRs:
14+
15+
- **PR 1 — inbound + auth** (#143). New `adapters/teams/bridge.py`: a `BridgeHttpAdapter` implementing the SDK `HttpServerAdapter` protocol routes already-authenticated webhooks through the SDK `App`. JWT validation now runs through the SDK's `TokenValidator` (RS256 + audience + Bot Framework issuer via the live JWKS) in place of the hand-rolled `_verify_bot_framework_token` block. Graph reads stay hand-rolled (no `msgraph-sdk` / `[graph]` extra).
16+
- **PR 2 — outbound** (#144). `post_message` / `start_typing` route through `App.send`; `edit_message` / `delete_message` route through `App.api.conversations.activities(...).update` / `.delete`. Per-thread service-URL routing retargets the SDK `ApiClient`'s service-url chain (validated against the SSRF allow-list). The camelCase wire dict is still returned as `RawMessage.raw`, preserving the public contract (attachment shape, file delivery, returned id).
17+
- **PR 3 — native streaming** (#145). DM streaming uses the SDK's native `IStreamer` (`microsoft-teams-apps` `HttpStream`) via `app.activity_sender.create_stream(...)` and `stream.emit(...)` per chunk, replacing the hand-rolled Bot Framework streaming wire format. The SDK owns the streamType/streamSequence framing, the inter-flush throttle (~500ms, 429-safe), and 429 retry. Atomically unwinds the two transitional public-type divergences (`RawMessage.text`, `update_interval_ms`) that PR 3 made unnecessary.
18+
- **PR 4 — release cut** (this entry). Version bump to `0.4.30`, fidelity re-pin to `chat@4.30.0`, docs, and the `@chat-adapter/teams@4.30.0` version-label normalization.
19+
20+
The residual adapter-level divergences (we keep the SDK as the auth + transport layer but route the authenticated activity ourselves through a lenient `CoreActivity`; the streamer is closed in our own `_handle_message_activity` `finally` because our bridge owns dispatch) are documented in `docs/UPSTREAM_SYNC.md`.
21+
22+
### Adapter ports — Telegram, Slack
23+
24+
- **Telegram: native DM draft streaming** (vercel/chat#340; PR #140). DMs stream via the `sendMessageDraft` Bot API method (the draft bubble updates in place, throttled to `update_interval_ms`, default 250ms), then a regular `sendMessage` persists the final text; non-DM threads return `None` before consuming any chunks so the SDK's post+edit fallback handles groups/channels. Adds a shared `with_telegram_markdown_fallback()` retry-without-`parse_mode` path wrapping `post_message` / `edit_message` / `send_document` / `send_attachment`.
25+
- **Slack: webhook + primitives subpaths** (vercel/chat#538, #547, #548, #555, #559; PR #139). New runtime-free `chat_sdk.adapters.slack.webhook` (and `slack.api`) subpaths for lower-level Slack request verification, signed-body reading, and Events/slash/interactive payload parsing into typed dataclasses. The adapter now verifies through the shared `verify_slack_request` / `verify_slack_signature` primitives (the inline `_verify_signature` method is removed, matching upstream); the slack package `__init__` is now lazy (PEP 562) so importing a subpath does not pull in the full adapter runtime. The new `slack/api` primitives carry SSRF/token-leak guards (`send_slack_response_url` + `fetch_slack_file` host allowlists).
26+
27+
### Adapter fixes — WhatsApp, Slack, Google Chat
28+
29+
- **WhatsApp: typing-indicator support** (vercel/chat#320; PR #141). `start_typing` resolves the latest inbound message id from the `ThreadHistoryCache` and posts a `typing_indicator` payload (also marking the message read); Graph API default bumped v21.0 → v25.0; `_graph_api_request` and the typing-indicator failure path raise `AdapterError` instead of `RuntimeError`.
30+
- **Slack / Google Chat: 4.30 rendering fixes** (vercel/chat#523, #553, #573; PR #141). Includes collapsing redundant autolink formatting for Google Chat email/`mailto:` links (port of upstream `177735a`).
1131

1232
#### Python-specific (divergence from upstream)
1333

1434
- **Twilio media-download SSRF guard.** `rehydrate_attachment` validates the rehydrated media URL (https + Twilio-owned host) inside the download closure before forwarding the account SID / auth token as HTTP Basic, where upstream `fetchTwilioMedia` GETs the URL blindly. Folded into the existing `rehydrate_attachment` URL allowlist non-parity row (Slack / Teams / Google Chat / **Twilio**); enforces `CLAUDE.md`'s SSRF rule. Regression: `tests/test_twilio_adapter.py::TestRehydrateAttachment::test_media_downloader_refuses_untrusted_hosts`.
1535

36+
### Pre-existing parity gaps closed (4.30 audit)
37+
38+
A pre-ship parity audit (the CI fidelity check covers only the mapped CORE `packages/chat` tests, never the adapters) surfaced 9 gaps present since 0.4.29 — the `chat@4.29.0` and `chat@4.30.0` tags are content-identical for the mapped core — and all but one (Linear agent sessions, deferred to 4.31) were closed in this wave, across four PRs:
39+
40+
- **Google Chat: clear `cardsV2` on edit-to-plain-text** (PR #148). BUG — editing a card message down to plain text left the old card stranded on the message; `edit_message` now sends an explicit empty `cardsV2` so the card is dropped (streaming finalization is the common trigger). Plus **`Select` / `RadioSelect``selectionInput` widgets**: these card elements now render as Google Chat `selectionInput` widgets and the selected option is read back from `formInputs`.
41+
- **Teams: ChoiceSet auto-submit fan-out** (PR #149). BUG / contract break — an Adaptive Card `Action.Submit` carrying multiple input keys now fires one `process_action` per input key, so each `on_action(input_key)` handler runs, instead of a single `__auto_submit` dispatch that no handler matched. Plus **`list_threads` / `post_channel_message`** (were raising `ChatNotImplementedError`, now implemented) and **`api_url` / `TEAMS_API_URL`** for a custom Bot Framework endpoint (GCC-High / sovereign cloud).
42+
- **`api_url` custom-endpoint config across Slack / Discord / GitHub / Linear** (PR #150). Custom base URLs for GovSlack / Enterprise Grid / GitHub Enterprise / self-hosted Linear; an empty string falls back to the default, matching upstream's truthy-spread default. Plus **GitHub public `get_installation_id()`**.
43+
- **Core: root `chat_sdk` re-exports the deprecated `chat/ai` type aliases** (PR #147). `AiMessage`, `AiMessagePart`, `ToAiMessagesOptions`, … resolve from the package root again (they had moved to `chat_sdk.ai`); `chat_sdk.ai` stays the canonical home.
44+
45+
**Documented exceptions.** 0.4.30 matches `chat@4.30.0` *with documented exceptions*. The **Linear agent-sessions** surface (#151) is the largest single gap from the audit and is deferred to the 4.31 wave. `adapter-web`, plus the GitHub / Linear native-client (`octokit` / `linearClient`) and `message.subject` halves, remain documented Known Non-Parity in `docs/UPSTREAM_SYNC.md`. The 4.31 wave is tracked in #152.
46+
1647
## 0.4.29 (2026-06-12)
1748

1849
Synced to upstream `vercel/chat@4.29.0` (release commit `6581d31`, May 18 2026; upstream never tagged `chat@4.27.0`/`chat@4.28.0`). Headlines: **Meta Messenger adapter** (9th platform), **`chat/ai` tool factories** (`create_chat_tools`), **`callback_url` on buttons and modals**, **Transcripts API + `thread_history` rename**, **`burst` concurrency strategy**, a Slack feature wave (verifier precedence flip, external installation providers, native `markdown_text`, `web_client`), the upstream adapter-hardening security pass, and a Python floor bump to 3.12. Sets `UPSTREAM_PARITY = "4.29.0"`; CI fidelity re-pinned to `chat@4.29.0`.
@@ -49,8 +80,7 @@ Synced to upstream `vercel/chat@4.29.0` (release commit `6581d31`, May 18 2026;
4980
### Python-only improvements
5081

5182
- **Slack `files_upload_v2` confirmation surfaced through `post()`** (PR #117; also shipped early as 0.4.27.1). `SentMessage.raw` carries `uploaded_file_ids`; history persistence nulls `raw` to avoid storage bloat/PII.
52-
- **Slack: DM block-action responses no longer thread** (PR #133). `_handle_block_actions` mirrors `_handle_message_event`'s DM handling so HITL button replies don't create phantom "1 reply" threads.
53-
- **Google Chat: file delivery via multipart media upload** (PR #112).
83+
- **Slack: DM block-action responses no longer thread** (PR #137, supersedes #133). `_handle_block_actions` mirrors `_handle_message_event`'s DM handling so HITL button replies don't create phantom "1 reply" threads.
5484

5585
### Not ported / deferred (documented in docs/UPSTREAM_SYNC.md)
5686

@@ -67,7 +97,7 @@ Synced to upstream `vercel/chat@4.29.0` (release commit `6581d31`, May 18 2026;
6797

6898
## 0.4.27.1 (2026-05-29)
6999

70-
Python-only point release on the 0.4.27 line (branched from `v0.4.27`; PR #120). Backports the Slack `files_upload_v2` confirmation fix (PR #117) so `SentMessage.raw` carries `uploaded_file_ids`, plus the history-persistence `raw` null-out. Shipped ahead of 0.4.29 to unblock chinchill-api's delivery-confirmation gating.
100+
Python-only point release on the 0.4.27 line (branched from `v0.4.27`; shipped via tag `v0.4.27.1` + merged PR #117). Backports the Slack `files_upload_v2` confirmation fix (PR #117) so `SentMessage.raw` carries `uploaded_file_ids`, plus the history-persistence `raw` null-out. Shipped ahead of 0.4.29 to unblock chinchill-api's delivery-confirmation gating.
71101

72102
## 0.4.29a2 (2026-05-28)
73103

CLAUDE.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Claude Code Quick Reference -- chat-sdk-python
22

33
## What is this?
4-
Python port of [Vercel Chat SDK](https://github.com/vercel/chat) (synced to upstream v4.29.0; next wave 4.30.0 is tracked separately). Multi-platform async chat framework.
4+
Python port of [Vercel Chat SDK](https://github.com/vercel/chat) (synced to upstream v4.30.0). Multi-platform async chat framework.
55

66
## Key Commands
77
```bash
@@ -27,6 +27,7 @@ Our version embeds the upstream Vercel Chat version: `0.{upstream_major}.{upstre
2727
- `0.4.27` = synced to upstream `4.27.0`
2828
- `0.4.27.1` = Python-only fix on top of `4.27.0`
2929
- `0.4.29` = synced to upstream `4.29.0` (upstream never tagged 4.27/4.28 as `chat@*`)
30+
- `0.4.30` = synced to upstream `4.30.0`
3031
- `UPSTREAM_PARITY` constant in `__init__.py` = programmatic access
3132

3233
## Architecture
@@ -109,7 +110,7 @@ will not pass CI.
109110

110111
**Fidelity check** (`scripts/verify_test_fidelity.py`) verifies every TS
111112
`it("...")` in the mapped core files has a matching Python `def test_*()`,
112-
pinned to `chat@4.29.0` (matches `UPSTREAM_PARITY`; upstream never tagged
113+
pinned to `chat@4.30.0` (matches `UPSTREAM_PARITY`; upstream never tagged
113114
`chat@4.27.0`/`chat@4.28.0`). The `MAPPING` dict in that script is the
114115
authoritative scope list — extending it to the remaining unmapped
115116
`packages/chat/src/*.test.ts` files is tracked as issue #78.
@@ -124,7 +125,7 @@ divergence in `docs/UPSTREAM_SYNC.md`.
124125
Before the fidelity check can run locally, clone the pinned upstream
125126
checkout (same command CI uses in `lint.yml`):
126127
```bash
127-
git clone --depth 1 --branch chat@4.29.0 \
128+
git clone --depth 1 --branch chat@4.30.0 \
128129
https://github.com/vercel/chat.git /tmp/vercel-chat
129130
```
130131
Then `TS_ROOT=/tmp/vercel-chat uv run python scripts/verify_test_fidelity.py --strict`.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
Multi-platform async chat SDK for Python. Port of [Vercel Chat](https://github.com/vercel/chat).
99

10-
> **Status: 0.4.29 — synced to [Vercel Chat 4.29.0](https://github.com/vercel/chat)** (`UPSTREAM_PARITY = "4.29.0"`). The 4.30 sync wave is tracked in [#135](https://github.com/Chinchill-AI/chat-sdk-python/issues/135). See [CHANGELOG.md](CHANGELOG.md).
10+
> **Status: 0.4.30 — synced to [Vercel Chat 4.30.0](https://github.com/vercel/chat)** (`UPSTREAM_PARITY = "4.30.0"`). See [CHANGELOG.md](CHANGELOG.md).
1111
1212
## Why chat-sdk?
1313

0 commit comments

Comments
 (0)