You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* 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)
Copy file name to clipboardExpand all lines: CHANGELOG.md
+37-7Lines changed: 37 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,18 +1,49 @@
1
1
# Changelog
2
2
3
-
## Unreleased
3
+
## 0.4.30
4
4
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).
7
6
8
7
### New adapter: Twilio (SMS / MMS / Voice)
9
8
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`).
11
31
12
32
#### Python-specific (divergence from upstream)
13
33
14
34
-**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`.
15
35
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
+
16
47
## 0.4.29 (2026-06-12)
17
48
18
49
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;
49
80
### Python-only improvements
50
81
51
82
-**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.
### Not ported / deferred (documented in docs/UPSTREAM_SYNC.md)
56
86
@@ -67,7 +97,7 @@ Synced to upstream `vercel/chat@4.29.0` (release commit `6581d31`, May 18 2026;
67
97
68
98
## 0.4.27.1 (2026-05-29)
69
99
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.
Copy file name to clipboardExpand all lines: CLAUDE.md
+4-3Lines changed: 4 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,7 +1,7 @@
1
1
# Claude Code Quick Reference -- chat-sdk-python
2
2
3
3
## 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.
5
5
6
6
## Key Commands
7
7
```bash
@@ -27,6 +27,7 @@ Our version embeds the upstream Vercel Chat version: `0.{upstream_major}.{upstre
27
27
-`0.4.27` = synced to upstream `4.27.0`
28
28
-`0.4.27.1` = Python-only fix on top of `4.27.0`
29
29
-`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`
30
31
-`UPSTREAM_PARITY` constant in `__init__.py` = programmatic access
31
32
32
33
## Architecture
@@ -109,7 +110,7 @@ will not pass CI.
109
110
110
111
**Fidelity check** (`scripts/verify_test_fidelity.py`) verifies every TS
111
112
`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
113
114
`chat@4.27.0`/`chat@4.28.0`). The `MAPPING` dict in that script is the
114
115
authoritative scope list — extending it to the remaining unmapped
115
116
`packages/chat/src/*.test.ts` files is tracked as issue #78.
@@ -124,7 +125,7 @@ divergence in `docs/UPSTREAM_SYNC.md`.
124
125
Before the fidelity check can run locally, clone the pinned upstream
Copy file name to clipboardExpand all lines: README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,7 +7,7 @@
7
7
8
8
Multi-platform async chat SDK for Python. Port of [Vercel Chat](https://github.com/vercel/chat).
9
9
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).
0 commit comments