Skip to content

Commit 23575f0

Browse files
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').
1 parent 0008f42 commit 23575f0

2 files changed

Lines changed: 16 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,17 @@ The residual adapter-level divergences (we keep the SDK as the auth + transport
3333

3434
- **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`.
3535

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 the 7 portable ones were closed in this wave:
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+
3647
## 0.4.29 (2026-06-12)
3748

3849
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`.

docs/UPSTREAM_SYNC.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,8 @@ The Python module layout mirrors the TS package layout:
194194
| `packages/adapter-slack/src/index.ts` | `src/chat_sdk/adapters/slack/adapter.py` |
195195
| `packages/state-memory/src/index.ts` | `src/chat_sdk/state/memory.py` |
196196
| `packages/state-redis/src/index.ts` | `src/chat_sdk/state/redis.py` |
197+
| `packages/state-ioredis/src/index.ts` | `src/chat_sdk/state/redis.py` (`IoRedisStateAdapter`) |
198+
| `packages/state-pg/src/index.ts` | `src/chat_sdk/state/postgres.py` |
197199

198200
## What to Port vs What to Adapt
199201

@@ -655,13 +657,15 @@ stay explicit instead of being rediscovered in code review.
655657
|------|--------|-----|-----------|
656658
| Teams certificate auth | Rejected (app password only) | Supported | Low demand; can add later |
657659
| Teams `dialog_open_timeout_ms` config | Not implemented | Configurable | Low demand |
658-
| Google Chat file uploads | Ignored in message parse | Supported | API complexity; can add later |
660+
| Google Chat outbound file delivery | Files attached to an outbound message are dropped — `post_message` logs "File uploads are not yet supported for Google Chat" and posts text/cards only (no media upload). Inbound attachments **are** parsed: `_create_attachment` builds a full `Attachment` (type detection, `fetch_data` download closure, `fetch_metadata`) for every `message.attachment` entry. | Both directions supported (multipart media upload on send) | Outbound upload (multipart to the Media API) not yet ported; API complexity, can add later. Inbound parity is complete, so this row is outbound-only. |
659661
| Discord Gateway WebSocket | HTTP interactions only | Both HTTP and Gateway | Gateway requires persistent connection |
660662
| Discord gateway-only interactions (vercel/chat#490) | Handled on the forwarded-event surface: a `GATEWAY_INTERACTION_CREATE` envelope (raw INTERACTION_CREATE dispatch payload in `data`) is deferred via `POST /interactions/{id}/{token}/callback` (type 5 slash / type 6 component) and routed through the existing HTTP interaction handlers; a malformed forward missing `id`/`token` is logged and skipped | Upstream handles `Events.InteractionCreate` directly on the resident discord.js client via `deferReply()`/`deferUpdate()`; the upstream forwarder never forwards interactions | Python has no resident Gateway client (row above), so gateway-only deployments run an external listener shim that forwards raw dispatch payloads (`x-discord-gateway-token`). Observable wire behavior is identical — same callback REST calls, same handler routing, same `@original` deferred-response resolution. |
661663
| Teams `User-Agent: Vercel.ChatSDK` outbound header | Not set on `aiohttp` calls | Propagated by `botbuilder` 2.0.8 | Python Teams adapter doesn't use `botbuilder` (raw `aiohttp`). Upstream's vercel/chat#415 was a JS-only `botbuilder` SDK bump that flipped `X-User-Agent``User-Agent`. No equivalent dependency to bump on the Python side. Setting a `User-Agent` on the ~9 outbound `aiohttp` call sites would be a defense-in-depth nice-to-have; deferred to a follow-up. |
662664
| Teams adapter on `microsoft-teams-apps` (official MS Python SDK) | Inbound webhook + JWT auth, outbound send/edit/delete/typing, and native DM streaming all delegate to the official `microsoft-teams-apps` SDK `App`; Graph reads stay hand-rolled over `aiohttp` | `@microsoft/teams.apps` owns the wire format, throttling, and activity routing | **Delivered in 0.4.30** (issue #93, PRs 1–4). The migration shipped as four PRs: inbound + auth (#143), outbound (#144), native streaming via the SDK `IStreamer` (#145), and this release cut. The 3.12 floor bump (#111) — the migration's prerequisite — landed in 0.4.29. The residual adapter-level divergences (we keep the SDK as auth + transport but route the authenticated activity ourselves; close the streamer in our own `finally` because our bridge owns dispatch) are documented in the Teams divergence rows above. Graph stays hand-rolled (no `msgraph-sdk` / `[graph]` extra). |
663665
| Telegram `get_user().is_bot` | Always `False` (matches upstream — `getChat` does not expose `is_bot`) | Always `false` (same caveat documented in upstream code comment) | The Telegram Bot API's `getChat` endpoint does not surface the `is_bot` field that's available on the `User` object inside incoming `Message` updates. Callers needing bot detection must use `message.author.is_bot` from webhooks instead of `chat.get_user(...).is_bot`. |
664666
| WhatsApp `get_user` | Raises `ChatNotImplementedError` (`Chat.get_user` translates to "does not support get_user") | Not implemented upstream either (no `getUser` on the WhatsApp adapter) | WhatsApp Cloud API has no user lookup endpoint — phone numbers are the only stable identifier and there's no equivalent of `users.info` exposed to business apps. Documented explicitly so callers don't expect parity with Slack/Teams/Discord. |
667+
| Linear agent sessions | Not ported — the ~120-reference agent-sessions surface (`parseMessageFromAgentSessionEvent`, `agentActivity`, `AgentSessionEventWebhookPayload`, `LinearAgentSessionThreadId`, …) is absent from the Python `LinearAdapter` | Full agent-sessions support (`adapter-linear` 4.27.0, `bc94f0a`): parses agent-session webhook events into messages, emits agent activity, and routes the agent-session thread id | Largest single gap from the 0.4.30 audit; pre-existing (present since 0.4.29). Deferred to the 4.31 wave — tracked in **#151**. |
668+
| `adapter-web` (`@chat-adapter/web`) | Neither half ported. (a) The server-side `WebAdapter` is **deferred** — not yet ported; (b) the client subpaths are out of scope (see Rationale). | Two distinct things: (a) a server-side `WebAdapter` — an `Adapter` implementation serving a browser chat UI over the AI SDK UI stream protocol (`3490a8c`, vercel/chat#444); (b) React/Vue/Svelte client subpaths (`716e934`) | The `WebAdapter` (a) **is portable** to a Python server SDK (it's a standard `Adapter`) and is deferred, not excluded — a future wave can port it. The client subpaths (b) are genuinely browser-only (front-end framework bindings) and are out of scope for a Python server SDK. (Corrects the earlier over-broad "browser-only; no Python runtime" note in CHANGELOG.) |
665669

666670
### Serialization differences
667671

0 commit comments

Comments
 (0)