Skip to content

Commit ac956e1

Browse files
Merge remote-tracking branch 'origin/main' into claude/port-message-subject
# Conflicts: # src/chat_sdk/types.py # tests/test_chat_faithful.py
2 parents bf498d0 + b5fc8b8 commit ac956e1

96 files changed

Lines changed: 15633 additions & 1013 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.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.26.0 \
63+
git clone --depth 1 --branch chat@4.29.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: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,61 @@
11
# Changelog
22

3+
## 0.4.29 (2026-06-12)
4+
5+
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`.
6+
7+
### Upstream parity ports — core (`packages/chat`)
8+
9+
- **`callback_url` on buttons and modals** (vercel/chat#454). New `src/chat_sdk/callback_url.py` plus plumbing through cards, modals, chat, channel, and thread: card buttons and modals can carry a `callback_url` that the SDK POSTs to when the action/submit fires, alongside regular handlers. Serialized wire keys stay camelCase (`callbackUrl`) for cross-SDK state compatibility.
10+
- **Transcripts API + per-thread cache rename to `thread_history`** (vercel/chat#448). `MessageHistoryCache``ThreadHistoryCache` (module `message_history``thread_history`) with back-compat shims at the old import path and config names (new name wins when both are set, matching upstream's `?? config.messageHistory` fallback). The persisted state key prefix `msg-history:` is **unchanged** (renaming would orphan existing data — upstream kept it too). New Transcripts surface for cross-platform per-user history; `ChatConfig.transcripts` requires `ChatConfig.identity` and raises on misconfiguration, matching upstream's guard.
11+
- **`message.subject` + `fetch_subject` adapter hook** (vercel/chat#459, PR #131). `MessageSubject` dataclass, optional `BaseAdapter.fetch_subject(raw)` hook, lazily-resolved cached `Message.subject` accessor, adapter bound at the `Chat._dispatch_to_handlers` convergence point. The GitHub/Linear adapter halves are blocked on native-client exposure (see Known Non-Parity rows).
12+
- **`burst` concurrency strategy** (vercel/chat#495, PR #114). Hybrid of `debounce` and `queue`: idle threads coalesce a burst window into one dispatch with earlier messages in `context.skipped`; busy threads drain like `queue`. Note: upstream's PR title says "queue-debounce" but the shipped strategy string is `"burst"` — the Python port matches the string (cross-SDK config parity).
13+
- **`process_message` returns the handler task** (core slice of vercel/chat#444). Streaming callers can await full handler completion and observe handler exceptions; `wait_until` keeps swallowed-error semantics; fire-and-forget callers are unaffected. The `@chat-adapter/web` package that motivated #444 is browser-only and not ported.
14+
- **`chat/ai` subpath** (vercel/chat#492, design #109; PRs #116 + #122). `chat_sdk.ai` is now a package: `ai/messages.py` (`to_ai_messages`, moved with deprecation shims) and `ai/tools.py``create_chat_tools(chat, preset=, require_approval=, overrides=)` returning the 17 upstream tool factories as `ChatTool` dataclasses (JSON-Schema `input_schema`, async `execute`, `needs_approval`), keyed by upstream's camelCase tool ids. No new runtime dependencies.
15+
16+
### New adapter: Messenger (Meta)
17+
18+
- **`chat_sdk.adapters.messenger`** (vercel/chat#461, design #110; PRs #118 + #124). Full Messenger Platform adapter: GET verification handshake + `X-Hub-Signature-256` HMAC verification, Graph API client with typed error mapping, text/Generic/Button-template sends with documented caps, buffered streaming (no edit API), postback/reaction/delivery/read handlers, attachment extraction with lazy `fetch_data`, local message cache backing `fetch_messages`. New extra: `chat-sdk-python[messenger]`. Capabilities matrix in the design issue; `get_user` tracked as #132.
19+
20+
### Upstream parity ports — adapters
21+
22+
- **Slack: `webhook_verifier` now takes precedence over `signing_secret`** (vercel/chat#468, PR #113). Reverses the 0.4.27 precedence after upstream reversed itself; see the Known Non-Parity row update. **Migration**: if you relied on `signing_secret` shadowing a configured `webhook_verifier`, remove one of the two.
23+
- **Slack: native `markdown_text` for outgoing messages** (vercel/chat#440). Outgoing posts use Slack's native markdown rendering instead of the legacy Block Kit conversion (deferred from 0.4.27).
24+
- **Slack: external installation providers for bot token management** (vercel/chat#467). Pluggable multi-workspace token source composing with the existing dynamic `bot_token` resolver (per-request ContextVar caching preserved).
25+
- **Slack: `web_client` property** (vercel/chat#471/#476/#478, PR #127). Sync `slack_sdk.WebClient` bound to the request-context token; `client` retained as a one-release deprecated alias.
26+
- **Teams: outbound file delivery via data-URI activity attachments** (PR #125, ports upstream `filesToAttachments`). Execution artifacts now reach Teams; `edit_message` delivery is a documented deliberate superset.
27+
- **Telegram: `video_note` extraction + typed attachment uploads** (vercel/chat#457, #485; PR #119).
28+
- **Discord: handle interactions in gateway-only mode** (vercel/chat#490).
29+
- **Adapter hardening pass** (slices of upstream `9824d33`): Slack timing-safe socket-token comparison (PR #126), GitHub eager bot-user-ID auto-detection (PR #128), Linear OAuth tokens encrypted at rest with AES-256-GCM (PR #129), and Google Chat fail-closed webhook verification (PR #130**breaking** for gchat configs that previously constructed without any verification gate; set `google_chat_project_number`, `pubsub_audience`, or the explicit `disable_signature_verification=True` escape hatch).
30+
31+
### Documentation alignment
32+
33+
- **DM routing precedence docstrings** (vercel/chat#491, PR #121). `on_direct_message` and `Thread.subscribe` docstrings now state the DM > subscribed > mention > pattern precedence the runtime already implemented; regression test pins DM > pattern.
34+
- **Streaming docstring refresh** (vercel/chat#463, PR #123). `StreamingPlanOptions.update_interval_ms` and `ThreadImpl._handle_stream` no longer imply a binary native-vs-fallback split.
35+
36+
### Python-only improvements
37+
38+
- **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.
39+
- **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.
40+
- **Google Chat: file delivery via multipart media upload** (PR #112).
41+
42+
### Not ported / deferred (documented in docs/UPSTREAM_SYNC.md)
43+
44+
- **`@chat-adapter/web`** (vercel/chat#444) — browser-only; no Python runtime.
45+
- **`@chat-adapter/tests` kit** (vercel/chat#470) — `chat_sdk.testing` already covers the surface; row added.
46+
- **GitHub `octokit` / Linear `linear_client` getters** (vercel/chat#459/#478 halves) — both Python adapters are hand-rolled over `aiohttp` with no SDK object to expose; rows added with the revisit conditions (`githubkit` adoption / an official Linear Python SDK).
47+
- **Teams migration to `microsoft-teams-apps`** (issue #93) — explicitly deferred to the 0.4.30 cycle; row added. The 3.12 floor prerequisite (#111) shipped in this release.
48+
49+
### Build / infra
50+
51+
- **Python floor bumped 3.10 → 3.12** (PR #111).
52+
- **Fidelity**: CI re-pinned to `chat@4.29.0`; `MAPPING` updated for the 4.29 layout (`ai.test.ts` split into `ai/messages.test.ts` + `ai/index.test.ts`) and extended to the new core test files; converter-exact test renames in `tests/test_ai_tools.py`; two `chat.test.ts` subject-rehydration ports are `skipif`-gated on `BaseAdapter.fetch_subject` and activate automatically when PR #131 lands.
53+
- **Next wave**: upstream `chat@4.30.0` (tagged 2026-06-01) is tracked in #135.
54+
55+
## 0.4.27.1 (2026-05-29)
56+
57+
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.
58+
359
## 0.4.29a2 (2026-05-28)
460

561
Python-only fix. No upstream version change.

CLAUDE.md

Lines changed: 11 additions & 14 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) (porting v4.29.0; last fully-synced release `0.4.27` at upstream `4.27.0`). Multi-platform async chat framework.
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.
55

66
## Key Commands
77
```bash
@@ -25,7 +25,8 @@ Our version embeds the upstream Vercel Chat version: `0.{upstream_major}.{upstre
2525
- `0.4.26` = synced to upstream `4.26.0`
2626
- `0.4.26.3` = Python-only fixes on top of `4.26.0`
2727
- `0.4.27` = synced to upstream `4.27.0`
28-
- `0.4.29a1` = alpha while porting upstream `4.29.0` (current branch; upstream skipped 4.28 tag)
28+
- `0.4.27.1` = Python-only fix on top of `4.27.0`
29+
- `0.4.29` = synced to upstream `4.29.0` (upstream never tagged 4.27/4.28 as `chat@*`)
2930
- `UPSTREAM_PARITY` constant in `__init__.py` = programmatic access
3031

3132
## Architecture
@@ -34,7 +35,7 @@ Our version embeds the upstream Vercel Chat version: `0.{upstream_major}.{upstre
3435
- `src/chat_sdk/channel.py` -- Channel (thread listing, metadata)
3536
- `src/chat_sdk/plan.py` -- Plan (PostableObject for structured task lists)
3637
- `src/chat_sdk/types.py` -- All types (Message, Author, Adapter protocol)
37-
- `src/chat_sdk/adapters/` -- 8 platform adapters
38+
- `src/chat_sdk/adapters/` -- 9 platform adapters
3839
- `src/chat_sdk/shared/` -- Markdown parser, format converter, streaming renderer
3940
- `src/chat_sdk/state/` -- Memory, Redis, Postgres backends
4041
- `tests/` -- 3,400+ tests
@@ -108,26 +109,22 @@ will not pass CI.
108109

109110
**Fidelity check** (`scripts/verify_test_fidelity.py`) verifies every TS
110111
`it("...")` in the mapped core files has a matching Python `def test_*()`,
111-
pinned to `chat@4.26.0` (upstream skipped tagging `chat@4.27.0` and
112-
`chat@4.28.0`, then resumed at `chat@4.29.0`; pin moves to `chat@4.29.0`
113-
once the in-flight 4.29 sync lands). The `MAPPING`
114-
dict in that script is the authoritative scope list — it currently covers 8
115-
of 17 `packages/chat/src/*.test.ts` files (extending it is tracked as a
116-
follow-up). **CI runs `--strict`** (see `.github/workflows/lint.yml`):
112+
pinned to `chat@4.29.0` (matches `UPSTREAM_PARITY`; upstream never tagged
113+
`chat@4.27.0`/`chat@4.28.0`). The `MAPPING` dict in that script is the
114+
authoritative scope list — extending it to the remaining unmapped
115+
`packages/chat/src/*.test.ts` files is tracked as issue #78.
116+
**CI runs `--strict`** (see `.github/workflows/lint.yml`):
117117
any missing translation in a mapped file fails the build, and a missing
118118
upstream checkout also fails (the script exits non-zero when any mapped
119119
TS file isn't found). Baseline mode (the default without `--strict`) is
120120
retained for local workflows where a few ports land in flight —
121121
regenerate via `--update-baseline` after documenting intentional
122-
divergence in `docs/UPSTREAM_SYNC.md`. During this sync cycle baseline
123-
mode reports a parity mismatch (baseline pinned at `chat@4.26.0`,
124-
`UPSTREAM_PARITY` says `4.29.0`); that's the intended signal until the
125-
sync lands.
122+
divergence in `docs/UPSTREAM_SYNC.md`.
126123

127124
Before the fidelity check can run locally, clone the pinned upstream
128125
checkout (same command CI uses in `lint.yml`):
129126
```bash
130-
git clone --depth 1 --branch chat@4.26.0 \
127+
git clone --depth 1 --branch chat@4.29.0 \
131128
https://github.com/vercel/chat.git /tmp/vercel-chat
132129
```
133130
Then `TS_ROOT=/tmp/vercel-chat uv run python scripts/verify_test_fidelity.py --strict`.

README.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77

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

10-
> **Status: Alpha (0.4.29a1porting [Vercel Chat 4.29.0](https://github.com/vercel/chat))** — API may change. Last fully-synced release: `0.4.27` (parity with upstream `chat@4.27.0`). See [CHANGELOG.md](CHANGELOG.md) for the in-flight sync plan.
10+
> **Status: 0.4.29synced 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).
1111
1212
## Why chat-sdk?
1313

14-
- **Write once, deploy to 8 platforms.** One handler runs on Slack, Discord, Teams, Telegram, WhatsApp, Google Chat, GitHub, and Linear.
14+
- **Write once, deploy to 9 platforms.** One handler runs on Slack, Discord, Teams, Telegram, WhatsApp, Messenger, Google Chat, GitHub, and Linear.
1515
- **Built-in concurrency primitives.** Deduplication, thread locking, and message queuing are handled for you.
1616
- **Cross-platform cards.** Author a `Card` once and it renders as Block Kit (Slack), Adaptive Cards (Teams), embeds (Discord), and more.
1717
- **Not a replacement for platform SDKs.** chat-sdk is built *on top of* them. You can always drop down to the native SDK when you need to.
@@ -54,10 +54,29 @@ async def handle_mention(thread, message):
5454
| Teams | `chat-sdk[teams]` | Alpha |
5555
| Telegram | `chat-sdk[telegram]` | Alpha |
5656
| WhatsApp | `chat-sdk[whatsapp]` | Alpha |
57+
| Messenger (Meta) | `chat-sdk[messenger]` | Alpha |
5758
| Google Chat | `chat-sdk[google-chat]` | Alpha |
5859
| GitHub | `chat-sdk[github]` | Alpha |
5960
| Linear | `chat-sdk[linear]` | Alpha |
6061

62+
## AI / LLM Integration
63+
64+
Expose chat actions to an LLM agent as tools (`chat/ai` parity, vercel/chat#492):
65+
66+
```python
67+
from chat_sdk.ai import create_chat_tools, to_ai_messages
68+
69+
tools = create_chat_tools(chat, preset="messenger", require_approval=True)
70+
# {"postMessage": ChatTool(description=..., input_schema={...}, execute=..., needs_approval=True), ...}
71+
```
72+
73+
Each `ChatTool` is SDK-agnostic: `input_schema` is a JSON-Schema dict you can
74+
hand to any agent runtime (Anthropic tool use, OpenAI tools, pydantic-ai, ...),
75+
`execute` is the async implementation, and `needs_approval` flags write tools
76+
for human-in-the-loop gating. Presets: `reader`, `messenger`, `moderator`.
77+
`to_ai_messages(thread)` converts thread history into model-ready messages.
78+
Runnable demo: [`examples/ai_tools_example.py`](examples/ai_tools_example.py).
79+
6180
## State Backends
6281

6382
| Backend | Install Extra |
@@ -70,7 +89,7 @@ async def handle_mention(thread, message):
7089

7190
| Feature | chat-sdk | Raw platform SDKs | BotFramework SDK |
7291
|---------|----------|--------------------|------------------|
73-
| Multi-platform from one codebase | 8 platforms | 1 per SDK | Teams + limited |
92+
| Multi-platform from one codebase | 9 platforms | 1 per SDK | Teams + limited |
7493
| Async-native (Python 3.12+) | Yes | Varies | No |
7594
| Cross-platform cards | Card model | Platform-specific | Adaptive Cards only |
7695
| Thread locking / dedup | Built-in | DIY | DIY |

0 commit comments

Comments
 (0)